Skip to content

Commit

Permalink
Add http.client|server.request|response.size metrics (open-telemetry#…
Browse files Browse the repository at this point in the history
  • Loading branch information
jack-berg authored and LironKS committed Oct 23, 2022
1 parent ebaf6c7 commit d23732f
Show file tree
Hide file tree
Showing 6 changed files with 206 additions and 21 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,23 @@

package io.opentelemetry.instrumentation.api.instrumenter.http;

import static io.opentelemetry.instrumentation.api.instrumenter.http.TemporaryMetricsView.applyClientDurationView;
import static io.opentelemetry.instrumentation.api.instrumenter.http.TemporaryMetricsView.applyClientDurationAndSizeView;
import static java.util.logging.Level.FINE;

import com.google.auto.value.AutoValue;
import io.opentelemetry.api.common.AttributeKey;
import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.api.metrics.DoubleHistogram;
import io.opentelemetry.api.metrics.LongHistogram;
import io.opentelemetry.api.metrics.Meter;
import io.opentelemetry.context.Context;
import io.opentelemetry.context.ContextKey;
import io.opentelemetry.instrumentation.api.instrumenter.OperationListener;
import io.opentelemetry.instrumentation.api.instrumenter.OperationMetrics;
import io.opentelemetry.semconv.trace.attributes.SemanticAttributes;
import java.util.concurrent.TimeUnit;
import java.util.logging.Logger;
import javax.annotation.Nullable;

/**
* {@link OperationListener} which keeps track of <a
Expand All @@ -43,6 +47,8 @@ public static OperationMetrics get() {
}

private final DoubleHistogram duration;
private final LongHistogram requestSize;
private final LongHistogram responseSize;

private HttpClientMetrics(Meter meter) {
duration =
Expand All @@ -51,6 +57,20 @@ private HttpClientMetrics(Meter meter) {
.setUnit("ms")
.setDescription("The duration of the outbound HTTP request")
.build();
requestSize =
meter
.histogramBuilder("http.client.request.size")
.setUnit("By")
.setDescription("The size of HTTP request messages")
.ofLongs()
.build();
responseSize =
meter
.histogramBuilder("http.client.response.size")
.setUnit("By")
.setDescription("The size of HTTP response messages")
.ofLongs()
.build();
}

@Override
Expand All @@ -70,10 +90,35 @@ public void onEnd(Context context, Attributes endAttributes, long endNanos) {
context);
return;
}
Attributes durationAndSizeAttributes =
applyClientDurationAndSizeView(state.startAttributes(), endAttributes);
duration.record(
(endNanos - state.startTimeNanos()) / NANOS_PER_MS,
applyClientDurationView(state.startAttributes(), endAttributes),
context);
(endNanos - state.startTimeNanos()) / NANOS_PER_MS, durationAndSizeAttributes, context);
Long requestLength =
getAttribute(
SemanticAttributes.HTTP_REQUEST_CONTENT_LENGTH, endAttributes, state.startAttributes());
if (requestLength != null) {
requestSize.record(requestLength, durationAndSizeAttributes);
}
Long responseLength =
getAttribute(
SemanticAttributes.HTTP_RESPONSE_CONTENT_LENGTH,
endAttributes,
state.startAttributes());
if (responseLength != null) {
responseSize.record(responseLength, durationAndSizeAttributes);
}
}

@Nullable
private static <T> T getAttribute(AttributeKey<T> key, Attributes... attributesList) {
for (Attributes attributes : attributesList) {
T value = attributes.get(key);
if (value != null) {
return value;
}
}
return null;
}

@AutoValue
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,24 @@
package io.opentelemetry.instrumentation.api.instrumenter.http;

import static io.opentelemetry.instrumentation.api.instrumenter.http.TemporaryMetricsView.applyActiveRequestsView;
import static io.opentelemetry.instrumentation.api.instrumenter.http.TemporaryMetricsView.applyServerDurationView;
import static io.opentelemetry.instrumentation.api.instrumenter.http.TemporaryMetricsView.applyServerDurationAndSizeView;
import static java.util.logging.Level.FINE;

import com.google.auto.value.AutoValue;
import io.opentelemetry.api.common.AttributeKey;
import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.api.metrics.DoubleHistogram;
import io.opentelemetry.api.metrics.LongHistogram;
import io.opentelemetry.api.metrics.LongUpDownCounter;
import io.opentelemetry.api.metrics.Meter;
import io.opentelemetry.context.Context;
import io.opentelemetry.context.ContextKey;
import io.opentelemetry.instrumentation.api.instrumenter.OperationListener;
import io.opentelemetry.instrumentation.api.instrumenter.OperationMetrics;
import io.opentelemetry.semconv.trace.attributes.SemanticAttributes;
import java.util.concurrent.TimeUnit;
import java.util.logging.Logger;
import javax.annotation.Nullable;

/**
* {@link OperationListener} which keeps track of <a
Expand All @@ -46,6 +50,8 @@ public static OperationMetrics get() {

private final LongUpDownCounter activeRequests;
private final DoubleHistogram duration;
private final LongHistogram requestSize;
private final LongHistogram responseSize;

private HttpServerMetrics(Meter meter) {
activeRequests =
Expand All @@ -61,6 +67,20 @@ private HttpServerMetrics(Meter meter) {
.setUnit("ms")
.setDescription("The duration of the inbound HTTP request")
.build();
requestSize =
meter
.histogramBuilder("http.server.request.size")
.setUnit("By")
.setDescription("The size of HTTP request messages")
.ofLongs()
.build();
responseSize =
meter
.histogramBuilder("http.server.response.size")
.setUnit("By")
.setDescription("The size of HTTP response messages")
.ofLongs()
.build();
}

@Override
Expand All @@ -83,10 +103,35 @@ public void onEnd(Context context, Attributes endAttributes, long endNanos) {
return;
}
activeRequests.add(-1, applyActiveRequestsView(state.startAttributes()), context);
Attributes durationAndSizeAttributes =
applyServerDurationAndSizeView(state.startAttributes(), endAttributes);
duration.record(
(endNanos - state.startTimeNanos()) / NANOS_PER_MS,
applyServerDurationView(state.startAttributes(), endAttributes),
context);
(endNanos - state.startTimeNanos()) / NANOS_PER_MS, durationAndSizeAttributes, context);
Long requestLength =
getAttribute(
SemanticAttributes.HTTP_REQUEST_CONTENT_LENGTH, endAttributes, state.startAttributes());
if (requestLength != null) {
requestSize.record(requestLength, durationAndSizeAttributes);
}
Long responseLength =
getAttribute(
SemanticAttributes.HTTP_RESPONSE_CONTENT_LENGTH,
endAttributes,
state.startAttributes());
if (responseLength != null) {
responseSize.record(responseLength, durationAndSizeAttributes);
}
}

@Nullable
private static <T> T getAttribute(AttributeKey<T> key, Attributes... attributesList) {
for (Attributes attributes : attributesList) {
T value = attributes.get(key);
if (value != null) {
return value;
}
}
return null;
}

@AutoValue
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,14 +68,16 @@ private static Set<AttributeKey> buildActiveRequestsView() {
return view;
}

static Attributes applyClientDurationView(Attributes startAttributes, Attributes endAttributes) {
static Attributes applyClientDurationAndSizeView(
Attributes startAttributes, Attributes endAttributes) {
AttributesBuilder filtered = Attributes.builder();
applyView(filtered, startAttributes, durationClientView);
applyView(filtered, endAttributes, durationClientView);
return filtered.build();
}

static Attributes applyServerDurationView(Attributes startAttributes, Attributes endAttributes) {
static Attributes applyServerDurationAndSizeView(
Attributes startAttributes, Attributes endAttributes) {
AttributesBuilder filtered = Attributes.builder();
applyView(filtered, startAttributes, durationServerView);
applyView(filtered, endAttributes, durationServerView);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,13 +41,15 @@ void collectsMetrics() {
.put("net.peer.name", "localhost")
.put("net.peer.ip", "0.0.0.0")
.put("net.peer.port", 1234)
.put("http.request_content_length", 100)
.build();

Attributes responseAttributes =
Attributes.builder()
.put("http.flavor", "2.0")
.put("http.server_name", "server")
.put("http.status_code", 200)
.put("http.response_content_length", 200)
.build();

Context parent =
Expand Down Expand Up @@ -92,7 +94,39 @@ void collectsMetrics() {
exemplar ->
exemplar
.hasTraceId("ff01020304050600ff0a0b0c0d0e0f00")
.hasSpanId("090a0b0c0d0e0f00")))));
.hasSpanId("090a0b0c0d0e0f00")))),
metric ->
assertThat(metric)
.hasName("http.client.request.size")
.hasUnit("By")
.hasHistogramSatisfying(
histogram ->
histogram.hasPointsSatisfying(
point ->
point
.hasSum(100 /* bytes */)
.hasAttributesSatisfying(
equalTo(SemanticAttributes.NET_PEER_NAME, "localhost"),
equalTo(SemanticAttributes.NET_PEER_PORT, 1234),
equalTo(SemanticAttributes.HTTP_METHOD, "GET"),
equalTo(SemanticAttributes.HTTP_FLAVOR, "2.0"),
equalTo(SemanticAttributes.HTTP_STATUS_CODE, 200)))),
metric ->
assertThat(metric)
.hasName("http.client.response.size")
.hasUnit("By")
.hasHistogramSatisfying(
histogram ->
histogram.hasPointsSatisfying(
point ->
point
.hasSum(200 /* bytes */)
.hasAttributesSatisfying(
equalTo(SemanticAttributes.NET_PEER_NAME, "localhost"),
equalTo(SemanticAttributes.NET_PEER_PORT, 1234),
equalTo(SemanticAttributes.HTTP_METHOD, "GET"),
equalTo(SemanticAttributes.HTTP_FLAVOR, "2.0"),
equalTo(SemanticAttributes.HTTP_STATUS_CODE, 200)))));

