Подтвердить что ты не робот

Как настроить и включить log4net для самостоятельной сборки библиотеки классов?

Фон

Я пишу сборку библиотеки классов в С#.NET 3.5, которая используется для интеграции с другими приложениями, включая сторонние инструменты Commercial-Off-The-Shelf (COTS). Поэтому иногда эта библиотека классов вызывается приложениями (EXE), которые я управляю, в то время как другие вызовы будут вызываться другими DLL или приложениями, которые я выполняю не.

Предположения

  • Я использую С# 3.0,.NET 3.5 SP1 и Visual Studio 2008 SP1
  • Я использую log4net 1.2.10.0 или выше

Ограничения

Любое решение должно:

  • Разрешить библиотеке классов включать и настраивать ведение журнала через собственный файл конфигурации, если вызывающее приложение не настраивает log4net.
  • Разрешить библиотеке классов включать и настраивать ведение журнала через конфигурацию вызывающих приложений, если она указывает информацию log4net

ИЛИ

  • Разрешить библиотеке классов включать и настраивать ведение журнала с использованием собственного файла конфигурации в любое время.

Проблема

Когда моя автономная библиотека классов вызывается DLL или приложением, которое я не контролирую (например, сторонним инструментом COTS) и которое не указывает информацию о конфигурации log4net, моя библиотека классов не может его регистрации.


Вопрос

Как настроить и включить log4net для самостоятельной сборки библиотеки классов, чтобы он регистрировался независимо от того, предоставляет ли вызывающее приложение конфигурацию log4net?

4b9b3361

Ответ 1

Решение 1

Решение для первого набора ограничений состоит в том, чтобы в основном обернуть log4net.LogManager в собственный собственный класс LogManager, например Jacob, Jeroen и McWafflestix предложили (см. код ниже).

К сожалению, класс log4net.LogManager является статическим, а С# не поддерживает статическое наследование, поэтому вы не можете просто наследовать его и переопределить метод GetLogger. Однако в классе log4net.LogManager не так много методов, поэтому это, безусловно, возможно.

Другим недостатком этого решения является то, что если у вас есть существующая кодовая база (что я делаю в моем случае), вам придется заменить все существующие вызовы на log4net.LogManager с вашим классом-оболочкой. Тем не менее, не имеет большого значения сегодня инструменты рефакторинга.

Для моего проекта эти недостатки перевешивают преимущества использования конфигурации ведения журнала, предоставляемой вызывающим приложением, поэтому я пошел с решением 2.

код

Сначала вам нужен класс оболочки LogManager:

using System;
using System.IO;
using log4net;
using log4net.Config;

namespace MyApplication.Logging
{
    //// TODO: Implement the additional GetLogger method signatures and log4net.LogManager methods that are not seen below.
    public static class LogManagerWrapper
    {
        private static readonly string LOG_CONFIG_FILE= @"path\to\log4net.config";

        public static ILog GetLogger(Type type)
        {
            // If no loggers have been created, load our own.
            if(LogManager.GetCurrentLoggers().Length == 0)
            {
                LoadConfig();
            }
            return LogManager.GetLogger(type);
        }

        private void LoadConfig()
        {
           //// TODO: Do exception handling for File access issues and supply sane defaults if it unavailable.   
           XmlConfigurator.ConfigureAndWatch(new FileInfo(LOG_CONFIG_FILE));
        }              
}

Затем в ваших классах вместо

private static readonly ILog log = LogManager.GetLogger(typeof(MyApp));

Использование:

private static readonly ILog log = LogManagerWrapper.GetLogger(typeof(MyApp));

Решение 2

В моих целях я решил решить решение, отвечающее второму набору ограничений. Для моего решения см. Код ниже.

Из Apache log4net document:

"Сборка может выбрать использование именованного репозитория регистрации, а не репозитория по умолчанию. Это полностью отделяет ведение журнала для сборки от остальной части приложения. Это может быть очень полезно разработчикам компонентов, которые хотят использовать log4net для своих но не хотят требовать, чтобы все приложения, использующие их компонент, знали о log4net.Это также означает, что их отладочная конфигурация отделена от конфигурации приложений. В сборке должно быть указано, что RepositoryAttribute устанавливает свой репозиторий журналов".

код

Я поместил следующие строки в файл AssemblyInfo.cs моей библиотеки классов:

// Log4Net configuration file location
[assembly: log4net.Config.Repository("CompanyName.IntegrationLibName")]
[assembly: log4net.Config.XmlConfigurator(ConfigFile = "CompanyName.IntegrationLibName.config", Watch = true)]

Ссылки

Ответ 2

Скорее всего, вы можете скопировать что-то вокруг класса XmlConfigurator:

public static class MyLogManager
{
    // for illustration, you should configure this somewhere else...
    private static string configFile = @"path\to\log4net.config";

