简体   繁体   English

使用log4Net在单个进程中记录多个客户端的帮助

[英]Logging help for Multiple Clients in a single process using log4Net

I chose log4Net after much considerations to be my Logging application so please no arguments on that 经过多次考虑后我选择了log4Net作为我的Logging应用程序,所以请不要争论

OK, hear is my problem 好的,听到是我的问题

  • I got a single process connected to multiple Clients 我有一个连接到多个客户端的进程
  • Each Client has a unique ID stored as a String in its own separate Thread 每个客户端都有一个唯一的ID,在其自己的独立线程中存储为String
  • Each Client with the same unique ID can connect multiple times 具有相同唯一ID的每个客户端可以多次连接

  • I want to create a log file for every Client in a different .txt file. 我想为另一个.txt文件中的每个客户端创建一个日志文件。

  • At every new connection, i want to create a log file with client ID appended by Date Time and seconds 在每个新连接,我想创建一个日期文件,其客户端ID附加日期时间和秒

This scenario has got me confused since i also don't have any previous logging experience of any application at all. 这个场景让我感到困惑,因为我根本没有任何应用程序的任何日志记录经验。

I hope i have made my scenario clear enough :) 我希望我的场景足够清晰:)

This does not answer you question for how to write the requests to their own files, but the log4net Help specifically recommends a simpler approach. 对于如何将请求写入自己的文件,这不能回答您的问题,但log4net帮助特别推荐了一种更简单的方法。 Use the ThreadContext.Properties object and other properties to decorate the log messages so that it is possible to distinguish messages from each request. 使用ThreadContext.Properties对象和其他属性来装饰日志消息,以便可以区分每个请求的消息。

http://logging.apache.org/log4net/release/faq.html http://logging.apache.org/log4net/release/faq.html

See "Can the outputs of multiple client request go to different log files?" 请参阅“多个客户端请求的输出是否可以转到不同的日志文件?”

If you have a Client ID, you could certainly do something like this: 如果您有客户端ID,您当然可以这样做:

log4net.ThreadContext.Properties["ClientID"] = GetTheClientId();

In your pattern layout, you can do something like this: 在您的模式布局中,您可以执行以下操作:

<conversionPattern value="%date [%thread] %-5level %logger [%property{ClientID}] - %message%newline" />

Where %property{ClientID} will pull your ClientID from the ThreadContext. %property{ClientID}将从ThreadContext中提取ClientID。

This will cause each logged message to be tagged with the relevant ClientID. 这将导致每条记录的消息都标记有相关的ClientID。

See this link for a good tutorial on using the log4net context objects: 有关使用log4net上下文对象的详细教程,请参阅此链接:

http://www.beefycode.com/post/Log4Net-Tutorial-pt-6-Log-Event-Context.aspx http://www.beefycode.com/post/Log4Net-Tutorial-pt-6-Log-Event-Context.aspx

The entire log4net tutorial is very good, especially if you are just starting out with log4net. 整个log4net教程非常好,特别是如果你刚刚开始使用log4net。

Here is Part 1: 这是第1部分:

http://www.beefycode.com/post/Log4Net-Tutorial-pt-1-Getting-Started.aspx http://www.beefycode.com/post/Log4Net-Tutorial-pt-1-Getting-Started.aspx

Having said all of that, people do often use the GlobalContext object to name their output file, such as is described in this link: 说完所有这些后,人们经常使用GlobalContext对象来命名他们的输出文件,如此链接中所述:

http://geekswithblogs.net/rgupta/archive/2009/03/03/dynamic-log-filenames-with-log4net.aspx http://geekswithblogs.net/rgupta/archive/2009/03/03/dynamic-log-filenames-with-log4net.aspx

Whenever I have seen the process of naming the output file via the GlobalContext, the suggested solution ALWAYS says to be sure to set the GlobalContext.Properties["whatever"] value BEFORE log4net actually starts. 每当我看到通过GlobalContext命名输出文件的过程时,建议的解决方案总是说要确保在log4net实际启动之前设置GlobalContext.Properties [“whatever”]值。 This leads me to believe that it will be difficult, if not impossible, to create individual log files based on information that is dynamically stored in the ThreadContext, since that information probably won't be known until log4net is already running. 这使我相信,即使不是不可能,也很难根据动态存储在ThreadContext中的信息创建单独的日志文件,因为在log4net已经运行之前可能无法知道该信息。

