基于log4net自定义异步logging组件

我们在做开发的时候,需要把一些信息记录下来,方便问题排查、数据分析和统计。通常我们使用log4net作为logging的工具,但是大部分时候需要加以封装,以便更加方便的使用,并且不妨碍主业务程序的运行。下面就是一个异步logging的例子,关键在于:

  1. 简洁:不做过度封装,能满足需要的就是做好的,“done is better than perfect”;
  2. 异步:所有的信息都以异步的方式进行记录,不会对主业务逻辑造成任何的block。

首先,在一个新建的工程里引用log4net.dll,并且进行简单的封装。

  1 using System;
  2 using System.Diagnostics;
  3 using System.IO;
  4 using log4net;
  5 
  6 [assembly: log4net.Config.XmlConfigurator(ConfigFile = "log4net.config", Watch = true)]
  7 
  8 namespace Log
  9 {
 10     public partial class CommonLogging
 11     {
 12         private const string StringNewLineString = "-------------------------------------------------------";
 13 
 14         private static ILog log;
 15 
 16         static CommonLogging()
 17         {
 18             log = LogManager.GetLogger("common");
 19             StartLogThread();
 20         }
 21 
 22         public static void Info(string message)
 23         {
 24             AddLog(message);
 25         }
 26 
 27         public static void Info(string message, Exception ex)
 28         {
 29             AddLog(message, LogType.Info, ex);
 30         }
 31 
 32         public static void InfoLine(string message)
 33         {
 34             AddLogFormat("{0}\r\n{1}", LogType.Info, null, StringNewLineString, message);
 35         }
 36 
 37         public static void Warn(string message)
 38         {
 39             AddLog(message, LogType.Warn);
 40         }
 41 
 42         public static void Warn(string message, Exception ex)
 43         {
 44             AddLog(message, LogType.Warn, ex);
 45         }
 46 
 47         public static void Debug(string message)
 48         {
 49             AddLog(message, LogType.Debug);
 50         }
 51 
 52         public static void Debug(string message, Exception ex)
 53         {
 54             AddLog(message, LogType.Debug, ex);
 55         }
 56 
 57         public static void Error(string message)
 58         {
 59             AddLog(message, LogType.Error);
 60         }
 61 
 62         public static void Error(string message, Exception ex)
 63         {
 64             if (null == ex)
 65             {
 66                 Error(message);
 67                 return;
 68             }
 69 
 70             AddLog(message, LogType.Error, ex);
 71         }
 72 
 73         public static void Fatal(string message)
 74         {
 75             AddLog(message, LogType.Fatal);
 76         }
 77 
 78         public static void Fatal(string message, Exception ex)
 79         {
 80             AddLog(message, LogType.Fatal, ex);
 81         }
 82 
 83         public static void InfoFormat(string format, params string[] args)
 84         {
 85             AddLogFormat(format, LogType.Info, null, args);
 86         }
 87 
 88         public static void ErrorFormat(string format, params string[] args)
 89         {
 90             AddLogFormat(format, LogType.Error, null, args);
 91         }
 92 
 93         public static void ErrorFormat(string format, Exception ex, params string[] args)
 94         {
 95             AddLogFormat(format, LogType.Error, ex, args);
 96         }
 97 
 98         public static void WatchToInfoLog(string message, Action action)
 99         {
100             Stopwatch sw = Stopwatch.StartNew();
101             Info(string.Format("start to {0}", message));
102             action();
103             sw.Stop();
104             Info(string.Format("{0} completed..., cost: {1}", message, sw.Elapsed.TotalSeconds));
105         }
106 
107         public static bool CatchLog(Action action, string errorMsg, bool isThrowException = false)
108         {
109             if (null == action)
110             {
111                 return true;
112             }
113 
114             try
115             {
116                 action();
117                 return true;
118             }
119             catch (Exception ex)
120             {
121                 Error(errorMsg, ex);
122 
123                 if (isThrowException)
124                 {
125                     throw;
126                 }
127 
128                 return false;
129             }
130         }
131 
132         private static string GetLogFileName(string tname)
133         {
134             string name;
135             string basedir = AppDomain.CurrentDomain.BaseDirectory;
136             int pos = basedir.IndexOf("\\inetpub\\");
137             if (pos < 0)
138             {
139                 // we are not running under an inetpub dir, log underneath the base dir
140                 string separator = basedir.EndsWith("\\") ? null : "\\";
141                 name = AppDomain.CurrentDomain.BaseDirectory + separator + @"logs\" + "nevmiss" + tname + ".log";
142             }
143             else
144             {
145                 // we're running on an IIS server, so log under the logs directory so we can share it
146                 name = basedir.Substring(0, pos + 9) + "logs" + Path.DirectorySeparatorChar + "nevmiss_" + tname + ".log";
147             }
148 
149             return name;
150         }
151     }
152 }
CommonLogging

 

使用一个partial类来进行扩展:

  1 using System;
  2 using System.Collections.Concurrent;
  3 using System.Threading;
  4 using System.Threading.Tasks;
  5 
  6 namespace Log
  7 {
  8     public partial class CommonLogging
  9     {
 10         private static ConcurrentQueue<LoggingModel> messageQueue;
 11 
 12         private static Thread thread;
 13 
 14         private static void StartLogThread()
 15         {
 16             messageQueue = new ConcurrentQueue<LoggingModel>();
 17             thread = new Thread(InternalWriteLog);
 18             thread.SetApartmentState(ApartmentState.STA);
 19             thread.IsBackground = true;
 20 
 21             thread.Start();
 22         }
 23 
 24         private static void AddLog(string message, LogType type = LogType.Info, Exception ex = null)
 25         {
 26             messageQueue.Enqueue(new LoggingModel(message, type, ex));
 27             CommonLogging.Trigger();
 28         }
 29 
 30         private static void AddLogFormat(string format, string arg0, LogType type = LogType.Info, Exception ex = null)
 31         {
 32             try
 33             {
 34                 messageQueue.Enqueue(new LoggingModel(string.Format(format, arg0), type, ex));
 35                 CommonLogging.Trigger();
 36             }
 37             catch (Exception exception)
 38             {
 39                 AddLog(string.Format("Add Log Format error, format string:'{0}' , arg0:{1}.", format, arg0), LogType.Error, exception);
 40             }
 41         }
 42 
 43         private static void AddLogFormat(string format, LogType type = LogType.Info, Exception ex = null, params string[] args)
 44         {
 45             try
 46             {
 47                 messageQueue.Enqueue(new LoggingModel(string.Format(format, args), type, ex));
 48                 CommonLogging.Trigger();
 49             }
 50             catch (Exception exception)
 51             {
 52                 AddLog(
 53                     string.Format("Add Log Format error,format:'{0}', arg:{1}.", format, null == args ? null : string.Join(" , ", args)),
 54                     LogType.Error,
 55                     exception);
 56             }
 57         }
 58 
 59         public static void Trigger()
 60         {
 61             if (IsProcessing)
 62             {
 63                 return;
 64             }
 65             else
 66             {
 67                 Task.Factory.StartNew(() =>
 68                 {
 69                     InternalWriteLog();
 70                 });
 71             }
 72         }
 73 
 74         private volatile static bool IsProcessing = false;
 75         public static void InternalWriteLog()
 76         {
 77             LoggingModel model;
 78             while (messageQueue.TryDequeue(out model))
 79             {
 80                 IsProcessing = true;
 81 
 82                 switch (model.MessageType)
 83                 {
 84                     case LogType.Info:
 85                         {
 86                             log.Info(model.Message, model.Exception);
 87                         }
 88                         break;
 89                     case LogType.Error:
 90                         {
 91                             log.Error(model.Message, model.Exception);
 92                         }
 93                         break;
 94                     case LogType.Warn:
 95                         {
 96                             log.Warn(model.Message, model.Exception);
 97                         }
 98                         break;
 99                     case LogType.Debug:
100                         {
101                             log.Debug(model.Message, model.Exception);
102                         }
103                         break;
104                     default:
105                         break;
106                 }
107 
108                 model.Dispose();
109             }
110 
111             IsProcessing = false;
112         }
113     }
114 }
CommonLogging

 

