Skip to content

Instantly share code, notes, and snippets.

@ladeak
Last active March 14, 2021 19:15
Show Gist options
  • Save ladeak/49b92edfdd99485e4a2ef55e3473806a to your computer and use it in GitHub Desktop.
Save ladeak/49b92edfdd99485e4a2ef55e3473806a to your computer and use it in GitHub Desktop.
OpenTelemetryActivityLogWriter
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.Diagnostics;
using System.Threading.Tasks;
namespace ConsoleApp2
{
public interface IActivityWriter
{
ValueTask Write(Activity activity);
}
}
using System;
using System.Diagnostics;
using System.Threading;
using System.Threading.Channels;
using System.Threading.Tasks;
using OpenTelemetry;
namespace ConsoleApp2
{
public class LogExporter : BaseExporter<Activity>
{
private readonly Action<Activity> _onActivity;
private readonly IActivityWriter _writer;
private readonly Channel<Activity> _channel = Channel.CreateBounded<Activity>(new BoundedChannelOptions(128) { SingleReader = true, FullMode = BoundedChannelFullMode.Wait });
private readonly TaskCompletionSource _taskCompletionSource = new TaskCompletionSource();
private readonly CancellationTokenSource _cancellationTokenSource = new CancellationTokenSource();
public override ExportResult Export(in Batch<Activity> batch)
{
bool success = true;
foreach (Activity activity in batch)
{
_onActivity?.Invoke(activity);
if (!_channel.Writer.TryWrite(activity))
success &= false;
}
return success ? ExportResult.Success : ExportResult.Failure;
}
public LogExporter(LogExporterOptions options)
{
_writer = options.Writer ?? throw new ArgumentNullException(nameof(options.Writer));
_onActivity = options.OnActivity;
_ = Run(_cancellationTokenSource.Token);
}
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();
}
}
protected override void Dispose(bool disposing)
{
_channel.Writer.TryComplete();
_channel.Reader.Completion.GetAwaiter().GetResult();
_taskCompletionSource.Task.GetAwaiter().GetResult();
}
protected override bool OnShutdown(int timeoutMilliseconds)
{
_channel.Writer.TryComplete();
_cancellationTokenSource.Cancel();
_channel.Reader.Completion.GetAwaiter().GetResult();
_taskCompletionSource.Task.GetAwaiter().GetResult();
return true;
}
}
}
using System;
using System.Diagnostics;
namespace ConsoleApp2
{
public class LogExporterOptions
{
public IActivityWriter Writer { get; set; }
public Action<Activity> OnActivity { get; set; }
}
}
using System;
using Microsoft.Extensions.Logging;
using OpenTelemetry;
using OpenTelemetry.Trace;
namespace ConsoleApp2
{
public static class OpenTelemetryExtensions
{
public static TracerProviderBuilder AddLogExporter(this TracerProviderBuilder builder, ILoggerFactory loggerFactory, Action<LogExporterOptions> configure = null)
{
_ = builder ?? throw new ArgumentNullException(nameof(builder));
var options = new LogExporterOptions()
{
Writer = new ActivityLogWriter(loggerFactory.CreateLogger<ActivityLogWriter>())
};
configure?.Invoke(options);
LogExporter exporter = new LogExporter(options);
return builder.AddProcessor(new SimpleActivityExportProcessor(exporter));
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment