在没有事件源注册的情况下写入Windows应用程序事件日志

是否有一种方法可以写入这个事件日志:

enter image description here

或者至少,一些其他Windows默认日志,我不需要注册事件源?

271506 次浏览

你可以使用EventLog类,如如何:写入应用程序事件日志(Visual c#)中解释的那样:

var appLog = new EventLog("Application");
appLog.Source = "MySource";
appLog.WriteEntry("Test log message");

但是,你需要使用管理权限来配置这个 "MySource":

使用WriteEvent和WriteEntry将事件写入事件日志。必须指定事件源来写入事件;在使用事件源写入第一个条目之前,必须创建并配置事件源。

试一试

   System.Diagnostics.EventLog appLog = new System.Diagnostics.EventLog();
appLog.Source = "This Application's Name";
appLog.WriteEntry("An entry to the Application event log.");

这是我使用的记录器类。私有Log()方法中有EventLog.WriteEntry(),这是您实际写入事件日志的方式。我把所有这些代码都包括在这里,因为它很方便。除了日志记录,该类还将确保消息不会太长而无法写入事件日志(它将截断消息)。如果消息太长,就会出现异常。调用方还可以指定源。如果调用者没有,这个类将获取源。希望能有所帮助。

顺便说一下,你可以从网上得到一个objectdump。我不想把这些都贴在这里。我从这里得到了我的:C:\Program Files (x86)\Microsoft Visual Studio 10.0\Samples\1033\CSharpSamples.zip\LinqSamples\ObjectDumper

using System;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Linq;
using System.Reflection;
using Xanico.Core.Utilities;


namespace Xanico.Core
{
/// <summary>
/// Logging operations
/// </summary>
public static class Logger
{
// Note: The actual limit is higher than this, but different Microsoft operating systems actually have
//       different limits. So just use 30,000 to be safe.
private const int MaxEventLogEntryLength = 30000;


/// <summary>
/// Gets or sets the source/caller. When logging, this logger class will attempt to get the
/// name of the executing/entry assembly and use that as the source when writing to a log.
/// In some cases, this class can't get the name of the executing assembly. This only seems
/// to happen though when the caller is in a separate domain created by its caller. So,
/// unless you're in that situation, there is no reason to set this. However, if there is
/// any reason that the source isn't being correctly logged, just set it here when your
/// process starts.
/// </summary>
public static string Source { get; set; }


/// <summary>
/// Logs the message, but only if debug logging is true.
/// </summary>
/// <param name="message">The message.</param>
/// <param name="debugLoggingEnabled">if set to <c>true</c> [debug logging enabled].</param>
/// <param name="source">The name of the app/process calling the logging method. If not provided,
/// an attempt will be made to get the name of the calling process.</param>
public static void LogDebug(string message, bool debugLoggingEnabled, string source = "")
{
if (debugLoggingEnabled == false) { return; }


Log(message, EventLogEntryType.Information, source);
}


/// <summary>
/// Logs the information.
/// </summary>
/// <param name="message">The message.</param>
/// <param name="source">The name of the app/process calling the logging method. If not provided,
/// an attempt will be made to get the name of the calling process.</param>
public static void LogInformation(string message, string source = "")
{
Log(message, EventLogEntryType.Information, source);
}


/// <summary>
/// Logs the warning.
/// </summary>
/// <param name="message">The message.</param>
/// <param name="source">The name of the app/process calling the logging method. If not provided,
/// an attempt will be made to get the name of the calling process.</param>
public static void LogWarning(string message, string source = "")
{
Log(message, EventLogEntryType.Warning, source);
}


/// <summary>
/// Logs the exception.
/// </summary>
/// <param name="ex">The ex.</param>
/// <param name="source">The name of the app/process calling the logging method. If not provided,
/// an attempt will be made to get the name of the calling process.</param>
public static void LogException(Exception ex, string source = "")
{
if (ex == null) { throw new ArgumentNullException("ex"); }


if (Environment.UserInteractive)
{
Console.WriteLine(ex.ToString());
}


Log(ex.ToString(), EventLogEntryType.Error, source);
}


/// <summary>
/// Recursively gets the properties and values of an object and dumps that to the log.
/// </summary>
/// <param name="theObject">The object to log</param>
[SuppressMessage("Microsoft.Globalization", "CA1303:Do not pass literals as localized parameters", MessageId = "Xanico.Core.Logger.Log(System.String,System.Diagnostics.EventLogEntryType,System.String)")]
[SuppressMessage("Microsoft.Naming", "CA1720:IdentifiersShouldNotContainTypeNames", MessageId = "object")]
public static void LogObjectDump(object theObject, string objectName, string source = "")
{
const int objectDepth = 5;
string objectDump = ObjectDumper.GetObjectDump(theObject, objectDepth);


string prefix = string.Format(CultureInfo.CurrentCulture,
"{0} object dump:{1}",
objectName,
Environment.NewLine);


Log(prefix + objectDump, EventLogEntryType.Warning, source);
}


private static void Log(string message, EventLogEntryType entryType, string source)
{
// Note: I got an error that the security log was inaccessible. To get around it, I ran the app as administrator
//       just once, then I could run it from within VS.


if (string.IsNullOrWhiteSpace(source))
{
source = GetSource();
}


string possiblyTruncatedMessage = EnsureLogMessageLimit(message);
EventLog.WriteEntry(source, possiblyTruncatedMessage, entryType);


// If we're running a console app, also write the message to the console window.
if (Environment.UserInteractive)
{
Console.WriteLine(message);
}
}


private static string GetSource()
{
// If the caller has explicitly set a source value, just use it.
if (!string.IsNullOrWhiteSpace(Source)) { return Source; }


try
{
var assembly = Assembly.GetEntryAssembly();


// GetEntryAssembly() can return null when called in the context of a unit test project.
// That can also happen when called from an app hosted in IIS, or even a windows service.


if (assembly == null)
{
assembly = Assembly.GetExecutingAssembly();
}




if (assembly == null)
{
// From http://stackoverflow.com/a/14165787/279516:
assembly = new StackTrace().GetFrames().Last().GetMethod().Module.Assembly;
}


if (assembly == null) { return "Unknown"; }


return assembly.GetName().Name;
}
catch
{
return "Unknown";
}
}


// Ensures that the log message entry text length does not exceed the event log viewer maximum length of 32766 characters.
private static string EnsureLogMessageLimit(string logMessage)
{
if (logMessage.Length > MaxEventLogEntryLength)
{
string truncateWarningText = string.Format(CultureInfo.CurrentCulture, "... | Log Message Truncated [ Limit: {0} ]", MaxEventLogEntryLength);


// Set the message to the max minus enough room to add the truncate warning.
logMessage = logMessage.Substring(0, MaxEventLogEntryLength - truncateWarningText.Length);


logMessage = string.Format(CultureInfo.CurrentCulture, "{0}{1}", logMessage, truncateWarningText);
}


return logMessage;
}
}
}

是的,有一种方法可以写入您正在寻找的事件日志。您不需要创建一个新的源,只需简单地使用现有的源,它通常与事件日志的名称相同,并且在某些情况下,如事件日志应用程序,可以在没有管理权限的情况下访问*。

*其他情况下,你不能直接访问它,是安全事件日志,例如,它只能被操作系统访问。

我使用这段代码直接写入事件日志

using (EventLog eventLog = new EventLog("Application"))
{
eventLog.Source = "Application";
eventLog.WriteEntry("Log message example", EventLogEntryType.Information, 101, 1);
}

如您所见,EventLog源与EventLog的名称相同。原因可以在事件来源@ Windows Dev Center中找到(我加粗了引用源名称的部分):

Eventlog键中的每个日志都包含称为事件源的子键。事件源是记录该事件的软件的名称。它通常是应用程序的名称或应用程序的子组件的名称(如果应用程序比较大)。最多可以向注册中心添加16,384个事件源。

正如MSDN(如。https://msdn.microsoft.com/en-us/library/system.diagnostics.eventlog (v = vs.110) . aspx),检查一个不存在的源和创建一个源需要管理权限。

然而,可以使用源“应用程序”而不使用。 在我在Windows 2012 Server r2下的测试中,我使用“应用程序”源获得了以下日志条目:

source Application中找不到事件ID xxxx的描述。引发此事件的组件没有安装在本地计算机上,或者安装已损坏。您可以在本地计算机上安装或修复组件。 如果事件起源于另一台计算机,则必须将显示信息与事件一起保存。 该活动包括以下资料: {我的事件输入消息} 消息资源存在,但在字符串/消息表

中没有找到消息

我定义了以下方法来创建源代码:

    private string CreateEventSource(string currentAppName)
{
string eventSource = currentAppName;
bool sourceExists;
try
{
// searching the source throws a security exception ONLY if not exists!
sourceExists = EventLog.SourceExists(eventSource);
if (!sourceExists)
{   // no exception until yet means the user as admin privilege
EventLog.CreateEventSource(eventSource, "Application");
}
}
catch (SecurityException)
{
eventSource = "Application";
}


return eventSource;
}

我用currentAppName = AppDomain.CurrentDomain.FriendlyName调用它

也许可以使用EventLogPermission类来代替这个try/catch,但不确定我们是否可以避免catch。

也可以在外部创建源,例如在提升的Powershell中:

New-EventLog -LogName Application -Source MyApp

然后,在上面的方法中使用'MyApp'将不会生成异常,并且可以使用该源创建EventLog。