Skip to content
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

Move ReconfigurableOpenTelemetry to the Jenkins Otel API Plugin #887

Merged
merged 5 commits into from
Jul 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 28 additions & 41 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -101,56 +101,75 @@
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>io.jenkins.plugins</groupId>
<artifactId>opentelemetry-api</artifactId>
<version>1.39.0-11.vd6b_87589988f</version>
</dependency>
<dependency>
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-api</artifactId>
<!-- provided by io.jenkins.plugins:opentelemetry-api -->
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-api-incubator</artifactId>
<!-- provided by io.jenkins.plugins:opentelemetry-api -->
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-context</artifactId>
<!-- provided by io.jenkins.plugins:opentelemetry-api -->
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.opentelemetry.semconv</groupId>
<artifactId>opentelemetry-semconv</artifactId>
<version>${opentelemetry-semconv.version}</version>
<!-- provided by io.jenkins.plugins:opentelemetry-api -->
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.opentelemetry.semconv</groupId>
<artifactId>opentelemetry-semconv-incubating</artifactId>
<version>${opentelemetry-semconv.version}</version>
<!-- provided by io.jenkins.plugins:opentelemetry-api -->
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.opentelemetry.instrumentation</groupId>
<artifactId>opentelemetry-instrumentation-api</artifactId>
<!-- provided by io.jenkins.plugins:opentelemetry-api -->
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-sdk</artifactId>
</dependency>
<dependency>
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-sdk-trace</artifactId>
</dependency>
<dependency>
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-sdk-metrics</artifactId>
<!-- provided by io.jenkins.plugins:opentelemetry-api -->
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-sdk-extension-autoconfigure-spi</artifactId>
<!-- provided by io.jenkins.plugins:opentelemetry-api -->
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-sdk-extension-autoconfigure</artifactId>
<!-- provided by io.jenkins.plugins:opentelemetry-api -->
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-extension-trace-propagators</artifactId>
</dependency>
<dependency>
<groupId>io.opentelemetry.instrumentation</groupId>
<artifactId>opentelemetry-apache-httpclient-4.3</artifactId>
</dependency>
<dependency>
<groupId>io.opentelemetry.instrumentation</groupId>
<artifactId>opentelemetry-resources</artifactId>
Expand Down Expand Up @@ -195,30 +214,6 @@
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-exporter-otlp</artifactId>
<exclusions>
<exclusion>
<!-- we get okhttp from io.jenkins.plugins:okhttp-api -->
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
</exclusion>
<exclusion>
<!-- we get okhttp from io.jenkins.plugins:okhttp-api -->
<groupId>com.squareup.okio</groupId>
<artifactId>okio</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-exporter-prometheus</artifactId>
</dependency>
<dependency>
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-exporter-logging</artifactId>
</dependency>

<dependency>
<groupId>jakarta.json</groupId>
Expand All @@ -229,10 +224,6 @@
<artifactId>parsson</artifactId>
</dependency>

<dependency>
<groupId>io.prometheus</groupId>
<artifactId>simpleclient_httpserver</artifactId>
</dependency>
<dependency>
<groupId>io.jenkins.plugins</groupId>
<artifactId>okhttp-api</artifactId>
Expand Down Expand Up @@ -274,10 +265,6 @@
<groupId>org.jenkins-ci.plugins</groupId>
<artifactId>apache-httpcomponents-client-4-api</artifactId>
</dependency>
<dependency>
<groupId>io.opentelemetry.instrumentation</groupId>
<artifactId>opentelemetry-apache-httpclient-4.3</artifactId>
</dependency>
<dependency>
<groupId>org.jenkins-ci.plugins</groupId>
<artifactId>cloudbees-disk-usage-simple</artifactId>
Expand Down Expand Up @@ -504,7 +491,7 @@
<io.jenkins.plugins.opentelemetry.job.MonitoringRunListener>INFO</io.jenkins.plugins.opentelemetry.job.MonitoringRunListener>
<io.jenkins.plugins.opentelemetry.init.JenkinsExecutorMonitoringInitializer>INFO</io.jenkins.plugins.opentelemetry.init.JenkinsExecutorMonitoringInitializer>
<io.jenkins.plugins.opentelemetry.job.MonitoringRunListener>INFO</io.jenkins.plugins.opentelemetry.job.MonitoringRunListener>
<io.jenkins.plugins.opentelemetry.opentelemetry.ReconfigurableMeterProvider>INFO</io.jenkins.plugins.opentelemetry.opentelemetry.ReconfigurableMeterProvider>
<io.jenkins.plugins.opentelemetry.opentelemetry.ReconfigurableMeterProvider>FINE</io.jenkins.plugins.opentelemetry.opentelemetry.ReconfigurableMeterProvider>
</loggers>
</configuration>
</plugin>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@
package io.jenkins.plugins.opentelemetry;

