log4net (и NLog) оба предоставляют метод ведения журнала, который позволяет «обернуть» их регистраторы и все же получить правильную информацию о сайте вызова. По сути, регистратору log4net (или NLog) нужно сообщить типу, который образует «границу» между кодом регистрации и кодом приложения. Я думаю, что они называют это «тип регистратора» или что-то подобное. Когда библиотеки получают информацию о сайте вызова, они перемещаются вверх по стеку вызовов до тех пор, пока MethodBase.DeclaringType не станет равным (или, возможно, AssignableFrom) «типу регистратора». Следующий кадр стека будет вызывать код приложения.
Вот пример того, как войти через NLog из оболочки (log4net был бы похож - посмотрите в документации по log4net интерфейс ILogger (не ILog):
LogEventInfo logEvent = new LogEventInfo(level, _logger.Name, null, "{0}", new object[] { message }, exception);
_logger.Log(declaringType, logEvent);
Где declaringType - это переменная-член, которая была установлена примерно так:
private readonly static Type declaringType = typeof(AbstractLogger);
И "AbstractLogger" - это тип вашей оболочки журнала. В вашем случае это будет выглядеть примерно так:
private readonly static Type declaringType = typeof(Log);
Если NLog необходимо получить информацию о сайте вызова (из-за операторов сайта вызова в макете), он будет перемещаться вверх по стеку до тех пор, пока MethodBase.DeclaringType для текущего кадра не станет равным (или AssignableFrom) declaringType. Следующим кадром в стеке будет фактический сайт вызова.
Вот некоторый код, который будет работать для регистрации с «обернутым» log4net logger. Он использует интерфейс log4net ILogger и передает тип «упаковочного» регистратора для сохранения информации о сайте вызова. Вам не нужно заполнять класс / структуру события этим методом:
_logger.Log(declaringType, level, message, exception);
Опять же, "declaringType" - это тип вашей оболочки. _logger - это log4net logger, Level - это значение log4net.LogLevel, message - это сообщение, исключение - это исключение (если есть, ноль в противном случае).
Что касается загрязнения ваших сайтов вызовов с помощью Typeof (что угодно), я думаю, вы застряли с этим, если хотите использовать один статический объект "Журнал". В качестве альтернативы, внутри методов ведения журнала объекта «Журнал» вы можете получить вызывающий метод, подобный принятому ответу в этом посте
Как найти метод, вызвавший текущий метод?
Эта ссылка показывает, как получить непосредственно предшествующего абонента. Если вам нужно получить метод, который вызвал функцию регистрации, но ваша работа выполняется на несколько уровней глубже, вам потребуется подняться в стеке на некоторое количество кадров, а не на один кадр.
Взяв все это вместе, вы бы написали свой метод Debug примерно так (опять же, это с точки зрения NLog, потому что это то, что я имею перед собой):
public static void Debug(object message)
{
MethodBase mb = GetCallingMethod();
Type t = mb.DeclaringType;
LogEventInfo logEvent = new LogEventInfo(LogLevel.Debug, t.Name, null, "{0}", new object [] message, null);
ILogger logger = getLogger(t) As ILogger;
logger.Log(declaringType, logEvent)
}
Обратите внимание, что вы, вероятно, не найдете здесь много людей в StackOverflow, которые бы рекомендовали написать функцию-оболочку журналирования, подобную этой (которая явно получает вызывающий метод для любого вызова журнала). Не могу сказать, что я бы тоже порекомендовал это, но он более или менее отвечает на вопрос, который вы задали. Если вы хотите использовать статический объект «Журнал», то вам придется либо явно передавать тип на каждом сайте вызовов журналирования (чтобы получить правильный регистратор классов), либо вам придется добавить код внутри вызова журналирования для навигации составить и выяснить эту информацию для себя. Я не думаю, что какой-либо из этих вариантов особенно привлекателен.
Теперь, сказав все это, вы можете рассмотреть возможность использования log4net или NLog напрямую, а не добавлять этот сложный (и не обязательно надежный) код для получения информации о сайте вызова. Как указывает Мэтью, NLog предоставляет простой способ получить регистратор для текущего класса. Чтобы получить регистратор для текущего класса с использованием log4net, вы должны сделать это в каждом классе:
private static readonly log4net.ILog log = log4net.LogManager.GetLogger(
System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
против этого с NLog:
private static readonly NLog.logger log = NLog.LogManager.GetCurrentClassLogger();
Это довольно распространенное использование.
Если вы не хотите зависеть от конкретной реализации ведения журнала, вы можете использовать одну из доступных абстракций ведения журнала, например Common.Logging (NET) или Simple Logging Facade (SLF) ) .
Даже если вы не используете одну из этих абстракций, загрузите исходный код Common.Logging и посмотрите на абстракцию для log4net.Он точно покажет, как обернуть регистратор log4net таким образом, чтобы информация о месте вызова была сохранена (и была доступна операторам макета).