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

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

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

 using System;
using System.Diagnostics;
using System.IO;
using log4net; [assembly: log4net.Config.XmlConfigurator(ConfigFile = "log4net.config", Watch = true)] namespace Log
{
public partial class CommonLogging
{
private const string StringNewLineString = "-------------------------------------------------------"; private static ILog log; static CommonLogging()
{
log = LogManager.GetLogger("common");
StartLogThread();
} public static void Info(string message)
{
AddLog(message);
} public static void Info(string message, Exception ex)
{
AddLog(message, LogType.Info, ex);
} public static void InfoLine(string message)
{
AddLogFormat("{0}\r\n{1}", LogType.Info, null, StringNewLineString, message);
} public static void Warn(string message)
{
AddLog(message, LogType.Warn);
} public static void Warn(string message, Exception ex)
{
AddLog(message, LogType.Warn, ex);
} public static void Debug(string message)
{
AddLog(message, LogType.Debug);
} public static void Debug(string message, Exception ex)
{
AddLog(message, LogType.Debug, ex);
} public static void Error(string message)
{
AddLog(message, LogType.Error);
} public static void Error(string message, Exception ex)
{
if (null == ex)
{
Error(message);
return;
} AddLog(message, LogType.Error, ex);
} public static void Fatal(string message)
{
AddLog(message, LogType.Fatal);
} public static void Fatal(string message, Exception ex)
{
AddLog(message, LogType.Fatal, ex);
} public static void InfoFormat(string format, params string[] args)
{
AddLogFormat(format, LogType.Info, null, args);
} public static void ErrorFormat(string format, params string[] args)
{
AddLogFormat(format, LogType.Error, null, args);
} public static void ErrorFormat(string format, Exception ex, params string[] args)
{
AddLogFormat(format, LogType.Error, ex, args);
} public static void WatchToInfoLog(string message, Action action)
{
Stopwatch sw = Stopwatch.StartNew();
Info(string.Format("start to {0}", message));
action();
sw.Stop();
Info(string.Format("{0} completed..., cost: {1}", message, sw.Elapsed.TotalSeconds));
} public static bool CatchLog(Action action, string errorMsg, bool isThrowException = false)
{
if (null == action)
{
return true;
} try
{
action();
return true;
}
catch (Exception ex)
{
Error(errorMsg, ex); if (isThrowException)
{
throw;
} return false;
}
} private static string GetLogFileName(string tname)
{
string name;
string basedir = AppDomain.CurrentDomain.BaseDirectory;
int pos = basedir.IndexOf("\\inetpub\\");
if (pos < )
{
// we are not running under an inetpub dir, log underneath the base dir
string separator = basedir.EndsWith("\\") ? null : "\\";
name = AppDomain.CurrentDomain.BaseDirectory + separator + @"logs\" + "nevmiss" + tname + ".log";
}
else
{
// we're running on an IIS server, so log under the logs directory so we can share it
name = basedir.Substring(, pos + ) + "logs" + Path.DirectorySeparatorChar + "nevmiss_" + tname + ".log";
} return name;
}
}
}

CommonLogging

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

 using System;
