По сути, вы создаете интерфейс, а затем конкретную реализацию этого интерфейса, который оборачивает классы и методы Log4net напрямую. Дополнительные системы ведения журналов можно обернуть, создав более конкретные классы, которые обертывают другие классы и методы этих систем. Наконец, используйте фабрику для создания экземпляров ваших оболочек на основе параметра конфигурации или строки изменения кода. (Примечание: вы можете стать более гибкими - и сложными - используя Inversion of Control контейнер, такой как StructureMap .)
public interface ILogger
{
void Debug(object message);
bool IsDebugEnabled { get; }
// continue for all methods like Error, Fatal ...
}
public class Log4NetWrapper : ILogger
{
private readonly log4net.ILog _logger;
public Log4NetWrapper(Type type)
{
_logger = log4net.LogManager.GetLogger(type);
}
public void Debug(object message)
{
_logger.Debug(message);
}
public bool IsDebugEnabled
{
get { return _logger.IsDebugEnabled; }
}
// complete ILogger interface implementation
}
public static class LogManager
{
public static ILogger GetLogger(Type type)
{
// if configuration file says log4net...
return new Log4NetWrapper(type);
// if it says Joe's Logger...
// return new JoesLoggerWrapper(type);
}
}
И пример использования этого кода в ваших классах (объявленных как статическое поле только для чтения):
private static readonly ILogger _logger =
LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
Вы можете получить тот же чуть более дружественный к производительности эффект, используя:
private static readonly ILogger _logger =
LogManager.GetLogger(typeof(YourTypeName));
Первый пример считается более понятным.
Вы не хотели бы создавать Singleton для обработки всех журналов, потому что Log4Net регистрирует для вызывающего типа; гораздо понятнее и полезнее, чтобы каждый тип использовал свой собственный регистратор, а не просто видел один тип в файле журнала, сообщающий обо всех сообщениях.
Поскольку ваша реализация должна быть достаточно многократно используемой (другие проекты в вашей организации), вы можете сделать ее собственной сборкой или, в идеале, включить ее в свою собственную сборку каркаса / утилит вашей организации. Не повторно объявляйте классы отдельно в каждой из ваших сборок бизнес / данных / пользовательского интерфейса, это не поддерживается.