Skip to content

Collision with Microsoft.Extensions.Telemetry #250

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
bdovaz opened this issue May 19, 2024 · 2 comments
Open

Collision with Microsoft.Extensions.Telemetry #250

bdovaz opened this issue May 19, 2024 · 2 comments

Comments

@bdovaz
Copy link

bdovaz commented May 19, 2024

https://www.nuget.org/packages/Microsoft.Extensions.Telemetry/

This library provides advanced logging and telemetry enrichment capabilities for .NET applications. It allows for detailed and configurable enrichment of log entries, along with enhanced latency monitoring and logging features. It is built for applications needing sophisticated telemetry and logging insights.

This package replaces the ILoggerFactory implementation and causes it to collide with the ILoggerFactory implementation of this repository:

https://github.com/dotnet/extensions/blob/5752f1d4ac15686432a228099386c709c7dacf74/src/Libraries/Microsoft.Extensions.Telemetry/Logging/LoggingEnrichmentExtensions.cs#L37

I would like to be able to use the Telemetry package at the same time as this Serilog package.

The use of Serilog in my case is because of the need to use certain Sinks (example: OpenSearch), that is why I would like to use all the possible functionalities of Microsoft.Extensions.Logging and Microsoft.Extensions.Telemetry without coupling to Serilog more than necessary.

@nblumhardt
Copy link
Member

Hi @bdovaz,

If you just want to use Serilog as a sink, then adding it via your ILoggingBuilder rather than at the host level will do what you need:

builder.Logging.AddSerilog(..)

The downside is that you will now have two logging frameworks in play, with their own filters, minimum levels, etc., but you should be able to work around that reasonably easily.

Hope this helps,
Nick

@vipentti
Copy link

Hi @bdovaz

Not sure if this is still relevant to you but we were able to at least make some progress using ILoggerFactory from Microsoft.Extensions.Telemetry package but using Serilog sinks.

The workaround which has not been thoroughly tested yet but seems to yield promising results but which requires a bit of boilerplate.

Create a custom logger provider:

/// <summary>
/// Custom <see cref="ILoggerProvider"/> which lazily configures <see cref="SerilogLoggerProvider"/> using the provided <paramref name="configureLogger"/>
/// </summary>
/// <param name="serviceProvider">The built service provider</param>
/// <param name="configureLogger">Configuration action to configure the <see cref="LoggerConfiguration"/></param>
/// <param name="setupAsGlobalSerilogLogger">Whether or not to set the created <see cref="Serilog.ILogger"/> as value for global <see cref="Log.Logger"/></param>
public sealed class CustomSerilogLoggerProvider(
    IServiceProvider serviceProvider,
    Action<IServiceProvider, LoggerConfiguration> configureLogger,
    bool setupAsGlobalSerilogLogger
    ) : ILoggerProvider
{
    private SerilogLoggerProvider? _provider;
    private SerilogLoggerProvider Provider => _provider ??= CreateProvider();

    private Serilog.Core.Logger? _logger;
    internal Serilog.Core.Logger SerilogLogger => _logger ??= CreateLogger();

    public Microsoft.Extensions.Logging.ILogger CreateLogger(string categoryName) =>
        Provider.CreateLogger(categoryName);

    private SerilogLoggerProvider CreateProvider() => new(
        SerilogLogger,
        dispose: !setupAsGlobalSerilogLogger
    );

    private Serilog.Core.Logger CreateLogger()
    {
        var logger = CreateConfiguration().CreateLogger();

        if (setupAsGlobalSerilogLogger)
        {
            Log.Logger = logger;
        }

        return logger;
    }

    private LoggerConfiguration CreateConfiguration()
    {
        var configuration = new LoggerConfiguration();
        configureLogger(serviceProvider, configuration);
        return configuration;
    }

    public void Dispose()
    {
        _provider?.Dispose();
    }
}

Create custom extension for ILoggingBuilder to setup the custom provider:

public static class CustomLoggingBuilderExtensions
{
    public static ILoggingBuilder AddCustomSerilog(
        this ILoggingBuilder builder,
        Action<IServiceProvider, LoggerConfiguration> configureLogger,
        bool setupAsGlobalSerilogLogger = false)
    {
        builder.Services.AddSingleton(container => new CustomSerilogLoggerProvider(
            container,
            configureLogger,
            setupAsGlobalSerilogLogger
        ));

        builder.Services.AddSingleton<ILoggerProvider>(container => container.GetRequiredService<CustomSerilogLoggerProvider>());

        builder.Services.AddSingleton<Serilog.ILogger>(container =>
            container.GetRequiredService<CustomSerilogLoggerProvider>().SerilogLogger
        );

        builder.AddFilter<CustomSerilogLoggerProvider>(null, LogLevel.Trace);

        // If using SerilogRequestLogging
        // Based on
        // https://github.com/serilog/serilog-extensions-hosting/blob/87e316f7d31ae431747d1106976dfceffdecc32c/src/Serilog.Extensions.Hosting/SerilogServiceCollectionExtensions.cs#L218
        builder.Services.AddSingleton(provider => new DiagnosticContext(provider.GetService<Serilog.ILogger>()));
        builder.Services.AddSingleton<IDiagnosticContext>(provider => provider.GetRequiredService<DiagnosticContext>());

        return builder;
    }
}

And then utilize that

builder.Services.AddLogging(logging =>
{
   // ... other logging setup ...
   logging.AddCustomSerilog((provider, config) => 
   {
       // configure LoggerConfiguration    
   });
});

Using this at least allowed us to utilize Microsoft.Extensions.Compliance.Redaction with some [LoggerMessage] generated log messages successfully, without these adjustments, redacted data would be completely missing from the logs because the "ExtendedLogger" seems to be the only one able to handle these. (https://github.com/dotnet/extensions/blob/c08790cf79d2d8feaa53751f039f38638741a154/src/Libraries/Microsoft.Extensions.Telemetry/Logging/ExtendedLogger.cs)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants