c# - 将 log4net 配置序列化为 XML?

c# - Serialize log4net Configuration to XML?

我在静态日志记录中封装 log4net 时遇到了一些问题 class。

我正在使用以下(未完成)class 动态生成 log4Net 配置:

public class eLogConfig
{
    public bool AppendToFile = true;
    /// <summary>
    /// This is the Path to the folder that will contain the 
    /// Configuation and Logs folder
    /// Recommended path is ProgramData\CompanyName
    /// </summary>
    public string ParentPath { get; set; }
    public string LogPattern = "%date [%thread] %-5level %logger - %message%newline";
    public int MaxLogFiles = 10;
    public int MaxLogSizeInMB = 10;
    public Level Level = Level.Debug;
    public string LogFilePath
    {
        get
        {
            return Path.Combine(LogFolder,
                Assembly.GetEntryAssembly().GetName().Name
                .e().ToFileName() + ".Log.txt");
        }
    }
    public string ConfigFilePath
    {
        get
        {
            return Path.GetFileNameWithoutExtension(
                    Assembly.GetEntryAssembly().Location
                ).e().ToFileName() + ".Log4Net.config";
        }
    }

    private string ConfigurationFolder
    {
        get
        {
            return Path.Combine(this.ParentPath, "Configuration");
        }
    }
    private string LogFolder
    {
        get
        {
            return Path.Combine(this.ParentPath, "Logs");
        }
    }

    /// <summary>
    /// Initializes a new eLogConfiguration object, for use with initializing a new eLog Logger
    /// </summary>
    /// <param name="ParentPath">The path which will contain the Configuration and Logs folders</param>
    public eLogConfig(DirectoryInfo ParentPath)
    {
        this.ParentPath = ParentPath.FullName;
        if (!Directory.Exists(this.ParentPath))
            Directory.CreateDirectory(this.ParentPath);
        if (!Directory.Exists(ConfigurationFolder))
            Directory.CreateDirectory(ConfigurationFolder);
        if (!Directory.Exists(LogFolder))
            Directory.CreateDirectory(LogFolder);
    }
    private bool initialized = false;
    public void Setup()
    {
        if (!initialized || !File.Exists(LogFilePath))
        {
            Hierarchy hierarchy = (Hierarchy)LogManager.GetRepository();

            PatternLayout patternLayout = new PatternLayout();
            patternLayout.ConversionPattern = this.LogPattern;
            patternLayout.ActivateOptions();

            RollingFileAppender roller = new RollingFileAppender();
            roller.AppendToFile = this.AppendToFile;
            roller.File = this.LogFilePath;
            roller.Layout = patternLayout;
            roller.MaxSizeRollBackups = MaxLogFiles;
            roller.MaximumFileSize = "{0}MB".e(this.MaxLogSizeInMB);
            roller.RollingStyle = RollingFileAppender.RollingMode.Size;
            roller.StaticLogFileName = true;
            roller.ActivateOptions();
            hierarchy.Root.AddAppender(roller);

            MemoryAppender memory = new MemoryAppender();
            memory.ActivateOptions();
            hierarchy.Root.AddAppender(memory);

            hierarchy.Root.Level = this.Level;
            hierarchy.Configured = true;

            //eFile.SaveAsString(hierarchy.Serialize(), ConfigurationFolder);
            initialized = true;
        }
    }
}

代码可以在存储库中创建一个新的 ILogger,我可以开始记录,但配置似乎已保存到 运行 应用程序配置中,但我不知道如何获取它将配置保存到文件中。 如您所见,我已经注释掉了序列化和保存层次结构对象的那一行,因为我知道那是错误的——这不是序列化配置,它会抛出一个异常,错误反映层次结构的内部类型。

我觉得我想多了,我的代码可能会有很大不同。我真的只想要一个 log4Net Config-File-Generator,我可以将其交回我的静态记录器 class 以用于 XmlConfigurator.ConfigureAndWatch(string newConfigPath)DOMConfigurator.ConfigureAndWatch(string newConfigPath)


