1616
1717package io .grpc .netty ;
1818
19- import com .google .common .collect .ImmutableList ;
2019import io .grpc .DoubleHistogramMetricInstrument ;
2120import io .grpc .LongCounterMetricInstrument ;
2221import io .grpc .LongUpDownCounterMetricInstrument ;
22+ import io .grpc .MetricInstrument ;
2323import io .grpc .MetricInstrumentRegistry ;
2424import io .grpc .MetricRecorder ;
2525import io .netty .channel .Channel ;
2626import java .lang .reflect .Method ;
27+ import java .util .Arrays ;
2728import java .util .Collections ;
29+ import java .util .List ;
2830
2931final class TcpMetrics {
3032
@@ -38,64 +40,133 @@ final class TcpMetrics {
3840 // bytes_retransmitted, etc., are not
3941 // currently exposed by Netty's EpollTcpInfo.java wrapper around
4042 // getSockOpt(TCP_INFO)."
43+ /**
44+ * Safe metric registration or retrieval for environments where TcpMetrics might
45+ * be loaded multiple times (e.g., shaded and unshaded).
46+ */
47+ private static LongCounterMetricInstrument safelyRegisterLongCounter (
48+ MetricInstrumentRegistry registry , String name , String description , String unit ,
49+ List <String > requiredLabelKeys , List <String > optionalLabelKeys ) {
50+ try {
51+ return registry .registerLongCounter (name , description , unit , requiredLabelKeys ,
52+ optionalLabelKeys , false );
53+ } catch (IllegalStateException e ) {
54+ if (e .getMessage () != null && e .getMessage ().contains ("already exists" )) {
55+ for (MetricInstrument instrument : registry .getMetricInstruments ()) {
56+ if (instrument .getName ().equals (name )
57+ && instrument instanceof LongCounterMetricInstrument ) {
58+ return (LongCounterMetricInstrument ) instrument ;
59+ }
60+ }
61+ }
62+ throw e ;
63+ }
64+ }
65+
66+ private static LongUpDownCounterMetricInstrument safelyRegisterLongUpDownCounter (
67+ MetricInstrumentRegistry registry , String name , String description , String unit ,
68+ List <String > requiredLabelKeys , List <String > optionalLabelKeys ) {
69+ try {
70+ return registry .registerLongUpDownCounter (name , description , unit , requiredLabelKeys ,
71+ optionalLabelKeys , false );
72+ } catch (IllegalStateException e ) {
73+ if (e .getMessage () != null && e .getMessage ().contains ("already exists" )) {
74+ for (MetricInstrument instrument : registry .getMetricInstruments ()) {
75+ if (instrument .getName ().equals (name )
76+ && instrument instanceof LongUpDownCounterMetricInstrument ) {
77+ return (LongUpDownCounterMetricInstrument ) instrument ;
78+ }
79+ }
80+ }
81+ throw e ;
82+ }
83+ }
84+
85+ private static DoubleHistogramMetricInstrument safelyRegisterDoubleHistogram (
86+ MetricInstrumentRegistry registry , String name , String description , String unit ,
87+ List <Double > bucketBoundaries , List <String > requiredLabelKeys ,
88+ List <String > optionalLabelKeys ) {
89+ try {
90+ return registry .registerDoubleHistogram (name , description , unit , bucketBoundaries ,
91+ requiredLabelKeys , optionalLabelKeys , false );
92+ } catch (IllegalStateException e ) {
93+ if (e .getMessage () != null && e .getMessage ().contains ("already exists" )) {
94+ for (MetricInstrument instrument : registry .getMetricInstruments ()) {
95+ if (instrument .getName ().equals (name )
96+ && instrument instanceof DoubleHistogramMetricInstrument ) {
97+ return (DoubleHistogramMetricInstrument ) instrument ;
98+ }
99+ }
100+ }
101+ throw e ;
102+ }
103+ }
104+
41105 static {
42106 MetricInstrumentRegistry registry = MetricInstrumentRegistry .getDefaultRegistry ();
43- ImmutableList <String > requiredLabels = ImmutableList . of ("grpc.target" );
44- ImmutableList <String > optionalLabels = ImmutableList . of (
107+ List <String > requiredLabels = Collections . singletonList ("grpc.target" );
108+ List <String > optionalLabels = Arrays . asList (
45109 "network.local.address" ,
46110 "network.local.port" ,
47111 "network.peer.address" ,
48112 "network.peer.port"
49113 );
50114
51- connectionsCreated = registry . registerLongCounter (
52- "grpc.tcp.connections_created" ,
115+ connectionsCreated = safelyRegisterLongCounter ( registry ,
116+ "grpc.tcp.connections_created" ,
53117 "Number of TCP connections created." ,
54118 "{connection}" ,
55119 requiredLabels ,
56- optionalLabels ,
57- false
120+ optionalLabels
58121 );
59122
60- connectionCount = registry . registerLongUpDownCounter (
61- "grpc.tcp.connection_count" ,
62- "Number of active TCP connections." ,
63- "{connection}" ,
123+ connectionCount = safelyRegisterLongUpDownCounter ( registry ,
124+ "grpc.tcp.connection_count" ,
125+ "Number of currently open TCP connections." ,
126+ "{connection}" ,
64127 requiredLabels ,
65- optionalLabels ,
66- false
128+ optionalLabels
67129 );
68130
69- packetsRetransmitted = registry . registerLongCounter (
70- "grpc.tcp.packets_retransmitted" ,
71- "Total packets sent by TCP except those sent for the first time." ,
72- "{packet}" ,
73- requiredLabels ,
74- optionalLabels ,
75- false
76- );
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+ }
77139
78- recurringRetransmits = registry .registerLongCounter (
79- "grpc.tcp.recurring_retransmits" ,
80- "The number of times the latest TCP packet was retransmitted." ,
81- "{packet}" ,
82- requiredLabels ,
83- optionalLabels ,
84- false
85- );
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 );
86147
87- minRtt = registry .registerDoubleHistogram (
88- "grpc.tcp.min_rtt" ,
89- "TCP's current estimate of minimum round trip time (RTT)." ,
90- "s" ,
91- ImmutableList .of (
92- 0.0001 , 0.0005 , 0.001 , 0.005 , 0.01 , 0.05 , 0.1 , 0.5 , 1.0 , 5.0 , 10.0 , 50.0 , 100.0 , 500.0 ,
93- 1000.0
94- ),
95- requiredLabels ,
96- optionalLabels ,
97- false
98- );
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+ }
99170 }
100171
101172
0 commit comments