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

发布于 2024-10-15 05:54:28 字数 356 浏览 1 评论 0原文

经过深思熟虑后,我选择了 log4Net 作为我的日志应用程序,所以请不要争论,

好吧,听听是我的问题,

  • 我有一个进程连接到多个客户端,
  • 每个客户端都有一个唯一的 ID,作为字符串存储在其自己的单独线程中
  • 具有相同唯一 ID 的每个客户端可以连接多次

  • 我想在不同的 .txt 文件中为每个客户端创建一个日志文件。

  • 在每个新连接中,我想创建一个日志文件,其中的客户端 ID 附加有日期时间和秒数。

这种情况让我很困惑,因为我以前根本没有任何应用程序的任何日志记录经验。

我希望我已经把我的场景说得足够清楚了:)

I chose log4Net after much considerations to be my Logging application so please no arguments on that

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
  • Each Client with the same unique ID can connect multiple times

  • I want to create a log file for every Client in a different .txt file.

  • At every new connection, i want to create a log file with client ID appended by Date Time and seconds

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 :)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

川水往事 2024-10-22 05:54:28

这并没有回答您如何将请求写入自己的文件的问题,但 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 对象来命名他们的输出文件,如以下链接中所述:

< a href="http://geekswithblogs.net/rgupta/archive/2009/03/03/dynamic-log-filenames-with-log4net.aspx" rel="nofollow noreferrer">http://geekswithblogs.net/rgupta /archive/2009/03/03/dynamic-log-filenames-with-log4net.aspx

每当我看到通过 GlobalContext 命名输出文件的过程时,建议的解决方案总是说一定要设置Log4net 实际启动之前的 GlobalContext.Properties["whatever"] 值。这让我相信,根据动态存储在 ThreadContext 中的信息创建单独的日志文件(如果不是不可能的话)将是很困难的,因为在 log4net 运行之前可能不会知道该信息。

[更新]

这是 SO 上的另一个链接,说明如何为 GlobalContext 中的值命名输出文件。再次注意,在配置 log4net 之前和检索记录器之前,必须将文件名所基于的值设置到 GlobalContext 中。

如何在 log4net 附加程序名称中使用 GlobalContext 属性?

我在上面和评论中说过,我不确定 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 对象)。

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. Use the ThreadContext.Properties object and other properties to decorate the log messages so that it is possible to distinguish messages from each request.

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:

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.

This will cause each logged message to be tagged with the relevant ClientID.

See this link for a good tutorial on using the log4net context objects:

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.

Here is Part 1:

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:

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. 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.

[UPDATE]

Here is another link from here at SO that illustrates how to name the output file for a value in the 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.

How do I use a GlobalContext property in a log4net appender name?

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. Maybe someone else who is more familiar with log4net can weigh in on that.

Having said that, it is possible to do exactly this in 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):

<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.

Similarly, with this configuration (note ${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).

煮茶煮酒煮时光 2024-10-22 05:54:28

谢谢你们的所有回答和帮助,但经过很多很多很多搜索,我终于找到了答案....我不仅可以创建多个文件,而且可以使用动态文件名。希望这也对你们有帮助:)

这个想法不是基于配置文件,因为正如大家所说,一个 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);
}

现在,我们要做的是创建一个具有指定名称的记录器,并随时随地在任何线程或任何地方获取它对于任何类,我们甚至可以获取创建的附加程序,并在需要时通过使用命令

     log4net.LogManager.GetRepository().GetAppenders()

并迭代它来修改它。所以实际上一切都是动态的:)

Woops 忘记添加原始源代码:
Log4Net 邮件存档

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

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

     log4net.LogManager.GetRepository().GetAppenders()

and iterating through it. So actually everything is Dynamic :)

Woops forgot to add in the orignal source:
Log4Net Mail archive

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文