大家早上好
我写了一个单一的 C# 2.0 应用程序(称之为 myapp)。
Myapp 被多次调用,每次调用都会生成一种“任务”,将在单独的线程中执行。
如果您在短时间内多次调用 myapp,任务将并行执行。
通常我使用 log4net 进行日志记录;我通过 XmlConfigurator.Configure(<config>.xml)
配置它加载一个 xml 文件在启动时,然后我使用静态 LogManager.GetLogger(name)
在每个类中我都需要一个记录器,非常简单。
相反,这种情况具有挑战性。 我需要做的是:根据每次调用收到的参数之一(称之为 arg),我需要得到一个不同的 RollingFileAppender 来记录不同的文件,即。 G。 .log.
举个例子:
第一次通话:myapp.exe -arg:01
- myapp 创建线程 1
- 将新的 RollingFileAppender 设置为 01.log 文件,如果不存在的话
- 此线程中使用的对象必须记录在 01.log 文件中
第二次通话:myapp.exe -arg:02
- 创建线程 2
- 将新的 RollingFileAppender 设置为 02.log 文件,如果不存在的话
- 此线程中使用的对象必须记录在 02.log 文件中,但不能记录在 log.01
第三次通话:myapp.exe -arg:01
- 创建 thread03
- 将 RollingFileAppender 获取到 01.log 文件(它已经存在!)
- 此线程中使用的对象必须记录在 01.log 文件中,但不能记录在 log.02
等等。
我不需要将 RollingAppender 的配置留在 xml 文件中,我可以通过编程方式创建它;我的想法是使用一个静态包装器类,将其称为 LogHelper,如果附加器不存在,它会根据 arg 创建附加器,并在对象需要时分派(dispatch)正确的 ILog istances(在类中我会使用一些东西像 ILog log = LogHelper.GetLogger(name, arg
) 让记录器使用默认的 log4net 方法 LogManager.GetLogger(name)
).
因此,如果我在 2 个不同的线程中有 2 个相同类的实例,当我记录消息时,每个文件一个,取决于或 arg (我将在每个对象中注入(inject) arg,如果需要的话)。
我在 StackOverflow 中浏览了很多线程,但找不到解决方案。
有人能指出我正确的方向吗?
提前致谢。
最佳答案
我最终得到了一个稍微不同的解决方案。
我创建了一个与默认 log4net LogManager
类类似的 LogMaster
静态类(抱歉名字不好)。
不同之处在于你可以根据arg
得到不同的ILog
istances:LogMaster
会为每一个创建一个新的ILoggerRepository
您将使用不同的 arg
。
这里是代码:
#region Usings
using System;
using System.IO;
using log4net;
using log4net.Appender;
using log4net.Config;
using log4net.Core;
using log4net.Filter;
using log4net.Layout;
using log4net.Repository;
using log4net.Repository.Hierarchy;
#endregion
namespace Common.Voyager
{
/// <summary>
/// A static class that emulates defualt log4net LogManager static class.
/// The difference is that you can get various loggers istances based from an args.
/// LogMaster will create a different logger repository for each new arg it will receive.
/// </summary>
public static class LogMaster
{
#region Const
private const string RollingFileAppenderNameDefault = "Rolling";
private const string MemoryAppenderNameDefault = "Memory";
#endregion
#region Constructors
static LogMaster()
{
}
#endregion
#region Public Methods
public static ILog GetLogger(string arg, string name)
{
//It will create a repository for each different arg it will receive
var repositoryName = arg;
ILoggerRepository repository = null;
var repositories = LogManager.GetAllRepositories();
foreach (var loggerRepository in repositories)
{
if (loggerRepository.Name.Equals(repositoryName))
{
repository = loggerRepository;
break;
}
}
Hierarchy hierarchy = null;
if (repository == null)
{
//Create a new repository
repository = LogManager.CreateRepository(repositoryName);
hierarchy = (Hierarchy)repository;
hierarchy.Root.Additivity = false;
//Add appenders you need: here I need a rolling file and a memoryappender
var rollingAppender = GetRollingAppender(repositoryName);
hierarchy.Root.AddAppender(rollingAppender);
var memoryAppender = GetMemoryAppender(repositoryName);
hierarchy.Root.AddAppender(memoryAppender);
BasicConfigurator.Configure(repository);
}
//Returns a logger from a particular repository;
//Logger with same name but different repository will log using different appenders
return LogManager.GetLogger(repositoryName, name);
}
#endregion
#region Private Methods
private static IAppender GetRollingAppender(string arg)
{
var level = Level.All;
var rollingFileAppenderLayout = new PatternLayout("%date{HH:mm:ss,fff}|T%2thread|%25.25logger|%5.5level| %message%newline");
rollingFileAppenderLayout.ActivateOptions();
var rollingFileAppenderName = string.Format("{0}{1}", RollingFileAppenderNameDefault, arg);
var rollingFileAppender = new RollingFileAppender();
rollingFileAppender.Name = rollingFileAppenderName;
rollingFileAppender.Threshold = level;
rollingFileAppender.CountDirection = 0;
rollingFileAppender.AppendToFile = true;
rollingFileAppender.LockingModel = new FileAppender.MinimalLock();
rollingFileAppender.StaticLogFileName = true;
rollingFileAppender.RollingStyle = RollingFileAppender.RollingMode.Date;
rollingFileAppender.DatePattern = ".yyyy-MM-dd'.log'";
rollingFileAppender.Layout = rollingFileAppenderLayout;
rollingFileAppender.File = string.Format("{0}.{1}", "log", arg);
rollingFileAppender.ActivateOptions();
return rollingFileAppender;
}
private static IAppender GetMemoryAppender(string station)
{
//MemoryAppender
var memoryAppenderLayout = new PatternLayout("%date{HH:MM:ss} | %message%newline");
memoryAppenderLayout.ActivateOptions();
var memoryAppenderWithEventsName = string.Format("{0}{1}", MemoryAppenderNameDefault, station);
var levelRangeFilter = new LevelRangeFilter();
levelRangeFilter.LevelMax = Level.Fatal;
levelRangeFilter.LevelMin = Level.Info;
var memoryAppenderWithEvents = new MemoryAppenderWithEvents();
memoryAppenderWithEvents.Name = memoryAppenderWithEventsName;
memoryAppenderWithEvents.AddFilter(levelRangeFilter);
memoryAppenderWithEvents.Layout = memoryAppenderLayout;
memoryAppenderWithEvents.ActivateOptions();
return memoryAppenderWithEvents;
}
#endregion
}
}
用法:
var arg = "myArg";
var loggerName = "MyLogger";
var log = LogMaster.GetLogger(arg, loggerName);
使用此解决方案,您可以受益于检索 ILog
记录器的默认 LogManager 行为:如果存储库中已存在具有相同名称的记录器,您将取回该状态(回收行为)。
感谢@making3 的建议!
关于c# - log4net:运行时不同文件附加程序上的不同日志,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21022467/