Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -7,20 +7,20 @@

import static io.opentelemetry.instrumentation.api.instrumenter.http.HttpMessageBodySizeUtil.getHttpRequestBodySize;
import static io.opentelemetry.instrumentation.api.instrumenter.http.HttpMessageBodySizeUtil.getHttpResponseBodySize;
import static io.opentelemetry.instrumentation.api.instrumenter.http.HttpMetricsUtil.createDurationHistogram;
import static io.opentelemetry.instrumentation.api.instrumenter.http.HttpMetricsUtil.nanosToUnit;
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.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.instrumentation.api.metrics.DurationHistogram;
import io.opentelemetry.instrumentation.api.metrics.DurationHistogramFactory;
import java.util.concurrent.TimeUnit;
import java.util.logging.Logger;

/**
Expand All @@ -44,13 +44,13 @@ public static OperationMetrics get() {
return HttpClientMetrics::new;
}

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

private HttpClientMetrics(Meter meter) {
duration =
createDurationHistogram(
DurationHistogramFactory.create(
meter, "http.client.duration", "The duration of the outbound HTTP request");
requestSize =
meter
Expand Down Expand Up @@ -89,7 +89,10 @@ public void onEnd(Context context, Attributes endAttributes, long endNanos) {
Attributes durationAndSizeAttributes =
applyClientDurationAndSizeView(state.startAttributes(), endAttributes);
duration.record(
nanosToUnit(endNanos - state.startTimeNanos()), durationAndSizeAttributes, context);
endNanos - state.startTimeNanos(),
TimeUnit.NANOSECONDS,
durationAndSizeAttributes,
context);

Long requestBodySize = getHttpRequestBodySize(endAttributes, state.startAttributes());
if (requestBodySize != null) {
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -7,22 +7,22 @@

import static io.opentelemetry.instrumentation.api.instrumenter.http.HttpMessageBodySizeUtil.getHttpRequestBodySize;
import static io.opentelemetry.instrumentation.api.instrumenter.http.HttpMessageBodySizeUtil.getHttpResponseBodySize;
import static io.opentelemetry.instrumentation.api.instrumenter.http.HttpMetricsUtil.createDurationHistogram;
import static io.opentelemetry.instrumentation.api.instrumenter.http.HttpMetricsUtil.nanosToUnit;
import static io.opentelemetry.instrumentation.api.instrumenter.http.TemporaryMetricsView.applyActiveRequestsView;
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.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.instrumentation.api.metrics.DurationHistogram;
import io.opentelemetry.instrumentation.api.metrics.DurationHistogramFactory;
import java.util.concurrent.TimeUnit;
import java.util.logging.Logger;

/**
Expand All @@ -47,7 +47,7 @@ public static OperationMetrics get() {
}

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

Expand All @@ -59,7 +59,7 @@ private HttpServerMetrics(Meter meter) {
.setDescription("The number of concurrent HTTP requests that are currently in-flight")
.build();
duration =
createDurationHistogram(
DurationHistogramFactory.create(
meter, "http.server.duration", "The duration of the inbound HTTP request");
requestSize =
meter
Expand Down Expand Up @@ -103,7 +103,10 @@ public void onEnd(Context context, Attributes endAttributes, long endNanos) {
Attributes durationAndSizeAttributes =
applyServerDurationAndSizeView(state.startAttributes(), endAttributes);
duration.record(
nanosToUnit(endNanos - state.startTimeNanos()), durationAndSizeAttributes, context);
endNanos - state.startTimeNanos(),
TimeUnit.NANOSECONDS,
durationAndSizeAttributes,
context);

Long requestBodySize = getHttpRequestBodySize(endAttributes, state.startAttributes());
if (requestBodySize != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,13 @@

import com.google.auto.value.AutoValue;
import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.api.metrics.DoubleHistogram;
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.instrumentation.api.metrics.DurationHistogram;
import io.opentelemetry.instrumentation.api.metrics.DurationHistogramFactory;
import java.util.concurrent.TimeUnit;
import java.util.logging.Logger;

Expand All @@ -26,22 +27,17 @@
*/
public final class RpcClientMetrics implements OperationListener {

private static final double NANOS_PER_MS = TimeUnit.MILLISECONDS.toNanos(1);

private static final ContextKey<RpcClientMetrics.State> RPC_CLIENT_REQUEST_METRICS_STATE =
ContextKey.named("rpc-client-request-metrics-state");

private static final Logger logger = Logger.getLogger(RpcClientMetrics.class.getName());

private final DoubleHistogram clientDurationHistogram;
private final DurationHistogram clientDurationHistogram;

private RpcClientMetrics(Meter meter) {
clientDurationHistogram =
meter
.histogramBuilder("rpc.client.duration")
.setDescription("The duration of an outbound RPC invocation")
.setUnit("ms")
.build();
DurationHistogramFactory.create(
meter, "rpc.client.duration", "The duration of an outbound RPC invocation");
}

/**
Expand Down Expand Up @@ -71,7 +67,8 @@ public void onEnd(Context context, Attributes endAttributes, long endNanos) {
return;
}
clientDurationHistogram.record(
(endNanos - state.startTimeNanos()) / NANOS_PER_MS,
endNanos - state.startTimeNanos(),
TimeUnit.NANOSECONDS,
applyClientView(state.startAttributes(), endAttributes),
context);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,13 @@

import com.google.auto.value.AutoValue;
import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.api.metrics.DoubleHistogram;
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.instrumentation.api.metrics.DurationHistogram;
import io.opentelemetry.instrumentation.api.metrics.DurationHistogramFactory;
import java.util.concurrent.TimeUnit;
import java.util.logging.Logger;

Expand All @@ -26,22 +27,17 @@
*/
public final class RpcServerMetrics implements OperationListener {

private static final double NANOS_PER_MS = TimeUnit.MILLISECONDS.toNanos(1);

private static final ContextKey<RpcServerMetrics.State> RPC_SERVER_REQUEST_METRICS_STATE =
ContextKey.named("rpc-server-request-metrics-state");

private static final Logger logger = Logger.getLogger(RpcServerMetrics.class.getName());

private final DoubleHistogram serverDurationHistogram;
private final DurationHistogram serverDurationHistogram;

private RpcServerMetrics(Meter meter) {
serverDurationHistogram =
meter
.histogramBuilder("rpc.server.duration")
.setDescription("The duration of an inbound RPC invocation")
.setUnit("ms")
.build();
DurationHistogramFactory.create(
meter, "rpc.server.duration", "The duration of an inbound RPC invocation");
}

/**
Expand Down Expand Up @@ -71,7 +67,8 @@ public void onEnd(Context context, Attributes endAttributes, long endNanos) {
return;
}
serverDurationHistogram.record(
(endNanos - state.startTimeNanos()) / NANOS_PER_MS,
endNanos - state.startTimeNanos(),
TimeUnit.NANOSECONDS,
applyServerView(state.startAttributes(), endAttributes),
context);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/

package io.opentelemetry.instrumentation.api.metrics;

import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.api.metrics.DoubleHistogram;
import io.opentelemetry.context.Context;
import java.util.concurrent.TimeUnit;
import javax.annotation.concurrent.ThreadSafe;

/** A Histogram instrument that records durations */
@ThreadSafe
public class DurationHistogram {

private final DoubleHistogram delegate;

public DurationHistogram(DoubleHistogram delegate) {
this.delegate = delegate;
}

public void record(long value, TimeUnit unit) {
delegate.record(DurationHistogramFactory.toUnit(value, unit));
}

public void record(long value, TimeUnit unit, Attributes attributes) {
delegate.record(DurationHistogramFactory.toUnit(value, unit), attributes);
}

public void record(long value, TimeUnit unit, Attributes attributes, Context context) {
delegate.record(DurationHistogramFactory.toUnit(value, unit), attributes, context);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/

package io.opentelemetry.instrumentation.api.metrics;

import static java.util.Arrays.asList;
import static java.util.Collections.unmodifiableList;

import io.opentelemetry.api.metrics.DoubleHistogramBuilder;
import io.opentelemetry.api.metrics.Meter;
import io.opentelemetry.extension.incubator.metrics.ExtendedDoubleHistogramBuilder;
import io.opentelemetry.instrumentation.api.internal.SemconvStability;
import java.util.List;
import java.util.concurrent.TimeUnit;

public class DurationHistogramFactory {
public static final List<Double> DURATION_SECONDS_BUCKETS =
unmodifiableList(
asList(
0.0, 0.005, 0.01, 0.025, 0.05, 0.075, 0.1, 0.25, 0.5, 0.75, 1.0, 2.5, 5.0, 7.5,
10.0));
// we'll use the old unit if the old semconv is in use
private static final boolean useSeconds =
SemconvStability.emitStableHttpSemconv() && !SemconvStability.emitOldHttpSemconv();

private DurationHistogramFactory() {}

public static DurationHistogram create(Meter meter, String name, String description) {
return create(meter.histogramBuilder(name).setDescription(description));
}

public static DurationHistogram create(DoubleHistogramBuilder builder) {
// don't set custom buckets if milliseconds are still used
if (useSeconds && builder instanceof ExtendedDoubleHistogramBuilder) {
((ExtendedDoubleHistogramBuilder) builder)
.setAdvice(advice -> advice.setExplicitBucketBoundaries(DURATION_SECONDS_BUCKETS));
}
return new DurationHistogram(builder.setUnit(useSeconds ? "s" : "ms").build());
}

static double toUnit(long duration, TimeUnit unit) {
return convertTimeUnit(
(double) duration, unit, useSeconds ? TimeUnit.SECONDS : TimeUnit.MILLISECONDS);
}

private static double convertTimeUnit(double amount, TimeUnit from, TimeUnit to) {
// if the same unit is passed, avoid the conversion
if (from == to) {
return amount;
}
// is from or to the larger unit?
if (from.ordinal() < to.ordinal()) { // from is smaller
return amount / from.convert(1, to);
} else {
return amount * to.convert(1, from);
}
}
}
Loading