Serilog无法将日志输出到txt文件中。

6

我使用dotnet worker service (.net 5),同时集成了serilog的enrichers和sinks。但是出现了一些问题,我的文件日志中没有任何输出。

这是我的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
        }
      }
    ]
  }
}

日志记录器的注册:

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>();
            });
}

这是一个实现:

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);
    }

当我通过Kestrel运行worker时,我可以在控制台日志中看到,但是在我的.txt文件或.json文件中却看不到。
更新#1 我尝试了下面的答案,但是当我部署我的worker时仍然有问题,我看不到任何日志。 当我通过service.exe文件运行它或者只是进行调试(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
      }
    }
  ]
}

以下是 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
}

更新#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);
                    });
    }
}

我也将简单的东西放在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
        }
      }
    ]
  }

这是工作中的 _logger 的别名,当我启动 .exe 文件(控制台)时,它再次起作用。

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

更新#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
      //  }
      //}
    ]
  }
}

更新#4

这是我的 worker 的最简示例: worker 示例


这可能是个愚蠢的问题,但你有检查过文件夹权限吗?执行进程需要对E:\logs具有写入访问权限。 - user3282374
是的,我检查过了。而且,我尝试更改应用程序的根文件夹 .\\Logs\log_.txt - Stefan0309
尝试使用异步编写器。我知道这听起来很荒谬,但在某些情况下,在同一线程中调用记录器将无法用于记录适配器(UseSerilog)。 - eocron
你是如何在Linux机器上部署你的应用程序的?使用Docker还是其他方法? - eocron
3个回答

7
你没有添加将Serilog的Logger转换为Microsoft.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);
        });

请注意,现在不再需要设置Log.Logger属性并直接从Main中构建LoggerConfiguration。使用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

就个人而言,我不喜欢这个选项,尤其是在使用ReadFrom.Configuration时,因为它需要您构建一个额外的配置对象。我更喜欢使用传递给回调函数的那个,因为它将匹配主机使用的所有其他配置。

ASP.NET Core

您在问题中打了 aspnet-core 的标签,并提到了 "Kestrel"。然而,您展示的代码显示了一个非常基本的泛型主机,而不是 Web 应用程序。如果这真的是一个 Web 应用程序,那么您应该添加 Serilog.AspNetCore。该包隐含引用了Serilog.Extensions.Hosting 并包含一些其他的部分,供 Web 应用程序内使用。


1
你需要在AppSettings.json中填写“Using”属性,以使用指定的sinks。请查看Serilog github上的示例。仅将它们列在WriteTo下是不够的,还必须列出它们的程序集名称。此外,我真的不建议使用No-Argument版本的UseSerilog,因为它有一些缺点。请先使用我展示的方式,并放弃任何关于静态记录器的内容。 - pinkfloydx33
1
这里有示例:https://github.com/serilog/serilog-settings-configuration#serilogsettingsconfiguration-- - pinkfloydx33
1
@Stefan0309 你是如何发布你的应用程序的?是单文件发布吗?如果是,除了添加Using属性之外,还有其他一些事情需要做才能使其正常工作。 - pinkfloydx33
在appsettings.json中添加using部分后,仍然是相同的。 - Stefan0309
我刚注意到你的路径是相对路径。根据你的部署方式,它们可能会登录到System32或某个奇怪的位置。为了测试目的,请尝试将绝对(完整)路径放置到用户具有写访问权限的文件夹中(例如创建“c:/logs”并在配置中使用它)。重要的是确保每个人都拥有完全访问权限,至少用于调试目的。 - pinkfloydx33
显示剩余9条评论

2
对我来说,我的.Net 5应用程序中的日志文件没有被写入,我遇到了类似的问题。正如@pinkfloydx33在上面多次提问的那样,您是否将此应用程序发布为单文件应用程序?在我的情况下,我正在这样做。他分享的链接和他提问的原因是因为在.Net 5单文件应用程序中,您需要在appsettings.json中使用“Using”语句。.Net 5单文件应用程序无法为您解析命名空间,因此必须在“Using”语句中指定它们。
这是他分享的文章:Serilog配置 这是处理.Net 5单文件应用程序的具体部分:Serilog单文件应用程序 一旦我在我的appsettings.json中简单地添加了“Serilog.Sinks.File”的using,我的记录器就开始写入文件了。
希望这能帮助某些人。

0

在使用Serilog时,我遇到了一些问题(如果上面提到过并且我错过了,请原谅)。

如果您在每个环境中有几个AppSettings,则它们将互相覆盖。 有时,根据您记录输出的方式,您可能需要考虑更改日志记录级别。调试或详细

最后一件事是在您的工作程序中,不要使用ms日志扩展,而是切换到使用serilog,这应该导致您的日志记录必须使用_log.Information("SampleEntry")进行,这是serilogs管道

如上所述,在appsetting中,您需要拥有 "Using": [ "Serilog.Sinks.File"],甚至可以使用"Serilog.Settings.Configuration"进行自定义配置


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接