Skip to content

Commit b0b5640

Browse files
authored
Add OpenTelemetry support for Java Azure Functions (#819)
* working version using agent * working using shading * make sure that the app setting is processed everywhere * update span name * remove exporters from worker * add unit tests * update app setting * test paths where otel is enabled/disabled * code cleanup * change tracer name to match conventions * remove middleware from worker and rely on serviceloader to load it in from the new otel library * set class loader consistently * remove otel dependencies * move initialization logic back to where it used to be * revert back to using appsettings to turn on capabilities * update logic for setting capabilities * remove unnecessary changes * revert log line back to its original state
1 parent 506cfa2 commit b0b5640

File tree

4 files changed

+30
-14
lines changed

4 files changed

+30
-14
lines changed

pom.xml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,8 @@
111111
<artifactId>javax.annotation-api</artifactId>
112112
<version>1.3.2</version>
113113
</dependency>
114+
115+
<!-- test -->
114116
<dependency>
115117
<groupId>com.microsoft.azure.functions</groupId>
116118
<artifactId>azure-functions-java-library</artifactId>

src/main/java/com/microsoft/azure/functions/worker/Constants.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,6 @@ private Constants(){}
1515
public final static String JAVA_LIBRARY_DIRECTORY = "/annotationLib";
1616
public final static String JAVA_LIBRARY_ARTIFACT_ID = "azure-functions-java-library";
1717
public final static String HAS_IMPLICIT_OUTPUT_QUALIFIED_NAME = "com.microsoft.azure.functions.annotation.HasImplicitOutput";
18+
public static final String JAVA_ENABLE_OPENTELEMETRY = "JAVA_ENABLE_OPENTELEMETRY";
19+
public static final String JAVA_APPLICATIONINSIGHTS_ENABLE_TELEMETRY = "JAVA_APPLICATIONINSIGHTS_ENABLE_TELEMETRY";
1820
}

