Serilog不将日志输出到txt文件中

Ste*_*BEG 6 c# backgroundworker serilog asp.net-core asp.net-core-webapi

我使用 dotnet worker 服务(.net 5),我集成了 serilog 以及丰富器和接收器。但由于某种原因,我在文件日志中看不到任何输出。

这是我的 appsettings.json

{
  "ConnectionStrings": {
    "DefaultConnection": "Server=.;Database=eeee;Trusted_Connection=True;MultipleActiveResultSets=true"
  },
  "WorkerOptions": {
    "Batch": 5
  },
  "Serilog": {
    "Using": [],
    "MinimumLevel": {
      "Default": "Information",
      "Override": {
        "Microsoft": "Warning",
        "System": "Warning"
      }
    },
    "Enrich": [ "FromLogContext", "WithMachineName", "WithProcessId", "WithThreadId" ],
    "WriteTo": [
      { "Name": "Console" },
      {
        "Name": "File",
        "Args": {
          "path": "E:\\Logs\\log_.txt",
          "outputTemplate": "{Timestamp:o} {Message}{NewLine:1}{Exception:1}",
          "rollingInterval": "Day",
          "retainedFileCountLimit": 7
        }
      },
      {
        "Name": "File",
        "Args": {
          "path": "E:\\Logs\\log_.json",
          "formatter": "Serilog.Formatting.Json.JsonFormatter, Serilog",
          "outputTemplate": "{Timestamp:o} {Message}{NewLine:1}{Exception:1}",
          "rollingInterval": "Day",
          "retainedFileCountLimit": 7
        }
      }
    ]
  }
}
Run Code Online (Sandbox Code Playgroud)

记录器注册:

public class Program
{
    public static void Main(string[] args)
    {
            
        var configuration = new ConfigurationBuilder()
            .AddJsonFile("appsettings.json")
            .Build();

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

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

    public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
               
            .ConfigureServices((hostContext, services) =>
            {

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

                var optionsBuilder = new DbContextOptionsBuilder<ApplicationDbContext>();
                optionsBuilder.UseSqlServer(configuration.GetConnectionString("DefaultConnection"));
                services.AddScoped<ApplicationDbContext>(s => new ApplicationDbContext(optionsBuilder.Options));
                services.AddHostedService<Worker>();
            });
}
Run Code Online (Sandbox Code Playgroud)

这是一个实现:

public class Worker : BackgroundService
{
    private readonly ILogger<Worker> _logger;
    private readonly IServiceScopeFactory _serviceScopeFactory;
    private readonly IConfiguration _config;
    public Worker(ILogger<Worker> logger, IServiceScopeFactory serviceScopeFactory, IConfiguration config)
    {
        _config = config;
        _logger = logger;
        _serviceScopeFactory = serviceScopeFactory;
    }

    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
     _logger.LogInformation("Worker picked up {0} requests for dispatch at at: {time}", generatedRequests.Count(), DateTimeOffset.Now);
    }
Run Code Online (Sandbox Code Playgroud)

当我通过 Kestrel 运行工作程序时,我可以在控制台日志中看到,但在 .txt 文件或 .json 文件中看不到

更新#1 我尝试使用下面的答案,但在部署工作人员时仍然遇到问题,我没有看到任何日志。当我通过 service.exe 文件运行它或只是执行 debugg (Kestrel) 时,会生成日志文件。

这是更新的 application.json:

"Serilog": {
  "Using": [],
  "MinimumLevel": {
    "Default": "Information",
    "Override": {
      "Microsoft": "Warning",
      "System": "Warning"
    }
  },
  "Enrich": [ "FromLogContext", "WithMachineName", "WithProcessId", "WithThreadId" ],
  "WriteTo": [
    { "Name": "Console" },
    {
      "Name": "File",
      "Args": {
        "path": ".\\Logs\\log_.txt",
        "outputTemplate": "{Timestamp:o} {Message}{NewLine:1}{Exception:1}",
        "rollingInterval": "Day",
        "retainedFileCountLimit": 7
      }
    },
    {
      "Name": "File",
      "Args": {
        "path": ".\\Logs\\log_.json",
        "formatter": "Serilog.Formatting.Json.JsonFormatter, Serilog",
        "outputTemplate": "{Timestamp:o} {Message}{NewLine:1}{Exception:1}",
        "rollingInterval": "Day",
        "retainedFileCountLimit": 7
      }
    }
  ]
}
Run Code Online (Sandbox Code Playgroud)

这是 Program.cs

public class Program
{
    public static void Main(string[] args)
    {
        var configuration = new ConfigurationBuilder()
                    .AddJsonFile("appsettings.json")
                    .Build();

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

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

    public static IHostBuilder CreateHostBuilder(string[] args) =>
                Host.CreateDefaultBuilder(args)
                    .UseWindowsService()
                    .ConfigureServices((hostContext, services) =>
                    {

                        var optionsBuilder = new DbContextOptionsBuilder<ApplicationDbContext>();
                        optionsBuilder.UseSqlServer(hostContext.Configuration.GetConnectionString("DefaultConnection"));
                        services.AddScoped<ApplicationDbContext>(s => new ApplicationDbContext(optionsBuilder.Options));
                        services.AddHostedService<Worker>();
                    })
                    .UseSerilog(); // no args
}
Run Code Online (Sandbox Code Playgroud)

UPDATE#2 我更新了 Program 类,如下所示:

public class Program
{
    public static void Main(string[] args)
    {
        CreateHostBuilder(args).Build().Run();
    }

