Catel帮助手册-Catel.Core(6):日志管理
1,简介
从2.2版本开始,Catel使用了一个自定义的日志系统,这种方式,针对log4net的引用可以被移除,做这个修改主要是为了不强迫用户使用log4net,同时,log4net看起来很长时间不更新了,其他的日志系统如NLog看起来在增长,新的日志系统将允许许多基础的日志,这样,日志将将非常简单,并且如果他需要,真正的日志将被用户执行。
1.1 Log和ILog
所有的日志将通过ILog接口。这个接口被自动的注册到Catel中的所有对象上作为Log字段,ILog接口仅仅有一个实现,每个对象能够调用Log自动的方法来记录任何信息。
在Catel中,仅仅有一个类继承与ILog接口,那就是Log类,这个类确保了日志消息能够正确的格式化,并且在消息写入日志的时候会触发LogMessage事件。
Cate内部创建了一个独立的Log类型,这样,开发者能够在许多日志中筛选它自己感兴趣的日志。
1.2 LogManager
LogManager是一个管理类,它将为类型创建新的日志,但是也跟踪所有的日志和日志监听,为了返回一个指定类的日志,可以使用如下代码。
private static readonly ILog Log = LogManager.GetCurrentClassLogger();
1.3 用代码记录日志
使用代码记录日志,ILog接口实现一些基础的方法来记录信息和一些额外数据选项,有一些扩展方法可以记录异常,字符串格式,等等,下面是记录履历的例子:
Log.Warning("Customer '{0}' does not exist", customerId);
或者,如果异常有效,也能写入到日志中。
Log.Error(ex, "Failed to delete file '{0}'", fileName);
1.4 记录到output窗口或者console中
默认情况下,Catel并不增加任何监听,然后,它包含一个立即可用的实现将日志写入到output窗口或者console中,这个就是DebugLogListener,为了注册这个监听,可以使用如下代码。
#if DEBUG
LogManager.AddDebugListener();
#endif
在Catel3.8之前,使用的是LogManager.RegisterDebugListener()
1.5 重写全局的标记级别
从3.8开始可以针对所有的监听重写全区日志标记,如果要这样做,在LogManager上设置一直的值,例如,在所有的监听上强制显示调试履历,使用如下代码:
LogManager.IsDebugEnabled = true;
要重写设置override,设置值为空:
LogManager.IsDebugEnabled = null;
2,自定义监听
每一个监听都可以自定义来返回监听者感兴趣的日志,这样,监听者如果不感兴趣,可以不返回事件,例如,仅仅返回错误,创建一个新的监听如下:
var listener = new MyLogListener();
listener.IsDebugEnabled = false;
listener.IsInfoEnabled = false;
listener.IsWarningEnabled = false;
listener.IsErrorEnabled = true;
默认情况下,所有的日志都会被监听。
3,批量日志监听
批量日志监听是继承IBatchLogListener接口的类(大部分可能继承与BatchLogListenerBase),这个接口增加了一个Flushmethod方法,允许监听者被清理掉,进一步的是日志监听写了一个较慢的监听存储。这个将不会访问每一个源头,而只是批量处理。
3.1 Flushing所有的监听者
当使用批量日志监听者时,当应用程序异常或者是退出时清理所有监听者时很重要的,这是因为有些重要的日志没有持久化到文件中的会丢失掉。
要flushing所有的监听者需要使用如下代码
LogManager.FlushAll();
3.2 实现一个自定义的IBatchLogListener
当实现一个通用的批量日志监听者,常用的方式是继承BatchLogListenerBase类,这个有如下优点:
1,BatchLogListenerBase是线程安全的
2,BatchLogListenerBase每5秒钟会自动的flushes监听者。
你只需要实现WriteLog方法来决定持久化存储的入口,下面是例子:
public class FileLogListener : BatchLogListenerBase
{
private readonly string _filePath;
private readonly int _maxSizeInKiloBytes;
public FileLogListener(string filePath, int maxSizeInKiloBytes)
{
Argument.IsNotNullOrWhitespace(() => filePath);
_filePath = filePath;
_maxSizeInKiloBytes = maxSizeInKiloBytes;
}
protected override void WriteBatch(System.Collections.Generic.List<LogBatchEntry> batchEntries)
{
try
{
var fileInfo = new FileInfo(_filePath);
if (fileInfo.Exists && (fileInfo.Length / 1024 >= _maxSizeInKiloBytes))
{
CreateCopyOfCurrentLogFile(_filePath);
}
using (var fileStream = new FileStream(_filePath, FileMode.Append, FileAccess.Write, FileShare.Read))
{
using (var writer = new StreamWriter(fileStream))
{
foreach (var batchEntry in batchEntries)
{
var message = FormatLogEvent(batchEntry.Log, batchEntry.Message, batchEntry.LogEvent, batchEntry.ExtraData);
writer.WriteLine(message);
}
}
}
}
catch (Exception)
{
// Swallow
}
}
private void CreateCopyOfCurrentLogFile(string filePath)
{
for (int i = 1; i < 999; i++)
{
var possibleFilePath = string.Format("{0}.{1:000}", filePath, i);
if (!File.Exists(possibleFilePath))
{
File.Move(filePath, possibleFilePath);
}
}
}
}
5,集成第三方日志功能
Catel中的日志默认并不写任何输出,这个给了开发者自由,可以使用任何最终的日志机制来处理它。例如Catel可以很容易的使用log4net或者NLOG来集成,通常,下面步骤需要来执行去集成日志。
1,创建自己的或者使用LogListenerBase创建一个自定义的ILogListener
2, 使用LogManager.AddListener将其注册进去。
5.1 集成Log4net方法
下面的例子为Log4net提供了一个ILogListener,但是有些额外的Log库可以被使用。
5.1.1 创建Listener
通过继承LogListenerBase来创建一个新的类:
public class Log4netListener : LogListenerBase
{
protected override void Debug(ILog log, string message, object extraData)
{
var finalLog = log4net.LogManager.GetLogger(log.TargetType);
finalLog.Debug(message);
} protected override void Info(ILog log, string message, object extraData)
{
var finalLog = log4net.LogManager.GetLogger(log.TargetType);
finalLog.Info(message);
} protected override void Warning(ILog log, string message, object extraData)
{
var finalLog = log4net.LogManager.GetLogger(log.TargetType);
finalLog.Warn(message);
} protected override void Error(ILog log, string message, object extraData)
{
var finalLog = log4net.LogManager.GetLogger(log.TargetType);
finalLog.Error(message);
}
}
5.1.2 注册一个监听
最后同样重要的,去注册这个监听
LogManager.AddListener(new Log4netListener());
5.1.3 配置log4net
注意,这仅仅是一个简单的配置,请查看log4net文档看所有的选项:
1,增加log4net的引用
2,增加[assembly: log4net.Config.XmlConfigurator(Watch = true)] 到AssemblyInfo.cs
3,在app.config中配置log4net的实际数据
5.2继承NLog方法
下面的例子为NLog提供了一个ILogListener,但是有些额外的Log库可以被使用。
5.2.1 创建Listener
通过继承LogListenerBase来创建一个新的类:
public class NLogListener : LogListenerBase
{
protected override void Debug(ILog log, string message, object extraData)
{
var finalLog = NLog.LogManager.GetLogger(log.TargetType.ToString());
finalLog.Debug(message);
} protected override void Info(ILog log, string message, object extraData)
{
var finalLog = NLog.LogManager.GetLogger(log.TargetType.ToString());
finalLog.Info(message);
} protected override void Warning(ILog log, string message, object extraData)
{
var finalLog = NLog.LogManager.GetLogger(log.TargetType.ToString());
finalLog.Warn(message);
} protected override void Error(ILog log, string message, object extraData)
{
var finalLog = NLog.LogManager.GetLogger(log.TargetType.ToString());
finalLog.Error(message);
}
}
5.1.2 注册一个监听
最后同样重要的,去注册这个监听
LogManager.AddListener(new NLogListener());
6,将日志写入到磁盘
Catel也支持非常轻量监听来允许其他的外部库,创建一个监听,先创建一个新的类来继承与ILogListener,下一步,将其注册到LogManager中。
ILogListener针对每个LogEvent有一个独立的方法,但是也有一个共享的方法来调用,例如,如果debug信息被写入日志中,Write和Debug方法都会在ILogListener上被调用。
注意:要看批量写入磁盘的例子,可以看前面的日志更新
注意:Catel已经包含了一个FileLogListener,不需要重写这个类,它作为一个例子是很容易理解的。
6.1创建一个监听
可以写一个新的类继承于LogListenerBase。
public class FileLogListener : LogListenerBase
{
private readonly TextWriter _textWriter; public FileLogListener(string fileName)
{
Argument.IsNotNullOrWhitespace("fileName", fileName);
FileName = fileName; _textWriter = new StreamWriter(fileName, true);
} public string FileName { get; private set; } public override void Write(ILog log, string message, LogEvent logEvent)
{
_textWriter.WriteLine(message);
}
}
6.2 注册监听
最后同样重要的注册这个监听
LogManager.AddListener(new FileLogListener("<log_file_path>"));
7,通过配置文件来创建监听
从3.8开始,可以通过配置文件初始化LogListener,下面是一个例子
<configSections>
<sectionGroup name="catel">
<section name="logging" type="Catel.Logging.LoggingConfigurationSection, Catel.Core" />
</sectionGroup>
</configSections> <catel>
<logging>
<listeners>
<listener type="Catel.Logging.FileLogListener" FilePath="CatelLogging.txt" IgnoreCatelLogging="true" IsDebugEnabled="false" IsInfoEnabled="true" IsWarningEnabled="true" IsErrorEnabled="true"/>
</listeners>
</logging>
</catel>
上面Logging节点,需要保护一个没有限制数量的监听,每个监听中至少要提供类型的命名空间
<listener type="Catel.Logging.FileLogListener" />
其他的属性是自定义的,者意味着可以自定义每个加入进来的监听,下面是注册FileLogListener的配置
<listener type="Catel.Logging.FileLogListener" FilePath="CatelLogging.txt" IgnoreCatelLogging="true"
IsDebugEnabled="false" IsInfoEnabled="true" IsWarningEnabled="true" IsErrorEnabled="true"/>
ILogListenr属性(IsDebugEnabled, IsInfoEnabled, IsWarningEnabled and IsErrorEnabled)是对所有的监听有效的,其他的选项依赖于具体的监听类,这样可以提高运行时的灵活性。
8,Antor.Catel.Fody
日志对应用程序是非常重要的,他在应用程序已经部署了很多客户端后,提供了应用程序运行的细节信息。这也是为什么日志是Catel框架中的第一个类。
通常日志通过定义一个继承ILog类的事例来完成。
private static readonly ILog Log = LogManager.GetCurrentClassLogger();
然后通过如下方式来进行调用
Log.Info("This is a logging with a format '{0}'", "test");
写日志定义是无聊和重复的,幸运的是Simon Cropp作为这个的一个解决方案出现了,称之为Antor.Catel.Fody,通过Anotar的实现,引用将被加入到解决方案中,然后在编译了程序集后会被移除,所有针对Log调用的类将会被Catel中实际的类所替换。
8.1 如何使用Antor
使用Antor非常简单,只需要调用LogTo类的静态方法,如下所示:
LogTo.Info("This is a logging with a format '{0}'", "test");
注意,再不需要Log字段了,它将被Anotar自动添加,除了它非常好用外,它执行效率非常高,GetCurrentClassLogger类使用反射来确定当前类,第一次(只会执行一次,因为是静态的)被使用的时候不太影响效率。Anotar通过如下的方式替换调用实现。
private static readonly ILog Log = LogManager.GetLogger(typeof(MyClass));
8.2 附加属性
8.2.1 不显示方法名和行号
通过默认的Anotar记录时会显示方法名和行号
03:58:11:858 => [DEBUG] [AnotarDemo.Program] Method: 'Void Main(String[])'. Line: ~19. this is a test
如果你不想要这样输出,你可以增加如下特性:
[assembly: LogMinimalMessage]
那么输出文件会显示成如下信息
03:59:36:344 => [DEBUG] [AnotarDemo1.Program] this is a test
8.2.2 自动记录异常
可以再一个方法中自动记录异常,要达到这个目的需要使用LogToDebugOnException特性来声明方法。
[LogToDebugOnException]
public static void ExceptionalMethod()
{
throw new Exception("This will be logged automatically");
}
这样声明后,则会打印如下履历。
04:01:48:331 => [DEBUG] [AnotarDemo.Program] Exception occurred in 'Void ExceptionalMethod()'. | [Exception] System.Exception: This will be logged automatically
at AnotarDemo.Program.ExceptionalMethod() in c:\Source\AnotarDemo\AnotarDemo\Program.cs:line 27
Catel帮助手册-Catel.Core(6):日志管理的更多相关文章
- Catel帮助手册-Catel.Core:(1)参数检查
我们检查方法是否正确,一般是返回对错,或者是是否抛出一个异常,大部分人不检查异常的正确性,那么这种错误在很深的堆栈中,很难查看. Catel与一般的检查方法不同,一般是使用 public vo ...
- ABP(现代ASP.NET样板开发框架)系列之8、ABP日志管理
点这里进入ABP系列文章总目录 基于DDD的现代ASP.NET开发框架--ABP系列之8.ABP日志管理 ABP是“ASP.NET Boilerplate Project (ASP.NET样板项目)” ...
- SQL Server中的事务日志管理(3/9):事务日志,备份与恢复
当一切正常时,没有必要特别留意什么是事务日志,它是如何工作的.你只要确保每个数据库都有正确的备份.当出现问题时,事务日志的理解对于采取修正操作是重要的,尤其在需要紧急恢复数据库到指定点时.这系列文章会 ...
- ABP日志管理
ABP日志管理 基于DDD的现代ASP.NET开发框架--ABP系列之8.ABP日志管理 ABP是“ASP.NET Boilerplate Project (ASP.NET样板项目)”的简称. ABP ...
- [置顶] 使用sping AOP 操作日志管理
记录后台操作人员的登陆.退出.进入了哪个界面.增加.删除.修改等操作 在数据库中建立一张SYSLOG表,使用Sping 的AOP实现日志管理,在Sping.xml中配置 <!-- Spring ...
- 八.利用springAMQP实现异步消息队列的日志管理
经过前段时间的学习和铺垫,已经对spring amqp有了大概的了解.俗话说学以致用,今天就利用springAMQP来完成一个日志管理模块.大概的需求是这样的:系统中有很多地方需要记录操作日志,比如登 ...
- Spring Boot 入门(五):集成 AOP 进行日志管理
本篇文章是接着 Spring boot 入门(四):集成 Shiro 实现登陆认证和权限管理写的,按照前面几篇博客的教程,可以搭建一个简单的项目,主要包含了 Pagehelper+MyBatis 分页 ...
- Docker日志管理--docker部署安装ELK (十一)--技术流ken
Docker logs 对于一个运行的容器,Docker 会将日志发送到 容器的 标准输出设备(STDOUT)和标准错误设备(STDERR),STDOUT 和 STDERR 实际上就是容器的控制台终端 ...
- 使用Common.Logging+log4net规范日志管理【转载】
使用Common.Logging+log4net规范日志管理 Common.Logging+(log4net/NLog/) common logging是一个通用日志接口,log4net是一个强大 ...
随机推荐
- 使用 ADD-ON SDK 开发 基于 Html JQuery 和 CSS 的 firefox 插件入门教程1: 创建一个简单的 Add-on
[本文转载自http://sixpoint.me/942/implementing-simple-addon/] 实现一个简单的插件 教程的这个部分带你使用 SDK 来实现, 运行并打包一个插件. 这 ...
- win8\win server 2012添加【中文--美式键盘】
1. 修改注册表 Windows Registry Editor Version 5.00 [HKEY_CURRENT_USERKeyboard Layout] [HKEY_CURRENT_USERK ...
- C++中复制构造函数与重载赋值操作符
我们都知道,在C++中建立一个类,这个类中肯定会包括构造函数.析构函数.复制构造函数和重载赋值操作:即使在你没有明确定义的情况下,编译器也会给你生成这样的四个函数.例如以下类: class CTe ...
- Cloudera Search配置
一.集群机器配置信息 Cloudera集群机器: 10.2.45.104 GBD000.localdomain GBD00010.2.45.105 GBD101.localdomain GBD1011 ...
- 转:对于linux下system()函数的深度理解(整理)
这几天调程序(嵌入式linux),发现程序有时就莫名其妙的死掉,每次都定位在程序中不同的system()函数,直接在shell下输入system()函数中调用的命令也都一切正常.就没理这个bug,以为 ...
- sizeof用法研究
一.基础研究 写一个c程序,打印int.long.double型变量所占的字节数.地址.各个字节的地址和内容.打印地址和内容比较好办,打印地址可以用取址符&,打印内容直接输出就行了,那么怎么打 ...
- Gmail 一些需注意的事
display none 的问题 如果我们写html 然后用 mail server 发给gmail client . 如果内容涉及 display:none , 请加一个 important 比如 ...
- 安卓应用使用QQ登录的申请流程
“QQ互联”是腾讯为第三方网站.媒体.终端提供的开放平台.QQ互联拥有8个组件,提供诸如分享.登陆.like.qq提醒等能力.开发者使用QQ帐号登陆组件可以降低了用户的注册门槛,减少注册环节的用户流失 ...
- 【转】ipad死机了,无法退出,也无法关机,怎么办
原文网址:http://zhidao.baidu.com/link?url=oTz6J78hmtCAKddhwu1ITUiPmLnVJIaA_v_0dZblPaIJUhuMdyTCdS6H2737GX ...
- Android中ListView同过自定义布局并使用SimpleAdapter的方式实现数据的绑定
1.listview的数据填充可以通过ArrayAdapter,SimpleAdapter,也可以是一个xml文件,但是ArrayAdapter与SimpleAdapter的区别是: 2 ArrayA ...