1919import static com .google .common .base .Preconditions .checkNotNull ;
2020import static io .grpc .opentelemetry .internal .OpenTelemetryConstants .BACKEND_SERVICE_KEY ;
2121import static io .grpc .opentelemetry .internal .OpenTelemetryConstants .BAGGAGE_KEY ;
22+ import static io .grpc .opentelemetry .internal .OpenTelemetryConstants .CUSTOM_LABEL_KEY ;
2223import static io .grpc .opentelemetry .internal .OpenTelemetryConstants .LOCALITY_KEY ;
2324import static io .grpc .opentelemetry .internal .OpenTelemetryConstants .METHOD_KEY ;
2425import static io .grpc .opentelemetry .internal .OpenTelemetryConstants .STATUS_KEY ;
3940import io .grpc .Deadline ;
4041import io .grpc .ForwardingClientCall .SimpleForwardingClientCall ;
4142import io .grpc .ForwardingClientCallListener .SimpleForwardingClientCallListener ;
43+ import io .grpc .Grpc ;
4244import io .grpc .Metadata ;
4345import io .grpc .MethodDescriptor ;
4446import io .grpc .ServerStreamTracer ;
@@ -94,6 +96,7 @@ final class OpenTelemetryMetricsModule {
9496 private final Supplier <Stopwatch > stopwatchSupplier ;
9597 private final boolean localityEnabled ;
9698 private final boolean backendServiceEnabled ;
99+ private final boolean customLabelEnabled ;
97100 private final ImmutableList <OpenTelemetryPlugin > plugins ;
98101
99102 OpenTelemetryMetricsModule (Supplier <Stopwatch > stopwatchSupplier ,
@@ -103,6 +106,7 @@ final class OpenTelemetryMetricsModule {
103106 this .stopwatchSupplier = checkNotNull (stopwatchSupplier , "stopwatchSupplier" );
104107 this .localityEnabled = optionalLabels .contains (LOCALITY_KEY .getKey ());
105108 this .backendServiceEnabled = optionalLabels .contains (BACKEND_SERVICE_KEY .getKey ());
109+ this .customLabelEnabled = optionalLabels .contains (CUSTOM_LABEL_KEY .getKey ());
106110 this .plugins = ImmutableList .copyOf (plugins );
107111 }
108112
@@ -249,7 +253,7 @@ public void streamClosed(Status status) {
249253 statusCode = Code .DEADLINE_EXCEEDED ;
250254 }
251255 }
252- attemptsState .attemptEnded ();
256+ attemptsState .attemptEnded (info . getCallOptions () );
253257 recordFinishedAttempt ();
254258 }
255259
@@ -273,6 +277,10 @@ void recordFinishedAttempt() {
273277 }
274278 builder .put (BACKEND_SERVICE_KEY , savedBackendService );
275279 }
280+ if (module .customLabelEnabled ) {
281+ builder .put (
282+ CUSTOM_LABEL_KEY , info .getCallOptions ().getOption (Grpc .CALL_OPTION_CUSTOM_LABEL ));
283+ }
276284 for (OpenTelemetryPlugin .ClientStreamPlugin plugin : streamPlugins ) {
277285 plugin .addLabels (builder );
278286 }
@@ -383,7 +391,7 @@ private ClientTracer newClientTracer(StreamInfo info) {
383391 }
384392
385393 // Called whenever each attempt is ended.
386- void attemptEnded () {
394+ void attemptEnded (CallOptions callOptions ) {
387395 boolean shouldRecordFinishedCall = false ;
388396 synchronized (lock ) {
389397 if (--activeStreams == 0 ) {
@@ -395,11 +403,11 @@ void attemptEnded() {
395403 }
396404 }
397405 if (shouldRecordFinishedCall ) {
398- recordFinishedCall ();
406+ recordFinishedCall (callOptions );
399407 }
400408 }
401409
402- void callEnded (Status status ) {
410+ void callEnded (Status status , CallOptions callOptions ) {
403411 callStopWatch .stop ();
404412 this .status = status ;
405413 boolean shouldRecordFinishedCall = false ;
@@ -415,11 +423,11 @@ void callEnded(Status status) {
415423 }
416424 }
417425 if (shouldRecordFinishedCall ) {
418- recordFinishedCall ();
426+ recordFinishedCall (callOptions );
419427 }
420428 }
421429
422- void recordFinishedCall () {
430+ void recordFinishedCall (CallOptions callOptions ) {
423431 Context otelContext = otelContextWithBaggage ();
424432 if (attemptsPerCall .get () == 0 ) {
425433 ClientTracer tracer = newClientTracer (null );
@@ -430,11 +438,13 @@ void recordFinishedCall() {
430438 callLatencyNanos = callStopWatch .elapsed (TimeUnit .NANOSECONDS );
431439
432440 // Base attributes
433- io .opentelemetry .api .common .Attributes baseAttributes =
434- io .opentelemetry .api .common .Attributes .of (
435- METHOD_KEY , fullMethodName ,
436- TARGET_KEY , target
437- );
441+ AttributesBuilder builder = io .opentelemetry .api .common .Attributes .builder ()
442+ .put (METHOD_KEY , fullMethodName )
443+ .put (TARGET_KEY , target );
444+ if (module .customLabelEnabled ) {
445+ builder .put (CUSTOM_LABEL_KEY , callOptions .getOption (Grpc .CALL_OPTION_CUSTOM_LABEL ));
446+ }
447+ io .opentelemetry .api .common .Attributes baseAttributes = builder .build ();
438448
439449 // Duration
440450 if (module .resource .clientCallDurationCounter () != null ) {
@@ -660,6 +670,7 @@ public <ReqT, RespT> ClientCall<ReqT, RespT> interceptCall(
660670 callOptions = plugin .filterCallOptions (callOptions );
661671 }
662672 }
673+ final CallOptions finalCallOptions = callOptions ;
663674 // Only record method name as an attribute if isSampledToLocalTracing is set to true,
664675 // which is true for all generated methods. Otherwise, programatically
665676 // created methods result in high cardinality metrics.
@@ -679,7 +690,7 @@ public void start(Listener<RespT> responseListener, Metadata headers) {
679690 new SimpleForwardingClientCallListener <RespT >(responseListener ) {
680691 @ Override
681692 public void onClose (Status status , Metadata trailers ) {
682- tracerFactory .callEnded (status );
693+ tracerFactory .callEnded (status , finalCallOptions );
683694 super .onClose (status , trailers );
684695 }
685696 },
0 commit comments