    public static IHostBuilder CreateHostBuilder(string[] args) =>
                Host.CreateDefaultBuilder(args)
                    .UseWindowsService()
                    .ConfigureServices((hostContext, services) =>
                    {

                        var optionsBuilder = new DbContextOptionsBuilder<ApplicationDbContext>();
                        optionsBuilder.UseSqlServer(hostContext.Configuration.GetConnectionString("DefaultConnection"));
                        services.AddScoped<ApplicationDbContext>(s => new ApplicationDbContext(optionsBuilder.Options));
                        services.AddHostedService<Worker>();
                    })
                    .UseSerilog((hostContext, services, logger) => {
                        logger.ReadFrom.Configuration(hostContext.Configuration);
                    });
    }
}
Run Code Online (Sandbox Code Playgroud)

我还在 appsettings.json 中添加了简单的内容:

  "Serilog": {
    "Using": [ "Serilog.Sinks.Console", "Serilog.Sinks.File" ],
    "MinimumLevel": {
      "Default": "Information",
      "Override": {
        "Microsoft": "Warning",
        "System": "Warning"
      }
    },
    "Enrich": [ "FromLogContext", "WithMachineName", "WithProcessId", "WithThreadId" ],
    "WriteTo": [
      { "Name": "Console" },
      {
        "Name": "File",
        "Args": { "path": "Logs/log.txt" }
      },
      //{
      //  "Name": "File",
      //  "Args": {
      //    "path": ".\\Logs\\log_.txt",
      //    "outputTemplate": "{Timestamp:o} {Message}{NewLine:1}{Exception:1}",
      //    "rollingInterval": "Day",
      //    "retainedFileCountLimit": 7
      //  }
      //},
      {
        "Name": "File",
        "Args": {
          "path": ".\\Logs\\log_.json",
          "formatter": "Serilog.Formatting.Json.JsonFormatter, Serilog",
          "outputTemplate": "{Timestamp:o} {Message}{NewLine:1}{Exception:1}",
          "rollingInterval": "Day",
          "retainedFileCountLimit": 7
        }
      }
    ]
  }
Run Code Online (Sandbox Code Playgroud)

这是当我启动 .exe 文件时正在工作的 _logger 的调用(控制台)

using Microsoft.Extensions.Logging;
...
private readonly ILogger<Worker> _logger;
...
_logger.LogInformation("Worker picked up {0} requests for dispatch at: {time}", generatedRequests.Count(), DateTimeOffset.Now);
Run Code Online (Sandbox Code Playgroud)

UPDATE#3 我只是设置了日志记录的绝对路径c:\\Logs\log.txt,它部分工作 - 它创建了一个 txt 文件,但文件是空的。这是新的 appsettings.json:

{
  "ConnectionStrings": {
    "DefaultConnection": "Server=.;Database=svcProcessor_dev;Trusted_Connection=True;MultipleActiveResultSets=true"
  },
  "WorkerOptions": {
    "Batch": 10,
    "Delay": 5000,
    "MaxAttempts":  3
  },
  "Serilog": {
    "Using": ["Serilog.Sinks.Console", "Serilog.Sinks.File"],
    "MinimumLevel": {
      "Default": "Information",
      "Override": {
        "Microsoft": "Warning",
        "System": "Warning"
      }
    },
    "Enrich": [ "FromLogContext", "WithMachineName", "WithProcessId", "WithThreadId" ],
    "WriteTo": [
      { "Name": "Console" },
      {
        "Name": "File",
        "Args": { "path": "C:\\Logs\\log.txt" }
      }
      //{
      //  "Name": "File",
      //  "Args": {
      //    "path": "C:\\Logs\\log_.txt",
      //    "outputTemplate": "{Timestamp:o} {Message}{NewLine:1}{Exception:1}",
      //    "rollingInterval": "Day",
      //    "retainedFileCountLimit": 7
      //  }
      //}
      //{
      //  "Name": "File",
      //  "Args": {
      //    "path": "C:\\Logs\\log_.json",
      //    "formatter": "Serilog.Formatting.Json.JsonFormatter, Serilog",
      //    "outputTemplate": "{Timestamp:o} {Message}{NewLine:1}{Exception:1}",
      //    "rollingInterval": "Day",
      //    "retainedFileCountLimit": 7
      //  }
      //}
    ]
  }
}
Run Code Online (Sandbox Code Playgroud)

更新#4

这是我的工人工人示例的最小示例

pin*_*x33 7

您没有添加基础设施来将 Serilog 转换LoggerMicrosoft.Extensions.Logging.ILogger. 就目前情况而言,您只是在创建 Serilog Logger,但并未实际使用它。您在控制台中看到的实际上是来自内置 Microsoft 记录器的日志,而不是来自 Serilog 的日志。

幸运的是,Serilog 有一个从其记录器到 Microsoft 记录器接口的适配器以及各种帮助程序包,具体取决于您的使用场景。您使用的是通用主机,因此首先将Serilog.Extensions.Hosting添加到您的项目中。然后调用UseSerilog扩展方法。传递给此方法的委托接收一个实例,HostBuilderContext您可以从中检索当前的实例IConfiguration以及IServiceProvider用于LoggingConfiguration配置记录器的实例:

public static void Main(string[] args)
{
    CreateHostBuilder(args).Build().Run();
}

public static IHostBuilder CreateHostBuilder(string[] args) =>
   Host.CreateDefaultBuilder(args)              
       .ConfigureServices((hostContext, services) =>
        {
           /* elided */
        })
       .UseSerilog((hostContext, services, logger) => {
            logger.ReadFrom.Configuration(hostContext.Configuration);
        });
Run Code Online (Sandbox Code Playgroud)

请注意,不再需要设置属性Log.LoggerLoggerConfiguration直接从Main. 该UseSerilog方法将自动设置静态记录器——尽管您不需要它,但ILogger<>无论如何您都会通过它进行记录。

或者,您可以按照当前的方式配置记录器(直接在 中Main)。如果您走这条路线,您将UseSerilog在不带任何参数的情况下进行调用。这将依次使用静态记录器的当前配置。

public static void Main(string[] args)
{
    var config = new ConfigurationBuilder()
                        .AddJsonFile("appsettings.json")
                        .Build();

    Log.Logger = new LoggingConfiguration()
                        .ReadFromConfiguration(config)
                        .CreateLogger();

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

public static IHostBuilder CreateHostBuilder(string[] args) =>
   Host.CreateDefaultBuilder(args)              
       .ConfigureServices((hostContext, services) =>
        {
           /* elided */
        })
       .UseSerilog(); // no args
Run Code Online (Sandbox Code Playgroud)

我个人不喜欢这个选项,尤其是在使用时ReadFrom.Configuration因为它需要您构建额外的配置对象。我更喜欢使用传入回调的配置,因为它将与主机使用的所有其他配置相匹配。

ASP.NET 核心

aspnet-core在问题中标记了您的问题并引用了“Kestrel”。然而,您演示的代码显示了一个非常基本的通用主机,而不是一个 Web 应用程序。如果这确实是一个 Web 应用程序,那么您应该添加该Serilog.AspNetCore。该包隐式引用 Serilog.Extensions.Hosting并包含一些其他的片段,以便在 Web 应用程序中使用。