zoukankan      html  css  js  c++  java
  • 基于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}
    {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="logscommon_"/>
          <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而不用担心性能的问题啦。

  • 相关阅读:
    Golang gRPC学习(01): gRPC介绍
    MySQL InnoDB存储引擎大观
    SpringBoot学习-图文并茂写Hello World
    Golang的goroutine协程和channel通道
    业务 产品 技术的一点看法
    需求一直做不完,怎么办?
    技术管理:项目开发中的几种风险管理
    go内存管理
    etcd实现分布式锁分析
    强缓存与协商缓存
  • 原文地址:https://www.cnblogs.com/allanli/p/5286137.html
Copyright © 2011-2022 走看看