Wolfringo Wolfringo
Wolfringo Wolfringo
Wolfringo (c) 2020 TehGM
DocFX, DiscordFX theme.
Search Results for

    Logging in Wolfringo

    A bot is a background process - most often it'll be running in background, without user interaction. For that reason, it's important to log information.

    Wolfringo on its own doesn't have a logger. It also doesn't have "Log" event or anything like that - these events often are error-prone, and require additional work when setting up.
    Instead Wolfringo has full support for @Microsoft.Extensions.Logging.ILogger interface. This makes it fully compatible with any relevant .NET logging library - Serilog, NLog, Log4Net, you name it! (Well, as long as it works with Microsoft.Extensions.Logging.ILogger).

    Setting logging up

    The exact way to set up logging might vary between libraries. Here I show a few examples.

    • Without Wolfringo.Hosting (Normal Bot)
    • With Wolfringo.Hosting (.NET Generic Host/ASP.NET Core)

    All examples will use a special method called "CreateLogger" in Program.cs. It'll be called before creating IWolfClient and ICommandsService. We'll also add it to service provider. You can also register other services - check Dependency Injection guide for more info.

    You should install Microsoft.Extensions.Logging NuGet package and then alter Program.cs as follows:

    using Microsoft.Extensions.Logging;
    
    private static async Task MainAsync(string[] args)
    {
        // ... other code ...
    
        _client = new WolfClientBuilder()
            .WithLogging(CreateLoggerFactory())     // pass a new logger factory
            .WithCommands()                         // enable commands - they'll automatically use the same factory! 
            .Build();
    
        // ... other code ...
    }
    
    private static ILoggerFactory CreateLoggerFactory()
    {
        // creating a logger factory depends on the library - see below!
    }
    
    Note

    You can find example on GitHub.

    Serilog

    Serilog is one of the most popular (if not the most popular) logging libraries for .NET. It is my personal choice in my projects, so let's start with it!

    First, using your NuGet package manager, install Serilog, Serilog.Extensions.Logging, and any of the sinks you want to use. For the sake of example, I will use Serilog.Sinks.File and Serilog.Sinks.Console.

    Once downloaded, add following using directives to your Program.cs:

    using Serilog;
    

    Finally, populate your CreateLoggerFactory method:

    private static ILoggerFactory CreateLoggerFactory()
    {
        Log.Logger = new LoggerConfiguration()  // initialize Serilog configuration
            .MinimumLevel.Information()         // set minimum logs level to Information - feel free to change it to whatever suits your needs
            .Enrich.FromLogContext()            // add log context to logs - optional, but Wolfringo makes use of it!
            .WriteTo.Console()                  // enable logging to console
            .WriteTo.File("logs.txt")           // enable logging to "logs.txt" files
            .CreateLogger();                    // create logger instance
    
        return new LoggerFactory()              // create factory for Microsoft.Extensions.Logging.ILogger
            .AddSerilog(Log.Logger);            // add our Serilog logger
    }
    

    Check Serilog repo on GitHub for more guides how to configure Serilog.

    Note: remember to add logger instance to IWolfClient and ICommandsService via constructor - if you only set Log.Logger, Wolfringo will not be able to log anything!

    Microsoft.Extensions.Logging

    Microsoft extensions logging also has some providers. These tend to be quite basic, and using logging libraries such as Serilog, NLog or Log4Net is recommended - but it is enough to get most basic logs!

    First, using your NuGet package manager, install Microsoft.Extensions.Logging.Console 2.0.0.

    Once downloaded, populate your CreateLoggerFactory method:

    private static ILoggerFactory CreateLoggerFactory()
    {
        return new LoggerFactory(                                       // create Microsoft.Extensions.Logging.ILogger factory
            new[] { new ConsoleLoggerProvider((_, level)                // enable logging to console
              => level != LogLevel.Trace && level != LogLevel.Debug,    // disable any logs below Information - feel free to change it to whatever suits yourneeds
            true) }                                                     // do include log scopes
        );
    }
    
    Warning

    Note that this ConsoleLoggerProvider constructor is removed since version 3.0.0 of Microsoft.Extensions.Logging.Console. The new versions require use of @Microsoft.Extensions.Options.IOptionsMonitor`1.
    If you don't want to hack your way around it, you can either switch to versions 2.0.0-2.2.0 of Microsoft.Extensions.Logging.Console, or use a different logging library.

    Other libraries

    Many other libraries support Microsoft.Extensions.Logging. Some might support it out of the box, while some might have a wrapper package available (like Serilog). Check out their documentations to see how to use them!

    Tip

    If you're searching on @Microsoft.Extensions.Logging.ILogger support for your library, you can use a phrase like "ASP.NET Core" - it includes native support for Microsoft.Extensions.Logging, so many articles focus on this use-case.

    Logging is built into .NET Generic Host/ASP.NET Core, so setting it up is really easy - just set it as you normally would in ASP.NET Core application!

    Wolfringo.Hosting's wrappers for Wolfringo services (HostedWolfClient and HostedCommandsService) will automatically use logging if it's configured in your host.

    Note: In addition to steps I include as examples below, I recommend checking Logging in .NET Core and ASP.NET Core for more details!

    Serilog

    Serilog is one of the most popular (if not the most popular) logging libraries for .NET. It is my personal choice in my projects, so let's start with it!

    Serilog has 2 recommended utility packages for hosted scenarios:

    • Serilog.AspNetCore when using ASP.NET Core
    • Serilog.Extensions.Hosting when using Generic Host without ASP.NET Core

    You will need to install the suitable utility package. To use configuration, we'll also use Serilog.Settings.Configuration. In addition, you'll want to install some sinks - for the sake of example, I will use Serilog.Sinks.File and Serilog.Sinks.Console.

    2nd step is to enable logging in your Program.cs, where you configure your host:

    // ...
    IHost host = Host.CreateDefaultBuilder(args)
        // ... other ConfigureSomething methods - such as ConfigureServices, etc
        .UseSerilog((context, config) =>
        {
            config.ReadFrom.Configuration(context.Configuration);   // read configuration from appsettings.json
        }, true)
        .Build();
    

    Lastly, you need to configure your appsettings.json to include logging configuration. Remove "Logging" section, and add a new "Serilog" section. Make sure to include every sink you're using in "Using" array, and configure each in "WriteTo" array:

    "Serilog": {
      "Using": [ "Serilog.Sinks.Console", "Serilog.Sinks.File" ],
      "MinimumLevel": {
        "Default": "Information",
        "Override": {
          "Microsoft": "Warning",
          "Microsoft.Hosting.Lifetime": "Information",
          "System.Net.Http.HttpClient": "Warning"
        }
      },
      "Enrich": [
        "FromLogContext"
      ],
      "WriteTo": [
        {
          "Name": "Console"
        },
        {
          "Name": "File",
          "Args": {
            "path": "logs.txt"
          }
        }
      ]
    }
    

    See Serilog.Settings.Configuration repo on GitHub for more information on how to use configuration with Serilog.
    Check Serilog.AspNetCore and Serilog.Extensions.Hosting GitHub repositories as well, for more information on how to use these packages!

    Microsoft.Extensions.Logging

    Microsoft extensions logging also has some providers. These tend to be quite basic, and using logging libraries such as Serilog, NLog or Log4Net is recommended - but it is enough to get most basic logs!

    Console logger for this approach is already built into Hosting, so you don't need to install any packages. Simply add a new using directive to Program.cs:

    using Microsoft.Extensions.Logging;
    

    Now, just add your configuration. In Hosted approach, logging is configured in Program.cs, where you configure your host:

    // ...
    IHost host = Host.CreateDefaultBuilder(args)
        // ... other ConfigureSomething methods - such as ConfigureServices, etc
        .ConfigureLogging((context, config) =>
        {
            config.SetMinimumLevel(LogLevel.Information);   // set minimum logs level to Information - feel free to change it to whatever suits your needs
        })
        .Build();
    

    Other libraries

    Many other libraries support Microsoft.Extensions.Logging. Some might support it out of the box, while some might have a wrapper package available (like Serilog). Check out their documentations to see how to use them!

    Tip

    If you're searching on @Microsoft.Extensions.Logging.ILogger support for your library, you can use a phrase like "ASP.NET Core" - it includes native support for Microsoft.Extensions.Logging, so many articles focus on this use-case.

    Logging in Handlers and Services

    Any service registered with Dependency Injection and all Handlers that CommandsService loads can use @Microsoft.Extensions.Logging.ILogger - simply inject it via constructor or method parameters. Check Dependency Injection guide for more details.
    You can inject either @Microsoft.Extensions.Logging.ILogger or @Microsoft.Extensions.Logging.ILogger`1 - if you use the generic one, the logs will use that type's full name as a category.

    [CommandsHandler]
    private class ExampleCommandsHandler
    {
        private readonly ILogger _log;
    
        public ExampleCommandsHandler(ILogger<ExampleCommandsHandler> log)
        {
            this._log = log;
        }
    
        [Command("example")]
        public async Task ExampleAsync(CommandContext context, ILogger log)
        {
            log.LogInformation("Received a message from {SenderID}", context.Message.SenderID.Value);
            // can also use _log instead of log
        }
    }