最近在使用log4net的時候有一個簡單的需求,就是自定義個格式化輸出符。這個輸出符是專門用來幫我記錄下業務ID、業務類型的。比如,“businessID:328593,businessType: orderID”。類似這樣的輸出日志。這些日志會被elk agent提取送到日志中心ES中,用來進行輔助排障。
簡單的看了下log4net的PatternLayout和PatternConverter兩個對象的作用,實現起來也是非常方便的。log4net有一組global的PatternLayout,這些全局的格式化對象是默認構造的時候就存在了,我們只需要提供對我們來說特殊場景的實現即可。
你所使用的所有常規的格式化輸出都在全局的注冊了。我們來實現自己的特殊用途的PatternLayout和PatternConverter,除此之外你還需要一個日志信息的載體對象,這里我使用BusinessIDLog類來存放。
using System.IO;
using log4net.Layout.Pattern;
using log4net.Core;
namespace log4net.appender.demo
{
public class BusinessIDPatternConvert : PatternLayoutConverter
{
protected override void Convert(TextWriter writer, LoggingEvent loggingEvent)
{
var businessID = loggingEvent.MessageObject as BusinessIDLog;
if (businessID == null) return;
writer.Write(string.Format(" businessID:{0},businessType:{1}", businessID.ID,businessID.BusinessType));
}
}
}
在log4net里面,每一個特殊的格式符都是一個converter。明白了這個就很容易理解為什么配置一個格式化的字符串就可以得到自己的想要的文本。
namespace log4net.appender.demo
{
public class BusinessIDPatternLayout : log4net.Layout.PatternLayout
{
public BusinessIDPatternLayout()
{
this.AddConverter("businessID", typeof(BusinessIDPatternConvert));
}
}
}
實現一個PatternLayout就可以接管所有的格式化。這里的this.AddConverter,是將我們的businessID的Converter放入當前instance的作用域內。它不是全局的,而是當前實例局部的。
然后在你的log4net的配置文件中配置你自定義的PatternLayout。
<!--日志格式-->
<layout type="log4net.appender.demo.BusinessIDPatternLayout">
<conversionPattern value="%date [%t]%-5level %c [%businessID] %n"/>
</layout>
用戶使用的時候需要傳入BusinessIDLog對象,要不然我們的Converter對象無法獲取到數據對象。
namespace log4net.appender.demo
{
class Program
{
static void Main(string[] args)
{
var loger = LogManager.GetLogger(typeof(Program));
loger.Info(new BusinessIDLog() { ID = "25434535", BusinessType = "orderID" });
}
}
}
這樣就OK了。
是不是很方便。