listener.onEnd(context2, responseAttributes, nanos(300));

Expand All @@ -103,8 +137,19 @@ void collectsMetrics() {
.hasName("http.client.duration")
.hasHistogramSatisfying(
histogram ->
histogram.hasPointsSatisfying(
point -> point.hasSum(300 /* millis */))));
histogram.hasPointsSatisfying(point -> point.hasSum(300 /* millis */))),
metric ->
assertThat(metric)
.hasName("http.client.request.size")
.hasHistogramSatisfying(
histogram ->
histogram.hasPointsSatisfying(point -> point.hasSum(200 /* bytes */))),
metric ->
assertThat(metric)
.hasName("http.client.response.size")
.hasHistogramSatisfying(
histogram ->
histogram.hasPointsSatisfying(point -> point.hasSum(400 /* bytes */))));
}

private static long nanos(int millis) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,13 +39,15 @@ void collectsMetrics() {
.put("http.scheme", "https")
.put("net.host.name", "localhost")
.put("net.host.port", 1234)
.put("http.request_content_length", 100)
.build();

Attributes responseAttributes =
Attributes.builder()
.put("http.flavor", "2.0")
.put("http.server_name", "server")
.put("http.status_code", 200)
.put("http.response_content_length", 200)
.build();

SpanContext spanContext1 =
Expand Down Expand Up @@ -154,7 +156,39 @@ void collectsMetrics() {
exemplar ->
exemplar
.hasTraceId(spanContext1.getTraceId())
.hasSpanId(spanContext1.getSpanId())))));
.hasSpanId(spanContext1.getSpanId())))),
metric ->
assertThat(metric)
.hasName("http.server.request.size")
.hasUnit("By")
.hasHistogramSatisfying(
histogram ->
histogram.hasPointsSatisfying(
point ->
point
.hasSum(100 /* bytes */)
.hasAttributesSatisfying(
equalTo(SemanticAttributes.HTTP_SCHEME, "https"),
equalTo(SemanticAttributes.HTTP_HOST, "host"),
equalTo(SemanticAttributes.HTTP_METHOD, "GET"),
equalTo(SemanticAttributes.HTTP_STATUS_CODE, 200),
equalTo(SemanticAttributes.HTTP_FLAVOR, "2.0")))),
metric ->
assertThat(metric)
.hasName("http.server.response.size")
.hasUnit("By")
.hasHistogramSatisfying(
histogram ->
histogram.hasPointsSatisfying(
point ->
point
.hasSum(200 /* bytes */)
.hasAttributesSatisfying(
equalTo(SemanticAttributes.HTTP_SCHEME, "https"),
equalTo(SemanticAttributes.HTTP_HOST, "host"),
equalTo(SemanticAttributes.HTTP_METHOD, "GET"),
equalTo(SemanticAttributes.HTTP_STATUS_CODE, 200),
equalTo(SemanticAttributes.HTTP_FLAVOR, "2.0")))));

listener.onEnd(context2, responseAttributes, nanos(300));

Expand All @@ -178,7 +212,19 @@ void collectsMetrics() {
exemplar ->
exemplar
.hasTraceId(spanContext2.getTraceId())
.hasSpanId(spanContext2.getSpanId())))));
.hasSpanId(spanContext2.getSpanId())))),
metric ->
assertThat(metric)
.hasName("http.server.request.size")
.hasHistogramSatisfying(
histogram ->
histogram.hasPointsSatisfying(point -> point.hasSum(200 /* bytes */))),
metric ->
assertThat(metric)
.hasName("http.server.response.size")
.hasHistogramSatisfying(
histogram ->
histogram.hasPointsSatisfying(point -> point.hasSum(400 /* bytes */))));
}

@Test
Expand Down
Loading

0 comments on commit d23732f

Please sign in to comment.