供参考:

我的静态日志记录 class 看起来像这样(另外,它目前不起作用,因为我一直在使用它来实现我的新配置 Generator\Wrapper):

/// <summary>
/// Log4Net wrapper, based on (http://code.google.com/p/codecampserver/source/list)
/// </summary>
public static partial class eLog
{
    private static readonly Dictionary<Assembly, Dictionary<Type, ILog>> _loggers = new Dictionary<Assembly, Dictionary<Type, ILog>>();
    private static bool _logInitialized;
    private static readonly object _lock = new object();

    public static string SerializeException(Exception exception)
    {
        return SerializeException(exception, string.Empty);
    }

    private static string SerializeException(Exception e, string exceptionMessage)
    {
        if (e == null) return string.Empty;

        exceptionMessage = string.Format(CultureInfo.InvariantCulture,
                                         "{0}{1}{2}\n{3}",
                                         exceptionMessage,

                                         string.IsNullOrEmpty(exceptionMessage) ? string.Empty : "\n\n",
                                         e.Message,
                                         e.StackTrace);

        if (e.InnerException != null)
            exceptionMessage = SerializeException(e.InnerException, exceptionMessage);

        return exceptionMessage;
    }

    private static ILog getLogger(Type source, Assembly assem)
    {
        EnsureInitialized();
        //.Location.Split('.')[0]
        lock (_lock)
        {
            if (!_loggers.ContainsKey(assem))
            {
                _loggers.Add(assem, new Dictionary<Type, ILog>());
            }

            if (_loggers[assem] == null)
            {
                _loggers[assem] = new Dictionary<Type, ILog>();
            }

            if (!_loggers[assem].ContainsKey(source))
            {
                var logger = LogManager.GetLogger(assem, source);
                _loggers[assem].Add(source, logger);
            }
            return _loggers[assem][source];
        }
    }

    /* Log a message object */
    public static void Debug(object source, string message)
    {
        Debug(source.GetType(), message);
    }

    public static void Debug(object source, string message, params object[] ps)
    {
        Debug(source.GetType(), string.Format(message, ps));
    }

    public static void Debug(Type source, string message)
    {
        ILog logger = getLogger(source, Assembly.GetEntryAssembly());
        if (logger.IsDebugEnabled)
            logger.Debug(message);
    }

    public static void Info(object source, object message)
    {
        Info(source.GetType(), message);
    }

    public static void Info(Type source, object message)
    {
        ILog logger = getLogger(source, Assembly.GetEntryAssembly());
        if (logger.IsInfoEnabled)
            logger.Info(message);
    }

    public static void Warn(object source, object message)
    {
        Warn(source.GetType(), message);
    }

    public static void Warn(Type source, object message)
    {
        ILog logger = getLogger(source, Assembly.GetEntryAssembly());
        if (logger.IsWarnEnabled)
            logger.Warn(message);
    }

    public static void Error(object source, object message)
    {
        Error(source.GetType(), message);
    }

    public static void Error(Type source, object message)
    {
        ILog logger = getLogger(source, Assembly.GetEntryAssembly());
        if (logger.IsErrorEnabled)
            logger.Error(message);
    }

    public static void Fatal(object source, object message)
    {
        Fatal(source.GetType(), message);
    }

    public static void Fatal(Type source, object message)
    {
        ILog logger = getLogger(source, Assembly.GetEntryAssembly());
        if (logger.IsFatalEnabled)
            logger.Fatal(message);
    }

    /* Log a message object and exception */

    public static void Debug(object source, object message, Exception exception)
    {
        Debug(source.GetType(), message, exception);
    }

    public static void Debug(Type source, object message, Exception exception)
    {
        getLogger(source, Assembly.GetEntryAssembly()).Debug(message, exception);
    }

    public static void Info(object source, object message, Exception exception)
    {
        Info(source.GetType(), message, exception);
    }

    public static void Info(Type source, object message, Exception exception)
    {
        getLogger(source, Assembly.GetEntryAssembly()).Info(message, exception);
    }

