我经过多次考虑后选择了log4Net作为我的Logging应用程序,所以请不要论这个
好的,听到是我的问题
具有相同唯一ID的每个客户端可以多次连接
我想为另一个.txt文件中的每个客户端创建一个日志文件。
这个场景让我感到困惑,因为我根本没有任何应用程序的任何日志记录经验。
我希望我的场景足够清晰:)
答案 0 :(得分:3)
这对于如何将请求写入自己的文件没有回答您的问题,但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" />
%property{ClientID}
将从ThreadContext中提取您的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已经运行之前可能无法知道该信息。
<强> [UPDATE] 强>
这是SO的另一个链接,它说明了如何为GlobalContext中的值命名输出文件。请再次注意,在配置log4net之前和检索记录器之前,必须将文件名所基于的值设置到GlobalContext中。
How do I use a GlobalContext property in a log4net appender name?
正如我在上面和我的评论中所说,我不确定log4net是否可以创建多个输出文件(对于相同的FileAppender配置),其输出文件名由ThreadContext中的值或由线程id属性。也许其他对log4net更熟悉的人可以权衡这一点。
话虽如此,在NLog中可以做到这一点。这是一个NLog配置,它定义了一个文件目标,其名称部分来自线程id(配置的fileName部分中的注释${threadid}
):
<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中的值(NLog等效于log4net的ThreadContext.Properties对象)获取多个输出文件。
答案 1 :(得分:2)
谢谢你们所有的答案和帮助,但经过大量的搜索后我终于找到了答案....不仅我可以创建多个文件,而且还有动态文件名。希望这可以帮助你们好吧:))
这个想法不是基于配置文件,因为每个人都说,一个Appender与一个文件名相关联,因此可以给一个appender一个动态文件名,但仍然不是N个文件名
所以我的配置如下
<configuration>
<configSections>
<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net"/>
</configSections>
<log4net>
</log4net>
</configuration>
[更新]:其实你甚至不需要任何配置 是的,我的配置是空的,因为我打算创建动态配置
以下是代码:
主:
SetLevel(clientID, "ALL");
AddAppender(clientID, CreateFileAppender(clientID, fileName));
ILog log = LogManager.GetLogger(clientID);
log.Any("whatever you want");
功能:
public static log4net.Appender.IAppender CreateFileAppender(string name, string fileName)
{
log4net.Appender.FileAppender appender = new
log4net.Appender.FileAppender();
appender.Name = name;
appender.File = fileName;
appender.AppendToFile = false;
log4net.Layout.PatternLayout layout = new
log4net.Layout.PatternLayout();
layout.ConversionPattern = "%d [%thread] %-5p %c [%a] - %m [%line] [%M]%n";
layout.ActivateOptions();
appender.Layout = layout;
appender.ActivateOptions();
return appender;
}
public static void SetLevel(string loggerName, string levelName)
{
log4net.ILog log = log4net.LogManager.GetLogger(loggerName);
log4net.Repository.Hierarchy.Logger l = (log4net.Repository.Hierarchy.Logger)log.Logger;
l.Level = l.Hierarchy.LevelMap[levelName];
}
// Add an appender to a logger
public static void AddAppender(string loggerName, log4net.Appender.IAppender appender)
{
log4net.ILog log = log4net.LogManager.GetLogger(loggerName);
log4net.Repository.Hierarchy.Logger l=(log4net.Repository.Hierarchy.Logger)log.Logger;
l.AddAppender(appender);
}
现在,我们要做的是创建一个具有指定名称的记录器,并在任何线程或任何类中随时随地获取它,甚至可以获取创建的appender并根据需要使用命令修改它
log4net.LogManager.GetRepository().GetAppenders()
并迭代它。所以实际上一切都是动态的:)
Woops忘了加入orignal来源: Log4Net Mail archive