core,services: Add ChannelTracing data object

Added `ChannelTrace` as an inner class of `Channelz`.

This is in preparation for the implementation of [Channel Tracing](https://github.com/grpc/proposal/blob/master/A3-channel-tracing.md)
This commit is contained in:
ZHANG Dapeng 2018-05-15 11:33:44 -07:00 committed by GitHub
parent 04a90bcad2
commit 561583be14
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 253 additions and 30 deletions

View File

@ -16,6 +16,9 @@
package io.grpc.internal;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Preconditions;
import io.grpc.ConnectivityState;
@ -244,7 +247,7 @@ public final class Channelz {
/** Creates an instance. */
public RootChannelList(List<Instrumented<ChannelStats>> channels, boolean end) {
this.channels = Preconditions.checkNotNull(channels);
this.channels = checkNotNull(channels);
this.end = end;
}
}
@ -255,7 +258,7 @@ public final class Channelz {
/** Creates an instance. */
public ServerList(List<Instrumented<ServerStats>> servers, boolean end) {
this.servers = Preconditions.checkNotNull(servers);
this.servers = checkNotNull(servers);
this.end = end;
}
}
@ -292,7 +295,7 @@ public final class Channelz {
this.callsSucceeded = callsSucceeded;
this.callsFailed = callsFailed;
this.lastCallStartedMillis = lastCallStartedMillis;
this.listenSockets = Preconditions.checkNotNull(listenSockets);
this.listenSockets = checkNotNull(listenSockets);
}
public static final class Builder {
@ -324,7 +327,7 @@ public final class Channelz {
/** Sets the listen sockets. */
public Builder setListenSockets(List<Instrumented<SocketStats>> listenSockets) {
Preconditions.checkNotNull(listenSockets);
checkNotNull(listenSockets);
this.listenSockets = Collections.unmodifiableList(
new ArrayList<Instrumented<SocketStats>>(listenSockets));
return this;
@ -351,6 +354,7 @@ public final class Channelz {
public static final class ChannelStats {
public final String target;
public final ConnectivityState state;
@Nullable public final ChannelTrace channelTrace;
public final long callsStarted;
public final long callsSucceeded;
public final long callsFailed;
@ -361,9 +365,10 @@ public final class Channelz {
/**
* Creates an instance.
*/
public ChannelStats(
private ChannelStats(
String target,
ConnectivityState state,
@Nullable ChannelTrace channelTrace,
long callsStarted,
long callsSucceeded,
long callsFailed,
@ -376,17 +381,19 @@ public final class Channelz {
+ "neither can have both");
this.target = target;
this.state = state;
this.channelTrace = channelTrace;
this.callsStarted = callsStarted;
this.callsSucceeded = callsSucceeded;
this.callsFailed = callsFailed;
this.lastCallStartedMillis = lastCallStartedMillis;
this.subchannels = Preconditions.checkNotNull(subchannels);
this.sockets = Preconditions.checkNotNull(sockets);
this.subchannels = checkNotNull(subchannels);
this.sockets = checkNotNull(sockets);
}
public static final class Builder {
private String target;
private ConnectivityState state;
private ChannelTrace channelTrace;
private long callsStarted;
private long callsSucceeded;
private long callsFailed;
@ -404,6 +411,11 @@ public final class Channelz {
return this;
}
public Builder setChannelTrace(ChannelTrace channelTrace) {
this.channelTrace = channelTrace;
return this;
}
public Builder setCallsStarted(long callsStarted) {
this.callsStarted = callsStarted;
return this;
@ -427,14 +439,14 @@ public final class Channelz {
/** Sets the subchannels. */
public Builder setSubchannels(List<WithLogId> subchannels) {
Preconditions.checkState(sockets.isEmpty());
this.subchannels = Collections.unmodifiableList(Preconditions.checkNotNull(subchannels));
this.subchannels = Collections.unmodifiableList(checkNotNull(subchannels));
return this;
}
/** Sets the sockets. */
public Builder setSockets(List<WithLogId> sockets) {
Preconditions.checkState(subchannels.isEmpty());
this.sockets = Collections.unmodifiableList(Preconditions.checkNotNull(sockets));
this.sockets = Collections.unmodifiableList(checkNotNull(sockets));
return this;
}
@ -445,6 +457,7 @@ public final class Channelz {
return new ChannelStats(
target,
state,
channelTrace,
callsStarted,
callsSucceeded,
callsFailed,
@ -455,6 +468,109 @@ public final class Channelz {
}
}
@Immutable
public static final class ChannelTrace {
public final long numEventsLogged;
public final long creationTimeNanos;
public final List<Event> events;
private ChannelTrace(long numEventsLogged, long creationTimeNanos, List<Event> events) {
this.numEventsLogged = numEventsLogged;
this.creationTimeNanos = creationTimeNanos;
this.events = events;
}
public static final class Builder {
private long numEventsLogged;
private long creationTimeNanos;
private List<Event> events = Collections.emptyList();
public Builder setNumEventsLogged(long numEventsLogged) {
this.numEventsLogged = numEventsLogged;
return this;
}
public Builder setCreationTimeNanos(long creationTimeNanos) {
this.creationTimeNanos = creationTimeNanos;
return this;
}
public Builder setEvents(List<Event> events) {
this.events = Collections.unmodifiableList(new ArrayList<Event>(events));
return this;
}
public ChannelTrace build() {
return new ChannelTrace(numEventsLogged, creationTimeNanos, events);
}
}
@Immutable
public static final class Event {
public final String description;
public final Severity severity;
public final long timestampNanos;
// the oneof child_ref field in proto: one of channelRef and channelRef
@Nullable public final WithLogId channelRef;
@Nullable public final WithLogId subchannelRef;
public enum Severity {
CT_UNKNOWN, CT_INFO, CT_WARNING, CT_ERROR
}
private Event(
String description, Severity severity, long timestampNanos,
@Nullable WithLogId channelRef, @Nullable WithLogId subchannelRef) {
checkArgument(
channelRef == null || subchannelRef == null,
"at least one of channelRef and subchannelRef must be null");
this.description = checkNotNull(description, "description");
this.severity = checkNotNull(severity, "severity");
this.timestampNanos = timestampNanos;
this.channelRef = channelRef;
this.subchannelRef = subchannelRef;
}
public static final class Builder {
private String description;
private Severity severity;
private long timestampNanos;
private WithLogId channelRef;
private WithLogId subchannelRef;
public Builder setDescription(String description) {
this.description = description;
return this;
}
public Builder setTimestampNaonos(long timestampNanos) {
this.timestampNanos = timestampNanos;
return this;
}
public Builder setSeverity(Severity severity) {
this.severity = severity;
return this;
}
public Builder setChannelRef(WithLogId channelRef) {
this.channelRef = channelRef;
return this;
}
public Builder setSubchannelRef(WithLogId subchannelRef) {
this.subchannelRef = subchannelRef;
return this;
}
public Event build() {
return new Event(description, severity, timestampNanos, channelRef, subchannelRef);
}
}
}
}
public static final class Security {
@Nullable
public final Tls tls;
@ -462,13 +578,13 @@ public final class Channelz {
public final OtherSecurity other;
public Security(Tls tls) {
this.tls = Preconditions.checkNotNull(tls);
this.tls = checkNotNull(tls);
this.other = null;
}
public Security(OtherSecurity other) {
this.tls = null;
this.other = Preconditions.checkNotNull(other);
this.other = checkNotNull(other);
}
}
@ -483,7 +599,7 @@ public final class Channelz {
* @param any a com.google.protobuf.Any object
*/
public OtherSecurity(String name, @Nullable Object any) {
this.name = Preconditions.checkNotNull(name);
this.name = checkNotNull(name);
Preconditions.checkState(
any == null || any.getClass().getName().endsWith("com.google.protobuf.Any"),
"the 'any' object must be of type com.google.protobuf.Any");
@ -553,9 +669,9 @@ public final class Channelz {
SocketOptions socketOptions,
Security security) {
this.data = data;
this.local = Preconditions.checkNotNull(local, "local socket");
this.local = checkNotNull(local, "local socket");
this.remote = remote;
this.socketOptions = Preconditions.checkNotNull(socketOptions);
this.socketOptions = checkNotNull(socketOptions);
this.security = security;
}
}
@ -827,7 +943,7 @@ public final class Channelz {
@Nullable Integer lingerSeconds,
@Nullable TcpInfo tcpInfo,
Map<String, String> others) {
Preconditions.checkNotNull(others);
checkNotNull(others);
this.soTimeoutMillis = timeoutMillis;
this.lingerSeconds = lingerSeconds;
this.tcpInfo = tcpInfo;
@ -861,7 +977,7 @@ public final class Channelz {
}
public Builder addOption(String name, String value) {
others.put(name, Preconditions.checkNotNull(value));
others.put(name, checkNotNull(value));
return this;
}

View File

@ -34,6 +34,9 @@ import io.grpc.channelz.v1.ChannelConnectivityState;
import io.grpc.channelz.v1.ChannelConnectivityState.State;
import io.grpc.channelz.v1.ChannelData;
import io.grpc.channelz.v1.ChannelRef;
import io.grpc.channelz.v1.ChannelTrace;
import io.grpc.channelz.v1.ChannelTraceEvent;
import io.grpc.channelz.v1.ChannelTraceEvent.Severity;
import io.grpc.channelz.v1.GetServerSocketsResponse;
import io.grpc.channelz.v1.GetServersResponse;
import io.grpc.channelz.v1.GetTopChannelsResponse;
@ -55,6 +58,7 @@ import io.grpc.channelz.v1.Subchannel;
import io.grpc.channelz.v1.SubchannelRef;
import io.grpc.internal.Channelz;
import io.grpc.internal.Channelz.ChannelStats;
import io.grpc.internal.Channelz.ChannelTrace.Event;
import io.grpc.internal.Channelz.RootChannelList;
import io.grpc.internal.Channelz.ServerList;
import io.grpc.internal.Channelz.ServerSocketsList;
@ -67,6 +71,7 @@ import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.security.cert.CertificateEncodingException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map.Entry;
import java.util.concurrent.ExecutionException;
@ -348,21 +353,49 @@ final class ChannelzProtoUtil {
}
static ChannelData extractChannelData(Channelz.ChannelStats stats) {
return ChannelData
.newBuilder()
.setTarget(stats.target)
ChannelData.Builder builder = ChannelData.newBuilder();
builder.setTarget(stats.target)
.setState(toChannelConnectivityState(stats.state))
.setCallsStarted(stats.callsStarted)
.setCallsSucceeded(stats.callsSucceeded)
.setCallsFailed(stats.callsFailed)
.setLastCallStartedTimestamp(Timestamps.fromMillis(stats.lastCallStartedMillis))
.build();
.setLastCallStartedTimestamp(Timestamps.fromMillis(stats.lastCallStartedMillis));
if (stats.channelTrace != null) {
builder.setTrace(toChannelTrace(stats.channelTrace));
}
return builder.build();
}
static ChannelConnectivityState toChannelConnectivityState(ConnectivityState s) {
return ChannelConnectivityState.newBuilder().setState(toState(s)).build();
}
private static ChannelTrace toChannelTrace(Channelz.ChannelTrace channelTrace) {
return ChannelTrace.newBuilder()
.setNumEventsLogged(channelTrace.numEventsLogged)
.setCreationTimestamp(Timestamps.fromNanos(channelTrace.creationTimeNanos))
.addAllEvents(toChannelTraceEvents(channelTrace.events))
.build();
}
private static List<ChannelTraceEvent> toChannelTraceEvents(List<Event> events) {
List<ChannelTraceEvent> channelTraceEvents = new ArrayList<ChannelTraceEvent>();
for (Event event : events) {
ChannelTraceEvent.Builder builder = ChannelTraceEvent.newBuilder()
.setDescription(event.description)
.setSeverity(Severity.valueOf(event.severity.name()))
.setTimestamp(Timestamps.fromNanos(event.timestampNanos));
if (event.channelRef != null) {
builder.setChannelRef(toChannelRef(event.channelRef));
}
if (event.subchannelRef != null) {
builder.setSubchannelRef(toSubchannelRef(event.subchannelRef));
}
channelTraceEvents.add(builder.build());
}
return Collections.unmodifiableList(channelTraceEvents);
}
static State toState(ConnectivityState state) {
if (state == null) {
return State.UNKNOWN;

View File

@ -41,6 +41,8 @@ import io.grpc.channelz.v1.ChannelConnectivityState;
import io.grpc.channelz.v1.ChannelConnectivityState.State;
import io.grpc.channelz.v1.ChannelData;
import io.grpc.channelz.v1.ChannelRef;
import io.grpc.channelz.v1.ChannelTrace;
import io.grpc.channelz.v1.ChannelTraceEvent;
import io.grpc.channelz.v1.GetChannelRequest;
import io.grpc.channelz.v1.GetServerSocketsResponse;
import io.grpc.channelz.v1.GetServersResponse;
@ -62,6 +64,8 @@ import io.grpc.channelz.v1.Subchannel;
import io.grpc.channelz.v1.SubchannelRef;
import io.grpc.internal.Channelz;
import io.grpc.internal.Channelz.ChannelStats;
import io.grpc.internal.Channelz.ChannelTrace.Event;
import io.grpc.internal.Channelz.ChannelTrace.Event.Severity;
import io.grpc.internal.Channelz.RootChannelList;
import io.grpc.internal.Channelz.ServerList;
import io.grpc.internal.Channelz.ServerSocketsList;
@ -79,6 +83,7 @@ import java.net.Inet4Address;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.security.cert.Certificate;
import java.util.Arrays;
import java.util.Collections;
import java.util.Map.Entry;
import org.junit.Test;
@ -310,6 +315,12 @@ public final class ChannelzProtoUtilTest {
.setPort(1000))
.build();
private final ChannelTrace channelTrace = ChannelTrace
.newBuilder()
.setNumEventsLogged(1234)
.setCreationTimestamp(Timestamps.fromNanos(1000))
.build();
@Test
public void toChannelRef() {
assertEquals(channelRef, ChannelzProtoUtil.toChannelRef(channel));
@ -832,6 +843,68 @@ public final class ChannelzProtoUtilTest {
.containsExactly(sockOptAdditional, otherOption);
}
@Test
public void channelTrace_withoutEvents() {
ChannelStats stats = toBuilder(channel.stats)
.setChannelTrace(new Channelz.ChannelTrace.Builder()
.setNumEventsLogged(1234)
.setCreationTimeNanos(1000)
.build())
.build();
ChannelData protoStats = channelData.toBuilder().setTrace(channelTrace).build();
assertEquals(ChannelzProtoUtil.extractChannelData(stats), protoStats);
}
@Test
public void channelTrace_withEvents() {
Event event1 = new Event.Builder()
.setDescription("event1")
.setSeverity(Severity.CT_ERROR)
.setTimestampNaonos(12)
.setSubchannelRef(subchannel)
.build();
Event event2 = new Event.Builder()
.setDescription("event2")
.setTimestampNaonos(34)
.setSeverity(Severity.CT_INFO)
.setChannelRef(channel)
.build();
ChannelStats stats =
toBuilder(channel.stats)
.setChannelTrace(
new Channelz.ChannelTrace.Builder()
.setNumEventsLogged(1234)
.setCreationTimeNanos(1000)
.setEvents(Arrays.asList(event1, event2))
.build())
.build();
ChannelTraceEvent protoEvent1 = ChannelTraceEvent
.newBuilder()
.setDescription("event1")
.setTimestamp(Timestamps.fromNanos(12))
.setSeverity(ChannelTraceEvent.Severity.CT_ERROR)
.setSubchannelRef(subchannelRef)
.build();
ChannelTraceEvent protoEvent2 = ChannelTraceEvent
.newBuilder()
.setDescription("event2")
.setTimestamp(Timestamps.fromNanos(34))
.setSeverity(ChannelTraceEvent.Severity.CT_INFO)
.setChannelRef(channelRef)
.build();
ChannelData protoStats = channelData
.toBuilder()
.setTrace(channelTrace
.toBuilder()
.addAllEvents(Arrays.asList(protoEvent1, protoEvent2))
.build())
.build();
assertEquals(ChannelzProtoUtil.extractChannelData(stats), protoStats);
}
private static ChannelStats.Builder toBuilder(ChannelStats stats) {
ChannelStats.Builder builder = new ChannelStats.Builder()
.setTarget(stats.target)

View File

@ -148,15 +148,16 @@ final class ChannelzTestHelper {
static final class TestChannel implements Instrumented<ChannelStats> {
private final LogId id = LogId.allocate("channel-or-subchannel");
ChannelStats stats = new ChannelStats(
/*target=*/ "sometarget",
/*state=*/ ConnectivityState.READY,
/*callsStarted=*/ 1,
/*callsSucceeded=*/ 2,
/*callsFailed=*/ 3,
/*lastCallStartedMillis=*/ 4,
/*subchannels=*/ Collections.<WithLogId>emptyList(),
/*sockets=*/ Collections.<WithLogId>emptyList());
ChannelStats stats = new ChannelStats.Builder()
.setTarget("sometarget")
.setState(ConnectivityState.READY)
.setCallsStarted(1)
.setCallsSucceeded(2)
.setCallsFailed(3)
.setLastCallStartedMillis(4)
.setSubchannels(Collections.<WithLogId>emptyList())
.setSockets(Collections.<WithLogId>emptyList())
.build();
@Override
public ListenableFuture<ChannelStats> getStats() {