.Net中将Logz.io注册为单例服务 日志不上报Kibana无报错
.Net 单例注入Logz.io日志上报失败排查及修复方案
代码存在的核心问题
loggerRepository字段未初始化:构造函数中仅对hierarchy字段赋值,声明的loggerRepository始终为null,创建LoggingEvent时传入null仓库参数,日志事件无法被正确路由到Logz.io appender。- Appender配置流程错误:
- 所有配置项(含自定义字段)赋值完成后,未调用
ActivateOptions()方法激活appender,log4net不会加载未激活的appender配置 - 自定义字段
source是在appender挂载到根节点、hierarchy标记为已配置之后才添加的,该配置不会被已完成初始化的appender识别
- 所有配置项(含自定义字段)赋值完成后,未调用
- 监听地址格式错误:配置的
AddListenerUrl未带https://协议头,appender发起上报请求时地址格式非法,请求无法送达Logz.io服务端 - 调试开关关闭:
AddDebug(false)导致appender内部的网络错误、配置错误日志全部被吞,程序表面无异常但实际上报全失败 - 未做资源释放处理:单例服务随应用生命周期存在,未在服务释放时主动刷新appender缓冲区,缓冲区未凑满100条、未到5秒超时的日志会在应用退出时直接丢失。
修复后的可运行代码
public class LogzioService : ILogzioService, IDisposable { private readonly string APPNAME = "MyApp0"; private readonly ILogger _logger; private readonly Hierarchy _hierarchy; private readonly LogzioAppender _logzioAppender; public LogzioService(IConfiguration config) { _hierarchy = (Hierarchy)LogManager.GetRepository(); _logzioAppender = new LogzioAppender(); // 所有配置项必须在ActivateOptions调用前全部赋值 _logzioAppender.AddToken(config["logzio_key"]); _logzioAppender.AddType("log4net"); // 注意补全https协议头 _logzioAppender.AddListenerUrl("https://listener-nl.logz.io:8071"); _logzioAppender.AddBufferSize(100); _logzioAppender.AddBufferTimeout(TimeSpan.FromSeconds(5)); _logzioAppender.AddRetriesMaxAttempts(3); _logzioAppender.AddRetriesInterval(TimeSpan.FromSeconds(2)); // 排查阶段先开debug,确认上报正常后再关 _logzioAppender.AddDebug(true); _logzioAppender.AddGzip(true); _logzioAppender.JsonKeysCamelCase(false); _logzioAppender.ParseJsonMessage(true); // 提前加自定义字段 LogzioAppenderCustomField sourceField = new LogzioAppenderCustomField { Key = "source", Value = APPNAME }; _logzioAppender.AddCustomField(sourceField); // 关键:激活appender配置 _logzioAppender.ActivateOptions(); _hierarchy.Root.AddAppender(_logzioAppender); _hierarchy.Root.Level = Level.All; _hierarchy.Configured = true; _logger = _hierarchy.GetLogger(APPNAME); } public void LogCritical(string message, Exception ex) { LoggingEventData loggingEventData = new LoggingEventData { Message = message, Level = Level.Critical, Domain = AppDomain.CurrentDomain.FriendlyName, ThreadName = Thread.CurrentThread.Name, ExceptionString = $"{ex}\n{ex.StackTrace}", TimeStampUtc = DateTime.UtcNow, LoggerName = APPNAME, UserName = Environment.UserName, LocationInfo = new LocationInfo(GetType()) }; // 传正确的logger仓库,不要传null LoggingEvent loggingEvent = new LoggingEvent( callerStackBoundaryDeclaringType: GetType(), repository: _hierarchy, data: loggingEventData); _logger.Log(loggingEvent); } public void Dispose() { // 服务释放时主动关闭appender,刷新缓冲区剩余日志 _logzioAppender.Close(); _hierarchy.Shutdown(); } }
配置注意事项
- 依赖注入注册时直接按单例生命周期注册即可,DI容器会自动在应用退出时调用服务的Dispose方法刷新缓冲区:
builder.Services.AddSingleton<ILogzioService, LogzioService>();
- 首次调试时保持
AddDebug(true),可以在程序输出窗口看到Logz.io appender的内部日志,包括网络连通性、鉴权失败、上报成功/失败的具体原因,确认上报正常后再改成false关闭调试日志。 - 确认账号所属区域匹配监听地址:西欧盟区Azure确实对应
listener-nl.logz.io:8071,其他区域需要替换对应地址,否则会出现token鉴权失败。 - 上报后如果Kibana查不到数据,先把时间范围放大到最近15分钟,Logz.io日志入库存在10-30秒的延迟,不要仅查询最近1分钟的数据。
内容的提问来源于stack exchange,提问作者johnykes
相关产品推荐
相关产品推荐

