Skip to content

Commit 822ec72

Browse files
committed
more
1 parent e2c1195 commit 822ec72

33 files changed

Lines changed: 178 additions & 42 deletions

File tree

.github/agents/knowledge/javaagent-module-patterns.md

Lines changed: 122 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,22 @@ The compact form does **not** apply when matchers are chained (e.g., positive +
150150
In that case, follow the multi-class rule: place each version comment directly above its
151151
class name string.
152152

153+
When the positive matcher in a chain still has a **single inline class string**, keep that
154+
class on the `return hasClassesNamed("...")` line and place its version comment on the
155+
preceding line. Place the negated matcher's comment above the `.and(...)` call. This keeps
156+
the compact look for chained-with-single-positive shapes:
157+
158+
```java
159+
// added in 4.0.0.Final
160+
return hasClassesNamed("io.netty.handler.codec.http.HttpMessage")
161+
// added in 4.1.0.Final
162+
.and(not(hasClassesNamed("io.netty.handler.codec.http.CombinedHttpHeaders")));
163+
```
164+
165+
Only break the positive class onto its own line (with the comment indented above it) when
166+
there are multiple positive classes, or when the chained landmark requires a multi-line
167+
two-line form (such as the artifact-presence-gate two-liner).
168+
153169
**How to identify ceiling classes**: look for a **newer sibling module** for the same
154170
library, such as `mongo-4.0` next to `mongo-3.7`. If the newer module's
155171
`classLoaderMatcher()` checks a different variant of the same class, such as
@@ -213,7 +229,8 @@ OpenTelemetry instrumentation and the agent should opt out.
213229
public ElementMatcher.Junction<ClassLoader> classLoaderMatcher() {
214230
// added in 7.0.0
215231
return hasClassesNamed("org.elasticsearch.client.RestClient$InternalRequest")
216-
// added in 8.10 (native OTel support)
232+
// artifact presence gate (native OTel support)
233+
// added in co.elastic.clients:elasticsearch-java 8.10
217234
.and(not(hasClassesNamed(
218235
"co.elastic.clients.transport.instrumentation.Instrumentation")));
219236
}
@@ -226,11 +243,115 @@ public ElementMatcher.Junction<ClassLoader> classLoaderMatcher() {
226243
public ElementMatcher.Junction<ClassLoader> classLoaderMatcher() {
227244
// added in 1.53
228245
return hasClassesNamed("com.azure.core.util.LibraryTelemetryOptions")
246+
// artifact presence gate (native OTel support)
229247
// added in com.azure:azure-core-tracing-opentelemetry 1.0.0-beta.47
230248
.and(not(hasClassesNamed("com.azure.core.tracing.opentelemetry.OpenTelemetryTracer")));
231249
}
232250
```
233251

252+
#### Main target artifact
253+
254+
Bare version numbers like `// added in 2.2.0` resolve to **the `InstrumentationModule`'s main
255+
target artifact**, which is normally the artifact pinned by the module's muzzle
256+
`pass { group + module }` block in `build.gradle.kts`.
257+
258+
When a single gradle module hosts **multiple `InstrumentationModule` classes targeting
259+
different artifacts** (rare — for example `aws-sdk-2.2/javaagent` has separate
260+
`InstrumentationModule`s for `:aws-core`, `:sqs`, `:sns`, `:lambda`, and `:bedrock-runtime`),
261+
open each `classLoaderMatcher()` with a one-line comment naming the target artifact. Bare
262+
version numbers in the landmark comments then resolve unambiguously to that artifact.
263+
264+
```java
265+
@Override
266+
public ElementMatcher.Junction<ClassLoader> classLoaderMatcher() {
267+
// this instrumentation module targets software.amazon.awssdk:lambda
268+
return hasClassesNamed(
269+
// added in 2.2.0
270+
"software.amazon.awssdk.services.lambda.model.InvokeRequest",
271+
// added in 2.17.0 (via software.amazon.awssdk:json-utils 2.17.0)
272+
"software.amazon.awssdk.protocols.jsoncore.JsonNode");
273+
}
274+
```
275+
276+
`(via groupId:artifactId A.B)` still means the landmark lives in a required transitive of
277+
the target artifact. `// added in groupId:artifactId X.Y` (no `via`) still means the landmark
278+
lives in an independent, opt-in artifact whose presence itself is the gate.
279+
280+
Single-`InstrumentationModule` gradle modules do not need this header.
281+
282+
#### Artifact presence gate annotation
283+
284+
When a landmark class lives in an **opt-in artifact that is not the module's target
285+
artifact**, use a two-line role comment: `// artifact presence gate` followed by
286+
`// added in groupId:artifactId X.Y`. Parenthetical context goes on whichever line it
287+
qualifies — attach it to `artifact presence gate` when it describes **why** the gate
288+
exists (e.g. `native OTel support`), and to `added in …` when it qualifies the **coordinate
289+
or version** (e.g. `renamed from extension.incubator`):
290+
291+
```java
292+
// artifact presence gate
293+
// added in groupId:artifactId X.Y
294+
```
295+
296+
```java
297+
// artifact presence gate (why the gate exists)
298+
// added in groupId:artifactId X.Y
299+
```
300+
301+
```java
302+
// artifact presence gate
303+
// added in groupId:artifactId X.Y (coordinate/version qualifier)
304+
```
305+
306+
The `artifact presence gate` label signals "this check is not pinning a version
307+
boundary of the target artifact — it is detecting that an independent, opt-in dependency
308+
is on the classpath". The version X.Y is the first version of that opt-in artifact where
309+
the class existed, for completeness. "Artifact presence" distinguishes this from the
310+
ordinary class-presence role of `hasClassesNamed` itself.
311+
312+
Typical cases:
313+
314+
- `.and(not(hasClassesNamed(...)))` to back off when a separately-shipped native OTel
315+
bridge is present.
316+
- `.and(hasClassesNamed(...))` to require an add-on that is not a required transitive of
317+
the target artifact.
318+
319+
Examples:
320+
321+
```java
322+
// artifact presence gate (native OTel support)
323+
// added in com.azure:azure-core-tracing-opentelemetry 1.0.0-beta.47
324+
.and(not(hasClassesNamed("com.azure.core.tracing.opentelemetry.OpenTelemetryTracer")));
325+
```
326+
327+
```java
328+
// artifact presence gate (native OTel support)
329+
// added in co.elastic.clients:elasticsearch-java 8.10
330+
.and(not(hasClassesNamed("co.elastic.clients.transport.instrumentation.Instrumentation")));
331+
```
332+
333+
Do **not** use the `artifact presence gate` label when the landmark class lives in the
334+
target artifact or a required transitive — those are ordinary version boundaries and use
335+
the usual role comments (`// added in X.Y`, `// added in X.Y (via groupId:artifactId A.B)`).
336+
Conversely, do not omit the `groupId:artifactId` qualifier on the `added in` line when
337+
using the `artifact presence gate` label: the label and the qualifier always go together.
338+
339+
#### `io.opentelemetry*` groupId shorthand
340+
341+
For artifacts whose `groupId` starts with `io.opentelemetry` (for example
342+
`io.opentelemetry:opentelemetry-api`, `io.opentelemetry:opentelemetry-api-incubator`,
343+
`io.opentelemetry.instrumentation:opentelemetry-instrumentation-annotations`), omit the
344+
`groupId` and use just the artifact name in role comments:
345+
346+
```java
347+
// added in opentelemetry-api 1.38.0
348+
// artifact presence gate
349+
// added in opentelemetry-instrumentation-annotations 1.16.0
350+
```
351+
352+
The shorthand does **not** apply to non-OpenTelemetry artifacts — those always use the
353+
full coordinate.
354+
234355
#### Rules for `classLoaderMatcher()`
235356

236357
- **Do NOT add `classLoaderMatcher()` for optimization.** The "skip when library is absent"

instrumentation/aws-sdk/aws-sdk-1.11/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/awssdk/v1_11/AbstractAwsSdkInstrumentationModule.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,7 @@ public String getModuleGroup() {
3737

3838
@Override
3939
public ElementMatcher.Junction<ClassLoader> classLoaderMatcher() {
40-
// We don't actually transform it but want to make sure we only apply the instrumentation when
41-
// our key dependency is present.
40+
// added in com.amazonaws:aws-java-sdk-core 1.10.33
4241
return hasClassesNamed("com.amazonaws.AmazonWebServiceClient");
4342
}
4443

instrumentation/aws-sdk/aws-sdk-2.2/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/awssdk/v2_2/AbstractAwsSdkInstrumentationModule.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,7 @@ public boolean isHelperClass(String className) {
3636

3737
@Override
3838
public ElementMatcher.Junction<ClassLoader> classLoaderMatcher() {
39-
// We don't actually transform it but want to make sure we only apply the instrumentation when
40-
// our key dependency is present.
39+
// added in 2.2.0
4140
return hasClassesNamed("software.amazon.awssdk.core.interceptor.ExecutionInterceptor");
4241
}
4342

instrumentation/aws-sdk/aws-sdk-2.2/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/awssdk/v2_2/BedrockRuntimeInstrumentationModule.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ public BedrockRuntimeInstrumentationModule() {
2727

2828
@Override
2929
public ElementMatcher.Junction<ClassLoader> classLoaderMatcher() {
30+
// this instrumentation module targets software.amazon.awssdk:bedrockruntime
31+
// added in 2.25.63
3032
return hasClassesNamed("software.amazon.awssdk.services.bedrockruntime.BedrockRuntimeClient");
3133
}
3234

instrumentation/aws-sdk/aws-sdk-2.2/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/awssdk/v2_2/LambdaInstrumentationModule.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,11 @@ public LambdaInstrumentationModule() {
2424

2525
@Override
2626
public ElementMatcher.Junction<ClassLoader> classLoaderMatcher() {
27+
// this instrumentation module targets software.amazon.awssdk:lambda
2728
return hasClassesNamed(
29+
// added in 2.2.0
2830
"software.amazon.awssdk.services.lambda.model.InvokeRequest",
29-
// added in software.amazon.awssdk:json-utils 2.17.0
31+
// added in 2.17.0 (via software.amazon.awssdk:json-utils 2.17.0)
3032
"software.amazon.awssdk.protocols.jsoncore.JsonNode");
3133
}
3234

instrumentation/aws-sdk/aws-sdk-2.2/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/awssdk/v2_2/SnsInstrumentationModule.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ public SnsInstrumentationModule() {
2424

2525
@Override
2626
public ElementMatcher.Junction<ClassLoader> classLoaderMatcher() {
27+
// this instrumentation module targets software.amazon.awssdk:sns
28+
// added in 2.2.0
2729
return hasClassesNamed("software.amazon.awssdk.services.sns.SnsClient");
2830
}
2931

instrumentation/aws-sdk/aws-sdk-2.2/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/awssdk/v2_2/SqsInstrumentationModule.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ public SqsInstrumentationModule() {
2727

2828
@Override
2929
public ElementMatcher.Junction<ClassLoader> classLoaderMatcher() {
30+
// this instrumentation module targets software.amazon.awssdk:sqs
31+
// added in 2.2.0
3032
return hasClassesNamed("software.amazon.awssdk.services.sqs.SqsClient");
3133
}
3234

instrumentation/azure-core/azure-core-1.14/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/azurecore/v1_14/AzureSdkInstrumentationModule.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,8 @@ public ElementMatcher.Junction<ClassLoader> classLoaderMatcher() {
5050
return hasClassesNamed("com.azure.core.util.tracing.Tracer")
5151
// added in 1.19.0
5252
.and(not(hasClassesNamed("com.azure.core.util.tracing.StartSpanOptions")))
53-
// added in com.azure:azure-core-tracing-opentelemetry 1.0.0-beta.47 (native OTel support)
53+
// artifact presence gate (provides native OTel support)
54+
// added in com.azure:azure-core-tracing-opentelemetry 1.0.0-beta.47
5455
.and(not(hasClassesNamed("com.azure.core.tracing.opentelemetry.OpenTelemetryTracer")));
5556
}
5657

instrumentation/azure-core/azure-core-1.19/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/azurecore/v1_19/AzureSdkInstrumentationModule.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,8 @@ public ElementMatcher.Junction<ClassLoader> classLoaderMatcher() {
5050
return hasClassesNamed("com.azure.core.util.tracing.StartSpanOptions")
5151
// added in 1.36
5252
.and(not(hasClassesNamed("com.azure.core.util.tracing.TracerProvider")))
53-
// added in com.azure:azure-core-tracing-opentelemetry 1.0.0-beta.47 (native OTel support)
53+
// artifact presence gate (provides native OTel support)
54+
// added in com.azure:azure-core-tracing-opentelemetry 1.0.0-beta.47
5455
.and(not(hasClassesNamed("com.azure.core.tracing.opentelemetry.OpenTelemetryTracer")));
5556
}
5657

instrumentation/azure-core/azure-core-1.36/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/azurecore/v1_36/AzureSdkInstrumentationModule.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,8 @@ public ElementMatcher.Junction<ClassLoader> classLoaderMatcher() {
5252
return hasClassesNamed("com.azure.core.util.tracing.TracerProvider")
5353
// added in 1.53
5454
.and(not(hasClassesNamed("com.azure.core.util.LibraryTelemetryOptions")))
55-
// added in com.azure:azure-core-tracing-opentelemetry 1.0.0-beta.47 (native OTel support)
55+
// artifact presence gate (provides native OTel support)
56+
// added in com.azure:azure-core-tracing-opentelemetry 1.0.0-beta.47
5657
.and(not(hasClassesNamed("com.azure.core.tracing.opentelemetry.OpenTelemetryTracer")));
5758
}
5859

0 commit comments

Comments
 (0)