Skip to content

Commit 3c7adf0

Browse files
aerospike instrumentation.
1 parent 1e50060 commit 3c7adf0

File tree

14 files changed

+1153
-0
lines changed

14 files changed

+1153
-0
lines changed
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
kotlin version: 2.2.0
2+
error message: Daemon compilation failed: Not enough memory to run compilation. Try to increase it via 'gradle.properties':
3+
kotlin.daemon.jvmargs=-Xmx<size>
4+
org.jetbrains.kotlin.gradle.tasks.OOMErrorException: Not enough memory to run compilation. Try to increase it via 'gradle.properties':
5+
kotlin.daemon.jvmargs=-Xmx<size>
6+
at org.jetbrains.kotlin.gradle.tasks.TasksUtilsKt.OOMErrorException(tasksUtils.kt:83)
7+
at org.jetbrains.kotlin.gradle.tasks.TasksUtilsKt.wrapCompilationExceptionIfNeeded(tasksUtils.kt:52)
8+
at org.jetbrains.kotlin.gradle.tasks.TasksUtilsKt.wrapAndRethrowCompilationException(tasksUtils.kt:65)
9+
at org.jetbrains.kotlin.compilerRunner.GradleKotlinCompilerWork.compileWithDaemon(GradleKotlinCompilerWork.kt:243)
10+
at org.jetbrains.kotlin.compilerRunner.GradleKotlinCompilerWork.compileWithDaemonOrFallbackImpl(GradleKotlinCompilerWork.kt:159)
11+
at org.jetbrains.kotlin.compilerRunner.GradleKotlinCompilerWork.run(GradleKotlinCompilerWork.kt:111)
12+
at org.jetbrains.kotlin.compilerRunner.GradleCompilerRunnerWithWorkers$GradleKotlinCompilerWorkAction.execute(GradleCompilerRunnerWithWorkers.kt:74)
13+
at org.gradle.workers.internal.DefaultWorkerServer.execute(DefaultWorkerServer.java:68)
14+
at org.gradle.workers.internal.NoIsolationWorkerFactory$1$1.create(NoIsolationWorkerFactory.java:66)
15+
at org.gradle.workers.internal.NoIsolationWorkerFactory$1$1.create(NoIsolationWorkerFactory.java:62)
16+
at org.gradle.internal.classloader.ClassLoaderUtils.executeInClassloader(ClassLoaderUtils.java:100)
17+
at org.gradle.workers.internal.NoIsolationWorkerFactory$1.lambda$execute$0(NoIsolationWorkerFactory.java:62)
18+
at org.gradle.workers.internal.AbstractWorker$1.call(AbstractWorker.java:44)
19+
at org.gradle.workers.internal.AbstractWorker$1.call(AbstractWorker.java:41)
20+
at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:209)
21+
at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:204)
22+
at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:66)
23+
at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:59)
24+
at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:166)
25+
at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:59)
26+
at org.gradle.internal.operations.DefaultBuildOperationRunner.call(DefaultBuildOperationRunner.java:53)
27+
at org.gradle.workers.internal.AbstractWorker.executeWrappedInBuildOperation(AbstractWorker.java:41)
28+
at org.gradle.workers.internal.NoIsolationWorkerFactory$1.execute(NoIsolationWorkerFactory.java:59)
29+
at org.gradle.workers.internal.DefaultWorkerExecutor.lambda$submitWork$0(DefaultWorkerExecutor.java:176)
30+
at java.base/java.util.concurrent.FutureTask.run(Unknown Source)
31+
at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner.runExecution(DefaultConditionalExecutionQueue.java:194)
32+
at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner.access$700(DefaultConditionalExecutionQueue.java:127)
33+
at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner$1.run(DefaultConditionalExecutionQueue.java:169)
34+
at org.gradle.internal.Factories$1.create(Factories.java:31)
35+
at org.gradle.internal.work.DefaultWorkerLeaseService.withLocks(DefaultWorkerLeaseService.java:263)
36+
at org.gradle.internal.work.DefaultWorkerLeaseService.runAsWorkerThread(DefaultWorkerLeaseService.java:127)
37+
at org.gradle.internal.work.DefaultWorkerLeaseService.runAsWorkerThread(DefaultWorkerLeaseService.java:132)
38+
at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner.runBatch(DefaultConditionalExecutionQueue.java:164)
39+
at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner.run(DefaultConditionalExecutionQueue.java:133)
40+
at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Unknown Source)
41+
at java.base/java.util.concurrent.FutureTask.run(Unknown Source)
42+
at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:64)
43+
at org.gradle.internal.concurrent.AbstractManagedExecutor$1.run(AbstractManagedExecutor.java:47)
44+
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
45+
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
46+
at java.base/java.lang.Thread.run(Unknown Source)
47+
48+
Lines changed: 187 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,187 @@
1+
# Vert.x Aerospike Client Instrumentation
2+
3+
This module provides OpenTelemetry instrumentation for Aerospike database operations in Vert.x applications.
4+
5+
## Overview
6+
7+
This instrumentation automatically creates spans for Aerospike database operations (GET, PUT, DELETE, etc.) with relevant attributes following OpenTelemetry semantic conventions for database clients.
8+
9+
## Status
10+
11+
⚠️ **This is a template/starter module** - It requires customization based on your actual Aerospike client implementation with Vert.x.
12+
13+
## Setup Required
14+
15+
### 1. Update Dependencies
16+
17+
In `build.gradle.kts`, update the Aerospike client dependency to match your actual library:
18+
19+
```kotlin
20+
library("io.vertx:vertx-aerospike-client:3.9.0") // If such library exists
21+
// OR
22+
library("com.aerospike:aerospike-client:5.0.0") // Standard Aerospike client
23+
```
24+
25+
### 2. Customize Type Matcher
26+
27+
In `AerospikeClientInstrumentation.java`, update the `typeMatcher()` to match your actual client class:
28+
29+
```java
30+
@Override
31+
public ElementMatcher<TypeDescription> typeMatcher() {
32+
// Replace with actual class name
33+
return named("your.actual.aerospike.Client");
34+
}
35+
```
36+
37+
### 3. Adjust Method Matchers
38+
39+
Update the method matchers to match the actual API methods you want to instrument:
40+
41+
```java
42+
transformer.applyAdviceToMethod(
43+
isMethod()
44+
.and(named("get")) // Match your actual method names
45+
.and(takesArgument(0, ...)), // Match actual parameter types
46+
...
47+
);
48+
```
49+
50+
### 4. Extract Request Metadata
51+
52+
In `AerospikeClientInstrumentation.createRequest()`, implement actual metadata extraction:
53+
54+
```java
55+
private static AerospikeRequest createRequest(String operation, Object key) {
56+
// Extract namespace, set, host, port from actual Aerospike Key/Client
57+
if (key instanceof com.aerospike.client.Key) {
58+
com.aerospike.client.Key aerospikeKey = (com.aerospike.client.Key) key;
59+
String namespace = aerospikeKey.namespace;
60+
String setName = aerospikeKey.setName;
61+
// ... extract other fields
62+
}
63+
64+
return new AerospikeRequest(operation, namespace, setName, host, port);
65+
}
66+
```
67+
68+
### 5. Handle Async Operations
69+
70+
If your Aerospike client uses async operations (like Vert.x Future/Promise), you'll need to:
71+
72+
1. Create a handler wrapper (similar to `VertxRedisClientUtil.java` in Redis module)
73+
2. Capture the context at operation start
74+
3. End the span when the Future/Promise completes
75+
76+
Example:
77+
```java
78+
// In onEnter: wrap the callback handler
79+
if (handler != null) {
80+
handler = wrapHandler(handler, request, context, parentContext);
81+
}
82+
```
83+
84+
### 6. Implement Tests
85+
86+
Update `VertxAerospikeClientTest.java`:
87+
88+
1. Add Aerospike Testcontainer setup
89+
2. Create actual Aerospike client instance
90+
3. Perform operations and verify spans
91+
4. Remove `@Disabled` annotation
92+
93+
## Building
94+
95+
```bash
96+
# Compile the module
97+
./gradlew :instrumentation:vertx:vertx-aerospike-client-3.9:javaagent:compileJava
98+
99+
# Run tests (after implementing)
100+
./gradlew :instrumentation:vertx:vertx-aerospike-client-3.9:javaagent:test
101+
102+
# Build the full agent with this instrumentation
103+
./gradlew :javaagent:shadowJar
104+
```
105+
106+
## Debugging
107+
108+
### Enable Debug Logging
109+
110+
Add to your advice code:
111+
112+
```java
113+
System.out.println("[AEROSPIKE-DEBUG] Operation: " + operation +
114+
", TraceId: " + Span.current().getSpanContext().getTraceId());
115+
```
116+
117+
### Run with Debug Agent
118+
119+
```bash
120+
java -javaagent:path/to/opentelemetry-javaagent.jar \
121+
-Dotel.javaagent.debug=true \
122+
-Dotel.traces.exporter=logging \
123+
-jar your-app.jar
124+
```
125+
126+
### Check Bytecode Transformation
127+
128+
```bash
129+
java -javaagent:path/to/opentelemetry-javaagent.jar \
130+
-Dnet.bytebuddy.dump=/tmp/bytebuddy-dump \
131+
-jar your-app.jar
132+
```
133+
134+
Then inspect `/tmp/bytebuddy-dump/` for transformed classes.
135+
136+
## Module Structure
137+
138+
```
139+
vertx-aerospike-client-3.9/
140+
├── metadata.yaml # Module description
141+
├── README.md # This file
142+
└── javaagent/
143+
├── build.gradle.kts # Build configuration
144+
└── src/
145+
├── main/java/.../aerospike/
146+
│ ├── VertxAerospikeClientInstrumentationModule.java # Entry point
147+
│ ├── AerospikeClientInstrumentation.java # Bytecode advice
148+
│ ├── AerospikeRequest.java # Request model
149+
│ ├── AerospikeAttributesGetter.java # DB attributes
150+
│ ├── AerospikeNetAttributesGetter.java # Network attributes
151+
│ └── AerospikeSingletons.java # Instrumenter setup
152+
└── test/java/.../aerospike/
153+
└── VertxAerospikeClientTest.java # Tests (TODO: implement)
154+
```
155+
156+
## Span Attributes
157+
158+
The instrumentation adds the following attributes to spans:
159+
160+
- `db.system`: "aerospike"
161+
- `db.operation.name`: Operation name (GET, PUT, DELETE, etc.)
162+
- `db.query.text`: Composed query text (e.g., "GET namespace.set")
163+
- `db.namespace`: Aerospike namespace
164+
- `db.collection.name`: Aerospike set name
165+
- `server.address`: Server hostname
166+
- `server.port`: Server port
167+
- `network.peer.address`: Peer IP address
168+
- `network.peer.port`: Peer port
169+
170+
## References
171+
172+
- [OpenTelemetry Java Instrumentation Docs](https://github.com/open-telemetry/opentelemetry-java-instrumentation)
173+
- [Writing Instrumentation Module Guide](../../docs/contributing/writing-instrumentation-module.md)
174+
- [Vert.x Redis Client Instrumentation](../vertx-redis-client-3.9/) (reference implementation)
175+
- [Aerospike Java Client](https://github.com/aerospike/aerospike-client-java)
176+
177+
## Next Steps
178+
179+
1. ✅ Basic module structure created
180+
2. ⚠️ Update dependencies to match actual Aerospike client library
181+
3. ⚠️ Customize type and method matchers for your API
182+
4. ⚠️ Implement metadata extraction from Key/Client objects
183+
5. ⚠️ Handle async operations if needed
184+
6. ⚠️ Implement and enable tests
185+
7. ⚠️ Test with real application
186+
8. ⚠️ Add VirtualField for connection info if needed
187+

0 commit comments

Comments
 (0)