up the blokcing tasks
Some checks failed
Docs CI / lint-and-preview (push) Has been cancelled
Notify Smoke Test / Notifier Service Tests (push) Has been cancelled
Notify Smoke Test / Notification Smoke Test (push) Has been cancelled
Notify Smoke Test / Notify Unit Tests (push) Has been cancelled
AOC Guard CI / aoc-guard (push) Has been cancelled
AOC Guard CI / aoc-verify (push) Has been cancelled
Export Center CI / export-ci (push) Has been cancelled
Manifest Integrity / Validate Schema Integrity (push) Has been cancelled
Manifest Integrity / Validate Contract Documents (push) Has been cancelled
Manifest Integrity / Validate Pack Fixtures (push) Has been cancelled
Manifest Integrity / Audit SHA256SUMS Files (push) Has been cancelled
Manifest Integrity / Verify Merkle Roots (push) Has been cancelled
Policy Lint & Smoke / policy-lint (push) Has been cancelled
Risk Bundle CI / risk-bundle-build (push) Has been cancelled
Scanner Analyzers / Discover Analyzers (push) Has been cancelled
Scanner Analyzers / Validate Test Fixtures (push) Has been cancelled
Risk Bundle CI / risk-bundle-offline-kit (push) Has been cancelled
Risk Bundle CI / publish-checksums (push) Has been cancelled
Scanner Analyzers / Build Analyzers (push) Has been cancelled
Scanner Analyzers / Test Language Analyzers (push) Has been cancelled
Scanner Analyzers / Verify Deterministic Output (push) Has been cancelled
devportal-offline / build-offline (push) Has been cancelled
Mirror Thin Bundle Sign & Verify / mirror-sign (push) Has been cancelled
Some checks failed
Docs CI / lint-and-preview (push) Has been cancelled
Notify Smoke Test / Notifier Service Tests (push) Has been cancelled
Notify Smoke Test / Notification Smoke Test (push) Has been cancelled
Notify Smoke Test / Notify Unit Tests (push) Has been cancelled
AOC Guard CI / aoc-guard (push) Has been cancelled
AOC Guard CI / aoc-verify (push) Has been cancelled
Export Center CI / export-ci (push) Has been cancelled
Manifest Integrity / Validate Schema Integrity (push) Has been cancelled
Manifest Integrity / Validate Contract Documents (push) Has been cancelled
Manifest Integrity / Validate Pack Fixtures (push) Has been cancelled
Manifest Integrity / Audit SHA256SUMS Files (push) Has been cancelled
Manifest Integrity / Verify Merkle Roots (push) Has been cancelled
Policy Lint & Smoke / policy-lint (push) Has been cancelled
Risk Bundle CI / risk-bundle-build (push) Has been cancelled
Scanner Analyzers / Discover Analyzers (push) Has been cancelled
Scanner Analyzers / Validate Test Fixtures (push) Has been cancelled
Risk Bundle CI / risk-bundle-offline-kit (push) Has been cancelled
Risk Bundle CI / publish-checksums (push) Has been cancelled
Scanner Analyzers / Build Analyzers (push) Has been cancelled
Scanner Analyzers / Test Language Analyzers (push) Has been cancelled
Scanner Analyzers / Verify Deterministic Output (push) Has been cancelled
devportal-offline / build-offline (push) Has been cancelled
Mirror Thin Bundle Sign & Verify / mirror-sign (push) Has been cancelled
This commit is contained in:
@@ -96,6 +96,7 @@ public sealed class SealedModeFileExporterTests : IDisposable
|
||||
var data = Encoding.UTF8.GetBytes("test data");
|
||||
|
||||
exporter.Write(data, TelemetrySignal.Traces);
|
||||
exporter.Dispose();
|
||||
|
||||
var fileContent = File.ReadAllText(exporter.CurrentFilePath!);
|
||||
Assert.Contains("test data", fileContent);
|
||||
@@ -110,6 +111,7 @@ public sealed class SealedModeFileExporterTests : IDisposable
|
||||
var data = Encoding.UTF8.GetBytes("test");
|
||||
|
||||
exporter.Write(data, TelemetrySignal.Traces);
|
||||
exporter.Dispose();
|
||||
|
||||
var fileContent = File.ReadAllText(exporter.CurrentFilePath!);
|
||||
Assert.Contains("2025-11-27", fileContent);
|
||||
@@ -122,8 +124,9 @@ public sealed class SealedModeFileExporterTests : IDisposable
|
||||
var data = Encoding.UTF8.GetBytes("auto-init test");
|
||||
|
||||
exporter.Write(data, TelemetrySignal.Metrics);
|
||||
|
||||
Assert.True(exporter.IsInitialized);
|
||||
exporter.Dispose();
|
||||
|
||||
var fileContent = File.ReadAllText(exporter.CurrentFilePath!);
|
||||
Assert.Contains("auto-init test", fileContent);
|
||||
}
|
||||
@@ -135,6 +138,7 @@ public sealed class SealedModeFileExporterTests : IDisposable
|
||||
exporter.Initialize();
|
||||
|
||||
exporter.WriteRecord("string record data", TelemetrySignal.Logs);
|
||||
exporter.Dispose();
|
||||
|
||||
var fileContent = File.ReadAllText(exporter.CurrentFilePath!);
|
||||
Assert.Contains("string record data", fileContent);
|
||||
@@ -219,6 +223,7 @@ public sealed class SealedModeFileExporterTests : IDisposable
|
||||
exporter.WriteRecord("traces data", TelemetrySignal.Traces);
|
||||
exporter.WriteRecord("metrics data", TelemetrySignal.Metrics);
|
||||
exporter.WriteRecord("logs data", TelemetrySignal.Logs);
|
||||
exporter.Dispose();
|
||||
|
||||
var fileContent = File.ReadAllText(exporter.CurrentFilePath!);
|
||||
Assert.Contains("[Traces]", fileContent);
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
@@ -35,6 +36,29 @@ public class TelemetryPropagationHandlerTests
|
||||
Assert.Equal("rule-b", terminal.SeenHeaders[options.Value.Propagation.ImposedRuleHeader]);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Handler_Propagates_Trace_When_Context_Missing()
|
||||
{
|
||||
var options = Options.Create(new StellaOpsTelemetryOptions());
|
||||
var accessor = new TelemetryContextAccessor();
|
||||
|
||||
using var activity = new Activity("test-trace").Start();
|
||||
|
||||
var terminal = new RecordingHandler();
|
||||
var handler = new TelemetryPropagationHandler(accessor, options)
|
||||
{
|
||||
InnerHandler = terminal
|
||||
};
|
||||
|
||||
var invoker = new HttpMessageInvoker(handler);
|
||||
await invoker.SendAsync(new HttpRequestMessage(HttpMethod.Get, "http://example.com"), CancellationToken.None);
|
||||
|
||||
Assert.Equal(activity.TraceId.ToString(), terminal.SeenHeaders[options.Value.Propagation.TraceIdHeader]);
|
||||
Assert.False(terminal.SeenHeaders.ContainsKey(options.Value.Propagation.TenantHeader));
|
||||
Assert.False(terminal.SeenHeaders.ContainsKey(options.Value.Propagation.ActorHeader));
|
||||
Assert.False(terminal.SeenHeaders.ContainsKey(options.Value.Propagation.ImposedRuleHeader));
|
||||
}
|
||||
|
||||
private sealed class RecordingHandler : HttpMessageHandler
|
||||
{
|
||||
public Dictionary<string, string?> SeenHeaders { get; } = new();
|
||||
|
||||
@@ -119,7 +119,7 @@ public sealed class SealedModeFileExporter : IDisposable
|
||||
filePath,
|
||||
FileMode.Append,
|
||||
FileAccess.Write,
|
||||
FileShare.Read,
|
||||
FileShare.ReadWrite,
|
||||
bufferSize: 4096,
|
||||
FileOptions.WriteThrough);
|
||||
|
||||
@@ -253,7 +253,7 @@ public sealed class SealedModeFileExporter : IDisposable
|
||||
basePath,
|
||||
FileMode.Create,
|
||||
FileAccess.Write,
|
||||
FileShare.Read,
|
||||
FileShare.ReadWrite,
|
||||
bufferSize: 4096,
|
||||
FileOptions.WriteThrough);
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.Net.Http;
|
||||
using System.Diagnostics;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Extensions.Options;
|
||||
@@ -24,6 +25,11 @@ public sealed class TelemetryPropagationHandler : DelegatingHandler
|
||||
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
|
||||
{
|
||||
var ctx = _accessor.Current;
|
||||
if (ctx is null)
|
||||
{
|
||||
// Preserve trace propagation even when an accessor has not been populated.
|
||||
ctx = TelemetryContext.FromActivity(Activity.Current);
|
||||
}
|
||||
var propagation = _options.Value.Propagation;
|
||||
|
||||
if (ctx is not null)
|
||||
|
||||
@@ -28,7 +28,7 @@ public sealed class TelemetryPropagationMiddleware
|
||||
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
||||
}
|
||||
|
||||
public async Task InvokeAsync(HttpContext context)
|
||||
public Task InvokeAsync(HttpContext context)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(context);
|
||||
|
||||
@@ -60,32 +60,50 @@ public sealed class TelemetryPropagationMiddleware
|
||||
telemetryContext.ImposedRule ?? string.Empty,
|
||||
telemetryContext.CorrelationId ?? string.Empty);
|
||||
|
||||
// Ensure accessor is repopulated from Items even if AsyncLocal flow is suppressed
|
||||
if (context.Items.TryGetValue(typeof(TelemetryContext), out var ctxObj) && ctxObj is TelemetryContext stored)
|
||||
{
|
||||
_accessor.Context = stored;
|
||||
_accessor.Current = stored;
|
||||
}
|
||||
else if (context.Items.TryGetValue("TelemetryContext", out var ctxString) && ctxString is TelemetryContext storedString)
|
||||
{
|
||||
_accessor.Context = storedString;
|
||||
_accessor.Current = storedString;
|
||||
}
|
||||
|
||||
var nextTask = _next(context);
|
||||
if (nextTask.IsCompletedSuccessfully)
|
||||
{
|
||||
Cleanup(previous, activity);
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
return Awaited(nextTask, previous, activity);
|
||||
}
|
||||
|
||||
private async Task Awaited(Task nextTask, TelemetryContext? previous, Activity activity)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Ensure accessor is repopulated from Items even if AsyncLocal flow is suppressed
|
||||
if (context.Items.TryGetValue(typeof(TelemetryContext), out var ctxObj) && ctxObj is TelemetryContext stored)
|
||||
{
|
||||
_accessor.Context = stored;
|
||||
_accessor.Current = stored;
|
||||
}
|
||||
else if (context.Items.TryGetValue("TelemetryContext", out var ctxString) && ctxString is TelemetryContext storedString)
|
||||
{
|
||||
_accessor.Context = storedString;
|
||||
_accessor.Current = storedString;
|
||||
}
|
||||
|
||||
await _next(context);
|
||||
await nextTask.ConfigureAwait(false);
|
||||
}
|
||||
finally
|
||||
{
|
||||
_accessor.Context = previous;
|
||||
_accessor.Current = previous;
|
||||
if (previous is null)
|
||||
{
|
||||
// ensure clean slate when there was no prior context
|
||||
_accessor.Context = null;
|
||||
_accessor.Current = null;
|
||||
}
|
||||
Cleanup(previous, activity);
|
||||
}
|
||||
}
|
||||
|
||||
private void Cleanup(TelemetryContext? previous, Activity activity)
|
||||
{
|
||||
Activity.Current = activity;
|
||||
|
||||
_accessor.Context = previous;
|
||||
_accessor.Current = previous;
|
||||
if (previous is null)
|
||||
{
|
||||
_accessor.Context = null;
|
||||
_accessor.Current = null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user