【问题标题】:Serilog does not output logs into the txt fileSerilog 不会将日志输出到 txt 文件中
【发布时间】:2021-04-28 12:21:04
【问题描述】:

我正在使用 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
        }
      }
    ]
  }
}

记录器的注册:

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 运行工作程序时,我可以在控制台日志中看到,但在 .txt 文件或 .json 文件中看不到

更新 #1 我在下面尝试了这个答案,但是当我部署我的工作人员时仍然遇到问题,我没有看到任何日志。 当我通过 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
        }
      }
    ]
  }

当我启动 .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);

更新#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 example

【问题讨论】:

  • 可能是个愚蠢的问题,但是您检查过文件夹权限吗?执行进程需要对E:\logs的写访问
  • 是的,我检查了。另外,我尝试更改为应用程序的根文件夹.\\Logs\log_.txt
  • 尝试使用异步写入器。我知道这听起来很荒谬,但在某些情况下,在同一线程中调用 logger 不适用于日志适配器 (UseSerilog)。
  • 你如何在 linux 机器上部署你的应用程序?码头工人或其他一些方法?

标签: c# asp.net-core asp.net-core-webapi backgroundworker serilog


【解决方案1】:

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

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

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

请注意,不再需要直接从Main 中设置Log.Logger 属性和构建LoggerConfigurationUseSerilog 方法将自动设置静态记录器——尽管您不需要它,但无论如何您都是通过 ILogger&lt;&gt; 记录的。

或者,您可以配置您当前执行的记录器方式(直接在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 核心

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

【讨论】:

  • 我仍然看不到任何日志。当我启动 Kestrel 时,日志在那里,但是当我发布我的应用程序并注册服务并启动服务时,我没有收到任何日志(未创建日志文件夹)
  • 您需要在 AppSettings.json 中的“使用”属性中填写要使用的接收器的名称。检查 Serilog github 以获取示例。将它们列在 WriteTo 下是不够的,必须列出它们的程序集名称。此外,我真的不建议使用 UseSerilog 的无参数版本,它有一些缺点。使用我首先展示的方式并放弃有关静态记录器的任何内容
  • 这里有例子:github.com/serilog/…
  • @Stefan0309 另外你是如何发布你的应用程序的?是单文件发布吗?如果是这样,除了添加 Using 属性之外,您还需要做一些其他事情才能使其正常工作
  • 还是一样,我在 appsettings.json 中添加 using 部分后
【解决方案2】:

对我来说,我遇到了类似的问题,即我的日志文件没有写入我的 .Net 5 应用程序中。正如@pinkfloydx33 上面多次询问的那样,您是否将此应用程序作为单个文件应用程序发布?就我而言,我正在这样做。在他分享的链接和他问的原因中,是因为您需要在 .Net 5 单文件应用程序中执行某些特定操作,这就是您的 appsettings.json 中的“使用”语句。 .Net 5 单文件应用程序无法为您解析命名空间,因此您必须在“Using”语句中指定它们。

这是他分享的文章:Serilog configuration

这里是处理 .Net 5 单文件应用程序的具体部分:Serilog single file applications

一旦我简单地将“Serilog.Sinks.File”的使用添加到我的 appsettings.json,我的记录器就开始写入该文件。

希望这对某人有所帮助。

【讨论】:

    【解决方案3】:

    我在使用 serilog 时看到的一些事情(如果上面提到了它们,我很抱歉,我错过了它们)。

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

    最后一件事是在您的工作人员中,而不是将 ms 日志记录扩展切换为使用 serilog,这应该会导致您的日志记录必须使用 _log.Information("SampleEntry") 来完成,它是 serilogs 管道

    如上所述,您将希望拥有 “使用”:[“Serilog.Sinks.File”],甚至可能是“Serilog.Settings.Configuration”用于自定义配置内容

    【讨论】:

      猜你喜欢
      • 2018-02-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-03-13
      相关资源
      最近更新 更多