serilog / serilog-settings-configuration

A Serilog configuration provider that reads from Microsoft.Extensions.Configuration
Apache License 2.0
444 stars 129 forks source link

How to create the log file by process name? #411

Open xuliujian opened 7 months ago

xuliujian commented 7 months ago

I create a common trace library for other solutions. But I can not find a way to configure the path dynamicly. I tried to create a enrich to add a property named InstanceName, but it does not work.

{ "Serilog": { "Using": [ "Serilog.Sinks.Console", "Serilog.Sinks.File" ], "MinimumLevel": "Debug", "WriteTo": [ { "Name": "Console", "Args": { "outputTemplate": "{TraceCategory} - {Timestamp:o} [{Level:u3}] {Message}{NewLine}" } }, { "Name": "File", "Args": { "path": "./logs/{InstanceName}.log", "outputTemplate": "{TraceCategory} - {Timestamp:o} [{Level:u3}] {Message}{NewLine}", "rollingInterval": "Day", "retainedFileCountLimit": 7 } } ], "Enrich": [ "FromLogContext", "WithMachineName", "WithThreadId", "WithTraceCategory", "WithInstanceName" ], "Destructure": [ { "Name": "ToMaximumDepth", "Args": { "maximumDestructuringDepth": 4 } }, { "Name": "ToMaximumStringLength", "Args": { "maximumStringLength": 100 } }, { "Name": "ToMaximumCollectionCount", "Args": { "maximumCollectionCount": 10 } } ] } }

bartelink commented 7 months ago

You're best off asking stuff like this on stackoverflow - anyone that watches this repo watches the serilog tag there - and be sure to take the time to format your question and include any information about messages you receive (search up about Serilog Selflog)

cocowalla commented 7 months ago

Enrichers don't work for filenames, only for log message templates.

I don't believe there is a way to name the log file based on the process name while using JSON config. Instead, I think you'll need to configure the loggewr in code instead. You probably already know this if you've tried writing an enricher, but you can get the process name (without the file extension) by using:

System.Diagnostics.Process.GetCurrentProcess().ProcessName
xuliujian commented 7 months ago

@cocowalla Thank you. At the moment, I have a workaround to implement this. I add a PlaceHolder flag such as ${InstanceName} in the path, and then read the appsettings.json and replace the PlaceHolder with the process name, then LogConfiguration reads from the configuration. But I think it is not too nice.

public static IConfigurationRoot ApplyPlaceHolder(this IConfigurationRoot configuration, string placeHolder, string placeTarget)
{
    var writeToDirectiveSection = configuration.GetSection("Serilog:WriteTo");

    if (writeToDirectiveSection.GetChildren().Any())
    {
        foreach (var sink in writeToDirectiveSection.GetChildren())
        {
            var pathConfigSection = sink.GetSection("Args:path");

            if (pathConfigSection != null && !string.IsNullOrEmpty(pathConfigSection.Value))
            {
                if (pathConfigSection.Value.Contains(placeHolder))
                {
                    pathConfigSection.Value = pathConfigSection.Value.Replace(placeHolder, placeTarget);
                }
            }
        }
    }

    return configuration;
}
            builder = new ConfigurationBuilder();
            configurationRoot = builder.AddJsonFile(Path.Combine(Directory.GetCurrentDirectory(), "appsettings.json")).Build();

            processName = Process.GetCurrentProcess().ProcessName;

            //Replace InstanceName with processName
            configurationRoot.ApplyPlaceHolder("${InstanceName}", processName);

            _loggerConfiguration = new LoggerConfiguration();
            _loggerConfiguration.ReadFrom.Configuration(configurationRoot)