Skip to content

Instantly share code, notes, and snippets.

@shirhatti
Last active April 29, 2024 05:30
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save shirhatti/56c24a36d2c105493dab6e3527e62456 to your computer and use it in GitHub Desktop.
Save shirhatti/56c24a36d2c105493dab6e3527e62456 to your computer and use it in GitHub Desktop.
Consume ILogger logs through EventListener
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net5.0</TargetFramework>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Logging.EventSource" Version="5.0.0-preview.4.20251.6" />
</ItemGroup>
</Project>
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.EventSource;
using System;
using System.Collections.Generic;
using System.Diagnostics.Tracing;
using System.Runtime.CompilerServices;
using System.Threading;
using System.Threading.Channels;
using System.Threading.Tasks;
namespace ConsoleApp4
{
public class Program
{
static async Task Main(string[] args)
{
var loggerFactory = LoggerFactory.Create(builder =>
{
builder.AddEventSourceLogger();
});
var logger = loggerFactory.CreateLogger<Program>();
using var cts = new CancellationTokenSource();
var token = cts.Token;
using var listener = new Listener();
var listenerTask = Task.Run(async () =>
{
await foreach (var message in listener.FetchLogs(token))
{
Console.WriteLine(message);
}
}, token);
// A few sample logs messages
logger.LogInformation("Value is {val}", 0);
logger.LogInformation("Value is {val}", 0);
logger.LogInformation("Value is {val}", 0);
logger.LogInformation("Value is {val}", 0);
listener?.Dispose();
await listenerTask;
}
internal class Listener : EventListener
{
private bool _initialized = false;
private EventSource? _loggingEventSource;
private static readonly string LoggingEventSourceName = "Microsoft-Extensions-Logging";
private const int _maxQueuedMessages = 10;
private readonly Channel<string> _channel = Channel.CreateBounded<string>(_maxQueuedMessages);
public Listener()
{
Enable();
_initialized = true;
}
private void Enable()
{
if (_loggingEventSource != null)
{
EnableEvents(_loggingEventSource, EventLevel.LogAlways, LoggingEventSource.Keywords.JsonMessage);
}
}
protected override void OnEventSourceCreated(EventSource eventSource)
{
if (eventSource.Name == LoggingEventSourceName)
{
_loggingEventSource = eventSource;
if (_initialized)
{
Enable();
}
}
}
protected override void OnEventWritten(EventWrittenEventArgs eventData)
{
if (!_initialized)
{
return;
}
if ((eventData.Payload?.Count) != 7)
{
return;
}
if (eventData.Payload?[6] is string exceptionPayload)
{
_ = _channel.Writer.TryWrite(exceptionPayload);
}
}
public async IAsyncEnumerable<string> FetchLogs([EnumeratorCancellation] CancellationToken token = default)
{
while (await _channel.Reader.WaitToReadAsync(token))
{
var logMessage = await _channel.Reader.ReadAsync(token);
yield return logMessage;
}
}
public override void Dispose()
{
_channel.Writer.TryComplete();
base.Dispose();
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment