可能不是 100% 适合您的问题,因为您的问题依赖于用户登录到您的应用程序,并且您的应用程序在他们的用户上下文下运行,但以下内容适用于“正常”应用程序编程...
创建一个新的公共静态类。我称我为“日志记录”。
如果您的程序集还没有,请添加对 NLog 的引用。
输出格式是免费提供的 Microsoft CMTrace 实用程序使用的格式。可在此处获取:CMTrace Download link
添加以下内容:
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"' 部分就是您所要求的。