Skip to content

Commit c607a7b

Browse files
[AzureMonitorExporter] Subscribe Statsbeat MeterProvider to distro Network SDKStats meter (Azure#60209)
* [AzureMonitorExporter] Subscribe Statsbeat MeterProvider to distro Network SDKStats meter The Microsoft.OpenTelemetry distro publishes Network SDKStats on a meter named `MicrosoftOpenTelemetryNetworkSdkStatsMeter` when it runs with a non-Azure-Monitor exporter (e.g. the Agent365 exporter), where the distro owns the network signal instead of the exporter's Breeze transmitter. This change: - Adds `StatsbeatConstants.DistroNetworkSdkStatsMeterName` constant. - Subscribes the Statsbeat MeterProvider in `AzureMonitorStatsbeat` to the new meter via `.AddMeter(...)` alongside the existing Attach, Feature, and distro Feature meters so distro-emitted Network stats flow through the existing Statsbeat cadence. This is the Network analog of Azure#59529 (distro Feature SDKStats meter). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * [AzureMonitorExporter] Add sentinel test for distro SDKStats meter subscriptions Adds a regression test guarding the Statsbeat MeterProvider's .AddMeter(...) subscriptions to the distro-owned Feature and Network SDKStats meters. The test publishes an observable instrument on each distro meter and asserts ForceFlush collects it, failing if a .AddMeter(StatsbeatConstants.Distro*SdkStatsMeterName) entry is removed or a meter constant is renamed. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent fbd3051 commit c607a7b

4 files changed

Lines changed: 56 additions & 0 deletions

File tree

sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/CHANGELOG.md

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

77
- Added support for the Microsoft OpenTelemetry distro's SDK statistics: a new internal meter subscription and an AppContext switch (`Azure.Monitor.OpenTelemetry.Exporter.RouteSdkStatsToDistroEndpoint`) that lets the distro redirect SDK statistics to its own ingestion path. The ingestion destination and an on/off signal are resolved at startup by fetching a remote configuration; on success the configured destination is used, an explicit remote disable signal turns SDK statistics off, and any other outcome falls back to the existing region-derived ingestion endpoint so SDK statistics keep flowing. The AppContext switch has no effect on Statsbeat for callers that do not opt in.
88

9+
- Subscribed the Statsbeat `MeterProvider` to the Microsoft OpenTelemetry distro's Network SDKStats meter (`MicrosoftOpenTelemetryNetworkSdkStatsMeter`) so distro-emitted Network statistics flow through the existing Statsbeat cadence when the distro runs with a non-Azure-Monitor exporter.
10+
911
### Breaking Changes
1012

1113
### Bugs Fixed

sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/src/Internals/Statsbeat/AzureMonitorStatsbeat.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,7 @@ private void BuildMeterProvider(string connectionString)
206206
.AddMeter(StatsbeatConstants.FeatureStatsbeatMeterName)
207207
.AddMeter(StatsbeatConstants.DistroFeatureSdkStatsMeterName)
208208
.AddMeter(StatsbeatConstants.NetworkSdkStatsMeterName)
209+
.AddMeter(StatsbeatConstants.DistroNetworkSdkStatsMeterName)
209210
.AddReader(new PeriodicExportingMetricReader(new AzureMonitorMetricExporter(exporterOptions), StatsbeatConstants.NetworkStatsbeatInterval)
210211
{ TemporalityPreference = MetricReaderTemporalityPreference.Delta })
211212
.Build();

sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/src/Internals/Statsbeat/StatsbeatConstants.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,5 +150,15 @@ internal static class StatsbeatConstants
150150
/// flow through to the same Statsbeat ingestion resource.
151151
/// </summary>
152152
internal const string DistroFeatureSdkStatsMeterName = "MicrosoftOpenTelemetryFeatureSdkStatsMeter";
153+
154+
/// <summary>
155+
/// Meter name used by the Microsoft OpenTelemetry distro to publish distro-owned Network
156+
/// SDKStats. When the distro runs with a non-Azure-Monitor exporter (e.g. the Agent365
157+
/// exporter), the distro owns the Network signal and records request success/failure,
158+
/// retry, throttle, duration, and exception counters on this meter. The Statsbeat
159+
/// <c>MeterProvider</c> subscribes to it so those measurements flow through the same
160+
/// Statsbeat ingestion resource as the Attach and Feature signals.
161+
/// </summary>
162+
internal const string DistroNetworkSdkStatsMeterName = "MicrosoftOpenTelemetryNetworkSdkStatsMeter";
153163
}
154164
}

sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/tests/Azure.Monitor.OpenTelemetry.Exporter.Tests/StatsbeatTests.cs

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
using Azure.Monitor.OpenTelemetry.Exporter.Internals.ConnectionString;
99
using Azure.Monitor.OpenTelemetry.Exporter.Internals.Statsbeat;
1010
using Azure.Monitor.OpenTelemetry.Exporter.Tests.CommonTestFramework;
11+
using OpenTelemetry;
12+
using OpenTelemetry.Metrics;
1113
using Xunit;
1214

1315
namespace Azure.Monitor.OpenTelemetry.Exporter.Tests
@@ -107,5 +109,46 @@ public void ConstructingAzureMonitorMetricExporter_TriggersStatsbeatSideEffect()
107109

108110
Assert.Contains(StatsbeatConstants.AttachStatsbeatMeterName, observedMeters);
109111
}
112+
113+
public static TheoryData<string> DistroSdkStatsMeterNames => new()
114+
{
115+
StatsbeatConstants.DistroFeatureSdkStatsMeterName,
116+
StatsbeatConstants.DistroNetworkSdkStatsMeterName,
117+
};
118+
119+
[Theory]
120+
[MemberData(nameof(DistroSdkStatsMeterNames))]
121+
public void StatsbeatMeterProvider_SubscribesToDistroSdkStatsMeters(string distroMeterName)
122+
{
123+
// SENTINEL TEST. The Microsoft.OpenTelemetry distro emits distro-owned Feature and
124+
// Network SDKStats on dedicated meters (e.g. when running with a non-Azure-Monitor
125+
// exporter). The Statsbeat MeterProvider must subscribe to those meters via
126+
// .AddMeter(...) so the measurements flow through the existing Statsbeat cadence.
127+
//
128+
// If this test fails, an .AddMeter(StatsbeatConstants.Distro*SdkStatsMeterName) entry
129+
// in AzureMonitorStatsbeat.BuildMeterProvider was removed or the meter constant was
130+
// renamed, silently dropping distro-emitted SDKStats.
131+
132+
var connectionString = "InstrumentationKey=00000000-0000-0000-0000-000000000000;IngestionEndpoint=https://eastus.in.applicationinsights.azure.com/";
133+
var connectionStringVars = ConnectionStringParser.GetValues(connectionString);
134+
135+
using var statsbeat = new AzureMonitorStatsbeat(connectionStringVars, new MockPlatform());
136+
Assert.NotNull(statsbeat._statsbeatMeterProvider);
137+
138+
// Publish an observable instrument on the distro meter. If the Statsbeat
139+
// MeterProvider subscribed to this meter, ForceFlush collects the instrument and
140+
// invokes the callback; otherwise the callback never runs.
141+
using var distroMeter = new Meter(distroMeterName);
142+
var callbackInvoked = false;
143+
distroMeter.CreateObservableGauge("test.sentinel", () =>
144+
{
145+
callbackInvoked = true;
146+
return new Measurement<long>(1);
147+
});
148+
149+
statsbeat._statsbeatMeterProvider!.ForceFlush();
150+
151+
Assert.True(callbackInvoked, $"Statsbeat MeterProvider did not subscribe to '{distroMeterName}'.");
152+
}
110153
}
111154
}

0 commit comments

Comments
 (0)