เขียนลงในบันทึกเหตุการณ์ของแอปพลิเคชัน Windows


166

มีวิธีเขียนไปยังบันทึกเหตุการณ์นี้หรือไม่:

ป้อนคำอธิบายรูปภาพที่นี่

หรืออย่างน้อยบางบันทึกเริ่มต้นของ Windows อื่น ๆที่ฉันไม่ต้องลงทะเบียนแหล่งที่มาของเหตุการณ์ ?




1
"คุณต้องสร้างและกำหนดค่าแหล่งที่มาของเหตุการณ์ก่อนที่จะเขียนรายการแรกด้วยแหล่งที่มา"
Jerther

ดูเหมือนว่าฉันไม่สามารถ ดังนั้นมีวิธีสำรองที่ดีเพื่อเตือนว่าโปรแกรมไม่สามารถเขียนบันทึก windows? ไฟล์แฟล็ตดูเหมือนดี แต่ที่ไหน? โฟลเดอร์แอปพลิเคชันยังคงต้องการสิทธิ์บางอย่าง แอปพลิเคชันของฉันคือบริการ windows
Jerther

3
หากแอปพลิเคชันของคุณเป็นบริการของ Windows แหล่งที่มาของเหตุการณ์จะถูกสร้างขึ้นสำหรับคุณโดยอัตโนมัติ ServiceBase.EventLogคุณสามารถเข้าถึงได้ผ่านทาง ชื่อเริ่มต้นของแหล่งที่มาคือ ServiceName
Mike Zboray

คำตอบ:


237

ใช่มีวิธีเขียนไปยังบันทึกเหตุการณ์ที่คุณต้องการ คุณไม่จำเป็นต้องสร้างแหล่งใหม่เพียงแค่ใช้แหล่งที่มีอยู่ซึ่งมักจะมีชื่อเดียวกับชื่อของ EventLog และในบางกรณีเช่นแอปพลิเคชันบันทึกเหตุการณ์สามารถเข้าถึงได้โดยไม่ต้องใช้สิทธิ์ของผู้ดูแลระบบ *

* กรณีอื่น ๆ ที่คุณไม่สามารถเข้าถึงได้โดยตรงเช่น Security EventLog ซึ่งระบบปฏิบัติการเข้าถึงได้เท่านั้น

ฉันใช้รหัสนี้เพื่อเขียนโดยตรงไปยังแอปพลิเคชันบันทึกเหตุการณ์:

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

อย่างที่คุณเห็นแหล่งที่มาของ EventLog นั้นเหมือนกับชื่อของ EventLog เหตุผลนี้สามารถพบได้ในEvent Sources @ Windows Dev Center (ฉันทำตัวหนาส่วนที่อ้างถึงชื่อแหล่งที่มา):

แต่ละบันทึกในคีย์ Eventlog มีคีย์ย่อยที่เรียกว่าแหล่งที่มาของเหตุการณ์ แหล่งที่มาของเหตุการณ์คือชื่อของซอฟต์แวร์ที่บันทึกเหตุการณ์ มักจะเป็นชื่อของแอปพลิเคชันหรือชื่อของคอมโพเนนต์ย่อยของแอปพลิเคชันหากแอปพลิเคชันมีขนาดใหญ่ คุณสามารถเพิ่มแหล่งเหตุการณ์ได้สูงสุด 16,384 แหล่งในรีจิสทรี


1
แต่ข้อความที่คุณยกมาบอกว่าคุณต้องลงทะเบียนแหล่งเหตุการณ์ภายใต้รหัสบันทึกเหตุการณ์
Raymond Chen

1
สิ่งที่ฉันหมายถึงคือชื่อของบันทึกเหตุการณ์มักจะเป็นชื่อเดียวกันของแอปพลิเคชันดังนั้นนั่นคือสาเหตุที่คุณสามารถลงทะเบียนรายการบันทึกเหตุการณ์ลงใน EventLog โดยตรงโดยไม่ต้องสร้างแหล่งใหม่ ฉันทำตัวหนาข้อความ quouted สำหรับการอ่านเพิ่มเติม
cloud120

3
ในทางเทคนิคแล้วการสร้างคีย์รีจิสทรีกำลังลงทะเบียนแหล่งที่มาของเหตุการณ์ การตั้งชื่อคีย์หลังจากชื่อแอปพลิเคชันเป็นแบบแผนเพื่อหลีกเลี่ยงความขัดแย้ง คำตอบของคุณนั้นเหมือนกับคำตอบนี้
Raymond Chen

7
ขอบคุณสำหรับเวลาของคุณเรย์มอนด์เฉินเราอยู่ที่นี่เพื่อพยายามแก้ไขหรือแนะนำสิ่งที่อาจช่วยเหลือผู้อื่น ในกรณีนี้ฉันเชื่อว่าฉันตอบคำถามหัวข้อ: "มีวิธีเขียนไปยังบันทึกเหตุการณ์นี้: หรืออย่างน้อยก็มีบันทึกเริ่มต้นอื่น ๆ ของ Windows ที่ฉันไม่ต้องลงทะเบียนแหล่งที่มาของเหตุการณ์" -> ฉันตอบว่า: ใช่แล้วและฉันได้แบ่งปันกับคุณ แม้จะมีข้อเท็จจริงที่ว่ามันอาจทำให้เกิดความขัดแย้งตามที่คุณพูดมันมีวิธี
cloud120