[UPDATE] [UPDATE]

Here is another link from here at SO that illustrates how to name the output file for a value in the GlobalContext. 这是SO的另一个链接,它说明了如何为GlobalContext中的值命名输出文件。 Note again that the value that filename is to be based on must be set into the GlobalContext before log4net is configured and before a logger is retrieved. 请再次注意,在配置log4net之前和检索记录器之前,必须将文件名所基于的值设置到GlobalContext中。

How do I use a GlobalContext property in a log4net appender name? 如何在log4net appender名称中使用GlobalContext属性?

As I say above and in my comments, I am not sure that it is possible for log4net to create multiple output files (for the same FileAppender configuration) with the output filename(s) dictated by a value in the ThreadContext or by the thread id property. 正如我在上面和我的评论中所说,我不确定log4net是否有可能创建多个输出文件(对于相同的FileAppender配置),其输出文件名由ThreadContext中的值或线程id指示属性。 Maybe someone else who is more familiar with log4net can weigh in on that. 也许对log4net更熟悉的其他人可以权衡一下。

Having said that, it is possible to do exactly this in NLog. 话虽如此,在NLog中可以做到这一点。 Here is an NLog configuration that defines a File Target whose name is derived, in part, from the thread id (note ${threadid} in the fileName portion of the configuration): 这是一个NLog配置,它定义了一个文件目标,其名称部分来自线程id(注意配置的fileName部分中的${threadid} ):

<targets>
    <target name="file" xsi:type="File" layout="${longdate} | ${processid} | ${threadid} | ${logger} | ${level} | ${message}" fileName="${basedir}/log_${threadid}.txt" />
</targets>

With the following code: 使用以下代码:

  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");
    }
  }

I got 4 log files, each of whose name contains the thread id and each of which contained messages only from a single thread. 我有4个日志文件,每个文件的名称都包含线程ID,每个文件只包含来自单个线程的消息。

Similarly, with this configuration (note ${mdc:item=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>

And this code: 这段代码:

  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");
    }
  }

I am able to get multiple output files based on the value stored in the MDC (the NLog equivalent to log4net's ThreadContext.Properties object). 我能够根据存储在MDC中的值(NLog等效于log4net的ThreadContext.Properties对象)获取多个输出文件。

Thank-you guys for all your answers and help but after lots and lots and lots of searching i finally found the answer .... not only i can create multiple Files but with dynamic file names.Hope this helps you guys as well :) 谢谢你们所有的答案和帮助,但经过大量的搜索后,我终于找到了答案....不仅我可以创建多个文件,而且还有动态文件名。希望这对你们有帮助:)

The idea is not to be based on a config file because as everybody said, one Appender is associated with one file name so one might be able to give one appender a dynamic file name but still not N number of File names 这个想法不是基于配置文件,因为每个人都说,一个Appender与一个文件名相关联,因此可以给一个appender一个动态文件名,但仍然不是N个文件名

so my configuration is as follows 所以我的配置如下

<configuration>
  <configSections>
    <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net"/>
  </configSections>

  <log4net>
  </log4net>

</configuration>

[UPDATE]: Actually you dont even need any config Yes, my configuration is empty, since i plan on to create dynamic configurations [更新]:其实你甚至不需要任何配置是的,我的配置是空的,因为我打算创建动态配置

Here is the code: 这是代码:

Main: 主要:

SetLevel(clientID, "ALL");
AddAppender(clientID, CreateFileAppender(clientID, fileName));

ILog log = LogManager.GetLogger(clientID);
log.Any("whatever you want");

Functions: 功能:

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);
}

Now, what we do is create a logger with a specified name, and fetch it whenever and wherever we want in any thread or any class, one can even fetch a created appender and modify it if required by using the command 现在,我们要做的是创建一个具有指定名称的记录器,并在任何线程或任何类中随时随地获取它,甚至可以获取创建的appender并在需要时使用该命令对其进行修改

     log4net.LogManager.GetRepository().GetAppenders()

and iterating through it. 并通过它迭代。 So actually everything is Dynamic :) 所以实际上一切都是动态:)

Woops forgot to add in the orignal source: Log4Net Mail archive Woops忘了添加orignal源: Log4Net Mail存档

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM