Eccezione intermittente EventLog
-
11-07-2019 - |
Domanda
Ho un problema intermittente con del codice che scrive in un registro eventi di Windows, usando la classe EventLog
di C # e .Net.
Fondamentalmente, questo codice funziona perfettamente ogni giorno, ma molto occasionalmente, iniziamo a ricevere errori come questo:
" System.ArgumentException: solo il file primi otto caratteri di un registro personalizzato il nome è significativo, e c'è già un altro registro sul sistema usando i primi otto caratteri di il nome dato. Nome dato: "Applicazione", nome del registro esistente: . 'Application' "
Sono in grado di identificare dalle altre informazioni sui nostri registri che lo stack di chiamate interessato è in questo modo - Puoi chiaramente vedere che sto effettivamente cercando di scrivere in un registro LB_Email
esistente ( LogEmail
viene chiamato per primo):
public static void LogEmail(string to, string type)
{
string message = String.Format("{0}\t{1}\t{2}", DateTime.Now, to, type);
Log(message, "LB_Email", EventLogEntryType.Information);
}
private static void Log(string message, string logName, EventLogEntryType type)
{
using (EventLog aLog = new EventLog())
{
aLog.Source = logName;
aLog.WriteEntry(message, type);
}
}
Una volta che si verificano gli errori, sembra che l'accesso al nostro registro eventi LB_Email
sia bloccato in qualche modo - la visualizzazione delle proprietà sul particolare registro eventi mostra la maggior parte delle informazioni in grigio e immutabili, e altri processi sembrano essere prevenuti dalla registrazione anche a quel registro. Tuttavia, visualizzo l'errore (che utilizza lo stesso metodo di registro sopra) tramite un try-catch che accede a un registro "LB_Error" e che continua a funzionare come previsto.
Sto chiamando questo codice da un'applicazione multi-thread, ma non sono stato in grado di identificare se il codice sopra è thread-safe o meno.
Posso anche confermare che il login in questione sta funzionando di nuovo bene dopo aver ucciso e riavviato il processo ... e aveva le impostazioni appropriate per riutilizzare le voci quando era pieno ... anche se non penso che fosse il problema .
Mi piacerebbe sentire i tuoi pensieri e suggerimenti.
Soluzione
La documentazione afferma che:
Puoi solo usare la Fonte per scrivere a un registro alla volta
Quindi sospetto che questo problema sia causato dalla tua app multithread che chiama il metodo Log
più di una volta in un dato momento e per la stessa fonte.
Suggerisco che, anziché una classe statica (o metodi), usi una classe singleton thread-safe per registrare questi eventi.
EDIT:
Jon Skeet ha un eccellente articolo sui singoli.
Se non vuoi implementare una classe singleton puoi fare qualcosa del genere:
static readonly object lockObj = new object();
public static void LogEmail(string to, string type)
{
string message = String.Format("{0}\t{1}\t{2}", DateTime.Now, to, type);
Log(message, "LB_Email", EventLogEntryType.Information);
}
private static void Log(string message, string logName, EventLogEntryType type)
{
lock (lockObj)
{
using (EventLog aLog = new EventLog())
{
aLog.Source = logName;
aLog.WriteEntry(message, type);
}
}
}
Spero che questo risolva il tuo problema.
Altri suggerimenti
Grazie Bruno,
Quindi, sbaglio nel pensare che l'istanza EventLog nel metodo Log sia diversa dall'istanza EventLog nella stessa chiamata del metodo in un thread diverso? O mi sto solo confondendo sulle istanze di oggetti all'interno di un metodo statico?
OK, quindi ho diversi metodi wrapper per il metodo Log (...). Se spostassi il metodo Log in una classe singleton, cambiassi i wrapper (LogEmail, LogXxxx, LogYyy ecc., Allora potrei mantenere le mie interfacce Log.Zzzz uguali, ma sfruttare la sicurezza del singleton LogSingleton.Instance.Log (...) dai registri correnti. O poiché desidero scrivere in registri diversi, ognuno richiederebbe il proprio LogSingletonXxx?
Puoi dire che sono confuso :) Sì, apprezzerei molto il codice di sincronizzazione :)
Nij