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

This commit is contained in:
StellaOps Bot
2025-12-11 02:32:18 +02:00
parent 92bc4d3a07
commit 49922dff5a
474 changed files with 76071 additions and 12411 deletions

View File

@@ -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);

View File

@@ -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();

View File

@@ -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);

View File

@@ -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)

View File

@@ -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;
}
}