Skip to content

Commit 64c1bd7

Browse files
Copilotdavidfowleerhardt
authored
Change Python OTEL configuration to environment variables without requiring opentelemetry-instrument (#11879)
* Initial plan * Change Python OTEL configuration to environment variables Co-authored-by: davidfowl <[email protected]> * Remove instrumentationExecutable detection, unconditionally add OTEL support Co-authored-by: davidfowl <[email protected]> * Remove publish mode check for OTEL environment variables Co-authored-by: davidfowl <[email protected]> * Fix Python tests to work with unconditional WithOtlpExporter Co-authored-by: davidfowl <[email protected]> * Revert cd6600a and update GetEnvironmentVariableValuesAsync to accept IServiceProvider Co-authored-by: davidfowl <[email protected]> * Refactor GetEnvironmentVariableValuesAsync to remove IServiceProvider parameter and use EmptyServiceProvider instead * Refactor environment variable retrieval to use EnvironmentVariableEvaluator and remove EmptyServiceProvider * Apply suggestions from code review * Update src/Aspire.Hosting.Python/PythonAppResourceBuilderExtensions.cs * Update src/Aspire.Hosting.Python/PythonAppResourceBuilderExtensions.cs * Update src/Aspire.Hosting.Python/PythonAppResourceBuilderExtensions.cs * Change OTEL_LOGS_EXPORTER from "otlp,console" to "otlp" and update tests Co-authored-by: davidfowl <[email protected]> * Apply comments from code review --------- Co-authored-by: copilot-swe-agent[bot] <[email protected]> Co-authored-by: davidfowl <[email protected]> Co-authored-by: David Fowler <[email protected]> Co-authored-by: Eric Erhardt <[email protected]>
1 parent 72d0399 commit 64c1bd7

File tree

2 files changed

+36
-40
lines changed

2 files changed

+36
-40
lines changed

src/Aspire.Hosting.Python/PythonAppResourceBuilderExtensions.cs

Lines changed: 11 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -119,34 +119,29 @@ public static IResourceBuilder<PythonAppResource> AddPythonApp(
119119
? virtualEnvironmentPath
120120
: Path.Join(appDirectory, virtualEnvironmentPath));
121121

122-
var instrumentationExecutable = virtualEnvironment.GetExecutable("opentelemetry-instrument");
123122
var pythonExecutable = virtualEnvironment.GetRequiredExecutable("python");
124-
var appExecutable = instrumentationExecutable ?? pythonExecutable;
125123

126-
var resource = new PythonAppResource(name, appExecutable, appDirectory);
124+
var resource = new PythonAppResource(name, pythonExecutable, appDirectory);
127125

128126
var resourceBuilder = builder.AddResource(resource).WithArgs(context =>
129127
{
130-
// If the app is to be automatically instrumented, add the instrumentation executable arguments first.
131-
if (!string.IsNullOrEmpty(instrumentationExecutable))
132-
{
133-
AddOpenTelemetryArguments(context);
134-
135-
// Add the python executable as the next argument so we can run the app.
136-
context.Args.Add(pythonExecutable!);
137-
}
138-
139128
AddArguments(scriptPath, scriptArgs, context);
140129
});
141130

142-
if (!string.IsNullOrEmpty(instrumentationExecutable))
131+
resourceBuilder.WithOtlpExporter();
132+
133+
// Configure OpenTelemetry exporters using environment variables
134+
// https://opentelemetry.io/docs/specs/otel/configuration/sdk-environment-variables/#exporter-selection
135+
resourceBuilder.WithEnvironment(context =>
143136
{
144-
resourceBuilder.WithOtlpExporter();
137+
context.EnvironmentVariables["OTEL_TRACES_EXPORTER"] = "otlp";
138+
context.EnvironmentVariables["OTEL_LOGS_EXPORTER"] = "otlp";
139+
context.EnvironmentVariables["OTEL_METRICS_EXPORTER"] = "otlp";
145140

146141
// Make sure to attach the logging instrumentation setting, so we can capture logs.
147142
// Without this you'll need to configure logging yourself. Which is kind of a pain.
148-
resourceBuilder.WithEnvironment("OTEL_PYTHON_LOGGING_AUTO_INSTRUMENTATION_ENABLED", "true");
149-
}
143+
context.EnvironmentVariables["OTEL_PYTHON_LOGGING_AUTO_INSTRUMENTATION_ENABLED"] = "true";
144+
});
150145

