add option to record transferred artifacts (#1875)
Co-authored-by: Cyrille Le Clerc <cyrille.leclerc@grafana.com>
This commit is contained in:
parent
b897a0ec76
commit
34937d2e24
|
@ -61,14 +61,15 @@ Without this setting, the traces won't be exported and the OpenTelemetry Maven E
|
|||
|
||||
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).
|
||||
|
||||
| System property <br /> Environment variable | Default value | Description |
|
||||
|--------------------------------------------------------------------------------------------|-------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| `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 |
|
||||
| `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. |
|
||||
| `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. |
|
||||
| `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. |
|
||||
| `otel.resource.attributes` <br /> `OTEL_RESOURCE_ATTRIBUTES` | | Specify resource attributes in the following format: key1=val1,key2=val2,key3=val3 |
|
||||
| `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. |
|
||||
| System property <br /> Environment variable | Default value | Description |
|
||||
|----------------------------------------------------------------------------------------------------|-------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| `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 |
|
||||
| `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. |
|
||||
| `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. |
|
||||
| `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. |
|
||||
| `otel.resource.attributes` <br /> `OTEL_RESOURCE_ATTRIBUTES` | | Specify resource attributes in the following format: key1=val1,key2=val2,key3=val3 |
|
||||
| `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. |
|
||||
| `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. |
|
||||
|
||||
ℹ️ The `service.name` is set to `maven` and the `service.version` to the version of the Maven runtime in use.
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ plugins {
|
|||
}
|
||||
|
||||
// NOTE
|
||||
// `META-INF/sis/javax.inject.Named` is manually handled under src/main/resources because there is
|
||||
// `META-INF/sisu/javax.inject.Named` is manually handled under src/main/resources because there is
|
||||
// no Gradle equivalent to the Maven plugin `org.eclipse.sisu:sisu-maven-plugin`
|
||||
|
||||
description = "Maven extension to observe Maven builds with distributed traces using OpenTelemetry SDK"
|
||||
|
@ -24,7 +24,7 @@ dependencies {
|
|||
implementation("io.opentelemetry:opentelemetry-sdk-extension-autoconfigure")
|
||||
implementation("io.opentelemetry:opentelemetry-exporter-otlp")
|
||||
implementation("io.opentelemetry.semconv:opentelemetry-semconv")
|
||||
testImplementation("io.opentelemetry.semconv:opentelemetry-semconv-incubating")
|
||||
implementation("io.opentelemetry.semconv:opentelemetry-semconv-incubating")
|
||||
|
||||
annotationProcessor("com.google.auto.value:auto-value")
|
||||
compileOnly("com.google.auto.value:auto-value-annotations")
|
||||
|
|
|
@ -0,0 +1,70 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.maven;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import org.eclipse.aether.transfer.TransferCancelledException;
|
||||
import org.eclipse.aether.transfer.TransferEvent;
|
||||
import org.eclipse.aether.transfer.TransferListener;
|
||||
|
||||
/**
|
||||
* Util class to chain multiple {@link TransferListener} as Maven APIs don't offer this capability.
|
||||
*/
|
||||
final class ChainedTransferListener implements TransferListener {
|
||||
|
||||
private final List<TransferListener> listeners;
|
||||
|
||||
/**
|
||||
* @param listeners {@code null} values are filtered
|
||||
*/
|
||||
ChainedTransferListener(TransferListener... listeners) {
|
||||
this.listeners = Arrays.stream(listeners).filter(e -> e != null).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void transferInitiated(TransferEvent event) throws TransferCancelledException {
|
||||
for (TransferListener listener : this.listeners) {
|
||||
listener.transferInitiated(event);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void transferStarted(TransferEvent event) throws TransferCancelledException {
|
||||
for (TransferListener listener : this.listeners) {
|
||||
listener.transferStarted(event);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void transferProgressed(TransferEvent event) throws TransferCancelledException {
|
||||
for (TransferListener listener : this.listeners) {
|
||||
listener.transferProgressed(event);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void transferCorrupted(TransferEvent event) throws TransferCancelledException {
|
||||
for (TransferListener listener : this.listeners) {
|
||||
listener.transferCorrupted(event);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void transferSucceeded(TransferEvent event) {
|
||||
for (TransferListener listener : this.listeners) {
|
||||
listener.transferSucceeded(event);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void transferFailed(TransferEvent event) {
|
||||
for (TransferListener listener : this.listeners) {
|
||||
listener.transferFailed(event);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -49,10 +49,12 @@ public final class OpenTelemetrySdkService implements Closeable {
|
|||
|
||||
private final boolean mojosInstrumentationEnabled;
|
||||
|
||||
private final boolean transferInstrumentationEnabled;
|
||||
|
||||
private boolean disposed;
|
||||
|
||||
public OpenTelemetrySdkService() {
|
||||
logger.debug(
|
||||
logger.info(
|
||||
"OpenTelemetry: Initialize OpenTelemetrySdkService v{}...",
|
||||
MavenOtelSemanticAttributes.TELEMETRY_DISTRO_VERSION_VALUE);
|
||||
|
||||
|
@ -76,6 +78,8 @@ public final class OpenTelemetrySdkService implements Closeable {
|
|||
|
||||
this.mojosInstrumentationEnabled =
|
||||
configProperties.getBoolean("otel.instrumentation.maven.mojo.enabled", true);
|
||||
this.transferInstrumentationEnabled =
|
||||
configProperties.getBoolean("otel.instrumentation.maven.transfer.enabled", false);
|
||||
|
||||
this.tracer = openTelemetrySdk.getTracer("io.opentelemetry.contrib.maven", VERSION);
|
||||
}
|
||||
|
@ -154,4 +158,8 @@ public final class OpenTelemetrySdkService implements Closeable {
|
|||
public boolean isMojosInstrumentationEnabled() {
|
||||
return mojosInstrumentationEnabled;
|
||||
}
|
||||
|
||||
public boolean isTransferInstrumentationEnabled() {
|
||||
return transferInstrumentationEnabled;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,12 +17,9 @@ import io.opentelemetry.context.propagation.TextMapGetter;
|
|||
import io.opentelemetry.maven.handler.MojoGoalExecutionHandler;
|
||||
import io.opentelemetry.maven.handler.MojoGoalExecutionHandlerConfiguration;
|
||||
import io.opentelemetry.maven.semconv.MavenOtelSemanticAttributes;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
import org.apache.maven.execution.AbstractExecutionListener;
|
||||
import org.apache.maven.execution.ExecutionEvent;
|
||||
import org.apache.maven.execution.ExecutionListener;
|
||||
|
@ -338,19 +335,4 @@ public final class OtelExecutionListener extends AbstractExecutionListener {
|
|||
logger.debug("OpenTelemetry: Maven session ended, end root span");
|
||||
spanRegistry.removeRootSpan().end();
|
||||
}
|
||||
|
||||
private static class ToUpperCaseTextMapGetter implements TextMapGetter<Map<String, String>> {
|
||||
@Override
|
||||
public Iterable<String> keys(Map<String, String> environmentVariables) {
|
||||
return environmentVariables.keySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public String get(@Nullable Map<String, String> environmentVariables, @Nonnull String key) {
|
||||
return environmentVariables == null
|
||||
? null
|
||||
: environmentVariables.get(key.toUpperCase(Locale.ROOT));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,6 +11,9 @@ import javax.inject.Singleton;
|
|||
import org.apache.maven.AbstractMavenLifecycleParticipant;
|
||||
import org.apache.maven.execution.ExecutionListener;
|
||||
import org.apache.maven.execution.MavenSession;
|
||||
import org.eclipse.aether.DefaultRepositorySystemSession;
|
||||
import org.eclipse.aether.RepositorySystemSession;
|
||||
import org.eclipse.aether.transfer.TransferListener;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
|
@ -25,6 +28,8 @@ public final class OtelLifecycleParticipant extends AbstractMavenLifecyclePartic
|
|||
|
||||
private final OtelExecutionListener otelExecutionListener;
|
||||
|
||||
private final OtelTransferListener otelTransferListener;
|
||||
|
||||
/**
|
||||
* Manually instantiate {@link OtelExecutionListener} and hook it in the Maven build lifecycle
|
||||
* because Maven Sisu doesn't load it when Maven Plexus did.
|
||||
|
@ -34,6 +39,14 @@ public final class OtelLifecycleParticipant extends AbstractMavenLifecyclePartic
|
|||
OpenTelemetrySdkService openTelemetrySdkService, SpanRegistry spanRegistry) {
|
||||
this.openTelemetrySdkService = openTelemetrySdkService;
|
||||
this.otelExecutionListener = new OtelExecutionListener(spanRegistry, openTelemetrySdkService);
|
||||
this.otelTransferListener = new OtelTransferListener(spanRegistry, openTelemetrySdkService);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterSessionStart(MavenSession session) {
|
||||
if (openTelemetrySdkService.isTransferInstrumentationEnabled()) {
|
||||
registerTransferListener(session);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -43,6 +56,10 @@ public final class OtelLifecycleParticipant extends AbstractMavenLifecyclePartic
|
|||
*/
|
||||
@Override
|
||||
public void afterProjectsRead(MavenSession session) {
|
||||
registerExecutionListener(session);
|
||||
}
|
||||
|
||||
void registerExecutionListener(MavenSession session) {
|
||||
ExecutionListener initialExecutionListener = session.getRequest().getExecutionListener();
|
||||
if (initialExecutionListener instanceof ChainedExecutionListener
|
||||
|| initialExecutionListener instanceof OtelExecutionListener) {
|
||||
|
@ -64,6 +81,40 @@ public final class OtelLifecycleParticipant extends AbstractMavenLifecyclePartic
|
|||
}
|
||||
}
|
||||
|
||||
void registerTransferListener(MavenSession session) {
|
||||
RepositorySystemSession repositorySession = session.getRepositorySession();
|
||||
TransferListener initialTransferListener = repositorySession.getTransferListener();
|
||||
if (initialTransferListener instanceof ChainedTransferListener
|
||||
|| initialTransferListener instanceof OtelTransferListener) {
|
||||
// already initialized
|
||||
logger.debug(
|
||||
"OpenTelemetry: OpenTelemetry extension already registered as transfer listener, skip.");
|
||||
} else if (initialTransferListener == null) {
|
||||
setTransferListener(this.otelTransferListener, repositorySession, session);
|
||||
logger.debug(
|
||||
"OpenTelemetry: OpenTelemetry extension registered as transfer listener. No transfer listener initially defined");
|
||||
} else {
|
||||
setTransferListener(
|
||||
new ChainedTransferListener(this.otelTransferListener, initialTransferListener),
|
||||
repositorySession,
|
||||
session);
|
||||
logger.debug(
|
||||
"OpenTelemetry: OpenTelemetry extension registered as transfer listener. InitialTransferListener: {}",
|
||||
initialTransferListener);
|
||||
}
|
||||
}
|
||||
|
||||
void setTransferListener(
|
||||
TransferListener transferListener,
|
||||
RepositorySystemSession repositorySession,
|
||||
MavenSession session) {
|
||||
if (repositorySession instanceof DefaultRepositorySystemSession) {
|
||||
((DefaultRepositorySystemSession) repositorySession).setTransferListener(transferListener);
|
||||
} else {
|
||||
logger.warn("OpenTelemetry: Cannot set transfer listener");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterSessionEnd(MavenSession session) {
|
||||
// Workaround https://issues.apache.org/jira/browse/MNG-8217
|
||||
|
|
|
@ -0,0 +1,166 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.maven;
|
||||
|
||||
import io.opentelemetry.api.trace.Span;
|
||||
import io.opentelemetry.api.trace.SpanBuilder;
|
||||
import io.opentelemetry.api.trace.SpanKind;
|
||||
import io.opentelemetry.api.trace.StatusCode;
|
||||
import io.opentelemetry.maven.semconv.MavenOtelSemanticAttributes;
|
||||
import io.opentelemetry.semconv.HttpAttributes;
|
||||
import io.opentelemetry.semconv.ServerAttributes;
|
||||
import io.opentelemetry.semconv.UrlAttributes;
|
||||
import io.opentelemetry.semconv.incubating.HttpIncubatingAttributes;
|
||||
import io.opentelemetry.semconv.incubating.UrlIncubatingAttributes;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import org.apache.maven.execution.ExecutionListener;
|
||||
import org.apache.maven.execution.MavenSession;
|
||||
import org.eclipse.aether.transfer.AbstractTransferListener;
|
||||
import org.eclipse.aether.transfer.TransferEvent;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Don't mark this class as {@link javax.inject.Named} and {@link javax.inject.Singleton} because
|
||||
* Maven Sisu doesn't automatically load instance of {@link ExecutionListener} as Maven Extension
|
||||
* hooks the same way Maven Plexus did so we manually hook this instance of {@link
|
||||
* ExecutionListener} through the {@link OtelLifecycleParticipant#afterProjectsRead(MavenSession)}.
|
||||
*/
|
||||
public final class OtelTransferListener extends AbstractTransferListener {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(OtelTransferListener.class);
|
||||
|
||||
private final SpanRegistry spanRegistry;
|
||||
|
||||
private final OpenTelemetrySdkService openTelemetrySdkService;
|
||||
|
||||
private final Map<String, Optional<URI>> repositoryUriMapping = new ConcurrentHashMap<>();
|
||||
|
||||
OtelTransferListener(SpanRegistry spanRegistry, OpenTelemetrySdkService openTelemetrySdkService) {
|
||||
this.spanRegistry = spanRegistry;
|
||||
this.openTelemetrySdkService = openTelemetrySdkService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void transferInitiated(TransferEvent event) {
|
||||
logger.debug("OpenTelemetry: OtelTransferListener#transferInitiated({})", event);
|
||||
|
||||
String httpRequestMethod;
|
||||
switch (event.getRequestType()) {
|
||||
case PUT:
|
||||
httpRequestMethod = "PUT";
|
||||
break;
|
||||
case GET:
|
||||
httpRequestMethod = "GET";
|
||||
break;
|
||||
case GET_EXISTENCE:
|
||||
httpRequestMethod = "HEAD";
|
||||
break;
|
||||
default:
|
||||
logger.warn(
|
||||
"OpenTelemetry: Unknown request type {} for event {}", event.getRequestType(), event);
|
||||
httpRequestMethod = event.getRequestType().name();
|
||||
}
|
||||
|
||||
String urlTemplate =
|
||||
event.getResource().getRepositoryUrl()
|
||||
+ "$groupId/$artifactId/$version/$artifactId-$version.$classifier";
|
||||
|
||||
String spanName = httpRequestMethod + " " + urlTemplate;
|
||||
|
||||
// Build an HTTP client span as the http call itself is not instrumented.
|
||||
SpanBuilder spanBuilder =
|
||||
this.openTelemetrySdkService
|
||||
.getTracer()
|
||||
.spanBuilder(spanName)
|
||||
.setSpanKind(SpanKind.CLIENT)
|
||||
.setAttribute(HttpAttributes.HTTP_REQUEST_METHOD, httpRequestMethod)
|
||||
.setAttribute(
|
||||
UrlAttributes.URL_PATH,
|
||||
event.getResource().getRepositoryUrl() + event.getResource().getResourceName())
|
||||
.setAttribute(UrlIncubatingAttributes.URL_TEMPLATE, urlTemplate)
|
||||
.setAttribute(
|
||||
MavenOtelSemanticAttributes.MAVEN_TRANSFER_TYPE, event.getRequestType().name())
|
||||
.setAttribute(
|
||||
MavenOtelSemanticAttributes.MAVEN_RESOURCE_NAME,
|
||||
event.getResource().getResourceName());
|
||||
|
||||
repositoryUriMapping
|
||||
.computeIfAbsent(
|
||||
event.getResource().getRepositoryUrl(),
|
||||
str -> {
|
||||
try {
|
||||
return str.isEmpty() ? Optional.empty() : Optional.of(new URI(str));
|
||||
} catch (URISyntaxException e) {
|
||||
return Optional.empty();
|
||||
}
|
||||
})
|
||||
.ifPresent(
|
||||
uri -> {
|
||||
spanBuilder.setAttribute(ServerAttributes.SERVER_ADDRESS, uri.getHost());
|
||||
if (uri.getPort() != -1) {
|
||||
spanBuilder.setAttribute(ServerAttributes.SERVER_PORT, uri.getPort());
|
||||
}
|
||||
// prevent ever increasing size
|
||||
if (repositoryUriMapping.size() > 128) {
|
||||
repositoryUriMapping.clear();
|
||||
}
|
||||
});
|
||||
spanRegistry.putSpan(spanBuilder.startSpan(), event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void transferSucceeded(TransferEvent event) {
|
||||
logger.debug("OpenTelemetry: OtelTransferListener#transferSucceeded({})", event);
|
||||
|
||||
Optional.ofNullable(spanRegistry.removeSpan(event))
|
||||
.ifPresent(
|
||||
span -> {
|
||||
span.setStatus(StatusCode.OK);
|
||||
finish(span, event);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void transferFailed(TransferEvent event) {
|
||||
logger.debug("OpenTelemetry: OtelTransferListener#transferFailed({})", event);
|
||||
|
||||
Optional.ofNullable(spanRegistry.removeSpan(event)).ifPresent(span -> fail(span, event));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void transferCorrupted(TransferEvent event) {
|
||||
logger.debug("OpenTelemetry: OtelTransferListener#transferCorrupted({})", event);
|
||||
|
||||
Optional.ofNullable(spanRegistry.removeSpan(event)).ifPresent(span -> fail(span, event));
|
||||
}
|
||||
|
||||
void finish(Span span, TransferEvent event) {
|
||||
switch (event.getRequestType()) {
|
||||
case PUT:
|
||||
span.setAttribute(
|
||||
HttpIncubatingAttributes.HTTP_REQUEST_BODY_SIZE, event.getTransferredBytes());
|
||||
break;
|
||||
case GET:
|
||||
case GET_EXISTENCE:
|
||||
span.setAttribute(
|
||||
HttpIncubatingAttributes.HTTP_RESPONSE_BODY_SIZE, event.getTransferredBytes());
|
||||
break;
|
||||
}
|
||||
span.end();
|
||||
}
|
||||
|
||||
void fail(Span span, TransferEvent event) {
|
||||
span.setStatus(
|
||||
StatusCode.ERROR,
|
||||
Optional.ofNullable(event.getException()).map(Exception::getMessage).orElse("n/a"));
|
||||
finish(span, event);
|
||||
}
|
||||
}
|
|
@ -17,6 +17,9 @@ import javax.inject.Singleton;
|
|||
import org.apache.maven.model.Plugin;
|
||||
import org.apache.maven.plugin.MojoExecution;
|
||||
import org.apache.maven.project.MavenProject;
|
||||
import org.eclipse.aether.RepositorySystemSession;
|
||||
import org.eclipse.aether.transfer.TransferEvent;
|
||||
import org.eclipse.aether.transfer.TransferResource;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
|
@ -35,6 +38,7 @@ public final class SpanRegistry {
|
|||
|
||||
private final Map<MojoExecutionKey, Span> mojoExecutionKeySpanMap = new ConcurrentHashMap<>();
|
||||
private final Map<MavenProjectKey, Span> mavenProjectKeySpanMap = new ConcurrentHashMap<>();
|
||||
private final Map<TransferKey, Span> transferKeySpanMap = new ConcurrentHashMap<>();
|
||||
@Nullable private Span rootSpan;
|
||||
|
||||
/**
|
||||
|
@ -113,6 +117,15 @@ public final class SpanRegistry {
|
|||
}
|
||||
}
|
||||
|
||||
public void putSpan(Span span, TransferEvent event) {
|
||||
TransferKey key = TransferKey.fromTransferEvent(event);
|
||||
logger.debug("OpenTelemetry: putSpan({})", key);
|
||||
Span previousSpanForKey = transferKeySpanMap.put(key, span);
|
||||
if (previousSpanForKey != null) {
|
||||
logger.warn("A span has already been started for " + key);
|
||||
}
|
||||
}
|
||||
|
||||
public Span removeSpan(MavenProject mavenProject) {
|
||||
logger.debug("OpenTelemetry: removeSpan({})", mavenProject);
|
||||
MavenProjectKey key = MavenProjectKey.fromMavenProject(mavenProject);
|
||||
|
@ -136,6 +149,17 @@ public final class SpanRegistry {
|
|||
return span;
|
||||
}
|
||||
|
||||
public Span removeSpan(TransferEvent event) {
|
||||
TransferKey key = TransferKey.fromTransferEvent(event);
|
||||
logger.debug("OpenTelemetry: removeSpan({})", key);
|
||||
Span span = transferKeySpanMap.remove(key);
|
||||
if (span == null) {
|
||||
logger.warn("No span found for " + key);
|
||||
return Span.getInvalid();
|
||||
}
|
||||
return span;
|
||||
}
|
||||
|
||||
@AutoValue
|
||||
abstract static class MavenProjectKey {
|
||||
abstract String groupId();
|
||||
|
@ -185,4 +209,18 @@ public final class SpanRegistry {
|
|||
MavenProjectKey.fromMavenProject(project));
|
||||
}
|
||||
}
|
||||
|
||||
@AutoValue
|
||||
abstract static class TransferKey {
|
||||
abstract String resourceName();
|
||||
|
||||
abstract String sessionId();
|
||||
|
||||
public static TransferKey fromTransferEvent(@Nonnull TransferEvent event) {
|
||||
TransferResource resource = event.getResource();
|
||||
RepositorySystemSession session = event.getSession();
|
||||
return new AutoValue_SpanRegistry_TransferKey(
|
||||
resource.getResourceName(), "session-" + System.identityHashCode(session));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.maven;
|
||||
|
||||
import io.opentelemetry.context.propagation.TextMapGetter;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
final class ToUpperCaseTextMapGetter implements TextMapGetter<Map<String, String>> {
|
||||
@Override
|
||||
public Set<String> keys(Map<String, String> environmentVariables) {
|
||||
return environmentVariables.keySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public String get(@Nullable Map<String, String> environmentVariables, @Nonnull String key) {
|
||||
return environmentVariables == null
|
||||
? null
|
||||
: environmentVariables.get(key.toUpperCase(Locale.ROOT));
|
||||
}
|
||||
}
|
|
@ -11,6 +11,7 @@ import static io.opentelemetry.api.common.AttributeKey.stringKey;
|
|||
import io.opentelemetry.api.common.AttributeKey;
|
||||
import io.opentelemetry.maven.OpenTelemetrySdkService;
|
||||
import java.util.List;
|
||||
import org.eclipse.aether.transfer.TransferEvent;
|
||||
|
||||
/**
|
||||
* Semantic attributes for Maven executions.
|
||||
|
@ -36,6 +37,7 @@ public class MavenOtelSemanticAttributes {
|
|||
stringKey("maven.build.repository.id");
|
||||
public static final AttributeKey<String> MAVEN_BUILD_REPOSITORY_URL =
|
||||
stringKey("maven.build.repository.url");
|
||||
|
||||
public static final AttributeKey<String> MAVEN_EXECUTION_GOAL = stringKey("maven.execution.goal");
|
||||
|
||||
public static final AttributeKey<String> MAVEN_EXECUTION_ID = stringKey("maven.execution.id");
|
||||
|
@ -53,6 +55,14 @@ public class MavenOtelSemanticAttributes {
|
|||
public static final AttributeKey<String> MAVEN_PROJECT_VERSION =
|
||||
stringKey("maven.project.version");
|
||||
|
||||
/** See {@link TransferEvent.RequestType}. */
|
||||
public static final AttributeKey<String> MAVEN_TRANSFER_TYPE =
|
||||
AttributeKey.stringKey("maven.transfer.type");
|
||||
|
||||
/** See {@link org.eclipse.aether.transfer.TransferResource}. */
|
||||
public static final AttributeKey<String> MAVEN_RESOURCE_NAME =
|
||||
AttributeKey.stringKey("maven.resource.name");
|
||||
|
||||
public static final String SERVICE_NAME_VALUE = "maven";
|
||||
|
||||
// inlined incubating attribute to prevent direct dependency on incubating semconv
|
||||
|
|
Loading…
Reference in New Issue