serilog-sinks-email icon indicating copy to clipboard operation
serilog-sinks-email copied to clipboard

Not possible to set Subject or Body using JSON configuration when using overload that accepts EmailSinkOptions and PeriodicBatchingSinkOptions

Open MrPsi opened this issue 1 year ago • 3 comments

It does not seem to be possible to set subject or body when using the overload that accepts EmailSinkOptions and PeriodicBatchingSinkOptions when using JSON configuration.

Program.cs

using Microsoft.Extensions.Configuration;
using Serilog;

var configuration = new ConfigurationBuilder()
    .AddJsonFile("appsettings.json")
    .Build();

Log.Logger = new LoggerConfiguration()
    .ReadFrom.Configuration(configuration)
    .CreateLogger();

var logger = Log.ForContext<TestContext>();
logger.Information("Log 1");
logger.Information("Log 2");
logger.Error(new Exception("the exception"), "Log 3");
await Log.CloseAndFlushAsync();

public class TestContext;

appsettings.json

{
  "Serilog": {
    "MinimumLevel": {
      "Default": "Information"
    },
    "WriteTo": [
      {
        "Name": "Email",
        "Args": {
          "options": {
            "subject": "Serilog test",
            "from": "[email protected]",
            "to": [ "[email protected]" ],
            "host": "localhost",
            "body": "[{Timestamp:HH:mm:ss} {Level}] {SourceContext}{NewLine}{Message}{NewLine}{Exception}{NewLine}"
          },
          "batchingOptions": {
            "batchSizeLimit": 10,
            "period": "00:00:01"
          },
          "restrictedToMinimumLevel": "Information"
        }
      }
    ]
  }
}

The default subject and body will be used instead of the one specified in the JSON. This is probably because Subject and Body in type EmailSinkOptions is of type ITextFormatter, and not string.

MrPsi avatar Apr 04 '24 08:04 MrPsi

After some more testing I found the following.

To specify the type like below does not work either.

{
  "Serilog": {
    "MinimumLevel": {
      "Default": "Information"
    },
    "WriteTo": [
      {
        "Name": "Email",
        "Args": {
          "options": {
            "subject": {
              "type": "Serilog.Formatting.Display.MessageTemplateTextFormatter, Serilog",
              "outputTemplate": "Serilog test"
            },
            "from": "[email protected]",
            "to": [ "[email protected]" ],
            "host": "localhost",
            "body": {
              "type": "Serilog.Formatting.Display.MessageTemplateTextFormatter, Serilog",
              "outputTemplate": "[{Timestamp:HH:mm:ss} {Level}] {SourceContext}{NewLine}{Message}{NewLine}{Exception}{NewLine}"
            }
          },
          "batchingOptions": {
            "batchSizeLimit": 10,
            "period": "00:00:01"
          },
          "restrictedToMinimumLevel": "Information"
        }
      }
    ]
  }
}

But if I add a constructor to EmailSinkOptions like below, the above configuration will work. ("to" need to be changed to string instead of list of strings)

    public EmailSinkOptions(
        string from,
        string to,
        string host,
        int port = DefaultPort,
        SecureSocketOptions connectionSecurity = DefaultConnectionSecurity,
        ICredentialsByHost? credentials = null,
        ITextFormatter? subject = null,
        ITextFormatter? body = null)
    {
        From = from;
        To = LoggerConfigurationEmailExtensions.SplitToAddresses(to);
        Host = host;
        Port = port;
        ConnectionSecurity = connectionSecurity;
        Credentials = credentials;
        Subject = subject ?? Subject;
        Body = body ?? Body;
    }

MrPsi avatar Apr 04 '24 12:04 MrPsi

Maybe it is better to add the following constructor to allow to just write a string as subject and body?

    public EmailSinkOptions(
        string from,
        string to,
        string host,
        int port = DefaultPort,
        SecureSocketOptions connectionSecurity = DefaultConnectionSecurity,
        ICredentialsByHost? credentials = null,
        string? subject = null,
        string? body = null)
    {
        if (from == null) throw new ArgumentNullException(nameof(from));
        if (to == null) throw new ArgumentNullException(nameof(to));
        if (host == null) throw new ArgumentNullException(nameof(host));

        From = from;
        To = LoggerConfigurationEmailExtensions.SplitToAddresses(to);
        Host = host;
        Port = port;
        ConnectionSecurity = connectionSecurity;
        Credentials = credentials;

        if (subject != null)
        {
            Subject = new MessageTemplateTextFormatter(subject);
        }

        if (body != null)
        {
            Body = new MessageTemplateTextFormatter(body);
        }
    }

Then the JSON can look like this:

{
  "Serilog": {
    "MinimumLevel": {
      "Default": "Information"
    },
    "WriteTo": [
      {
        "Name": "Email",
        "Args": {
          "options": {
            "subject": "Serilog test",
            "from": "[email protected]",
            "to": "[email protected]",
            "host": "localhost",
            "body": "[{Timestamp:HH:mm:ss} {Level}] {SourceContext}{NewLine}{Message}{NewLine}{Exception}{NewLine}"
          },
          "batchingOptions": {
            "batchSizeLimit": 10,
            "period": "00:00:01"
          },
          "restrictedToMinimumLevel": "Information"
        }
      }
    ]
  }
}

MrPsi avatar Apr 04 '24 13:04 MrPsi

Created pull request https://github.com/serilog/serilog-sinks-email/pull/131

MrPsi avatar Apr 04 '24 13:04 MrPsi

As of the latest release of Serilog.Settings.Configuration (8.0.3) the below will work.

{
  "Serilog": {
    "MinimumLevel": {
      "Default": "Information"
    },
    "WriteTo": [
      {
        "Name": "Email",
        "Args": {
          "options": {
            "subject": {
              "type": "Serilog.Formatting.Display.MessageTemplateTextFormatter, Serilog",
              "outputTemplate": "Serilog test"
            },
            "from": "[email protected]",
            "to": [ "[email protected]" ],
            "host": "localhost",
            "body": {
              "type": "Serilog.Formatting.Display.MessageTemplateTextFormatter, Serilog",
              "outputTemplate": "[{Timestamp:HH:mm:ss} {Level}] {SourceContext}{NewLine}{Message}{NewLine}{Exception}{NewLine}"
            }
          },
          "batchingOptions": {
            "batchSizeLimit": 10,
            "period": "00:00:01"
          },
          "restrictedToMinimumLevel": "Information"
        }
      }
    ]
  }
}

MrPsi avatar Oct 08 '24 09:10 MrPsi