using System.Collections.Concurrent;
using System.Threading;
using System.Threading.Tasks; namespace Log
{
public partial class CommonLogging
{
private static ConcurrentQueue<LoggingModel> messageQueue; private static Thread thread; private static void StartLogThread()
{
messageQueue = new ConcurrentQueue<LoggingModel>();
thread = new Thread(InternalWriteLog);
thread.SetApartmentState(ApartmentState.STA);
thread.IsBackground = true; thread.Start();
} private static void AddLog(string message, LogType type = LogType.Info, Exception ex = null)
{
messageQueue.Enqueue(new LoggingModel(message, type, ex));
CommonLogging.Trigger();
} private static void AddLogFormat(string format, string arg0, LogType type = LogType.Info, Exception ex = null)
{
try
{
messageQueue.Enqueue(new LoggingModel(string.Format(format, arg0), type, ex));
CommonLogging.Trigger();
}
catch (Exception exception)
{
AddLog(string.Format("Add Log Format error, format string:'{0}' , arg0:{1}.", format, arg0), LogType.Error, exception);
}
} private static void AddLogFormat(string format, LogType type = LogType.Info, Exception ex = null, params string[] args)
{
try
{
messageQueue.Enqueue(new LoggingModel(string.Format(format, args), type, ex));
CommonLogging.Trigger();
}
catch (Exception exception)
{
AddLog(
string.Format("Add Log Format error,format:'{0}', arg:{1}.", format, null == args ? null : string.Join(" , ", args)),
LogType.Error,
exception);
}
} public static void Trigger()
{
if (IsProcessing)
{
return;
}
else
{
Task.Factory.StartNew(() =>
{
InternalWriteLog();
});
}
} private volatile static bool IsProcessing = false;
public static void InternalWriteLog()
{
LoggingModel model;
while (messageQueue.TryDequeue(out model))
{
IsProcessing = true; switch (model.MessageType)
{
case LogType.Info:
{
log.Info(model.Message, model.Exception);
}
break;
case LogType.Error:
{
log.Error(model.Message, model.Exception);
}
break;
case LogType.Warn:
{
log.Warn(model.Message, model.Exception);
}
break;
case LogType.Debug:
{
log.Debug(model.Message, model.Exception);
}
break;
default:
break;
} model.Dispose();
} IsProcessing = false;
}
}
}

CommonLogging

用到的LoggingModel:

 using System;

 namespace Log
{
internal struct LoggingModel : IDisposable
{
private string message;
private LogType messageType;
private Exception exception; public Exception Exception
{
get { return this.exception; }
set { this.exception = value; }
} internal LogType MessageType
{
get { return this.messageType; }
set { this.messageType = value; }
} public string Message
{
get { return this.message; }
set
{
this.message = value;
}
} public LoggingModel(string message, bool isError = false, Exception ex = null)
{
this.message = string.Format("[{0}],{1}", DateTime.UtcNow.ToString("HH:mm:ss,fff"), message);
this.messageType = isError ? LogType.Error : LogType.Info;
this.exception = ex;
} public LoggingModel(string message, LogType type = LogType.Info, Exception ex = null)
{
this.message = string.Format("[{0}] {1}", DateTime.UtcNow.ToString("HH:mm:ss,fff"), message);
this.messageType = type;
this.exception = ex;
} public void Dispose()
{
this.exception = null;
this.message = null;
}
} internal enum LogType
{
Debug = , Info = , Warn = , Error = , Fatal = ,
}
}

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而不用担心性能的问题啦。

基于log4net自定义异步logging组件的更多相关文章

  1. 基于uniapp自定义Navbar+Tabbar组件「兼容H5+小程序+App端Nvue」

    uni-app跨端自定义navbar+tabbar组件|沉浸式导航条|仿咸鱼凸起标签栏 在跨端项目开发中,uniapp是个不错的框架.采用vue.js和小程序语法结构,使得入门开发更容易.拥有非常丰富 ...

  2. 基于log4net的日志组件扩展封装,实现自动记录交互日志 XYH.Log4Net.Extend(微服务监控)

    背景: 随着公司的项目不断的完善,功能越来越复杂,服务也越来越多(微服务),公司迫切需要对整个系统的每一个程序的运行情况进行监控,并且能够实现对自动记录不同服务间的程序调用的交互日志,以及通一个服务或 ...

  3. 011-多线程-基础-基于AbstractQueuedSynchronizer自定义同步组件

    一.概述 队列同步器AbstractQueuedSynchronizer,是用来构建锁或者其他同步组件的基础框架. 1.1.自定义独占锁同步组件 设计一个同步工具:该工具在同一时刻,只允许一个线程访问 ...

  4. 基于事件的异步模式——BackgroundWorker

    实现异步处理的方法很多,经常用的有基于委托的方式,今天记录的是基于事件的异步模式.利用BackgroundWorker组件可以很轻松的实现异步处理,并且该组件还支持事件的取消.进度报告等功能.本文以计 ...

  5. 饿了么基于Vue2.0的通用组件开发之路(分享会记录)

    Element:一套通用组件库的开发之路 Element 是由饿了么UED设计.饿了么大前端开发的一套基于 Vue 2.0 的桌面端组件库.今天我们要分享的就是开发 Element 的一些心得. 官网 ...

  6. 实践基于Task的异步模式

    Await 返回该系列目录<基于Task的异步模式--全面介绍> 在API级别,实现没有阻塞的等待的方法是提供callback(回调函数).对于Tasks来说,这是通过像ContinueW ...

  7. 基于Task的异步模式的定义

    返回该系列目录<基于Task的异步模式--全面介绍> 命名,参数和返回类型 在TAP(Task-based Asynchronous Pattern)中的异步操作的启动和完成是通过一个单独 ...

  8. artDialog是一个基于javascript编写的对话框组件,它拥有精致的界面与友好的接口

    artDialog是一个基于javascript编写的对话框组件,它拥有精致的界面与友好的接口 自适应内容 artDialog的特殊UI框架能够适应内容变化,甚至连外部程序动态插入的内容它仍然能自适应 ...

  9. Event-based Asynchronous Pattern Overview基于事件的异步模式概览

    https://msdn.microsoft.com/zh-cn/library/wewwczdw(v=vs.110).aspx Applications that perform many task ...

