如何用新的Logger实例替换NLog Logger?

时间:2016-08-10 13:17:36

标签: c# logging nlog

所以,刚开始使用NLog。我正在进行程序化实施,我尝试设置一个可以导入任何项目的类。该类有两个方法:CreateLogger()和GenerateLog()。这是完整的课程:

using System;
using NLog;
using NLog.Config;
using NLog.Targets;

namespace LogEngine
{
    /// <summary>
    ///     Create an instance of NLog for use on a per class level. 
    /// </summary>
    internal sealed class EventLog
    {
        #region Internal Methods

        /// <summary>
        ///     Generates the NLog.Logger object that will control logging facilities in this program. 
        /// </summary>
        /// <returns>
        ///     static reference to a <see cref="NLog.Logger" /> object. 
        /// </returns>
        internal static Logger CreateLogger(string baseDir = @"${basedir}\")
        {
            // Setup log configuration object and new file and screen output targets.
            var config = new LoggingConfiguration();

            var screenTarget = new ConsoleTarget();
            config.AddTarget("screen", screenTarget);

            var fileTarget = new FileTarget();
            config.AddTarget("file", fileTarget);

            screenTarget.Layout = @"${newline}${message}";

            var MinScreenOutput = new LoggingRule("*", LogLevel.Fatal, screenTarget);
            config.LoggingRules.Add(MinScreenOutput);

            // Set the properties for the file output target.
            fileTarget.FileName = baseDir + @"${appdomain:format={1\}} logs\${shortdate}.log";
            fileTarget.Layout = @"${longdate} ${pad:padcharacter=~:padding=29:inner= ${level:uppercase=true}}"
                              + @" ${pad:padcharacter=~:padding=30:inner= Event ID\: ${event-properties:item=EventCode}}"
                              + @"${newline}${message} ${when:when=level == 'Error':inner=${newline}Class / Method\:"
                              + @"${pad:padding=9:inner=}${callsite:fileName=true:includeSourcePath=false:skipFrames=1}"
                              + @"${newline}Exception\:${pad:padding=14:inner=}${exception}}${newline}";

            // Define what sort of events to send to the file output target.
            var MinOutputDebug = new LoggingRule("*", LogLevel.Debug, fileTarget);
            config.LoggingRules.Add(MinOutputDebug);

            // Set the configuration for the LogManager
            LogManager.Configuration = config;

            // Get the working instance of the logger.
            return LogManager.GetLogger("LogEngine");
        }

        /// <summary>
        ///     Passes one log entry to the destination logger. 
        /// </summary>
        /// <param name="log">
        ///     The <see cref="NLog.Logger" /> object to write the log entry to. 
        /// </param>
        /// <param name="eventId">
        ///     Four character unique event ID as <see cref="System.String" />. 
        /// </param>
        /// <param name="level">
        ///     The <see cref="NLog.LogLevel" /> value. 
        /// </param>
        /// <param name="message">
        ///     The message to save to the log file as <see cref="System.String" />. 
        /// </param>
        /// <param name="ex">
        ///     If this is an error log event, pass it as an <see cref="System.Exception" /> object. 
        /// </param>
        internal static void GenerateLog(Logger log, string eventId, LogLevel level, string message, Exception ex = null)
        {
            // Values used for all events.
            LogEventInfo logEvent = new LogEventInfo();
            logEvent.Properties["EventCode"] = eventId;
            logEvent.Level = level;
            logEvent.Message = message;

            // If we have an error log, make sure the exception is passed.
            if (level.Equals(LogLevel.Error))
                logEvent.Exception = ex;

            // Actually write the log entry.
            log.Log(logEvent);

            if (level.Equals(LogLevel.Error) || level.Equals(LogLevel.Fatal))
                System.Environment.Exit(Convert.ToInt32(eventId));
        }

        #endregion Internal Methods
    }
}

在CreateLogger()方法中,您将看到有一个默认参数。所以,当我在课程开始时在我的程序中调用CreateLogger()时,事情是如何工作的,我没有传递任何参数,$ {basedir}值用于生成初始记录:

internal class Program
{
    #region Private Fields

    private static Logger log = EventLog.CreateLogger();

