Summary
On Azure Functions Flex Consumption (Linux, Java) using identity-based storage (no AzureWebJobsStorage connection string, only AzureWebJobsStorage__accountName + AzureWebJobsStorage__credential), the Application Insights Java agent never runs its specialization initializer. As a result, custom logs are not correlated to operation_Id and sampling stays at the cold default (sampled=false on exported spans, no exports).
The agent's FunctionEnvironmentReloadInstrumentation aborts when the bare AzureWebJobsStorage env var is absent. On identity-based Flex apps that env var is intentionally not set, so the FERR (FunctionEnvironmentReload) signal that should trigger the agent's specialization is dropped.
Environment
- Azure Functions Flex Consumption, Linux
- Java 17 (also reproduces with other Java versions on Flex)
host.json: "telemetryMode": "OpenTelemetry", extension bundle [4.*, 5.0.0)
- AI Java agent: 3.7.6 (image-bundled at
/azure-functions-host/workers/java/agent/applicationinsights-agent.jar)
- Storage: identity-based (
AzureWebJobsStorage__accountName / AzureWebJobsStorage__credential, no bare AzureWebJobsStorage)
Observed symptoms
- Custom logs from function code arrive in App Insights
traces with no operation_Id.
- Worker-side OpenTelemetry spans show
sampled=false; downstream sampling decisions are stuck at 0.
- The agent's diagnostic log does not emit
Application Insights Java Agent specialized successfully or Application Insights Java Agent disabled after FERR.
Background: how the agent specializes on Flex
The Java worker's worker.config.json selects an AppInsightsPlaceholder profile when env INITIALIZED_FROM_PLACEHOLDER=true. That profile loads -javaagent:applicationinsights-agent.jar with -DLazySetOptIn=false. The agent installs bytecode transformers at premain, but the telemetry pipeline (exporter, sampler, connection string, role name) cannot be configured at premain because no app is assigned yet. So configuration is deferred to specialization:
SecondEntryPoint registers AzureFunctions.setup(hasConnectionString, AzureFunctionsInitializer).
- On FERR,
FunctionEnvironmentReloadInstrumentation advice calls AzureFunctions.configureOnce(), which runs the AzureFunctionsInitializer lazily.
AzureFunctionsInitializer.run() consults the opt-in gate (APPLICATIONINSIGHTS_ENABLE_AGENT env or -DLazySetOptIn sys prop). If enabled, it reads the connection string and applies the runtime config.
Root cause
FunctionEnvironmentReloadInstrumentation has this early return:
if (System.getenv("AzureWebJobsStorage") == null) {
return;
}
On identity-based Flex workers this env var is absent (storage is configured via AzureWebJobsStorage__accountName + AzureWebJobsStorage__credential), so the advice returns before invoking AzureFunctions.configureOnce(). The agent stays in its pre-specialization state for the life of the worker. The presence of AzureWebJobsStorage__accountName is not considered.
This was empirically confirmed with an A/B on the same app:
State of AzureWebJobsStorage |
hasConnectionString after FERR |
Worker span exports |
| absent (identity-based default) |
not consulted, agent never specializes |
0, sampled=false |
| present (bare conn string added) |
true, agent specializes |
full exports, sampled=true |
Reproduction
- Create a Flex Consumption Java function app with identity-based storage (do not set a bare
AzureWebJobsStorage app setting).
- Set
host.json -> "telemetryMode": "OpenTelemetry".
- Deploy an HTTP function that logs via
context.getLogger() and emits a worker-side OpenTelemetry span.
- Invoke it after specialization (avoid forcing a cold start). Observe:
traces rows have no operation_Id.
- Worker spans have
sampled=false and no exports.
- Agent diagnostic log lacks the specialization message.
Workarounds and drawbacks
Workaround A: Add a bare AzureWebJobsStorage connection string AND set APPLICATIONINSIGHTS_ENABLE_AGENT=true
Both app settings are required together. Adding only one is not sufficient.
AzureWebJobsStorage=<full connection string> makes the FERR guard pass so the agent's specialization runs.
APPLICATIONINSIGHTS_ENABLE_AGENT=true flips the agent's opt-in gate to true so specialization actually configures the telemetry pipeline (instead of self-disabling). This second setting is required because Flex Consumption does not auto-set it the way Linux Dedicated does. On a portal-created Linux Dedicated Java app, APPLICATIONINSIGHTS_ENABLE_AGENT=true is added to app settings automatically by the Functions / App Service provisioning layer when Application Insights is configured. On Flex, this auto-set does not happen, so users must set it explicitly. This is a Functions platform gap, not an agent bug, and is tracked separately.
Drawbacks:
- Storing a bare
AzureWebJobsStorage connection string defeats the purpose of identity-based storage. The connection string is a long-lived account key on app settings, exactly what identity-based storage is intended to eliminate.
- Two settings must be coordinated. Missing either silently degrades telemetry, and the failure mode is hard to diagnose without reading the agent code.
Workaround B: Force the worker to restart after the app is assigned (e.g. set languageWorkers__java__arguments to a harmless value)
The restarted worker still receives the Placeholder profile and loads the agent with -DLazySetOptIn=false, but because the app is already assigned by the time the new worker starts, APPLICATIONINSIGHTS_CONNECTION_STRING is present in the process env when premain runs. SecondEntryPoint configures the telemetry client at premain, hasConnectionString() returns true, and configureOnce() short-circuits at FERR. The opt-in gate is never consulted, so neither APPLICATIONINSIGHTS_ENABLE_AGENT nor LazySetOptIn matters. The FERR guard also no longer matters because the lazy path is bypassed.
Drawbacks:
- Every worker recycle and scale-out pays a full Java cold start. For Java workloads this is the most expensive part of placeholder warm-start to lose.
Suggested fix
Relax the FERR guard in FunctionEnvironmentReloadInstrumentation so identity-based storage is also accepted. Options:
- Also treat the worker as Functions-storage-configured when
AzureWebJobsStorage__accountName is present.
- Or remove the guard entirely. The FERR signal itself is the trigger that matters; the guard exists to filter out non-Functions reloads, but the FERR advice path is already Functions-specific.
The first option preserves the original intent of the guard while fixing the identity-based case. Either way, no agent-default change is needed; the existing APPLICATIONINSIGHTS_ENABLE_AGENT opt-in continues to work the same way it does on Linux Dedicated.
Related (not part of this issue)
The need to explicitly set APPLICATIONINSIGHTS_ENABLE_AGENT=true on Flex is a Functions platform gap: Linux Dedicated portal-created apps get this set for the user automatically, Flex does not. That is being tracked separately with the Functions Flex team and is not a bug in this agent. It is mentioned here only so that users following Workaround A have the full picture.
References (code paths)
agent/instrumentation/azure-functions/.../FunctionEnvironmentReloadInstrumentation.java (the guard)
agent/agent-bootstrap/.../AzureFunctions.java (configureOnce, hasConnectionString)
agent/agent-tooling/.../init/SecondEntryPoint.java (AzureFunctions.setup wiring)
agent/agent-tooling/.../init/AzureFunctionsInitializer.java (run, isAgentEnabled, initialize)
agent/instrumentation/azure-functions/.../InvocationInstrumentation.java (sampling override gated on hasConnectionString)
Summary
On Azure Functions Flex Consumption (Linux, Java) using identity-based storage (no
AzureWebJobsStorageconnection string, onlyAzureWebJobsStorage__accountName+AzureWebJobsStorage__credential), the Application Insights Java agent never runs its specialization initializer. As a result, custom logs are not correlated tooperation_Idand sampling stays at the cold default (sampled=falseon exported spans, no exports).The agent's
FunctionEnvironmentReloadInstrumentationaborts when the bareAzureWebJobsStorageenv var is absent. On identity-based Flex apps that env var is intentionally not set, so the FERR (FunctionEnvironmentReload) signal that should trigger the agent's specialization is dropped.Environment
host.json:"telemetryMode": "OpenTelemetry", extension bundle[4.*, 5.0.0)/azure-functions-host/workers/java/agent/applicationinsights-agent.jar)AzureWebJobsStorage__accountName/AzureWebJobsStorage__credential, no bareAzureWebJobsStorage)Observed symptoms
traceswith nooperation_Id.sampled=false; downstream sampling decisions are stuck at 0.Application Insights Java Agent specialized successfullyorApplication Insights Java Agent disabledafter FERR.Background: how the agent specializes on Flex
The Java worker's
worker.config.jsonselects anAppInsightsPlaceholderprofile when envINITIALIZED_FROM_PLACEHOLDER=true. That profile loads-javaagent:applicationinsights-agent.jarwith-DLazySetOptIn=false. The agent installs bytecode transformers at premain, but the telemetry pipeline (exporter, sampler, connection string, role name) cannot be configured at premain because no app is assigned yet. So configuration is deferred to specialization:SecondEntryPointregistersAzureFunctions.setup(hasConnectionString, AzureFunctionsInitializer).FunctionEnvironmentReloadInstrumentationadvice callsAzureFunctions.configureOnce(), which runs theAzureFunctionsInitializerlazily.AzureFunctionsInitializer.run()consults the opt-in gate (APPLICATIONINSIGHTS_ENABLE_AGENTenv or-DLazySetOptInsys prop). If enabled, it reads the connection string and applies the runtime config.Root cause
FunctionEnvironmentReloadInstrumentationhas this early return:On identity-based Flex workers this env var is absent (storage is configured via
AzureWebJobsStorage__accountName+AzureWebJobsStorage__credential), so the advice returns before invokingAzureFunctions.configureOnce(). The agent stays in its pre-specialization state for the life of the worker. The presence ofAzureWebJobsStorage__accountNameis not considered.This was empirically confirmed with an A/B on the same app:
AzureWebJobsStoragehasConnectionStringafter FERRsampled=falsesampled=trueReproduction
AzureWebJobsStorageapp setting).host.json->"telemetryMode": "OpenTelemetry".context.getLogger()and emits a worker-side OpenTelemetry span.tracesrows have nooperation_Id.sampled=falseand no exports.Workarounds and drawbacks
Workaround A: Add a bare
AzureWebJobsStorageconnection string AND setAPPLICATIONINSIGHTS_ENABLE_AGENT=trueBoth app settings are required together. Adding only one is not sufficient.
AzureWebJobsStorage=<full connection string>makes the FERR guard pass so the agent's specialization runs.APPLICATIONINSIGHTS_ENABLE_AGENT=trueflips the agent's opt-in gate to true so specialization actually configures the telemetry pipeline (instead of self-disabling). This second setting is required because Flex Consumption does not auto-set it the way Linux Dedicated does. On a portal-created Linux Dedicated Java app,APPLICATIONINSIGHTS_ENABLE_AGENT=trueis added to app settings automatically by the Functions / App Service provisioning layer when Application Insights is configured. On Flex, this auto-set does not happen, so users must set it explicitly. This is a Functions platform gap, not an agent bug, and is tracked separately.Drawbacks:
AzureWebJobsStorageconnection string defeats the purpose of identity-based storage. The connection string is a long-lived account key on app settings, exactly what identity-based storage is intended to eliminate.Workaround B: Force the worker to restart after the app is assigned (e.g. set
languageWorkers__java__argumentsto a harmless value)The restarted worker still receives the Placeholder profile and loads the agent with
-DLazySetOptIn=false, but because the app is already assigned by the time the new worker starts,APPLICATIONINSIGHTS_CONNECTION_STRINGis present in the process env when premain runs.SecondEntryPointconfigures the telemetry client at premain,hasConnectionString()returns true, andconfigureOnce()short-circuits at FERR. The opt-in gate is never consulted, so neitherAPPLICATIONINSIGHTS_ENABLE_AGENTnorLazySetOptInmatters. The FERR guard also no longer matters because the lazy path is bypassed.Drawbacks:
Suggested fix
Relax the FERR guard in
FunctionEnvironmentReloadInstrumentationso identity-based storage is also accepted. Options:AzureWebJobsStorage__accountNameis present.The first option preserves the original intent of the guard while fixing the identity-based case. Either way, no agent-default change is needed; the existing
APPLICATIONINSIGHTS_ENABLE_AGENTopt-in continues to work the same way it does on Linux Dedicated.Related (not part of this issue)
The need to explicitly set
APPLICATIONINSIGHTS_ENABLE_AGENT=trueon Flex is a Functions platform gap: Linux Dedicated portal-created apps get this set for the user automatically, Flex does not. That is being tracked separately with the Functions Flex team and is not a bug in this agent. It is mentioned here only so that users following Workaround A have the full picture.References (code paths)
agent/instrumentation/azure-functions/.../FunctionEnvironmentReloadInstrumentation.java(the guard)agent/agent-bootstrap/.../AzureFunctions.java(configureOnce,hasConnectionString)agent/agent-tooling/.../init/SecondEntryPoint.java(AzureFunctions.setupwiring)agent/agent-tooling/.../init/AzureFunctionsInitializer.java(run,isAgentEnabled,initialize)agent/instrumentation/azure-functions/.../InvocationInstrumentation.java(sampling override gated onhasConnectionString)