Ghi vào Nhật ký sự kiện ứng dụng Windows


164

Có cách nào để ghi vào nhật ký sự kiện này không:

nhập mô tả hình ảnh ở đây

Hoặc ít nhất, một số nhật ký mặc định khác của Windows, nơi tôi không phải đăng ký nguồn sự kiện ?




1
"Bạn phải tạo và định cấu hình nguồn sự kiện trước khi viết mục nhập đầu tiên với nguồn."
Jerther

Có vẻ như tôi không thể. Vì vậy, có một phương pháp dự phòng tốt để cảnh báo rằng ứng dụng không thể ghi vào nhật ký windows? Một tập tin phẳng có vẻ tốt nhưng, ở đâu? Thư mục ứng dụng vẫn cần một số quyền. Ứng dụng của tôi là một dịch vụ windows.
Jerther

3
Nếu ứng dụng của bạn là Dịch vụ Windows, thì nguồn sự kiện sẽ được tạo tự động cho bạn. Bạn có thể truy cập nó thông qua ServiceBase.EventLog. Tên mặc định của Nguồn là ServiceName.
Mike Zboray

Câu trả lời:


236

Vâng, có một cách để ghi vào nhật ký sự kiện mà bạn đang tìm kiếm. Bạn không cần tạo nguồn mới, chỉ cần sử dụng nguồn hiện có, thường có cùng tên với tên của EventLog và trong một số trường hợp như Ứng dụng nhật ký sự kiện, có thể truy cập được mà không cần đặc quyền quản trị *.

* Các trường hợp khác, trong đó bạn không thể truy cập trực tiếp vào nó, ví dụ như Security EventLog, chỉ được truy cập bởi hệ điều hành.

Tôi đã sử dụng mã này để ghi trực tiếp vào ứng dụng nhật ký sự kiện:

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

Như bạn có thể thấy, nguồn EventLog giống như tên của EventLog. Lý do của điều này có thể được tìm thấy trong Nguồn sự kiện @ Windows Dev Center (Tôi đã nhấn mạnh phần đề cập đến tên nguồn):

Mỗi nhật ký trong khóa Eventlog chứa các khóa con được gọi là nguồn sự kiện. Nguồn sự kiện là tên của phần mềm ghi lại sự kiện. Nó thường là tên của ứng dụng hoặc tên của một thành phần con của ứng dụng nếu ứng dụng lớn. Bạn có thể thêm tối đa 16.384 nguồn sự kiện vào sổ đăng ký.


1
Nhưng văn bản bạn trích dẫn nói rằng bạn phải đăng ký nguồn sự kiện dưới khóa Nhật ký sự kiện.
Raymond Chen

1
Ý tôi là tên của Nhật ký sự kiện thường là cùng tên của ứng dụng, vì vậy đó là lý do tại sao bạn có thể đăng ký một mục sự kiện trực tiếp vào EventLog mà không cần tạo nguồn mới. Tôi nhấn mạnh văn bản được trích dẫn để đọc thêm.
đám mây120

3
Về mặt kỹ thuật, hành động tạo khóa đăng ký đăng ký nguồn sự kiện. Đặt tên khóa sau tên ứng dụng là một quy ước để tránh xung đột. Câu trả lời của bạn về cơ bản giống như câu trả lời này .
Raymond Chen

7
Cảm ơn thời gian của bạn Raymond Chen, chúng tôi ở đây để cố gắng giải quyết hoặc đề xuất một cái gì đó có thể giúp đỡ người khác. Trong trường hợp này, tôi tin rằng tôi đã trả lời câu hỏi chủ đề: "Có cách nào để ghi vào nhật ký sự kiện này không: Hoặc ít nhất, một số nhật ký mặc định khác của Windows, nơi tôi không phải đăng ký nguồn sự kiện?". -> Tôi đã trả lời: Có và tôi đã chia sẻ nó với bạn. Mặc dù thực tế rằng nó có thể gây ra xung đột như bạn nói, nó tồn tại một cách.
đám mây120

7
Bạn đang trả lời câu hỏi "Có cách nào để làm điều đó mà không cần đăng ký nguồn sự kiện không?" và câu trả lời của bạn cho biết "Tạo khóa đăng ký này để đăng ký nguồn sự kiện." Nó cũng giống hệt với một câu trả lời hiện có.
Raymond Chen

14

