-
Notifications
You must be signed in to change notification settings - Fork 917
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Aerospike client instrumentation #9836
base: main
Are you sure you want to change the base?
Changes from 7 commits
faf4a92
a03903c
ecdd747
226b9e1
58f1b46
ec950dc
14f1109
4133b58
b4af69a
d1818c1
e82bdcb
7c17dfc
5da5b5b
5059c8e
93da28f
a30b6d7
7f84218
afda86d
0ef5f40
3a3e509
7d2f3a5
cc92b86
453c2b9
cfc0227
3b6ab9b
c34b20d
72c35de
79765c5
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,115 @@ | ||
/* | ||
* Copyright The OpenTelemetry Authors | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
package io.opentelemetry.instrumentation.api.instrumenter.db; | ||
|
||
import static io.opentelemetry.instrumentation.api.instrumenter.db.DbMessageSizeUtil.getMessageSize; | ||
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.DoubleHistogramBuilder; | ||
import io.opentelemetry.api.metrics.LongCounter; | ||
import io.opentelemetry.api.metrics.LongCounterBuilder; | ||
import io.opentelemetry.api.metrics.LongUpDownCounter; | ||
import io.opentelemetry.api.metrics.LongUpDownCounterBuilder; | ||
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 java.util.concurrent.TimeUnit; | ||
import java.util.logging.Logger; | ||
|
||
public final class AerospikeMetrics implements OperationListener { | ||
private static final double NANOS_PER_MS = TimeUnit.MILLISECONDS.toNanos(1); | ||
|
||
private static final ContextKey<State> AEROSPIKE_CLIENT_METRICS_STATE = | ||
ContextKey.named("aerospike-client-metrics-state"); | ||
|
||
private static final Logger logger = Logger.getLogger(AerospikeMetrics.class.getName()); | ||
|
||
private final LongCounter requestCounter; | ||
private final LongCounter responseCounter; | ||
private final LongUpDownCounter concurrencyUpDownCounter; | ||
private final DoubleHistogram clientLatencyHistogram; | ||
|
||
@SuppressWarnings("unused") | ||
private final DoubleHistogram recordSizeHistogram; | ||
|
||
private AerospikeMetrics(Meter meter) { | ||
LongCounterBuilder requestCounterBuilder = | ||
meter.counterBuilder("aerospike.requests").setDescription("Aerospike Calls"); | ||
AerospikeMetricsAdvice.applyRequestCounterAdvice(requestCounterBuilder); | ||
requestCounter = requestCounterBuilder.build(); | ||
LongCounterBuilder responseCounterBuilder = | ||
meter.counterBuilder("aerospike.response").setDescription("Aerospike Responses"); | ||
AerospikeMetricsAdvice.applyResponseCounterAdvice(responseCounterBuilder); | ||
responseCounter = responseCounterBuilder.build(); | ||
LongUpDownCounterBuilder concurrencyUpDownCounterBuilder = | ||
meter | ||
.upDownCounterBuilder("aerospike.concurrreny") | ||
.setDescription("Aerospike Concurrent Requests"); | ||
AerospikeMetricsAdvice.applyConcurrencyUpDownCounterAdvice(concurrencyUpDownCounterBuilder); | ||
concurrencyUpDownCounter = concurrencyUpDownCounterBuilder.build(); | ||
DoubleHistogramBuilder durationBuilder = | ||
meter | ||
.histogramBuilder("aerospike.client.duration") | ||
.setDescription("Aerospike Response Latency") | ||
.setUnit("ms"); | ||
AerospikeMetricsAdvice.applyClientDurationAdvice(durationBuilder); | ||
clientLatencyHistogram = durationBuilder.build(); | ||
DoubleHistogramBuilder recordSizeHistogramBuilder = | ||
meter | ||
.histogramBuilder("aerospike.record.size") | ||
.setDescription("Aerospike Record Size") | ||
.setUnit("By"); | ||
AerospikeMetricsAdvice.applyRecordSizeAdvice(recordSizeHistogramBuilder); | ||
recordSizeHistogram = recordSizeHistogramBuilder.build(); | ||
} | ||
|
||
public static OperationMetrics get() { | ||
return AerospikeMetrics::new; | ||
} | ||
|
||
@Override | ||
public Context onStart(Context context, Attributes startAttributes, long startNanos) { | ||
requestCounter.add(1, startAttributes, context); | ||
concurrencyUpDownCounter.add(1, startAttributes, context); | ||
return context.with( | ||
AEROSPIKE_CLIENT_METRICS_STATE, | ||
new AutoValue_AerospikeMetrics_State(startAttributes, startNanos)); | ||
} | ||
|
||
@Override | ||
public void onEnd(Context context, Attributes endAttributes, long endNanos) { | ||
State state = context.get(AEROSPIKE_CLIENT_METRICS_STATE); | ||
if (state == null) { | ||
logger.log( | ||
FINE, | ||
"No state present when ending context {0}. Cannot record Aerospike End Call metrics.", | ||
context); | ||
return; | ||
} | ||
concurrencyUpDownCounter.add(-1, state.startAttributes(), context); | ||
Attributes mergedAttributes = state.startAttributes().toBuilder().putAll(endAttributes).build(); | ||
responseCounter.add(1, mergedAttributes, context); | ||
clientLatencyHistogram.record( | ||
(endNanos - state.startTimeNanos()) / NANOS_PER_MS, mergedAttributes, context); | ||
Long requestBodySize = getMessageSize(mergedAttributes); | ||
if (requestBodySize != null) { | ||
recordSizeHistogram.record(requestBodySize, mergedAttributes, context); | ||
} | ||
} | ||
|
||
@AutoValue | ||
abstract static class State { | ||
|
||
abstract Attributes startAttributes(); | ||
|
||
abstract long startTimeNanos(); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,163 @@ | ||
/* | ||
* Copyright The OpenTelemetry Authors | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
package io.opentelemetry.instrumentation.api.instrumenter.db; | ||
|
||
import io.opentelemetry.api.common.AttributeKey; | ||
import io.opentelemetry.api.metrics.DoubleHistogramBuilder; | ||
import io.opentelemetry.api.metrics.LongCounterBuilder; | ||
import io.opentelemetry.api.metrics.LongUpDownCounterBuilder; | ||
import io.opentelemetry.extension.incubator.metrics.ExtendedDoubleHistogramBuilder; | ||
import io.opentelemetry.extension.incubator.metrics.ExtendedLongCounterBuilder; | ||
import io.opentelemetry.extension.incubator.metrics.ExtendedLongUpDownCounterBuilder; | ||
import io.opentelemetry.instrumentation.api.internal.SemconvStability; | ||
import io.opentelemetry.semconv.SemanticAttributes; | ||
import java.util.ArrayList; | ||
import java.util.List; | ||
|
||
final class AerospikeMetricsAdvice { | ||
private AerospikeMetricsAdvice() {} | ||
|
||
@SuppressWarnings("deprecation") // until old http semconv are dropped in 2.0 | ||
static void applyRequestCounterAdvice(LongCounterBuilder builder) { | ||
if (!(builder instanceof ExtendedLongCounterBuilder)) { | ||
return; | ||
} | ||
|
||
List<AttributeKey<?>> attributes = new ArrayList<>(); | ||
attributes.add(SemanticAttributes.DB_SYSTEM); | ||
attributes.add(SemanticAttributes.DB_OPERATION); | ||
attributes.add(AerospikeSemanticAttributes.AEROSPIKE_NAMESPACE); | ||
attributes.add(AerospikeSemanticAttributes.AEROSPIKE_SET_NAME); | ||
attributes.add(AerospikeSemanticAttributes.AEROSPIKE_USER_KEY); | ||
if (SemconvStability.emitStableHttpSemconv()) { | ||
attributes.add(SemanticAttributes.NETWORK_TYPE); | ||
attributes.add(SemanticAttributes.NETWORK_TRANSPORT); | ||
attributes.add(SemanticAttributes.SERVER_ADDRESS); | ||
attributes.add(SemanticAttributes.SERVER_PORT); | ||
} | ||
if (SemconvStability.emitOldHttpSemconv()) { | ||
attributes.add(SemanticAttributes.NET_SOCK_PEER_ADDR); | ||
attributes.add(SemanticAttributes.NET_SOCK_PEER_NAME); | ||
attributes.add(SemanticAttributes.NET_SOCK_PEER_PORT); | ||
} | ||
|
||
((ExtendedLongCounterBuilder) builder).setAttributesAdvice(attributes); | ||
} | ||
|
||
@SuppressWarnings("deprecation") // until old http semconv are dropped in 2.0 | ||
static void applyConcurrencyUpDownCounterAdvice(LongUpDownCounterBuilder builder) { | ||
if (!(builder instanceof ExtendedLongUpDownCounterBuilder)) { | ||
return; | ||
} | ||
|
||
List<AttributeKey<?>> attributes = new ArrayList<>(); | ||
attributes.add(SemanticAttributes.DB_SYSTEM); | ||
attributes.add(SemanticAttributes.DB_OPERATION); | ||
attributes.add(AerospikeSemanticAttributes.AEROSPIKE_NAMESPACE); | ||
attributes.add(AerospikeSemanticAttributes.AEROSPIKE_SET_NAME); | ||
attributes.add(AerospikeSemanticAttributes.AEROSPIKE_USER_KEY); | ||
if (SemconvStability.emitStableHttpSemconv()) { | ||
attributes.add(SemanticAttributes.NETWORK_TYPE); | ||
attributes.add(SemanticAttributes.NETWORK_TRANSPORT); | ||
attributes.add(SemanticAttributes.SERVER_ADDRESS); | ||
attributes.add(SemanticAttributes.SERVER_PORT); | ||
} | ||
if (SemconvStability.emitOldHttpSemconv()) { | ||
attributes.add(SemanticAttributes.NET_SOCK_PEER_ADDR); | ||
attributes.add(SemanticAttributes.NET_SOCK_PEER_NAME); | ||
attributes.add(SemanticAttributes.NET_SOCK_PEER_PORT); | ||
} | ||
|
||
((ExtendedLongUpDownCounterBuilder) builder).setAttributesAdvice(attributes); | ||
} | ||
|
||
@SuppressWarnings("deprecation") // until old http semconv are dropped in 2.0 | ||
static void applyResponseCounterAdvice(LongCounterBuilder builder) { | ||
if (!(builder instanceof ExtendedLongCounterBuilder)) { | ||
return; | ||
} | ||
|
||
List<AttributeKey<?>> attributes = new ArrayList<>(); | ||
attributes.add(SemanticAttributes.DB_SYSTEM); | ||
attributes.add(SemanticAttributes.DB_OPERATION); | ||
attributes.add(AerospikeSemanticAttributes.AEROSPIKE_NAMESPACE); | ||
attributes.add(AerospikeSemanticAttributes.AEROSPIKE_SET_NAME); | ||
attributes.add(AerospikeSemanticAttributes.AEROSPIKE_USER_KEY); | ||
attributes.add(AerospikeSemanticAttributes.AEROSPIKE_STATUS); | ||
attributes.add(AerospikeSemanticAttributes.AEROSPIKE_ERROR_CODE); | ||
if (SemconvStability.emitStableHttpSemconv()) { | ||
attributes.add(SemanticAttributes.NETWORK_TYPE); | ||
attributes.add(SemanticAttributes.NETWORK_TRANSPORT); | ||
attributes.add(SemanticAttributes.SERVER_ADDRESS); | ||
attributes.add(SemanticAttributes.SERVER_PORT); | ||
} | ||
if (SemconvStability.emitOldHttpSemconv()) { | ||
attributes.add(SemanticAttributes.NET_SOCK_PEER_ADDR); | ||
attributes.add(SemanticAttributes.NET_SOCK_PEER_NAME); | ||
attributes.add(SemanticAttributes.NET_SOCK_PEER_PORT); | ||
} | ||
|
||
((ExtendedLongCounterBuilder) builder).setAttributesAdvice(attributes); | ||
} | ||
|
||
@SuppressWarnings("deprecation") // until old http semconv are dropped in 2.0 | ||
static void applyClientDurationAdvice(DoubleHistogramBuilder builder) { | ||
if (!(builder instanceof ExtendedDoubleHistogramBuilder)) { | ||
return; | ||
} | ||
|
||
List<AttributeKey<?>> attributes = new ArrayList<>(); | ||
attributes.add(SemanticAttributes.DB_SYSTEM); | ||
attributes.add(SemanticAttributes.DB_OPERATION); | ||
attributes.add(AerospikeSemanticAttributes.AEROSPIKE_NAMESPACE); | ||
attributes.add(AerospikeSemanticAttributes.AEROSPIKE_SET_NAME); | ||
attributes.add(AerospikeSemanticAttributes.AEROSPIKE_USER_KEY); | ||
attributes.add(AerospikeSemanticAttributes.AEROSPIKE_STATUS); | ||
attributes.add(AerospikeSemanticAttributes.AEROSPIKE_ERROR_CODE); | ||
if (SemconvStability.emitStableHttpSemconv()) { | ||
attributes.add(SemanticAttributes.NETWORK_TYPE); | ||
attributes.add(SemanticAttributes.NETWORK_TRANSPORT); | ||
attributes.add(SemanticAttributes.SERVER_ADDRESS); | ||
attributes.add(SemanticAttributes.SERVER_PORT); | ||
} | ||
if (SemconvStability.emitOldHttpSemconv()) { | ||
attributes.add(SemanticAttributes.NET_SOCK_PEER_ADDR); | ||
attributes.add(SemanticAttributes.NET_SOCK_PEER_NAME); | ||
attributes.add(SemanticAttributes.NET_SOCK_PEER_PORT); | ||
} | ||
|
||
((ExtendedDoubleHistogramBuilder) builder).setAttributesAdvice(attributes); | ||
} | ||
|
||
@SuppressWarnings("deprecation") // until old http semconv are dropped in 2.0 | ||
static void applyRecordSizeAdvice(DoubleHistogramBuilder builder) { | ||
if (!(builder instanceof ExtendedDoubleHistogramBuilder)) { | ||
return; | ||
} | ||
|
||
List<AttributeKey<?>> attributes = new ArrayList<>(); | ||
attributes.add(SemanticAttributes.DB_SYSTEM); | ||
attributes.add(SemanticAttributes.DB_OPERATION); | ||
attributes.add(AerospikeSemanticAttributes.AEROSPIKE_NAMESPACE); | ||
attributes.add(AerospikeSemanticAttributes.AEROSPIKE_SET_NAME); | ||
attributes.add(AerospikeSemanticAttributes.AEROSPIKE_USER_KEY); | ||
attributes.add(AerospikeSemanticAttributes.AEROSPIKE_ERROR_CODE); | ||
attributes.add(AerospikeSemanticAttributes.AEROSPIKE_STATUS); | ||
if (SemconvStability.emitStableHttpSemconv()) { | ||
attributes.add(SemanticAttributes.NETWORK_TYPE); | ||
attributes.add(SemanticAttributes.NETWORK_TRANSPORT); | ||
attributes.add(SemanticAttributes.SERVER_ADDRESS); | ||
attributes.add(SemanticAttributes.SERVER_PORT); | ||
} | ||
if (SemconvStability.emitOldHttpSemconv()) { | ||
attributes.add(SemanticAttributes.NET_SOCK_PEER_ADDR); | ||
attributes.add(SemanticAttributes.NET_SOCK_PEER_NAME); | ||
attributes.add(SemanticAttributes.NET_SOCK_PEER_PORT); | ||
} | ||
|
||
((ExtendedDoubleHistogramBuilder) builder).setAttributesAdvice(attributes); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
/* | ||
* Copyright The OpenTelemetry Authors | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
package io.opentelemetry.instrumentation.api.instrumenter.db; | ||
|
||
import static io.opentelemetry.api.common.AttributeKey.longKey; | ||
import static io.opentelemetry.api.common.AttributeKey.stringKey; | ||
|
||
import io.opentelemetry.api.common.AttributeKey; | ||
|
||
public final class AerospikeSemanticAttributes { | ||
private AerospikeSemanticAttributes() {} | ||
|
||
public static final AttributeKey<String> AEROSPIKE_STATUS = stringKey("aerospike.status"); | ||
public static final AttributeKey<Long> AEROSPIKE_ERROR_CODE = longKey("aerospike.error.code"); | ||
public static final AttributeKey<String> AEROSPIKE_NAMESPACE = stringKey("aerospike.namespace"); | ||
public static final AttributeKey<String> AEROSPIKE_SET_NAME = stringKey("aerospike.set.name"); | ||
public static final AttributeKey<String> AEROSPIKE_USER_KEY = stringKey("aerospike.user.key"); | ||
public static final AttributeKey<Long> AEROSPIKE_TRANSFER_SIZE = | ||
longKey("aerospike.transfer.size"); | ||
|
||
public static final class DbSystemValues { | ||
public static final String AEROSPIKE = "aerospike"; | ||
|
||
private DbSystemValues() {} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
/* | ||
* Copyright The OpenTelemetry Authors | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
package io.opentelemetry.instrumentation.api.instrumenter.db; | ||
|
||
import io.opentelemetry.api.common.AttributeKey; | ||
import io.opentelemetry.api.common.Attributes; | ||
import javax.annotation.Nullable; | ||
|
||
final class DbMessageSizeUtil { | ||
|
||
@Nullable | ||
static Long getMessageSize(Attributes... attributesList) { | ||
return getAttribute(AerospikeSemanticAttributes.AEROSPIKE_TRANSFER_SIZE, attributesList); | ||
} | ||
|
||
@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; | ||
} | ||
|
||
private DbMessageSizeUtil() {} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
plugins { | ||
id("otel.javaagent-instrumentation") | ||
} | ||
|
||
muzzle { | ||
pass { | ||
group.set("com.aerospike") | ||
module.set("aerospike-client") | ||
versions.set("[7.1.0,)") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. usually we also add There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Added, assertInverse |
||
} | ||
} | ||
|
||
dependencies { | ||
library("com.aerospike:aerospike-client:7.1.0") | ||
|
||
compileOnly("com.google.auto.value:auto-value-annotations") | ||
annotationProcessor("com.google.auto.value:auto-value") | ||
testInstrumentation(project(":instrumentation:aerospike-client:aerospike-client-7.1:javaagent")) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. should be added automatically There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, changed it to use the framework instrumentation library. |
||
} | ||
|
||
tasks { | ||
test { | ||
jvmArgs("-Djava.net.preferIPv4Stack=true") | ||
usesService(gradle.sharedServices.registrations["testcontainersBuildService"].service) | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Usually we place framework specific instrumentation classes with the framework instrumentation not here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Moved it to the library in framework instrumentation.