Мне интересно узнать больше о том, как люди внедряют протоколирование с помощью платформ внедрения зависимостей. Хотя ссылки ниже и мои примеры относятся к log4net и Unity, я не обязательно буду использовать ни один из них. Для внедрения зависимостей / IOC я, вероятно, буду использовать MEF, поскольку это стандарт, на котором основывается остальная часть проекта (большая).
Я очень плохо знаком с внедрением зависимостей / ioc и довольно плохо знаком с C # и .NET (написал очень мало рабочего кода на C # /. NET после последних 10 лет или около того VC6 и VB6). Я провел много исследований различных решений для ведения журналов, которые существуют, поэтому я думаю, что у меня есть приличный контроль над их наборами функций. Я просто недостаточно знаком с реальной механикой внедрения одной зависимости (или, может быть, более "правильно", получения абстрактной версии одной зависимости).
Я видел другие сообщения, связанные с ведением журнала и / или внедрением зависимостей, например:
интерфейсы внедрения и регистрации зависимостей
Регистрация лучших практик
Как будет выглядеть класс Log4Net Wrapper?
снова о log4net и конфигурации Unity IOC
Мой вопрос не имеет ничего общего с темой «Как внедрить платформу журналирования xxx с помощью ioc tool yyy?» Скорее меня интересует, как люди справляются с переносом платформы ведения журналов (как это часто бывает, но не всегда рекомендуется) и конфигурацией (то есть app.config). Например, используя в качестве примера log4net, я мог бы настроить (в app.config) несколько регистраторов, а затем получить эти регистраторы (без внедрения зависимостей) стандартным способом использования кода, подобного следующему:
private static readonly ILog logger = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
В качестве альтернативы, если мой регистратор не назван для класса, а скорее для функциональной области, я мог бы сделать это:
private static readonly ILog logger = LogManager.GetLogger("Login");
private static readonly ILog logger = LogManager.GetLogger("Query");
private static readonly ILog logger = LogManager.GetLogger("Report");
Итак, я предполагаю, что мои "требования" будут примерно такими:
Я бы хотел изолировать источник моего продукта от прямой зависимости от платформы ведения журналов.
Я хотел бы иметь возможность разрешить конкретный именованный экземпляр регистратора (возможно, совместно использовать один и тот же экземпляр среди всех запрашивающих экземпляров с одинаковым именованным экземпляром) прямо или косвенно с помощью какого-либо внедрения зависимости, возможно, MEF. *
Я не знаю, назову ли я это жестким требованием, но мне бы хотелось иметь возможность получать именованный регистратор (отличный от регистратора классов) по требованию. Например, я мог бы создать регистратор для своего класса на основе имени класса, но один метод требует особенно тяжелой диагностики, которую я хотел бы контролировать отдельно. Другими словами, я бы хотел, чтобы один класс «зависел» от двух отдельных экземпляров регистратора.
Давайте начнем с номера 1. Я прочитал ряд статей, в первую очередь здесь, о stackoverflow, о том, стоит ли оборачивать это хорошей идеей. Посмотрите ссылку "лучшие практики" выше и перейдите к комментарию jeffrey hantin , чтобы узнать, почему плохо оборачивать log4net. Если бы вы сделали обертывание (и если бы вы могли обернуть его эффективно), вы бы обернули его строго с целью инъекции / удаления прямой зависимости? Или вы также попытаетесь абстрагироваться от части или всей информации log4net app.config?
Допустим, я хочу использовать System.Diagnostics. Возможно, я бы хотел реализовать основанный на интерфейсе регистратор (может быть, даже используя «общий» интерфейс ILogger / ILog), возможно, на основе TraceSource, чтобы я мог внедрить его. Вы бы реализовали интерфейс, скажем, через TraceSource, и просто использовали бы информацию System.Diagnostics app.config как есть?
Примерно так:
public class MyLogger : ILogger
{
private TraceSource ts;
public MyLogger(string name)
{
ts = new TraceSource(name);
}
public void ILogger.Log(string msg)
{
ts.TraceEvent(msg);
}
}
И используйте это так:
private static readonly ILogger logger = new MyLogger("stackoverflow");
logger.Info("Hello world!")
Переходя к номеру 2 ... Как разрешить конкретный именованный экземпляр регистратора? Должен ли я просто использовать информацию app.config выбранной мной платформы ведения журналов (то есть разрешить регистраторы на основе схемы именования в app.config)? Итак, в случае log4net, я мог бы предпочесть «внедрить» LogManager (обратите внимание, что я знаю, что это невозможно, так как это статический объект)? Я мог бы обернуть LogManager (назовите его MyLogManager), дать ему интерфейс ILogManager, а затем разрешить интерфейс MyLogManager.ILogManager. Другие мои объекты могут иметь зависимость (на языке импорта на MEF) от ILogManager (экспорт из сборки, в которой он реализован). Теперь у меня могут быть такие объекты:
public class MyClass
{
private ILogger logger;
public MyClass([Import(typeof(ILogManager))] logManager)
{
logger = logManager.GetLogger("MyClass");
}
}
Каждый раз, когда вызывается ILogManager, он напрямую делегирует LogManager log4net. Кроме того, может ли обернутый LogManager взять экземпляры ILogger, которые он получает на основе app.config, и добавить их в контейнер (a?) MEF по имени. Позже, когда запрашивается логгер с тем же именем, обернутый LogManager запрашивается для этого имени. Если есть ILogger, он решается таким образом. Если это возможно с MEF, есть ли какая-то выгода для этого?
В этом случае, действительно, только «ILogManager» «внедряется», и он может раздавать экземпляры ILogger так, как это обычно делает log4net. Как этот тип внедрения (по существу, фабричный) сравнивается с внедрением именованных экземпляров регистратора? Это позволяет более легко использовать файл app.config log4net (или другой платформы ведения журналов).
Я знаю, что могу получить именованные экземпляры из контейнера MEF следующим образом:
var container = new CompositionContainer(<catalogs and other stuff>);
ILogger logger = container.GetExportedValue<ILogger>("ThisLogger");
Но как мне получить именованные экземпляры в контейнер? Я знаю о модели на основе атрибутов, где у меня могут быть разные реализации ILogger, каждая из которых названа (через атрибут MEF), но это мне не очень помогает. Есть ли способ создать что-то вроде app.config (или раздел в нем), который бы перечислял регистраторы (все той же реализации) по имени и которые MEF мог читать? Может ли / должен быть центральный «менеджер» (например, MyLogManager), который разрешает именованные регистраторы через базовый app.config, а затем вставляет разрешенный регистратор в контейнер MEF? Таким образом, он будет доступен кому-то еще, у которого есть доступ к тому же контейнеру MEF (хотя без знания MyLogManager о том, как использовать информацию app.config log4net, кажется, что контейнер не сможет разрешить любые именованные регистраторы напрямую).
Это уже довольно долго. Я надеюсь, что это связно. Пожалуйста, не стесняйтесь делиться любой конкретной информацией о том, как ваша зависимость внедрила платформу журналирования (мы, скорее всего, рассматриваем log4net, NLog или что-то (возможно, тонкое), построенное на System.Diagnostics) в ваше приложение.
Вы вводили "manager" и возвращали ли он экземпляры логгера?
Вы добавили некоторую свою информацию о конфигурации в свой собственный раздел конфигурации или в раздел конфигурации своей платформы DI, чтобы упростить / сделать возможным непосредственное внедрение экземпляров регистратора (т. Е. Сделать ваши зависимости зависимыми от ILogger, а не ILogManager).
Как насчет наличия статического или глобального контейнера, в котором есть либо интерфейс ILogManager, либо набор именованных экземпляров ILogger. Таким образом, вместо введения в обычном смысле (через конструктор, свойство или данные элемента) зависимость ведения журнала явно разрешается по требованию. Это хороший или плохой способ внедрения зависимости.
Я отмечаю это как вики сообщества, так как это не похоже на вопрос с определенным ответом. Если кто-то чувствует себя иначе, смело меняйте его.
Спасибо за любую помощь!