LAUREL BRIDGE

LaurelBridge.DCFExamples.NLogAdapter Namespace

DICOM Connectivity Framework V3.4
The NLogAdapter example demonstrates how to add a custom LogAdapter to the DCF.
Classes

  ClassDescription
Public classNLogLogAdapter
Adapter class to demonstrate using NLog as the back end log facility.
Examples

LogAdapter Sample Code
public sealed class NLogLogAdapter : ILogAdapter, IDisposable
{
    private Logger _logger;
    private static readonly object[] NullParams = null;
    private const string NullMessage = "null message";
    private const string NullFormat = "null format";
    private static readonly string _nlogConfigName = "NLog4.config";
    private static readonly string _nlogConfigNameKey = "nlogConfigName";

    /// <summary>
    /// Constructor that configures NLog using the input path to the desired nlog configuration xml file.
    /// </summary>
    /// <remarks>
    /// The logger is constructed using the type of the calling class.
    /// </remarks>
    /// <param name="cfgFilePath">The path of the xml configuration file to use to configure NLog. If the file is null or
    ///     missing, the already loaded nlog configuration will be used.</param>
    /// <param name="formatProvider">The format provider to use when logging messages to nlog, which if set to null will use
    ///     CultureInfo.InvariantCulture.</param>
    public NLogLogAdapter(string cfgFilePath = null, IFormatProvider formatProvider = null)
    {
        if (!String.IsNullOrEmpty(cfgFilePath) && File.Exists(cfgFilePath))
        {
            try
            {
                LoggingConfiguration nlogConfig = new XmlLoggingConfiguration(cfgFilePath);
                LogManager.Configuration = nlogConfig;
            }
            catch
            {
                Console.WriteLine("Error creating new nlog configuration. Using default...");
            }
        }

        FormatProvider = formatProvider ?? CultureInfo.InvariantCulture;
        // get the type of the caller
        Type declaringType = new StackFrame(1).GetMethod().DeclaringType;
        _logger = LogManager.GetLogger(declaringType == null ? "UnknownType" : declaringType.FullName);
    }

    /// <summary>
    /// Get/Set the format provider to use when logging messages to nlog.
    /// </summary>
    /// <remarks>
    /// Unless otherwise specified, a default value of CultureInfo.InvariantCulture will be used.
    /// </remarks>
    public IFormatProvider FormatProvider { get; set; }

    /// <summary>
    /// Get the file name associated with a logging target name.  Dig through any
    /// wrapper filters until we get to a file target and return the directory name.
    /// </summary>
    /// <param name="targetName">The target name.</param>
    /// <returns>The path to the NLog directory.</returns>
    public static string GetNLogLogDirectoryPath(string targetName)
    {
        Target target = NLog.LogManager.Configuration.FindTargetByName(targetName);
        if (target == null)
            throw new ArgumentException("target(" + targetName + ") not found");
        while (target is WrapperTargetBase)
        {
            target = (target as WrapperTargetBase).WrappedTarget;
        }
        FileTarget fileTarget = target as FileTarget;
        if (fileTarget == null)
            throw new ArgumentException("could not find file target for target(" + targetName + ")");

        // Following is a way to get the path of the NLog file    
        LogEventInfo logEventInfo = new LogEventInfo { TimeStamp = DateTime.Now };
        string fileName = fileTarget.FileName.Render(logEventInfo);
        string directoryName = Path.GetDirectoryName(fileName) ?? ".";

        return directoryName;
    }

