Skip to content

Commit 34937d2

Browse files
add option to record transferred artifacts (#1875)
Co-authored-by: Cyrille Le Clerc <[email protected]>
1 parent b897a0e commit 34937d2

10 files changed

+383
-29
lines changed

maven-extension/README.md

+9-8
Original file line numberDiff line numberDiff line change
@@ -61,14 +61,15 @@ Without this setting, the traces won't be exported and the OpenTelemetry Maven E
6161

6262
The Maven OpenTelemetry Extension supports a subset of the [OpenTelemetry autoconfiguration environment variables and JVM system properties](https://github.com/open-telemetry/opentelemetry-java/tree/main/sdk-extensions/autoconfigure).
6363

64-
| System property <br /> Environment variable | Default value | Description |
65-
|--------------------------------------------------------------------------------------------|-------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------|
66-
| `otel.traces.exporter` <br /> `OTEL_TRACES_EXPORTER` | `none` | Select the OpenTelemetry exporter for tracing, the currently only supported values are `none` and `otlp`. `none` makes the instrumentation NoOp |
67-
| `otel.exporter.otlp.endpoint` <br /> `OTEL_EXPORTER_OTLP_ENDPOINT` | `http://localhost:4317` | The OTLP traces and metrics endpoint to connect to. Must be a URL with a scheme of either `http` or `https` based on the use of TLS. |
68-
| `otel.exporter.otlp.headers` <br /> `OTEL_EXPORTER_OTLP_HEADERS` | | Key-value pairs separated by commas to pass as request headers on OTLP trace and metrics requests. |
69-
| `otel.exporter.otlp.timeout` <br /> `OTEL_EXPORTER_OTLP_TIMEOUT` | `10000` | The maximum waiting time, in milliseconds, allowed to send each OTLP trace and metric batch. |
70-
| `otel.resource.attributes` <br /> `OTEL_RESOURCE_ATTRIBUTES` | | Specify resource attributes in the following format: key1=val1,key2=val2,key3=val3 |
71-
| `otel.instrumentation.maven.mojo.enabled` <br /> `OTEL_INSTRUMENTATION_MAVEN_MOJO_ENABLED` | `true` | Whether to create spans for mojo goal executions, `true` or `false`. Can be configured to reduce the number of spans created for large builds. |
64+
| System property <br /> Environment variable | Default value | Description |
65+
|----------------------------------------------------------------------------------------------------|-------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------|
66+
| `otel.traces.exporter` <br /> `OTEL_TRACES_EXPORTER` | `none` | Select the OpenTelemetry exporter for tracing, the currently only supported values are `none` and `otlp`. `none` makes the instrumentation NoOp |
67+
| `otel.exporter.otlp.endpoint` <br /> `OTEL_EXPORTER_OTLP_ENDPOINT` | `http://localhost:4317` | The OTLP traces and metrics endpoint to connect to. Must be a URL with a scheme of either `http` or `https` based on the use of TLS. |
68+
| `otel.exporter.otlp.headers` <br /> `OTEL_EXPORTER_OTLP_HEADERS` | | Key-value pairs separated by commas to pass as request headers on OTLP trace and metrics requests. |
69+
| `otel.exporter.otlp.timeout` <br /> `OTEL_EXPORTER_OTLP_TIMEOUT` | `10000` | The maximum waiting time, in milliseconds, allowed to send each OTLP trace and metric batch. |
70+
| `otel.resource.attributes` <br /> `OTEL_RESOURCE_ATTRIBUTES` | | Specify resource attributes in the following format: key1=val1,key2=val2,key3=val3 |
71+
| `otel.instrumentation.maven.mojo.enabled` <br /> `OTEL_INSTRUMENTATION_MAVEN_MOJO_ENABLED` | `true` | Whether to create spans for mojo goal executions, `true` or `false`. Can be configured to reduce the number of spans created for large builds. |
72+
| `otel.instrumentation.maven.transfer.enabled` <br /> `OTEL_INSTRUMENTATION_MAVEN_TRANSFER_ENABLED` | `false` | Whether to create spans for artifact transfers, `true` or `false`. Can be activated to understand impact of artifact transfers on performances. |
7273

7374
ℹ️ The `service.name` is set to `maven` and the `service.version` to the version of the Maven runtime in use.
7475

maven-extension/build.gradle.kts

+2-2
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ plugins {
66
}
77

88
// NOTE
9-
// `META-INF/sis/javax.inject.Named` is manually handled under src/main/resources because there is
9+
// `META-INF/sisu/javax.inject.Named` is manually handled under src/main/resources because there is
1010
// no Gradle equivalent to the Maven plugin `org.eclipse.sisu:sisu-maven-plugin`
1111

1212
description = "Maven extension to observe Maven builds with distributed traces using OpenTelemetry SDK"
@@ -24,7 +24,7 @@ dependencies {
2424
implementation("io.opentelemetry:opentelemetry-sdk-extension-autoconfigure")
2525
implementation("io.opentelemetry:opentelemetry-exporter-otlp")
2626
implementation("io.opentelemetry.semconv:opentelemetry-semconv")
27-
testImplementation("io.opentelemetry.semconv:opentelemetry-semconv-incubating")
27+
implementation("io.opentelemetry.semconv:opentelemetry-semconv-incubating")
2828

2929
annotationProcessor("com.google.auto.value:auto-value")
3030
compileOnly("com.google.auto.value:auto-value-annotations")
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
/*
2+
* Copyright The OpenTelemetry Authors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package io.opentelemetry.maven;
7+
8+
import java.util.Arrays;
9+
import java.util.List;
10+
import java.util.stream.Collectors;
11+
import org.eclipse.aether.transfer.TransferCancelledException;
12+
import org.eclipse.aether.transfer.TransferEvent;
13+
import org.eclipse.aether.transfer.TransferListener;
14+
15+
/**
16+
* Util class to chain multiple {@link TransferListener} as Maven APIs don't offer this capability.
17+
*/
18+
final class ChainedTransferListener implements TransferListener {
19+
20+
private final List<TransferListener> listeners;
21+
22+
/**
23+
* @param listeners {@code null} values are filtered
24+
*/
25+
ChainedTransferListener(TransferListener... listeners) {
26+
this.listeners = Arrays.stream(listeners).filter(e -> e != null).collect(Collectors.toList());
27+
}
28+
29+
@Override
30+
public void transferInitiated(TransferEvent event) throws TransferCancelledException {
31+
for (TransferListener listener : this.listeners) {
32+
listener.transferInitiated(event);
33+
}
34+
}
35+
36+
@Override
37+
public void transferStarted(TransferEvent event) throws TransferCancelledException {
38+
for (TransferListener listener : this.listeners) {
39+
listener.transferStarted(event);
40+
}
41+
}
42+
43+
@Override
44+
public void transferProgressed(TransferEvent event) throws TransferCancelledException {
45+
for (TransferListener listener : this.listeners) {
46+
listener.transferProgressed(event);
47+
}
48+
}
49+
50+
@Override
51+
public void transferCorrupted(TransferEvent event) throws TransferCancelledException {
52+
for (TransferListener listener : this.listeners) {
53+
listener.transferCorrupted(event);
54+
}
55+
}
56+
57+
@Override
58+
public void transferSucceeded(TransferEvent event) {
59+
for (TransferListener listener : this.listeners) {
60+
listener.transferSucceeded(event);
61+
}
62+
}
63+
64+
@Override
65+
public void transferFailed(TransferEvent event) {
66+
for (TransferListener listener : this.listeners) {
67+
listener.transferFailed(event);
68+
}
69+
}
70+
}

maven-extension/src/main/java/io/opentelemetry/maven/OpenTelemetrySdkService.java

+9-1
Original file line numberDiff line numberDiff line change
@@ -49,10 +49,12 @@ public final class OpenTelemetrySdkService implements Closeable {
4949

5050
private final boolean mojosInstrumentationEnabled;
5151

52+
private final boolean transferInstrumentationEnabled;
53+
5254
private boolean disposed;
5355

5456
public OpenTelemetrySdkService() {
55-
logger.debug(
57+
logger.info(
5658
"OpenTelemetry: Initialize OpenTelemetrySdkService v{}...",
5759
MavenOtelSemanticAttributes.TELEMETRY_DISTRO_VERSION_VALUE);
5860

@@ -76,6 +78,8 @@ public OpenTelemetrySdkService() {
7678

7779
this.mojosInstrumentationEnabled =
7880
configProperties.getBoolean("otel.instrumentation.maven.mojo.enabled", true);
81+
this.transferInstrumentationEnabled =
82+
configProperties.getBoolean("otel.instrumentation.maven.transfer.enabled", false);
7983

8084
this.tracer = openTelemetrySdk.getTracer("io.opentelemetry.contrib.maven", VERSION);
8185
}
@@ -154,4 +158,8 @@ public ContextPropagators getPropagators() {
154158
public boolean isMojosInstrumentationEnabled() {
155159
return mojosInstrumentationEnabled;
156160
}
161+
162+
public boolean isTransferInstrumentationEnabled() {
163+
return transferInstrumentationEnabled;
164+
}
157165
}

maven-extension/src/main/java/io/opentelemetry/maven/OtelExecutionListener.java

-18
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,9 @@
1717
import io.opentelemetry.maven.handler.MojoGoalExecutionHandler;
1818
import io.opentelemetry.maven.handler.MojoGoalExecutionHandlerConfiguration;
1919
import io.opentelemetry.maven.semconv.MavenOtelSemanticAttributes;
20-
import java.util.Locale;
2120
import java.util.Map;
2221
import java.util.Optional;
2322
import java.util.stream.Collectors;
24-
import javax.annotation.Nonnull;
25-
import javax.annotation.Nullable;
2623
import org.apache.maven.execution.AbstractExecutionListener;
2724
import org.apache.maven.execution.ExecutionEvent;
2825
import org.apache.maven.execution.ExecutionListener;
@@ -338,19 +335,4 @@ public void sessionEnded(ExecutionEvent event) {
338335
logger.debug("OpenTelemetry: Maven session ended, end root span");
339336
spanRegistry.removeRootSpan().end();
340337
}
341-
342-
private static class ToUpperCaseTextMapGetter implements TextMapGetter<Map<String, String>> {
343-
@Override
344-
public Iterable<String> keys(Map<String, String> environmentVariables) {
345-
return environmentVariables.keySet();
346-
}
347-
348-
@Override
349-
@Nullable
350-
public String get(@Nullable Map<String, String> environmentVariables, @Nonnull String key) {
351-
return environmentVariables == null
352-
? null
353-
: environmentVariables.get(key.toUpperCase(Locale.ROOT));
354-
}
355-
}
356338
}

maven-extension/src/main/java/io/opentelemetry/maven/OtelLifecycleParticipant.java

+51
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@
1111
import org.apache.maven.AbstractMavenLifecycleParticipant;
1212
import org.apache.maven.execution.ExecutionListener;
1313
import org.apache.maven.execution.MavenSession;
14+
import org.eclipse.aether.DefaultRepositorySystemSession;
15+
import org.eclipse.aether.RepositorySystemSession;
16+
import org.eclipse.aether.transfer.TransferListener;
1417
import org.slf4j.Logger;
1518
import org.slf4j.LoggerFactory;
1619

@@ -25,6 +28,8 @@ public final class OtelLifecycleParticipant extends AbstractMavenLifecyclePartic
2528

2629
private final OtelExecutionListener otelExecutionListener;
2730

31+
private final OtelTransferListener otelTransferListener;
32+
2833
/**
2934
* Manually instantiate {@link OtelExecutionListener} and hook it in the Maven build lifecycle
3035
* because Maven Sisu doesn't load it when Maven Plexus did.
@@ -34,6 +39,14 @@ public final class OtelLifecycleParticipant extends AbstractMavenLifecyclePartic
3439
OpenTelemetrySdkService openTelemetrySdkService, SpanRegistry spanRegistry) {
3540
this.openTelemetrySdkService = openTelemetrySdkService;
3641
this.otelExecutionListener = new OtelExecutionListener(spanRegistry, openTelemetrySdkService);
42+
this.otelTransferListener = new OtelTransferListener(spanRegistry, openTelemetrySdkService);
43+
}
44+
45+
@Override
46+
public void afterSessionStart(MavenSession session) {
47+
if (openTelemetrySdkService.isTransferInstrumentationEnabled()) {
48+
registerTransferListener(session);
49+
}
3750
}
3851

3952
/**
@@ -43,6 +56,10 @@ public final class OtelLifecycleParticipant extends AbstractMavenLifecyclePartic
4356
*/
4457
@Override
4558
public void afterProjectsRead(MavenSession session) {
59+
registerExecutionListener(session);
60+
}
61+
62+
void registerExecutionListener(MavenSession session) {
4663
ExecutionListener initialExecutionListener = session.getRequest().getExecutionListener();
4764
if (initialExecutionListener instanceof ChainedExecutionListener
4865
|| initialExecutionListener instanceof OtelExecutionListener) {
@@ -64,6 +81,40 @@ public void afterProjectsRead(MavenSession session) {
6481
}
6582
}
6683

84+
void registerTransferListener(MavenSession session) {
85+
RepositorySystemSession repositorySession = session.getRepositorySession();
86+
TransferListener initialTransferListener = repositorySession.getTransferListener();
87+
if (initialTransferListener instanceof ChainedTransferListener
88+
|| initialTransferListener instanceof OtelTransferListener) {
89+
// already initialized
90+
logger.debug(
91+
"OpenTelemetry: OpenTelemetry extension already registered as transfer listener, skip.");
92+
} else if (initialTransferListener == null) {
93+
setTransferListener(this.otelTransferListener, repositorySession, session);
94+
logger.debug(
95+
"OpenTelemetry: OpenTelemetry extension registered as transfer listener. No transfer listener initially defined");
96+
} else {
97+
setTransferListener(
98+
new ChainedTransferListener(this.otelTransferListener, initialTransferListener),
99+
repositorySession,
100+
session);
101+
logger.debug(
102+
"OpenTelemetry: OpenTelemetry extension registered as transfer listener. InitialTransferListener: {}",
103+
initialTransferListener);
104+
}
105+
}
106+
107+
void setTransferListener(
108+
TransferListener transferListener,
109+
RepositorySystemSession repositorySession,
110+
MavenSession session) {
111+
if (repositorySession instanceof DefaultRepositorySystemSession) {
112+
((DefaultRepositorySystemSession) repositorySession).setTransferListener(transferListener);
113+
} else {
114+
logger.warn("OpenTelemetry: Cannot set transfer listener");
115+
}
116+
}
117+
67118
@Override
68119
public void afterSessionEnd(MavenSession session) {
69120
// Workaround https://issues.apache.org/jira/browse/MNG-8217

0 commit comments

Comments
 (0)