    #endregion Private Fields
...

但是,在执行期间,我需要将日志记录位置从$ {basedir}更改为我从SQL数据库中提取的值。我是这样做的:

if (!path.Equals(null))
{
    sArgs.path = path.ToString().Trim();
    //NLog.Config.SimpleConfigurator.ConfigureForFileLogging(sArgs.path + @"Logs\log1.txt", LogLevel.Debug);
    //LogManager.Shutdown();
    //LogManager.ReconfigExistingLoggers();
    log = EventLog.CreateLogger(sArgs.path);
    LogManager.ReconfigExistingLoggers();
}

&#34;路径&#34;是对SQLCommand.ExecuteScalar()的调用返回的对象。它是$ {basedir}的替代品,我需要将我的Logger连接到。如果路径不为null,那么我将其转换为字符串并将其存储到实例化为&#34; sArgs&#34;的单例类中。这里有一些注释掉的代码,用于说明我是如何尝试解决此问题的。

好的,所以我看到的是最后一个代码块(当我设置&#34; log&#34;到CreateLogger生成的新实例(sArgs.path)时)我可以看到我的日志记录日志对象中的路径实际上正在更新。但是,当我第一次有机会记录事件时,它仍然使用旧的Logger实例(因此$ {basedir}仍然在使用,而不是sArgs.path)。

我的问题是,我错过的是将更改保留在&#34; log&#34;我可以清楚地看到我在调试器中执行代码时实际上成为Logger对象的位置?或者我是否完全错误地使用EventLog类?

感谢您提供有关此问题的任何见解。

2 个答案:

答案 0 :(得分:0)

对于使用private static Logger log = EventLog.CreateLogger();的每个类,只要不希望使用EventLog类中定义的默认baseDir,就需要更改baseDir。

您没有为您的单件类sArgs或您要使用EventLog的类的任何其他示例提供代码。

使用您的代码,我只将EventLog更改为EventLogger,将默认CreateLogger更改为internal static Logger CreateLogger(string baseDir = @"C:\Temp\NLog\Default\")

using System;
using NLog;

namespace ConsoleApplication1
{
    class Program
    {
        private static Logger log = EventLogger.CreateLogger();

        static void Main(string[] args)
        {

            EventLogger.GenerateLog(log, "1", LogLevel.Debug, "Default", null);

            log = EventLogger.CreateLogger(@"C:\Temp\NLog\New\");
            LogManager.ReconfigExistingLoggers();

            EventLogger.GenerateLog(log, "2", LogLevel.Debug, "New", null);

            Class1.DoSomething();

            Console.WriteLine("Press ENTER to exit");
            Console.ReadLine();
         }
    }
}

和Class1:

using NLog;

namespace ConsoleApplication1
{
    public static class Class1
    {
        private static Logger log = EventLogger.CreateLogger();

        public static void DoSomething()
        {
            EventLogger.GenerateLog(log, "3", LogLevel.Debug, "Class1.DoSomething", null);
        }
    }
}

运行代码会产生以下输出:

Log EventId 1将写入C:\Temp\NLog\Default\ConsoleApplication1.vshost.exe\logs Log EventId 2将写入C:\Temp\NLog\New\ConsoleApplication1.vshost.exe\logs

Class1.cs中的

和LogEventId 3将写入C:\Temp\NLog\Default\ConsoleApplication1.vshost.exe\logs,因为在初始化日志的Class1.cs中,使用了默认路径。如果要在Class1.cs(以及后续类)中更改日志的baseDir,则需要单独更新路径。

希望这会有所帮助。

答案 1 :(得分:0)

感谢@Riann的帮助和补充评论。我实际上将它作为单例类工作而不影响$ {callsite}知道捕获错误的实际方法和行的能力。以下是我从更新的EventLog类开始的方式:

using System;
using NLog;
using NLog.Config;
using NLog.Targets;

namespace LogEngine
{
    /// <summary>
    ///     Create an instance of NLog for use on a per class level. 
    /// </summary>
    internal sealed class EventLog
    {
        #region Constructors

        static EventLog()
        {
        }

        private EventLog()
        {
            this.CreateLogger();
        }

        #endregion Constructors

        #region Singleton Objects

        internal static EventLog logger { get { return _logger; } }

        private static readonly EventLog _logger = new EventLog();

        #endregion Singleton Objects

        #region Private Fields

        private static Logger _log;

        #endregion Private Fields

        #region Internal Methods

        /// <summary>
        ///     Generates the NLog.Logger object that will control logging facilities in this program. 
        /// </summary>
        internal void CreateLogger(string baseDir = @"${basedir}\")
        {
            // Setup log configuration object and new file and screen output targets.
            var config = new LoggingConfiguration();

            var screenTarget = new ConsoleTarget();
            config.AddTarget("screen", screenTarget);

            var fileTarget = new FileTarget();
            config.AddTarget("file", fileTarget);

            screenTarget.Layout = @"${newline}${message}";

            var MinScreenOutput = new LoggingRule("*", LogLevel.Fatal, screenTarget);
            config.LoggingRules.Add(MinScreenOutput);

            // Set the properties for the file output target.
            fileTarget.FileName = baseDir + @"${appdomain:format={1\}} logs\${shortdate}.log";
            fileTarget.Layout = @"${longdate} ${pad:padcharacter=~:padding=29:inner= ${level:uppercase=true}}"
                                + @" ${pad:padcharacter=~:padding=30:inner= Event ID\: ${event-properties:item=EventCode}}"
                                + @"${newline}${message} ${when:when=level == 'Error':inner=${newline}Class / Method\:"
                                + @"${pad:padding=9:inner=}${callsite:fileName=true:includeSourcePath=false:skipFrames=1}"
                                + @"${newline}Exception\:${pad:padding=14:inner=}${exception}}"
                                + @"${when:when=level == 'Fatal':inner=${newline}Class / Method\:"
                                + @"${pad:padding=9:inner=}${callsite:fileName=true:includeSourcePath=false:skipFrames=1}"
                                + @"${newline}Exception\:${pad:padding=14:inner=}${exception}}${newline}";

            // Define what sort of events to send to the file output target.
            var MinOutputDebug = new LoggingRule("*", LogLevel.Debug, fileTarget);
            config.LoggingRules.Add(MinOutputDebug);

            // Set the configuration for the LogManager
            LogManager.Configuration = config;

            // Get the working instance of the logger.
            _log = LogManager.GetLogger("LogEngine");
        }

        /// <summary>
        ///     Passes one log entry to the destination logger and associated exception information. 
        /// </summary>
        /// <remarks>
        ///     Use this form of the method when <see cref="NLog.LogLevel.Error" /> or
        ///     <see cref="NLog.LogLevel.Fatal" /> is used.
        /// </remarks>
        /// <param name="caller">
        ///     <see cref="System.String" /> holding information about the calling method. 
        /// </param>
        /// <param name="eventId">
        ///     Four character unique event ID as <see cref="System.String" />. 
        /// </param>
        /// <param name="level">
        ///     The <see cref="NLog.LogLevel" /> value. 
        /// </param>
        /// <param name="message">
        ///     The message to save to the log file as <see cref="System.String" />. 
        /// </param>
        /// <param name="ex">
        ///     If this is an error log event, pass it as an <see cref="System.Exception" /> object. 
        /// </param>
        internal void GenerateLog(string eventId, LogLevel level, string message, Exception ex)
        {
            // Values used for all events.
            LogEventInfo logEvent = new LogEventInfo();
            logEvent.Properties["EventCode"] = eventId;
            logEvent.Level = level;
            logEvent.Message = message;

            logEvent.Exception = ex;

            // Actually write the log entry.
            _log.Log(logEvent);

            if (level.Equals(LogLevel.Error) || level.Equals(LogLevel.Fatal))
                Environment.Exit(Convert.ToInt32(eventId));
        }

        /// <summary>
        ///     Passes one log entry to the destination logger. 
        /// </summary>
        /// <remarks>
        ///     Use this form of the method when <see cref="NLog.LogLevel.Warn" /> or
        ///     <see cref="NLog.LogLevel.Info" /> is used.
        /// </remarks>
        /// <param name="caller">
        ///     <see cref="System.String" /> holding information about the calling method. 
        /// </param>
        /// <param name="eventId">
        ///     Four character unique event ID as <see cref="System.String" />. 
        /// </param>
        /// <param name="level">
        ///     The <see cref="NLog.LogLevel" /> value. 
        /// </param>
        /// <param name="message">
        ///     The message to save to the log file as <see cref="System.String" />. 
        /// </param>
        internal void GenerateLog(string eventId, LogLevel level, string message)
        {
            // Values used for all events.
            LogEventInfo logEvent = new LogEventInfo();
            logEvent.Properties["EventCode"] = eventId;
            logEvent.Level = level;
            logEvent.Message = message;

            // Actually write the log entry.
            _log.Log(logEvent);
        }

        #endregion Internal Methods
    }
}

基本上,除了Contructor,Singleton Objects和Private Fields区域之外,所有这些都是新的,我不得不在CreateLogger()和GenerateLog()中更改我的调用以影响私有字段_log。我也使GenerateLogger()成为重载方法,但这不会影响EventLog类的整体使用。

在我的其他每个课程中,我只需要更改打开记录器的方式。我打算在方法级别执行此操作,但决定在课程级别执行此操作:

internal class Program
{
    #region Private Fields

    private static readonly EventLog log = EventLog.logger;

    #endregion Private Fields
...

因此,对于我所处的任何方法,如果我想更改我的日志记录路径,我只是要求我的日志实例调用CreateLogger(path):

if (!path.Equals(null))
{
    sArgs.path = path.ToString().Trim();
    log.CreateLogger(sArgs.path);
}

任何未来的电话,无论我在哪个班级,我只需要调用GenerateLog(),我就会有正确的日志路径。