src/main/java/com/microsoft/azure/functions/worker/broker/JavaFunctionBroker.java

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -42,12 +42,13 @@ public class JavaFunctionBroker {
4242
private volatile InvocationChainFactory invocationChainFactory;
4343
private volatile FunctionInstanceInjector functionInstanceInjector;
4444
private final Object oneTimeLogicInitializationLock = new Object();
45-
private List<Middleware> baseMiddlewares = new ArrayList<>();
45+
private List<Middleware> serviceLoadedMiddlewares = new ArrayList<>();
4646
private final Map<String, InvocationChainFactory> functionFactories = new ConcurrentHashMap<>();
4747
private final SdkParameterAnalyzer sdkParameterAnalyzer = new SdkParameterAnalyzer();
4848
private final WorkerObjectCache<CacheKey> workerObjectCache;
4949
private static final boolean JAVA_ENABLE_SDK_TYPES_FLAG =
5050
Boolean.parseBoolean(System.getenv("JAVA_ENABLE_SDK_TYPES"));
51+
private ClassLoader userContextClassLoader;
5152

5253
private FunctionInstanceInjector newInstanceInjector() {
5354
return new FunctionInstanceInjector() {
@@ -86,17 +87,16 @@ private void createInvocationChainFactory(FunctionDefinition functionDefinition,
8687
SdkParameterAnalysisResult sdkParameterAnalysisResult =
8788
this.sdkParameterAnalyzer.analyze(functionDefinition.getCandidate().getMethod());
8889

89-
ClassLoader classLoader = this.classLoaderProvider.createClassLoader();
90-
List<Middleware> functionMws = new ArrayList<>(this.baseMiddlewares);
90+
List<Middleware> functionMws = new ArrayList<>(this.serviceLoadedMiddlewares);
9191
boolean hasAnySdkTypes = sdkParameterAnalysisResult.hasAnySdkTypes();
9292

9393
if (hasAnySdkTypes) {
94-
functionMws.add(new SdkTypeMiddleware(classLoader,
94+
functionMws.add(new SdkTypeMiddleware(userContextClassLoader,
9595
sdkParameterAnalysisResult.getSdkTypesMetaData(),
9696
this.sdkParameterAnalyzer.getRegistry()));
9797
}
9898

99-
functionMws.add(getFunctionExecutionMiddleWare(classLoader));
99+
functionMws.add(getFunctionExecutionMiddleWare(userContextClassLoader));
100100

101101
InvocationChainFactory factory = new InvocationChainFactory(functionMws);
102102
String functionId = functionDefinition.getDescriptor().getId();
@@ -110,15 +110,16 @@ private void initializeOneTimeLogics() {
110110
if (!oneTimeLogicInitialized) {
111111
synchronized (oneTimeLogicInitializationLock) {
112112
if (!oneTimeLogicInitialized) {
113+
userContextClassLoader = classLoaderProvider.createClassLoader();
113114

114115
if (JAVA_ENABLE_SDK_TYPES_FLAG) {
115116
loadGlobalMiddlewares();
116117
} else {
117118
initializeInvocationChainFactory();
118119
}
119120

120-
initializeFunctionInstanceInjector();
121121
oneTimeLogicInitialized = true;
122+
initializeFunctionInstanceInjector();
122123
}
123124
}
124125
}
@@ -128,9 +129,9 @@ private void loadGlobalMiddlewares() {
128129
ClassLoader prevContextClassLoader = Thread.currentThread().getContextClassLoader();
129130
try {
130131
//ServiceLoader will use thread context classloader to verify loaded class
131-
Thread.currentThread().setContextClassLoader(classLoaderProvider.createClassLoader());
132+
Thread.currentThread().setContextClassLoader(userContextClassLoader);
132133
for (Middleware middleware : ServiceLoader.load(Middleware.class)) {
133-
this.baseMiddlewares.add(middleware);
134+
this.serviceLoadedMiddlewares.add(middleware);
134135
WorkerLogManager.getSystemLogger().info("Loading discovered middleware " + middleware.getClass().getSimpleName());
135136
}
136137
} finally {
@@ -139,20 +140,20 @@ private void loadGlobalMiddlewares() {
139140
}
140141

141142
private void initializeInvocationChainFactory() {
142-
ArrayList<Middleware> middlewares = new ArrayList<>();
143-
ClassLoader prevContextClassLoader = Thread.currentThread().getContextClassLoader();
144-
ClassLoader newContextClassLoader = classLoaderProvider.createClassLoader();
143+
ClassLoader prevContextClassLoader = Thread.currentThread().getContextClassLoader();
145144
try {
146145
//ServiceLoader will use thread context classloader to verify loaded class
147-
Thread.currentThread().setContextClassLoader(newContextClassLoader);
146+
Thread.currentThread().setContextClassLoader(userContextClassLoader);
148147
for (Middleware middleware : ServiceLoader.load(Middleware.class)) {
149-
middlewares.add(middleware);
148+
this.serviceLoadedMiddlewares.add(middleware);
150149
WorkerLogManager.getSystemLogger().info("Load middleware " + middleware.getClass().getSimpleName());
151150
}
152151
} finally {
153152
Thread.currentThread().setContextClassLoader(prevContextClassLoader);
154153
}
155-
middlewares.add(getFunctionExecutionMiddleWare(newContextClassLoader));
154+
155+
ArrayList<Middleware> middlewares = new ArrayList<>(this.serviceLoadedMiddlewares);
156+
middlewares.add(getFunctionExecutionMiddleWare(userContextClassLoader));
156157
this.invocationChainFactory = new InvocationChainFactory(middlewares);
157158
}
158159

src/main/java/com/microsoft/azure/functions/worker/handler/WorkerInitRequestHandler.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@
66

77
import java.util.logging.Level;
88

9+
import static com.microsoft.azure.functions.worker.Constants.JAVA_APPLICATIONINSIGHTS_ENABLE_TELEMETRY;
10+
import static com.microsoft.azure.functions.worker.Constants.JAVA_ENABLE_OPENTELEMETRY;
11+
912
public class WorkerInitRequestHandler extends MessageHandler<WorkerInitRequest, WorkerInitResponse.Builder> {
1013
public WorkerInitRequestHandler(JavaFunctionBroker broker) {
1114
super(StreamingMessage::getWorkerInitRequest,
@@ -26,7 +29,15 @@ String execute(WorkerInitRequest request, WorkerInitResponse.Builder response) {
2629
response.putCapabilities("RpcHttpTriggerMetadataRemoved", "RpcHttpTriggerMetadataRemoved");
2730
response.putCapabilities("HandlesWorkerTerminateMessage", "HandlesWorkerTerminateMessage");
2831
response.putCapabilities("HandlesWorkerWarmupMessage", "HandlesWorkerWarmupMessage");
32+
33+
if (Boolean.parseBoolean(System.getenv(JAVA_ENABLE_OPENTELEMETRY)) ||
34+
Boolean.parseBoolean(System.getenv(JAVA_APPLICATIONINSIGHTS_ENABLE_TELEMETRY))) {
35+
response.putCapabilities("WorkerOpenTelemetryEnabled", "true");
36+
response.putCapabilities("WorkerApplicationInsightsLoggingEnabled", "true");
37+
}
38+
2939
response.setWorkerMetadata(composeWorkerMetadata());
40+
3041
return "Worker initialized";
3142
}
3243

0 commit comments

Comments
 (0)