C# 如何将用户信息添加到nlog错误日志

C# 如何将用户信息添加到nlog错误日志,c#,exception,nlog,asp.net-core-3.1,error-logging,C#,Exception,Nlog,Asp.net Core 3.1,Error Logging,最近,我开始使用nLog在我的应用程序上记录错误。但是,如果在异常发生时用户当前登录到应用程序,我将在这里查看是否有任何方法可以将有关应用程序上当前登录用户的一些信息添加到日志布局中 目前我有以下布局: <target xsi:type="File" name="errorlogs" fileName="./logs/error-logs/${shortdate}.log" layout="${longd

最近,我开始使用nLog在我的应用程序上记录错误。但是,如果在异常发生时用户当前登录到应用程序,我将在这里查看是否有任何方法可以将有关应用程序上当前登录用户的一些信息添加到日志布局中

目前我有以下布局:

<target xsi:type="File" name="errorlogs" fileName="./logs/error-logs/${shortdate}.log"
        layout="${longdate}|${event-properties:item=EventId_Id}|${uppercase:${level}}|${logger}|${message} ${exception:format=tostring}|url: ${aspnet-request-url}|action: ${aspnet-mvc-action}" />

但是,如果应用程序上有登录用户时发生异常,我希望添加当前登录用户的电子邮件

我的应用程序运行在ASP.NETCore3.1上

如何将其添加到布局中


谢谢

可能不是100%合适,因为您的问题取决于用户登录到您的应用程序,以及您的应用程序在其用户上下文下运行,但以下内容在“正常”应用程序编程中适用于我

创建一个新的公共静态类。我把我的称为“日志记录”。 如果程序集还没有,请添加对NLog的引用

输出格式由免费提供的Microsoft CMTrace实用程序使用。可从以下网址获得:

添加以下内容:

    public static class Logging
{
    #region Fields

    private static bool _IsSetup = false;
    private static Logger _Log = LogManager.GetCurrentClassLogger();

    #endregion

    #region Private Methods

    [MethodImpl(MethodImplOptions.NoInlining)]
    private static string GetCurrentMethod()
    {
        StackTrace st = new StackTrace();
        int FrameNumber = 1;
        StackFrame sf = st.GetFrame(FrameNumber);  // Get the previous stack frame
        string MethodName = sf.GetMethod().Name;
        string ClassName = sf.GetMethod().ReflectedType.FullName;

        while (MethodName == "Log" || MethodName.StartsWith("Write")) // If it's the "Log" or "Write" method calling this, get the method before that one.
        {
            FrameNumber++;

            if (FrameNumber < 6)
            {
                try
                {
                    MethodName = st.GetFrame(FrameNumber).GetMethod().Name;
                    ClassName = st.GetFrame(FrameNumber).GetMethod().ReflectedType.FullName;
                }
                catch
                {
                }
            }
            else // Prevent an infinite loop
            {
                MethodName = "Unknown Method";
                ClassName = "Unknown Class";
            }
        }
        return ClassName + "." + MethodName;
    }

    #endregion

    #region Public Methods

    /// <summary>
    /// Append the specified text to the given TextBox
    /// </summary>
    /// <param name="Message">The message to append</param>
    /// <param name="Control">The TextBox to target</param>
    public static void LogToTextbox(string Message, TextBox Control)
    {
        if (Message.Length > 0)
        {
            Control.AppendText(Message + Environment.NewLine);
            Control.Refresh();
            Application.DoEvents();
        }
    }