随机推荐

  1. 带参宏定义和inline修饰的内联函数

    带参宏定义和inline修饰的内联函数都是在编译时,用函数体替换掉宏调用或函数调用.这样用的好处是减少调用函数所花费的时间. 例如: 算法导论在讲到堆排序时说的,好的堆排序实现一般是把Left(i), ...

  2. 论道HTML5 PDF扫描版

    论道HTML5先简要介绍了如何用HTML5和CSS3制作网站,然后全面介绍了API和Canvas2D,接着介绍了如何在手机浏览器上开发HTML5相关的应用.WebSocketAPI相关的三个案例和时下 ...

  3. 【java】小技巧和注意事项

    1.字符串反向比较  “abc”.equals(sting) 2.文档注释 /** *注释内容 */ 3.

  4. MVC身份验证.MVC过滤器.MVC6关键字Task,Async.前端模拟表单验证,提交.自定义匿名集合.Edge导出到Excel.BootstrapTree树状菜单的全选和反选.bootstrap可搜索可多选可全选下拉框

    1.MVC身份验证. 有两种方式.一个是传统的所有控制器继承自定义Control,然后再里面用MVC的过滤器拦截.所以每次网站的后台被访问时.就会先走入拦截器.进行前端和后端的验证 一个是利用(MVC ...

  5. c#操作word类,进行html和word文档的互相转换

    实例引用:http://www.7es.cn/Software_development/171.shtml using Microsoft.Office.Core;using Word = Micro ...

  6. 用递归算法返回该元素id下面的所有子集id

    private List<int> listAreaId = new List<int>(); /// <summary> /// 递归获取本区域下面的所有子集 / ...

  7. c# ftp创建文件(非上传文件)

    c#  ftp创建文件(非上传文件) 一.奇葩的故事: 今天项目中遇到这么个奇葩的问题,ftp文件传输完成后要在ftp目录下另一个文件夹下创建对应的空文件,听说是为了文件的完整性,既然这么说,那么就必 ...

  8. iOS开发--OC常见报错

    1.解决RegexKitLite导入报错问题 2.The working copy "Test" failed to commit files.问题解决

  9. 【bzoj4800】: [Ceoi2015]Ice Hockey World Championship dfs

    [bzoj4800]: [Ceoi2015]Ice Hockey World Championship N<=40所以如果直接dfs背包会TLE 考虑Meet-in-the-middle 如果把 ...

  10. Jmeter-无法启动,'findstr'不是内部或外部命令,也不是可运行的程序

    今天有一个同事的jmeter无法安装,于是帮他看了看,报以下错误: JAVA的环境变量没有配置好,于是重新配置了下环境变量后,再启动,发现还是不好,于是网上查了下, 发现要在电脑的环境变量中增加 pa ...