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"); .... }
入口显然还是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。
第一步,从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();
这个就是所谓的配置文件修改后立即热刷新的实现,我们在写自己的组件的时候可以参考下。
つづく