Как инициализировать Serilog в Windows Service? - PullRequest
1 голос
/ 19 сентября 2019

У меня следующая проблема. Я хочу иметь возможность использовать Serilog внутри службы Windows, и я не знаю, где она должна быть инициализирована:

В настоящее время я инициализирую ее в моем Main:

using Serilog;

public static void RunService() {
    Log.Logger = new LoggerConfiguration()
      .WriteTo.RollingFile([some path])
      .CreateLogger();

    MyService daemon = new MyService();
    Log.Information("Service initialized")

    ServiceBase[] services;
    services = new ServiceBase[] {
        service
    };
    Log.Information("Before running the service");
    ServiceBase.Run(services);
}

static void Main(string[] args) {
   RunService();
}

Служба

public class MyService:ServiceBase{
   protected override void OnSessionChange(SessionChangeDescription changeDescription) {
    Log.Information("session changed");
   } 
   protected override void OnStart(string[] args) {
     Log.Information("Started service");
   }
}

Таким образом, чтобы использовать Serilog как в Main, который выполняет сбор служб, так и внутри целевой службыкак это сделать?

Ответы [ 2 ]

2 голосов
/ 20 сентября 2019

Обычная практика - делать то, что вы делаете, то есть инициализировать запись в самом начале и сохранять регистратор в Log.Logger, а затем, внутри вашей службы, захватить регистратор контекста, Log.ForContext<T>.Например,

using System.ServiceProcess;
using Serilog;

namespace WindowsServiceHost
{
    public partial class MyService : ServiceBase
    {
        private readonly ILogger _log = Log.ForContext<MyService>();

        public MyService()
        {
            InitializeComponent();
        }

        protected override void OnStart(string[] args)
        {
            _log.Information("Service starting...");
            // ...

            _log.Information("Service started.");
        }

        protected override void OnStop()
        {
            _log.Information("Service stopping...");
            // ...

            _log.Information("Service stopped.");
        }
    }
}

Это упрощает получение доступа к регистратору Serilog и дает дополнительное преимущество: контекстная информация о том, откуда поступают сообщения журнала, что полезно.

Возможно, вам будет интересно прочитать это: Контекст и корреляция - структурированные концепции ведения журналов в .NET (5)


Кроме того, не забудьте:позвоните Log.CloseAndFlush() до того, как ваша служба остановится, чтобы убедиться, что любые буферизованные сообщения записаны в приемники.

static class Program
{
    static void Main()
    {
        Log.Logger = new LoggerConfiguration()
            .WriteTo.File(@"C:\SomePath\MyApp.log")
            .CreateLogger();

        try
        {
            var servicesToRun = new ServiceBase[]
            {
                new MyService(),
            };

            ServiceBase.Run(servicesToRun);
        }
        catch(Exception ex)
        {
            Log.Fatal(ex, ex.Message);
            throw;
        }
        finally
        {
            Log.CloseAndFlush(); // <<<<<<<<<<<<<<<<<<<
        }
    }
}

Подробнее об этом можно прочитать в документации: Жизненный цикл регистраторов

0 голосов
/ 20 сентября 2019

Другой способ сделать это - вставить экземпляр ILogger в конструктор службы Windows, который вы передаете из метода Main.

static class Program
{
    static void Main()
    {
        Log.Logger = new LoggerConfiguration()
            .WriteTo.File(@"C:\SomePath\MyApp.log")
            .CreateLogger();

        var servicesToRun = new ServiceBase[]
        {
            new MyService(Log.Logger), // <<<<<<<<<<<<<<<<<<<
        };

        ServiceBase.Run(servicesToRun);
    }
}

И в службу Windows,Вы добавляете конструктор, который принимает экземпляр ILogger.Вам все еще нужно сохранить конструктор, который не принимает никаких аргументов, чтобы вы все равно открывали визуальный дизайнер в Visual Studio:

public partial class MyService : ServiceBase
{
    private readonly ILogger _log;

    public MyService()
        : this(Log.Logger)
    {
        InitializeComponent();
    }

    public MyService(ILogger logger) // <<<<<<<<<<<<<<<<<<<
    {
        InitializeComponent();

        if (logger == null) throw new ArgumentNullException(nameof(logger));
        _log = logger.ForContext<MyService>();
    }

    protected override void OnStart(string[] args)
    {
        _log.Information("Service starting...");
        // ...

        _log.Information("Service started.");
    }

    protected override void OnStop()
    {
        _log.Information("Service stopping...");
        // ...

        _log.Information("Service stopped.");
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...