2 // System.Diagnostics.EventLog.cs
5 // Jonathan Pryor (jonpryor@vt.edu)
6 // Andreas Nahr (ClassDevelopment@A-SoftTech.com)
7 // Gert Driesen (drieseng@users.sourceforge.net)
10 // Copyright (C) 2003 Andreas Nahr
11 // Copyright (C) 2006 Novell, Inc (http://www.novell.com)
14 // Permission is hereby granted, free of charge, to any person obtaining
15 // a copy of this software and associated documentation files (the
16 // "Software"), to deal in the Software without restriction, including
17 // without limitation the rights to use, copy, modify, merge, publish,
18 // distribute, sublicense, and/or sell copies of the Software, and to
19 // permit persons to whom the Software is furnished to do so, subject to
20 // the following conditions:
22 // The above copyright notice and this permission notice shall be
23 // included in all copies or substantial portions of the Software.
25 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
26 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
27 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
28 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
29 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
30 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
31 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
35 using System.Diagnostics;
36 using System.Collections;
37 using System.ComponentModel;
38 using System.ComponentModel.Design;
39 using System.Globalization;
42 namespace System.Diagnostics
44 [DefaultEvent ("EntryWritten")]
45 [InstallerType (typeof (EventLogInstaller))]
46 [Designer ("Microsoft.VisualStudio.Install.EventLogInstallableComponentDesigner, " + Consts.AssemblyMicrosoft_VisualStudio)]
47 public class EventLog : Component, ISupportInitialize
49 private string source;
50 private string logName;
51 private string machineName;
52 private bool doRaiseEvents = false;
53 private ISynchronizeInvoke synchronizingObject = null;
55 // IMPORTANT: also update constants in EventLogTest
56 internal const string LOCAL_FILE_IMPL = "local";
57 private const string WIN32_IMPL = "win32";
58 private const string NULL_IMPL = "null";
60 internal const string EVENTLOG_TYPE_VAR = "MONO_EVENTLOG_TYPE";
62 private EventLogImpl Impl;
64 public EventLog() : this (string.Empty)
68 public EventLog(string logName) : this (logName, ".")
72 public EventLog(string logName, string machineName)
73 : this (logName, machineName, string.Empty)
77 public EventLog(string logName, string machineName, string source)
79 if (logName == null) {
80 throw new ArgumentNullException ("logName");
82 if (machineName == null || machineName.Length == 0)
84 throw new ArgumentException (string.Format (
85 CultureInfo.InvariantCulture, "Invalid value '{0}' for"
86 + " parameter 'machineName'.", machineName));
88 throw new ArgumentException (string.Format (
89 CultureInfo.InvariantCulture, "Invalid value {0} for"
90 + " parameter MachineName.", machineName));
94 this.machineName = machineName;
95 this.logName = logName;
97 Impl = CreateEventLogImpl (this);
98 Impl.EntryWritten += new EntryWrittenEventHandler (EntryWrittenHandler);
101 private void EntryWrittenHandler (object sender, EntryWrittenEventArgs e)
104 OnEntryWritten (e.Entry);
107 [Browsable (false), DefaultValue (false)]
108 [MonitoringDescription ("If enabled raises event when a log is written.")]
109 public bool EnableRaisingEvents {
110 get {return doRaiseEvents;}
111 set {doRaiseEvents = value;}
114 [Browsable (false), DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
115 [MonitoringDescription ("The entries in the log.")]
116 public EventLogEntryCollection Entries {
117 get {return new EventLogEntryCollection(Impl);}
120 [ReadOnly (true), DefaultValue (""), RecommendedAsConfigurable (true)]
121 [TypeConverter ("System.Diagnostics.Design.LogConverter, " + Consts.AssemblySystem_Design)]
122 [MonitoringDescription ("Name of the log that is read and written.")]
125 if (source != null && source.Length > 0)
126 return GetLogName ();
131 throw new ArgumentNullException ("value");
137 public string LogDisplayName {
138 get {return Impl.LogDisplayName;}
141 [ReadOnly (true), DefaultValue ("."), RecommendedAsConfigurable (true)]
142 [MonitoringDescription ("Name of the machine that this log get written to.")]
143 public string MachineName {
144 get {return machineName;}
145 set {machineName = value;}
148 [ReadOnly (true), DefaultValue (""), RecommendedAsConfigurable (true)]
149 [TypeConverter ("System.Diagnostics.Design.StringValueConverter, " + Consts.AssemblySystem_Design)]
150 [MonitoringDescription ("The application name that writes the log.")]
151 public string Source {
152 get { return source; }
153 set { source = (value == null) ? string.Empty : value; }
156 [Browsable (false), DefaultValue (null)]
157 [MonitoringDescription ("An object that synchronizes event handler calls.")]
158 public ISynchronizeInvoke SynchronizingObject {
159 get {return synchronizingObject;}
160 set {synchronizingObject = value;}
163 public void BeginInit ()
170 string logName = Log;
171 if (logName == null || logName.Length == 0)
172 throw new ArgumentException ("Log property value has not been specified.");
174 if (!EventLog.Exists (logName, MachineName))
175 throw new InvalidOperationException (string.Format (
176 CultureInfo.InvariantCulture, "Event Log '{0}'"
177 + " does not exist on computer '{1}'.", logName,
188 public static void CreateEventSource (string source, string logName)
190 CreateEventSource (source, logName, ".");
193 public static void CreateEventSource (string source,
197 CreateEventSource (new EventSourceCreationData (source, logName,
202 [MonoTODO ("Support remote machine")]
207 static void CreateEventSource (EventSourceCreationData sourceData)
209 if (sourceData.Source == null || sourceData.Source.Length == 0)
210 throw new ArgumentException ("Source property value has not been specified.");
212 if (sourceData.LogName == null || sourceData.LogName.Length == 0)
213 throw new ArgumentException ("Log property value has not been specified.");
215 if (SourceExists (sourceData.Source, sourceData.MachineName))
216 throw new ArgumentException (string.Format (CultureInfo.InvariantCulture,
217 "Source '{0}' already exists on '{1}'.", sourceData.Source,
218 sourceData.MachineName));
220 EventLogImpl impl = CreateEventLogImpl (sourceData.LogName,
221 sourceData.MachineName, sourceData.Source);
222 impl.CreateEventSource (sourceData);
225 public static void Delete (string logName)
227 Delete (logName, ".");
230 [MonoTODO ("Support remote machine")]
231 public static void Delete (string logName, string machineName)
233 if (machineName == null || machineName.Length == 0)
234 throw new ArgumentException ("Invalid format for argument"
237 if (logName == null || logName.Length == 0)
238 throw new ArgumentException ("Log to delete was not specified.");
240 EventLogImpl impl = CreateEventLogImpl (logName, machineName,
242 impl.Delete (logName, machineName);
245 public static void DeleteEventSource (string source)
247 DeleteEventSource (source, ".");
250 [MonoTODO ("Support remote machine")]
251 public static void DeleteEventSource (string source, string machineName)
253 if (machineName == null || machineName.Length == 0)
255 throw new ArgumentException (string.Format (
256 CultureInfo.InvariantCulture, "Invalid value '{0}' for"
257 + " parameter 'machineName'.", machineName));
259 throw new ArgumentException (string.Format (
260 CultureInfo.InvariantCulture, "Invalid value {0} for"
261 + " parameter machineName.", machineName));
264 EventLogImpl impl = CreateEventLogImpl (string.Empty, machineName,
266 impl.DeleteEventSource (source, machineName);
269 protected override void Dispose (bool disposing)
272 Impl.Dispose (disposing);
275 public void EndInit()
280 public static bool Exists (string logName)
282 return Exists (logName, ".");
285 [MonoTODO ("Support remote machine")]
286 public static bool Exists (string logName, string machineName)
288 if (machineName == null || machineName.Length == 0)
289 throw new ArgumentException ("Invalid format for argument machineName.");
291 if (logName == null || logName.Length == 0)
294 EventLogImpl impl = CreateEventLogImpl (logName, machineName,
296 return impl.Exists (logName, machineName);
299 public static EventLog[] GetEventLogs ()
301 return GetEventLogs (".");
304 [MonoTODO ("Support remote machine")]
305 public static EventLog[] GetEventLogs (string machineName)
307 EventLogImpl impl = CreateEventLogImpl (new EventLog ());
308 return impl.GetEventLogs (machineName);
311 [MonoTODO ("Support remote machine")]
312 public static string LogNameFromSourceName (string source, string machineName)
314 if (machineName == null || machineName.Length == 0)
316 throw new ArgumentException (string.Format (
317 CultureInfo.InvariantCulture, "Invalid value '{0}' for"
318 + " parameter 'MachineName'.", machineName));
320 throw new ArgumentException (string.Format (
321 CultureInfo.InvariantCulture, "Invalid value {0} for"
322 + " parameter MachineName.", machineName));
325 EventLogImpl impl = CreateEventLogImpl (string.Empty, machineName,
327 return impl.LogNameFromSourceName (source, machineName);
330 public static bool SourceExists (string source)
332 return SourceExists (source, ".");
335 [MonoTODO ("Support remote machines")]
336 public static bool SourceExists (string source, string machineName)
338 if (machineName == null || machineName.Length == 0)
339 throw new ArgumentException (string.Format (
340 CultureInfo.InvariantCulture, "Invalid value '{0}' for"
341 + " parameter 'machineName'.", machineName));
343 EventLogImpl impl = CreateEventLogImpl (string.Empty, machineName,
345 return impl.SourceExists (source, machineName);
348 public void WriteEntry (string message)
350 WriteEntry (message, EventLogEntryType.Information);
353 public void WriteEntry (string message, EventLogEntryType type)
355 WriteEntry (message, type, 0);
358 public void WriteEntry (string message, EventLogEntryType type,
361 WriteEntry (message, type, eventID, 0);
364 public void WriteEntry (string message, EventLogEntryType type,
368 WriteEntry (message, type, eventID, category, null);
371 public void WriteEntry (string message, EventLogEntryType type,
373 short category, byte[] rawData)
375 WriteEntry (new string [] { message }, type, eventID,
379 public static void WriteEntry (string source, string message)
381 WriteEntry (source, message, EventLogEntryType.Information);
384 public static void WriteEntry (string source, string message,
385 EventLogEntryType type)
387 WriteEntry (source, message, type, 0);
390 public static void WriteEntry (string source, string message,
391 EventLogEntryType type, int eventID)
393 WriteEntry (source, message, type, eventID, 0);
396 public static void WriteEntry (string source, string message,
397 EventLogEntryType type, int eventID, short category)
399 WriteEntry (source, message, type, eventID, category, null);
402 public static void WriteEntry (string source, string message,
403 EventLogEntryType type, int eventID, short category,
406 using (EventLog eventLog = new EventLog ()) {
407 eventLog.Source = source;
408 eventLog.WriteEntry (message, type, eventID, category, rawData);
413 public void WriteEvent (EventInstance instance, params object [] values)
415 WriteEvent (instance, null, values);
418 public void WriteEvent (EventInstance instance, byte [] data, params object [] values)
420 if (instance == null)
421 throw new ArgumentNullException ("instance");
423 string [] replacementStrings = null;
424 if (values != null) {
425 replacementStrings = new string [values.Length];
426 for (int i = 0; i < values.Length; i++) {
427 object value = values [i];
429 replacementStrings [i] = string.Empty;
431 replacementStrings [i] = values [i].ToString ();
434 replacementStrings = new string [0];
437 WriteEntry (replacementStrings, instance.EntryType, instance
438 .InstanceId, (short) instance.CategoryId, data);
441 public static void WriteEvent (string source, EventInstance instance, params object [] values)
443 WriteEvent (source, instance, null, values);
446 public static void WriteEvent (string source, EventInstance instance, byte [] data, params object [] values)
448 using (EventLog eventLog = new EventLog ()) {
449 eventLog.Source = source;
450 eventLog.WriteEvent (instance, data, values);
455 internal void OnEntryWritten (EventLogEntry newEntry)
457 if (EntryWritten != null)
458 EntryWritten (this, new EntryWrittenEventArgs (newEntry));
461 [MonitoringDescription ("Raised for each EventLog entry written.")]
462 [MonoTODO ("Use FSM for local file implementation, and NotifyChangeEventLog for win32")]
463 public event EntryWrittenEventHandler EntryWritten;
465 internal string GetLogName ()
467 if (logName != null && logName.Length > 0)
470 // if no log name has been set, then use source to determine name of log
471 logName = LogNameFromSourceName (source, machineName);
475 private static EventLogImpl CreateEventLogImpl (string logName, string machineName, string source)
477 EventLog eventLog = new EventLog (logName, machineName, source);
478 return CreateEventLogImpl (eventLog);
481 private static EventLogImpl CreateEventLogImpl (EventLog eventLog)
483 switch (EventLogImplType) {
484 case LOCAL_FILE_IMPL:
485 return new LocalFileEventLog (eventLog);
487 return new Win32EventLog (eventLog);
489 return new NullEventLog (eventLog);
491 // we should never get here
492 throw new NotSupportedException (string.Format (
493 CultureInfo.InvariantCulture, "Eventlog implementation"
494 + " '{0}' is not supported.", EventLogImplType));
498 private static bool Win32EventLogEnabled {
500 return (Environment.OSVersion.Platform == PlatformID.Win32NT);
504 // IMPORTANT: also modify corresponding property in EventLogTest
505 private static string EventLogImplType
508 string implType = Environment.GetEnvironmentVariable (EVENTLOG_TYPE_VAR);
509 if (implType == null) {
510 if (Win32EventLogEnabled)
512 implType = NULL_IMPL;
514 if (Win32EventLogEnabled && string.Compare (implType, WIN32_IMPL, true) == 0)
515 implType = WIN32_IMPL;
516 else if (string.Compare (implType, NULL_IMPL, true) == 0)
517 implType = NULL_IMPL;
518 else if (string.Compare (implType, 0, LOCAL_FILE_IMPL, 0, LOCAL_FILE_IMPL.Length, true) == 0)
519 implType = LOCAL_FILE_IMPL;
521 throw new NotSupportedException (string.Format (
522 CultureInfo.InvariantCulture, "Eventlog implementation"
523 + " '{0}' is not supported.", implType));
529 private void WriteEntry (string [] replacementStrings, EventLogEntryType type, long instanceID, short category, byte [] rawData)
531 if (Source.Length == 0)
532 throw new ArgumentException ("Source property was not set"
533 + "before writing to the event log.");
535 if (!Enum.IsDefined (typeof (EventLogEntryType), type))
536 throw new InvalidEnumArgumentException ("type", (int) type,
537 typeof (EventLogEntryType));
540 ValidateEventID (instanceID);
543 if (!SourceExists (Source, MachineName)) {
544 if (Log == null || Log.Length == 0) {
547 CreateEventSource (Source, Log, MachineName);
550 ValidateEventID (instanceID);
552 } else if (logName != null && logName.Length != 0) {
554 ValidateEventID (instanceID);
556 string actualLog = LogNameFromSourceName (Source, MachineName);
557 if (string.Compare (logName, actualLog, true, CultureInfo.InvariantCulture) != 0)
558 throw new ArgumentException (string.Format (
559 CultureInfo.InvariantCulture, "The source '{0}' is not"
560 + " registered in log '{1}' (it is registered in log"
561 + " '{2}'). The Source and Log properties must be"
562 + " matched, or you may set Log to the empty string,"
563 + " and it will automatically be matched to the Source"
564 + " property.", Source, logName, actualLog));
568 ValidateEventID (instanceID);
572 rawData = new byte [0];
574 Impl.WriteEntry (replacementStrings, type, (uint) instanceID, category, rawData);
577 private void ValidateEventID (long instanceID)
579 int eventID = GetEventID (instanceID);
580 if (eventID < ushort.MinValue || eventID > ushort.MaxValue)
581 throw new ArgumentException (string.Format (CultureInfo.InvariantCulture,
582 "Invalid eventID value '{0}'. It must be in the range between"
583 + " '{1}' and '{2}'.", instanceID, ushort.MinValue, ushort.MaxValue));
586 internal static int GetEventID (long instanceID)
588 long inst = (instanceID < 0) ? -instanceID : instanceID;
590 // MSDN: eventID equals the InstanceId with the top two bits masked
591 int eventID = (int) (inst & 0x3fffffff);
592 return (instanceID < 0) ? -eventID : eventID;