Skip to content

Commit 5d27f02

Browse files
asweet-confluentcrossoverJieotelbot[bot]laurit
authored
Response/Request Size GRPC Metrics Instrumentation (#14342)
Co-authored-by: crossoverJie <[email protected]> Co-authored-by: otelbot <[email protected]> Co-authored-by: Lauri Tulmin <[email protected]>
1 parent 9dce150 commit 5d27f02

File tree

15 files changed

+585
-279
lines changed

15 files changed

+585
-279
lines changed

instrumentation-api-incubator/src/main/java/io/opentelemetry/instrumentation/api/incubator/semconv/rpc/RpcAttributesGetter.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,4 +24,14 @@ public interface RpcAttributesGetter<REQUEST> {
2424

2525
@Nullable
2626
String getMethod(REQUEST request);
27+
28+
@Nullable
29+
default Long getRequestSize(REQUEST request) {
30+
return null;
31+
}
32+
33+
@Nullable
34+
default Long getResponseSize(REQUEST request) {
35+
return null;
36+
}
2737
}

instrumentation-api-incubator/src/main/java/io/opentelemetry/instrumentation/api/incubator/semconv/rpc/RpcClientMetrics.java

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
import io.opentelemetry.api.common.Attributes;
1212
import io.opentelemetry.api.metrics.DoubleHistogram;
1313
import io.opentelemetry.api.metrics.DoubleHistogramBuilder;
14+
import io.opentelemetry.api.metrics.LongHistogram;
15+
import io.opentelemetry.api.metrics.LongHistogramBuilder;
1416
import io.opentelemetry.api.metrics.Meter;
1517
import io.opentelemetry.context.Context;
1618
import io.opentelemetry.context.ContextKey;
@@ -35,6 +37,8 @@ public final class RpcClientMetrics implements OperationListener {
3537
private static final Logger logger = Logger.getLogger(RpcClientMetrics.class.getName());
3638

3739
private final DoubleHistogram clientDurationHistogram;
40+
private final LongHistogram clientRequestSize;
41+
private final LongHistogram clientResponseSize;
3842

3943
private RpcClientMetrics(Meter meter) {
4044
DoubleHistogramBuilder durationBuilder =
@@ -44,6 +48,24 @@ private RpcClientMetrics(Meter meter) {
4448
.setUnit("ms");
4549
RpcMetricsAdvice.applyClientDurationAdvice(durationBuilder);
4650
clientDurationHistogram = durationBuilder.build();
51+
52+
LongHistogramBuilder requestSizeBuilder =
53+
meter
54+
.histogramBuilder("rpc.client.request.size")
55+
.setUnit("By")
56+
.setDescription("Measures the size of RPC request messages (uncompressed).")
57+
.ofLongs();
58+
RpcMetricsAdvice.applyClientRequestSizeAdvice(requestSizeBuilder);
59+
clientRequestSize = requestSizeBuilder.build();
60+
61+
LongHistogramBuilder responseSizeBuilder =
62+
meter
63+
.histogramBuilder("rpc.client.response.size")
64+
.setUnit("By")
65+
.setDescription("Measures the size of RPC response messages (uncompressed).")
66+
.ofLongs();
67+
RpcMetricsAdvice.applyClientRequestSizeAdvice(responseSizeBuilder);
68+
clientResponseSize = responseSizeBuilder.build();
4769
}
4870

4971
/**
@@ -72,10 +94,19 @@ public void onEnd(Context context, Attributes endAttributes, long endNanos) {
7294
context);
7395
return;
7496
}
97+
Attributes attributes = state.startAttributes().toBuilder().putAll(endAttributes).build();
7598
clientDurationHistogram.record(
76-
(endNanos - state.startTimeNanos()) / NANOS_PER_MS,
77-
state.startAttributes().toBuilder().putAll(endAttributes).build(),
78-
context);
99+
(endNanos - state.startTimeNanos()) / NANOS_PER_MS, attributes, context);
100+
101+
Long rpcClientRequestBodySize = attributes.get(RpcSizeAttributesExtractor.RPC_REQUEST_SIZE);
102+
if (rpcClientRequestBodySize != null) {
103+
clientRequestSize.record(rpcClientRequestBodySize, attributes, context);
104+
}
105+
106+
Long rpcClientResponseBodySize = attributes.get(RpcSizeAttributesExtractor.RPC_RESPONSE_SIZE);
107+
if (rpcClientResponseBodySize != null) {
108+
clientResponseSize.record(rpcClientResponseBodySize, attributes, context);
109+
}
79110
}
80111

81112
@AutoValue

instrumentation-api-incubator/src/main/java/io/opentelemetry/instrumentation/api/incubator/semconv/rpc/RpcMetricsAdvice.java

Lines changed: 35 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -5,36 +5,40 @@
55

66
package io.opentelemetry.instrumentation.api.incubator.semconv.rpc;
77

8+
import static java.util.Arrays.asList;
9+
810
import io.opentelemetry.api.common.AttributeKey;
911
import io.opentelemetry.api.incubator.metrics.ExtendedDoubleHistogramBuilder;
12+
import io.opentelemetry.api.incubator.metrics.ExtendedLongHistogramBuilder;
1013
import io.opentelemetry.api.metrics.DoubleHistogramBuilder;
14+
import io.opentelemetry.api.metrics.LongHistogramBuilder;
1115
import io.opentelemetry.semconv.NetworkAttributes;
1216
import io.opentelemetry.semconv.ServerAttributes;
13-
import java.util.Arrays;
17+
import java.util.List;
1418

1519
final class RpcMetricsAdvice {
1620

1721
// copied from RpcIncubatingAttributes
1822
private static final AttributeKey<Long> RPC_GRPC_STATUS_CODE =
1923
AttributeKey.longKey("rpc.grpc.status_code");
24+
private static final List<AttributeKey<?>> RPC_METRICS_ATTRIBUTE_KEYS =
25+
asList(
26+
RpcCommonAttributesExtractor.RPC_SYSTEM,
27+
RpcCommonAttributesExtractor.RPC_SERVICE,
28+
RpcCommonAttributesExtractor.RPC_METHOD,
29+
RPC_GRPC_STATUS_CODE,
30+
NetworkAttributes.NETWORK_TYPE,
31+
NetworkAttributes.NETWORK_TRANSPORT,
32+
ServerAttributes.SERVER_ADDRESS,
33+
ServerAttributes.SERVER_PORT);
2034

2135
static void applyClientDurationAdvice(DoubleHistogramBuilder builder) {
2236
if (!(builder instanceof ExtendedDoubleHistogramBuilder)) {
2337
return;
2438
}
2539
// the list of recommended metrics attributes is from
2640
// https://github.com/open-telemetry/semantic-conventions/blob/main/docs/rpc/rpc-metrics.md
27-
((ExtendedDoubleHistogramBuilder) builder)
28-
.setAttributesAdvice(
29-
Arrays.asList(
30-
RpcCommonAttributesExtractor.RPC_SYSTEM,
31-
RpcCommonAttributesExtractor.RPC_SERVICE,
32-
RpcCommonAttributesExtractor.RPC_METHOD,
33-
RPC_GRPC_STATUS_CODE,
34-
NetworkAttributes.NETWORK_TYPE,
35-
NetworkAttributes.NETWORK_TRANSPORT,
36-
ServerAttributes.SERVER_ADDRESS,
37-
ServerAttributes.SERVER_PORT));
41+
((ExtendedDoubleHistogramBuilder) builder).setAttributesAdvice(RPC_METRICS_ATTRIBUTE_KEYS);
3842
}
3943

4044
static void applyServerDurationAdvice(DoubleHistogramBuilder builder) {
@@ -43,17 +47,25 @@ static void applyServerDurationAdvice(DoubleHistogramBuilder builder) {
4347
}
4448
// the list of recommended metrics attributes is from
4549
// https://github.com/open-telemetry/semantic-conventions/blob/main/docs/rpc/rpc-metrics.md
46-
((ExtendedDoubleHistogramBuilder) builder)
47-
.setAttributesAdvice(
48-
Arrays.asList(
49-
RpcCommonAttributesExtractor.RPC_SYSTEM,
50-
RpcCommonAttributesExtractor.RPC_SERVICE,
51-
RpcCommonAttributesExtractor.RPC_METHOD,
52-
RPC_GRPC_STATUS_CODE,
53-
NetworkAttributes.NETWORK_TYPE,
54-
NetworkAttributes.NETWORK_TRANSPORT,
55-
ServerAttributes.SERVER_ADDRESS,
56-
ServerAttributes.SERVER_PORT));
50+
((ExtendedDoubleHistogramBuilder) builder).setAttributesAdvice(RPC_METRICS_ATTRIBUTE_KEYS);
51+
}
52+
53+
static void applyClientRequestSizeAdvice(LongHistogramBuilder builder) {
54+
if (!(builder instanceof ExtendedLongHistogramBuilder)) {
55+
return;
56+
}
57+
// the list of recommended metrics attributes is from
58+
// https://github.com/open-telemetry/semantic-conventions/blob/main/docs/rpc/rpc-metrics.md
59+
((ExtendedLongHistogramBuilder) builder).setAttributesAdvice(RPC_METRICS_ATTRIBUTE_KEYS);
60+
}
61+
62+
static void applyServerRequestSizeAdvice(LongHistogramBuilder builder) {
63+
if (!(builder instanceof ExtendedLongHistogramBuilder)) {
64+
return;
65+
}
66+
// the list of recommended metrics attributes is from
67+
// https://github.com/open-telemetry/semantic-conventions/blob/main/docs/rpc/rpc-metrics.md
68+
((ExtendedLongHistogramBuilder) builder).setAttributesAdvice(RPC_METRICS_ATTRIBUTE_KEYS);
5769
}
5870

5971
private RpcMetricsAdvice() {}

instrumentation-api-incubator/src/main/java/io/opentelemetry/instrumentation/api/incubator/semconv/rpc/RpcServerMetrics.java

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
import io.opentelemetry.api.common.Attributes;
1212
import io.opentelemetry.api.metrics.DoubleHistogram;
1313
import io.opentelemetry.api.metrics.DoubleHistogramBuilder;
14+
import io.opentelemetry.api.metrics.LongHistogram;
15+
import io.opentelemetry.api.metrics.LongHistogramBuilder;
1416
import io.opentelemetry.api.metrics.Meter;
1517
import io.opentelemetry.context.Context;
1618
import io.opentelemetry.context.ContextKey;
@@ -35,6 +37,8 @@ public final class RpcServerMetrics implements OperationListener {
3537
private static final Logger logger = Logger.getLogger(RpcServerMetrics.class.getName());
3638

3739
private final DoubleHistogram serverDurationHistogram;
40+
private final LongHistogram serverRequestSize;
41+
private final LongHistogram serverResponseSize;
3842

3943
private RpcServerMetrics(Meter meter) {
4044
DoubleHistogramBuilder durationBuilder =
@@ -44,6 +48,24 @@ private RpcServerMetrics(Meter meter) {
4448
.setUnit("ms");
4549
RpcMetricsAdvice.applyServerDurationAdvice(durationBuilder);
4650
serverDurationHistogram = durationBuilder.build();
51+
52+
LongHistogramBuilder requestSizeBuilder =
53+
meter
54+
.histogramBuilder("rpc.server.request.size")
55+
.setUnit("By")
56+
.setDescription("Measures the size of RPC request messages (uncompressed).")
57+
.ofLongs();
58+
RpcMetricsAdvice.applyServerRequestSizeAdvice(requestSizeBuilder);
59+
serverRequestSize = requestSizeBuilder.build();
60+
61+
LongHistogramBuilder responseSizeBuilder =
62+
meter
63+
.histogramBuilder("rpc.server.response.size")
64+
.setUnit("By")
65+
.setDescription("Measures the size of RPC response messages (uncompressed).")
66+
.ofLongs();
67+
RpcMetricsAdvice.applyServerRequestSizeAdvice(responseSizeBuilder);
68+
serverResponseSize = responseSizeBuilder.build();
4769
}
4870

4971
/**
@@ -72,10 +94,19 @@ public void onEnd(Context context, Attributes endAttributes, long endNanos) {
7294
context);
7395
return;
7496
}
97+
Attributes attributes = state.startAttributes().toBuilder().putAll(endAttributes).build();
7598
serverDurationHistogram.record(
76-
(endNanos - state.startTimeNanos()) / NANOS_PER_MS,
77-
state.startAttributes().toBuilder().putAll(endAttributes).build(),
78-
context);
99+
(endNanos - state.startTimeNanos()) / NANOS_PER_MS, attributes, context);
100+
101+
Long rpcServerRequestBodySize = attributes.get(RpcSizeAttributesExtractor.RPC_REQUEST_SIZE);
102+
if (rpcServerRequestBodySize != null) {
103+
serverRequestSize.record(rpcServerRequestBodySize, attributes, context);
104+
}
105+
106+
Long rpcServerResponseBodySize = attributes.get(RpcSizeAttributesExtractor.RPC_RESPONSE_SIZE);
107+
if (rpcServerResponseBodySize != null) {
108+
serverResponseSize.record(rpcServerResponseBodySize, attributes, context);
109+
}
79110
}
80111

81112
@AutoValue
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
/*
2+
* Copyright The OpenTelemetry Authors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package io.opentelemetry.instrumentation.api.incubator.semconv.rpc;
7+
8+
import static io.opentelemetry.instrumentation.api.internal.AttributesExtractorUtil.internalSet;
9+
10+
import io.opentelemetry.api.common.AttributeKey;
11+
import io.opentelemetry.api.common.AttributesBuilder;
12+
import io.opentelemetry.context.Context;
13+
import io.opentelemetry.instrumentation.api.instrumenter.AttributesExtractor;
14+
import javax.annotation.Nullable;
15+
16+
public final class RpcSizeAttributesExtractor<REQUEST, RESPONSE>
17+
implements AttributesExtractor<REQUEST, RESPONSE> {
18+
19+
static final AttributeKey<Long> RPC_REQUEST_SIZE = AttributeKey.longKey("rpc.request.size");
20+
static final AttributeKey<Long> RPC_RESPONSE_SIZE = AttributeKey.longKey("rpc.response.size");
21+
22+
private final RpcAttributesGetter<REQUEST> getter;
23+
24+
RpcSizeAttributesExtractor(RpcAttributesGetter<REQUEST> getter) {
25+
this.getter = getter;
26+
}
27+
28+
/**
29+
* Returns a new {@link RpcSizeAttributesExtractor} that will use the passed {@code
30+
* attributesGetter} instance to determine the request and response size.
31+
*/
32+
public static <REQUEST, RESPONSE> RpcSizeAttributesExtractor<REQUEST, RESPONSE> create(
33+
RpcAttributesGetter<REQUEST> attributesGetter) {
34+
return new RpcSizeAttributesExtractor<>(attributesGetter);
35+
}
36+
37+
@Override
38+
public void onStart(AttributesBuilder attributes, Context parentContext, REQUEST request) {}
39+
40+
@Override
41+
public void onEnd(
42+
AttributesBuilder attributes,
43+
Context context,
44+
REQUEST request,
45+
@Nullable RESPONSE response,
46+
@Nullable Throwable error) {
47+
internalSet(attributes, RPC_REQUEST_SIZE, getter.getRequestSize(request));
48+
internalSet(attributes, RPC_RESPONSE_SIZE, getter.getResponseSize(request));
49+
}
50+
}

0 commit comments

Comments
 (0)