如何使用 log4net 每个任务登录到不同的文件?
Posted
技术标签:
【中文标题】如何使用 log4net 每个任务登录到不同的文件?【英文标题】:How to log into a different file per Task with log4net? 【发布时间】:2021-11-25 15:25:56 【问题描述】:我开发了一个并行运行多个任务的应用程序。为了使应用程序的日志文件更易于阅读,我希望这些任务中的每一个都通过 log4net 登录到自己的日志文件中。 此外,我还希望在任务之外记录的所有内容都记录到“主”日志文件中,因此每个任务都有一个日志文件,还有一个日志文件,其中包含除任务内记录的内容之外的所有内容。 这是我当前的 log4net 配置 xml:
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<configSections>
<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net" />
</configSections>
<log4net>
<appender name="MainRollingLogFileAppender" type="log4net.Appender.RollingFileAppender">
<filter type="log4net.Filter.PropertyFilter">
<key value="LogicName" />
<regexToMatch value="^(?!Main$).*$" />
<acceptOnMatch value="false" />
</filter>
<param name="File" value="C:\Temp\Test\Main.log" />
<appendToFile value="true" />
<rollingStyle value="Size" />
<maxSizeRollBackups value="100" />
<maximumFileSize value="10MB" />
<staticLogFileName value="true" />
<datePattern value="yyyyMMdd" />
<lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
<layout type="log4net.Layout.PatternLayout, log4net">
<conversionPattern value="%date [%thread] %-5level %logger: %message%newline" />
</layout>
</appender>
<appender name="TaskRollingLogFileAppender" type="log4net.Appender.RollingFileAppender">
<filter type="log4net.Filter.PropertyFilter">
<key value="LogicName" />
<regexToMatch value="^(?!Main$).*$" />
</filter>
<filter type="log4net.Filter.DenyAllFilter" />
<file type="log4net.Util.PatternString" value="C:\Temp\Test\%propertyLogicName.log" />
<appendToFile value="true" />
<rollingStyle value="Size" />
<maxSizeRollBackups value="100" />
<maximumFileSize value="10MB" />
<datePattern value="yyyyMMdd" />
<lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
<layout type="log4net.Layout.PatternLayout, log4net">
<conversionPattern value="%date [%thread] %-5level %logger: %message%newline" />
</layout>
</appender>
<root>
<level value="ALL" />
<appender-ref ref="MainRollingLogFileAppender" />
<appender-ref ref="LogicRollingLogFileAppender" />
</root>
</log4net>
</configuration>
在创建单个任务时,我立即运行这行代码来设置该任务的当前逻辑名称(logicName
包含当前任务中执行的逻辑名称):
log4net.LogicalThreadContext.Properties["LogicName"] = logicName;
每个任务都是这样开始的:
Task.Run(async () =>
await executeLogic(); // The first line in this function sets the logicName in the LogicalThreadContext
, cancellationToken);
遗憾的是,这一切只是创建一个在应用程序运行时保持为空的 Main.log
文件和一个包含所有应用程序日志的 (null).log
文件。
理想情况下,我希望在 LogicalThreadContext 中没有指定 LogicName
的所有内容都自动记录在主日志文件中。
我的 log4net 配置必须看起来如何才能使其正常工作?
【问题讨论】:
【参考方案1】:由于每个RollingFileAppender
都有一个文件句柄,因此不可能使用相同的附加程序动态创建新文件。在这种情况下,您不能使用配置文件 - 您必须在每次创建新的 Thread
时以编程方式创建新的附加程序。
这是一个如何实现这一目标的示例。来自Main
的所有日志都将发送到Main.log
,每个线程都有自己的日志文件。
using log4net;
using log4net.Appender;
using log4net.Config;
using log4net.Filter;
using log4net.Layout;
using System.Threading;
using System.Threading.Tasks;
namespace AppenderTest
static class Program
static ILog log;
static void Main(string[] args)
ConfigureAppender("Main");
log = LogManager.GetLogger(typeof(Program));
log.Info("Starting from Main!");
Task task1 = Task.Run(() => NewThread("LogicName1"));
log.Info("Hello from Main!");
Task task2 = Task.Run(() => NewThread("LogicName2"));
log.Info("Hello again from Main!");
Task.WaitAll(task1, task2);
log.Info("Still from Main!");
public static void NewThread(string name)
ConfigureAppender(name);
for (int i = 0; i < 10; i++)
Thread.Sleep(50);
log.Info($"Loop index i");
private static void ConfigureAppender(string name)
RollingFileAppender appender = new RollingFileAppender
Name = $"nameAppender",
File = $"name.log"
;
PatternLayout layout = new PatternLayout
ConversionPattern = "%datehh:mm:ss.fff %level %thread %logger %propertyLogicName - %message%newline"
;
layout.ActivateOptions();
appender.Layout = layout;
PropertyFilter filter = new PropertyFilter
Key = "LogicName",
StringToMatch = name,
AcceptOnMatch = true
;
filter.ActivateOptions();
appender.AddFilter(filter);
appender.AddFilter(new DenyAllFilter());
appender.ActivateOptions();
LogicalThreadContext.Properties["LogicName"] = name;
BasicConfigurator.Configure(appender);
【讨论】:
以上是关于如何使用 log4net 每个任务登录到不同的文件?的主要内容,如果未能解决你的问题,请参考以下文章