log4net: разные журналы для разных файловых приложений во время выполнения
Доброе утро, парни.
Я написал единственное приложение istance C# 2.0 (назовите его myapp).
Myapp вызывается много раз, и при каждом вызове генерирует своего рода "задачу", которая будет выполняться в отдельном потоке.
Если вы вызываете myapp несколько раз за короткое время, задача выполняется параллельно.
Обычно я использую log4net для регистрации; Я настраиваю его загрузку xml файла XmlConfigurator.Configure(<config>.xml)
при запуске я использую статический LogManager.GetLogger(name)
в каждом классе мне нужен регистратор, довольно просто.
Этот сценарий сложен, вместо этого. Мне нужно сделать следующее: на основе одного из аргументов, полученных при каждом вызове (назовите его arg), мне нужно получить другой RollingFileAppender, который регистрирует в другом файле, например,.log.
Просто для примера:
1-й звонок: myapp.exe -arg:01
- myapp создает поток1
- установить новый RollingFileAppender в файл 01.log, если он не существует
- объекты, используемые в этой теме, должны войти в файл 01.log
2-й звонок: myapp.exe -arg:02
- создать тему2
- установить новый RollingFileAppender в файл 02.log, если он не существует
- объекты, используемые в этой теме, должны войти в файл 02.log, но не в log.01
3-й звонок: myapp.exe -arg:01
- создать тему 03
- получить файл RollingFileAppender to 01.log (он уже существует!)
- объекты, используемые в этой теме, должны войти в файл 01.log, но не в log.02
И так далее. Мне не нужно оставлять конфигурацию RollingAppender в XML-файле, я могу создать ее программно; моя идея состоит в том, чтобы использовать статический класс-обертку, назовите его LogHelper, который создает дополнения, если они не существуют на основе аргумента arg, и отправляет правильные значения ILog, когда это необходимо для объектов (в классах я использовал бы что-то вроде ILog log = LogHelper.GetLogger(name, arg
) чтобы использовать регистратор вместо метода по умолчанию log4net LogManager.GetLogger(name)
). Так что, если у меня есть 2 экземпляра одного и того же класса в 2 разных потоках, когда я регистрирую сообщения, по одному идет на файл, в зависимости от аргумента (я буду вставлять аргумент в каждый объект, если это необходимо).
Я просматриваю множество тем здесь, в Stackru, но не могу найти решение.
Может ли кто-нибудь указать мне правильное направление?
Заранее спасибо.
2 ответа
Я закончил с немного другим решением.
Я создал LogMaster
статический класс (извините за плохое имя), который работает аналогично стандартному log4net LogManager
учебный класс.
Разница в том, что вы можете получить разные ILog
Истины основаны на arg
: 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);
Используя это решение, вы можете извлечь выгоду из извлечения поведения LogManager по умолчанию ILog
регистраторы: если регистратор с таким именем уже существует в репозитории, вы вернете этот момент (поведение утилизации).
Спасибо @making3 за ваши предложения!
Я сделал что-то похожее, где мне нужны разные журналы для каждого экземпляра класса. Вы можете создавать журналы динамически с помощью нескольких шагов.
Похоже, что Logger по умолчанию (строка 97) уже определен, но он является внутренним по отношению к их сборке, поэтому он должен быть унаследован (насколько я знаю).
public sealed class DynamicLogger : Logger
{
internal DynamicLogger(string name) : base(name)
{
base.Hierarchy = (log4net.Repository.Hierarchy.Hierarchy)LogManager.GetRepository();
}
}
Пример метода для получения ILog:
public static ILog GetSample(string arg)
{
var logger = new DynamicLogger(arg);
logger.Level = Level.All;
var consoleAppender = new ConsoleAppender();
consoleAppender.Name = arg;
consoleAppender.Layout = new PatternLayout(arg + ": %m%newline");
logger.AddAppender(consoleAppender);
var newLog = new LogImpl(logger);
if (_logs.Any(log => log.Logger.Name == newLog.Logger.Name) == false)
_logs.Add(newLog);
return newLog;
}
Основное использование:
var foo = DynamicLog.GetSample("foo");
var bar = DynamicLog.GetSample("bar");
foo.Error("Test");
bar.Error("Test");
Для вашего сценария посмотрите на создание RollingFileAppender
и посмотрите на доступные свойства объекта, так как это был всего лишь пример.
РЕДАКТИРОВАТЬ: Добавлено ниже для хранения ILog, и изменил оригинал GetSample
метод выше.
Добавьте массив методов ILog и GetLogger:
private static List<ILog> _logs = new List<ILog>();
public static ILog GetLogger(string name)
{
return _logs.SingleOrDefault(a => a.Logger.Name == name);
}
Пример использования:
DynamicLog.GetSample("foo");
var foo = DynamicLog.GetLogger("foo");