2010-06-21 Atsushi Enomoto <atsushi@ximian.com>
[mcs.git] / class / System / System.Diagnostics / EventLog.cs
blob2c88565e580c90f8814afbe0318a3d6c08bfdf22
1 //
2 // System.Diagnostics.EventLog.cs
3 //
4 // Authors:
5 // Jonathan Pryor (jonpryor@vt.edu)
6 // Andreas Nahr (ClassDevelopment@A-SoftTech.com)
7 // Gert Driesen (drieseng@users.sourceforge.net)
8 //
9 // Copyright (C) 2002
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:
21 //
22 // The above copyright notice and this permission notice shall be
23 // included in all copies or substantial portions of the Software.
24 //
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.
34 using System;
35 using System.Diagnostics;
36 using System.Collections;
37 using System.ComponentModel;
38 using System.ComponentModel.Design;
39 using System.Globalization;
40 using System.IO;
41 using System.Runtime.InteropServices;
43 namespace System.Diagnostics
45 [DefaultEvent ("EntryWritten")]
46 [InstallerType (typeof (EventLogInstaller))]
47 #if NET_2_0
48 [MonitoringDescription ("Represents an event log")]
49 #else
50 [Designer ("Microsoft.VisualStudio.Install.EventLogInstallableComponentDesigner, " + Consts.AssemblyMicrosoft_VisualStudio)]
51 #endif
52 public class EventLog : Component, ISupportInitialize
54 private string source;
55 private string logName;
56 private string machineName;
57 private bool doRaiseEvents = false;
58 private ISynchronizeInvoke synchronizingObject = null;
60 // IMPORTANT: also update constants in EventLogTest
61 internal const string LOCAL_FILE_IMPL = "local";
62 private const string WIN32_IMPL = "win32";
63 private const string NULL_IMPL = "null";
65 internal const string EVENTLOG_TYPE_VAR = "MONO_EVENTLOG_TYPE";
67 private EventLogImpl Impl;
69 public EventLog() : this (string.Empty)
73 public EventLog(string logName) : this (logName, ".")
77 public EventLog(string logName, string machineName)
78 : this (logName, machineName, string.Empty)
82 public EventLog(string logName, string machineName, string source)
84 if (logName == null) {
85 throw new ArgumentNullException ("logName");
87 if (machineName == null || machineName.Trim ().Length == 0)
88 #if NET_2_0
89 throw new ArgumentException (string.Format (
90 CultureInfo.InvariantCulture, "Invalid value '{0}' for"
91 + " parameter 'machineName'.", machineName));
92 #else
93 throw new ArgumentException (string.Format (
94 CultureInfo.InvariantCulture, "Invalid value {0} for"
95 + " parameter MachineName.", machineName));
96 #endif
98 this.source = source;
99 this.machineName = machineName;
100 this.logName = logName;
102 Impl = CreateEventLogImpl (this);
105 [Browsable (false), DefaultValue (false)]
106 [MonitoringDescription ("If enabled raises event when a log is written.")]
107 public bool EnableRaisingEvents {
108 get {return doRaiseEvents;}
109 set {
110 if (value == doRaiseEvents)
111 return;
113 if (value)
114 Impl.EnableNotification ();
115 else
116 Impl.DisableNotification ();
117 doRaiseEvents = value;
121 [Browsable (false), DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
122 [MonitoringDescription ("The entries in the log.")]
123 public EventLogEntryCollection Entries {
124 get {return new EventLogEntryCollection(Impl);}
127 [ReadOnly (true), DefaultValue (""), RecommendedAsConfigurable (true)]
128 [TypeConverter ("System.Diagnostics.Design.LogConverter, " + Consts.AssemblySystem_Design)]
129 [MonitoringDescription ("Name of the log that is read and written.")]
130 public string Log {
131 get {
132 if (source != null && source.Length > 0)
133 return GetLogName ();
134 return logName;
136 set {
137 if (value == null)
138 throw new ArgumentNullException ("value");
140 // log name is treated case-insensitively on all platforms
141 if (string.Compare (logName, value, true) != 0) {
142 logName = value;
143 Reset ();
148 [Browsable (false)]
149 public string LogDisplayName {
150 get { return Impl.LogDisplayName; }
153 [ReadOnly (true), DefaultValue ("."), RecommendedAsConfigurable (true)]
154 [MonitoringDescription ("Name of the machine that this log get written to.")]
155 public string MachineName {
156 get { return machineName; }
157 set {
158 if (value == null || value.Trim ().Length == 0)
159 throw new ArgumentException (string.Format (
160 CultureInfo.InvariantCulture, "Invalid value {0} for"
161 + " property MachineName.", value));
163 if (string.Compare (machineName, value, true) != 0) {
164 Close ();
165 machineName = value;
170 [ReadOnly (true), DefaultValue (""), RecommendedAsConfigurable (true)]
171 [TypeConverter ("System.Diagnostics.Design.StringValueConverter, " + Consts.AssemblySystem_Design)]
172 [MonitoringDescription ("The application name that writes the log.")]
173 public string Source {
174 get { return source; }
175 set {
176 if (value == null)
177 value = string.Empty;
179 // Source only affects eventlog implementation if Source was set
180 // and no Log was set
181 if (source == null || source.Length == 0 && (logName == null ||logName.Length == 0)) {
182 source = value;
183 } else if (string.Compare (source, value, true) != 0) {
184 source = value;
185 Reset ();
190 [Browsable (false), DefaultValue (null)]
191 [MonitoringDescription ("An object that synchronizes event handler calls.")]
192 public ISynchronizeInvoke SynchronizingObject {
193 get {return synchronizingObject;}
194 set {synchronizingObject = value;}
197 #if NET_2_0
198 [MonoTODO]
199 [ComVisibleAttribute (false)]
200 [Browsable (false)]
201 public OverflowAction OverflowAction {
202 get { return Impl.OverflowAction; }
205 [MonoTODO]
206 [ComVisibleAttribute (false)]
207 [Browsable (false)]
208 public int MinimumRetentionDays {
209 get { return Impl.MinimumRetentionDays; }
212 [MonoTODO]
213 [ComVisibleAttribute (false)]
214 [Browsable (false)]
215 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
216 public long MaximumKilobytes {
217 get { return Impl.MaximumKilobytes; }
218 set { Impl.MaximumKilobytes = value; }
221 [MonoTODO]
222 [ComVisible (false)]
223 public void ModifyOverflowPolicy (OverflowAction action, int retentionDays)
225 Impl.ModifyOverflowPolicy (action, retentionDays);
228 [MonoTODO]
229 [ComVisibleAttribute (false)]
230 public void RegisterDisplayName (string resourceFile, long resourceId)
232 Impl.RegisterDisplayName (resourceFile, resourceId);
234 #endif
236 public void BeginInit ()
238 Impl.BeginInit();
241 public void Clear ()
243 string logName = Log;
244 if (logName == null || logName.Length == 0)
245 throw new ArgumentException ("Log property value has not been specified.");
247 if (!EventLog.Exists (logName, MachineName))
248 throw new InvalidOperationException (string.Format (
249 CultureInfo.InvariantCulture, "Event Log '{0}'"
250 + " does not exist on computer '{1}'.", logName,
251 machineName));
253 Impl.Clear ();
254 Reset ();
257 public void Close ()
259 Impl.Close();
260 EnableRaisingEvents = false;
263 internal void Reset ()
265 bool enableRaisingEvents = EnableRaisingEvents;
266 Close ();
267 EnableRaisingEvents = enableRaisingEvents;
270 public static void CreateEventSource (string source, string logName)
272 CreateEventSource (source, logName, ".");
275 #if NET_2_0
276 [Obsolete ("use CreateEventSource(EventSourceCreationData) instead")]
277 #endif
278 public static void CreateEventSource (string source,
279 string logName,
280 string machineName)
282 CreateEventSource (new EventSourceCreationData (source, logName,
283 machineName));
286 #if NET_2_0
287 [MonoNotSupported ("remote machine is not supported")]
288 public
289 #else
290 private
291 #endif
292 static void CreateEventSource (EventSourceCreationData sourceData)
294 if (sourceData.Source == null || sourceData.Source.Length == 0)
295 throw new ArgumentException ("Source property value has not been specified.");
297 if (sourceData.LogName == null || sourceData.LogName.Length == 0)
298 throw new ArgumentException ("Log property value has not been specified.");
300 if (SourceExists (sourceData.Source, sourceData.MachineName))
301 throw new ArgumentException (string.Format (CultureInfo.InvariantCulture,
302 "Source '{0}' already exists on '{1}'.", sourceData.Source,
303 sourceData.MachineName));
305 EventLogImpl impl = CreateEventLogImpl (sourceData.LogName,
306 sourceData.MachineName, sourceData.Source);
307 impl.CreateEventSource (sourceData);
310 public static void Delete (string logName)
312 Delete (logName, ".");
315 [MonoNotSupported ("remote machine is not supported")]
316 public static void Delete (string logName, string machineName)
318 if (machineName == null || machineName.Trim ().Length == 0)
319 throw new ArgumentException ("Invalid format for argument"
320 + " machineName.");
322 if (logName == null || logName.Length == 0)
323 throw new ArgumentException ("Log to delete was not specified.");
325 EventLogImpl impl = CreateEventLogImpl (logName, machineName,
326 string.Empty);
327 impl.Delete (logName, machineName);
330 public static void DeleteEventSource (string source)
332 DeleteEventSource (source, ".");
335 [MonoNotSupported ("remote machine is not supported")]
336 public static void DeleteEventSource (string source, string machineName)
338 if (machineName == null || machineName.Trim ().Length == 0)
339 #if NET_2_0
340 throw new ArgumentException (string.Format (
341 CultureInfo.InvariantCulture, "Invalid value '{0}' for"
342 + " parameter 'machineName'.", machineName));
343 #else
344 throw new ArgumentException (string.Format (
345 CultureInfo.InvariantCulture, "Invalid value {0} for"
346 + " parameter machineName.", machineName));
347 #endif
349 EventLogImpl impl = CreateEventLogImpl (string.Empty, machineName,
350 source);
351 impl.DeleteEventSource (source, machineName);
354 protected override void Dispose (bool disposing)
356 if (Impl != null)
357 Impl.Dispose (disposing);
360 public void EndInit()
362 Impl.EndInit();
365 public static bool Exists (string logName)
367 return Exists (logName, ".");
370 [MonoNotSupported ("remote machine is not supported")]
371 public static bool Exists (string logName, string machineName)
373 if (machineName == null || machineName.Trim ().Length == 0)
374 throw new ArgumentException ("Invalid format for argument machineName.");
376 if (logName == null || logName.Length == 0)
377 return false;
379 EventLogImpl impl = CreateEventLogImpl (logName, machineName,
380 string.Empty);
381 return impl.Exists (logName, machineName);
384 public static EventLog[] GetEventLogs ()
386 return GetEventLogs (".");
389 [MonoNotSupported ("remote machine is not supported")]
390 public static EventLog[] GetEventLogs (string machineName)
392 EventLogImpl impl = CreateEventLogImpl (new EventLog ());
393 return impl.GetEventLogs (machineName);
396 [MonoNotSupported ("remote machine is not supported")]
397 public static string LogNameFromSourceName (string source, string machineName)
399 if (machineName == null || machineName.Trim ().Length == 0)
400 #if NET_2_0
401 throw new ArgumentException (string.Format (
402 CultureInfo.InvariantCulture, "Invalid value '{0}' for"
403 + " parameter 'MachineName'.", machineName));
404 #else
405 throw new ArgumentException (string.Format (
406 CultureInfo.InvariantCulture, "Invalid value {0} for"
407 + " parameter MachineName.", machineName));
408 #endif
410 EventLogImpl impl = CreateEventLogImpl (string.Empty, machineName,
411 source);
412 return impl.LogNameFromSourceName (source, machineName);
415 public static bool SourceExists (string source)
417 return SourceExists (source, ".");
420 [MonoNotSupported ("remote machine is not supported")]
421 public static bool SourceExists (string source, string machineName)
423 if (machineName == null || machineName.Trim ().Length == 0)
424 #if NET_2_0
425 throw new ArgumentException (string.Format (
426 CultureInfo.InvariantCulture, "Invalid value '{0}' for"
427 + " parameter 'machineName'.", machineName));
428 #else
429 throw new ArgumentException (string.Format (
430 CultureInfo.InvariantCulture, "Invalid value {0} for"
431 + " parameter machineName.", machineName));
432 #endif
434 EventLogImpl impl = CreateEventLogImpl (string.Empty, machineName,
435 source);
436 return impl.SourceExists (source, machineName);
439 public void WriteEntry (string message)
441 WriteEntry (message, EventLogEntryType.Information);
444 public void WriteEntry (string message, EventLogEntryType type)
446 WriteEntry (message, type, 0);
449 public void WriteEntry (string message, EventLogEntryType type,
450 int eventID)
452 WriteEntry (message, type, eventID, 0);
455 public void WriteEntry (string message, EventLogEntryType type,
456 int eventID,
457 short category)
459 WriteEntry (message, type, eventID, category, null);
462 public void WriteEntry (string message, EventLogEntryType type,
463 int eventID,
464 short category, byte[] rawData)
466 WriteEntry (new string [] { message }, type, eventID,
467 category, rawData);
470 public static void WriteEntry (string source, string message)
472 WriteEntry (source, message, EventLogEntryType.Information);
475 public static void WriteEntry (string source, string message,
476 EventLogEntryType type)
478 WriteEntry (source, message, type, 0);
481 public static void WriteEntry (string source, string message,
482 EventLogEntryType type, int eventID)
484 WriteEntry (source, message, type, eventID, 0);
487 public static void WriteEntry (string source, string message,
488 EventLogEntryType type, int eventID, short category)
490 WriteEntry (source, message, type, eventID, category, null);
493 public static void WriteEntry (string source, string message,
494 EventLogEntryType type, int eventID, short category,
495 byte[] rawData)
497 using (EventLog eventLog = new EventLog ()) {
498 eventLog.Source = source;
499 eventLog.WriteEntry (message, type, eventID, category, rawData);
503 #if NET_2_0
504 [ComVisible (false)]
505 public void WriteEvent (EventInstance instance, params object [] values)
507 WriteEvent (instance, null, values);
510 [ComVisible (false)]
511 public void WriteEvent (EventInstance instance, byte [] data, params object [] values)
513 if (instance == null)
514 throw new ArgumentNullException ("instance");
516 string [] replacementStrings = null;
517 if (values != null) {
518 replacementStrings = new string [values.Length];
519 for (int i = 0; i < values.Length; i++) {
520 object value = values [i];
521 if (value == null)
522 replacementStrings [i] = string.Empty;
523 else
524 replacementStrings [i] = values [i].ToString ();
526 } else {
527 replacementStrings = new string [0];
530 WriteEntry (replacementStrings, instance.EntryType, instance
531 .InstanceId, (short) instance.CategoryId, data);
534 public static void WriteEvent (string source, EventInstance instance, params object [] values)
536 WriteEvent (source, instance, null, values);
539 public static void WriteEvent (string source, EventInstance instance, byte [] data, params object [] values)
541 using (EventLog eventLog = new EventLog ()) {
542 eventLog.Source = source;
543 eventLog.WriteEvent (instance, data, values);
546 #endif
548 internal void OnEntryWritten (EventLogEntry newEntry)
550 if (doRaiseEvents && EntryWritten != null)
551 EntryWritten (this, new EntryWrittenEventArgs (newEntry));
554 [MonitoringDescription ("Raised for each EventLog entry written.")]
555 public event EntryWrittenEventHandler EntryWritten;
557 internal string GetLogName ()
559 if (logName != null && logName.Length > 0)
560 return logName;
562 // if no log name has been set, then use source to determine name of log
563 logName = LogNameFromSourceName (source, machineName);
564 return logName;
567 private static EventLogImpl CreateEventLogImpl (string logName, string machineName, string source)
569 EventLog eventLog = new EventLog (logName, machineName, source);
570 return CreateEventLogImpl (eventLog);
573 private static EventLogImpl CreateEventLogImpl (EventLog eventLog)
575 switch (EventLogImplType) {
576 case LOCAL_FILE_IMPL:
577 return new LocalFileEventLog (eventLog);
578 case WIN32_IMPL:
579 return new Win32EventLog (eventLog);
580 case NULL_IMPL:
581 return new NullEventLog (eventLog);
582 default:
583 // we should never get here
584 throw new NotSupportedException (string.Format (
585 CultureInfo.InvariantCulture, "Eventlog implementation"
586 + " '{0}' is not supported.", EventLogImplType));
590 private static bool Win32EventLogEnabled {
591 get {
592 return (Environment.OSVersion.Platform == PlatformID.Win32NT);
596 // IMPORTANT: also modify corresponding property in EventLogTest
597 private static string EventLogImplType {
598 get {
599 string implType = Environment.GetEnvironmentVariable (EVENTLOG_TYPE_VAR);
600 if (implType == null) {
601 if (Win32EventLogEnabled)
602 return WIN32_IMPL;
603 implType = NULL_IMPL;
604 } else {
605 if (Win32EventLogEnabled && string.Compare (implType, WIN32_IMPL, true) == 0)
606 implType = WIN32_IMPL;
607 else if (string.Compare (implType, NULL_IMPL, true) == 0)
608 implType = NULL_IMPL;
609 else if (string.Compare (implType, 0, LOCAL_FILE_IMPL, 0, LOCAL_FILE_IMPL.Length, true) == 0)
610 implType = LOCAL_FILE_IMPL;
611 else
612 throw new NotSupportedException (string.Format (
613 CultureInfo.InvariantCulture, "Eventlog implementation"
614 + " '{0}' is not supported.", implType));
616 return implType;
620 private void WriteEntry (string [] replacementStrings, EventLogEntryType type, long instanceID, short category, byte [] rawData)
622 if (Source.Length == 0)
623 throw new ArgumentException ("Source property was not set"
624 + "before writing to the event log.");
626 if (!Enum.IsDefined (typeof (EventLogEntryType), type))
627 throw new InvalidEnumArgumentException ("type", (int) type,
628 typeof (EventLogEntryType));
630 #if NET_2_0
631 ValidateEventID (instanceID);
632 #endif
634 if (!SourceExists (Source, MachineName)) {
635 if (Log == null || Log.Length == 0) {
636 Log = "Application";
638 CreateEventSource (Source, Log, MachineName);
640 #if ONLY_1_1
641 ValidateEventID (instanceID);
642 #endif
643 } else if (logName != null && logName.Length != 0) {
644 #if ONLY_1_1
645 ValidateEventID (instanceID);
646 #endif
647 string actualLog = LogNameFromSourceName (Source, MachineName);
648 if (string.Compare (logName, actualLog, true, CultureInfo.InvariantCulture) != 0)
649 throw new ArgumentException (string.Format (
650 CultureInfo.InvariantCulture, "The source '{0}' is not"
651 + " registered in log '{1}' (it is registered in log"
652 + " '{2}'). The Source and Log properties must be"
653 + " matched, or you may set Log to the empty string,"
654 + " and it will automatically be matched to the Source"
655 + " property.", Source, logName, actualLog));
658 #if ONLY_1_1
659 ValidateEventID (instanceID);
660 #endif
662 if (rawData == null)
663 rawData = new byte [0];
665 Impl.WriteEntry (replacementStrings, type, (uint) instanceID, category, rawData);
668 private void ValidateEventID (long instanceID)
670 int eventID = GetEventID (instanceID);
671 if (eventID < ushort.MinValue || eventID > ushort.MaxValue)
672 throw new ArgumentException (string.Format (CultureInfo.InvariantCulture,
673 "Invalid eventID value '{0}'. It must be in the range between"
674 + " '{1}' and '{2}'.", instanceID, ushort.MinValue, ushort.MaxValue));
677 internal static int GetEventID (long instanceID)
679 long inst = (instanceID < 0) ? -instanceID : instanceID;
681 // MSDN: eventID equals the InstanceId with the top two bits masked
682 int eventID = (int) (inst & 0x3fffffff);
683 return (instanceID < 0) ? -eventID : eventID;