    public static void Warn(object source, object message, Exception exception)
    {
        Warn(source.GetType(), message, exception);
    }

    public static void Warn(Type source, object message, Exception exception)
    {
        getLogger(source, Assembly.GetEntryAssembly()).Warn(message, exception);
    }

    public static void Error(object source, object message, Exception exception)
    {
        Error(source.GetType(), message, exception);
    }

    public static void Error(Type source, object message, Exception exception)
    {
        getLogger(source, Assembly.GetEntryAssembly()).Error(message, exception);
    }

    public static void Fatal(object source, object message, Exception exception)
    {
        Fatal(source.GetType(), message, exception);
    }

    public static void Fatal(Type source, object message, Exception exception)
    {
        getLogger(source, Assembly.GetEntryAssembly()).Fatal(message, exception);
    }

    private static void initialize()
    {
        string path = Path.Combine(
                    eWindows.Paths.ProgramData, // ProgramData
                    Assembly.GetEntryAssembly().FullName.Split('.')[0]);
        eLogConfig config = new eLogConfig(new DirectoryInfo(path));
        config.Setup();

        //XmlConfigurator.ConfigureAndWatch(new FileInfo(path));
        //DOMConfigurator.Configure()

        _logInitialized = true;

    }

    public static void EnsureInitialized()
    {
        if (!_logInitialized)
        {
            initialize();
        }
    }
}

我已经创建了以下简单的 Log4Net 配置和静态日志记录 class(基于 codecampserver 的工作),它使用 IXmlSerializable 接口进行序列化。静态日志 class 自动处理记录器的所有配置,并允许从引用日志 class 的任何程序集进行单行日志记录,它将在 C:\ProgramData\{MyRootNameSpace}\Configuration\ 中创建新的配置文件和文件夹并记录C:\ProgramData\{MyRootNameSpace}\Logs\ 目录中的文件。

*注意:此实现仅支持将日志记录到每个入口程序集的 1 个 Appender。可以添加其他记录器,但可能需要修改序列化和记录 classes。有关详细信息,请参阅底部的 "To-Do"。

using log4net;
using log4net.Appender;
using log4net.Config;
using log4net.Core;
using log4net.Layout;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Xml.Linq;
using System.Runtime.CompilerServices;
using System.Diagnostics;
using System.Security.AccessControl; // Used in IsWritable(directory)
using System.Security.Principal; // Used in IsWritable(directory)

namespace LogWrapper
{
    public class LogConfig
    {
        /// <summary>
        /// Initializes a new LogConfig object, for use with initializing a new Logger
        /// </summary>
        public LogConfig(Type type, Assembly assem)
        {
            Type = type;
            EntryAssembly = assem;
        }
        private Type Type { get; set; }
        private Assembly assembly = Assembly.GetEntryAssembly();
        private Assembly EntryAssembly
        {
            get
            {
                return assembly;
            }
            set
            {
                if (assembly != null)
                    assembly = value;
                this.Update();
            }
        }
        public bool AppendToFile { get; set; } = true;
        private string parentPath = String.Empty;
        /// <summary>
        /// This is the Path to the folder that will contain the 
        /// Configuation and Logs folder
        /// Recommended path is ProgramData\CompanyName
        /// </summary>
        private string ParentPath
        {
            get
            {
                if (String.IsNullOrEmpty(parentPath))
                {
                    return Path.Combine(
                        ProgramData, // ProgramData
                        EntryAssembly.FullName.Split('.')[0]);
                }
                else
                {
                    return parentPath;
                }
            }
            set
            {
                if (IsWritable(new DirectoryInfo(value)))
                {
                    parentPath = value;
                }
                this.Update();
            }
        }
        private string _pattern = "%-5level\t%date{yyyy-MM-dd HH:mm:ss.fff}\t[%thread]\t%logger\t%message%newline";
        public string LogPattern
        {
            get
            {
                return this._pattern;
            }
            set
            {
                if (!String.IsNullOrEmpty(value))
                {
                    this._pattern = value;
                    this.Update();
                }
            }
        }
        public int MaxLogFiles = 5;
        public int MaxLogSizeInMB = 5;
        private Level _level = Level.Debug;
        public Level Level
        {
            get
            {
                return this._level;
            }
            set
            {
                _level = value;
                this.Update();
            }
        }
        private string LogFilePath
        {
            get
            {
                return Path.Combine(LogFolder,
                    EntryAssembly.GetName().Name
                    .ToFileName() + ".log");
            }
        }
        private string ConfigFilePath
        {
            get
            {
                return Path.Combine(ConfigurationFolder,
                    Path.GetFileNameWithoutExtension(
                        EntryAssembly.Location
                    ).ToFileName() + ".Log4Net.config.xml");
            }
        }

