.net - ilog - log4net implementation in c#
¿Cómo registrar NombreMetodológico al ajustar Log4net? (8)
He envuelto Log4net en un contenedor estático y quiero iniciar sesión
loggingEvent.LocationInformation.MethodName
loggingEvent.LocationInformation.ClassName
Sin embargo, todo lo que obtengo es el nombre de mi envoltorio.
¿Cómo puedo registrar esa información usando un forwardingappender y una clase de contenedor estático como
Logger.Debug("Logging to Debug");
Logger.Info("Logging to Info");
Logger.Warn("Logging to Warn");
Logger.Error(ex);
Logger.Fatal(ex);
¿Qué hay de C # 4.5 característica callerinfo - http://msdn.microsoft.com/en-us/library/system.runtime.compilerservices.callermembernameattribute.aspx
¿Qué pasa con las variables %M
y %C
? http://logging.apache.org/log4net/log4net-1.2.11/release/sdk/log4net.Layout.PatternLayout.html
Uso, algo como:
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date [%thread] %-5level %logger [%M %C] - %message%newline" />
</layout>
¿Eso no hace lo que estás buscando?
Bueno, el error estaba en algún lugar de mi apéndice, pero para completarlo, incluiré la respuesta a mi leal saber y entender:
la fachada que necesita debe envolver ILogger y NO ILog
public static class Logger
{
private readonly static Type ThisDeclaringType = typeof(Logger);
private static readonly ILogger defaultLogger;
static Logger()
{
defaultLogger =
LoggerManager.GetLogger(Assembly.GetCallingAssembly(),"MyDefaultLoggger");
...
public static void Info(string message)
{
if (defaultLogger.IsEnabledFor(infoLevel))
{
defaultLogger.Log(typeof(Logger), infoLevel, message, null);
}
}
Escribiré más código de la respuesta correcta de Claus
En la clase de envoltura
public static class Logger
{
private static readonly ILogger DefaultLogger;
static Logger()
{
defaultLogger = LoggerManager.GetLogger(Assembly.GetCallingAssembly(), "MyDefaultLoggger"); // MyDefaultLoggger is the name of Logger
}
public static void LogError(object message)
{
Level errorLevel = Level.Error;
if (DefaultLogger.IsEnabledFor(errorLevel))
{
DefaultLogger.Log(typeof(Logger), errorLevel, message, null);
}
}
public static void LogError(object message, Exception exception)
{
Level errorLevel = Level.Error;
if (DefaultLogger.IsEnabledFor(errorLevel))
{
DefaultLogger.Log(typeof(Logger), errorLevel, message, exception);
}
}
y así sucesivamente para el resto de métodos.
en web.config o app.config log4net.Layout.PatternLayout puede usar algunos patrones de conversión como:
%location %method %line
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date{dd/MM/yyyy hh:mm:ss.fff tt} [%thread] %level %logger [%location %method %line] [%C %M] - %newline%message%newline%exception"/>
</layout>
Esta publicación me ayudó a pensar en cómo escribir mi propio contenedor, a cambio, pensé que te gustaría que mi clase completa envuelva el registrador, que parece funcionar muy bien y que en realidad lleva más de la mitad de tiempo que usar un ILog directamente.
Todo lo que se requiere es el xml apropiado para configurar el registro en el archivo de configuración y
[assembly: log4net.Config.XmlConfigurator(Watch = true)]
en su AssemblyInfo.cs y debería funcionar fácilmente.
Una nota: estoy usando Log4NetDash con una configuración muy simple, así que hice trampa y puse algo de información en los campos incorrectos (por ejemplo, seguimiento de la pila en el campo Dominio), esto todavía funciona para mí ya que no me importa dónde está la información. se muestra, pero es posible que desee corregir esto si está configurando cosas correctamente si tiene tiempo libre.
using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Reflection;
using System.Threading;
using log4net;
using log4net.Core;
namespace Utility
{
public class Logger
{
static Logger()
{
LogManager.GetLogger(typeof(Logger));
}
public static void Debug(string message, params object[] parameters)
{
Log(message, Level.Debug, null, parameters);
}
public static void Info(string message, params object[] parameters)
{
Log(message, Level.Info, null, parameters);
}
public static void Warn(string message, params object[] parameters)
{
Log(message, Level.Warn, null, parameters);
}
public static void Error(string message, params object[] parameters)
{
Error(message, null, parameters);
}
public static void Error(Exception exception)
{
if (exception==null)
return;
Error(exception.Message, exception);
}
public static void Error(string message, Exception exception, params object[] parameters)
{
string exceptionStack = "";
if (exception != null)
{
exceptionStack = exception.GetType().Name + " : " + exception.Message + Environment.NewLine;
Exception loopException = exception;
while (loopException.InnerException != null)
{
loopException = loopException.InnerException;
exceptionStack += loopException.GetType().Name + " : " + loopException.Message + Environment.NewLine;
}
}
Log(message, Level.Error, exceptionStack, parameters);
}
private static void Log(string message, Level logLevel, string exceptionMessage, params object[] parameters)
{
BackgroundWorker worker = new BackgroundWorker();
worker.DoWork += LogEvent;
worker.RunWorkerAsync(new LogMessageSpec
{
ExceptionMessage = exceptionMessage,
LogLevel = logLevel,
Message = message,
Parameters = parameters,
Stack = new StackTrace(),
LogTime = DateTime.Now
});
}
private static void LogEvent(object sender, DoWorkEventArgs e)
{
try
{
LogMessageSpec messageSpec = (LogMessageSpec) e.Argument;
StackFrame frame = messageSpec.Stack.GetFrame(2);
MethodBase method = frame.GetMethod();
Type reflectedType = method.ReflectedType;
ILogger log = LoggerManager.GetLogger(reflectedType.Assembly, reflectedType);
Level currenLoggingLevel = ((log4net.Repository.Hierarchy.Logger) log).Parent.Level;
if (messageSpec.LogLevel<currenLoggingLevel)
return;
messageSpec.Message = string.Format(messageSpec.Message, messageSpec.Parameters);
string stackTrace = "";
StackFrame[] frames = messageSpec.Stack.GetFrames();
if (frames != null)
{
foreach (StackFrame tempFrame in frames)
{
MethodBase tempMethod = tempFrame.GetMethod();
stackTrace += tempMethod.Name + Environment.NewLine;
}
}
string userName = Thread.CurrentPrincipal.Identity.Name;
LoggingEventData evdat = new LoggingEventData
{
Domain = stackTrace,
Identity = userName,
Level = messageSpec.LogLevel,
LocationInfo = new LocationInfo(reflectedType.FullName,
method.Name,
frame.GetFileName(),
frame.GetFileLineNumber().ToString()),
LoggerName = reflectedType.Name,
Message = messageSpec.Message,
TimeStamp = messageSpec.LogTime,
UserName = userName,
ExceptionString = messageSpec.ExceptionMessage
};
log.Log(new LoggingEvent(evdat));
}
catch (Exception)
{}//don''t throw exceptions on background thread especially about logging!
}
private class LogMessageSpec
{
public StackTrace Stack { get; set; }
public string Message { get; set; }
public Level LogLevel { get; set; }
public string ExceptionMessage { get; set; }
public object[] Parameters { get; set; }
public DateTime LogTime { get; set; }
}
}
}
Lo único que se me ocurre hacer (ya que actualmente no uso log4net) es solicitar un stacktrace (nuevo StackTrace) y retroceder un cuadro para obtener la información que necesita. Sin embargo, no estoy seguro del impacto en el rendimiento del tiempo de ejecución de esto.
Simplemente declare su variable de registro así ...
private static readonly log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
Entonces puedes usarlo normalmente.
Simplemente usaría algo como %stacktrace{2}
como un patrón de conversión.
Ejemplo de salida:
MyNamespace.ClassName.Method> Common.Log.Warning
donde MyNamespace.ClassName.Method
es un método que llama a mi envoltorio y Common.Log.Warning
es un método de la clase contenedora.
Los patrones de conversión se pueden encontrar here .