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

c#-将log4net配置序列化为XML?,c#,serialization,log4net,wrapper,C#,Serialization,Log4net,Wrapper,在静态日志类中包装log4net时遇到一些问题 我正在使用以下(未完成)类动态生成log4Net配置: public class eLogConfig { public bool AppendToFile = true; /// <summary> /// This is the Path to the folder that will contain the /// Configuation and Logs folder /// Reco

在静态日志类中包装log4net时遇到一些问题

我正在使用以下(未完成)类动态生成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;
        }
    }
}

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

*注意:此实现仅支持每个条目程序集记录到1个Appender。可以添加其他记录器,但可能需要修改序列化和日志类。有关更多信息,请参阅底部的“待办事项”

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);
            }
        }
    }
}
按钮2的输出\u单击:

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
输出文件夹结构:


记录器可配置属性: 设置这些属性将自动更新与条目程序集(&type)关联的logger.config.xml文件


要做:
  • (性能改进)找到另一种获取
    CallingMethod.DeclaringType
    的方法,而无需在
    Log.Debug()
    Log.Info()
    Log.Warn()
    消息上使用StackTrace
  • Log.Error()
    Log.Fatal()
  • 多追加器支持
  • 可配置的输出文件夹路径
  • 实现PatternBuilder类和接口

  • 你的配置文件是什么样子的,你能发布吗?
    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"));
            }
    
        }
    }
    
    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
    
    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
    
    Log.Config.AppendToFile = true;
    Log.Config.Level = Level.Debug;
    Log.Config.LogPattern = "%-5level %date %message";
    Log.Config.MaxLogFiles = 5;
    Log.Config.MaxLogSizeInMB = 5;