151146
resourceBuilder.WithVSCodeDebugSupport(mode => new PythonLaunchConfiguration { ProgramPath = Path.Join(appDirectory, scriptPath), Mode = mode }, "ms-python.python", ctx =>
152147
{
@@ -168,18 +163,6 @@ private static void AddArguments(string scriptPath, string[] scriptArgs, Command
168163
}
169164
}
170165

171-
private static void AddOpenTelemetryArguments(CommandLineArgsCallbackContext context)
172-
{
173-
context.Args.Add("--traces_exporter");
174-
context.Args.Add("otlp");
175-
176-
context.Args.Add("--logs_exporter");
177-
context.Args.Add("console,otlp");
178-
179-
context.Args.Add("--metrics_exporter");
180-
context.Args.Add("otlp");
181-
}
182-
183166
private static void ThrowIfNullOrContainsIsNullOrEmpty(string[] scriptArgs)
184167
{
185168
ArgumentNullException.ThrowIfNull(scriptArgs);

tests/Aspire.Hosting.Python.Tests/AddPythonAppTests.cs

Lines changed: 25 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,12 @@ public async Task AddPythonAppProducesDockerfileResourceInManifest()
3737
"build": {
3838
"context": ".",
3939
"dockerfile": "Dockerfile"
40+
},
41+
"env": {
42+
"OTEL_TRACES_EXPORTER": "otlp",
43+
"OTEL_LOGS_EXPORTER": "otlp",
44+
"OTEL_METRICS_EXPORTER": "otlp",
45+
"OTEL_PYTHON_LOGGING_AUTO_INSTRUMENTATION_ENABLED": "true"
4046
}
4147
}
4248
""";
@@ -71,6 +77,9 @@ public async Task AddInstrumentedPythonProjectProducesDockerfileResourceInManife
7177
"dockerfile": "Dockerfile"
7278
},
7379
"env": {
80+
"OTEL_TRACES_EXPORTER": "otlp",
81+
"OTEL_LOGS_EXPORTER": "otlp",
82+
"OTEL_METRICS_EXPORTER": "otlp",
7483
"OTEL_PYTHON_LOGGING_AUTO_INSTRUMENTATION_ENABLED": "true"
7584
}
7685
}
@@ -118,7 +127,8 @@ public async Task PythonResourceSupportsWithReference()
118127
var pyproj = builder.AddPythonApp("pyproj", projectDirectory, scriptName)
119128
.WithReference(externalResource);
120129

121-
var environmentVariables = await pyproj.Resource.GetEnvironmentVariableValuesAsync(DistributedApplicationOperation.Run);
130+
using var app = builder.Build();
131+
var environmentVariables = await EnvironmentVariableEvaluator.GetEnvironmentVariablesAsync(pyproj.Resource, DistributedApplicationOperation.Run, TestServiceProvider.Instance);
122132

123133
Assert.Equal("test", environmentVariables["ConnectionStrings__connectionString"]);
124134

@@ -172,30 +182,33 @@ public async Task AddPythonAppWithInstrumentation_SwitchesExecutableToInstrument
172182

173183
builder.AddPythonApp("pythonProject", projectDirectory, scriptName, virtualEnvironmentPath: ".venv");
174184

175-
var app = builder.Build();
185+
using var app = builder.Build();
176186
var appModel = app.Services.GetRequiredService<DistributedApplicationModel>();
177187
var executableResources = appModel.GetExecutableResources();
178188

179189
var pythonProjectResource = Assert.Single(executableResources);
180190
var commandArguments = await ArgumentEvaluator.GetArgumentListAsync(pythonProjectResource, TestServiceProvider.Instance);
181191

192+
// Should use Python executable directly, not opentelemetry-instrument
182193
if (OperatingSystem.IsWindows())
183194
{
184-
Assert.Equal(Path.Join(projectDirectory, ".venv", "Scripts", "opentelemetry-instrument.exe"), pythonProjectResource.Command);
195+
Assert.Equal(Path.Join(projectDirectory, ".venv", "Scripts", "python.exe"), pythonProjectResource.Command);
185196
}
186197
else
187198
{
188-
Assert.Equal(Path.Join(projectDirectory, ".venv", "bin", "opentelemetry-instrument"), pythonProjectResource.Command);
199+
Assert.Equal(Path.Join(projectDirectory, ".venv", "bin", "python"), pythonProjectResource.Command);
189200
}
190201

191-
Assert.Equal("--traces_exporter", commandArguments[0]);
192-
Assert.Equal("otlp", commandArguments[1]);
193-
Assert.Equal("--logs_exporter", commandArguments[2]);
194-
Assert.Equal("console,otlp", commandArguments[3]);
195-
Assert.Equal("--metrics_exporter", commandArguments[4]);
196-
Assert.Equal("otlp", commandArguments[5]);
197-
Assert.Equal(pythonExecutable, commandArguments[6]);
198-
Assert.Equal(scriptName, commandArguments[7]);
202+
// Arguments should be: [script name]
203+
Assert.Single(commandArguments);
204+
Assert.Equal(scriptName, commandArguments[0]);
205+
206+
// Check for environment variables instead of command-line arguments
207+
var environmentVariables = await EnvironmentVariableEvaluator.GetEnvironmentVariablesAsync(pythonProjectResource, DistributedApplicationOperation.Run, TestServiceProvider.Instance);
208+
Assert.Equal("otlp", environmentVariables["OTEL_TRACES_EXPORTER"]);
209+
Assert.Equal("otlp", environmentVariables["OTEL_LOGS_EXPORTER"]);
210+
Assert.Equal("otlp", environmentVariables["OTEL_METRICS_EXPORTER"]);
211+
Assert.Equal("true", environmentVariables["OTEL_PYTHON_LOGGING_AUTO_INSTRUMENTATION_ENABLED"]);
199212

200213
// If we don't throw, clean up the directories.
201214
Directory.Delete(projectDirectory, true);

0 commit comments

Comments
 (0)