
com.microsoft.azure.functions.opentelemetry.FunctionsOpenTelemetry Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of azure-functions-java-opentelemetry Show documentation
Show all versions of azure-functions-java-opentelemetry Show documentation
This package contains classes/interfaces for advanced SDK-based type bindings for Azure Functions Java Worker.
The newest version!
package com.microsoft.azure.functions.opentelemetry;
import com.microsoft.azure.functions.TraceContext;
import io.opentelemetry.api.GlobalOpenTelemetry;
import io.opentelemetry.api.trace.Span;
import io.opentelemetry.api.trace.SpanKind;
import io.opentelemetry.context.Context;
import io.opentelemetry.context.propagation.TextMapGetter;
import io.opentelemetry.sdk.OpenTelemetrySdk;
import io.opentelemetry.sdk.autoconfigure.AutoConfiguredOpenTelemetrySdk;
import io.opentelemetry.sdk.autoconfigure.AutoConfiguredOpenTelemetrySdkBuilder;
import java.lang.reflect.Method;
import java.util.logging.Level;
import java.util.logging.Logger;
public final class FunctionsOpenTelemetry {
private static Logger LOGGER = Logger.getLogger(FunctionsOpenTelemetry.class.getSimpleName());
private static volatile OpenTelemetrySdk sdk;
public static void setLogger(Logger logger) {
LOGGER = logger;
}
/**
* Ensures that the OpenTelemetry SDK is created.
*/
public static void initialize() {
if (sdk == null) {
synchronized (FunctionsOpenTelemetry.class) {
if (sdk == null) {
sdk = buildSdk();
}
}
}
}
public static OpenTelemetrySdk sdk() {
return sdk;
}
/**
* Creates an SDK, optionally enriching it with Azure Monitor if the
* environment variable
* {@code APPLICATIONINSIGHTS_CONNECTION_STRING}
* is present and not null.
*
* Reflection is used only for the optional
* {@code AzureMonitorAutoConfigure} class so that users are free to exclude
* it (or pull it in transitively) without breaking compilation.
*/
private static OpenTelemetrySdk buildSdk() {
LOGGER.info("Initializing OpenTelemetry SDK ...");
OpenTelemetrySdk sdk;
try {
final AutoConfiguredOpenTelemetrySdkBuilder builder =
AutoConfiguredOpenTelemetrySdk.builder();
builder.addResourceCustomizer(
(existing, unused) -> existing.merge(FunctionsResourceDetector.getResource()));
if (isAppInsightsEnabled()) {
final String connStr = System.getenv("APPLICATIONINSIGHTS_CONNECTION_STRING");
applyAzureMonitor(builder, connStr);
}
sdk = builder.build().getOpenTelemetrySdk();
GlobalOpenTelemetry.set(sdk);
LOGGER.info("OpenTelemetry SDK initialised successfully.");
} catch (Exception ex) {
LOGGER.log(Level.SEVERE,
"Failed to initialise OpenTelemetry SDK – falling back to no-op", ex);
sdk = OpenTelemetrySdk.builder().build();
GlobalOpenTelemetry.set(sdk);
}
// ---- Add shutdown hook (needs a final reference) --------------------------
final OpenTelemetrySdk finalSdk = sdk;
Runtime.getRuntime().addShutdownHook(
new Thread(() -> finalSdk.getSdkTracerProvider().shutdown()));
return sdk;
}
private static boolean isAppInsightsEnabled() {
return Boolean.parseBoolean(
System.getenv("JAVA_APPLICATIONINSIGHTS_ENABLE_TELEMETRY"));
}
private static void applyAzureMonitor(AutoConfiguredOpenTelemetrySdkBuilder builder, String connStr) {
try {
ClassLoader cl = FunctionsOpenTelemetry.class.getClassLoader();
// Resolve the types we need with the same CL
Class> autoCfgClass = Class.forName(
"com.azure.monitor.opentelemetry.autoconfigure.AzureMonitorAutoConfigure", false, cl);
Class> customizerIfc = Class.forName(
"io.opentelemetry.sdk.autoconfigure.spi.AutoConfigurationCustomizer", false, cl);
// Directly look up the exact overload we expect
Method customize =
autoCfgClass.getMethod("customize", customizerIfc, String.class);
customize.invoke(null, builder, connStr);
LOGGER.info("AzureMonitorAutoConfigure applied via reflection");
} catch (ClassNotFoundException e) {
LOGGER.fine("azure-monitor-opentelemetry-autoconfigure not present – skipping");
} catch (NoSuchMethodException e) {
LOGGER.warning("AzureMonitorAutoConfigure.customize(...) not found – "
+ "library version may have changed");
} catch (Throwable t) {
LOGGER.log(Level.WARNING, "Failed to apply AzureMonitorAutoConfigure", t);
}
}
private static final TextMapGetter TRACE_CONTEXT_GETTER = TraceContextTextMapGetter.INSTANCE;
public static Span startSpan(
String tracerName,
String spanName,
Context parent,
SpanKind kind) {
if (spanName == null || spanName.isEmpty()) {
throw new IllegalArgumentException("spanName must be non-null and non-empty");
}
if (tracerName == null || tracerName.isEmpty()) {
throw new IllegalArgumentException("tracerName must be non-null and non-empty");
}
return sdk().getTracer(tracerName)
.spanBuilder(spanName)
.setParent(parent == null ? Context.current() : parent)
.setSpanKind(kind == null ? SpanKind.INTERNAL : kind)
.startSpan();
}
public static Span startSpan(
String tracerName,
String spanName,
TraceContext traceContext,
SpanKind kind) {
Context parent = sdk().getPropagators()
.getTextMapPropagator()
.extract(Context.current(), traceContext, TRACE_CONTEXT_GETTER);
return startSpan(tracerName, spanName, parent, kind);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy