Git是个很好的源码管理系统,你可以瞬间切换为任何历史版本。为了更好的解析NLog这个组件,我们将时钟倒拨回2004年。(注意:NLog v0.9 has been released 是在2005-06-09)

架构

首先主体项目的代码结构是这个样子的:

逻辑上是这个样子的:

测试

这个时候,代码还没有很多的test case,处于相当的简单粗暴阶段。

static void Main(string[] args)
{
    var l = LogManager.GetLogger("Aaa");
    var l2 = LogManager.GetLogger("Bbb");

    l.Debug("to jest debug");
    l.Info("to jest info");
    l.Warn("to jest warning");
    l2.Debug("to jest debug");
    l2.Info("to jest info");
    l2.Warn("to jest warning");
    l.Error("to jest error");
    l.Fatal("to jest fatal");
    l2.Error("to jest error");
    l2.Fatal("to jest fatal");
    ....
}

GetLogger

入口显然还是LogManager的GetLogger。

    public static Logger GetLogger(string name)
    {
        if (ReloadConfigOnNextLog)
            ReloadConfig();

        lock (typeof(LogManager))
        {

            object l = _loggerCache[name];
            if (l != null)
                return (Logger)l;

            ArrayList[] appendersByLevel = GetAppendersByLevelForLogger(name, Configuration);

            Logger newLogger = new LoggerImpl(name, appendersByLevel);
            _loggerCache[name] = newLogger;
            return newLogger;
        }
    }

这里采用经典的hashtable去储存这些logger实例,以name为key。

Configuration

第一步,从appconfig里面取。

lock (typeof(LogManager))
{
    if (_configLoaded)
        return _config;

    if (_config == null)
    {
        // try to load default configuration
        _config = XmlLoggingConfiguration.AppConfig;
    }

第二步,从一些约定的位置去取,这里我把所有的nlog修改成了mlog是为了方便识别变化点。

private static IEnumerable<string> GetCandidateConfigFileNames()
{
    var currentAppDomain = AppDomain.CurrentDomain;

    // mLog.config from application directory
    yield return Path.Combine(currentAppDomain.BaseDirectory, "mLog.config");

    // Current config file with .config renamed to .nlog
    string cf = AppDomain.CurrentDomain.SetupInformation.ConfigurationFile;
    if (cf != null)
    {
        yield return Path.ChangeExtension(cf, ".mlog");

        // .nlog file based on the non-vshost version of the current config file
        const string vshostSubStr = ".vshost.";
        if (cf.Contains(vshostSubStr))
        {
            yield return Path.ChangeExtension(cf.Replace(vshostSubStr, "."), ".mlog");
        }
    }
}

顺序总结下来,如下图所示:

拿到配置后,这里使用XmlLoggingConfiguration来读取xml格式的配置。

public class XmlLoggingConfiguration : LoggingConfiguration

最后,如果成功的取到了配置,将会实时监控改配置文件的变化

if (_config != null)
    {
        _watcher.Watch(_config.FileNamesToWatch);
    }

当配置改变时候触发标志位的变化:

private static void ConfigFileChanged(object sender, EventArgs args)
{
    // Console.WriteLine("ConfigFileChanged!!!");
    ReloadConfigOnNextLog = true;
}

在每一次write之前,会依据该标志位的变化重载配置文件。

private void WriteToAppenders(LogLevel level, ArrayList appenders, IFormatProvider formatProvider, string message, object[] args) {
        if (LogManager.ReloadConfigOnNextLog)
            LogManager.ReloadConfig();

这个就是所谓的配置文件修改后立即热刷新的实现,我们在写自己的组件的时候可以参考下。

つづく

.NET NLog 详解(二)的更多相关文章

  1. .NET DLL 保护措施详解(二)关于性能的测试

    先说结果: 加了缓存的结果与C#原生代码差异不大了 我对三种方式进行了测试: 第一种,每次调用均动态编译 第二种,缓存编译好的对象 第三种,直接调用原生C#代码 .net dll保护系列 ------ ...

  2. PopUpWindow使用详解(二)——进阶及答疑

      相关文章:1.<PopUpWindow使用详解(一)——基本使用>2.<PopUpWindow使用详解(二)——进阶及答疑> 上篇为大家基本讲述了有关PopupWindow ...

  3. Android 布局学习之——Layout(布局)详解二(常见布局和布局参数)

    [Android布局学习系列]   1.Android 布局学习之——Layout(布局)详解一   2.Android 布局学习之——Layout(布局)详解二(常见布局和布局参数)   3.And ...

  4. logback -- 配置详解 -- 二 -- <appender>

    附: logback.xml实例 logback -- 配置详解 -- 一 -- <configuration>及子节点 logback -- 配置详解 -- 二 -- <appen ...

  5. 爬虫入门之urllib库详解(二)

    爬虫入门之urllib库详解(二) 1 urllib模块 urllib模块是一个运用于URL的包 urllib.request用于访问和读取URLS urllib.error包括了所有urllib.r ...

  6. [转]文件IO详解(二)---文件描述符(fd)和inode号的关系

    原文:https://www.cnblogs.com/frank-yxs/p/5925563.html 文件IO详解(二)---文件描述符(fd)和inode号的关系 ---------------- ...

  7. Android View 的绘制流程之 Layout 和 Draw 过程详解 (二)

    View 的绘制系列文章: Android View 的绘制流程之 Measure 过程详解 (一) Android View 绘制流程之 DecorView 与 ViewRootImpl 在上一篇  ...

  8. HTTPS详解二:SSL / TLS 工作原理和详细握手过程

    HTTPS 详解一:附带最精美详尽的 HTTPS 原理图 HTTPS详解二:SSL / TLS 工作原理和详细握手过程 在上篇文章HTTPS详解一中,我已经为大家介绍了 HTTPS 的详细原理和通信流 ...

  9. Linux dts 设备树详解(二) 动手编写设备树dts

    Linux dts 设备树详解(一) 基础知识 Linux dts 设备树详解(二) 动手编写设备树dts 文章目录 前言 硬件结构 设备树dts文件 前言 在简单了解概念之后,我们可以开始尝试写一个 ...

随机推荐

  1. Navicat for MySQL的使用

    一. 在Navicat for MySQL软件中,如何打开MySQL命令行界面: 图 (1) 如何调出MySQL命令行界面 如图(1)所示,在左侧空白处,右键单击即可调出“命令列介面” 注意,输入My ...

  2. Java总结(一):封装——Encapsulation

    官方定义:一种将抽象性函式接口的实作细节部份包装.隐藏起来的方法.封装可以被认为是一个保护屏障,防止该类的代码和数 据被外部类定义的代码随机访问. 大白话定义:通过getter和setter方法访问私 ...

  3. wxPython中文教程入门实例

    这篇文章主要为大家分享下python编程中有关wxPython的中文教程,分享一些wxPython入门实例,有需要的朋友参考下     wxPython中文教程入门实例 wx.Window 是一个基类 ...

  4. 使用Java中File类批量创建文件和批量修改文件名

    批量创建文件 int cont = 1; String s = "E:\\学习资料\\Java笔记-"; while(cont<100){ File f = new File ...

  5. ios 获得设备型号方法

    以前用UIScreen 的大小来判断设备类型,现在有了iphone6 和 iphone6 plus, 这种方法不能用了.因为当程序不提供相应的启动图片时,系统会把程序运行在320*568的size下, ...

  6. java Thread和Runnable区别

    ①Thread类实现了Runnable接口,主要构造方法为Thread(Runnable target).Thread(Runnable target,String name).Thread(Stri ...

  7. Java for LeetCode 206 Reverse Linked List

    Reverse a singly linked list. 解题思路: 用Stack实现,JAVA实现如下: public ListNode reverseList(ListNode head) { ...

  8. Effective C++ -----条款23:宁以non-member、non-friend替换member函数

    宁可拿non-member non-friend函数替换member函数.这样做可以增加封装性.包裹弹性(packaging flexibility)和机能扩充性.

  9. codeforces 495A. Digital Counter 解题报告

    题目链接:http://codeforces.com/problemset/problem/495/A 这个题目意思好绕好绕~~好绕~~~~~,昨天早上做得 virtual 看不懂,晚上继续看还是,差 ...

  10. H5 前端页面适配响应式

    辞职有半个月了,面试了几家公司,还在挣扎中.... 不废话,H5页面适配成响应式,可以用百分比或者rem. rem是相对于html根元素的单位,可以根据根元素的大小做出等比缩放, 通常,假如设置,ht ...