.Net Core 6 Worker Service not writing to Logs when running as a Windows Service
Asked Answered
I

2

6

I have created a Worker Service using C# / .Net Core 6 (Visual Studio 2022).

It writes to a log file as expected if run via Visual Studio or started directly from Windows Explorer / PowerShell. However, when installed as a Windows Service, it does not create or write to a log file.

This is my program.cs:

Log.Logger = new LoggerConfiguration()
    .MinimumLevel.Information()
    .MinimumLevel.Override("Microsoft", LogEventLevel.Warning)
    .MinimumLevel.Override("Microsoft.Hosting.Lifetime", LogEventLevel.Information)
    .Enrich.FromLogContext()
    .WriteTo.File("./logs/log-.txt", rollingInterval:RollingInterval.Day)
    .CreateBootstrapLogger();

try
{
    Log.Information("Starting the Service");

    IHost host = Host.CreateDefaultBuilder(args)
        .UseWindowsService()
        .ConfigureAppConfiguration((hostContext, configBuilder) =>
        {
            configBuilder
                //.SetBasePath(Directory.GetCurrentDirectory())
                .AddJsonFile("appsettings.json")
                .AddJsonFile($"appsettings.{hostContext.HostingEnvironment.EnvironmentName}.json", optional: true, reloadOnChange: true)
                .AddJsonFile($"appsettings.{Environment.MachineName}.json", true, true)
                .Build();
        })
        .UseSerilog((context, services, configuration) => configuration
            .ReadFrom.Configuration(context.Configuration)
            .ReadFrom.Services(services)
            .Enrich.FromLogContext())
        .ConfigureServices((hostContext, services) =>
        {
            ... 
        })
        .Build();

    
    await host.RunAsync();
}
catch (Exception ex)
{
    Log.Fatal(ex, "There was a problem starting the service");
}
finally
{
    Log.Information("Service successfully stopped");

    Log.CloseAndFlush();
}

I have this in appsettings.json:

  "Serilog": {
    "Using": [ "Serilog.Sinks.Console", "Serilog.Sinks.File", "Serilog.Sinks.Debug" ],
    "MinimumLevel": {
      "Default": "Information",
      "Override": {
        "Microsoft": "Warning",
        "System": "Warning"
      }
    },
    "WriteTo": [
      { "Name": "Console" },
      {
        "Name": "File",
        "Args": {
          "path": ".\\logs\\log-.txt",
          "rollingInterval": "Day"
        }
      }
    ],
    "Enrich": [ "FromLogContext" ]
  }

If I include the "SetBasePath" part, the service fails to start (although it still runs via Visual Studio).

I am publishing the service from Visual Studio with Target Framework = net6.0, Deployment Mode = Framework Dependent, Target runtime = win-x64.

Note: I have created a Logger in Program.cs because I wanted to log the start and stop / crash of the service.

Irremissible answered 18/3, 2022 at 13:16 Comment(5)
Check folder permissions of the log folder, and make sure the account the service runs under can write to that log folderUnfailing
Are you sure you're looking in the correct folder? You configured Serilog to use a relative path. That's relative to the running process' working directory, not the binary's location. Services are executed by the svchost process. It's quite likely your logs are in System32. Use an absolute path instead, preferably one based on configuration settingsHaplology
A Service default to a System Account that has no Environmental Variables. Start service with a user account (or a service) account that has an environment.Misdemean
As mentioned check permissions(change it to logon as an admin user to test) in services, have you also tried moving .UseWindowsService() to just before .Build()? I usually put this as far down as possible in the chain, but that is just my preference.Monospermous
@PanagiotisKanavos yes, my log files were ending up in System32! I've added a setting to appSettings now, just a shame I can't see how to implement logging of the start & stop within program.csIrremissible
E
5

As others have noted, services run with a working directory different than the process location. One old trick I like to use is to set the working directory to the process' binary directory first thing:

Environment.CurrentDirectory = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
Elfont answered 19/3, 2022 at 1:7 Comment(0)
K
1

In my case, I just changed Deployment mode to Self-Contained and choose the Produce single file. Although it will create a large file but now compiler embed all dependent libraries into a single file.

enter image description here

Kayleen answered 3/6, 2022 at 14:6 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.