简体   繁体   English

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

[英]Write to Windows Application Event Log without event source registration

Is there a way to write to this event log:有没有办法写入此事件日志:

在此处输入图像描述

Or at least, some other Windows default log, where I don't have to register an event source ?或者至少是其他一些 Windows 默认日志,我不必在其中注册事件源

Yes, there is a way to write to the event log you are looking for.是的,有一种方法可以写入您要查找的事件日志。 You don't need to create a new source, just simply use the existent one, which often has the same name as the EventLog's name and also, in some cases like the event log Application, can be accessible without administrative privileges*.您不需要创建新的源,只需使用现有的源,它通常与 EventLog 的名称同名,并且在某些情况下,例如事件日志应用程序,无需管理权限即可访问*。

*Other cases, where you cannot access it directly, are the Security EventLog, for example, which is only accessed by the operating system. *您无法直接访问它的其他情况是安全事件日志,例如,它只能由操作系统访问。

I used this code to write directly to the event log Application:我使用此代码直接写入事件日志应用程序:

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

As you can see, the EventLog source is the same as the EventLog's name.如您所见,EventLog 源与 EventLog 的名称相同。 The reason of this can be found in Event Sources @ Windows Dev Center (I bolded the part which refers to source name):原因可以在Event Sources @ Windows Dev Center中找到(我将引用源名称的部分加粗):

Each log in the Eventlog key contains subkeys called event sources. Eventlog 键中的每个日志都包含称为事件源的子键。 The event source is the name of the software that logs the event.事件源是记录事件的软件的名称。 It is often the name of the application or the name of a subcomponent of the application if the application is large.如果应用程序很大,它通常是应用程序的名称或应用程序的子组件的名称。 You can add a maximum of 16,384 event sources to the registry.您最多可以向注册表添加 16,384 个事件源。

You can using the EventLog class, as explained on How to: Write to the Application Event Log (Visual C#) :您可以使用 EventLog 类,如如何:写入应用程序事件日志 (Visual C#) 中所述

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

However, you'll need to configure this source "MySource" using administrative privileges:但是,您需要使用管理权限配置此“MySource”:

Use WriteEvent and WriteEntry to write events to an event log.使用 WriteEvent 和 WriteEntry 将事件写入事件日志。 You must specify an event source to write events;必须指定事件源才能写入事件; you must create and configure the event source before writing the first entry with the source.在使用源编写第一个条目之前,您必须创建和配置事件源。

As stated in MSDN (eg. https://msdn.microsoft.com/en-us/library/system.diagnostics.eventlog(v=vs.110).aspx ), checking an non existing source and creating a source requires admin privilege.如 MSDN 中所述(例如https://msdn.microsoft.com/en-us/library/system.diagnostics.eventlog(v=vs.110).aspx ),检查不存在的源并创建源需要管理员特权。

It is however possible to use the source "Application" without.但是,可以不使用源“应用程序” In my test under Windows 2012 Server r2, I however get the following log entry using "Application" source:然而,在我在 Windows 2012 Server r2 下的测试中,我使用“应用程序”源获得了以下日志条目:

The description for Event ID xxxx from source Application cannot be found.找不到来自源应用程序的事件 ID xxxx 的描述。 Either the component that raises this event is not installed on your local computer or the installation is corrupted.引发此事件的组件未安装在本地计算机上,或者安装已损坏。 You can install or repair the component on the local computer.您可以在本地计算机上安装或修复组件。 If the event originated on another computer, the display information had to be saved with the event.如果事件起源于另一台计算机,则显示信息必须与事件一起保存。 The following information was included with the event: {my event entry message} the message resource is present but the message is not found in the string/message table事件中包含以下信息:{我的事件条目消息}消息资源存在,但在字符串/消息表中找不到消息

I defined the following method to create the source:我定义了以下方法来创建源:

    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;
    }

I am calling it with currentAppName = AppDomain.CurrentDomain.FriendlyName我用 currentAppName = AppDomain.CurrentDomain.FriendlyName 调用它

It might be possible to use the EventLogPermission class instead of this try/catch but not sure we can avoid the catch.可能可以使用 EventLogPermission 类而不是这个 try/catch,但不确定我们是否可以避免捕获。

It is also possible to create the source externally, eg in elevated Powershell:也可以在外部创建源,例如在提升的 Powershell 中:

New-EventLog -LogName Application -Source MyApp

Then, using 'MyApp' in the method above will NOT generate exception and the EventLog can be created with that source.然后,在上述方法中使用“MyApp”将不会产生异常,并且可以使用该源创建 EventLog。

This is the logger class that I use.这是我使用的记录器类。 The private Log() method has EventLog.WriteEntry() in it, which is how you actually write to the event log.私有 Log() 方法中包含EventLog.WriteEntry() ,这是您实际写入事件日志的方式。 I'm including all of this code here because it's handy.我在这里包含所有这些代码,因为它很方便。 In addition to logging, this class will also make sure the message isn't too long to write to the event log (it will truncate the message).除了记录之外,该类还将确保消息不会太长而无法写入事件日志(它将截断消息)。 If the message was too long, you'd get an exception.如果消息太长,你会得到一个异常。 The caller can also specify the source.调用者还可以指定源。 If the caller doesn't, this class will get the source.如果调用者没有,这个类将获取源。 Hope it helps.希望能帮助到你。

By the way, you can get an ObjectDumper from the web.顺便说一句,您可以从网上获取 ObjectDumper。 I didn't want to post all that here.我不想在这里发布所有这些。 I got mine from here: C:\Program Files (x86)\Microsoft Visual Studio 10.0\Samples\1033\CSharpSamples.zip\LinqSamples\ObjectDumper我从这里得到了我的: 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;
        }
    }
}

try尝试

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM