retener rapido puedo para olvidar memorizar memoria juegos informacion fundamentacion escuchar entrenar entrenamiento ejercicios como aprender c# logging nlog

c# - rapido - juegos para entrenar la memoria



Cómo retener información de callsite cuando se envuelve NLog (6)

Alternativamente, puede evitar la solución nativa desde la configuración de NLog y recuperar el archivo | método | información de línea en su código de envolturas:

using System.Diagnostics; ... static private string GetCallsite() { StackFrame sf = new StackTrace(2/*Skip two frames - dive to the callers context*/, true/*Yes I want the file info !*/).GetFrame(0); return "{" + sf.GetFileName() + " | " + sf.GetMethod().Name + "-" + sf.GetFileLineNumber() + "} "; }

Luego, simplemente llame a sus métodos estáticos y agregue el callsite antes del mensaje:

LogManager.GetCurrentClassLogger().Trace(GetCallsite() + "My Trace Message.");

Tengo una clase que envuelve NLog (llamada NLogger). Mis registros se guardan en mi base de datos. Lo que estoy teniendo un problema es cómo mostrar dónde se produjo el registro. tengo esto

<parameter name="@Logger" layout="${callsite}"/>

pero esto solo muestra Core.Logging.Loggers.NLogLogger.Log, que es mi NlogWrapper, no la clase que llama a mi envoltorio.

Este es mi método de envoltura

public void Log(LogType messageType, Type context, string message, Exception exception) { NLog.Logger logger = NLog.LogManager.GetLogger(context.Name); LogLevel logLevel = LogLevel.Info; // Default level to info switch (messageType) { case LogType.Debug: logLevel = LogLevel.Debug; break; case LogType.Info: logLevel = LogLevel.Info; break; case LogType.Warning: logLevel = LogLevel.Warn; break; case LogType.Error: logLevel = LogLevel.Error; break; case LogType.Fatal: logLevel = LogLevel.Fatal; break; default: throw new ArgumentException("Log message type is not supported"); } logger.Log(logLevel, message, exception); }


Chicos Después de varios días de trabajo arduo y búsqueda. Finalmente, utilizo una clase simple construida en el Contenedor Nlog que puede retener el $ {callsite} y obtener el nombre del registrador correcto cuando se crea la instancia de Nlog Wrapper. Voy a poner el código como sigue con un simple comentario. Como puede ver, utilizo Stacktrace para obtener el nombre correcto del registrador. Use write y writewithex para registrar el logevnet para que pueda retener el callsite.

public class NlogWrapper { private readonly NLog.Logger _logger; //NLog logger /// <summary> /// This is the construtor, which get the correct logger name when instance created /// </summary> public NlogWrapper() { StackTrace trace = new StackTrace(); if (trace.FrameCount > 1) { _logger = LogManager.GetLogger(trace.GetFrame(1).GetMethod().ReflectedType.FullName); } else //This would go back to the stated problem { _logger = LogManager.GetCurrentClassLogger(); } } /// <summary> /// These two method are used to retain the ${callsite} for all the Nlog method /// </summary> /// <param name="level">LogLevel.</param> /// <param name="format">Passed message.</param> /// <param name="ex">Exception.</param> private void Write(LogLevel level, string format, params object[] args) { LogEventInfo le = new LogEventInfo(level, _logger.Name, null, format, args); _logger.Log(typeof(NlogWrapper), le); } private void WriteWithEx(LogLevel level, string format,Exception ex, params object[] args) { LogEventInfo le = new LogEventInfo(level, _logger.Name, null, format, args); le.Exception = ex; _logger.Log(typeof(NlogWrapper), le); } #region Methods /// <summary> /// This method writes the Debug information to trace file /// </summary> /// <param name="message">The message.</param> public void Debug(String message) { if (!_logger.IsDebugEnabled) return; Write(LogLevel.Debug, message); } public void Debug(string message, Exception exception, params object[] args) { if (!_logger.IsFatalEnabled) return; WriteWithEx(LogLevel.Debug, message, exception); } /// <summary> /// This method writes the Information to trace file /// </summary> /// <param name="message">The message.</param> public void Info(String message) { if (!_logger.IsInfoEnabled) return; Write(LogLevel.Info, message); } public void Info(string message, Exception exception, params object[] args) { if (!_logger.IsFatalEnabled) return; WriteWithEx(LogLevel.Info, message, exception); } /// <summary> /// This method writes the Warning information to trace file /// </summary> /// <param name="message">The message.</param> public void Warn(String message) { if (!_logger.IsWarnEnabled) return; Write(LogLevel.Warn, message); } public void Warn(string message, Exception exception, params object[] args) { if (!_logger.IsFatalEnabled) return; WriteWithEx(LogLevel.Warn, message, exception); } /// <summary> /// This method writes the Error Information to trace file /// </summary> /// <param name="error">The error.</param> /// <param name="exception">The exception.</param> // public static void Error( string message) // { // if (!_logger.IsErrorEnabled) return; // _logger.Error(message); //} public void Error(String message) { if (!_logger.IsWarnEnabled) return; //_logger.Warn(message); Write(LogLevel.Error, message); } public void Error(string message, Exception exception, params object[] args) { if (!_logger.IsFatalEnabled) return; WriteWithEx(LogLevel.Error, message, exception); } /// <summary> /// This method writes the Fatal exception information to trace target /// </summary> /// <param name="message">The message.</param> public void Fatal(String message) { if (!_logger.IsFatalEnabled) return; Write(LogLevel.Fatal, message); } public void Fatal(string message, Exception exception, params object[] args) { if (!_logger.IsFatalEnabled) return; WriteWithEx(LogLevel.Fatal, message, exception); } /// <summary> /// This method writes the trace information to trace target /// </summary> /// <param name="message">The message.</param> /// public void Trace(string message, Exception exception, params object[] args) { if (!_logger.IsFatalEnabled) return; WriteWithEx(LogLevel.Trace, message, exception); } public void Trace(String message) { if (!_logger.IsTraceEnabled) return; Write(LogLevel.Trace, message); } #endregion }


El problema es que su envoltorio no está envolviendo correctamente. Aquí hay un ejemplo de cómo ajustar NLog correctamente, tomado directamente del árbol fuente de NLog :

using System; using System.Text; using NLog; namespace LoggerWrapper { /// <summary> /// Provides methods to write messages with event IDs - useful for the Event Log target. /// Wraps a Logger instance. /// </summary> class MyLogger { private Logger _logger; public MyLogger(string name) { _logger = LogManager.GetLogger(name); } public void WriteMessage(string eventID, string message) { /// /// create log event from the passed message /// LogEventInfo logEvent = new LogEventInfo(LogLevel.Info, _logger.Name, message); // // set event-specific context parameter // this context parameter can be retrieved using ${event-context:EventID} // logEvent.Context["EventID"] = eventID; // // Call the Log() method. It is important to pass typeof(MyLogger) as the // first parameter. If you don''t, ${callsite} and other callstack-related // layout renderers will not work properly. // _logger.Log(typeof(MyLogger), logEvent); } } }

La clave está pasando el tipo de contenedor de su registrador a la llamada a Log. Cuando NLog intenta encontrar el sitio de llamada, sube la pila hasta que el primer método de llamada cuyo tipo de declaración NO sea el tipo pasado a la llamada de registro. Este será el código que realmente llama a su envoltorio.

En tu caso, tu registrador se vería así:

public void Log(LogType messageType, Type context, string message, Exception exception) { NLog.Logger logger = NLog.LogManager.GetLogger(context.Name); LogLevel logLevel = LogLevel.Info; // Default level to info switch (messageType) { case LogType.Debug: logLevel = LogLevel.Debug; break; case LogType.Info: logLevel = LogLevel.Info; break; case LogType.Warning: logLevel = LogLevel.Warn; break; case LogType.Error: logLevel = LogLevel.Error; break; case LogType.Fatal: logLevel = LogLevel.Fatal; break; default: throw new ArgumentException("Log message type is not supported"); } // // Build LogEvent here... // LogEventInfo logEvent = new LogEventInfo(logLevel, context.Name, message); logEvent.Exception = exception; // // Pass the type of your wrapper class here... // logger.Log(typeof(YourWrapperClass), logEvent); }


He estado luchando con este problema desde hace un tiempo.

Realmente importante fue el Callsite (espacio de nombres completamente calificado) dentro de los archivos de registro.

Primero, intenté sacar el registrador correcto de Stacktrace:

[MethodImpl(MethodImplOptions.NoInlining)] private static NLog.Logger GetLogger() { var stackTrace = new StackTrace(false); StackFrame[] frames = stackTrace.GetFrames(); if (null == frames) throw new ArgumentException("Stack frame array is null."); StackFrame stackFrame; switch (frames.Length) { case 0: throw new ArgumentException("Length of stack frames is 0."); case 1: case 2: stackFrame = frames[frames.Length - 1]; break; default: stackFrame = stackTrace.GetFrame(2); break; } Type declaringType = stackFrame.GetMethod() .DeclaringType; return declaringType == null ? LogManager.GetCurrentClassLogger() : LogManager.GetLogger(declaringType.FullName); }

Pero lamentablemente, la Stacktrace con MEF es muy larga y no puedo identificar claramente a la persona que llama para el Solicitante de la ILogger.

Entonces, en lugar de inyectar la Interfaz de ILogger a través de la Inyección de Constructor, he creado una Interfaz ILogFactory, que puede ser inyectada a través de la Inyección de Constructor y llamar al Método Crear en la Fábrica.

public interface ILogFactory { #region Public Methods and Operators /// <summary> /// Creates a logger with the Callsite of the given Type /// </summary> /// <example> /// factory.Create(GetType()); /// </example> /// <param name="type">The type.</param> /// <returns></returns> ILogger Create(Type type); #endregion }

Y lo implementé:

using System; using System.ComponentModel.Composition; [Export(typeof(ILogFactory))] [PartCreationPolicy(CreationPolicy.Shared)] public class LogFactory : ILogFactory { #region Public Methods and Operators public ILogger Create(Type type) { var logger = new Logger().CreateLogger(type); return logger; } #endregion }

Con el ILogger:

public interface ILogger { #region Public Properties bool IsDebugEnabled { get; } bool IsErrorEnabled { get; } bool IsFatalEnabled { get; } bool IsInfoEnabled { get; } bool IsTraceEnabled { get; } bool IsWarnEnabled { get; } #endregion #region Public Methods and Operators void Debug(Exception exception); void Debug(string format, params object[] args); void Debug(Exception exception, string format, params object[] args); void Error(Exception exception); void Error(string format, params object[] args); void Error(Exception exception, string format, params object[] args); void Fatal(Exception exception); void Fatal(string format, params object[] args); void Fatal(Exception exception, string format, params object[] args); void Info(Exception exception); void Info(string format, params object[] args); void Info(Exception exception, string format, params object[] args); void Trace(Exception exception); void Trace(string format, params object[] args); void Trace(Exception exception, string format, params object[] args); void Warn(Exception exception); void Warn(string format, params object[] args); void Warn(Exception exception, string format, params object[] args); #endregion }

e Implementación de:

using System; using NLog; using NLog.Config; /// <summary> /// The logging service. /// </summary> public class Logger : NLog.Logger, ILogger { #region Fields private string _loggerName; #endregion #region Public Methods and Operators /// <summary> /// The get logging service. /// </summary> /// <returns> /// The <see cref="ILogger" />. /// </returns> public ILogger CreateLogger(Type type) { if (type == null) throw new ArgumentNullException("type"); _loggerName = type.FullName; var logger = (ILogger)LogManager.GetLogger(_loggerName, typeof(Logger)); return logger; }

Para usarlo ... simplemente inyecte ILogFactory y haga clic en Crear método en un constructor de importación de Mefed:

[ImportingConstructor] public MyConstructor( ILogFactory logFactory) { _logger = logFactory.Create(GetType()); }

espero que esto ayude


Para omitir algunos fotogramas y sumergirse en el contexto de las personas que contestan, configúrelo en App.config, o en el programa del famoso modificador:

skipFrames = 1

Ejemplos: consulte esta página para ${callsite:skipFrames=Integer} y esta página para ${callsite-linenumber:skipFrames=Integer}

Te recomiendo que uses este formato en tu envoltorio:

${callsite:fileName=true:includeSourcePath=false:skipFrames=1}

El resultado de esta configuración será el siguiente:

... {LicenseServer.LSCore.MainThreadFunction (LSCore.cs: 220)} ...


internal string GetCallingMethodName() { string result = "unknown"; StackTrace trace = new StackTrace(false); for (int i = 0; i < trace.FrameCount; i++) { StackFrame frame = trace.GetFrame(i); MethodBase method = frame.GetMethod(); Type dt = method.DeclaringType; if (!typeof(ILogger).IsAssignableFrom(dt) && method.DeclaringType.Namespace != "DiagnosticsLibrary") { result = string.Concat(method.DeclaringType.FullName, ".", method.Name); break; } } return result; }

Fuente: http://slf.codeplex.com/discussions/210075

Utilicé el código publicado arriba para simplemente extraer el nombre del método de llamada y pasarlo como parte del parámetro "mensaje" al diseño. Esto me permite tener el nombre del método original donde se llamó el contenedor de registro escrito en el archivo de registro (en lugar del nombre de clase del contenedor de registro).