blob: 33e84e5a0b8c1f40aad5127d21e15d6b32332dfb [file] [log] [blame]
/*
* Copyright 2016 The gRPC Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.grpc.internal;
import static com.google.common.base.Preconditions.checkNotNull;
import com.google.common.annotations.VisibleForTesting;
import io.grpc.Attributes;
import io.grpc.ClientStreamTracer;
import io.grpc.Context;
import io.grpc.Metadata;
import io.grpc.ServerStreamTracer;
import io.grpc.ServerStreamTracer.ServerCallInfo;
import io.grpc.Status;
import io.grpc.StreamTracer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
import javax.annotation.concurrent.ThreadSafe;
/**
* The stats and tracing information for a stream.
*/
@ThreadSafe
public final class StatsTraceContext {
public static final StatsTraceContext NOOP = new StatsTraceContext(new StreamTracer[0]);
private final StreamTracer[] tracers;
private final AtomicBoolean closed = new AtomicBoolean(false);
/**
* Factory method for the client-side.
*/
public static StatsTraceContext newClientContext(
ClientStreamTracer[] tracers, Attributes transportAtts, Metadata headers) {
StatsTraceContext ctx = new StatsTraceContext(tracers);
for (ClientStreamTracer tracer : tracers) {
tracer.streamCreated(transportAtts, headers);
}
return ctx;
}
/**
* Factory method for the server-side.
*/
public static StatsTraceContext newServerContext(
List<? extends ServerStreamTracer.Factory> factories,
String fullMethodName,
Metadata headers) {
if (factories.isEmpty()) {
return NOOP;
}
StreamTracer[] tracers = new StreamTracer[factories.size()];
for (int i = 0; i < tracers.length; i++) {
tracers[i] = factories.get(i).newServerStreamTracer(fullMethodName, headers);
}
return new StatsTraceContext(tracers);
}
@VisibleForTesting
StatsTraceContext(StreamTracer[] tracers) {
this.tracers = tracers;
}
/**
* Returns a copy of the tracer list.
*/
@VisibleForTesting
public List<StreamTracer> getTracersForTest() {
return new ArrayList<>(Arrays.asList(tracers));
}
/**
* See {@link ClientStreamTracer#outboundHeaders}. For client-side only.
*
* <p>Transport-specific, thus should be called by transport implementations.
*/
public void clientOutboundHeaders() {
for (StreamTracer tracer : tracers) {
((ClientStreamTracer) tracer).outboundHeaders();
}
}
/**
* See {@link ClientStreamTracer#inboundHeaders}. For client-side only.
*
* <p>Called from abstract stream implementations.
*/
public void clientInboundHeaders() {
for (StreamTracer tracer : tracers) {
((ClientStreamTracer) tracer).inboundHeaders();
}
}
/**
* See {@link ClientStreamTracer#inboundTrailers}. For client-side only.
*
* <p>Called from abstract stream implementations.
*/
public void clientInboundTrailers(Metadata trailers) {
for (StreamTracer tracer : tracers) {
((ClientStreamTracer) tracer).inboundTrailers(trailers);
}
}
/**
* See {@link ServerStreamTracer#filterContext}. For server-side only.
*
* <p>Called from {@link io.grpc.internal.ServerImpl}.
*/
public <ReqT, RespT> Context serverFilterContext(Context context) {
Context ctx = checkNotNull(context, "context");
for (StreamTracer tracer : tracers) {
ctx = ((ServerStreamTracer) tracer).filterContext(ctx);
checkNotNull(ctx, "%s returns null context", tracer);
}
return ctx;
}
/**
* See {@link ServerStreamTracer#serverCallStarted}. For server-side only.
*
* <p>Called from {@link io.grpc.internal.ServerImpl}.
*/
public void serverCallStarted(ServerCallInfo<?, ?> callInfo) {
for (StreamTracer tracer : tracers) {
((ServerStreamTracer) tracer).serverCallStarted(callInfo);
}
}
/**
* See {@link StreamTracer#streamClosed}. This may be called multiple times, and only the first
* value will be taken.
*
* <p>Called from abstract stream implementations.
*/
public void streamClosed(Status status) {
if (closed.compareAndSet(false, true)) {
for (StreamTracer tracer : tracers) {
tracer.streamClosed(status);
}
}
}
/**
* See {@link StreamTracer#outboundMessage(int)}.
*
* <p>Called from {@link io.grpc.internal.Framer}.
*/
public void outboundMessage(int seqNo) {
for (StreamTracer tracer : tracers) {
tracer.outboundMessage(seqNo);
}
}
/**
* See {@link StreamTracer#inboundMessage(int)}.
*
* <p>Called from {@link io.grpc.internal.MessageDeframer}.
*/
public void inboundMessage(int seqNo) {
for (StreamTracer tracer : tracers) {
tracer.inboundMessage(seqNo);
}
}
/**
* See {@link StreamTracer#outboundMessageSent}.
*
* <p>Called from {@link io.grpc.internal.Framer}.
*/
public void outboundMessageSent(int seqNo, long optionalWireSize, long optionalUncompressedSize) {
for (StreamTracer tracer : tracers) {
tracer.outboundMessageSent(seqNo, optionalWireSize, optionalUncompressedSize);
}
}
/**
* See {@link StreamTracer#inboundMessageRead}.
*
* <p>Called from {@link io.grpc.internal.MessageDeframer}.
*/
public void inboundMessageRead(int seqNo, long optionalWireSize, long optionalUncompressedSize) {
for (StreamTracer tracer : tracers) {
tracer.inboundMessageRead(seqNo, optionalWireSize, optionalUncompressedSize);
}
}
/**
* See {@link StreamTracer#outboundUncompressedSize}.
*
* <p>Called from {@link io.grpc.internal.Framer}.
*/
public void outboundUncompressedSize(long bytes) {
for (StreamTracer tracer : tracers) {
tracer.outboundUncompressedSize(bytes);
}
}
/**
* See {@link StreamTracer#outboundWireSize}.
*
* <p>Called from {@link io.grpc.internal.Framer}.
*/
public void outboundWireSize(long bytes) {
for (StreamTracer tracer : tracers) {
tracer.outboundWireSize(bytes);
}
}
/**
* See {@link StreamTracer#inboundUncompressedSize}.
*
* <p>Called from {@link io.grpc.internal.MessageDeframer}.
*/
public void inboundUncompressedSize(long bytes) {
for (StreamTracer tracer : tracers) {
tracer.inboundUncompressedSize(bytes);
}
}
/**
* See {@link StreamTracer#inboundWireSize}.
*
* <p>Called from {@link io.grpc.internal.MessageDeframer}.
*/
public void inboundWireSize(long bytes) {
for (StreamTracer tracer : tracers) {
tracer.inboundWireSize(bytes);
}
}
}