.NET 6 Worker应用Serilog日志无法写入Elasticsearch求助
问题排查:.NET 6 Worker服务Serilog日志无法写入Elasticsearch及控制台测试日志不输出
问题描述
基于.NET 6开发Worker服务,采用Serilog实现日志写入Elasticsearch,遇到以下问题:
- Elasticsearch未创建对应索引,控制台仅提示
Unable to submit event,无有效错误信息用于排查 - Program.cs中的测试日志
Log.Information("test log")未输出到控制台,Worker中的日志也无法提交到Elasticsearch
相关代码与配置
Program.cs
public class Program { public static void Main(string[] args) { CreateHostBuilder(args).Build().Run(); } public static IHostBuilder CreateHostBuilder(string[] args) => Host.CreateDefaultBuilder(args) .UseSerilog((context, configuration) => { configuration.Enrich.FromLogContext() .Enrich.WithExceptionDetails() .Enrich.WithMachineName() .WriteTo.Console() .WriteTo.Elasticsearch( new ElasticsearchSinkOptions(new Uri("http://localhost:9200/")) { IndexFormat = $"Elastic-logs-ApprovalCycle-{context.HostingEnvironment.EnvironmentName?.ToLower().Replace(".", "-")}-{DateTime.UtcNow:yyyy-MM-dd}", TypeName = null, AutoRegisterTemplate = true, BatchAction = ElasticOpType.Create, CustomFormatter = new ElasticsearchJsonFormatter(), OverwriteTemplate = true, DetectElasticsearchVersion = true, AutoRegisterTemplateVersion = AutoRegisterTemplateVersion.ESv7, NumberOfReplicas = 1, NumberOfShards = 2, FailureCallback = e => Console.WriteLine("Unable to submit event " + e.MessageTemplate), EmitEventFailure = EmitEventFailureHandling.WriteToSelfLog | EmitEventFailureHandling.WriteToFailureSink | EmitEventFailureHandling.RaiseCallback | EmitEventFailureHandling.ThrowException }) .Enrich.WithProperty("Environment", context.HostingEnvironment.EnvironmentName) .ReadFrom.Configuration(context.Configuration); } ) .ConfigureServices((hostContext, services) => { Log.Information("test log"); Serilog.Debugging.SelfLog.Enable(msg => Debug.WriteLine(msg)); services.AddSerilog(); services.AddSingleton(rabbit); services.AddHostedService<Worker>(); services.AddHostedService<Worker2>(); }); }
Worker.cs
using System; using System.Threading; using System.Threading.Tasks; using Approval.Workflow; using Microsoft.Extensions.Hosting; using SSRM; using ILogger = Serilog.ILogger; namespace Approval { public class Worker : BackgroundService { private readonly ILogger _logger; private readonly RmqOptions _options; private readonly RmqListener<> _listener; public Worker(ILogger logger,RmqOptions options) { _logger = logger; _options = options; _listener=new RmqListener<>(options); } protected override async Task ExecuteAsync(CancellationToken stoppingToken) { try { _logger.Information("Start listen ... "); while (!stoppingToken.IsCancellationRequested) { await _listener.Listen("Queue"); } } catch (Exception e) { _logger.Information("Listen to Queue: 'Queue' Exception" + e); } } public override async Task StopAsync(CancellationToken cancellationToken) { await ApprovalDriver.StopAsync(cancellationToken); } } }
依赖包
<PackageReference Include="Elasticsearch.Net" Version="7.17.5" /> <PackageReference Include="Microsoft.Extensions.Hosting" Version="7.0.1" /> <PackageReference Include="Newtonsoft.Json" Version="13.0.3" /> <PackageReference Include="RabbitMQ.Client" Version="6.5.0" /> <PackageReference Include="restsharp" Version="110.2.0" /> <PackageReference Include="Serilog" Version="3.0.1" /> <PackageReference Include="serilog.aspnetcore" Version="7.0.0" /> <PackageReference Include="Serilog.Enrichers.Environment" Version="2.2.0" /> <PackageReference Include="Serilog.Exceptions" Version="8.4.0" /> <PackageReference Include="Serilog.Extensions.Logging" Version="7.0.0" /> <PackageReference Include="Serilog.Formatting.Elasticsearch" Version="9.0.3" /> <PackageReference Include="Serilog.Sinks.Console" Version="4.1.0" /> <PackageReference Include="Serilog.Sinks.Debug" Version="2.0.0" /> <PackageReference Include="Serilog.Sinks.Elasticsearch" Version="9.0.3" /> <PackageReference Include="Synergy.Contracts" Version="2.0.132" /> <PackageReference Include="WorkflowCore.Persistence.MySQL" Version="3.0.1" />
appsettings.json
"Serilog": { "MinimumLevel": { "Default": "Information", "Override": { "Microsoft": "Information", "System": "Warning" } } }
控制台输出
"C:\Program Files\JetBrains\JetBrains Rider 2021.2.1\plugins\dpa\DotFiles\JetBrains.DPA.Runner.exe" --handle=5600 --backend-pid=28808 --detach-event-name=dpa.detach.5600 C:/Users/u12749/Desktop/update/Approval/Approval/bin/Debug/net6.0/Approval.exe [10:22:50 INF] Start listen ... Unable to submit event Start listen ... Unable to submit event Start listen ...
原因分析
控制台测试日志不输出
Log.Information("test log")在ConfigureServices中调用时,Serilog全局Logger尚未完成初始化,静态Log类还未被正确配置。Serilog.Debugging.SelfLog.Enable启用时机过晚,无法捕获Serilog初始化阶段的错误信息。
Elasticsearch无法写入
- 索引格式错误:
IndexFormat中使用DateTime.UtcNow会导致索引名称固定为应用启动时的日期,而非日志产生时的日期,同时会干扰Serilog模板注册逻辑。 - 依赖版本不兼容:Serilog.Sinks.Elasticsearch 9.x版本适配Elasticsearch 8.x,而当前使用的Elasticsearch.Net是7.17.5(对应Elasticsearch 7.x),版本不匹配导致连接或序列化错误。
- 错误信息缺失:
FailureCallback仅输出日志模板,未包含异常详细信息,无法定位具体失败原因。 - SelfLog启用太晚:无法捕获Serilog连接Elasticsearch阶段的初始化错误。
解决方案
修复控制台测试日志不输出
- 调整测试日志位置:将测试日志移到Host构建完成后,确保Serilog已初始化:
或通过依赖注入获取ILogger记录日志:public static void Main(string[] args) { var host = CreateHostBuilder(args).Build(); Log.Information("test log"); host.Run(); }.ConfigureServices((hostContext, services) => { var logger = services.BuildServiceProvider().GetRequiredService<ILogger<Program>>(); logger.LogInformation("test log"); // 其他服务注册代码 }) - 提前启用SelfLog:在Program类静态构造函数中启用,捕获全阶段错误:
public class Program { static Program() { Serilog.Debugging.SelfLog.Enable(msg => Console.WriteLine($"Serilog SelfLog: {msg}")); } // 其他代码 }
修复Elasticsearch无法写入
- 修正索引格式:使用Serilog占位符
{0:yyyy-MM-dd}实现按天分片,注意用双大括号转义:IndexFormat = $"Elastic-logs-ApprovalCycle-{context.HostingEnvironment.EnvironmentName?.ToLower().Replace(".", "-")}-{{0:yyyy-MM-dd}}" - 对齐依赖版本:
- 若使用Elasticsearch 7.x,将Serilog.Sinks.Elasticsearch降级到8.4.0,保持与Elasticsearch.Net 7.17.5兼容:
<PackageReference Include="Serilog.Sinks.Elasticsearch" Version="8.4.0" /> - 或升级Elasticsearch服务器到8.x,保留当前Serilog.Sinks.Elasticsearch 9.x版本。
- 若使用Elasticsearch 7.x,将Serilog.Sinks.Elasticsearch降级到8.4.0,保持与Elasticsearch.Net 7.17.5兼容:
- 增强错误日志:修改
FailureCallback输出完整异常信息:FailureCallback = e => { Console.WriteLine($"Unable to submit event: {e.MessageTemplate}"); if (e.Exception != null) { Console.WriteLine($"Exception details: {e.Exception.ToString()}"); } } - 简化配置调试:暂时移除非必要配置项,先确保基础连接正常:
.WriteTo.Elasticsearch(new ElasticsearchSinkOptions(new Uri("http://localhost:9200/")) { IndexFormat = $"Elastic-logs-ApprovalCycle-{context.HostingEnvironment.EnvironmentName?.ToLower().Replace(".", "-")}-{{0:yyyy-MM-dd}}", TypeName = null, AutoRegisterTemplate = true, AutoRegisterTemplateVersion = AutoRegisterTemplateVersion.ESv7, FailureCallback = e => { Console.WriteLine($"Unable to submit event: {e.MessageTemplate}"); if (e.Exception != null) Console.WriteLine(e.Exception); }, EmitEventFailure = EmitEventFailureHandling.WriteToSelfLog | EmitEventFailureHandling.RaiseCallback }) - 验证Elasticsearch连接:添加连接测试代码,确认网络可达:
// 在Main方法中添加 var client = new Elasticsearch.Net.ElasticLowLevelClient(new Uri("http://localhost:9200/")); var response = client.Ping<StringResponse>(); Console.WriteLine($"Elasticsearch Ping Result: {response.Success} - {response.Body}");
内容的提问来源于stack exchange,提问作者marah
相关产品推荐
相关产品推荐