    /// <summary>
    /// Reconfigures the output log directory for the file logger.
    /// </summary>
    /// <remarks>
    /// <para>
    /// This will only change the log directory if the input log dir is not null or empty and the name of the nlog configuration 
    /// file used to configure the current logger matches the expected name for this nlog log adapter.
    /// </para>
    /// <para>
    /// This method is provided for testing purposes in order to programmatically alter the output directory for various types of 
    /// file loggers (session logging, rotating logging, etc). It is recommended to alter the application configuration file where
    /// possible if a different output log directory is desired.
    /// </para>
    /// </remarks>
    /// <param name="logDir">The new log output directory for the file logger.</param>
    /// <param name="targetName">The name of the NLog FileTarget whose log directory will be reconfigured. If none
    /// is specified, the default target name of 'FileLogger' is used.</param>
    /// <param name="logDirConfigName">The name of the logDir configuration variable in the currently loaded NLog configuration.
    /// Default value is logDir.</param>
    /// <param name="logNameConfigName">The name of the logName configuration variable in the currently loaded NLog configuration.
    /// Default value is logName.</param>
    /// <param name="extension">The extension of the log file. Default value is .log.</param>
    public void ReconfigureLogDirectory(string logDir, string targetName = "FileLogger", string logDirConfigName = "logDir",
        string logNameConfigName = "logName", string extension = ".log")
    {
        if (_logger == null)
            throw new ObjectDisposedException("NLogLogAdapter");
        if (!String.IsNullOrEmpty(logDir) && CheckNLogConfigName())
        {
            try
            {
                LoggingConfiguration cfg = LogManager.Configuration;
                IDictionary<string, SimpleLayout> layouts = cfg.Variables;
                if (layouts.ContainsKey(logDirConfigName))
                {
                    FileTarget target = cfg.FindTargetByName(targetName) as FileTarget;
                    if (target == null)
                        return;
                    string fileName = layouts[logNameConfigName].Text;
                    target.FileName = Path.Combine(logDir, fileName + (extension ?? String.Empty));

                    if (target.ArchiveFileName != null && target.ArchiveFileName.ToString() != String.Empty)
                        target.ArchiveFileName = Path.Combine(logDir, "Archive", fileName, "{#}" + extension);

                    LogManager.ReconfigExistingLoggers();
                }
            }
            catch (Exception e)
            {
                ErrorFormat(new LogEvent(GetType().FullName), e, "Error changing log directory:");
            }
        }
    }

    #region Helpers
    private bool CheckNLogConfigName()
    {
        if (LogManager.Configuration == null || !LogManager.Configuration.Variables.ContainsKey(_nlogConfigNameKey))
            return false;
        string nlogConfigName = LogManager.Configuration.Variables[_nlogConfigNameKey].Text;
        return nlogConfigName.Equals(_nlogConfigName);
    }

    private void WriteLogMessage(LogLevel level, LogEvent context, Exception e, object message)
    {
        WriteLogMessage(level, context, e, (message == null ? NullMessage : message.ToString()), NullParams);
    }

    private void WriteLogMessage(LogLevel level, LogEvent context, Exception e, string format, params object[] args)
    {
        if (format == null)
            format = NullFormat;
        LogEventInfo logEventInfo = new LogEventInfo(level, context.LoggerName, FormatProvider, format, args, e);
        logEventInfo.Properties["SessionId"] = context.IsDefaultSession ? (object)String.Empty : context.SessionId;
        logEventInfo.Properties["SessionName"] = context.SessionName;

        if (context.HasLogContext)
        {
            IDictionary<object, object> contextItems = context.GetLogContext();
            foreach (string key in contextItems.Keys)
            {
                logEventInfo.Properties[key] = contextItems[key];
            }
        }
        _logger.Log(logEventInfo);
    }
    #endregion

    #region ILogAdapter Members
    /// <summary>
    /// Log a fatal level message to the logging backend.
    /// </summary>
    /// <param name="context">The LogEvent for this message.</param>
    /// <param name="e">An exception to be logged if non-null.</param>
    /// <param name="message">The message object.</param>
    public void Fatal(LogEvent context, Exception e, object message)
    {
        WriteLogMessage(LogLevel.Fatal, context, e, message);
    }

    /// <summary>
    /// Log a fatal level message to the logging backend.
    /// </summary>
    /// <param name="context">The LogEvent for this message.</param>
    /// <param name="e">An exception to be logged if non-null.</param>
    /// <param name="format">The format string for the message.</param>
    /// <param name="args">The arguments to the formatted message.</param>
    public void FatalFormat(LogEvent context, Exception e, string format, params object[] args)
    {
        WriteLogMessage(LogLevel.Fatal, context, e, format, args);
    }

    /// <summary>
    /// Log an error level message to the logging backend.
    /// </summary>
    /// <param name="context">The LogEvent for this message.</param>
    /// <param name="e">An exception to be logged if non-null.</param>
    /// <param name="message">The message object.</param>
    public void Error(LogEvent context, Exception e, object message)
    {
        WriteLogMessage(LogLevel.Error, context, e, message);
    }

    /// <summary>
    /// Log an error level message to the logging backend.
    /// </summary>
    /// <param name="context">The LogEvent for this message.</param>
    /// <param name="e">An exception to be logged if non-null.</param>
    /// <param name="format">The format string for the message.</param>
    /// <param name="args">The arguments to the formatted message.</param>
    public void ErrorFormat(LogEvent context, Exception e, string format, params object[] args)
    {
        WriteLogMessage(LogLevel.Error, context, e, format, args);
    }