用到的LoggingModel:

 

 1 using System;
 2 
 3 namespace Log
 4 {
 5     internal struct LoggingModel : IDisposable
 6     {
 7         private string message;
 8         private LogType messageType;
 9         private Exception exception;
10 
11         public Exception Exception
12         {
13             get { return this.exception; }
14             set { this.exception = value; }
15         }
16 
17         internal LogType MessageType
18         {
19             get { return this.messageType; }
20             set { this.messageType = value; }
21         }
22 
23         public string Message
24         {
25             get { return this.message; }
26             set
27             {
28                 this.message = value;
29             }
30         }
31 
32         public LoggingModel(string message, bool isError = false, Exception ex = null)
33         {
34             this.message = string.Format("[{0}],{1}", DateTime.UtcNow.ToString("HH:mm:ss,fff"), message);
35             this.messageType = isError ? LogType.Error : LogType.Info;
36             this.exception = ex;
37         }
38 
39         public LoggingModel(string message, LogType type = LogType.Info, Exception ex = null)
40         {
41             this.message = string.Format("[{0}] {1}", DateTime.UtcNow.ToString("HH:mm:ss,fff"), message);
42             this.messageType = type;
43             this.exception = ex;
44         }
45 
46         public void Dispose()
47         {
48             this.exception = null;
49             this.message = null;
50         }
51     }
52 
53     internal enum LogType
54     {
55         Debug = 0,
56 
57         Info = 1,
58 
59         Warn = 2,
60 
61         Error = 3,
62 
63         Fatal = 4,
64     }
65 }
LoggingModel

 

 

 

其次,在需要使用logging的工程中加入单独的配置文件:

<?xml version="1.0"?>
<configuration>
  <configSections>
    <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net"/>
  </configSections>
  <log4net>
    
    <appender name="ConsoleAppender" type="log4net.Appender.ConsoleAppender">
      <layout type="log4net.Layout.PatternLayout">
        <conversionPattern value="%date [%thread] %-5level %logger %ndc - %message%newline" />
      </layout>
    </appender>

    <appender name="CommonLogAppender" type="log4net.Appender.RollingFileAppender">
      <file value="logs\common_"/>
      <encoding value="utf-8"/>
      <appendToFile value="true"/>
      <rollingStyle value="Date"/>
      <datePattern value="yyyyMMdd'.log'"/>
      <maxSizeRollBackups value="10"/>
      <maximumFileSize value="50MB"/>
      <staticLogFileName value="false"/>
      <layout type="log4net.Layout.PatternLayout">
        <conversionPattern value="%date [%thread] %-5level- %message%newline"/>
      </layout>
    </appender>
    
    <!-- Setup the root category, add the appenders and set the default level -->
    <root>
      <level value="ALL" />
      <appender-ref ref="ConsoleAppender" />
    </root>

    <logger name="common">
      <level value="INFO" />
      <appender-ref ref="CommonLogAppender" />
    </logger>
  </log4net>
</configuration>

注意:需要设置log4net.config的属性,使之能够自动拷贝到编译的文件夹中。

 

并且在app.config或者web.config中指定对应的引用:

<appSettings>
    <add key="log4net.Config" value="log4net.config" />
    <add key="log4net.Config.Watch" value="True" />
  </appSettings>

 

这样就可以方便地使用logging而不用担心性能的问题啦。

 

转载于:https://www.cnblogs.com/allanli/p/5286137.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值