diff --git a/docs/telemetry.md b/docs/telemetry.md
index 5dbad512d9..94b3c1ca10 100644
--- a/docs/telemetry.md
+++ b/docs/telemetry.md
@@ -2,17 +2,17 @@
Instances can be configured to emit telemetry to aid in performance testing or troubleshooting performance-related issues.
-Both the error and the audit instance report their ingestion the same way. Set `OtlpEndpointUrl`
-in that instance's settings root to a valid [OTLP endpoint url](https://opentelemetry.io/docs/specs/otel/protocol/exporter/#configuration-options).
-Only GRPC endpoints are supported at this stage.
+Both the error and the audit instance report their ingestion the same way. Exporting is configured with the standard [OpenTelemetry environment variables](https://opentelemetry.io/docs/specs/otel/protocol/exporter/#configuration-options), not with instance settings, so the same variables that configure any other OpenTelemetry process apply here. Setting `OTEL_EXPORTER_OTLP_ENDPOINT` is enough to turn metrics on. Both gRPC and HTTP endpoints are supported, and `OTEL_EXPORTER_OTLP_PROTOCOL` selects between them.
-The instruments differ only in their prefix and in the categories a message can fall into, so the
-same dashboard works for both with the prefix swapped. What the batches being measured actually are
-is covered in [ingestion-pipeline.md](ingestion-pipeline.md).
+The signal-specific variables, `OTEL_EXPORTER_OTLP_METRICS_ENDPOINT` and its siblings, have no effect. The SDK only honours those under `UseOtlpExporter`, and instances use `AddOtlpExporter` so that OTLP applies to metrics without also being turned on for every other signal.
+
+Logs are exported separately. Add `Otlp` to the instance's `LoggingProviders` setting, which is what turns the OTLP log exporter on, and it then reads the same environment variables for its endpoint.
+
+The instruments differ only in their prefix and in the categories a message can fall into, so the same dashboard works for both with the prefix swapped. What the batches being measured actually are is covered in [ingestion-pipeline.md](ingestion-pipeline.md).
## Error
-Meter `Particular.ServiceControl`, configured with `ServiceControl/OtlpEndpointUrl`.
+Meter `Particular.ServiceControl`.
- `sc.error.ingestion.batch_duration_seconds` - Message batch processing duration in seconds
- `result` - Whether the batch was written at its configured size: `full`, `partial` or `failed`
@@ -29,7 +29,7 @@ Meter `Particular.ServiceControl`, configured with `ServiceControl/OtlpEndpointU
## Audit
-Meter `Particular.ServiceControl.Audit`, configured with `ServiceControl.Audit/OtlpEndpointUrl`.
+Meter `Particular.ServiceControl.Audit`.
- `sc.audit.ingestion.batch_duration_seconds` - Message batch processing duration in seconds
- `result` - Whether the batch was written at its configured size: `full`, `partial` or `failed`
diff --git a/src/ServiceControl.Audit.UnitTests/ApprovalFiles/APIApprovals.PlatformSampleSettings.approved.txt b/src/ServiceControl.Audit.UnitTests/ApprovalFiles/APIApprovals.PlatformSampleSettings.approved.txt
index a1901c1f2c..c1066673e7 100644
--- a/src/ServiceControl.Audit.UnitTests/ApprovalFiles/APIApprovals.PlatformSampleSettings.approved.txt
+++ b/src/ServiceControl.Audit.UnitTests/ApprovalFiles/APIApprovals.PlatformSampleSettings.approved.txt
@@ -1,4 +1,4 @@
-{
+{
"LoggingSettings": {
"LogLevel": "Information",
"LogPath": "C:\\Logs"
@@ -47,7 +47,6 @@
"ApiUrl": "http://localhost:8888/api",
"Port": 8888,
"PrintMetrics": false,
- "OtlpEndpointUrl": null,
"Hostname": "localhost",
"VirtualDirectory": "",
"TransportType": "LearningTransport",
diff --git a/src/ServiceControl.Audit/App.config b/src/ServiceControl.Audit/App.config
index a3f5781c51..6e4cc74869 100644
--- a/src/ServiceControl.Audit/App.config
+++ b/src/ServiceControl.Audit/App.config
@@ -1,4 +1,4 @@
-
+
-
-
-
+
+
+
+
+
diff --git a/src/ServiceControl.Audit/HostApplicationBuilderExtensions.cs b/src/ServiceControl.Audit/HostApplicationBuilderExtensions.cs
index 151d7b9315..ccd2c635cc 100644
--- a/src/ServiceControl.Audit/HostApplicationBuilderExtensions.cs
+++ b/src/ServiceControl.Audit/HostApplicationBuilderExtensions.cs
@@ -1,4 +1,4 @@
-namespace ServiceControl.Audit;
+namespace ServiceControl.Audit;
using System;
using System.Diagnostics;
@@ -97,31 +97,30 @@ public static void AddMetrics(this IHostApplicationBuilder builder, Settings set
{
builder.Services.AddSingleton();
- if (!string.IsNullOrEmpty(settings.OtlpEndpointUrl))
+ var otlpEndpoint = OtlpEndpoint.Read(builder.Configuration);
+
+ if (otlpEndpoint is null)
{
- if (!Uri.TryCreate(settings.OtlpEndpointUrl, UriKind.Absolute, out var otelMetricsUri))
+ return;
+ }
+
+ builder.Services.AddOpenTelemetry()
+ .ConfigureResource(b => b.AddService(
+ serviceName: settings.InstanceName,
+ serviceVersion: InstanceVersion,
+ autoGenerateServiceInstanceId: true))
+ .WithMetrics(b =>
{
- throw new UriFormatException($"Invalid OtlpEndpointUrl: {settings.OtlpEndpointUrl}");
- }
-
- builder.Services.AddOpenTelemetry()
- .ConfigureResource(b => b.AddService(
- serviceName: settings.InstanceName,
- serviceVersion: InstanceVersion,
- autoGenerateServiceInstanceId: true))
- .WithMetrics(b =>
+ b.AddIngestionMetrics();
+ b.AddOtlpExporter();
+ if (Debugger.IsAttached)
{
- b.AddIngestionMetrics();
- b.AddOtlpExporter(e => e.Endpoint = otelMetricsUri);
- if (Debugger.IsAttached)
- {
- b.AddConsoleExporter();
- }
- });
-
- var logger = LoggerUtil.CreateStaticLogger(typeof(HostApplicationBuilderExtensions), settings.LoggingSettings.LogLevel);
- logger.LogInformation("OpenTelemetry metrics exporter enabled: {OtlpEndpointUrl}", settings.OtlpEndpointUrl);
- }
+ b.AddConsoleExporter();
+ }
+ });
+
+ var logger = LoggerUtil.CreateStaticLogger(typeof(HostApplicationBuilderExtensions), settings.LoggingSettings.LogLevel);
+ logger.LogInformation("OpenTelemetry metrics exporter enabled: {OtlpEndpoint}", otlpEndpoint);
}
static void RecordStartup(Settings settings, EndpointConfiguration endpointConfiguration, IPersistenceConfiguration persistenceConfiguration)
diff --git a/src/ServiceControl.Audit/Infrastructure/Settings/Settings.cs b/src/ServiceControl.Audit/Infrastructure/Settings/Settings.cs
index e60961c560..7a6b8d978f 100644
--- a/src/ServiceControl.Audit/Infrastructure/Settings/Settings.cs
+++ b/src/ServiceControl.Audit/Infrastructure/Settings/Settings.cs
@@ -148,7 +148,6 @@ public string RootUrl
public int Port { get; set; }
public bool PrintMetrics => SettingsReader.Read(SettingsRootNamespace, "PrintMetrics");
- public string OtlpEndpointUrl { get; set; } = SettingsReader.Read(SettingsRootNamespace, nameof(OtlpEndpointUrl));
public string Hostname { get; private set; }
public string VirtualDirectory => SettingsReader.Read(SettingsRootNamespace, "VirtualDirectory", string.Empty);
diff --git a/src/ServiceControl.Infrastructure/OtlpEndpoint.cs b/src/ServiceControl.Infrastructure/OtlpEndpoint.cs
new file mode 100644
index 0000000000..eee1f7cbf6
--- /dev/null
+++ b/src/ServiceControl.Infrastructure/OtlpEndpoint.cs
@@ -0,0 +1,28 @@
+namespace ServiceControl.Infrastructure;
+
+using System;
+using Microsoft.Extensions.Configuration;
+
+public static class OtlpEndpoint
+{
+ // This is the default environment variable name used by the OpenTelemetry .NET SDK to configure the OTLP exporter endpoint
+ // as specified in https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/protocol/exporter.md.
+ const string EndpointKey = "OTEL_EXPORTER_OTLP_ENDPOINT";
+
+ public static Uri Read(IConfiguration configuration)
+ {
+ var configuredEndpoint = configuration[EndpointKey];
+
+ if (string.IsNullOrWhiteSpace(configuredEndpoint))
+ {
+ return null;
+ }
+
+ if (!Uri.TryCreate(configuredEndpoint, UriKind.Absolute, out var endpoint))
+ {
+ throw new UriFormatException($"Invalid {EndpointKey}: {configuredEndpoint}");
+ }
+
+ return endpoint;
+ }
+}
diff --git a/src/ServiceControl.Monitoring.UnitTests/ApprovalFiles/SettingsTests.PlatformSampleSettings.approved.txt b/src/ServiceControl.Monitoring.UnitTests/ApprovalFiles/SettingsTests.PlatformSampleSettings.approved.txt
index b8f0237609..ca16ad95a4 100644
--- a/src/ServiceControl.Monitoring.UnitTests/ApprovalFiles/SettingsTests.PlatformSampleSettings.approved.txt
+++ b/src/ServiceControl.Monitoring.UnitTests/ApprovalFiles/SettingsTests.PlatformSampleSettings.approved.txt
@@ -1,4 +1,4 @@
-{
+{
"LoggingSettings": {
"LogLevel": "Information",
"LogPath": "C:\\Logs"
diff --git a/src/ServiceControl.Monitoring/App.config b/src/ServiceControl.Monitoring/App.config
index ab620acab4..be1b700c36 100644
--- a/src/ServiceControl.Monitoring/App.config
+++ b/src/ServiceControl.Monitoring/App.config
@@ -1,4 +1,4 @@
-
+
-
-
-
+
+
+
+
+
diff --git a/src/ServiceControl.Monitoring/Settings.cs b/src/ServiceControl.Monitoring/Settings.cs
index e6f6b84f02..a1b11750b8 100644
--- a/src/ServiceControl.Monitoring/Settings.cs
+++ b/src/ServiceControl.Monitoring/Settings.cs
@@ -1,4 +1,4 @@
-namespace ServiceControl.Monitoring
+namespace ServiceControl.Monitoring
{
using System;
using System.Collections.Generic;
diff --git a/src/ServiceControl.UnitTests/ApprovalFiles/APIApprovals.PlatformSampleSettings.approved.txt b/src/ServiceControl.UnitTests/ApprovalFiles/APIApprovals.PlatformSampleSettings.approved.txt
index a638e3df4f..abd4c98313 100644
--- a/src/ServiceControl.UnitTests/ApprovalFiles/APIApprovals.PlatformSampleSettings.approved.txt
+++ b/src/ServiceControl.UnitTests/ApprovalFiles/APIApprovals.PlatformSampleSettings.approved.txt
@@ -1,4 +1,4 @@
-{
+{
"LoggingSettings": {
"LogLevel": "Information",
"LogPath": "C:\\Logs"
@@ -59,7 +59,6 @@
"Port": 8888,
"PersisterSpecificSettings": null,
"PrintMetrics": false,
- "OtlpEndpointUrl": null,
"Hostname": "localhost",
"VirtualDirectory": "",
"HeartbeatGracePeriod": "00:00:40",
diff --git a/src/ServiceControl/App.config b/src/ServiceControl/App.config
index 4a77515a3b..98d8fc8433 100644
--- a/src/ServiceControl/App.config
+++ b/src/ServiceControl/App.config
@@ -1,4 +1,4 @@
-
+
+
+
diff --git a/src/ServiceControl/HostApplicationBuilderExtensions.cs b/src/ServiceControl/HostApplicationBuilderExtensions.cs
index cbef15f93b..6f132742bc 100644
--- a/src/ServiceControl/HostApplicationBuilderExtensions.cs
+++ b/src/ServiceControl/HostApplicationBuilderExtensions.cs
@@ -152,14 +152,11 @@ public static void AddIngestionMetrics(this IHostApplicationBuilder hostBuilder,
{
hostBuilder.Services.AddSingleton();
- if (string.IsNullOrEmpty(settings.OtlpEndpointUrl))
- {
- return;
- }
+ var otlpEndpoint = OtlpEndpoint.Read(hostBuilder.Configuration);
- if (!Uri.TryCreate(settings.OtlpEndpointUrl, UriKind.Absolute, out var otlpEndpoint))
+ if (otlpEndpoint is null)
{
- throw new UriFormatException($"Invalid OtlpEndpointUrl: {settings.OtlpEndpointUrl}");
+ return;
}
hostBuilder.Services.AddOpenTelemetry()
@@ -170,7 +167,7 @@ public static void AddIngestionMetrics(this IHostApplicationBuilder hostBuilder,
.WithMetrics(metrics =>
{
metrics.AddIngestionMetrics();
- metrics.AddOtlpExporter(exporter => exporter.Endpoint = otlpEndpoint);
+ metrics.AddOtlpExporter();
if (Debugger.IsAttached)
{
@@ -179,7 +176,7 @@ public static void AddIngestionMetrics(this IHostApplicationBuilder hostBuilder,
});
LoggerUtil.CreateStaticLogger(typeof(HostApplicationBuilderExtensions), settings.LoggingSettings.LogLevel)
- .LogInformation("OpenTelemetry metrics exporter enabled: {OtlpEndpointUrl}", settings.OtlpEndpointUrl);
+ .LogInformation("OpenTelemetry metrics exporter enabled: {OtlpEndpoint}", otlpEndpoint);
}
static void RecordStartup(Settings settings, EndpointConfiguration endpointConfiguration)
diff --git a/src/ServiceControl/Infrastructure/Settings/Settings.cs b/src/ServiceControl/Infrastructure/Settings/Settings.cs
index 8be72ac55e..af52f4bf88 100644
--- a/src/ServiceControl/Infrastructure/Settings/Settings.cs
+++ b/src/ServiceControl/Infrastructure/Settings/Settings.cs
@@ -178,7 +178,6 @@ public string InstanceId
public bool PrintMetrics => SettingsReader.Read(SettingsRootNamespace, "PrintMetrics");
- public string OtlpEndpointUrl { get; set; } = SettingsReader.Read(SettingsRootNamespace, nameof(OtlpEndpointUrl));
public string Hostname { get; private set; }
public string VirtualDirectory => SettingsReader.Read(SettingsRootNamespace, "VirtualDirectory", string.Empty);