    public static ILog GetLogger(Type type)
    {
        if(log4net.LogManager.GetCurrentLoggers().Length == 0)
        {
            // load logger config with XmlConfigurator
            log4net.Config.XmlConfigurator.Configure(configFile);
        }
        return LogManager.GetLogger(type);
    }
}

Затем в ваших классах вместо

private static readonly ILog log = LogManager.GetLogger(typeof(MyApp));

Использование:

private static readonly ILog log = MyLogManager.GetLogger(typeof(MyApp));

Конечно, было бы предпочтительнее сделать этот класс сервисом и динамически настроить его с помощью контейнера IoC по вашему выбору, но вы получите идею?

РЕДАКТИРОВАТЬ: Проблема с фиксированным числом() указана в комментариях.

Ответ 3

В вашем коде вы можете проверить, есть ли какие-либо журналы с помощью

log4net.LogManager.GetCurrentLoggers().Count()

Тогда вы могли бы использовать XmlConfigurator для загрузки конфигурации по умолчанию из файла:

log4net.Config.XmlConfigurator.Configure(configFile)

Вы можете выполнить инициализацию в статическом или регулярном конструкторе.

class Sample
{
    private static readonly log4net.ILog LOG;

    static Sample()
    {
        if (log4net.LogManager.GetCurrentLoggers().Count() == 0)
        {
            loadConfig();
        }
        LOG = log4net.LogManager.GetLogger(typeof(Sample));

    }

    private static void loadConfig()
    {
        /* Load your config file here */
    }

    public void YourMethod()
    {
       LOG.Info("Your messages");
    }
}

Ответ 4

В вашей автономной библиотеке классов используйте синглтон, который загружает конфигурационный файл log4net, используя log4net.Config.XmlConfigurator.

В частности, вы можете определить весь свой код, чтобы использовать свой собственный класс ведения журнала; этот класс может просто быть простой оболочкой вызовов журнала log4net с одним добавлением; создать статический член, который содержит информацию журнала, к которой вы хотите войти; инициализируйте это с помощью вызова XmlConfigurator в статическом конструкторе для этого класса. Это все, что вам нужно сделать.

Ответ 5

Здесь вы можете найти хорошее описание: log4net: краткое руководство по началу работы

Как описано в статье, чтобы отдельно настроить каждую сборку, создайте XML файл для своей сборки с именем AssemblyName.dll.log4net и поместите в него следующий код XML:

<?xml version="1.0" encoding="utf-8"?>
<log4net debug="false">
   <appender name="XmlSchemaFileAppender" type="log4net.Appender.FileAppender">
      <file value="AppLog.xml" />
      <appendToFile value="true" />
      <lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
      <layout type="log4net.Layout.XmlLayout" />
   </appender>

   <root>
      <level value="WARN" />
      <appender-ref ref="XmlSchemaFileAppender" />
   </root>
</log4net>

Далее описывается, как создать экземпляр нового регистратора, просто объявить его как переменную для всего класса следующим образом:

public class LogSample
{
    private static readonly log4net.ILog Log 
            = log4net.LogManager.GetLogger(typeof(LogSample));
    // Class Methods Go Here...
}

Затем вы можете использовать закрытую переменную Log внутри вашего класса:

Log.Info("Sample message");

Аналогичным образом вы можете использовать Log.Error("Error occurred while running myMethod", ex) для регистрации ошибок вместе с деталями исключения.

Я нашел следующее:

  • Не забудьте вызвать log4net.Config.XmlConfigurator.Configure();, чтобы активировать вашу конфигурацию

  • Если вам нужно знать путь к файлу (-ам), написанный здесь, некоторый код, как его получить из Log4Net

Надеюсь, это поможет.