15

I want to configure Serilog to create one log file per app run.
File name should be based on current date/time:
1st run: log_20180413_1020.txt
2nd run: log_20180413_1033.txt

I didn't find how to do it in any File sink (Rolling, Alternative..)
Any clue?

IgorStack
  • 799
  • 2
  • 6
  • 22
  • I posted answer to similar question... [https://stackoverflow.com/a/54537396/4331722](https://stackoverflow.com/a/54537396/4331722) – Stefan Varga Feb 05 '19 at 15:13

3 Answers3

24

Configure the Serilog.Sinks.File sink without any rolling period or size limit, and add the timestamp to the log filename when you configure logging at startup:

string timestamp = DateTime.Now.ToString("yyyyMMdd_HHmm");
var log = new LoggerConfiguration()
    .WriteTo.File($"log{timestamp}.txt")
    .CreateLogger();

Per the Rolling Policies section of the README:

Specifying both rollingInterval and rollOnFileSizeLimit will cause both policies to be applied, while specifying neither will result in all events being written to a single file.

McGuireV10
  • 9,572
  • 5
  • 48
  • 64
  • 7
    How can this be achieved from appsetting.json? instead of code. – user1066231 Jun 23 '20 at 07:55
  • 1
    Also, I'd prefer to have `rollingInterval` and `rollOnFileSizeLimit` to be turned on in addition to roll per run too.. – tsul Sep 02 '20 at 18:20
  • See the [configuration package](https://github.com/serilog/serilog-settings-configuration), it's extremely flexible, it can apply arbitrary settings through some fairly advanced reflection. – McGuireV10 Sep 02 '20 at 22:03
  • This still logs to the same file if the application is run twice in the same minute. – Benjamin4991 Jun 27 '22 at 13:52
  • @Benjamin4991 ... true, but trivial to add `ss` to the timestamp if that's a use-case of concern. – McGuireV10 Jun 27 '22 at 18:38
  • @McGuireV10 I tried this and did not work. "specifying neither will result in all events being written to a single file."...I think that means it will write all logs to a single file (which is what I am seeing) not a single log file per app run. – seanrco Jul 10 '22 at 01:51
0

In case someone is still trying to find out how to achieve this from appsettings.json, I've ended up with this workaround:

// Add this line before creating a logger
UpdateLogFilePath(configuration);

// This is your existing Serilog logger creation logic
var logger = new LoggerConfiguration()
    .ReadFrom.Configuration(configuration)
    .CreateLogger();

Implementation of the UpdateLogFilePath method:

private static void UpdateLogFilePath(IConfigurationRoot configuration)
{
    // A configuration key pattern we are going to look for
    string pattern = "^Serilog:WriteTo.*Args:path$";

    foreach (var kvp in configuration.AsEnumerable())
    {
        if (Regex.IsMatch(kvp.Key, pattern, RegexOptions.IgnoreCase) 
            && !string.IsNullOrEmpty(kvp.Value))
        {
            // Format a file path in the logger configuration
            configuration[kvp.Key] = string.Format(kvp.Value, DateTime.Now);
        }
    }
}

Sample of the appsettings.json:

{
  "Serilog": {
    "Using": [ "Serilog.Sinks.File" ],
    "WriteTo": [
      {
        "Name": "File",
        "Args": {
          "path": "log_{0:yyyyMMdd_HHmm}.txt"
        }
      }
    ]
  }
}
Ivan
  • 355
  • 2
  • 14
0

This is my approach for Serilog.Sinks.File and Serilog.Settings.Configuration. It's an evolution of the accepted answer, but also using an appsettings.json.

Sample of the appsettings.json:

"Serilog": {
  "Using": [ "Serilog.Sinks.Debug", "Serilog.Sinks.File" ],
  "MinimumLevel": "Debug",
  "WriteTo": {
    "DebugSink": "Debug",
    "FileSink": {
      "Name": "File",
      "Args": {
        "path": "%LOCALAPPDATA%/Company/Application/{timestamp}.log"
      }
    }
  }
}

Please look at how I handle array declaration in the WriteTo - it is on purpose to have an easier to replace a {timestamp} placeholder — details about WriteTo can find in this section.

Now, let's configure the logger using the config from appsettings.json:

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

const string serilogFileSinkPath = "Serilog:WriteTo:FileSink:Args:path";

if (configuration.GetSection(serilogFileSinkPath).Exists())
{
    var filePath = configuration[serilogFileSinkPath];
    configuration[serilogFileSinkPath] = filePath.Replace("{timestamp}", DateTime.Now.ToString("yyyyMMdd_HHmmss"));
}

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

The code reads the configuration.
Next, it checks if the given section that contains the file path is present - if yes, then the replacement of the placeholder happens.
Now configuration has all the needed data, so it can be used to configure the logger.

Lukasz Szczygielek
  • 2,768
  • 2
  • 20
  • 34