Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
4516222
grpc support request/response size
crossoverJie Jul 16, 2024
e8f6b0e
fix ci
crossoverJie Jul 16, 2024
01a1bb0
fix ci
crossoverJie Jul 16, 2024
6121b30
fix ci
crossoverJie Jul 16, 2024
9680219
fix test
crossoverJie Jul 17, 2024
cce97f1
fix ci
crossoverJie Jul 17, 2024
22a791f
fix muzzle
crossoverJie Jul 17, 2024
c5c46dd
fix muzzle
crossoverJie Jul 17, 2024
d17a36c
fix muzzle
crossoverJie Jul 17, 2024
9f6055d
fix ci
crossoverJie Jul 17, 2024
b9f6cee
fix ci
crossoverJie Jul 17, 2024
fcc4468
fix ci
crossoverJie Jul 18, 2024
6dc7346
revert ci
crossoverJie Jul 18, 2024
9b350b4
revert ci
crossoverJie Jul 18, 2024
69ee2bd
fix muzzle
crossoverJie Jul 18, 2024
a10ffca
fix muzzle
crossoverJie Jul 18, 2024
e45c225
fix muzzle
crossoverJie Jul 18, 2024
bfe9087
fix muzzle
crossoverJie Jul 20, 2024
43054ad
use static import asList
crossoverJie Jul 22, 2024
1438a0a
fix with cr
crossoverJie Jul 24, 2024
063160f
remove client&server prefix.
crossoverJie Jul 31, 2024
d16cccf
fix tests
asweet-confluent Jul 28, 2025
4387287
Fix tests
asweet-confluent Jul 28, 2025
3cbfa5a
Merge branch 'main' into grpc-req-res-size
asweet-confluent Jul 28, 2025
484f0e8
Remove newlines
asweet-confluent Jul 28, 2025
d89492f
Merge remote-tracking branch 'origin/main' into grpc-req-res-size
asweet-confluent Aug 21, 2025
c88ae14
Remove message size trace attributes
asweet-confluent Aug 22, 2025
bc2abb0
./gradlew spotlessApply
otelbot[bot] Aug 22, 2025
337ea9d
Fix metrics tests
asweet-confluent Aug 22, 2025
b37fd07
./gradlew spotlessApply
otelbot[bot] Aug 22, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,12 @@ public interface RpcAttributesGetter<REQUEST> {

@Nullable
String getMethod(REQUEST request);

default Long getRequestSize(REQUEST request) {
return null;
}

default Long getResponseSize(REQUEST request) {
return null;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.api.metrics.DoubleHistogram;
import io.opentelemetry.api.metrics.DoubleHistogramBuilder;
import io.opentelemetry.api.metrics.LongHistogram;
import io.opentelemetry.api.metrics.LongHistogramBuilder;
import io.opentelemetry.api.metrics.Meter;
import io.opentelemetry.context.Context;
import io.opentelemetry.context.ContextKey;
Expand All @@ -35,6 +37,8 @@ public final class RpcClientMetrics implements OperationListener {
private static final Logger logger = Logger.getLogger(RpcClientMetrics.class.getName());

private final DoubleHistogram clientDurationHistogram;
private final LongHistogram clientRequestSize;
private final LongHistogram clientResponseSize;

private RpcClientMetrics(Meter meter) {
DoubleHistogramBuilder durationBuilder =
Expand All @@ -44,6 +48,24 @@ private RpcClientMetrics(Meter meter) {
.setUnit("ms");
RpcMetricsAdvice.applyClientDurationAdvice(durationBuilder);
clientDurationHistogram = durationBuilder.build();

LongHistogramBuilder requestSizeBuilder =
meter
.histogramBuilder("rpc.client.request.size")
.setUnit("By")
.setDescription("Measures the size of RPC request messages (uncompressed).")
.ofLongs();
RpcMetricsAdvice.applyClientRequestSizeAdvice(requestSizeBuilder);
clientRequestSize = requestSizeBuilder.build();

LongHistogramBuilder responseSizeBuilder =
meter
.histogramBuilder("rpc.client.response.size")
.setUnit("By")
.setDescription("Measures the size of RPC response messages (uncompressed).")
.ofLongs();
RpcMetricsAdvice.applyClientRequestSizeAdvice(responseSizeBuilder);
clientResponseSize = responseSizeBuilder.build();
}

/**
Expand Down Expand Up @@ -72,10 +94,19 @@ public void onEnd(Context context, Attributes endAttributes, long endNanos) {
context);
return;
}
Attributes attributes = state.startAttributes().toBuilder().putAll(endAttributes).build();
clientDurationHistogram.record(
(endNanos - state.startTimeNanos()) / NANOS_PER_MS,
state.startAttributes().toBuilder().putAll(endAttributes).build(),
context);
(endNanos - state.startTimeNanos()) / NANOS_PER_MS, attributes, context);

Long rpcClientRequestBodySize = RpcMetricsHolder.getRequestBodySize(context);
if (rpcClientRequestBodySize != null) {
clientRequestSize.record(rpcClientRequestBodySize, attributes, context);
}

Long rpcClientResponseBodySize = RpcMetricsHolder.getResponseBodySize(context);
if (rpcClientResponseBodySize != null) {
clientResponseSize.record(rpcClientResponseBodySize, attributes, context);
}
}

@AutoValue
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,24 @@ public final void onEnd(
REQUEST request,
@Nullable RESPONSE response,
@Nullable Throwable error) {
// No response attributes
Long requestSize = getter.getRequestSize(request);
Long responseSize = getter.getResponseSize(request);
if (this instanceof RpcClientAttributesExtractor) {
if (requestSize != null) {
RpcMetricsHolder.setRequestBodySize(context, requestSize);
}
if (responseSize != null) {
RpcMetricsHolder.setResponseBodySize(context, responseSize);
}
}

if (this instanceof RpcServerAttributesExtractor) {
if (requestSize != null) {
RpcMetricsHolder.setRequestBodySize(context, requestSize);
}
if (responseSize != null) {
RpcMetricsHolder.setResponseBodySize(context, responseSize);
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,36 +5,40 @@

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

import static java.util.Arrays.asList;

import io.opentelemetry.api.common.AttributeKey;
import io.opentelemetry.api.incubator.metrics.ExtendedDoubleHistogramBuilder;
import io.opentelemetry.api.incubator.metrics.ExtendedLongHistogramBuilder;
import io.opentelemetry.api.metrics.DoubleHistogramBuilder;
import io.opentelemetry.api.metrics.LongHistogramBuilder;
import io.opentelemetry.semconv.NetworkAttributes;
import io.opentelemetry.semconv.ServerAttributes;
import java.util.Arrays;
import java.util.List;

final class RpcMetricsAdvice {

// copied from RpcIncubatingAttributes
private static final AttributeKey<Long> RPC_GRPC_STATUS_CODE =
AttributeKey.longKey("rpc.grpc.status_code");
private static final List<AttributeKey<?>> RPC_METRICS_ATTRIBUTE_KEYS =
asList(
RpcCommonAttributesExtractor.RPC_SYSTEM,
RpcCommonAttributesExtractor.RPC_SERVICE,
RpcCommonAttributesExtractor.RPC_METHOD,
RPC_GRPC_STATUS_CODE,
NetworkAttributes.NETWORK_TYPE,
NetworkAttributes.NETWORK_TRANSPORT,
ServerAttributes.SERVER_ADDRESS,
ServerAttributes.SERVER_PORT);

static void applyClientDurationAdvice(DoubleHistogramBuilder builder) {
if (!(builder instanceof ExtendedDoubleHistogramBuilder)) {
return;
}
// the list of recommended metrics attributes is from
// https://github.com/open-telemetry/semantic-conventions/blob/main/docs/rpc/rpc-metrics.md
((ExtendedDoubleHistogramBuilder) builder)
.setAttributesAdvice(
Arrays.asList(
RpcCommonAttributesExtractor.RPC_SYSTEM,
RpcCommonAttributesExtractor.RPC_SERVICE,
RpcCommonAttributesExtractor.RPC_METHOD,
RPC_GRPC_STATUS_CODE,
NetworkAttributes.NETWORK_TYPE,
NetworkAttributes.NETWORK_TRANSPORT,
ServerAttributes.SERVER_ADDRESS,
ServerAttributes.SERVER_PORT));
((ExtendedDoubleHistogramBuilder) builder).setAttributesAdvice(RPC_METRICS_ATTRIBUTE_KEYS);
}

static void applyServerDurationAdvice(DoubleHistogramBuilder builder) {
Expand All @@ -43,17 +47,25 @@ static void applyServerDurationAdvice(DoubleHistogramBuilder builder) {
}
// the list of recommended metrics attributes is from
// https://github.com/open-telemetry/semantic-conventions/blob/main/docs/rpc/rpc-metrics.md
((ExtendedDoubleHistogramBuilder) builder)
.setAttributesAdvice(
Arrays.asList(
RpcCommonAttributesExtractor.RPC_SYSTEM,
RpcCommonAttributesExtractor.RPC_SERVICE,
RpcCommonAttributesExtractor.RPC_METHOD,
RPC_GRPC_STATUS_CODE,
NetworkAttributes.NETWORK_TYPE,
NetworkAttributes.NETWORK_TRANSPORT,
ServerAttributes.SERVER_ADDRESS,
ServerAttributes.SERVER_PORT));
((ExtendedDoubleHistogramBuilder) builder).setAttributesAdvice(RPC_METRICS_ATTRIBUTE_KEYS);
}

static void applyClientRequestSizeAdvice(LongHistogramBuilder builder) {
if (!(builder instanceof ExtendedLongHistogramBuilder)) {
return;
}
// the list of recommended metrics attributes is from
// https://github.com/open-telemetry/semantic-conventions/blob/main/docs/rpc/rpc-metrics.md
((ExtendedLongHistogramBuilder) builder).setAttributesAdvice(RPC_METRICS_ATTRIBUTE_KEYS);
}

static void applyServerRequestSizeAdvice(LongHistogramBuilder builder) {
if (!(builder instanceof ExtendedLongHistogramBuilder)) {
return;
}
// the list of recommended metrics attributes is from
// https://github.com/open-telemetry/semantic-conventions/blob/main/docs/rpc/rpc-metrics.md
((ExtendedLongHistogramBuilder) builder).setAttributesAdvice(RPC_METRICS_ATTRIBUTE_KEYS);
}

private RpcMetricsAdvice() {}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/

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

import static io.opentelemetry.context.ContextKey.named;

import io.opentelemetry.context.Context;
import io.opentelemetry.context.ContextKey;
import io.opentelemetry.context.ImplicitContextKeyed;
import javax.annotation.Nullable;

public class RpcMetricsHolder implements ImplicitContextKeyed {

private static final ContextKey<RpcMetricsHolder> KEY = named("opentelemetry-rpc-metrics");

@Nullable private Long requestBodySize = null;
@Nullable private Long responseBodySize = null;

private RpcMetricsHolder() {}

public static Context init(Context context) {
if (context.get(KEY) != null) {
return context;
}
return context.with(new RpcMetricsHolder());
}

public static void setRequestBodySize(Context context, long requestBodySize) {
RpcMetricsHolder holder = context.get(KEY);
if (holder != null) {
holder.requestBodySize = requestBodySize;
}
}

public static void setResponseBodySize(Context context, long responseBodySize) {
RpcMetricsHolder holder = context.get(KEY);
if (holder != null) {
holder.responseBodySize = responseBodySize;
}
}

public static Long getRequestBodySize(Context context) {
RpcMetricsHolder holder = context.get(KEY);
if (holder != null) {
return holder.requestBodySize;
}
return null;
}

public static Long getResponseBodySize(Context context) {
RpcMetricsHolder holder = context.get(KEY);
if (holder != null) {
return holder.responseBodySize;
}
return null;
}

@Override
public Context storeInContext(Context context) {
return context.with(KEY, this);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.api.metrics.DoubleHistogram;
import io.opentelemetry.api.metrics.DoubleHistogramBuilder;
import io.opentelemetry.api.metrics.LongHistogram;
import io.opentelemetry.api.metrics.LongHistogramBuilder;
import io.opentelemetry.api.metrics.Meter;
import io.opentelemetry.context.Context;
import io.opentelemetry.context.ContextKey;
Expand All @@ -35,6 +37,8 @@ public final class RpcServerMetrics implements OperationListener {
private static final Logger logger = Logger.getLogger(RpcServerMetrics.class.getName());

private final DoubleHistogram serverDurationHistogram;
private final LongHistogram serverRequestSize;
private final LongHistogram serverResponseSize;

private RpcServerMetrics(Meter meter) {
DoubleHistogramBuilder durationBuilder =
Expand All @@ -44,6 +48,24 @@ private RpcServerMetrics(Meter meter) {
.setUnit("ms");
RpcMetricsAdvice.applyServerDurationAdvice(durationBuilder);
serverDurationHistogram = durationBuilder.build();

LongHistogramBuilder requestSizeBuilder =
meter
.histogramBuilder("rpc.server.request.size")
.setUnit("By")
.setDescription("Measures the size of RPC request messages (uncompressed).")
.ofLongs();
RpcMetricsAdvice.applyServerRequestSizeAdvice(requestSizeBuilder);
serverRequestSize = requestSizeBuilder.build();

LongHistogramBuilder responseSizeBuilder =
meter
.histogramBuilder("rpc.server.response.size")
.setUnit("By")
.setDescription("Measures the size of RPC response messages (uncompressed).")
.ofLongs();
RpcMetricsAdvice.applyServerRequestSizeAdvice(responseSizeBuilder);
serverResponseSize = responseSizeBuilder.build();
}

/**
Expand Down Expand Up @@ -72,10 +94,19 @@ public void onEnd(Context context, Attributes endAttributes, long endNanos) {
context);
return;
}
Attributes attributes = state.startAttributes().toBuilder().putAll(endAttributes).build();
serverDurationHistogram.record(
(endNanos - state.startTimeNanos()) / NANOS_PER_MS,
state.startAttributes().toBuilder().putAll(endAttributes).build(),
context);
(endNanos - state.startTimeNanos()) / NANOS_PER_MS, attributes, context);

Long rpcServerRequestBodySize = RpcMetricsHolder.getRequestBodySize(context);
if (rpcServerRequestBodySize != null) {
serverRequestSize.record(rpcServerRequestBodySize, attributes, context);
}

Long rpcServerResponseBodySize = RpcMetricsHolder.getResponseBodySize(context);
if (rpcServerResponseBodySize != null) {
serverResponseSize.record(rpcServerResponseBodySize, attributes, context);
}
}

@AutoValue
Expand Down
Loading