如何在NLog中根据日志消息生成对应文件名?
解决NLog 5.2.4的两个问题:按IP端口分日志文件+共享ILogger添加自定义属性
一、正确按IP:Port生成目标日志文件
你之前的配置问题主要有两点:一是提取的IP:Port包含文件名不允许的冒号,二是正则匹配可靠性不足,直接从${message}提取也容易受消息格式变化影响。
修正后的配置(仍从message提取的方案)
如果必须基于现有message格式提取,可嵌套${replace}先提取[]内的IP:Port,再替换冒号为下划线:
<target xsi:type="AsyncWrapper" name="testAsync" queueLimit="50000" timeToSleepBetweenBatches="0" batchSize="500" overflowAction="Grow"> <target name="testFile" layout="${longdate} ${level:uppercase=true} ${logger} ${message} ${exception:format=ToString:innerFormat=ToString:maxInnerExceptionLevel=5}" fileName="Log/test_${replace:searchFor=: :replaceWith=_:input=${replace:regex=true:searchFor=^\[([^\]]+)\].*:replaceWith=$1:input=${message:raw=true}}}.log" xsi:type="File" maxArchiveFiles="5" archiveAboveSize="10000000" /> </target>
${message:raw=true}确保消息原始内容被正则处理,避免转义干扰- 第一层
replace提取[]内的完整内容(比如127.0.0.1:50543) - 第二层
replace把冒号替换为下划线,生成合法文件名
二、更可靠的方案:给共享ILogger添加自定义属性
直接从message提取容易因格式变动失效,推荐给日志事件添加自定义属性,多个对象共享ILogger时也能轻松区分上下文:
代码中添加自定义属性
有两种常用方式:
- 使用日志Scope(适合上下文绑定的场景)
// 每个对象处理请求时,创建包含IpPort的Scope using (logger.BeginScope(new Dictionary<string, object> { { "IpPort", "127.0.0.1:50543" } })) { logger.LogInformation("Here comes some text ...."); }
- 直接在日志调用时传入属性
// 日志时直接附带IpPort属性 logger.LogInformation("{Message}", new { IpPort = "127.0.0.1:50543", Message = "Here comes some text ...." });
对应NLog配置
配置中直接引用自定义属性,无需再解析message:
<target xsi:type="AsyncWrapper" name="testAsync" queueLimit="50000" timeToSleepBetweenBatches="0" batchSize="500" overflowAction="Grow"> <target name="testFile" layout="${longdate} ${level:uppercase=true} ${logger} ${event-properties:Message} ${exception:format=ToString:innerFormat=ToString:maxInnerExceptionLevel=5}" fileName="Log/test_${replace:searchFor=: :replaceWith=_:input=${event-properties:IpPort}}.log" xsi:type="File" maxArchiveFiles="5" archiveAboveSize="10000000" /> </target>
${event-properties:IpPort}直接获取代码中传入的自定义属性值${event-properties:Message}获取日志消息内容(对应代码里的Message字段)
内容的提问来源于stack exchange,提问作者Tundy
相关产品推荐
相关产品推荐

