Can I log to separate files using Serilog?

爷,独闯天下 提交于 2019-12-24 05:22:08

问题


My ASP.NET Core 2.1 app logs to a Serilog file sink, all the "usual stuff" - i.e. app related stuff such as debug, monitoring, performance, etc.

However we also need to log other data to a separate file. Not app related, but customer related - the kind of stuff that should go into a database. However for legacy reasons, there is no database on this system and so that data needs to be saved to a file instead. Obviously this can't be written to the same log file.

I could just write to a FileStream. But I prefer to do structured logging with Serilog.

So is there a way to have two loggers simultaneously? Which log different data to different file sinks.

(If so, how do I inject them into my classes - right now I just inject ILogger<ClassName>.)


回答1:


You can definitely do that.

  1. You need to import package Serilog.Sinks.File

  2. Then you have to configure Serilog.

    In program.cs do following thing.

    Log.Logger = new LoggerConfiguration()
            .MinimumLevel.Debug()
            .MinimumLevel.Override("Microsoft", LogEventLevel.Information)
            .Enrich.FromLogContext()
        .WriteTo.File(
            @"<<your log file path>>",
        fileSizeLimitBytes: 10000000,
        rollOnFileSizeLimit: true,
        shared: true,
        flushToDiskInterval: TimeSpan.FromSeconds(1))
            .CreateLogger();
    

In buildWebHost function add UseSerilog().

public static IWebHost BuildWebHost(string[] args) =>
    WebHost.CreateDefaultBuilder(args)
    .UseStartup<Startup>()
        .UseSerilog() // <-- Add this line
        .Build();

Update 1

I have used EventId property. This is just demo that how you can use different file based on eventId but for your requirement you have to implement additional thing your own.

Program.cs

public class Program
    {
        public static void Main(string[] args)
        {
            Log.Logger = new LoggerConfiguration()
                .WriteTo.Logger(cc => cc.Filter.ByIncludingOnly(WithProperty("EventId",1001)).WriteTo.File("Test1001.txt",flushToDiskInterval: TimeSpan.FromSeconds(1)))
                .WriteTo.Logger(cc => cc.Filter.ByIncludingOnly(WithProperty("EventId", 2001)).WriteTo.File("Test2001.txt", flushToDiskInterval: TimeSpan.FromSeconds(1)))
                .CreateLogger();

            CreateWebHostBuilder(args).Build().Run();
        }

        public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
            WebHost.CreateDefaultBuilder(args).UseSerilog()
                .UseStartup<Startup>();

        public static Func<LogEvent, bool> WithProperty(string propertyName, object scalarValue)
        {
            if (propertyName == null) throw new ArgumentNullException("propertyName");           
            ScalarValue scalar = new ScalarValue(scalarValue);
            return e=>
            {
                LogEventPropertyValue propertyValue;
                if (e.Properties.TryGetValue(propertyName, out propertyValue))
                {
                    var stValue = propertyValue as StructureValue;
                    if (stValue != null)
                    {
                        var value = stValue.Properties.Where(cc => cc.Name == "Id").FirstOrDefault();
                        bool result = scalar.Equals(value.Value);
                        return result;
                    }
                }
                return false;
            };
        }
    }

My HomeController.cs

  public class HomeController : Controller
    {
        ILogger<HomeController> logger;
        public HomeController(ILogger<HomeController> logger)
        {
            this.logger = logger;
        }
        public IActionResult Index()
        {
            logger.Log(LogLevel.Information,new EventId(1001), "This is test 1");
            logger.Log(LogLevel.Information, new EventId(2001), "This is test 2");
            return View();
        } 
    }

Note: Main thing is that you have to use some type of filter.




回答2:


The simplest way I've managed to do this was to implement a new unique interface that I could pass to the DI system to be consumed by the controllers.
Note: In the example I used the Serilog.Sinks.RollingFile NuGet package. Use any other sinks as you see fit. I use asp.net Core 2.1.

New Interface

using Serilog;
using Serilog.Core;

public interface ICustomLogger
{
    ILogger Log { get; }
}

public class CustomLogger : ICustomLogger
{
    private readonly Logger _logger;

    public ILogger Log { get { return _logger; } }

    public CustomLogger( Logger logger )
    {
        _logger = logger;
    }
}

Implementation in Startup.cs

using Serilog;
...
public void ConfigureServices( IServiceCollection services )
{
    ...

    ICustomLogger customLogger = new CustomLogger( new LoggerConfiguration()
        .MinimumLevel.Debug()
        .WriteTo.RollingFile( @"Logs\CustomLog.{Date}.log", retainedFileCountLimit: 7 )
        .CreateLogger() );
    services.AddSingleton( customLogger );

    ...
}

Usage in Controller

public class MyTestController : Controller
{
    private readonly ICustomLogger _customLogger;

    public MyTestController( ICustomLogger customLogger )
    {
        _customLogger = customLogger;
    }

    public IActionResult Index()
    {
        ...
        _customLogger.Log.Debug( "Serving Index" );
        ...
    }
}



回答3:


Serilog.Sinks.Map does this, and includes a file logging example:

Log.Logger = new LoggerConfiguration()
    .WriteTo.Map("EventId", "Other", (name, wt) => wt.File($"./logs/log-{name}.txt"))
    .CreateLogger();


来源:https://stackoverflow.com/questions/51213779/can-i-log-to-separate-files-using-serilog

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!