        private string ConfigurationFolder
        {
            get
            {
                return Path.Combine(this.ParentPath, "Configuration");
            }
        }
        private string LogFolder
        {
            get
            {
                return Path.Combine(this.ParentPath, "Logs");
            }
        }
        private bool initialized = false;
        internal ILog Setup()
        {
            return this.Update(false);
        }
        internal ILog Update(bool overwrite = true)
        {
            if (!Directory.Exists(this.ParentPath))
                Directory.CreateDirectory(this.ParentPath);
            if (!Directory.Exists(ConfigurationFolder))
                Directory.CreateDirectory(ConfigurationFolder);
            if (!Directory.Exists(LogFolder))
                Directory.CreateDirectory(LogFolder);
            if (!File.Exists(ConfigFilePath) || overwrite)
            {
                var config = this.Serialize();
                File.Create(ConfigFilePath).Close();
                File.WriteAllText(ConfigFilePath, config.ToString());
            }
            var logger = LogManager.GetLogger(EntryAssembly, Type);
            XmlConfigurator.ConfigureAndWatch(new FileInfo(ConfigFilePath));
            if (!initialized)
            {
                initialized = true;
            }
            return logger;
        }
        private XDocument Serialize()
        {
            XDocument xDoc = new XDocument();

            //apender
            var param = new XElement("param");
            param.SetAttributeValue("name", "ConversionPattern");
            param.SetAttributeValue("value", LogPattern);

            var layout = new XElement("layout", param);
            layout.SetAttributeValue("type", typeof(PatternLayout));

            var file = new XElement("file");
            file.SetAttributeValue("value", LogFilePath);

            var append = new XElement("appendToFile");
            append.SetAttributeValue("value", AppendToFile);

            var rollingstyle = new XElement("rollingStyle");
            rollingstyle.SetAttributeValue("value",
                Enum.GetName(typeof(RollingFileAppender.RollingMode)
                    , RollingFileAppender.RollingMode.Size));

            var maxFiles = new XElement("maxSizeRollBackups");
            maxFiles.SetAttributeValue("value", MaxLogFiles);

            var maxFileSize = new XElement("maximumFileSize");
            maxFileSize.SetAttributeValue("value", "{0}MB".FormatWith(MaxLogSizeInMB));

            var staticLogFile = new XElement("StaticLogFileName");
            staticLogFile.SetAttributeValue("value", true);

            var appender = new XElement("appender"
                , file
                , append
                , rollingstyle
                , maxFiles
                , maxFileSize
                , staticLogFile
                , layout);
            appender.SetAttributeValue("name", EntryAssembly.GetName().Name);
            appender.SetAttributeValue("type", typeof(RollingFileAppender));

            //Root
            var level = new XElement("level");
            level.SetAttributeValue("value", Level.Name);
            var appRef = new XElement("appender-ref");
            appRef.SetAttributeValue("ref", EntryAssembly.GetName().Name);

            var root = new XElement("root", level, appRef);

            //Config
            var section = new XElement("section");
            section.SetAttributeValue("name", "log4net");
            section.SetAttributeValue("type", "{0}, {1}".FormatWith(typeof(Log4NetConfigurationSectionHandler), "log4net"));

            var configSection = new XElement("configSections", section);

            var configuration = new XElement("configuration",
                configSection,
                new XElement("log4net",
                    appender, root));

            return XDocument.Parse(configuration.ToString());
        }
        //Helper Methods
        private static string ProgramData
        {
            get
            {
                return Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData);
            }
        }
        private static bool IsWritable(DirectoryInfo destDir)
        {
            if (string.IsNullOrEmpty(destDir.FullName) || !Directory.Exists(destDir.FullName)) return false;
            try
            {
                DirectorySecurity security = Directory.GetAccessControl(destDir.FullName);
                SecurityIdentifier users = new SecurityIdentifier(WellKnownSidType.BuiltinUsersSid, null);
                foreach (AuthorizationRule rule in security.GetAccessRules(true, true, typeof(SecurityIdentifier)))
                {
                    if (rule.IdentityReference == users)
                    {
                        FileSystemAccessRule rights = ((FileSystemAccessRule)rule);
                        if (rights.AccessControlType == AccessControlType.Allow)
                        {
                            if (rights.FileSystemRights == (rights.FileSystemRights | FileSystemRights.Modify)) return true;
                        }
                    }
                }
                return false;
            }
            catch
            {
                return false;
            }
        }
    }
    /// <summary>
    /// Log4Net wrapper, modified from codecampserver (http://code.google.com/p/codecampserver/source/list)
    /// </summary>
    public static partial class Log
    {
        private static readonly Dictionary<Assembly, Dictionary<Type, ILog>> _loggers = new Dictionary<Assembly, Dictionary<Type, ILog>>();
        private static bool _logInitialized;
        private static readonly object _lock = new object();

        public static string SerializException(Exception exception)
        {
            return SerializException(exception, string.Empty);
        }

        private static string SerializException(Exception e, string exceptionMessage)
        {
            if (e == null) return string.Empty;

            exceptionMessage = string.Format(CultureInfo.InvariantCulture,
                                            "{0}{1}{2}\n{3}",
                                            exceptionMessage,
                                            string.IsNullOrEmpty(exceptionMessage) ? string.Empty : "\n\n",
                                            e.Message,
                                            e.StackTrace);

            if (e.InnerException != null)
                exceptionMessage = SerializException(e.InnerException, exceptionMessage);

            return exceptionMessage;
        }

        private static ILog getLogger(Type source, Assembly assem)
        {
            //EnsureInitialized(assem, source);
            lock (_lock)
            {
                if (!_loggers.ContainsKey(assem))
                {
                    _loggers.Add(assem, new Dictionary<Type, ILog>());
                }

                if (_loggers[assem] == null)
                {
                    _loggers[assem] = new Dictionary<Type, ILog>();
                }

                if (!_loggers[assem].ContainsKey(source))
                {
                    _loggers[assem].Add(source, new LogConfig(source, assem).Setup());
                }
                var logger = _loggers[assem][source];
                return logger;
            }
        }
        public static void Debug(string message = "", Exception ex = null, [CallerMemberName] string methodName = "")
        {
            MethodBase method = new StackTrace().GetFrame(1).GetMethod();
            Debug(method.DeclaringType, "{0}()\t{1}".FormatWith(methodName, message.ToCSVFormat()), ex);
        }
        public static void Info(string message = "", Exception ex = null, [CallerMemberName] string methodName = "")
        {
            MethodBase method = new StackTrace().GetFrame(1).GetMethod();
            Info(method.DeclaringType, "{0}()\t{1}".FormatWith(methodName, message.ToCSVFormat()), ex);
        }
        public static void Warn(string message = "", Exception ex = null, [CallerMemberName] string methodName = "")
        {
            MethodBase method = new StackTrace().GetFrame(1).GetMethod();
            Warn(method.DeclaringType, "{0}()\t{1}".FormatWith(methodName, message.ToCSVFormat()), ex);
        }
        public static void Error(string message = "", Exception ex = null, [CallerMemberName] string methodName = "", [CallerFilePath] string file = "")
        {
            MethodBase method = new StackTrace().GetFrame(1).GetMethod();
            Error(method.DeclaringType, "{0}()\t{1} in {2}".FormatWith(methodName, message.ToCSVFormat(), file), ex);
        }
        public static void Error(Exception ex, [CallerMemberName] string methodName = "", [CallerFilePath] string file = "")
        {
            MethodBase method = new StackTrace().GetFrame(1).GetMethod();
            Error(method.DeclaringType, "{0}()\t{1} in {2}".FormatWith(methodName, ex.Message.ToCSVFormat(), file), ex);
        }
        public static void Fatal(string message = "", Exception ex = null, [CallerMemberName] string methodName = "", [CallerLineNumber] int line = -1, [CallerFilePath] string file = "")
        {
            MethodBase method = new StackTrace().GetFrame(1).GetMethod();
            Fatal(method.DeclaringType, "{0}()\t{1} at Line# {2} in [{3}]".FormatWith(methodName, message.ToCSVFormat()), ex);
        }
        public static void Fatal(Exception ex = null, [CallerMemberName] string methodName = "", [CallerLineNumber] int line = -1, [CallerFilePath] string file = "")
        {
            MethodBase method = new StackTrace().GetFrame(1).GetMethod();
            Fatal(method.DeclaringType, "{0}()\t{1} at Line# {2} in [{3}]".FormatWith(methodName, ex.Message.ToCSVFormat()), ex);
        }
        public static LogConfig Config
        {
            get
            {
                return new LogConfig(MethodBase.GetCurrentMethod().DeclaringType, Assembly.GetEntryAssembly());
            }
            set
            {
                _loggers[Assembly.GetEntryAssembly()][MethodBase.GetCurrentMethod().DeclaringType] = value.Update();
            }
        }
        /* Log a message object */
        private static void Debug(Type source, string message)
        {
            ILog logger = getLogger(source, Assembly.GetEntryAssembly());
            if (logger.IsDebugEnabled)
                logger.Debug(message);
        }
        private static void Info(Type source, object message)
        {
            ILog logger = getLogger(source, Assembly.GetEntryAssembly());
            if (logger.IsInfoEnabled)
                logger.Info(message);
        }
        private static void Warn(Type source, object message)
        {
            ILog logger = getLogger(source, Assembly.GetEntryAssembly());
            if (logger.IsWarnEnabled)
                logger.Warn(message);
        }
        private static void Error(Type source, object message)
        {
            ILog logger = getLogger(source, Assembly.GetEntryAssembly());
            if (logger.IsErrorEnabled)
                logger.Error(message);
        }
        private static void Fatal(Type source, object message)
        {
            ILog logger = getLogger(source, Assembly.GetEntryAssembly());
            if (logger.IsFatalEnabled)
                logger.Fatal(message);
        }

        /* Log a message object and exception */
        private static void Debug(object source, object message, Exception exception)
        {
            Debug(source.GetType(), message, exception);
        }
        private static void Debug(Type source, object message, Exception exception)
        {
            getLogger(source, Assembly.GetEntryAssembly()).Debug(message, exception);
        }
        private static void Debug(Type source, string message, Exception exception)
        {
            getLogger(source, Assembly.GetEntryAssembly()).Debug(message, exception);
        }
        private static void Info(object source, object message, Exception exception)
        {
            Info(source.GetType(), message, exception);
        }
        private static void Info(Type source, object message, Exception exception)
        {
            getLogger(source, Assembly.GetEntryAssembly()).Info(message, exception);
        }
        private static void Info(Type source, string message, Exception exception)
        {
            getLogger(source, Assembly.GetEntryAssembly()).Info(message, exception);
        }
        private static void Warn(object source, object message, Exception exception)
        {
            Warn(source.GetType(), message, exception);
        }
        private static void Warn(Type source, object message, Exception exception)
        {
            getLogger(source, Assembly.GetEntryAssembly()).Warn(message, exception);
        }
        private static void Warn(Type source, string message, Exception exception)
        {
            getLogger(source, Assembly.GetEntryAssembly()).Warn(message, exception);
        }
        private static void Error(object source, object message, Exception exception)
        {
            Error(source.GetType(), message, exception);
        }
        private static void Error(Type source, object message, Exception exception)
        {
            getLogger(source, Assembly.GetEntryAssembly()).Error(message, exception);
        }
        private static void Error(Type source, string message, Exception exception)
        {
            getLogger(source, Assembly.GetEntryAssembly()).Error(message, exception);
        }
        private static void Fatal(object source, object message, Exception exception)
        {
            Fatal(source.GetType(), message, exception);
        }
        private static void Fatal(Type source, object message, Exception exception)
        {
            getLogger(source, Assembly.GetEntryAssembly()).Fatal(message, exception);
        }
        private static void Fatal(Type source, string message, Exception exception)
        {
            getLogger(source, Assembly.GetEntryAssembly()).Fatal(message, exception);
        }
        private static void initialize(Assembly assem, Type t)
        {
            _logInitialized = true;
        }
        private static void EnsureInitialized(Assembly assem, Type t)
        {
            if (!_logInitialized)
            {
                initialize(assem, t);
            }
        }
    }
}