7
คุณกำลังตอบคำถาม "มีวิธีทำโดยไม่ต้องลงทะเบียนแหล่งที่มาของเหตุการณ์หรือไม่" และคำตอบของคุณบอกว่า "สร้างรีจิสตรีคีย์นี้เพื่อลงทะเบียนแหล่งที่มาของเหตุการณ์" มันก็เหมือนกันกับคำตอบที่มีอยู่
Raymond Chen

14

คุณสามารถใช้คลาส EventLog ตามที่อธิบายไว้ในวิธีการ: เขียนไปยังแอปพลิเคชันบันทึกเหตุการณ์ (Visual C #) :

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

อย่างไรก็ตามคุณจะต้องกำหนดค่าที่มา "MySource" นี้โดยใช้สิทธิ์ผู้ดูแลระบบ:

ใช้ WriteEvent และ WriteEntry เพื่อเขียนเหตุการณ์ลงในบันทึกเหตุการณ์ คุณต้องระบุแหล่งที่มาของเหตุการณ์เพื่อเขียนเหตุการณ์ คุณต้องสร้างและกำหนดค่าแหล่งที่มาของเหตุการณ์ก่อนที่จะเขียนรายการแรกด้วยแหล่งที่มา


2
นี่คือปัญหาที่ฉันมี: ฉันไม่สามารถสร้างแหล่งที่มาได้เนื่องจากฉันไม่มีสิทธิ์เหล่านั้น แต่ฉันยังต้องบันทึกปัญหานั้นอยู่ที่ไหนสักแห่ง
Jerther

2
จากนั้นใช้โปรแกรมติดตั้ง ( stackoverflow.com/questions/1484605/… ) หรือล็อกไฟล์
CodeCaster

1
ขอบคุณ. นี่นำฉันไปยังคำถาม SO อื่น ๆ นี้: stackoverflow.com/questions/3930529/…
Jerther

@CodeCaster - เราสามารถเข้าถึงบันทึกเหล่านี้ได้จากที่ใด ฉันหมายถึงสถานที่จัดเก็บหรือไม่
Arvind Chourasiya

1
@ ตอบคำถามนั้นไม่มีส่วนเกี่ยวข้องกับคำตอบของฉันและเป็นคำถามใหม่ทั้งหมด
CodeCaster

11

ตามที่ระบุไว้ใน MSDN (เช่นhttps://msdn.microsoft.com/en-us/library/system.diagnostics.eventlog(v=vsv . 1010 ) .aspx ) การตรวจสอบแหล่งที่ไม่มีอยู่และการสร้างแหล่งที่ต้องการผู้ดูแลระบบ สิทธิพิเศษ

อย่างไรก็ตามมีความเป็นไปได้ที่จะใช้"แอปพลิเคชัน" ต้นทางโดยไม่ต้อง ในการทดสอบของฉันภายใต้ Windows 2012 Server r2 ฉันได้รับรายการบันทึกต่อไปนี้โดยใช้แหล่งที่มาของ "Application":

ไม่พบคำอธิบายสำหรับรหัสเหตุการณ์ 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 ด้วยแหล่งที่มานั้นได้


10

นี่คือคลาสตัวบันทึกที่ฉันใช้ ไพรเวต Log () มีEventLog.WriteEntry()อยู่ในนั้นซึ่งเป็นวิธีที่คุณเขียนลงในบันทึกเหตุการณ์ ฉันรวมรหัสทั้งหมดนี้ไว้ที่นี่เพราะมันมีประโยชน์ นอกเหนือจากการบันทึกคลาสนี้จะทำให้แน่ใจว่าข้อความไม่นานเกินกว่าจะเขียนลงในบันทึกเหตุการณ์ (มันจะตัดทอนข้อความ) หากข้อความยาวเกินไปคุณจะได้รับการยกเว้น ผู้โทรยังสามารถระบุแหล่งที่มา หากผู้โทรไม่ได้คลาสนี้จะได้รับแหล่งที่มา หวังว่ามันจะช่วย

โดยวิธีการที่คุณสามารถรับ 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;
        }
    }
}

3
และรหัสนี้แสดงให้เห็นว่า การแบ่งปันสิ่งนี้กับเขาเป็นอันตรายอย่างไร มันจะไม่เป็นประโยชน์กับ OP และคนอื่น ๆ ?
Bob Horn

5
คุณไม่สามารถเขียนลงในบันทึกเหตุการณ์โดยไม่ต้องสร้างแหล่งที่มาของเหตุการณ์ดังนั้นรหัสนี้จะไม่แสดงว่า
CodeCaster

2
ฉันยังต้องการสร้างแหล่งเหตุการณ์ แต่คุณโพสต์ anwser ของคุณก่อนที่จะอัปเดตชื่อคำถาม ถึงกระนั้นฉันไม่ทราบเกี่ยวกับการจำกัดความยาว
Jerther

-4

ลอง

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

3
สิ่งนี้ต้องลงทะเบียนแหล่งที่มาของกิจกรรมจึงไม่ตอบคำถาม ขอโทษ
Jerther

แนวคิดหลักของคำถามนี้คือการใช้แหล่งเหตุการณ์ "แอปพลิเคชัน"
rcarrillopadron
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.