cocowalla / serilog-sinks-file-archive

Plugin for the Serilog File sink that works with rolling log files, archiving completed log files before they are deleted by Serilog's retention mechanism
Apache License 2.0
31 stars 7 forks source link

Complex Parameter binding with Serilog.Settings.Configuration #12

Closed MenWhoRust closed 1 year ago

MenWhoRust commented 1 year ago

Good day,

A small query concerning using an appSettings.json file to configure your plugin.

I'm having a tough time using Complex Parameter Binding to configure the plugin.

{
        "Name": "File",
        "Args": {
          "path": "D:/Logs/log.json",
          "rollingInterval": "Day",
          "rollOnFileSizeLimit": true,
          "fileSizeLimitBytes": 20971520,
          "retainedFileCountLimit": 31,
          "buffer": true,
          "hooks": {
            "type": "Serilog.Sinks.File.Archive.ArchiveHooks, Serilog.Sinks.File.Archive",
            "compressionLevel": "System.IO.Compression.CompressionLevel::Fastest, System.IO.Compression",
            "targetDirectory": "D:/Logs/Archive"
          },
          "formatter": "Serilog.Formatting.Compact.CompactJsonFormatter, Serilog.Formatting.Compact"
        }
      }

Using the above configuration results in the following exception: Cannot create instance of type 'Serilog.Sinks.File.FileLifecycleHooks' because it is either abstract or an interface.

Please let me know if your plugin does not support this kind of configuration or if I'm am configuring it incorrectly

nblumhardt commented 1 year ago

Which Serilog.Settings.Configuration package version are you using?

MenWhoRust commented 1 year ago

I am using 3.4.0

And sorry for accidentally closing the issue, been a long morning 😅

cocowalla commented 1 year ago

Hmm, I've never tried to use it like that, instead using this pattern: https://github.com/cocowalla/serilog-sinks-file-archive#json-appsettingsjson-configuration.

I don't think this is really an issue with this plugin, but more with serilog/serilog-settings-configuration - I'm afraid I don't think Serilog.Settings.Configuration supports what you are trying to do.

See here: https://github.com/serilog/serilog-settings-configuration#abstract-parameter-types. It looks like it can only create instances of abstract types when the implementation has a parameterless constructor.

cocowalla commented 1 year ago

Ah, I've found a workaround for you 😄

Basically, you create your own extension method to configure the file sink. First, add a new class, SerilogExtensions, to your project:

using System;
using System.IO.Compression;
using System.Text;
using Microsoft.Extensions.Configuration;
using Serilog.Configuration;
using Serilog.Core;
using Serilog.Events;
using Serilog.Sinks.File.Archive;

namespace Serilog;

public static class SerilogExtensions
{
    const int DefaultRetainedFileCountLimit = 31; // A long month of logs
    const long DefaultFileSizeLimitBytes = 1L * 1024 * 1024 * 1024; // 1GB
    const string DefaultOutputTemplate = "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level:u3}] {Message:lj}{NewLine}{Exception}";

    public static LoggerConfiguration File(
        this LoggerSinkConfiguration sinkConfiguration,
        string path,
        LogEventLevel restrictedToMinimumLevel = LevelAlias.Minimum,
        string outputTemplate = DefaultOutputTemplate,
        IFormatProvider? formatProvider = null,
        long? fileSizeLimitBytes = DefaultFileSizeLimitBytes,
        LoggingLevelSwitch? levelSwitch = null,
        bool buffered = false,
        bool shared = false,
        TimeSpan? flushToDiskInterval = null,
        RollingInterval rollingInterval = RollingInterval.Infinite,
        bool rollOnFileSizeLimit = false,
        int? retainedFileCountLimit = DefaultRetainedFileCountLimit,
        Encoding? encoding = null,
        CompressionLevel archiveCompressionLevel = CompressionLevel.Optimal,
        string archiveTargetDirectory = null,
        IConfiguration? configuration = null,
        TimeSpan? retainedFileTimeLimit = null)
    {
        ArchiveHooks archiveHooks = new ArchiveHooks(archiveCompressionLevel, archiveTargetDirectory);

        return FileLoggerConfigurationExtensions.File(
            sinkConfiguration,
            path,
            restrictedToMinimumLevel,
            outputTemplate,
            formatProvider,
            fileSizeLimitBytes,
            levelSwitch,
            buffered,
            shared,
            flushToDiskInterval,
            rollingInterval,
            rollOnFileSizeLimit,
            retainedFileCountLimit,
            encoding,
            archiveHooks);
    }
}

Finally, update your JSON config to (change paths as needed):

{
  "Serilog": {
    "MinimumLevel": {
      "Default": "Debug"
    },
    "WriteTo": [
      {
        "Name": "File",
        "Args": {
          "path": ".\\Logs\\sample.log",
          "rollingInterval": "Day",
          "rollOnFileSizeLimit": true,
          "fileSizeLimitBytes": 20971520,
          "retainedFileCountLimit": 31,
          "buffer": true,
          "formatter": "Serilog.Formatting.Compact.CompactJsonFormatter, Serilog.Formatting.Compact",
          "archiveCompressionLevel": "Fastest",
          "archiveTargetDirectory": ".\\Logs\\Archive"
        }
      }
    ],
    "Enrich": [ "FromLogContext" ]
  }
}

I've tested this, and it works as expected 😃

MenWhoRust commented 1 year ago

Thank you so much, that worked perfectly.

Really appreciate the assistance😁