„Musisz utworzyć i skonfigurować źródło zdarzenia przed zapisaniem pierwszego wpisu ze źródłem”.
Jerther,
Wydaje się, że nie mogę. Czy jest więc dobra metoda awaryjna ostrzegająca, że aplikacja nie może zapisywać w dziennikach systemu Windows? Plik płaski wydaje się dobry, ale gdzie? Folder aplikacji nadal wymagałby pewnych uprawnień. Moja aplikacja jest usługą systemu Windows.
Jerther,
3
Jeśli Twoja aplikacja jest usługą systemu Windows, źródło zdarzeń jest tworzone automatycznie. Możesz uzyskać do niego dostęp przez ServiceBase.EventLog. Domyślną nazwą źródła jest ServiceName.
Mike Zboray,
Odpowiedzi:
237
Tak, istnieje sposób, aby zapisać się do dziennika zdarzeń, którego szukasz. Nie musisz tworzyć nowego źródła, po prostu użyj istniejącego, które często ma taką samą nazwę jak nazwa EventLog, a także, w niektórych przypadkach, jak aplikacja dziennika zdarzeń, może być dostępna bez uprawnień administratora *.
* Inne przypadki, w których nie można uzyskać do niego bezpośredniego dostępu, to na przykład Security EventLog, do którego dostęp ma tylko system operacyjny.
Użyłem tego kodu, aby napisać bezpośrednio do dziennika zdarzeń Aplikacja:
using (EventLog eventLog =newEventLog("Application")){
eventLog.Source="Application";
eventLog.WriteEntry("Log message example",EventLogEntryType.Information,101,1);}
Jak widać, źródło EventLog jest takie samo jak nazwa EventLog. Powód tego można znaleźć w Event Sources @ Windows Dev Center (pogrubiłem część, która odnosi się do nazwy źródła):
Każdy dziennik w kluczu Eventlog zawiera podklucze zwane źródłami zdarzeń. Źródło zdarzenia to nazwa oprogramowania, które rejestruje zdarzenie. Często jest to nazwa aplikacji lub nazwa podkomponentu aplikacji, jeśli aplikacja jest duża. Do rejestru można dodać maksymalnie 16 384 źródła zdarzeń.
Ale cytowany tekst mówi, że musisz zarejestrować źródło zdarzenia w kluczu dziennika zdarzeń.
Raymond Chen
1
Chodziło mi o to, że nazwa dziennika zdarzeń jest często tą samą nazwą aplikacji, dlatego można zarejestrować wpis dziennika zdarzeń bezpośrednio w dzienniku zdarzeń bez tworzenia nowego źródła. Pogrubiłem cytowany tekst do dalszych lektur.
cloud120
3
Technicznie rzecz biorąc, czynnością tworzenia klucza rejestru jest rejestracja źródła zdarzenia. Nazywanie klucza po nazwie aplikacji jest konwencją pozwalającą uniknąć konfliktów. Twoja odpowiedź jest zasadniczo taka sama jak ta odpowiedź .
Raymond Chen
7
Dzięki za poświęcony czas Raymond Chen, jesteśmy tutaj, aby spróbować rozwiązać lub zasugerować coś, co mogłoby pomóc innym. W tym przypadku wydaje mi się, że odpowiedziałem na pytanie w temacie: „Czy jest sposób, aby zapisać do tego dziennika zdarzeń: Albo przynajmniej jakiś inny domyślny dziennik systemu Windows, w którym nie muszę rejestrować źródła zdarzeń?”. -> Odpowiedziałem: Tak i podzieliłem się tym z Tobą. Pomimo tego, że może powodować konflikty, jak powiedziałeś, istnieje sposób.
cloud120
7
Odpowiadasz na pytanie „Czy można to zrobić bez rejestracji źródła zdarzenia?” a Twoja odpowiedź brzmi: „Utwórz ten klucz rejestru, aby zarejestrować źródło zdarzenia”. Jest również identyczna z istniejącą odpowiedzią.
var appLog =newEventLog("Application");
appLog.Source="MySource";
appLog.WriteEntry("Test log message");
Musisz jednak skonfigurować to źródło „Moje źródło ” przy użyciu uprawnień administracyjnych:
Użyj WriteEvent i WriteEntry, aby zapisywać zdarzenia w dzienniku zdarzeń. Aby zapisywać zdarzenia, musisz określić źródło zdarzenia; musisz utworzyć i skonfigurować źródło zdarzenia przed zapisaniem pierwszego wpisu ze źródłem.
Możliwe jest jednak użycie źródła „Aplikacja” bez. Podczas testu w systemie Windows 2012 Server r2 otrzymuję jednak następujący wpis dziennika przy użyciu źródła „Aplikacja”:
Nie można znaleźć opisu dla identyfikatora zdarzenia xxxx z aplikacji źródłowej. Albo składnik wywołujący to zdarzenie nie jest zainstalowany na komputerze lokalnym albo instalacja jest uszkodzona. Możesz zainstalować lub naprawić komponent na komputerze lokalnym. Jeśli zdarzenie powstało na innym komputerze, informacje o wyświetlaniu musiały zostać zapisane wraz ze zdarzeniem. Następujące informacje zostały dołączone do zdarzenia: {my event entry message} zasób wiadomości jest obecny, ale wiadomość nie została znaleziona w tabeli string / message
Zdefiniowałem następującą metodę tworzenia źródła:
privatestringCreateEventSource(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 privilegeEventLog.CreateEventSource(eventSource,"Application");}}catch(SecurityException){
eventSource ="Application";}return eventSource;}
Wołam to z currentAppName = AppDomain.CurrentDomain.FriendlyName
Może być możliwe użycie klasy EventLogPermission zamiast tego try / catch, ale nie jesteśmy pewni, czy uda nam się uniknąć złapania.
Możliwe jest również utworzenie źródła zewnętrznie, np. W podwyższonym Powershellu:
New-EventLog-LogNameApplication-SourceMyApp
Następnie użycie „MyApp” w powyższej metodzie NIE spowoduje wygenerowania wyjątku, a dziennik zdarzeń można utworzyć za pomocą tego źródła.
To jest klasa rejestratora, której używam. Zawiera metodę private Log () EventLog.WriteEntry(), czyli sposób, w jaki faktycznie zapisujesz w dzienniku zdarzeń. Dołączam tutaj cały ten kod, ponieważ jest przydatny. Oprócz rejestrowania ta klasa zapewnia również, że wiadomość nie jest zbyt długa, aby można ją było zapisać w dzienniku zdarzeń (spowoduje to obcięcie wiadomości). Jeśli wiadomość była za długa, pojawi się wyjątek. Wzywający może również określić źródło. Jeśli wywołujący tego nie zrobi, ta klasa otrzyma źródło. Mam nadzieję, że to pomoże.
Nawiasem mówiąc, możesz pobrać ObjectDumper z Internetu. Nie chciałem tego tutaj publikować. Mam stąd: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>publicstaticclassLogger{// 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.privateconstintMaxEventLogEntryLength=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>publicstaticstringSource{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>publicstaticvoidLogDebug(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>publicstaticvoidLogInformation(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>publicstaticvoidLogWarning(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>publicstaticvoidLogException(Exception ex,string source =""){if(ex ==null){thrownewArgumentNullException("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")]publicstaticvoidLogObjectDump(object theObject,string objectName,string source =""){constint 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);}privatestaticvoidLog(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);}}privatestaticstringGetSource(){// If the caller has explicitly set a source value, just use it.if(!string.IsNullOrWhiteSpace(Source)){returnSource;}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 =newStackTrace().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.privatestaticstringEnsureLogMessageLimit(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;}}}
Ten kod to pokazuje. Jaka jest szkoda w dzieleniu się z nim tym? Czy nie mogłoby to być pomocne dla PO i innych osób?
Bob Horn
5
Nie można pisać do dziennika zdarzeń bez utworzenia źródła zdarzenia , więc ten kod tego nie pokazuje.
CodeCaster
2
Nadal musiałbym utworzyć źródło zdarzenia, ale wysłałeś swoją odpowiedź przed aktualizacją tytułu pytania. Mimo to nie wiedziałem o limicie długości dzięki.
Jerther,
-4
próbować
System.Diagnostics.EventLog appLog =newSystem.Diagnostics.EventLog();
appLog.Source="This Application's Name";
appLog.WriteEntry("An entry to the Application event log.");
ServiceBase.EventLog
. Domyślną nazwą źródła jest ServiceName.Odpowiedzi:
Tak, istnieje sposób, aby zapisać się do dziennika zdarzeń, którego szukasz. Nie musisz tworzyć nowego źródła, po prostu użyj istniejącego, które często ma taką samą nazwę jak nazwa EventLog, a także, w niektórych przypadkach, jak aplikacja dziennika zdarzeń, może być dostępna bez uprawnień administratora *.
* Inne przypadki, w których nie można uzyskać do niego bezpośredniego dostępu, to na przykład Security EventLog, do którego dostęp ma tylko system operacyjny.
Użyłem tego kodu, aby napisać bezpośrednio do dziennika zdarzeń Aplikacja:
Jak widać, źródło EventLog jest takie samo jak nazwa EventLog. Powód tego można znaleźć w Event Sources @ Windows Dev Center (pogrubiłem część, która odnosi się do nazwy źródła):
źródło
Możesz użyć klasy EventLog, jak wyjaśniono w temacie How to: Write to the Application Event Log (Visual C #) :
Musisz jednak skonfigurować to źródło „Moje źródło ” przy użyciu uprawnień administracyjnych:
źródło
Jak podano w MSDN (np. Https://msdn.microsoft.com/en-us/library/system.diagnostics.eventlog(v=vs.110).aspx ), sprawdzenie nieistniejącego źródła i utworzenie źródła wymaga administratora przywilej.
Możliwe jest jednak użycie źródła „Aplikacja” bez. Podczas testu w systemie Windows 2012 Server r2 otrzymuję jednak następujący wpis dziennika przy użyciu źródła „Aplikacja”:
Zdefiniowałem następującą metodę tworzenia źródła:
Wołam to z currentAppName = AppDomain.CurrentDomain.FriendlyName
Może być możliwe użycie klasy EventLogPermission zamiast tego try / catch, ale nie jesteśmy pewni, czy uda nam się uniknąć złapania.
Możliwe jest również utworzenie źródła zewnętrznie, np. W podwyższonym Powershellu:
Następnie użycie „MyApp” w powyższej metodzie NIE spowoduje wygenerowania wyjątku, a dziennik zdarzeń można utworzyć za pomocą tego źródła.
źródło
To jest klasa rejestratora, której używam. Zawiera metodę private Log ()
EventLog.WriteEntry()
, czyli sposób, w jaki faktycznie zapisujesz w dzienniku zdarzeń. Dołączam tutaj cały ten kod, ponieważ jest przydatny. Oprócz rejestrowania ta klasa zapewnia również, że wiadomość nie jest zbyt długa, aby można ją było zapisać w dzienniku zdarzeń (spowoduje to obcięcie wiadomości). Jeśli wiadomość była za długa, pojawi się wyjątek. Wzywający może również określić źródło. Jeśli wywołujący tego nie zrobi, ta klasa otrzyma źródło. Mam nadzieję, że to pomoże.Nawiasem mówiąc, możesz pobrać ObjectDumper z Internetu. Nie chciałem tego tutaj publikować. Mam stąd:
C:\Program Files (x86)\Microsoft Visual Studio 10.0\Samples\1033\CSharpSamples.zip\LinqSamples\ObjectDumper
źródło
próbować
źródło