using System.Diagnostics; using MessageFlow; namespace MessageFlow.Samples; /// /// Shows the built-in logging and tracing middleware, UseLogging and UseTracing. /// public static class DiagnosticsSample { /// /// Builds a chain observed by a logger and by an per request. /// /// Receives one entry per request. /// The composed chain. public static IChain BuildChain(IChainLogger logger) { ArgumentNullException.ThrowIfNull(logger); return Chain.Create() .UseLogging(logger, ChainLogLevel.Information) .UseTracing("MessageFlow.Samples.Diagnostics") .UseWhen( request => request.StartsWith("ping", StringComparison.OrdinalIgnoreCase), (_, _) => new ValueTask("pong")) .WithFallback((request, _) => new ValueTask($"echo: {request}")) .Build(); } /// /// Runs the sample with a listener subscribed to the library activity source. /// /// The writer receiving the sample output. /// A token used to cancel the operation. /// The log entries produced by the requests. public static async Task> RunAsync( TextWriter output, CancellationToken cancellationToken = default) { ArgumentNullException.ThrowIfNull(output); var logger = new CollectingChainLogger(); var activityNames = new List(); using var listener = new ActivityListener { ShouldListenTo = source => source.Name == ChainDiagnostics.ActivitySourceName, Sample = (ref ActivityCreationOptions _) => ActivitySamplingResult.AllDataAndRecorded, ActivityStopped = activity => activityNames.Add($"{activity.OperationName}:{activity.Status}"), }; ActivitySource.AddActivityListener(listener); var chain = BuildChain(logger); foreach (var request in new[] { "ping", "hello" }) { var response = await chain.ExecuteAsync(request, cancellationToken).ConfigureAwait(false); await output.WriteLineAsync($"{request} => {response}").ConfigureAwait(false); } foreach (var entry in logger.Entries) { await output.WriteLineAsync($" log: {entry}").ConfigureAwait(false); } foreach (var activity in activityNames) { await output.WriteLineAsync($" activity: {activity}").ConfigureAwait(false); } return logger.Entries; } /// /// A minimal collecting the formatted entries in memory. /// private sealed class CollectingChainLogger : IChainLogger { public List Entries { get; } = []; public bool IsEnabled(ChainLogLevel level) => level >= ChainLogLevel.Information; public void Log(ChainLogLevel level, string message, Exception? exception) => Entries.Add($"{level}: {message}"); } }