Bạn có thể sử dụng lớp EventLog, như được giải thích về Cách: Ghi vào Nhật ký sự kiện ứng dụng (Visual C #) :

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

Tuy nhiên, bạn sẽ cần định cấu hình nguồn "MySource" này bằng các đặc quyền quản trị:

Sử dụng WriteEvent và WriteEntry để viết các sự kiện vào nhật ký sự kiện. Bạn phải chỉ định một nguồn sự kiện để viết các sự kiện; bạn phải tạo và định cấu hình nguồn sự kiện trước khi viết mục đầu tiên với nguồn.


2
Đây là vấn đề tôi gặp phải: Tôi không thể tạo nguồn vì tôi không có những đặc quyền đó, nhưng tôi vẫn cần phải ghi lại vấn đề đó ở đâu đó
Jerther

2
Sau đó, sử dụng trình cài đặt ( stackoverflow.com/questions/1484605/, ) hoặc đăng nhập vào tệp.
CodeCaster

1
Cảm ơn bạn. Điều này dẫn tôi đến câu hỏi SO khác: stackoverflow.com/questions/3930529/ cấp
Jerther

@CodeCaster - Từ đâu chúng ta có thể truy cập các nhật ký này? Tôi có nghĩa là vị trí nơi nó đang lưu trữ?
Arvind Chourasiya

1
@Arvind câu hỏi đó không liên quan gì đến câu trả lời của tôi và là một câu hỏi hoàn toàn mới.
CodeCaster

11

Như đã nêu trong MSDN (ví dụ: https://msdn.microsoft.com/en-us/l Library / system.diagnostics.eventlog ( v = vs.110 ) .aspx ), kiểm tra nguồn không tồn tại và tạo nguồn cần có quản trị viên đặc quyền.

Tuy nhiên, có thể sử dụng nguồn "Ứng dụng" mà không cần. Trong thử nghiệm của tôi trong Windows 2012 Server r2, tuy nhiên tôi nhận được mục nhật ký sau bằng cách sử dụng nguồn "Ứng dụng":

Không thể tìm thấy mô tả cho ID sự kiện xxxx từ Ứng dụng nguồn. Thành phần gây ra sự kiện này không được cài đặt trên máy tính cục bộ của bạn hoặc cài đặt bị hỏng. Bạn có thể cài đặt hoặc sửa chữa thành phần trên máy tính cục bộ. Nếu sự kiện bắt nguồn từ một máy tính khác, thông tin hiển thị phải được lưu cùng với sự kiện. Thông tin sau được bao gồm trong sự kiện: {thông báo nhập sự kiện của tôi} tài nguyên thông báo có mặt nhưng không tìm thấy thông báo trong bảng chuỗi / thông báo

Tôi đã định nghĩa phương pháp sau để tạo nguồn:

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

Tôi đang gọi nó với currentAppName = AppDomain.CiverseDomain.FriendlyName

Có thể sử dụng lớp EventLogPermission thay vì thử / bắt này nhưng không chắc chắn chúng ta có thể tránh được việc bắt.

Cũng có thể tạo nguồn bên ngoài, ví dụ như trong Powershell nâng cao:

New-EventLog -LogName Application -Source MyApp

Sau đó, sử dụng 'MyApp' trong phương thức trên sẽ KHÔNG tạo ra ngoại lệ và EventLog có thể được tạo bằng nguồn đó.


10

Đây là lớp logger mà tôi sử dụng. Phương thức Log () riêng tư có EventLog.WriteEntry()trong đó, đó là cách bạn thực sự ghi vào nhật ký sự kiện. Tôi bao gồm tất cả các mã này ở đây vì nó tiện dụng. Ngoài việc ghi nhật ký, lớp này cũng sẽ đảm bảo tin nhắn không quá dài để ghi vào nhật ký sự kiện (nó sẽ cắt bớt tin nhắn). Nếu tin nhắn quá dài, bạn sẽ có một ngoại lệ. Người gọi cũng có thể chỉ định nguồn. Nếu người gọi không, lớp này sẽ lấy nguồn. Hy vọng nó giúp.

Nhân tiện, bạn có thể lấy ObjectDumper từ web. Tôi không muốn đăng tất cả những thứ đó ở đây. Tôi có của tôi từ đây: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
Và mã này cho thấy rằng. Có hại gì khi chia sẻ điều này với anh ấy? Nó không hữu ích cho OP và những người khác sao?
Bob Horn

5
Bạn không thể ghi vào nhật ký sự kiện mà không tạo nguồn sự kiện , vì vậy mã này không hiển thị điều đó.
CodeCaster

2
Tôi vẫn sẽ cần tạo nguồn sự kiện nhưng bạn đã đăng anwser của mình trước khi tiêu đề câu hỏi được cập nhật. Tuy nhiên, tôi không biết về giới hạn chiều dài cảm ơn.
Jerther

-4

thử

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

3
điều này cần đăng ký Nguồn sự kiện và do đó không trả lời câu hỏi. lấy làm tiếc.
Jerther

Ý tưởng chính của câu hỏi này là sử dụng nguồn sự kiện "Ứng dụng".
rcarrillopadron
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.