Log4net自定义实现httpAppender
Log4net内置了很多Appender但似乎找不到基于Http.在应用希望在本地保存日志的同时也可以把日志提交到一个Http服务中用于统一跟踪管理.如果每记录一次日志都提交给Http服务那对于应用端来说连接的创建是件很损耗性能的事情.由于日志不需要实时同步性,在设计上可以通过定时或当内存日志到达一定数量的时候才进行提交,这样就不会出现频繁提交日志带来的性能问题.
功能定义
Log4net实现一个Appender是一件比较简单的工作,只需要实IAppender接口即可以,当然Log4net也会提供一些基类方便我们实现.接下来我们实现一个httpAppender.在实现之前需制定一些参数用于内部实现用.
Host 日志提交的URL,如:http://localhost:30532/logupload.aspx
ServerTag 提交日志的服务器标记,如:192.168.0.1
AppName 应用程序的名称,如:Game
MaxRecords 内存保存的最大记录数,当日志数量超过些值是进行数据提交
Timer 定时提交时间
制定消息存储结构
public class LogEvent { public LogEvent() { Errors = new List<EventMessage>(); } public string EventType { get; set; } public string ServerTag { get; set; } public string Message { get; set; } public string AppName { get; set; } public DateTime ErrorTime { get; set; } public List<EventMessage> Errors { get; set; } }
public class EventMessage { public string Message { get; set; } public string StackTrace { get; set; } }
Appender实现
/// <summary> /// <code> /// <appender name="HttpAppender" type="log4netUTS.HttpAppender,log4netUTS"> /// <param name="Host" value="http://localhost:30532/WEBFORM1.ASPX"/> /// <param name="ServerTag" value="192.168.0.1"/> /// <param name="AppName" value="test"/> /// <param name="Timer" value="10000"/> /// <param name="MaxRecords" value="1000"/> /// </appender> /// </code> /// </summary> public class HttpAppender : log4net.Appender.AppenderSkeleton { public HttpAppender() { Timer = 5000; MaxRecords = 300; } private System.Threading.Timer mTimer; private void CreateTime() { lock (this) { if (mTimer == null) mTimer = new System.Threading.Timer(Upload, null, Timer, Timer); } } private readonly static Type declaringType = typeof(HttpAppender); private Queue<LogEvent> mEvents = new Queue<LogEvent>(1000); private void Add(LogEvent item) { CreateTime(); lock (mEvents) { mEvents.Enqueue(item); if (mEvents.Count > MaxRecords) Upload(null); } } private void Upload(object state) { List<LogEvent> items = new List<LogEvent>(); lock (mEvents) { while (mEvents.Count > 0) { items.Add(mEvents.Dequeue()); } } if (items.Count > 0) { OnUpload(items); } } private void OnUpload(object state) { try { List<LogEvent> items = (List<LogEvent>)state; string param = "LogData=" + Newtonsoft.Json.JsonConvert.SerializeObject(items); byte[] data = Encoding.UTF8.GetBytes(param); HttpWebRequest req = (HttpWebRequest)HttpWebRequest.Create(Host); req.Method = "POST"; req.ContentType = "application/x-www-form-urlencoded"; req.ContentLength = data.Length; using (Stream reqStream = req.GetRequestStream()) { reqStream.Write(data, 0, data.Length); } using (WebResponse wr = req.GetResponse()) { } } catch (Exception e_) { LogLog.Error(declaringType, e_.Message); } } public string Host { get; set; } public string ServerTag { get; set; } public string AppName { get; set; } public int MaxRecords { get; set; } public int Timer { get; set; } protected override void Append(log4net.Core.LoggingEvent loggingEvent) { try { LogEvent le = new LogEvent(); le.ErrorTime = loggingEvent.TimeStamp; le.EventType = loggingEvent.Level.ToString(); le.Message = loggingEvent.RenderedMessage; le.AppName = AppName; le.ServerTag = ServerTag; AddError(le, loggingEvent.ExceptionObject); Add(le); } catch (Exception e_) { LogLog.Error(declaringType, e_.Message); } } private void AddError(LogEvent e, Exception err) { if (err != null) { e.Errors.Add(new EventMessage { Message = err.Message, StackTrace = err.StackTrace }); err = err.InnerException; while (err != null) { e.Errors.Add(new EventMessage { Message = err.Message, StackTrace = err.StackTrace }); err = err.InnerException; } } } }
实现代码相对比较简单,就是把队列中的数据打包成json格式上传到相关http服务.
访问Beetlex的Github