3030
3131final class TcpMetrics {
3232
33- static final LongCounterMetricInstrument connectionsCreated ;
34- static final LongUpDownCounterMetricInstrument connectionCount ;
35- static final LongCounterMetricInstrument packetsRetransmitted ;
36- static final LongCounterMetricInstrument recurringRetransmits ;
37- static final DoubleHistogramMetricInstrument minRtt ;
38-
39- // Note: Metrics like delivery_rate, bytes_sent, packets_sent,
40- // bytes_retransmitted, etc., are not
41- // currently exposed by Netty's EpollTcpInfo.java wrapper around
42- // getSockOpt(TCP_INFO)."
33+ private static final Metrics DEFAULT_METRICS ;
34+
35+ static {
36+ boolean epollAvailable = false ;
37+ try {
38+ Class <?> epollClass = Class .forName ("io.netty.channel.epoll.Epoll" );
39+ Method isAvailableMethod = epollClass .getDeclaredMethod ("isAvailable" );
40+ epollAvailable = (Boolean ) isAvailableMethod .invoke (null );
41+ } catch (Throwable t ) {
42+ // Ignored
43+ }
44+ DEFAULT_METRICS = new Metrics (MetricInstrumentRegistry .getDefaultRegistry (), epollAvailable );
45+ }
46+
47+ static Metrics getDefaultMetrics () {
48+ return DEFAULT_METRICS ;
49+ }
50+
51+ static final class Metrics {
52+ final LongCounterMetricInstrument connectionsCreated ;
53+ final LongUpDownCounterMetricInstrument connectionCount ;
54+ final LongCounterMetricInstrument packetsRetransmitted ;
55+ final LongCounterMetricInstrument recurringRetransmits ;
56+ final DoubleHistogramMetricInstrument minRtt ;
57+
58+ Metrics (MetricInstrumentRegistry registry , boolean epollAvailable ) {
59+ List <String > requiredLabels = Collections .singletonList ("grpc.target" );
60+ List <String > optionalLabels = Arrays .asList (
61+ "network.local.address" ,
62+ "network.local.port" ,
63+ "network.peer.address" ,
64+ "network.peer.port" );
65+
66+ connectionsCreated = safelyRegisterLongCounter (registry ,
67+ "grpc.tcp.connections_created" ,
68+ "Number of TCP connections created." ,
69+ "{connection}" ,
70+ requiredLabels ,
71+ optionalLabels );
72+
73+ connectionCount = safelyRegisterLongUpDownCounter (registry ,
74+ "grpc.tcp.connection_count" ,
75+ "Number of currently open TCP connections." ,
76+ "{connection}" ,
77+ requiredLabels ,
78+ optionalLabels );
79+
80+ if (epollAvailable ) {
81+ packetsRetransmitted = safelyRegisterLongCounter (registry ,
82+ "grpc.tcp.packets_retransmitted" ,
83+ "Total number of packets retransmitted for a single TCP connection." ,
84+ "{packet}" ,
85+ requiredLabels ,
86+ optionalLabels );
87+
88+ recurringRetransmits = safelyRegisterLongCounter (registry ,
89+ "grpc.tcp.recurring_retransmits" ,
90+ "Total number of unacknowledged packets to be retransmitted "
91+ + "since the last acknowledgment." ,
92+ "{packet}" ,
93+ requiredLabels ,
94+ optionalLabels );
95+
96+ minRtt = safelyRegisterDoubleHistogram (registry ,
97+ "grpc.tcp.min_rtt" ,
98+ "Minimum RTT observed for a single TCP connection." ,
99+ "s" ,
100+ Arrays .asList (0.0001 , 0.0005 , 0.001 , 0.005 , 0.01 , 0.05 , 0.1 , 0.25 , 0.5 , 1.0 , 2.5 ,
101+ 5.0 , 10.0 , 25.0 , 50.0 , 100.0 , 250.0 ),
102+ requiredLabels ,
103+ optionalLabels );
104+ } else {
105+ packetsRetransmitted = null ;
106+ recurringRetransmits = null ;
107+ minRtt = null ;
108+ }
109+ }
110+ }
111+
43112 /**
44113 * Safe metric registration or retrieval for environments where TcpMetrics might
45114 * be loaded multiple times (e.g., shaded and unshaded).
@@ -102,81 +171,30 @@ private static DoubleHistogramMetricInstrument safelyRegisterDoubleHistogram(
102171 }
103172 }
104173
105- static {
106- MetricInstrumentRegistry registry = MetricInstrumentRegistry .getDefaultRegistry ();
107- List <String > requiredLabels = Collections .singletonList ("grpc.target" );
108- List <String > optionalLabels = Arrays .asList (
109- "network.local.address" ,
110- "network.local.port" ,
111- "network.peer.address" ,
112- "network.peer.port"
113- );
114-
115- connectionsCreated = safelyRegisterLongCounter (registry ,
116- "grpc.tcp.connections_created" ,
117- "Number of TCP connections created." ,
118- "{connection}" ,
119- requiredLabels ,
120- optionalLabels
121- );
122-
123- connectionCount = safelyRegisterLongUpDownCounter (registry ,
124- "grpc.tcp.connection_count" ,
125- "Number of currently open TCP connections." ,
126- "{connection}" ,
127- requiredLabels ,
128- optionalLabels
129- );
130-
131- boolean epollAvailable = false ;
132- try {
133- Class <?> epollClass = Class .forName ("io.netty.channel.epoll.Epoll" );
134- Method isAvailableMethod = epollClass .getDeclaredMethod ("isAvailable" );
135- epollAvailable = (Boolean ) isAvailableMethod .invoke (null );
136- } catch (Throwable t ) {
137- // Ignored
138- }
139-
140- if (epollAvailable ) {
141- packetsRetransmitted = safelyRegisterLongCounter (registry ,
142- "grpc.tcp.packets_retransmitted" ,
143- "Total number of packets retransmitted for a single TCP connection." ,
144- "{packet}" ,
145- requiredLabels ,
146- optionalLabels );
147-
148- recurringRetransmits = safelyRegisterLongCounter (registry ,
149- "grpc.tcp.recurring_retransmits" ,
150- "Total number of unacknowledged packets to be retransmitted "
151- + "since the last acknowledgment." ,
152- "{packet}" ,
153- requiredLabels ,
154- optionalLabels );
155-
156- minRtt = safelyRegisterDoubleHistogram (registry ,
157- "grpc.tcp.min_rtt" ,
158- "Minimum RTT observed for a single TCP connection." ,
159- "s" ,
160- Arrays .asList (0.0001 , 0.0005 , 0.001 , 0.005 , 0.01 , 0.05 , 0.1 , 0.25 , 0.5 , 1.0 , 2.5 ,
161- 5.0 , 10.0 , 25.0 , 50.0 , 100.0 , 250.0 ),
162- requiredLabels ,
163- optionalLabels );
164- } else {
165- // Initialize to null if epoll is not available, as these metrics won't be used.
166- packetsRetransmitted = null ;
167- recurringRetransmits = null ;
168- minRtt = null ;
169- }
170- }
171-
172-
173174 static final class Tracker {
174175 private final MetricRecorder metricRecorder ;
175176 private final String target ;
177+ private final Metrics metrics ;
178+ private final String epollSocketChannelClassName ;
179+ private final String epollTcpInfoClassName ;
176180
177181 Tracker (MetricRecorder metricRecorder , String target ) {
182+ this (metricRecorder , target , DEFAULT_METRICS );
183+ }
184+
185+ Tracker (MetricRecorder metricRecorder , String target , Metrics metrics ) {
186+ this (metricRecorder , target , metrics ,
187+ "io.netty.channel.epoll.EpollSocketChannel" ,
188+ "io.netty.channel.epoll.EpollTcpInfo" );
189+ }
190+
191+ Tracker (MetricRecorder metricRecorder , String target , Metrics metrics ,
192+ String epollSocketChannelClassName , String epollTcpInfoClassName ) {
178193 this .metricRecorder = metricRecorder ;
179194 this .target = target ;
195+ this .metrics = metrics ;
196+ this .epollSocketChannelClassName = epollSocketChannelClassName ;
197+ this .epollTcpInfoClassName = epollTcpInfoClassName ;
180198 }
181199
182200 private static final long RECORD_INTERVAL_MILLIS ;
@@ -200,9 +218,9 @@ static final class Tracker {
200218 void channelActive (Channel channel ) {
201219 if (metricRecorder != null && target != null ) {
202220 java .util .List <String > labelValues = getLabelValues (channel );
203- metricRecorder .addLongCounter (TcpMetrics .connectionsCreated , 1 ,
221+ metricRecorder .addLongCounter (metrics .connectionsCreated , 1 ,
204222 Collections .singletonList (target ), labelValues );
205- metricRecorder .addLongUpDownCounter (TcpMetrics .connectionCount , 1 ,
223+ metricRecorder .addLongUpDownCounter (metrics .connectionCount , 1 ,
206224 Collections .singletonList (target ), labelValues );
207225 scheduleNextReport (channel );
208226 }
@@ -240,7 +258,7 @@ void channelInactive(Channel channel) {
240258 }
241259 if (metricRecorder != null && target != null ) {
242260 java .util .List <String > labelValues = getLabelValues (channel );
243- metricRecorder .addLongUpDownCounter (TcpMetrics .connectionCount , -1 ,
261+ metricRecorder .addLongUpDownCounter (metrics .connectionCount , -1 ,
244262 Collections .singletonList (target ), labelValues );
245263 // Final collection on close
246264 recordTcpInfo (channel );
@@ -253,28 +271,33 @@ private void recordTcpInfo(Channel channel) {
253271 }
254272 java .util .List <String > labelValues = getLabelValues (channel );
255273 try {
256- if (channel .getClass ().getName ().equals ("io.netty.channel.epoll.EpollSocketChannel" )) {
257- Method tcpInfoMethod = channel .getClass ().getMethod ("tcpInfo" ,
258- Class .forName ("io.netty.channel.epoll.EpollTcpInfo" ));
259- Object info = Class .forName ("io.netty.channel.epoll.EpollTcpInfo" )
260- .getDeclaredConstructor ().newInstance ();
274+ if (channel .getClass ().getName ().equals (epollSocketChannelClassName )) {
275+ Class <?> tcpInfoClass = Class .forName (epollTcpInfoClassName );
276+ Method tcpInfoMethod = channel .getClass ().getMethod ("tcpInfo" , tcpInfoClass );
277+ Object info = tcpInfoClass .getDeclaredConstructor ().newInstance ();
261278 tcpInfoMethod .invoke (channel , info );
262279
263- Method totalRetransMethod = info . getClass () .getMethod ("totalRetrans" );
264- Method retransmitsMethod = info . getClass () .getMethod ("retransmits" );
265- Method rttMethod = info . getClass () .getMethod ("rtt" );
280+ Method totalRetransMethod = tcpInfoClass .getMethod ("totalRetrans" );
281+ Method retransmitsMethod = tcpInfoClass .getMethod ("retransmits" );
282+ Method rttMethod = tcpInfoClass .getMethod ("rtt" );
266283
267284 long totalRetrans = (Long ) totalRetransMethod .invoke (info );
268285 int retransmits = (Integer ) retransmitsMethod .invoke (info );
269286 long rtt = (Long ) rttMethod .invoke (info );
270287
271- metricRecorder .addLongCounter (TcpMetrics .packetsRetransmitted , totalRetrans ,
272- Collections .singletonList (target ), labelValues );
273- metricRecorder .addLongCounter (TcpMetrics .recurringRetransmits , retransmits ,
274- Collections .singletonList (target ), labelValues );
275- metricRecorder .recordDoubleHistogram (TcpMetrics .minRtt ,
276- rtt / 1000000.0 , // Convert microseconds to seconds
277- Collections .singletonList (target ), labelValues );
288+ if (metrics .packetsRetransmitted != null ) {
289+ metricRecorder .addLongCounter (metrics .packetsRetransmitted , totalRetrans ,
290+ Collections .singletonList (target ), labelValues );
291+ }
292+ if (metrics .recurringRetransmits != null ) {
293+ metricRecorder .addLongCounter (metrics .recurringRetransmits , retransmits ,
294+ Collections .singletonList (target ), labelValues );
295+ }
296+ if (metrics .minRtt != null ) {
297+ metricRecorder .recordDoubleHistogram (metrics .minRtt ,
298+ rtt / 1000000.0 , // Convert microseconds to seconds
299+ Collections .singletonList (target ), labelValues );
300+ }
278301 }
279302 } catch (Throwable t ) {
280303 // Epoll not available or error getting tcp_info, just ignore.
0 commit comments