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 ?
ServiceBase.EventLog
. Tên mặc định của Nguồn là ServiceName.
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 ?
ServiceBase.EventLog
. Tên mặc định của Nguồn là ServiceName.
Câu trả lời:
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ý.
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.
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 đó.
Đâ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;
}
}
}
thử
System.Diagnostics.EventLog appLog = new System.Diagnostics.EventLog();
appLog.Source = "This Application's Name";
appLog.WriteEntry("An entry to the Application event log.");