    /// <summary>
    /// Setup Logging
    /// </summary>
    /// <param name="Overwrite">If set to true, any existing file will be over-written</param>
    public static void Setup(bool Overwrite = false)
    {
        LoggingConfiguration Config = new LoggingConfiguration();
        FileTarget File = new FileTarget();

        Config.AddTarget("File", File);
        File.Layout = "${message}";
        File.FileName = System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), Application.CompanyName, System.Diagnostics.Process.GetCurrentProcess().ProcessName) + ".log";
        File.AutoFlush = true;
        File.KeepFileOpen = false;
        File.ArchiveFileName = System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), Application.CompanyName, System.Diagnostics.Process.GetCurrentProcess().ProcessName) + "_{#}.log";
        File.ArchiveNumbering = ArchiveNumberingMode.Rolling;
        File.ArchiveEvery = FileArchivePeriod.Day;
        File.MaxArchiveDays = 31;

        if (Overwrite)
        {
            File.DeleteOldFileOnStartup = true;
        }

        // Create rules
        LoggingRule Rule1 = new LoggingRule("*", LogLevel.Trace, File);

        // Apply rules
        Config.LoggingRules.Add(Rule1);

        // Activate logging
        LogManager.Configuration = Config;

        // Cleanup

        _IsSetup = true;
    }

    /// <summary>
    /// Write the specified message type and string to the logfile, located at %PROGRAMDATA/[Application.CompanyName]
    /// </summary>
    /// <param name="Level">The level of message to write</param>
    /// <param name="Message">The message to write</param>
    public static void Write(LogLevel Level, string Message)
    {
        string Severity;
        string OutputMessage;
        DateTime UtcNow = DateTime.UtcNow;
        DateTime Now = DateTime.Now;
        string UtcDate = UtcNow.ToString("MM-dd-yyyy");
        string UtcTime = UtcNow.ToString("HH:mm:ss.") + UtcNow.Millisecond;
        string Date = Now.ToString("dd-MM-yyyy");
        string Time = Now.ToString("HH:mm:ss.") + UtcNow.Millisecond;
        string TZOffset = TimeZoneInfo.Local.GetUtcOffset(Now).TotalHours.ToString("+000");

        if (!_IsSetup)
        {
            Setup();
        }

        Trace.WriteLine(Message);

        Message = $"{Date} {Time}: {Message}";

        switch (Level.Name)
        {
            default:
                Severity = "0";
                break;
            case "Info":
                Severity = "1";
                break;
            case "Warn":
                Severity = "2";
                break;
            case "Error":
                Severity = "3";
                break;
        }

        // https://adamtheautomator.com/building-logs-for-cmtrace-powershell/

        OutputMessage = $"<![LOG[{Message}]LOG]!><time=\"{UtcTime}{TZOffset}\" date=\"{UtcDate}\" component=\"{GetCurrentMethod()}\" context=\"{Environment.UserName}\" type=\"{Severity}\" thread=\"{Thread.CurrentThread.ManagedThreadId}\" file=\"{System.Diagnostics.Process.GetCurrentProcess().ProcessName}\">";

        // The following can be used as a catch-all

        //try
        //{
        _Log.Log(Level, OutputMessage);
        //}
        //catch (Exception e)
        //{
        //    // If we cannot write to the log file, write to the EventLog instead.
        //    using (EventLog eventLog = new EventLog("Application"))
        //    {
        //        string OutputFolderName = System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), Application.CompanyName);
        //        string ExecutableName = System.Diagnostics.Process.GetCurrentProcess().ProcessName;

        //        eventLog.Source = "Application";
        //        eventLog.WriteEntry($"Failed to write to application logfile (in {OutputFolderName}) for {ExecutableName}.  The error was: {e.Message}", EventLogEntryType.Error, 101, 1);
        //    }
        //}
    }

    /// <summary>
    /// Write a error message to the logfile, located at %PROGRAMDATA/[Application.CompanyName]
    /// </summary>
    /// <param name="Message">The message to write</param>
    public static void WriteError(string Message)
    {
        Write(LogLevel.Error, Message);
    }

    /// <summary>
    /// Write an informational message to the logfile, located at %PROGRAMDATA/[Application.CompanyName]
    /// </summary>
    /// <param name="Message">The message to write</param>
    public static void WriteInfo(string Message)
    {
        Write(LogLevel.Info, Message);
    }

    /// <summary>
    /// Write a warning message to the logfile, located at %PROGRAMDATA/[Application.CompanyName]
    /// </summary>
    /// <param name="Message">The message to write</param>
    public static void WriteWarning(string Message)
    {
        Write(LogLevel.Warn, Message);
    }

    #endregion

}
示例输出:

<![LOG[20-11-2020 13:22:48.626: Application startup]LOG]!><time="05:22:48.626+008" date="11-20-2020" component="Bitberry.Elda.GetLatest.frmMain..ctor" context="DaveR" type="1" thread="1" file="GetLatest">


具体来说,“context=”USERNAME“部分就是您要求的内容。

电子邮件是否可以通过?此拉取请求将添加对用户声明查找的支持:记住GDPR规则:)认为原始问题是记录登录到AspNet网站的用户的电子邮件<代码>环境。用户名<代码>将返回正在运行的应用程序的服务帐户/用户帐户(匹配nlog <代码> ${环境用户} /代码>),您应该考虑利用Nlog LayouTrEnter来执行上下文捕获。然后您的代码段可以简化为一条NLog-Layout-line。谢谢@RolfKristensen。请注意,我在我的第一段中(或至少,我试着)阐述了你的观点(在你的第一条评论中)
<![LOG[20-11-2020 13:22:48.626: Application startup]LOG]!><time="05:22:48.626+008" date="11-20-2020" component="Bitberry.Elda.GetLatest.frmMain..ctor" context="DaveR" type="1" thread="1" file="GetLatest">