Log4Net 如何同时使用 ErrorFormat 和 Error
Log4Net how to use both the ErrorFormat and the Error at the same time
log4net中有2个非常不错的函数:
Log.Error("Message", myException);
和
Log.ErrorFormat("Message {0}", CustomerId);
生产日志记录在输出日志文件中非常漂亮。异常一个很好,因为它很好地打印堆栈跟踪和所有异常详细信息,格式一个很好,因为它允许我指定导致失败的参数。有没有 "best of both worlds" 方法,或者有什么方法可以做到?
Log.ErrorFormatEx("Message {0}", CustomerId, myException)
编辑:我检查了可能重复的问题,但它们的格式很糟糕,不要完全这样问。我在寻找扩展方法或现有方法
您可以创建一个扩展方法:
namespace log4net.Core
{
public class Log4NetExtensions
{
public static void ErrorFormatEx(this ILog logger, string format, Exception exception, params object[] args)
{
logger.Error(string.Format(format, args), exception);
}
}
}
然后您就可以像使用任何其他 Log4Net
方法一样使用它了:
Log.ErrorFormatEx("Message {0}", exception, CustomerId);
知道这个问题已经得到解答,但只是针对可能会发现此替代方案有用的其他用户。我创建了一个 ILog 接口和一个 Log Class 到 "centralize" 我的 log4net 方法和逻辑。我还为 "Error" 方法创建了多个重载。
ILog.cs
public interface ILog
{
void Error(Exception exception);
void Error(string customMessage, Exception exception);
void Error(string format, Exception exception, params object[] args);
void Warn(Exception exception);
void Info(string message);
}
Log.cs
public class Log : ILog
{
public void Error(Exception exception)
{
log4net.ILog logger = log4net.LogManager.GetLogger(exception.TargetSite.DeclaringType);
logger.Error(exception.GetBaseException().Message, exception);
}
public void Error(string customMessage, Exception exception)
{
log4net.ILog logger = log4net.LogManager.GetLogger(exception.TargetSite.DeclaringType);
logger.Error(customMessage, exception);
}
public void Error(string format, Exception exception, params object[] args)
{
log4net.ILog logger = log4net.LogManager.GetLogger(exception.TargetSite.DeclaringType);
logger.Error(string.Format(format, args), exception);
}
public void Warn(Exception exception)
{
log4net.ILog logger = log4net.LogManager.GetLogger(exception.TargetSite.DeclaringType);
logger.Warn(exception.GetBaseException().Message, exception);
}
public void Info(string message)
{
log4net.ILog logger = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
logger.Info(message);
}
}
用法示例
public MyClass DeserializeJsonFile(string path)
{
try
{
using (StreamReader r = new StreamReader(path))
{
string json = r.ReadToEnd();
return JsonConvert.DeserializeObject<MyClass>(json);
}
}
catch (Exception ex)
{
this.log.Error("Error deserializing jsonfile. FilePath: {0}", ex, path);
return null;
}
}
现在用字符串插值解决了这个问题:
Log.Error($"Message {CustomerId}", myException);
最简单的是使用:
Log.Error($"Message {CustomerId}, {myException}");
就我而言,我需要临时使用两个记录器(Log4Net 和 Serilog)。我没有写出很好的代码,因为解决方案是临时的。下面是我用的。
public void Error(Exception exception, string messageTemplate, params object[] propertyValues)
{
_messageTemplateProcessor.Process(messageTemplate, propertyValues, out var parsedMessage);
Log.Error(parsedMessage, exception); //Log4Net
_logger.Error(exception, messageTemplate, propertyValues); //Serilog
}
using System.Collections.Generic;
namespace CommonServices
{
class MessageTemplateProcessor
{
public void Process(string messageTemplate, object[] messageTemplateParameters, out string parsedMessage)
{
var blocks = Parse(messageTemplate);
parsedMessage = string.Empty;
var i = 0;
foreach (var block in blocks)
{
if (!block.IsProperty)
{
parsedMessage += block.Text;
continue;
}
parsedMessage += messageTemplateParameters[i];
i++;
}
}
private IEnumerable<Block> Parse(string messageTemplate)
{
var blocks = new List<Block>();
if (string.IsNullOrEmpty(messageTemplate))
{
return blocks;
}
var stack = new Stack<char>();
var word = string.Empty;
foreach (var ch in messageTemplate)
{
if (ch == '{' && stack.Count == 0)
{
if (!string.IsNullOrEmpty(word))
{
blocks.Add(new Block(word, false));
word = string.Empty;
}
stack.Push(ch);
word += ch;
continue;
}
word += ch;
if ((ch != '{' && ch != '}') || (ch == '}' && stack.Count == 0))
{
continue;
}
if (ch == '{' && stack.Count > 0)
{
stack.Push(ch);
continue;
}
if (ch == '}' && stack.Count > 0)
{
if (stack.Count == 1)
{
blocks.Add(new Block(word, true));
word = string.Empty;
stack.Pop();
continue;
}
if (stack.Peek() == '{')
{
stack.Pop();
}
else
{
stack.Push(ch);
}
}
}
if (!string.IsNullOrEmpty(word))
{
blocks.Add(new Block(word, false));
}
return blocks;
}
class Block
{
public Block(string text, bool isProperty)
{
Text = text;
IsProperty = isProperty;
}
public string Text { get; }
public bool IsProperty { get; }
}
}
}
log4net中有2个非常不错的函数:
Log.Error("Message", myException);
和
Log.ErrorFormat("Message {0}", CustomerId);
生产日志记录在输出日志文件中非常漂亮。异常一个很好,因为它很好地打印堆栈跟踪和所有异常详细信息,格式一个很好,因为它允许我指定导致失败的参数。有没有 "best of both worlds" 方法,或者有什么方法可以做到?
Log.ErrorFormatEx("Message {0}", CustomerId, myException)
编辑:我检查了可能重复的问题,但它们的格式很糟糕,不要完全这样问。我在寻找扩展方法或现有方法
您可以创建一个扩展方法:
namespace log4net.Core
{
public class Log4NetExtensions
{
public static void ErrorFormatEx(this ILog logger, string format, Exception exception, params object[] args)
{
logger.Error(string.Format(format, args), exception);
}
}
}
然后您就可以像使用任何其他 Log4Net
方法一样使用它了:
Log.ErrorFormatEx("Message {0}", exception, CustomerId);
知道这个问题已经得到解答,但只是针对可能会发现此替代方案有用的其他用户。我创建了一个 ILog 接口和一个 Log Class 到 "centralize" 我的 log4net 方法和逻辑。我还为 "Error" 方法创建了多个重载。
ILog.cs
public interface ILog
{
void Error(Exception exception);
void Error(string customMessage, Exception exception);
void Error(string format, Exception exception, params object[] args);
void Warn(Exception exception);
void Info(string message);
}
Log.cs
public class Log : ILog
{
public void Error(Exception exception)
{
log4net.ILog logger = log4net.LogManager.GetLogger(exception.TargetSite.DeclaringType);
logger.Error(exception.GetBaseException().Message, exception);
}
public void Error(string customMessage, Exception exception)
{
log4net.ILog logger = log4net.LogManager.GetLogger(exception.TargetSite.DeclaringType);
logger.Error(customMessage, exception);
}
public void Error(string format, Exception exception, params object[] args)
{
log4net.ILog logger = log4net.LogManager.GetLogger(exception.TargetSite.DeclaringType);
logger.Error(string.Format(format, args), exception);
}
public void Warn(Exception exception)
{
log4net.ILog logger = log4net.LogManager.GetLogger(exception.TargetSite.DeclaringType);
logger.Warn(exception.GetBaseException().Message, exception);
}
public void Info(string message)
{
log4net.ILog logger = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
logger.Info(message);
}
}
用法示例
public MyClass DeserializeJsonFile(string path)
{
try
{
using (StreamReader r = new StreamReader(path))
{
string json = r.ReadToEnd();
return JsonConvert.DeserializeObject<MyClass>(json);
}
}
catch (Exception ex)
{
this.log.Error("Error deserializing jsonfile. FilePath: {0}", ex, path);
return null;
}
}
现在用字符串插值解决了这个问题:
Log.Error($"Message {CustomerId}", myException);
最简单的是使用:
Log.Error($"Message {CustomerId}, {myException}");
就我而言,我需要临时使用两个记录器(Log4Net 和 Serilog)。我没有写出很好的代码,因为解决方案是临时的。下面是我用的。
public void Error(Exception exception, string messageTemplate, params object[] propertyValues)
{
_messageTemplateProcessor.Process(messageTemplate, propertyValues, out var parsedMessage);
Log.Error(parsedMessage, exception); //Log4Net
_logger.Error(exception, messageTemplate, propertyValues); //Serilog
}
using System.Collections.Generic;
namespace CommonServices
{
class MessageTemplateProcessor
{
public void Process(string messageTemplate, object[] messageTemplateParameters, out string parsedMessage)
{
var blocks = Parse(messageTemplate);
parsedMessage = string.Empty;
var i = 0;
foreach (var block in blocks)
{
if (!block.IsProperty)
{
parsedMessage += block.Text;
continue;
}
parsedMessage += messageTemplateParameters[i];
i++;
}
}
private IEnumerable<Block> Parse(string messageTemplate)
{
var blocks = new List<Block>();
if (string.IsNullOrEmpty(messageTemplate))
{
return blocks;
}
var stack = new Stack<char>();
var word = string.Empty;
foreach (var ch in messageTemplate)
{
if (ch == '{' && stack.Count == 0)
{
if (!string.IsNullOrEmpty(word))
{
blocks.Add(new Block(word, false));
word = string.Empty;
}
stack.Push(ch);
word += ch;
continue;
}
word += ch;
if ((ch != '{' && ch != '}') || (ch == '}' && stack.Count == 0))
{
continue;
}
if (ch == '{' && stack.Count > 0)
{
stack.Push(ch);
continue;
}
if (ch == '}' && stack.Count > 0)
{
if (stack.Count == 1)
{
blocks.Add(new Block(word, true));
word = string.Empty;
stack.Pop();
continue;
}
if (stack.Peek() == '{')
{
stack.Pop();
}
else
{
stack.Push(ch);
}
}
}
if (!string.IsNullOrEmpty(word))
{
blocks.Add(new Block(word, false));
}
return blocks;
}
class Block
{
public Block(string text, bool isProperty)
{
Text = text;
IsProperty = isProperty;
}
public string Text { get; }
public bool IsProperty { get; }
}
}
}