import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Preconditions;
import edu.umd.cs.findbugs.annotations.NonNull;
import hudson.Extension;
import hudson.ExtensionList;
import io.jenkins.plugins.opentelemetry.opentelemetry.ReconfigurableOpenTelemetry;
import hudson.ExtensionPoint;
import io.jenkins.plugins.opentelemetry.api.ReconfigurableOpenTelemetry;
import io.jenkins.plugins.opentelemetry.semconv.JenkinsOtelSemanticAttributes;
import io.opentelemetry.api.OpenTelemetry;
import io.opentelemetry.api.incubator.events.EventLogger;
Expand All @@ -19,15 +19,16 @@
import io.opentelemetry.instrumentation.resources.ProcessResourceProvider;
import io.opentelemetry.sdk.OpenTelemetrySdk;

import javax.annotation.PreDestroy;
import javax.annotation.PostConstruct;
import javax.inject.Inject;
import java.util.Optional;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Level;

/**
* {@link OpenTelemetry} instance intended to live on the Jenkins Controller.
*/
@Extension(ordinal = Integer.MAX_VALUE)
public class JenkinsControllerOpenTelemetry extends ReconfigurableOpenTelemetry implements OpenTelemetry {
public class JenkinsControllerOpenTelemetry implements ExtensionPoint {

/**
* See {@code OTEL_JAVA_DISABLED_RESOURCE_PROVIDERS}
Expand All @@ -36,33 +37,34 @@ public class JenkinsControllerOpenTelemetry extends ReconfigurableOpenTelemetry

public final static AtomicInteger INSTANCE_COUNTER = new AtomicInteger(0);

@NonNull
private final Tracer defaultTracer;
@NonNull
private final Meter defaultMeter;
@NonNull
private final EventLogger defaultEventLogger;
@VisibleForTesting
@Inject
protected ReconfigurableOpenTelemetry openTelemetry;

private Tracer defaultTracer;
private Meter defaultMeter;
private EventLogger defaultEventLogger;

public JenkinsControllerOpenTelemetry() {
super();
if (INSTANCE_COUNTER.get() > 0) {
logger.log(Level.WARNING, "More than one instance of JenkinsControllerOpenTelemetry created: " + INSTANCE_COUNTER.get());
}
}

@PostConstruct
public void postConstruct() {
String opentelemetryPluginVersion = OtelUtils.getOpentelemetryPluginVersion();

this.defaultTracer =
getTracerProvider()
this.openTelemetry
.tracerBuilder(JenkinsOtelSemanticAttributes.INSTRUMENTATION_NAME)
.setInstrumentationVersion(opentelemetryPluginVersion)
.build();

this.defaultEventLogger = getEventLoggerProvider()
this.defaultEventLogger = openTelemetry
.eventLoggerBuilder(JenkinsOtelSemanticAttributes.INSTRUMENTATION_NAME)
.setInstrumentationVersion(opentelemetryPluginVersion)
.build();

this.defaultMeter = getMeterProvider()
this.defaultMeter = openTelemetry
.meterBuilder(JenkinsOtelSemanticAttributes.INSTRUMENTATION_NAME)
.setInstrumentationVersion(opentelemetryPluginVersion)
.build();
Expand All @@ -84,42 +86,28 @@ public EventLogger getDefaultEventLogger() {
}

public boolean isLogsEnabled() {
String otelLogsExporter = getConfig().getString("otel.logs.exporter");
String otelLogsExporter = openTelemetry.getConfig().getString("otel.logs.exporter");
return otelLogsExporter != null && !otelLogsExporter.equals("none");
}

public boolean isOtelLogsMirrorToDisk() {
String otelLogsExporter = getConfig().getString("otel.logs.mirror_to_disk");
String otelLogsExporter = openTelemetry.getConfig().getString("otel.logs.mirror_to_disk");
return otelLogsExporter != null && otelLogsExporter.equals("true");
}

@VisibleForTesting
@NonNull
@Deprecated
protected OpenTelemetrySdk getOpenTelemetrySdk() {
Preconditions.checkNotNull(getOpenTelemetryDelegate());
if (getOpenTelemetryDelegate() instanceof OpenTelemetrySdk) {
return (OpenTelemetrySdk) getOpenTelemetryDelegate();
} else {
throw new IllegalStateException("OpenTelemetry initialized as NoOp");
}
}

@PreDestroy
public void shutdown() {
super.close();
return (OpenTelemetrySdk) Optional.ofNullable(openTelemetry).map(ReconfigurableOpenTelemetry::getImplementation).orElseThrow(() -> new IllegalStateException("OpenTelemetry not initialized"));
}

public void initialize(@NonNull OpenTelemetryConfiguration configuration) {
configure(
openTelemetry.configure(
configuration.toOpenTelemetryProperties(),
configuration.toOpenTelemetryResource());
}

@Override
protected void postOpenTelemetrySdkConfiguration() {
ExtensionList.lookup(OpenTelemetryLifecycleListener.class).forEach(l -> l.afterConfiguration(getConfig()));
}

static public JenkinsControllerOpenTelemetry get() {
return ExtensionList.lookupSingleton(JenkinsControllerOpenTelemetry.class);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import hudson.model.Descriptor;
import hudson.tasks.BuildStep;
import hudson.util.FormValidation;
import io.jenkins.plugins.opentelemetry.api.ReconfigurableOpenTelemetry;
import io.jenkins.plugins.opentelemetry.authentication.NoAuthentication;
import io.jenkins.plugins.opentelemetry.authentication.OtlpAuthentication;
import io.jenkins.plugins.opentelemetry.backend.ObservabilityBackend;
Expand Down Expand Up @@ -128,7 +129,8 @@

private String disabledResourceProviders = JenkinsControllerOpenTelemetry.DEFAULT_OTEL_JAVA_DISABLED_RESOURCE_PROVIDERS;

private transient JenkinsControllerOpenTelemetry jenkinsControllerOpenTelemetry;
@Inject
private transient ReconfigurableOpenTelemetry openTelemetry;

private transient LogStorageRetriever logStorageRetriever;

Expand Down Expand Up @@ -217,22 +219,6 @@
configurationProperties);
}

/**
* Register {@link io.jenkins.plugins.opentelemetry.opentelemetry.ReconfigurableOpenTelemetry}
* on {@link io.opentelemetry.api.GlobalOpenTelemetry}
* and {@link io.jenkins.plugins.opentelemetry.opentelemetry.ReconfigurableEventLoggerProvider}
* on {@link io.opentelemetry.api.incubator.events.GlobalEventLoggerProvider}
* as early as possible in Jenkins lifecycle so any plugin invoking those Global getters will have the
* reconfigurable instance .
*
* TODO can this be refactored into an annotation on the JenkinsControllerOpenTelemetry to force its early instantiation?
*/
@Initializer(after = InitMilestone.EXTENSIONS_AUGMENTED, before = InitMilestone.SYSTEM_CONFIG_LOADED)
public void initializeOpenTelemetryAfterExtensionsAugmented() {
LOGGER.log(Level.FINE, "Initialize Jenkins OpenTelemetry Plugin with a NoOp implementation...");
jenkinsControllerOpenTelemetry.configure(Collections.emptyMap(), Resource.empty());
}

/**
* Initialize the Otel SDK, must happen after the plugin has been configured by the standard config and by JCasC
* JCasC configuration happens during `SYSTEM_CONFIG_ADAPTED` (see `io.jenkins.plugins.casc.ConfigurationAsCode#init()`)
Expand All @@ -245,7 +231,7 @@
if (Objects.equals(this.currentOpenTelemetryConfiguration, newOpenTelemetryConfiguration)) {
LOGGER.log(Level.FINE, "Configuration didn't change, skip reconfiguration");
} else {
jenkinsControllerOpenTelemetry.initialize(newOpenTelemetryConfiguration);
openTelemetry.configure(newOpenTelemetryConfiguration.toOpenTelemetryProperties(), newOpenTelemetryConfiguration.toOpenTelemetryResource());
this.currentOpenTelemetryConfiguration = newOpenTelemetryConfiguration;
}

Expand Down Expand Up @@ -322,11 +308,6 @@
return observabilityBackends;
}

@Inject
public void setJenkinsControllerOpenTelemetry(JenkinsControllerOpenTelemetry jenkinsControllerOpenTelemetry) {
this.jenkinsControllerOpenTelemetry = jenkinsControllerOpenTelemetry;
}

public Integer getExporterTimeoutMillis() {
return exporterTimeoutMillis;
}
Expand Down Expand Up @@ -535,30 +516,30 @@

@NonNull
public Resource getResource() {
if (this.jenkinsControllerOpenTelemetry == null) {
if (this.openTelemetry == null) {
return Resource.empty();
} else {
return this.jenkinsControllerOpenTelemetry.getResource();
return this.openTelemetry.getResource();
}
}

/**
* Used in io/jenkins/plugins/opentelemetry/JenkinsOpenTelemetryPluginConfiguration/config.jelly because
* cyrille doesn't know how to format the content with linebreaks in a html teaxtarea
*/
@NonNull
public String getResourceAsText() {
return this.getResource().getAttributes().asMap().entrySet().stream().
map(e -> e.getKey() + "=" + e.getValue()).
collect(Collectors.joining("\r\n"));
}

@NonNull
public ConfigProperties getConfigProperties() {
if (this.jenkinsControllerOpenTelemetry == null) {
if (this.openTelemetry == null) {
return ConfigPropertiesUtils.emptyConfig();
} else {
return this.jenkinsControllerOpenTelemetry.getConfig();
return this.openTelemetry.getConfig();

Check warning on line 542 in src/main/java/io/jenkins/plugins/opentelemetry/JenkinsOpenTelemetryPluginConfiguration.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Not covered lines

Lines 519-542 are not covered by tests
}
}

Expand Down Expand Up @@ -588,7 +569,7 @@
private LogStorageRetriever resolveLogStorageRetriever() {
LogStorageRetriever logStorageRetriever = null;

Resource otelSdkResource = jenkinsControllerOpenTelemetry.getResource();
Resource otelSdkResource = openTelemetry.getResource();
String serviceName = Objects.requireNonNull(otelSdkResource.getAttribute(ServiceAttributes.SERVICE_NAME), "service.name can't be null");
String serviceNamespace = otelSdkResource.getAttribute(ServiceIncubatingAttributes.SERVICE_NAMESPACE);

Expand Down
Loading