Я сделал это так, чтобы создать класс-оболочку для NLog, который будет обертывать каждый метод журнала, скрывать имя метода и использовать объект StackTrace для получения имени метода. Тогда вам не придется писать это каждый раз; имя метода, вызывающего метод-оболочку Logging, вводится автоматически.
Это будет выглядеть чище, так как у вас не будет везде {0} и methodName.
Вы можете сделать еще один шаг вперед и создать класс-оболочку ведения журнала, который принимает строку журнала и действие, выполняет действие и вызывает объект журнала, используя объект StackTrace, и все это за один раз.
Я использовал это для выполнения временных действий и их регистрации, удобно делать все за один вызов и экономить на повторяющемся коде. Мой метод ExecuteTimedAction(string logString, Action actionToExecute) использует секундомер, регистрирует стартовую строку, запускает секундомер, выполняет метод (делегат действия), останавливает секундомер и снова регистрирует оба журнала с отметкой времени, именем сборки и имя метода, из которого инициирован вызов.
Код для получения метода прост: используйте объект StackTrace и получите StackFrame предыдущего вызова.
var stackTrace = new StackTrace();
var callingMethodName = stackTrace.GetFrame(2).GetMethod().Name;
Примечание. У меня есть 2 жестко закодированных выше, но это из-за дополнительного вызова оболочки; если вы звоните напрямую, вам может понадобиться GetFrame(1). Лучший способ - использовать непосредственное окно и попробовать разные кадры или просто просмотреть его, чтобы увидеть, что вы получите, используя метод GetFrames() объекта StackTrace.
Сейчас я изучаю сохранение параметров для строкового формата и добавление первого параметра для оболочки журнала. Это можно сделать примерно так:
public static class LogWrapper
{
private static Logger _logger // where Logger assumes that is the actual NLog logger, not sure if it is the right name but this is for example
public static void Info(string logString, object[] params)
{
// Just prepend the method name and then pass the string and the params to the NLog object
_logger.Info(
string.Concat(
GetMethodName(),
": ",
logString
),
params
);
}
public static void Warn(string logString, object[] params)
{
// _logger.Warn(
// You get the point ;)
// )
}
private static string GetMethodName()
{
var stackTrace = new StackTrace(); // Make sure to add using System.Diagnostics at the top of the file
var callingMethodName = stackTrace.GetFrame(2).GetMethod().Name; // Possibly a different frame may have the correct method, might not be 2, might be 1, etc.
}
}
Затем в вызывающем коде член _logger становится LoggerWrapper, а не Logger, и вы вызываете его точно так же, но удаляете {0} из кода. Вам нужно будет проверить наличие нулей и, возможно, если других параметров нет, иметь перегрузку метода, которая просто вызывает без параметров; Я не уверен, поддерживает ли это NLog, так что вы должны это проверить.
... РЕДАКТИРОВАТЬ:
Просто для интереса я использую этот тип кода в сборках общего типа библиотеки, на которые может ссылаться множество сборок, поэтому я могу получить информацию, такую как вызов сборки, имя метода и т. д., без жесткого кодирования или беспокойства о это в моем коде регистрации. Это также гарантирует, что никому другому, использующему код, не придется об этом беспокоиться. Они просто вызывают Log() или Warn() или что-то еще, и сборка автоматически сохраняется в журналах.
Вот пример (я знаю, что вы сказали, что это излишество для вас, но пища для размышлений на будущее, если вам может понадобиться что-то подобное). В этом примере я регистрировал только сборку, а не имя метода, но его можно легко комбинировать.
#region : Execute Timed Action :
public static T ExecuteTimedAction<T>(string actionText, Func<T> executeFunc)
{
return ExecuteTimedAction<T>(actionText, executeFunc, null);
}
/// <summary>
/// Generic method for performing an operation and tracking the time it takes to complete (returns a value)
/// </summary>
/// <typeparam name="T">Generic parameter which can be any Type</typeparam>
/// <param name="actionText">Title for the log entry</param>
/// <param name="func">The action (delegate method) to execute</param>
/// <returns>The generic Type returned from the operation's execution</returns>
public static T ExecuteTimedAction<T>(string actionText, Func<T> executeFunc, Action<string> logAction)
{
string beginText = string.Format("Begin Execute Timed Action: {0}", actionText);
if (null != logAction)
{
logAction(beginText);
}
else
{
LogUtil.Log(beginText);
}
Stopwatch stopWatch = Stopwatch.StartNew();
T t = executeFunc(); // Execute the action
stopWatch.Stop();
string endText = string.Format("End Execute Timed Action: {0}", actionText);
string durationText = string.Format("Total Execution Time (for {0}): {1}", actionText, stopWatch.Elapsed);
if (null != logAction)
{
logAction(endText);
logAction(durationText);
}
else
{
LogUtil.Log(endText);
LogUtil.Log(durationText);
}
return t;
}
public static void ExecuteTimedAction(string actionText, Action executeAction)
{
bool executed = ExecuteTimedAction<bool>(actionText, () => { executeAction(); return true; }, null);
}
/// <summary>
/// Method for performing an operation and tracking the time it takes to complete (does not return a value)
/// </summary>
/// <param name="actionText">Title for the log entry</param>
/// <param name="action">The action (delegate void) to execute</param>
public static void ExecuteTimedAction(string actionText, Action executeAction, Action<string> logAction)
{
bool executed = ExecuteTimedAction<bool>(actionText, () => { executeAction(); return true; }, logAction);
}
#endregion
Затем функция журнала выглядит примерно так, как вы можете видеть, моя функция журнала не жестко закодирована в ExecuteTimedAction, поэтому я могу передать ей любое действие журнала.
В классе журнала я сохраняю имя сборки Entry один раз в статической переменной и использую ее для всех журналов...
private static readonly string _entryAssemblyName = Assembly.GetEntryAssembly().GetName().Name;
Надеюсь, это даст вам достаточно пищи для размышлений о рефакторинге!
person
Dmitriy Khaykin
schedule
05.03.2013