    /// <summary>
    /// Log a warn level message to the logging backend.
    /// </summary>
    /// <param name="context">The LogEvent for this message.</param>
    /// <param name="e">An exception to be logged if non-null.</param>
    /// <param name="message">The message object.</param>
    public void Warn(LogEvent context, Exception e, object message)
    {
        WriteLogMessage(LogLevel.Warn, context, e, message);
    }

    /// <summary>
    /// Log a warn level message to the logging backend.
    /// </summary>
    /// <param name="context">The LogEvent for this message.</param>
    /// <param name="e">An exception to be logged if non-null.</param>
    /// <param name="format">The format string for the message.</param>
    /// <param name="args">The arguments to the formatted message.</param>
    public void WarnFormat(LogEvent context, Exception e, string format, params object[] args)
    {
        WriteLogMessage(LogLevel.Warn, context, e, format, args);
    }

    /// <summary>
    /// Log an info level message to the logging backend.
    /// </summary>
    /// <param name="context">The LogEvent for this message.</param>
    /// <param name="e">An exception to be logged if non-null.</param>
    /// <param name="message">The message object.</param>
    public void Info(LogEvent context, Exception e, object message)
    {
        WriteLogMessage(LogLevel.Info, context, e, message);
    }

    /// <summary>
    /// Log an info level message to the logging backend.
    /// </summary>
    /// <param name="context">The LogEvent for this message.</param>
    /// <param name="e">An exception to be logged if non-null.</param>
    /// <param name="format">The format string for the message.</param>
    /// <param name="args">The arguments to the formatted message.</param>
    public void InfoFormat(LogEvent context, Exception e, string format, params object[] args)
    {
        WriteLogMessage(LogLevel.Info, context, e, format, args);
    }

    /// <summary>
    /// Log a debug level message to the logging backend.
    /// </summary>
    /// <param name="context">The LogEvent for this message.</param>
    /// <param name="e">An exception to be logged if non-null.</param>
    /// <param name="message">The message object.</param>
    public void Debug(LogEvent context, Exception e, object message)
    {
        WriteLogMessage(LogLevel.Debug, context, e, message);
    }

    /// <summary>
    /// Log a debug level message to the logging backend.
    /// </summary>
    /// <param name="context">The LogEvent for this message.</param>
    /// <param name="e">An exception to be logged if non-null.</param>
    /// <param name="format">The format string for the message.</param>
    /// <param name="args">The arguments to the formatted message.</param>
    public void DebugFormat(LogEvent context, Exception e, string format, params object[] args)
    {
        WriteLogMessage(LogLevel.Debug, context, e, format, args);
    }

    /// <summary>
    /// Log a verbose level message to the logging backend.
    /// </summary>
    /// <param name="context">The LogEvent for this message.</param>
    /// <param name="e">An exception to be logged if non-null.</param>
    /// <param name="message">The message object.</param>
    public void Verbose(LogEvent context, Exception e, object message)
    {
        WriteLogMessage(LogLevel.Trace, context, e, message);
    }

    /// <summary>
    /// Log a verbose level message to the logging backend.
    /// </summary>
    /// <param name="context">The LogEvent for this message.</param>
    /// <param name="e">An exception to be logged if non-null.</param>
    /// <param name="format">The format string for the message.</param>
    /// <param name="args">The arguments to the formatted message.</param>
    public void VerboseFormat(LogEvent context, Exception e, string format, params object[] args)
    {
        WriteLogMessage(LogLevel.Trace, context, e, format, args);
    }

    /// <summary>
    /// Flush any pending buffered log messages.  The implementation of this method is defined by the LogAdapter.
    /// </summary>
    public void Flush()
    {
        if (_logger == null)
            throw new ObjectDisposedException("NLogLogAdapter");
        LogManager.Flush();
    }
    #endregion

    #region IDisposable Members
    /// <summary>
    /// Flush any pending buffered log messages and cleanup logger resources.
    /// </summary>
    /// <remarks>
    /// NLog hooks up to the AppDomain.CurrentDomain.ProcessExit and AppDomain.CurrentDomain.DomainUpload events, and
    /// as such, will automatically shutdown each logger. LogManager.Shutdown currently has a significant expense wrt
    /// how long it takes to dispose.
    /// </remarks>
    public void Dispose()
    {
        if (_logger == null)
            return;
        try
        {
            LogManager.Flush();
            LogManager.Shutdown();
        }
        catch (Exception)
        {
            // ignored
        }
        finally
        {
            _logger = null;
        }
    }
    #endregion
}