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
;
41 using System
.Runtime
.InteropServices
;
43 namespace System
.Diagnostics
45 [DefaultEvent ("EntryWritten")]
46 [InstallerType (typeof (EventLogInstaller
))]
48 [MonitoringDescription ("Represents an event log")]
50 [Designer ("Microsoft.VisualStudio.Install.EventLogInstallableComponentDesigner, " + Consts
.AssemblyMicrosoft_VisualStudio
)]
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)
89 throw new ArgumentException (string.Format (
90 CultureInfo
.InvariantCulture
, "Invalid value '{0}' for"
91 + " parameter 'machineName'.", machineName
));
93 throw new ArgumentException (string.Format (
94 CultureInfo
.InvariantCulture
, "Invalid value {0} for"
95 + " parameter MachineName.", machineName
));
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;}
110 if (value == doRaiseEvents
)
114 Impl
.EnableNotification ();
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.")]
132 if (source
!= null && source
.Length
> 0)
133 return GetLogName ();
138 throw new ArgumentNullException ("value");
140 // log name is treated case-insensitively on all platforms
141 if (string.Compare (logName
, value, true) != 0) {
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; }
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) {
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; }
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)) {
183 } else if (string.Compare (source
, value, true) != 0) {
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;}
199 [ComVisibleAttribute (false)]
201 public OverflowAction OverflowAction
{
202 get { return Impl.OverflowAction; }
206 [ComVisibleAttribute (false)]
208 public int MinimumRetentionDays
{
209 get { return Impl.MinimumRetentionDays; }
213 [ComVisibleAttribute (false)]
215 [DesignerSerializationVisibility (DesignerSerializationVisibility
.Hidden
)]
216 public long MaximumKilobytes
{
217 get { return Impl.MaximumKilobytes; }
218 set { Impl.MaximumKilobytes = value; }
223 public void ModifyOverflowPolicy (OverflowAction action
, int retentionDays
)
225 Impl
.ModifyOverflowPolicy (action
, retentionDays
);
229 [ComVisibleAttribute (false)]
230 public void RegisterDisplayName (string resourceFile
, long resourceId
)
232 Impl
.RegisterDisplayName (resourceFile
, resourceId
);
236 public void BeginInit ()
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
,
260 EnableRaisingEvents
= false;
263 internal void Reset ()
265 bool enableRaisingEvents
= EnableRaisingEvents
;
267 EnableRaisingEvents
= enableRaisingEvents
;
270 public static void CreateEventSource (string source
, string logName
)
272 CreateEventSource (source
, logName
, ".");
276 [Obsolete ("use CreateEventSource(EventSourceCreationData) instead")]
278 public static void CreateEventSource (string source
,
282 CreateEventSource (new EventSourceCreationData (source
, logName
,
287 [MonoNotSupported ("remote machine is not supported")]
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"
322 if (logName
== null || logName
.Length
== 0)
323 throw new ArgumentException ("Log to delete was not specified.");
325 EventLogImpl impl
= CreateEventLogImpl (logName
, machineName
,
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)
340 throw new ArgumentException (string.Format (
341 CultureInfo
.InvariantCulture
, "Invalid value '{0}' for"
342 + " parameter 'machineName'.", machineName
));
344 throw new ArgumentException (string.Format (
345 CultureInfo
.InvariantCulture
, "Invalid value {0} for"
346 + " parameter machineName.", machineName
));
349 EventLogImpl impl
= CreateEventLogImpl (string.Empty
, machineName
,
351 impl
.DeleteEventSource (source
, machineName
);
354 protected override void Dispose (bool disposing
)
357 Impl
.Dispose (disposing
);
360 public void 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)
379 EventLogImpl impl
= CreateEventLogImpl (logName
, machineName
,
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)
401 throw new ArgumentException (string.Format (
402 CultureInfo
.InvariantCulture
, "Invalid value '{0}' for"
403 + " parameter 'MachineName'.", machineName
));
405 throw new ArgumentException (string.Format (
406 CultureInfo
.InvariantCulture
, "Invalid value {0} for"
407 + " parameter MachineName.", machineName
));
410 EventLogImpl impl
= CreateEventLogImpl (string.Empty
, machineName
,
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)
425 throw new ArgumentException (string.Format (
426 CultureInfo
.InvariantCulture
, "Invalid value '{0}' for"
427 + " parameter 'machineName'.", machineName
));
429 throw new ArgumentException (string.Format (
430 CultureInfo
.InvariantCulture
, "Invalid value {0} for"
431 + " parameter machineName.", machineName
));
434 EventLogImpl impl
= CreateEventLogImpl (string.Empty
, machineName
,
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
,
452 WriteEntry (message
, type
, eventID
, 0);
455 public void WriteEntry (string message
, EventLogEntryType type
,
459 WriteEntry (message
, type
, eventID
, category
, null);
462 public void WriteEntry (string message
, EventLogEntryType type
,
464 short category
, byte[] rawData
)
466 WriteEntry (new string [] { message }
, type
, eventID
,
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
,
497 using (EventLog eventLog
= new EventLog ()) {
498 eventLog
.Source
= source
;
499 eventLog
.WriteEntry (message
, type
, eventID
, category
, rawData
);
505 public void WriteEvent (EventInstance instance
, params object [] values
)
507 WriteEvent (instance
, null, values
);
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
];
522 replacementStrings
[i
] = string.Empty
;
524 replacementStrings
[i
] = values
[i
].ToString ();
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
);
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)
562 // if no log name has been set, then use source to determine name of log
563 logName
= LogNameFromSourceName (source
, machineName
);
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
);
579 return new Win32EventLog (eventLog
);
581 return new NullEventLog (eventLog
);
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
{
592 return (Environment
.OSVersion
.Platform
== PlatformID
.Win32NT
);
596 // IMPORTANT: also modify corresponding property in EventLogTest
597 private static string EventLogImplType
{
599 string implType
= Environment
.GetEnvironmentVariable (EVENTLOG_TYPE_VAR
);
600 if (implType
== null) {
601 if (Win32EventLogEnabled
)
603 implType
= NULL_IMPL
;
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
;
612 throw new NotSupportedException (string.Format (
613 CultureInfo
.InvariantCulture
, "Eventlog implementation"
614 + " '{0}' is not supported.", 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
));
631 ValidateEventID (instanceID
);
634 if (!SourceExists (Source
, MachineName
)) {
635 if (Log
== null || Log
.Length
== 0) {
638 CreateEventSource (Source
, Log
, MachineName
);
641 ValidateEventID (instanceID
);
643 } else if (logName
!= null && logName
.Length
!= 0) {
645 ValidateEventID (instanceID
);
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
));
659 ValidateEventID (instanceID
);
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
;