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服務.