diff options
author | zpencer <spencerfang@google.com> | 2018-03-30 08:48:37 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-03-30 08:48:37 -0700 |
commit | 7c37f1d32b9dc11027ff1ba946303f5a11dbfe00 (patch) | |
tree | 8323666a75669ee53e6740a78069539e309beda1 /netty | |
parent | 2a95e3825753a455810a93890c36348e7815b4f9 (diff) | |
download | grpc-grpc-java-7c37f1d32b9dc11027ff1ba946303f5a11dbfe00.tar.gz |
core,netty,okhttp,services: expose socket options to channelz (#4228)
For okhttp, expose the standard options from the Socket object.
For netty, expose all the `io.netty.channel.ChannelOption`s of the
`channel.config()`.
Diffstat (limited to 'netty')
4 files changed, 90 insertions, 0 deletions
diff --git a/netty/src/main/java/io/grpc/netty/NettyClientTransport.java b/netty/src/main/java/io/grpc/netty/NettyClientTransport.java index 87b11ddf9..0b3c48b41 100644 --- a/netty/src/main/java/io/grpc/netty/NettyClientTransport.java +++ b/netty/src/main/java/io/grpc/netty/NettyClientTransport.java @@ -323,6 +323,7 @@ class NettyClientTransport implements ConnectionClientTransport { transportTracer.getStats(), channel.localAddress(), channel.remoteAddress(), + Utils.getSocketOptions(channel), new Security())); return result; } @@ -335,6 +336,7 @@ class NettyClientTransport implements ConnectionClientTransport { transportTracer.getStats(), channel.localAddress(), channel.remoteAddress(), + Utils.getSocketOptions(channel), new Security())); } }); diff --git a/netty/src/main/java/io/grpc/netty/NettyServerTransport.java b/netty/src/main/java/io/grpc/netty/NettyServerTransport.java index 73c748b1b..fe905bb2d 100644 --- a/netty/src/main/java/io/grpc/netty/NettyServerTransport.java +++ b/netty/src/main/java/io/grpc/netty/NettyServerTransport.java @@ -206,6 +206,7 @@ class NettyServerTransport implements ServerTransport { transportTracer.getStats(), channel.localAddress(), channel.remoteAddress(), + Utils.getSocketOptions(channel), /*security=*/ null)); return result; } @@ -218,6 +219,7 @@ class NettyServerTransport implements ServerTransport { transportTracer.getStats(), channel.localAddress(), channel.remoteAddress(), + Utils.getSocketOptions(channel), /*security=*/ null)); } }); diff --git a/netty/src/main/java/io/grpc/netty/Utils.java b/netty/src/main/java/io/grpc/netty/Utils.java index 5dda2ad80..473a4c8ef 100644 --- a/netty/src/main/java/io/grpc/netty/Utils.java +++ b/netty/src/main/java/io/grpc/netty/Utils.java @@ -19,6 +19,8 @@ package io.grpc.netty; import static io.grpc.internal.GrpcUtil.CONTENT_TYPE_KEY; import static io.grpc.internal.TransportFrameUtil.toHttp2Headers; import static io.grpc.internal.TransportFrameUtil.toRawSerializedHeaders; +import static io.netty.channel.ChannelOption.SO_LINGER; +import static io.netty.channel.ChannelOption.SO_TIMEOUT; import static io.netty.util.CharsetUtil.UTF_8; import com.google.common.annotations.VisibleForTesting; @@ -26,9 +28,13 @@ import com.google.common.base.Preconditions; import io.grpc.InternalMetadata; import io.grpc.Metadata; import io.grpc.Status; +import io.grpc.internal.Channelz; import io.grpc.internal.GrpcUtil; import io.grpc.internal.SharedResourceHolder.Resource; import io.grpc.netty.GrpcHttp2HeadersUtils.GrpcHttp2InboundHeaders; +import io.netty.channel.Channel; +import io.netty.channel.ChannelConfig; +import io.netty.channel.ChannelOption; import io.netty.channel.EventLoopGroup; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.handler.codec.http2.Http2Exception; @@ -38,6 +44,7 @@ import io.netty.util.concurrent.DefaultThreadFactory; import java.io.IOException; import java.nio.channels.ClosedChannelException; import java.util.Map; +import java.util.Map.Entry; import java.util.concurrent.ThreadFactory; import java.util.concurrent.TimeUnit; @@ -201,6 +208,36 @@ class Utils { } } + static Channelz.SocketOptions getSocketOptions(Channel channel) { + ChannelConfig config = channel.config(); + Channelz.SocketOptions.Builder b = new Channelz.SocketOptions.Builder(); + + // The API allows returning null but not sure if it can happen in practice. + // Let's be paranoid and do null checking just in case. + Integer lingerSeconds = config.getOption(SO_LINGER); + if (lingerSeconds != null) { + b.setSocketOptionLingerSeconds(lingerSeconds); + } + + Integer timeoutMillis = config.getOption(SO_TIMEOUT); + if (timeoutMillis != null) { + // in java, SO_TIMEOUT only applies to receiving + b.setSocketOptionTimeoutMillis(timeoutMillis); + } + + for (Entry<ChannelOption<?>, Object> opt : config.getOptions().entrySet()) { + ChannelOption<?> key = opt.getKey(); + // Constants are pooled, so there should only be one instance of each constant + if (key.equals(SO_LINGER) || key.equals(SO_TIMEOUT)) { + continue; + } + Object value = opt.getValue(); + // zpencer: Can a netty option be null? + b.addOption(key.name(), String.valueOf(value)); + } + return b.build(); + } + private Utils() { // Prevents instantiation } diff --git a/netty/src/test/java/io/grpc/netty/UtilsTest.java b/netty/src/test/java/io/grpc/netty/UtilsTest.java index ead175667..372c451c6 100644 --- a/netty/src/test/java/io/grpc/netty/UtilsTest.java +++ b/netty/src/test/java/io/grpc/netty/UtilsTest.java @@ -17,14 +17,23 @@ package io.grpc.netty; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; import static org.junit.Assert.assertSame; import com.google.common.base.MoreObjects; import com.google.common.truth.Truth; import io.grpc.Metadata; import io.grpc.Status; +import io.grpc.internal.Channelz; +import io.grpc.internal.Channelz.SocketOptions; import io.grpc.internal.GrpcUtil; +import io.netty.channel.Channel; +import io.netty.channel.ChannelOption; import io.netty.channel.ConnectTimeoutException; +import io.netty.channel.WriteBufferWaterMark; +import io.netty.channel.embedded.EmbeddedChannel; +import io.netty.channel.socket.nio.NioSocketChannel; +import io.netty.channel.socket.oio.OioSocketChannel; import io.netty.handler.codec.http2.DefaultHttp2Headers; import io.netty.handler.codec.http2.Http2Error; import io.netty.handler.codec.http2.Http2Exception; @@ -118,6 +127,46 @@ public class UtilsTest { assertEquals(Utils.CONTENT_TYPE_GRPC, headers.get(GrpcUtil.CONTENT_TYPE_KEY.name())); } + @Test + public void channelOptionsTest_noLinger() { + Channel channel = new EmbeddedChannel(); + assertNull(channel.config().getOption(ChannelOption.SO_LINGER)); + Channelz.SocketOptions socketOptions = Utils.getSocketOptions(channel); + assertNull(socketOptions.lingerSeconds); + } + + @Test + public void channelOptionsTest_oio() { + Channel channel = new OioSocketChannel(); + SocketOptions socketOptions = setAndValidateGeneric(channel); + assertEquals(250, (int) socketOptions.soTimeoutMillis); + } + + @Test + public void channelOptionsTest_nio() { + Channel channel = new NioSocketChannel(); + SocketOptions socketOptions = setAndValidateGeneric(channel); + assertNull(socketOptions.soTimeoutMillis); + } + + private static Channelz.SocketOptions setAndValidateGeneric(Channel channel) { + channel.config().setOption(ChannelOption.SO_LINGER, 3); + // only applicable for OIO channels: + channel.config().setOption(ChannelOption.SO_TIMEOUT, 250); + // Test some arbitrarily chosen options with a non numeric values + channel.config().setOption(ChannelOption.SO_KEEPALIVE, true); + WriteBufferWaterMark writeBufWaterMark = new WriteBufferWaterMark(10, 20); + channel.config().setOption(ChannelOption.WRITE_BUFFER_WATER_MARK, writeBufWaterMark); + + Channelz.SocketOptions socketOptions = Utils.getSocketOptions(channel); + assertEquals(3, (int) socketOptions.lingerSeconds); + assertEquals("true", socketOptions.others.get("SO_KEEPALIVE")); + assertEquals( + writeBufWaterMark.toString(), + socketOptions.others.get(ChannelOption.WRITE_BUFFER_WATER_MARK.toString())); + return socketOptions; + } + private static void assertStatusEquals(Status expected, Status actual) { assertEquals(expected.getCode(), actual.getCode()); Truth.assertThat(MoreObjects.firstNonNull(actual.getDescription(), "")) |