Skip to content

Commit b170334

Browse files
authoredNov 14, 2024··
Make channelz work with proto lite (#11685)
Allows android apps to expose internal grpc state for debugging.
1 parent 921f88a commit b170334

File tree

2 files changed

+149
-87
lines changed

2 files changed

+149
-87
lines changed
 

‎services/src/main/java/io/grpc/protobuf/services/ChannelzProtoUtil.java

+53-19
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import com.google.protobuf.Any;
2222
import com.google.protobuf.ByteString;
2323
import com.google.protobuf.Int64Value;
24+
import com.google.protobuf.MessageLite;
2425
import com.google.protobuf.util.Durations;
2526
import com.google.protobuf.util.Timestamps;
2627
import io.grpc.ConnectivityState;
@@ -79,6 +80,8 @@
7980

8081
/**
8182
* A static utility class for turning internal data structures into protos.
83+
*
84+
* <p>Works with both regular and lite protos.
8285
*/
8386
final class ChannelzProtoUtil {
8487
private static final Logger logger = Logger.getLogger(ChannelzProtoUtil.class.getName());
@@ -254,22 +257,20 @@ static SocketOption toSocketOptionLinger(int lingerSeconds) {
254257
} else {
255258
lingerOpt = SocketOptionLinger.getDefaultInstance();
256259
}
257-
return SocketOption
258-
.newBuilder()
260+
return SocketOption.newBuilder()
259261
.setName(SO_LINGER)
260-
.setAdditional(Any.pack(lingerOpt))
262+
.setAdditional(packToAny("SocketOptionLinger", lingerOpt))
261263
.build();
262264
}
263265

264266
static SocketOption toSocketOptionTimeout(String name, int timeoutMillis) {
265267
Preconditions.checkNotNull(name);
266-
return SocketOption
267-
.newBuilder()
268+
return SocketOption.newBuilder()
268269
.setName(name)
269270
.setAdditional(
270-
Any.pack(
271-
SocketOptionTimeout
272-
.newBuilder()
271+
packToAny(
272+
"SocketOptionTimeout",
273+
SocketOptionTimeout.newBuilder()
273274
.setDuration(Durations.fromMillis(timeoutMillis))
274275
.build()))
275276
.build();
@@ -307,10 +308,9 @@ static SocketOption toSocketOptionTcpInfo(InternalChannelz.TcpInfo i) {
307308
.setTcpiAdvmss(i.advmss)
308309
.setTcpiReordering(i.reordering)
309310
.build();
310-
return SocketOption
311-
.newBuilder()
311+
return SocketOption.newBuilder()
312312
.setName(TCP_INFO)
313-
.setAdditional(Any.pack(tcpInfo))
313+
.setAdditional(packToAny("SocketOptionTcpInfo", tcpInfo))
314314
.build();
315315
}
316316

@@ -380,10 +380,11 @@ private static ChannelTrace toChannelTrace(InternalChannelz.ChannelTrace channel
380380
private static List<ChannelTraceEvent> toChannelTraceEvents(List<Event> events) {
381381
List<ChannelTraceEvent> channelTraceEvents = new ArrayList<>();
382382
for (Event event : events) {
383-
ChannelTraceEvent.Builder builder = ChannelTraceEvent.newBuilder()
384-
.setDescription(event.description)
385-
.setSeverity(Severity.valueOf(event.severity.name()))
386-
.setTimestamp(Timestamps.fromNanos(event.timestampNanos));
383+
ChannelTraceEvent.Builder builder =
384+
ChannelTraceEvent.newBuilder()
385+
.setDescription(event.description)
386+
.setSeverity(toSeverity(event.severity))
387+
.setTimestamp(Timestamps.fromNanos(event.timestampNanos));
387388
if (event.channelRef != null) {
388389
builder.setChannelRef(toChannelRef(event.channelRef));
389390
}
@@ -395,14 +396,39 @@ private static List<ChannelTraceEvent> toChannelTraceEvents(List<Event> events)
395396
return Collections.unmodifiableList(channelTraceEvents);
396397
}
397398

399+
static Severity toSeverity(Event.Severity severity) {
400+
if (severity == null) {
401+
return Severity.CT_UNKNOWN;
402+
}
403+
switch (severity) {
404+
case CT_INFO:
405+
return Severity.CT_INFO;
406+
case CT_ERROR:
407+
return Severity.CT_ERROR;
408+
case CT_WARNING:
409+
return Severity.CT_WARNING;
410+
default:
411+
return Severity.CT_UNKNOWN;
412+
}
413+
}
414+
398415
static State toState(ConnectivityState state) {
399416
if (state == null) {
400417
return State.UNKNOWN;
401418
}
402-
try {
403-
return Enum.valueOf(State.class, state.name());
404-
} catch (IllegalArgumentException e) {
405-
return State.UNKNOWN;
419+
switch (state) {
420+
case IDLE:
421+
return State.IDLE;
422+
case READY:
423+
return State.READY;
424+
case CONNECTING:
425+
return State.CONNECTING;
426+
case SHUTDOWN:
427+
return State.SHUTDOWN;
428+
case TRANSIENT_FAILURE:
429+
return State.TRANSIENT_FAILURE;
430+
default:
431+
return State.UNKNOWN;
406432
}
407433
}
408434

@@ -468,4 +494,12 @@ private static <T> T getFuture(ListenableFuture<T> future) {
468494
throw Status.INTERNAL.withCause(e).asRuntimeException();
469495
}
470496
}
497+
498+
// A version of Any.pack() that works with protolite.
499+
private static Any packToAny(String typeName, MessageLite value) {
500+
return Any.newBuilder()
501+
.setTypeUrl("type.googleapis.com/grpc.channelz.v1." + typeName)
502+
.setValue(value.toByteString())
503+
.build();
504+
}
471505
}

‎services/src/test/java/io/grpc/protobuf/services/ChannelzProtoUtilTest.java

+96-68
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
import com.google.protobuf.Any;
2828
import com.google.protobuf.ByteString;
2929
import com.google.protobuf.Int64Value;
30-
import com.google.protobuf.Message;
30+
import com.google.protobuf.MessageLite;
3131
import com.google.protobuf.util.Durations;
3232
import com.google.protobuf.util.Timestamps;
3333
import io.grpc.ConnectivityState;
@@ -154,33 +154,44 @@ public final class ChannelzProtoUtilTest {
154154
.setData(serverData)
155155
.build();
156156

157-
private final SocketOption sockOptLingerDisabled = SocketOption
158-
.newBuilder()
159-
.setName("SO_LINGER")
160-
.setAdditional(
161-
Any.pack(SocketOptionLinger.getDefaultInstance()))
162-
.build();
163-
164-
private final SocketOption sockOptlinger10s = SocketOption
165-
.newBuilder()
166-
.setName("SO_LINGER")
167-
.setAdditional(
168-
Any.pack(SocketOptionLinger
169-
.newBuilder()
170-
.setActive(true)
171-
.setDuration(Durations.fromSeconds(10))
172-
.build()))
173-
.build();
174-
175-
private final SocketOption sockOptTimeout200ms = SocketOption
176-
.newBuilder()
177-
.setName("SO_TIMEOUT")
178-
.setAdditional(
179-
Any.pack(SocketOptionTimeout
180-
.newBuilder()
181-
.setDuration(Durations.fromMillis(200))
182-
.build())
183-
).build();
157+
private final SocketOption sockOptLingerDisabled =
158+
SocketOption.newBuilder()
159+
.setName("SO_LINGER")
160+
.setAdditional(
161+
Any.newBuilder()
162+
.setTypeUrl("type.googleapis.com/grpc.channelz.v1.SocketOptionLinger")
163+
.setValue(SocketOptionLinger.getDefaultInstance().toByteString())
164+
.build())
165+
.build();
166+
167+
private final SocketOption sockOptlinger10s =
168+
SocketOption.newBuilder()
169+
.setName("SO_LINGER")
170+
.setAdditional(
171+
Any.newBuilder()
172+
.setTypeUrl("type.googleapis.com/grpc.channelz.v1.SocketOptionLinger")
173+
.setValue(
174+
SocketOptionLinger.newBuilder()
175+
.setActive(true)
176+
.setDuration(Durations.fromSeconds(10))
177+
.build()
178+
.toByteString())
179+
.build())
180+
.build();
181+
182+
private final SocketOption sockOptTimeout200ms =
183+
SocketOption.newBuilder()
184+
.setName("SO_TIMEOUT")
185+
.setAdditional(
186+
Any.newBuilder()
187+
.setTypeUrl("type.googleapis.com/grpc.channelz.v1.SocketOptionTimeout")
188+
.setValue(
189+
SocketOptionTimeout.newBuilder()
190+
.setDuration(Durations.fromMillis(200))
191+
.build()
192+
.toByteString())
193+
.build())
194+
.build();
184195

185196
private final SocketOption sockOptAdditional = SocketOption
186197
.newBuilder()
@@ -221,43 +232,46 @@ public final class ChannelzProtoUtilTest {
221232
.setReordering(728)
222233
.build();
223234

224-
private final SocketOption socketOptionTcpInfo = SocketOption
225-
.newBuilder()
226-
.setName("TCP_INFO")
227-
.setAdditional(
228-
Any.pack(
229-
SocketOptionTcpInfo.newBuilder()
230-
.setTcpiState(70)
231-
.setTcpiCaState(71)
232-
.setTcpiRetransmits(72)
233-
.setTcpiProbes(73)
234-
.setTcpiBackoff(74)
235-
.setTcpiOptions(75)
236-
.setTcpiSndWscale(76)
237-
.setTcpiRcvWscale(77)
238-
.setTcpiRto(78)
239-
.setTcpiAto(79)
240-
.setTcpiSndMss(710)
241-
.setTcpiRcvMss(711)
242-
.setTcpiUnacked(712)
243-
.setTcpiSacked(713)
244-
.setTcpiLost(714)
245-
.setTcpiRetrans(715)
246-
.setTcpiFackets(716)
247-
.setTcpiLastDataSent(717)
248-
.setTcpiLastAckSent(718)
249-
.setTcpiLastDataRecv(719)
250-
.setTcpiLastAckRecv(720)
251-
.setTcpiPmtu(721)
252-
.setTcpiRcvSsthresh(722)
253-
.setTcpiRtt(723)
254-
.setTcpiRttvar(724)
255-
.setTcpiSndSsthresh(725)
256-
.setTcpiSndCwnd(726)
257-
.setTcpiAdvmss(727)
258-
.setTcpiReordering(728)
259-
.build()))
260-
.build();
235+
private final SocketOption socketOptionTcpInfo =
236+
SocketOption.newBuilder()
237+
.setName("TCP_INFO")
238+
.setAdditional(
239+
Any.newBuilder()
240+
.setTypeUrl("type.googleapis.com/grpc.channelz.v1.SocketOptionTcpInfo")
241+
.setValue(
242+
SocketOptionTcpInfo.newBuilder()
243+
.setTcpiState(70)
244+
.setTcpiCaState(71)
245+
.setTcpiRetransmits(72)
246+
.setTcpiProbes(73)
247+
.setTcpiBackoff(74)
248+
.setTcpiOptions(75)
249+
.setTcpiSndWscale(76)
250+
.setTcpiRcvWscale(77)
251+
.setTcpiRto(78)
252+
.setTcpiAto(79)
253+
.setTcpiSndMss(710)
254+
.setTcpiRcvMss(711)
255+
.setTcpiUnacked(712)
256+
.setTcpiSacked(713)
257+
.setTcpiLost(714)
258+
.setTcpiRetrans(715)
259+
.setTcpiFackets(716)
260+
.setTcpiLastDataSent(717)
261+
.setTcpiLastAckSent(718)
262+
.setTcpiLastDataRecv(719)
263+
.setTcpiLastAckRecv(720)
264+
.setTcpiPmtu(721)
265+
.setTcpiRcvSsthresh(722)
266+
.setTcpiRtt(723)
267+
.setTcpiRttvar(724)
268+
.setTcpiSndSsthresh(725)
269+
.setTcpiSndCwnd(726)
270+
.setTcpiAdvmss(727)
271+
.setTcpiReordering(728)
272+
.build()
273+
.toByteString()))
274+
.build();
261275

262276
private final TestListenSocket listenSocket = new TestListenSocket();
263277
private final SocketRef listenSocketRef = SocketRef
@@ -336,6 +350,16 @@ public void toServerRef() {
336350
assertEquals(serverRef, ChannelzProtoUtil.toServerRef(server));
337351
}
338352

353+
@Test
354+
public void toSeverity() {
355+
for (Severity severity : Severity.values()) {
356+
assertEquals(
357+
severity.name(),
358+
ChannelzProtoUtil.toSeverity(severity).name()); // OK because test isn't proguarded.
359+
}
360+
assertEquals(ChannelTraceEvent.Severity.CT_UNKNOWN, ChannelzProtoUtil.toSeverity(null));
361+
}
362+
339363
@Test
340364
public void toSocketRef() {
341365
assertEquals(socketRef, ChannelzProtoUtil.toSocketRef(socket));
@@ -346,7 +370,7 @@ public void toState() {
346370
for (ConnectivityState connectivityState : ConnectivityState.values()) {
347371
assertEquals(
348372
connectivityState.name(),
349-
ChannelzProtoUtil.toState(connectivityState).getValueDescriptor().getName());
373+
ChannelzProtoUtil.toState(connectivityState).name()); // OK because test isn't proguarded.
350374
}
351375
assertEquals(State.UNKNOWN, ChannelzProtoUtil.toState(null));
352376
}
@@ -475,8 +499,12 @@ public void socketSecurityTls() throws Exception {
475499
@Test
476500
public void socketSecurityOther() throws Exception {
477501
// what is packed here is not important, just pick some proto message
478-
Message contents = GetChannelRequest.newBuilder().setChannelId(1).build();
479-
Any packed = Any.pack(contents);
502+
MessageLite contents = GetChannelRequest.newBuilder().setChannelId(1).build();
503+
Any packed =
504+
Any.newBuilder()
505+
.setTypeUrl("type.googleapis.com/grpc.channelz.v1.GetChannelRequest")
506+
.setValue(contents.toByteString())
507+
.build();
480508
socket.security
481509
= new InternalChannelz.Security(
482510
new InternalChannelz.OtherSecurity("other_security", packed));

0 commit comments

Comments
 (0)
Please sign in to comment.