// System.Diagnostics.EventLog.cs
//
// Authors:
-// Jonathan Pryor (jonpryor@vt.edu)
-// Andreas Nahr (ClassDevelopment@A-SoftTech.com)
+// Jonathan Pryor (jonpryor@vt.edu)
+// Andreas Nahr (ClassDevelopment@A-SoftTech.com)
+// Gert Driesen (drieseng@users.sourceforge.net)
//
-// (C) 2002
-// (C) 2003 Andreas Nahr
+// Copyright (C) 2002
+// Copyright (C) 2003 Andreas Nahr
+// Copyright (C) 2006 Novell, Inc (http://www.novell.com)
//
-
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
using System.Globalization;
using System.IO;
-using Microsoft.Win32;
-
namespace System.Diagnostics
{
[DefaultEvent ("EntryWritten")]
private bool doRaiseEvents = false;
private ISynchronizeInvoke synchronizingObject = null;
+ // IMPORTANT: also update constants in EventLogTest
+ internal const string LOCAL_FILE_IMPL = "local";
+ private const string WIN32_IMPL = "win32";
+ private const string NULL_IMPL = "null";
+
+ internal const string EVENTLOG_TYPE_VAR = "MONO_EVENTLOG_TYPE";
+
private EventLogImpl Impl;
- public EventLog()
- : this (string.Empty)
+ public EventLog() : this (string.Empty)
{
}
- public EventLog(string logName)
- : this (logName, ".")
+ public EventLog(string logName) : this (logName, ".")
{
}
throw new ArgumentNullException ("logName");
}
if (machineName == null || machineName.Length == 0)
+#if NET_2_0
throw new ArgumentException (string.Format (
CultureInfo.InvariantCulture, "Invalid value '{0}' for"
+ " parameter 'machineName'.", machineName));
+#else
+ throw new ArgumentException (string.Format (
+ CultureInfo.InvariantCulture, "Invalid value {0} for"
+ + " parameter MachineName.", machineName));
+#endif
this.source = source;
this.machineName = machineName;
this.logName = logName;
- Impl = new NullEventLog (this);
- /*
- if (Win32EventLogEnabled) {
- Impl = new Win32EventLog (this);
- } else {
- Impl = new UnixEventLog (this);
- }
- */
+ Impl = CreateEventLogImpl (this);
Impl.EntryWritten += new EntryWrittenEventHandler (EntryWrittenHandler);
}
set {synchronizingObject = value;}
}
- public void BeginInit()
+ public void BeginInit ()
{
Impl.BeginInit();
}
- public void Clear()
+ public void Clear ()
{
- Impl.Clear();
+ string logName = Log;
+ if (logName == null || logName.Length == 0)
+ throw new ArgumentException ("Log property value has not been specified.");
+
+ if (!EventLog.Exists (logName, MachineName))
+ throw new InvalidOperationException (string.Format (
+ CultureInfo.InvariantCulture, "Event Log '{0}'"
+ + " does not exist on computer '{1}'.", logName,
+ machineName));
+
+ Impl.Clear ();
}
- public void Close()
+ public void Close ()
{
Impl.Close();
}
- public static void CreateEventSource(string source, string logName)
+ public static void CreateEventSource (string source, string logName)
{
CreateEventSource (source, logName, ".");
}
- public static void CreateEventSource(string source,
+ public static void CreateEventSource (string source,
string logName,
string machineName)
{
#endif
static void CreateEventSource (EventSourceCreationData sourceData)
{
- if (sourceData.Source == null || sourceData.Source.Length == 0) {
- throw new ArgumentException ("Source is not set");
- }
- if (sourceData.LogName == null || sourceData.LogName.Length == 0) {
- throw new ArgumentException ("LogName is not set");
- }
+ if (sourceData.Source == null || sourceData.Source.Length == 0)
+ throw new ArgumentException ("Source property value has not been specified.");
- if (SourceExists (sourceData.Source, sourceData.MachineName)) {
+ if (sourceData.LogName == null || sourceData.LogName.Length == 0)
+ throw new ArgumentException ("Log property value has not been specified.");
+
+ if (SourceExists (sourceData.Source, sourceData.MachineName))
throw new ArgumentException (string.Format (CultureInfo.InvariantCulture,
"Source '{0}' already exists on '{1}'.", sourceData.Source,
sourceData.MachineName));
- }
- using (RegistryKey eventLogKey = GetEventLogKey (sourceData.MachineName, true)) {
- if (eventLogKey == null)
- throw new InvalidOperationException ("EventLog registry key is missing.");
-
- bool logKeyCreated = false;
- RegistryKey logKey = null;
- try {
- logKey = eventLogKey.OpenSubKey (sourceData.LogName, true);
- if (logKey == null) {
- logKey = eventLogKey.CreateSubKey (sourceData.LogName);
- logKey.SetValue ("Sources", new string[] { sourceData.LogName,
- sourceData.Source });
- UpdateLogRegistry (logKey);
-
- using (RegistryKey sourceKey = logKey.CreateSubKey (sourceData.LogName)) {
- UpdateSourceRegistry (sourceKey, sourceData);
- }
-
- logKeyCreated = true;
- }
-
- if (sourceData.LogName != sourceData.Source) {
- if (!logKeyCreated) {
- string[] sources = (string[]) logKey.GetValue ("Sources");
- if (sources == null) {
- logKey.SetValue ("Sources", new string[] { sourceData.LogName,
- sourceData.Source });
- } else {
- bool found = false;
- for (int i = 0; i < sources.Length; i++) {
- if (sources[i] == sourceData.Source) {
- found = true;
- break;
- }
- }
- if (!found) {
- string[] newSources = new string[sources.Length + 1];
- Array.Copy (sources, 0, newSources, 0, sources.Length);
- newSources[sources.Length] = sourceData.Source;
- logKey.SetValue ("Sources", newSources);
- }
- }
- }
- using (RegistryKey sourceKey = logKey.CreateSubKey (sourceData.Source)) {
- UpdateSourceRegistry (sourceKey, sourceData);
- }
- }
- } finally {
- if (logKey != null)
- logKey.Close ();
- }
- }
+ EventLogImpl impl = CreateEventLogImpl (sourceData.LogName,
+ sourceData.MachineName, sourceData.Source);
+ impl.CreateEventSource (sourceData);
}
- public static void Delete(string logName)
+ public static void Delete (string logName)
{
Delete (logName, ".");
}
if (logName == null || logName.Length == 0)
throw new ArgumentException ("Log to delete was not specified.");
- using (RegistryKey eventLogKey = GetEventLogKey (machineName, true)) {
- if (eventLogKey == null)
- throw new InvalidOperationException ("The event log key does not exist.");
-
- using (RegistryKey logKey = eventLogKey.OpenSubKey (logName, false)) {
- if (logKey == null)
- throw new InvalidOperationException (string.Format (
- CultureInfo.InvariantCulture, "Event Log '{0}'"
- + " does not exist on computer '{1}'.", logName,
- machineName));
-
- // remove all eventlog entries for specified log
- using (EventLog eventLog = new EventLog (logName, machineName)) {
- eventLog.Clear ();
- }
-
- // remove file holding event log entries
- string file = (string) logKey.GetValue ("File");
- if (file != null) {
- try {
- File.Delete (file);
- } catch (Exception) {
- // .NET seems to ignore failures here
- }
- }
- }
-
- eventLogKey.DeleteSubKeyTree (logName);
- }
+ EventLogImpl impl = CreateEventLogImpl (logName, machineName,
+ string.Empty);
+ impl.Delete (logName, machineName);
}
- public static void DeleteEventSource(string source)
+ public static void DeleteEventSource (string source)
{
DeleteEventSource (source, ".");
}
public static void DeleteEventSource (string source, string machineName)
{
if (machineName == null || machineName.Length == 0)
+#if NET_2_0
throw new ArgumentException (string.Format (
CultureInfo.InvariantCulture, "Invalid value '{0}' for"
+ " parameter 'machineName'.", machineName));
+#else
+ throw new ArgumentException (string.Format (
+ CultureInfo.InvariantCulture, "Invalid value {0} for"
+ + " parameter machineName.", machineName));
+#endif
- using (RegistryKey logKey = FindLogKeyBySource (source, machineName, true)) {
- if (logKey == null) {
- throw new ArgumentException (string.Format (
- CultureInfo.InvariantCulture, "The source '{0}' is not"
- + " registered on computer '{1}'.", source, machineName));
- }
-
- logKey.DeleteSubKeyTree (source);
-
- string[] sources = (string[]) logKey.GetValue ("Sources");
- if (sources != null) {
- ArrayList temp = new ArrayList ();
- for (int i = 0; i < sources.Length; i++)
- if (sources[i] != source)
- temp.Add (sources[i]);
- string[] newSources = new string[temp.Count];
- temp.CopyTo (newSources, 0);
- logKey.SetValue ("Sources", newSources);
- }
- }
+ EventLogImpl impl = CreateEventLogImpl (string.Empty, machineName,
+ source);
+ impl.DeleteEventSource (source, machineName);
}
protected override void Dispose (bool disposing)
{
- Impl.Dispose (disposing);
+ if (Impl != null)
+ Impl.Dispose (disposing);
}
public void EndInit()
Impl.EndInit();
}
- public static bool Exists(string logName)
+ public static bool Exists (string logName)
{
return Exists (logName, ".");
}
[MonoTODO ("Support remote machine")]
public static bool Exists (string logName, string machineName)
{
- using (RegistryKey logKey = FindLogKeyByName (logName, machineName, false)) {
- return (logKey != null);
- }
+ if (machineName == null || machineName.Length == 0)
+ throw new ArgumentException ("Invalid format for argument machineName.");
+
+ if (logName == null || logName.Length == 0)
+ return false;
+
+ EventLogImpl impl = CreateEventLogImpl (logName, machineName,
+ string.Empty);
+ return impl.Exists (logName, machineName);
}
public static EventLog[] GetEventLogs ()
[MonoTODO ("Support remote machine")]
public static EventLog[] GetEventLogs (string machineName)
{
- using (RegistryKey eventLogKey = GetEventLogKey (machineName, false)) {
- if (eventLogKey == null) {
- throw new InvalidOperationException ("TODO");
- }
- string[] logNames = eventLogKey.GetSubKeyNames ();
- EventLog[] eventLogs = new EventLog[logNames.Length];
- for (int i = 0; i < logNames.Length; i++) {
- EventLog eventLog = new EventLog (logNames[i], machineName);
- eventLogs[i] = eventLog;
- }
- return eventLogs;
- }
+ EventLogImpl impl = CreateEventLogImpl (new EventLog ());
+ return impl.GetEventLogs (machineName);
}
[MonoTODO ("Support remote machine")]
public static string LogNameFromSourceName (string source, string machineName)
{
- using (RegistryKey logKey = FindLogKeyBySource (source, machineName, false)) {
- if (logKey == null)
- return string.Empty;
+ if (machineName == null || machineName.Length == 0)
+#if NET_2_0
+ throw new ArgumentException (string.Format (
+ CultureInfo.InvariantCulture, "Invalid value '{0}' for"
+ + " parameter 'MachineName'.", machineName));
+#else
+ throw new ArgumentException (string.Format (
+ CultureInfo.InvariantCulture, "Invalid value {0} for"
+ + " parameter MachineName.", machineName));
+#endif
- return GetLogName (logKey);
- }
+ EventLogImpl impl = CreateEventLogImpl (string.Empty, machineName,
+ source);
+ return impl.LogNameFromSourceName (source, machineName);
}
- public static bool SourceExists(string source)
+ public static bool SourceExists (string source)
{
return SourceExists (source, ".");
}
CultureInfo.InvariantCulture, "Invalid value '{0}' for"
+ " parameter 'machineName'.", machineName));
- RegistryKey logKey = FindLogKeyBySource (source, machineName, false);
- if (logKey != null) {
- logKey.Close ();
- return true;
- }
- return false;
+ EventLogImpl impl = CreateEventLogImpl (string.Empty, machineName,
+ source);
+ return impl.SourceExists (source, machineName);
}
- public void WriteEntry(string message)
+ public void WriteEntry (string message)
{
WriteEntry (message, EventLogEntryType.Information);
}
- public void WriteEntry(string message, EventLogEntryType type)
+ public void WriteEntry (string message, EventLogEntryType type)
{
WriteEntry (message, type, 0);
}
- public void WriteEntry(string message, EventLogEntryType type,
+ public void WriteEntry (string message, EventLogEntryType type,
int eventID)
{
WriteEntry (message, type, eventID, 0);
}
- public void WriteEntry(string message, EventLogEntryType type,
+ public void WriteEntry (string message, EventLogEntryType type,
int eventID,
short category)
{
- if (Source.Length == 0) {
- throw new ArgumentException ("Source property was not set"
- + "before writing to the event log.");
- }
-
- if (!SourceExists (Source, MachineName)) {
- if (Log == null || Log.Length == 0) {
- Log = "Application";
- }
- CreateEventSource (Source, Log, MachineName);
- }
-
WriteEntry (message, type, eventID, category, null);
}
- public void WriteEntry(string message, EventLogEntryType type,
+ public void WriteEntry (string message, EventLogEntryType type,
int eventID,
short category, byte[] rawData)
{
- Impl.WriteEntry (message, type, eventID, category, rawData);
+ WriteEntry (new string [] { message }, type, eventID,
+ category, rawData);
}
- public static void WriteEntry(string source, string message)
+ public static void WriteEntry (string source, string message)
{
WriteEntry (source, message, EventLogEntryType.Information);
}
- public static void WriteEntry(string source, string message,
+ public static void WriteEntry (string source, string message,
EventLogEntryType type)
{
- WriteEntry (source, message, EventLogEntryType.Information, 0);
+ WriteEntry (source, message, type, 0);
}
- public static void WriteEntry(string source, string message,
+ public static void WriteEntry (string source, string message,
EventLogEntryType type, int eventID)
{
- WriteEntry (source, message, EventLogEntryType.Information, eventID, 0);
+ WriteEntry (source, message, type, eventID, 0);
}
- public static void WriteEntry(string source, string message,
+ public static void WriteEntry (string source, string message,
EventLogEntryType type, int eventID, short category)
{
- WriteEntry (source, message, EventLogEntryType.Information, eventID, category, null);
+ WriteEntry (source, message, type, eventID, category, null);
}
- public static void WriteEntry(string source, string message,
+ public static void WriteEntry (string source, string message,
EventLogEntryType type, int eventID, short category,
byte[] rawData)
{
}
}
+#if NET_2_0
+ public void WriteEvent (EventInstance instance, params object [] values)
+ {
+ WriteEvent (instance, null, values);
+ }
+
+ public void WriteEvent (EventInstance instance, byte [] data, params object [] values)
+ {
+ if (instance == null)
+ throw new ArgumentNullException ("instance");
+
+ string [] replacementStrings = null;
+ if (values != null) {
+ replacementStrings = new string [values.Length];
+ for (int i = 0; i < values.Length; i++) {
+ object value = values [i];
+ if (value == null)
+ replacementStrings [i] = string.Empty;
+ else
+ replacementStrings [i] = values [i].ToString ();
+ }
+ } else {
+ replacementStrings = new string [0];
+ }
+
+ WriteEntry (replacementStrings, instance.EntryType, instance
+ .InstanceId, (short) instance.CategoryId, data);
+ }
+
+ public static void WriteEvent (string source, EventInstance instance, params object [] values)
+ {
+ WriteEvent (source, instance, null, values);
+ }
+
+ public static void WriteEvent (string source, EventInstance instance, byte [] data, params object [] values)
+ {
+ using (EventLog eventLog = new EventLog ()) {
+ eventLog.Source = source;
+ eventLog.WriteEvent (instance, data, values);
+ }
+ }
+#endif
+
internal void OnEntryWritten (EventLogEntry newEntry)
{
if (EntryWritten != null)
}
[MonitoringDescription ("Raised for each EventLog entry written.")]
+ [MonoTODO ("Use FSM for local file implementation, and NotifyChangeEventLog for win32")]
public event EntryWrittenEventHandler EntryWritten;
internal string GetLogName ()
return logName;
}
+ private static EventLogImpl CreateEventLogImpl (string logName, string machineName, string source)
+ {
+ EventLog eventLog = new EventLog (logName, machineName, source);
+ return CreateEventLogImpl (eventLog);
+ }
+
+ private static EventLogImpl CreateEventLogImpl (EventLog eventLog)
+ {
+ switch (EventLogImplType) {
+ case LOCAL_FILE_IMPL:
+ return new LocalFileEventLog (eventLog);
+ case WIN32_IMPL:
+ return new Win32EventLog (eventLog);
+ case NULL_IMPL:
+ return new NullEventLog (eventLog);
+ default:
+ // we should never get here
+ throw new NotSupportedException (string.Format (
+ CultureInfo.InvariantCulture, "Eventlog implementation"
+ + " '{0}' is not supported.", EventLogImplType));
+ }
+ }
+
private static bool Win32EventLogEnabled {
get {
return (Environment.OSVersion.Platform == PlatformID.Win32NT);
}
}
- private static void UpdateLogRegistry (RegistryKey logKey)
+ // IMPORTANT: also modify corresponding property in EventLogTest
+ private static string EventLogImplType
{
- if (!Win32EventLogEnabled)
- return;
-
- // TODO: write other Log values:
- // - MaxSize
- // - Retention
- // - AutoBackupLogFiles
-
- if (logKey.GetValue ("File") == null) {
- string logName = GetLogName (logKey);
- string file;
- if (logName.Length > 8) {
- file = logName.Substring (0, 8) + ".evt";
+ get {
+ string implType = Environment.GetEnvironmentVariable (EVENTLOG_TYPE_VAR);
+ if (implType == null) {
+ if (Win32EventLogEnabled)
+ return WIN32_IMPL;
+ implType = NULL_IMPL;
} else {
- file = logName + ".evt";
+ if (Win32EventLogEnabled && string.Compare (implType, WIN32_IMPL, true) == 0)
+ implType = WIN32_IMPL;
+ else if (string.Compare (implType, NULL_IMPL, true) == 0)
+ implType = NULL_IMPL;
+ else if (string.Compare (implType, 0, LOCAL_FILE_IMPL, 0, LOCAL_FILE_IMPL.Length, true) == 0)
+ implType = LOCAL_FILE_IMPL;
+ else
+ throw new NotSupportedException (string.Format (
+ CultureInfo.InvariantCulture, "Eventlog implementation"
+ + " '{0}' is not supported.", implType));
}
- string configPath = Path.Combine (Environment.GetFolderPath (
- Environment.SpecialFolder.System), "config");
- logKey.SetValue ("File", Path.Combine (configPath, file));
+ return implType;
}
-
}
- private static void UpdateSourceRegistry (RegistryKey sourceKey, EventSourceCreationData data)
+ private void WriteEntry (string [] replacementStrings, EventLogEntryType type, long instanceID, short category, byte [] rawData)
{
- if (data.CategoryCount > 0)
- sourceKey.SetValue ("CategoryCount", data.CategoryCount);
+ if (Source.Length == 0)
+ throw new ArgumentException ("Source property was not set"
+ + "before writing to the event log.");
- if (data.CategoryResourceFile != null && data.CategoryResourceFile.Length > 0)
- sourceKey.SetValue ("CategoryMessageFile", data.CategoryResourceFile);
+ if (!Enum.IsDefined (typeof (EventLogEntryType), type))
+ throw new InvalidEnumArgumentException ("type", (int) type,
+ typeof (EventLogEntryType));
- if (data.MessageResourceFile != null && data.MessageResourceFile.Length > 0)
- sourceKey.SetValue ("EventMessageFile", data.MessageResourceFile);
+#if NET_2_0
+ ValidateEventID (instanceID);
+#endif
- if (data.ParameterResourceFile != null && data.ParameterResourceFile.Length > 0)
- sourceKey.SetValue ("ParameterMessageFile", data.ParameterResourceFile);
- }
+ if (!SourceExists (Source, MachineName)) {
+ if (Log == null || Log.Length == 0) {
+ Log = "Application";
+ }
+ CreateEventSource (Source, Log, MachineName);
+
+#if ONLY_1_1
+ ValidateEventID (instanceID);
+#endif
+ } else if (logName != null && logName.Length != 0) {
+#if ONLY_1_1
+ ValidateEventID (instanceID);
+#endif
+ string actualLog = LogNameFromSourceName (Source, MachineName);
+ if (string.Compare (logName, actualLog, true, CultureInfo.InvariantCulture) != 0)
+ throw new ArgumentException (string.Format (
+ CultureInfo.InvariantCulture, "The source '{0}' is not"
+ + " registered in log '{1}' (it is registered in log"
+ + " '{2}'). The Source and Log properties must be"
+ + " matched, or you may set Log to the empty string,"
+ + " and it will automatically be matched to the Source"
+ + " property.", Source, logName, actualLog));
+ }
- private static string GetLogName (RegistryKey logKey) {
- string logName = logKey.Name;
- return logName.Substring (logName.LastIndexOf ("\\") + 1);
+#if ONLY_1_1
+ ValidateEventID (instanceID);
+#endif
+
+ if (rawData == null)
+ rawData = new byte [0];
+
+ Impl.WriteEntry (replacementStrings, type, (uint) instanceID, category, rawData);
}
- [MonoTODO ("Support remote machines")]
- private static RegistryKey GetEventLogKey (string machineName, bool writable)
+ private void ValidateEventID (long instanceID)
{
- return Registry.LocalMachine.OpenSubKey (@"SYSTEM\CurrentControlSet\Services\EventLog", writable);
+ int eventID = GetEventID (instanceID);
+ if (eventID < ushort.MinValue || eventID > ushort.MaxValue)
+ throw new ArgumentException (string.Format (CultureInfo.InvariantCulture,
+ "Invalid eventID value '{0}'. It must be in the range between"
+ + " '{1}' and '{2}'.", instanceID, ushort.MinValue, ushort.MaxValue));
}
- private static RegistryKey FindLogKeyByName (string logName, string machineName, bool writable)
+ internal static int GetEventID (long instanceID)
{
- using (RegistryKey eventLogKey = GetEventLogKey (machineName, writable)) {
- if (eventLogKey == null) {
- return null;
- }
+ long inst = (instanceID < 0) ? -instanceID : instanceID;
- return eventLogKey.OpenSubKey (logName, writable);
- }
- }
-
- private static RegistryKey FindLogKeyBySource (string source, string machineName, bool writable)
- {
- if (source == null || source.Length == 0)
- return null;
-
- RegistryKey eventLogKey = null;
- try {
- eventLogKey = GetEventLogKey (machineName, writable);
- if (eventLogKey == null)
- return null;
-
- string[] subKeys = eventLogKey.GetSubKeyNames ();
- for (int i = 0; i < subKeys.Length; i++) {
- RegistryKey sourceKey = null;
- try {
- RegistryKey logKey = eventLogKey.OpenSubKey (subKeys[i], writable);
- if (logKey != null) {
- sourceKey = logKey.OpenSubKey (source, writable);
- if (sourceKey != null)
- return logKey;
- }
- } finally {
- if (sourceKey != null)
- sourceKey.Close ();
- }
- }
- return null;
- } finally {
- if (eventLogKey != null)
- eventLogKey.Close ();
- }
+ // MSDN: eventID equals the InstanceId with the top two bits masked
+ int eventID = (int) (inst & 0x3fffffff);
+ return (instanceID < 0) ? -eventID : eventID;
}
}
}