如何在没有 DI 的类库中使用 ILogger<Class>

Posted

技术标签:

【中文标题】如何在没有 DI 的类库中使用 ILogger<Class>【英文标题】:How to use ILogger<Class> in a Class Library without DI 【发布时间】:2022-01-09 15:33:20 【问题描述】:

我有一个类库和一个使用 Serilog 的测试集成示例应用程序。如何将记录器添加到类库中?我更喜欢Microsoft.Extensions.Logging,但我找不到不依赖注入的方法。

示例

using System.Reactive.Disposables;
using Ardalis.GuardClauses;
using Binance.WebSocket.Client.Extensions;
using Binance.WebSocket.Client.Subscriptions;
using Serilog;
using Serilog.Events;
using Serilog.Sinks.SystemConsole.Themes;

namespace Binance.WebSocket.Client.Sample;

public class Program

    private static readonly ManualResetEvent ExitEvent = new(false);

    private static async Task Main()
    
        Log.Logger = new LoggerConfiguration()
            .MinimumLevel.Verbose()
            .Enrich.FromLogContext()
            .WriteTo.Console(LogEventLevel.Debug, theme: SystemConsoleTheme.Colored)
            .WriteTo.File(Path.Combine("logs", "verbose.log"), rollingInterval: RollingInterval.Day)
            .CreateLogger();

        var disposable = new CompositeDisposable();
        var uri = new Uri("wss://stream.binance.com:9443");

        using var communicator = new BinanceWebSocketCommunicator(uri);

        communicator.Name = "Binance-Spot";
        communicator.ReconnectTimeout = TimeSpan.FromMinutes(10);

        communicator.ReconnectionHappened
            .Subscribe(info => Log.Information($"Reconnection happened, type: info.Type"))
            .DisposeWith(disposable);

        communicator.DisconnectionHappened
            .Subscribe(info => Log.Information($"Disconnection happened, type: info.Type"))
            .DisposeWith(disposable);

        using var client = new BinanceWebSocketClient(communicator);

        client.Streams.PongStream
            .Subscribe(x => Log.Information($"Pong received (x.Message)"))
            .DisposeWith(disposable);

        client.Streams.AggregateTradesStream
            .Subscribe(response =>
            
                Guard.Against.Null(response, nameof(response));
                Guard.Against.Null(response.Data, nameof(response.Data),
                    "Something went wrong and the aggregated trade object is null");

                var trade = response.Data;
                Log.Information($"Aggregated trade [trade.Symbol] [trade.Side] " +
                                $"Price: trade.Price Size: trade.Quantity");
            )
            .DisposeWith(disposable);

        client.Streams.KlineStream
            .Subscribe(response =>
            
                Guard.Against.Null(response, nameof(response));
                Guard.Against.Null(response.Data, nameof(response.Data),
                    "Something went wrong and the kline object is null");
                Guard.Against.Null(response.Data.Data, nameof(response.Data.Data),
                    "Something went wrong and the kline data object is null");

                var kline = response.Data;
                var klineData = response.Data.Data;

                Log.Information($"Kline [kline.Symbol] " +
                                $"Kline start time: klineData.StartTime " +
                                $"Kline close time: klineData.CloseTime " +
                                $"Interval: klineData.Interval " +
                                $"First trade ID: klineData.FirstTradeId " +
                                $"Last trade ID: klineData.LastTradeId " +
                                $"Open price: klineData.OpenPrice " +
                                $"Close price: klineData.ClosePrice " +
                                $"High price: klineData.HighPrice " +
                                $"Low price: klineData.LowPrice " +
                                $"Base asset volume: klineData.BaseAssetVolume " +
                                $"Number of trades: klineData.NumberTrades " +
                                $"Is this kline closed?: klineData.IsClosed " +
                                $"Quote asset volume: klineData.QuoteAssetVolume " +
                                $"Taker buy base: klineData.TakerBuyBaseAssetVolume " +
                                $"Taker buy quote: klineData.TakerBuyQuoteAssetVolume " +
                                $"Ignore: klineData.Ignore ");
            )
            .DisposeWith(disposable);

        client.AddSubscription(
            new AggregateTradeSubscription("bnbusdt"),
            new KlineSubscription("btcusdt", "1h"));

        await communicator.Start().ConfigureAwait(false);

        ExitEvent.WaitOne();
 
        disposable.Dispose();

        Log.CloseAndFlush();
    

【问题讨论】:

您显示的代码不是库代码。我真的不明白该代码与登录库的问题有何关系。 【参考方案1】:

你可以像下面这样使用 LoggerFactory

using var loggerFactory = LoggerFactory.Create(builder =>

    builder
        .AddFilter("Microsoft", LogLevel.Warning)
        .AddFilter("System", LogLevel.Warning)
        .AddFilter("LoggingConsoleApp.Program", LogLevel.Debug)
        .AddConsole()
        .AddEventLog();
);

ILogger logger = loggerFactory.CreateLogger<Program>();
logger.LogInformation("Example log message");

参考: https://docs.microsoft.com/en-us/aspnet/core/fundamentals/logging/?view=aspnetcore-5.0#non-host-console-app

【讨论】:

感谢您的回答!我如何使用SerilogLoggerFactory tho? 引用nuget.org/packages/Serilog.Extensions.Logging后可以使用Serilog库.AddSerilog(serilog);提供的扩展方法 谢谢!它起作用了,但是现在我必须想办法将它传递给类库,就像这里的人所做的那样github.com/JKorf/CryptoExchange.Net/blob/…

以上是关于如何在没有 DI 的类库中使用 ILogger<Class>的主要内容,如果未能解决你的问题,请参考以下文章

如何从不同appdomain的类库中调用实例方法?

在C#的类库中可以创建WPF的窗口吗

将域的 BALL 包装到它自己的类库中是不是合理,我将如何设置它?

我需要弄清楚如何将我的类库中的枚举绑定到我的应用程序中的单选按钮

#if DEBUG 指令在编译的类库中

类库中的 HtmlEncode