用法和输出

用法示例:

namespace Test.Sandbox
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }
        //Example 1: 
        private void button1_Click(object sender, RoutedEventArgs e)
        {
            Log.Debug();
            Log.Debug("button1 Clicked");
            Log.Debug("Fake Error Occured", new Exception("Fake Error"));
        }
        //Example 2:
        private void button2_Click(object sender, RoutedEventArgs e)
        {
            Log.Config.Level = Level.Error; // Set error level (updates logconfig.xml)
            Log.Debug(); //Does not get written because Level has been set to 'Error', above
            Log.Error();
            Log.Error("This is an Error");
            Log.Error(new Exception("Fake Error 2"));
        }

    }
}

来自button1_Click的输出:

DEBUG   2015-12-07 13:11:05.618 [9] Test.Sandbox.MainWindow button1_Click() 
DEBUG   2015-12-07 13:11:05.623 [9] Test.Sandbox.MainWindow button1_Click() button1 Clicked
DEBUG   2015-12-07 13:11:05.623 [9] Test.Sandbox.MainWindow button1_Click() Fake Error Occured
System.Exception: Fake Error

来自button2_Click的输出:

ERROR   2015-12-07 13:11:07.033 [9] Test.Sandbox.MainWindow button2_Click()  in C:\Projects\Test.NET\Test.Sandbox\MainWindow.xaml.cs
ERROR   2015-12-07 13:11:07.034 [9] Test.Sandbox.MainWindow button2_Click() This is an Error in C:\Projects\Test.NET\Test.Sandbox\MainWindow.xaml.cs
ERROR   2015-12-07 13:11:07.034 [9] Test.Sandbox.MainWindow button2_Click() Fake Error 2 in C:\Projects\Test.NET\Test.Sandbox\MainWindow.xaml.cs
System.Exception: Fake Error 2

输出文件夹结构:


记录器可配置属性:

设置这些属性将自动更新与 Entry-Assembly(& 类型)关联的 logger.config.xml 文件

Log.Config.AppendToFile = true;
Log.Config.Level = Level.Debug;
Log.Config.LogPattern = "%-5level %date %message";
Log.Config.MaxLogFiles = 5;
Log.Config.MaxLogSizeInMB = 5;

待办事项:

  1. (性能改进)找到另一种获取 CallingMethod.DeclaringType 的替代方法,而无需在 Log.Debug()Log.Info()Log.Warn() 消息上使用 StackTrace。
  2. Log.Error()Log.Fatal()
  3. 收集额外的 StackTrace 信息
  4. 多 Appender 支持
  5. 可配置的输出文件夹路径
  6. 实施 PatternBuilder class & 接口