c# - 如何将用户信息添加到 nlog 错误日志中
问题描述
我最近开始使用 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.Net Core 3.1 上运行。
如何将其添加到布局中。
谢谢
解决方案
也许不是 100% 适合您的问题,因为您的问题依赖于用户登录到您的应用程序,并且您的应用程序在他们的用户上下文下运行,但以下内容在“正常”应用程序编程中对我有用......
创建一个新的公共静态类。我称我为“日志记录”。如果您的程序集还没有它,请添加对 NLog 的引用。
输出格式是免费提供的 Microsoft CMTrace 实用程序使用的格式。可在此处获取: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
}
用法:
Logging.Setup();
Logging.WriteInfo("Application startup");
Logging.WriteError($"{DestinationFilename}: Cannot overwrite file. User advised to delete file manually. The error was: {ex.Message}");
示例输出:
<![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"' 部分是您所要求的。
推荐阅读
- node.js - 每当我尝试将服务器添加到用户模型时,Sequelize 不会在直通/联结表中添加记录
- python - 编写一个函数longestWord(),它接收一个单词列表,然后返回以“ion”结尾的最长单词
- json - sed 帮助:如何仅当在另一个匹配行范围内找到时打印一系列行
- javascript - 当我将 Google App 脚本嵌入 iFrame 时,为什么有些页面可以工作而有些页面不能工作
- docker - 在运行的 docker 容器中安装包
- javascript - Cheerio 查找功能包括祖先和后代
- c# - 如何重构这些相同的逻辑结构?
- git - 禁用 Git 全局用户名和电子邮件
- python - 调用 .fit 后未安装 Sklearn 管道?
- laravel - 消息:“未定义索引:SKU”