zoukankan      html  css  js  c++  java
  • Nlog、Log4Net 的一个小扩展(增加自定义LEVEL)

    因公司ELK监控分析日志的需要,需要区分进程运行状态日志以及错误日志,以便能够根据日志级别(level)进行不同策略的预警,而现有的Nlog、Log4Net都没有Process这样的level,故针对这两个日志框架做了一些扩展,实现了自定义PROCESS LEVEL,因代码不多,故直接贴代码,有疑问的或好的建议可以下方评论留言交流,谢谢!

    NlogExtend.cs:(Nlog的扩展)文件代码内容如下:

        public static class NlogExtend
        {
            public static void Process(this ILogger logger, string message = "RUNNING")
            {
                var logEventInfo = new LogEventInfo(LogLevel.Trace, logger.Name, message);
                logEventInfo.Properties["custLevel"] = Tuple.Create(9, "Process");
                logger.Log(logEventInfo);
            }
        }
    
        [LayoutRenderer("levelx")]
        public class LevelExLayoutRenderer : LevelLayoutRenderer
        {
    
            protected override void Append(StringBuilder builder, LogEventInfo logEvent)
            {
                if (logEvent.Level == LogLevel.Trace && logEvent.Properties.ContainsKey("custLevel"))
                {
                    var custLevel = logEvent.Properties["custLevel"] as Tuple<int, string>;
                    if (custLevel == null)
                    {
                        throw new InvalidCastException("Invalid Cast Tuple<int, string>");
                    }
    
                    switch (this.Format)
                    {
                        case LevelFormat.Name:
                            builder.Append(custLevel.Item2);
                            break;
                        case LevelFormat.FirstCharacter:
                            builder.Append(custLevel.Item2[0]);
                            break;
                        case LevelFormat.Ordinal:
                            builder.Append(custLevel.Item1);
                            break;
                    }
                }
                else
                {
                    base.Append(builder, logEvent);
                }
            }
        }
    

     因Nlog的LogLevel不允许直接通过继承或New 构造函数来创建一个新的Level,故只能采取把自定义的level写入到LogEventInfo的扩展属性中,然后再自定义一个继承自LevelLayoutRenderer的布局生成器类,就OK了

    用法如下:

    config文件:(用levelx取代原来的level即可)

      <nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
        <targets async="true">
          <target name="file" xsi:type="File" fileName="${basedir}/Logs/${shortdate}.log" layout="[${date:format=yyyy-MM-dd HH:mm:ss.fff}]  ${levelx:uppercase=true}  ${processname}  Thread-${threadid}  ${processname}  ${message}  Stack:${stacktrace}" archiveFileName="${basedir}/Logs/Archives/log.{#}.log" archiveEvery="Day" archiveNumbering="DateAndSequence" archiveAboveSize="10485760" archiveDateFormat="yyyyMMdd" maxArchiveFiles="30" concurrentWrites="true" keepFileOpen="false" />
        </targets>
        <rules>
          <logger name="*" minlevel="Trace" writeTo="file" />
        </rules>
      </nlog>代

    代码中输出PROCESS日志:

        /// <summary>
        /// 基于NLOG框架的日志工具类
        /// </summary>
        public static class LogUtil
        {
            private readonly static ILogger logger = null;
    
            static LogUtil()
            {
                NLog.Config.ConfigurationItemFactory.Default.LayoutRenderers.RegisterDefinition("levelx", typeof(WMSNWPP.LevelExLayoutRenderer));//注册自定义的布局生成器,这样config文件中的levelx才能生效
                logger = LogManager.GetCurrentClassLogger();
            }
    
            public static void Info(string msg)
            {
                try
                {
                    logger.Info(msg);
                }
                catch
                { }
            }
    
            public static void Error(Exception ex)
            {
                try
                {
                    logger.Error(ex);
                }
                catch
                { }
            }
    
    
            public static void Error(string msg)
            {
                try
                {
                    Log(LogLevel.Error, msg);
                }
                catch
                { }
            }
    
            public static void Warn(string msg)
            {
                try
                {
                    logger.Warn(msg);
                }
                catch
                { }
            }
    
            public static void Log(LogLevel level, string msg)
            {
                try
                {
                    logger.Log(level, msg);
                }
                catch
                { }
            }
    
            public static void Process(string message = "RUNNING")
            {
                try
                {
                    logger.Process(message);
                }
                catch
                { }
            }
    
        }
    
    
    
    
    //调用写Process进程日志
    LogUtil.Process();
    

     说完了Nlog,再来说一下Log4Net的扩展实现。

    Log4NetExtend.cs:(Nlog的扩展)文件代码内容如下:

        /// <summary>
        /// Log4Net扩展(扩展一个Process的LOG LEVEL,以便定时输出进程运行日志)
        /// Author:Zuowenjun
        /// Date:2018-4-25
        /// </summary>
        public static class Log4NetExtend
        {
            public static readonly log4net.Core.Level ProcessLevel = new log4net.Core.Level(10001, "PROCESS");
    
            private static void AddProcessLevel(log4net.ILog log)
            {
                if (!log.Logger.Repository.LevelMap.AllLevels.Contains(ProcessLevel))
                {
                    log.Logger.Repository.LevelMap.Add(ProcessLevel);
                }
            }
    
            public static void Process(this log4net.ILog log, string message)
            {
                AddProcessLevel(log);
                log.Logger.Log(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType,
                    ProcessLevel, message, null);
            }
    
            public static void ProcessFormat(this log4net.ILog log, string message, params object[] args)
            {
                AddProcessLevel(log);
                string formattedMessage = string.Format(message, args);
                log.Logger.Log(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType,
                    ProcessLevel, formattedMessage, null);
            }
        }
    
        /// <summary>
        /// 输出当前进程名转换器
        /// </summary>
        public class ProcessPatternConvert : PatternLayoutConverter
        {
            private readonly static string processName = System.Diagnostics.Process.GetCurrentProcess().ProcessName;
            protected override void Convert(System.IO.TextWriter writer, log4net.Core.LoggingEvent loggingEvent)
            {
                writer.Write(processName);//输出当前进程名
            }
        }
    
        public class CustomPatternLayout : log4net.Layout.PatternLayout
        {
            public CustomPatternLayout()
            {
                this.AddConverter("proc", typeof(ProcessPatternConvert));
            }
        }
    

     log4net相对于Nlog好一点,可以通过New Level的构造函数自定义一个新的level实例,但也不好的地方,就是没有默认的显示进程名字,故需要自定义ProcessPatternConvert、CustomPatternLayout,通过CustomPatternLayout的构造函数把ProcessPatternConvert布局转换器类添加到布局转换器集合,这样config中就可以配置proc,以便输出进程名,config配置如下:

      <log4net>
        <appender name="RollingLogFileAppender" type="log4net.Appender.RollingFileAppender">
          <!--日志路径-->
          <param name="File" value="Logs" />
          <!--是否是向文件中追加日志-->
          <param name="AppendToFile" value="true" />
          <!--log保留天数-->
          <param name="MaxSizeRollBackups" value="30" />
          <!--日志文件名是否是固定不变的-->
          <param name="StaticLogFileName" value="false" />
          <!--日志文件名格式为:2008-08-31.log-->
          <param name="DatePattern" value="yyyyMMdd".log"" />
          <!--当日志文件达到10MB,则产生新的日志文件-->
          <maximumFileSize value="10MB"/>
          <!--日志根据日期文件大小滚动-->
          <param name="RollingStyle" value="Composite" />
          <!--最小锁定模型以允许多个进程可以写入同一个文件-->
          <param name="lockingModel" type="log4net.Appender.FileAppender+MinimalLock" />
          <layout type="KyAutoTimingExecSystem.CommonLib.CustomPatternLayout">
            <param name="Header" value="[Begin]
    " />
            <param name="Footer" value="[End]
    " />
            <param name="ConversionPattern" value="[%d]  %5p  %proc Thread-%t  %m%n  Stack:%stacktrace{10}%n" />
          </layout>
        </appender>
        <root>
          <level value="ALL" />
          <appender-ref ref="RollingLogFileAppender" />
        </root>
      </log4net>
    

     代码使用如下:

    public static ILog Logger = LogManager.GetLogger("KyAutoTimingExecSystem");
    Logger.Process(msg);
    

     好了,就介绍到这里,没有什么高大上的技术分享,只是一点对框架扩展的总结,举一反三,可以扩展其它方面。  

  • 相关阅读:
    算法-最大公约数
    算法-最大连续子序列和
    iOS开发-Bug锦囊
    iOS开发-简单抽奖
    iOS开发-UIActionSheet简单介绍
    iOS开发-UIActivityIndicatorView简单使用
    iOS开发-UITextView实现PlaceHolder的方式
    iOS开发-Reachability实时检测Wifi,2G/3G/4G/网络状态
    [转]jsPlumb插件做一个模仿viso的可拖拉流程图
    Python 日期和时间
  • 原文地址:https://www.cnblogs.com/zuowj/p/9147091.html
Copyright © 2011-2022 走看看