这并没有回答您如何将请求写入自己的文件的问题,但 log4net 帮助特别推荐了一种更简单的方法。使用 ThreadContext.Properties 对象和其他属性来装饰日志消息,以便可以区分来自每个请求的消息。
http://logging.apache.org/log4net/release/faq.html
请参阅“多个客户端请求的输出可以转到不同的日志文件吗?”
如果你有一个客户 ID,你当然可以这样做:
log4net.ThreadContext.Properties["ClientID"] = GetTheClientId();
在您的模式布局中,您可以执行以下操作:
<conversionPattern value="%date [%thread] %-5level %logger [%property{ClientID}] - %message%newline" />
从 ThreadContext中%property{ClientID}
提取您的 ClientID 的位置。
这将导致每条记录的消息都用相关的 ClientID 进行标记。
有关使用 log4net 上下文对象的优秀教程,请参阅此链接:
http://www.beefycode.com/post/Log4Net-Tutorial-pt-6-Log-Event-Context.aspx
整个 log4net 教程非常好,特别是如果您刚刚开始使用 log4net。
这是第 1 部分:
http://www.beefycode.com/post/Log4Net-Tutorial-pt-1-Getting-Started.aspx
说了这么多,人们确实经常使用 GlobalContext 对象来命名他们的输出文件,例如这个链接中描述的:
http://geekswithblogs.net/rgupta/archive/2009/03/03/dynamic-log-filenames-with-log4net.aspx
每当我看到通过 GlobalContext 命名输出文件的过程时,建议的解决方案总是说要确保在 log4net 实际启动之前设置 GlobalContext.Properties["whatever"] 值。这使我相信,即使不是不可能,也很难根据动态存储在 ThreadContext 中的信息创建单独的日志文件,因为在 log4net 已经运行之前可能不会知道这些信息。
[更新]
这是来自此处的另一个链接,说明了如何为 GlobalContext 中的值命名输出文件。再次注意,文件名所基于的值必须在配置 log4net 之前和检索记录器之前设置到 GlobalContext 中。
如何在 log4net appender 名称中使用 GlobalContext 属性?
正如我在上面和我的评论中所说,我不确定 log4net 是否可以创建多个输出文件(对于相同的 FileAppender 配置),输出文件名由 ThreadContext 中的值或线程 id 指定财产。也许其他更熟悉 log4net 的人可以权衡一下。
话虽如此,在 NLog 中完全可以做到这一点。这是一个 NLog 配置,它定义了一个文件目标,其名称部分来自线程 id(请注意${threadid}
配置的 fileName 部分):
<targets>
<target name="file" xsi:type="File" layout="${longdate} | ${processid} | ${threadid} | ${logger} | ${level} | ${message}" fileName="${basedir}/log_${threadid}.txt" />
</targets>
使用以下代码:
class Program
{
public static Logger logger = LogManager.GetCurrentClassLogger();
static void Main(string[] args)
{
int totalThreads = 20;
TaskCreationOptions tco = TaskCreationOptions.None;
Task task = null;
logger.Info("Enter Main");
Task[] allTasks = new Task[totalThreads];
for (int i = 0; i < totalThreads; i++)
{
int ii = i;
task = Task.Factory.StartNew(() =>
{
logger.Info("Inside delegate. i = {0}", ii);
});
allTasks[i] = task;
}
logger.Info("Wait on tasks");
Task.WaitAll(allTasks);
logger.Info("Tasks finished");
logger.Info("Exit Main");
}
}
我有 4 个日志文件,每个文件的名称都包含线程 ID,每个文件只包含来自单个线程的消息。
同样,使用此配置(注${mdc:item=id}
):
<targets>
<target name="file" xsi:type="File" layout="${longdate} | ${processid} | ${threadid} | ${logger} | ${level} | ${message}" fileName="${basedir}/log_${mdc:item=id}.txt" />
</targets>
而这段代码:
class Program
{
public static Logger logger = LogManager.GetCurrentClassLogger();
static void Main(string[] args)
{
int totalThreads = 20;
TaskCreationOptions tco = TaskCreationOptions.None;
Task task = null;
logger.Info("Enter Main");
Task[] allTasks = new Task[totalThreads];
for (int i = 0; i < totalThreads; i++)
{
int ii = i;
task = Task.Factory.StartNew(() =>
{
MDC.Set("id",Thread.CurrentThread.ManagedThreadId.ToString());
logger.Info("Inside delegate. i = {0}", ii);
});
allTasks[i] = task;
}
logger.Info("Wait on tasks");
Task.WaitAll(allTasks);
logger.Info("Tasks finished");
logger.Info("Exit Main");
}
}
我能够根据存储在 MDC 中的值(相当于 log4net 的 ThreadContext.Properties 对象的 NLog)获取多个输出文件。