Skip to content

Instantly share code, notes, and snippets.

@ladeak
Created March 14, 2021 19:14
Show Gist options
  • Save ladeak/9889acc08821de73d675c22679704425 to your computer and use it in GitHub Desktop.
Save ladeak/9889acc08821de73d675c22679704425 to your computer and use it in GitHub Desktop.
ActivityLogWriter
using System.Diagnostics;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
namespace ConsoleApp2
{
public class ActivityLogWriter : IActivityWriter
{
private readonly ILogger<ActivityLogWriter> _logger;
public ActivityLogWriter(ILogger<ActivityLogWriter> logger)
{
_logger = logger;
}
public ValueTask Write(Activity activity)
{
_logger.LogInformation($"Name: { activity.OperationName}, Duration: {activity.Duration}");
return ValueTask.CompletedTask;
}
}
}
using System;
using System.Diagnostics;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
namespace ConsoleApp2
{
public partial class Program
{
public class ActivityTraceBuilder
{
private readonly Func<string, bool> _sourceFilter;
private readonly Action<Activity> _onActivity;
private readonly IActivityWriter _writer;
private readonly ILoggerFactory _loggerFactory;
private ActivityTraceBuilder(Func<string, bool> sourceFilter, Action<Activity> onActivity, IActivityWriter writer, ILoggerFactory loggerFactory)
{
_sourceFilter = sourceFilter;
_onActivity = onActivity;
_writer = writer;
_loggerFactory = loggerFactory;
}
public static ActivityTraceBuilder Create(IActivityWriter writer) => new ActivityTraceBuilder(null, null, writer, null);
public static ActivityTraceBuilder CreateCaptureToLog(ILoggerFactory loggerFactory) => new ActivityTraceBuilder(null, null, new ActivityLogWriter(loggerFactory.CreateLogger<ActivityLogWriter>()), loggerFactory);
public ActivityTraceBuilder WithFilter(Func<string, bool> sourceFilter) => new ActivityTraceBuilder(sourceFilter, _onActivity, _writer, _loggerFactory);
public ActivityTraceBuilder WithOnActivity(Action<Activity> onActivity) => new ActivityTraceBuilder(_sourceFilter, onActivity, _writer, _loggerFactory);
public ActivityTraceBuilder WithLogger(ILoggerFactory loggerFactory) => new ActivityTraceBuilder(_sourceFilter, _onActivity, _writer, loggerFactory);
public ChannledActivityListener Build()
{
return new ChannledActivityListener(_sourceFilter, _onActivity, _writer, _loggerFactory?.CreateLogger<ChannledActivityListener>() ?? NullLogger<ChannledActivityListener>.Instance);
}
}
}
}
using System;
using System.Diagnostics;
using System.Threading;
using System.Threading.Channels;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
namespace ConsoleApp2
{
public class ChannledActivityListener : IDisposable, IAsyncDisposable
{
private readonly ActivityListener _listener;
private readonly Action<Activity> _onActivity;
private readonly IActivityWriter _writer;
private readonly ILogger<ChannledActivityListener> _logger;
private readonly Channel<Activity> _channel = Channel.CreateBounded<Activity>(new BoundedChannelOptions(128) { SingleReader = true, FullMode = BoundedChannelFullMode.Wait });
private readonly TaskCompletionSource _taskCompletionSource = new TaskCompletionSource();
public ChannledActivityListener(Func<string, bool> sourceFilter, Action<Activity> onActivity, IActivityWriter writer, ILogger<ChannledActivityListener> logger)
{
_writer = writer ?? throw new ArgumentNullException(nameof(writer));
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
_listener = new ActivityListener();
_listener.ShouldListenTo = source => sourceFilter?.Invoke(source.Name) ?? true;
_onActivity = onActivity;
_listener.ActivityStopped = OnActivityComplete;
_listener.Sample = new SampleActivity<ActivityContext>((ref ActivityCreationOptions<ActivityContext> options) => ActivitySamplingResult.AllData);
_ = Run();
ActivitySource.AddActivityListener(_listener);
}
public async Task Run(CancellationToken token = default)
{
try
{
while (await _channel.Reader.WaitToReadAsync(token))
{
while (!token.IsCancellationRequested && _channel.Reader.TryRead(out var activity))
{
await _writer.Write(activity);
}
}
}
finally
{
_taskCompletionSource.SetResult();
}
}
public void OnActivityComplete(Activity activity)
{
_onActivity?.Invoke(activity);
if (!_channel.Writer.TryWrite(activity))
{
_logger.LogError("Bounded channel returns false, when the queue is full");
}
}
public void Dispose()
{
_channel.Writer.TryComplete();
_channel.Reader.Completion.GetAwaiter().GetResult();
_taskCompletionSource.Task.GetAwaiter().GetResult();
_listener.Dispose();
}
public async ValueTask DisposeAsync()
{
_listener.Dispose();
_channel.Writer.TryComplete();
await _channel.Reader.Completion;
await _taskCompletionSource.Task;
}
}
}
using System.Diagnostics;
using System.Threading.Tasks;
namespace ConsoleApp2
{
public interface IActivityWriter
{
ValueTask Write(Activity activity);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment