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");
Другие вопросы по тегам