Updates referencesource to .NET 4.7
[mono.git] / mcs / class / referencesource / System.Web / Management / WebEvents.cs
1 //------------------------------------------------------------------------------
2 // <copyright file="WebEvents.cs" company="Microsoft">
3 //     Copyright (c) Microsoft Corporation.  All rights reserved.
4 // </copyright>
5 //------------------------------------------------------------------------------
6
7 namespace System.Web.Management {
8     using System;
9     using System.Collections;
10     using System.Collections.Generic;
11     using System.Configuration;
12     using System.Configuration.Provider;
13     using System.Diagnostics;
14     using System.Globalization;
15     using System.Runtime.Remoting.Messaging;
16     using System.Security;
17     using System.Security.Permissions;
18     using System.Security.Principal;
19     using System.Text;
20     using System.Threading;
21     using System.Web;
22     using System.Web.Caching;
23     using System.Web.Configuration;
24     using System.Web.Hosting;
25     using System.Web.Security;
26     using System.Web.UI;
27     using System.Web.Util;
28
29     using Debug = System.Web.Util.Debug;
30
31     // This enum matches the native one enum WebEventType (in webevent.h).
32     internal enum WebEventType : int {
33         WEBEVENT_BASE_EVENT = 0,
34         WEBEVENT_MANAGEMENT_EVENT,
35         WEBEVENT_APP_LIFETIME_EVENT,
36         WEBEVENT_REQUEST_EVENT,
37         WEBEVENT_HEARTBEAT_EVENT,
38         WEBEVENT_BASE_ERROR_EVENT,
39         WEBEVENT_REQUEST_ERROR_EVENT,
40         WEBEVENT_ERROR_EVENT,
41         WEBEVENT_AUDIT_EVENT,
42         WEBEVENT_SUCCESS_AUDIT_EVENT,
43         WEBEVENT_AUTHENTICATION_SUCCESS_AUDIT_EVENT,
44         WEBEVENT_FAILURE_AUDIT_EVENT,
45         WEBEVENT_AUTHENTICATION_FAILURE_AUDIT_EVENT,
46         WEBEVENT_VIEWSTATE_FAILURE_AUDIT_EVENT,
47     };
48
49     internal enum WebEventFieldType : int {
50         String = 0,
51         Int = 1,
52         Bool = 2,
53         Long = 3,
54         Date = 4,
55     }
56
57     // Used for marshalling over to IIS Trace
58     internal class WebEventFieldData {
59         string _name;
60         public string Name {
61             get {
62                 return _name;
63             }
64         }
65
66         string _data;
67         public string Data {
68             get {
69                 return _data;
70             }
71         }
72
73         WebEventFieldType _type;
74         public WebEventFieldType Type {
75             get {
76                 return _type;
77             }
78         }
79
80         public WebEventFieldData(string name, string data, WebEventFieldType type) {
81             _name = name;
82             _data = data;
83             _type = type;
84         }
85     }
86
87
88     // Interface for event provider
89     public abstract class WebEventProvider : ProviderBase {
90
91         // methods
92         public abstract void ProcessEvent(WebBaseEvent raisedEvent);
93         public abstract void Shutdown();
94         public abstract void Flush();
95
96         int _exceptionLogged;
97
98         internal void LogException(Exception e) {
99             // In order to not overflow the eventlog, we only log one exception per provider instance.
100             if (Interlocked.CompareExchange( ref _exceptionLogged, 1, 0) == 0) {
101                 // Log all errors in eventlog
102                 UnsafeNativeMethods.LogWebeventProviderFailure(
103                                         HttpRuntime.AppDomainAppVirtualPath,
104                                         Name,
105                                         e.ToString());
106             }
107         }
108     }
109
110     // Interface for custom event evaluator
111
112     public interface IWebEventCustomEvaluator {
113         bool CanFire(WebBaseEvent raisedEvent, RuleFiringRecord record);
114     }
115
116     ////////////////
117     // Events
118     ////////////////
119
120     public class WebBaseEvent {
121         DateTime        _eventTimeUtc;
122         int             _code;
123         int             _detailCode;
124         Object          _source;
125         string          _message;
126         long            _sequenceNumber;
127         long            _occurrenceNumber;
128         Guid            _id  = Guid.Empty;
129
130         static long                         s_globalSequenceNumber = 0;
131         static WebApplicationInformation    s_applicationInfo = new WebApplicationInformation();
132         const string                        WEBEVENT_RAISE_IN_PROGRESS = "_WEvtRIP";
133
134         // A array that cache the result of eventCode to SystemEventType mapping.
135         static readonly SystemEventType[,]  s_eventCodeToSystemEventTypeMappings = new SystemEventType[WebEventCodes.GetEventArrayDimensionSize(0),
136                                                                   WebEventCodes.GetEventArrayDimensionSize(1)];
137
138         // A array that store the # of occurrence per custom event code.
139         static readonly long[,]             s_eventCodeOccurrence = new long[WebEventCodes.GetEventArrayDimensionSize(0),
140                                                                   WebEventCodes.GetEventArrayDimensionSize(1)];
141
142         static Hashtable                    s_customEventCodeOccurrence = new Hashtable();
143         #pragma warning disable 0649
144         static ReadWriteSpinLock            s_lockCustomEventCodeOccurrence;
145         #pragma warning restore 0649
146
147         static WebBaseEvent() {
148
149             // Initialize the mappings.  We will fill up each entry on demand by calling
150             // SystemEventTypeFromEventCode().
151
152             for (int i = 0; i < s_eventCodeToSystemEventTypeMappings.GetLength(0); i++) {
153                 for (int j = 0; j < s_eventCodeToSystemEventTypeMappings.GetLength(1); j++) {
154                     s_eventCodeToSystemEventTypeMappings[i,j] = SystemEventType.Unknown;
155                 }
156             }
157
158             for (int i = 0; i < s_eventCodeOccurrence.GetLength(0); i++) {
159                 for (int j = 0; j < s_eventCodeOccurrence.GetLength(1); j++) {
160                     s_eventCodeOccurrence[i,j] = 0;
161                 }
162             }
163         }
164
165         void Init(string message, Object eventSource, int eventCode, int eventDetailCode) {
166             if (eventCode < 0) {
167                 throw new ArgumentOutOfRangeException("eventCode",
168                     SR.GetString(SR.Invalid_eventCode_error));
169             }
170
171             if (eventDetailCode < 0) {
172                 throw new ArgumentOutOfRangeException("eventDetailCode",
173                     SR.GetString(SR.Invalid_eventDetailCode_error));
174             }
175
176             _code = eventCode;
177             _detailCode = eventDetailCode;
178             _source = eventSource;
179             _eventTimeUtc = DateTime.UtcNow;
180             _message = message;
181
182             // Creation of _id is always delayed until it's needed.
183         }
184
185         // ctors
186         internal protected WebBaseEvent(string message, Object eventSource, int eventCode) {
187             Init(message, eventSource, eventCode, WebEventCodes.UndefinedEventDetailCode);
188         }
189
190         internal protected WebBaseEvent(string message, Object eventSource, int eventCode, int eventDetailCode) {
191             Init(message, eventSource, eventCode, eventDetailCode);
192         }
193
194         internal WebBaseEvent() {
195             // For creating dummy event.  See GetSystemDummyEvent()
196         }
197
198         internal bool IsSystemEvent {
199             get {
200                 return (_code < WebEventCodes.WebExtendedBase);
201             }
202         }
203
204         // Properties
205
206         public DateTime EventTime { get { return _eventTimeUtc.ToLocalTime(); } }
207
208         public DateTime EventTimeUtc { get { return _eventTimeUtc; } }
209
210         public String Message { get { return _message; } }
211
212         public Object EventSource { get { return _source; } }
213
214         public long EventSequence { get { return _sequenceNumber; } }
215
216         public long EventOccurrence { get { return _occurrenceNumber; } }
217
218         public int EventCode { get { return _code; } }
219
220         public int EventDetailCode { get { return _detailCode; } }
221
222         public Guid EventID {
223             get {
224                 if (_id == Guid.Empty) {
225                     lock(this) {
226                         if (_id == Guid.Empty) {
227                             _id = Guid.NewGuid();
228                         }
229                     }
230                 }
231
232                 return _id;
233             }
234         }
235
236         public static WebApplicationInformation ApplicationInformation {
237             get { return s_applicationInfo; }
238         }
239
240         virtual internal void FormatToString(WebEventFormatter formatter, bool includeAppInfo) {
241             formatter.AppendLine(WebBaseEvent.FormatResourceStringWithCache(SR.Webevent_event_code, EventCode.ToString(CultureInfo.InstalledUICulture)));
242             formatter.AppendLine(WebBaseEvent.FormatResourceStringWithCache(SR.Webevent_event_message, Message));
243             formatter.AppendLine(WebBaseEvent.FormatResourceStringWithCache(SR.Webevent_event_time, EventTime.ToString(CultureInfo.InstalledUICulture)));
244             formatter.AppendLine(WebBaseEvent.FormatResourceStringWithCache(SR.Webevent_event_time_Utc, EventTimeUtc.ToString(CultureInfo.InstalledUICulture)));
245             formatter.AppendLine(WebBaseEvent.FormatResourceStringWithCache(SR.Webevent_event_id, EventID.ToString("N", CultureInfo.InstalledUICulture)));
246             formatter.AppendLine(WebBaseEvent.FormatResourceStringWithCache(SR.Webevent_event_sequence, EventSequence.ToString(CultureInfo.InstalledUICulture)));
247             formatter.AppendLine(WebBaseEvent.FormatResourceStringWithCache(SR.Webevent_event_occurrence, EventOccurrence.ToString(CultureInfo.InstalledUICulture)));
248             formatter.AppendLine(WebBaseEvent.FormatResourceStringWithCache(SR.Webevent_event_detail_code, EventDetailCode.ToString(CultureInfo.InstalledUICulture)));
249
250             if (includeAppInfo) {
251                 formatter.AppendLine(String.Empty);
252                 formatter.AppendLine(WebBaseEvent.FormatResourceStringWithCache(SR.Webevent_event_application_information));
253                 formatter.IndentationLevel += 1;
254                 ApplicationInformation.FormatToString(formatter);
255                 formatter.IndentationLevel -= 1;
256             }
257         }
258
259
260         public override string ToString() {
261             return ToString(true, true);
262         }
263
264         public virtual string ToString(bool includeAppInfo, bool includeCustomEventDetails) {
265             WebEventFormatter   formatter = new WebEventFormatter();
266
267             FormatToString(formatter, includeAppInfo);
268
269             if (!IsSystemEvent && includeCustomEventDetails) {
270                 formatter.AppendLine(String.Empty);
271                 formatter.AppendLine(WebBaseEvent.FormatResourceStringWithCache(SR.Webevent_event_custom_event_details));
272                 formatter.IndentationLevel += 1;
273                 FormatCustomEventDetails(formatter);
274                 formatter.IndentationLevel -= 1;
275             }
276
277             return formatter.ToString();
278         }
279
280         virtual public void FormatCustomEventDetails(WebEventFormatter formatter) {
281         }
282
283         internal int InferEtwTraceVerbosity() {
284             WebEventType type = WebBaseEvent.WebEventTypeFromWebEvent(this);
285             switch (type) {
286                 case WebEventType.WEBEVENT_VIEWSTATE_FAILURE_AUDIT_EVENT:
287                 case WebEventType.WEBEVENT_BASE_ERROR_EVENT:
288                 case WebEventType.WEBEVENT_REQUEST_ERROR_EVENT:
289                 case WebEventType.WEBEVENT_FAILURE_AUDIT_EVENT:
290                 case WebEventType.WEBEVENT_AUTHENTICATION_FAILURE_AUDIT_EVENT:
291                 case WebEventType.WEBEVENT_ERROR_EVENT:
292                     return EtwTraceLevel.Warning;
293                 case WebEventType.WEBEVENT_AUDIT_EVENT:
294                 case WebEventType.WEBEVENT_SUCCESS_AUDIT_EVENT:
295                 case WebEventType.WEBEVENT_AUTHENTICATION_SUCCESS_AUDIT_EVENT:
296                     return EtwTraceLevel.Information;
297                 case WebEventType.WEBEVENT_BASE_EVENT:
298                 case WebEventType.WEBEVENT_MANAGEMENT_EVENT:
299                 case WebEventType.WEBEVENT_REQUEST_EVENT:
300                 default:
301                     return EtwTraceLevel.Verbose;
302             }
303         }
304
305         internal void DeconstructWebEvent(out int eventType, out int fieldCount, out string[] fieldNames, out int[] fieldTypes, out string[] fieldData) {
306             List<WebEventFieldData> fields = new List<WebEventFieldData>();
307
308             eventType = (int)WebBaseEvent.WebEventTypeFromWebEvent(this);
309             GenerateFieldsForMarshal(fields);
310             fieldCount = fields.Count;
311             fieldNames = new string[fieldCount];
312             fieldData = new string[fieldCount];
313             fieldTypes = new int[fieldCount];
314
315             for (int i = 0; i < fieldCount; ++i) {
316                 fieldNames[i] = fields[i].Name;
317                 fieldData[i] = fields[i].Data;
318                 fieldTypes[i] = (int)fields[i].Type;
319             }
320         }
321
322         internal virtual void GenerateFieldsForMarshal(List<WebEventFieldData> fields) {
323             fields.Add(new WebEventFieldData("EventTime", EventTimeUtc.ToString(), WebEventFieldType.String));
324             fields.Add(new WebEventFieldData("EventID", EventID.ToString(), WebEventFieldType.String));
325             fields.Add(new WebEventFieldData("EventMessage", Message, WebEventFieldType.String));
326             fields.Add(new WebEventFieldData("ApplicationDomain", WebBaseEvent.ApplicationInformation.ApplicationDomain, WebEventFieldType.String));
327             fields.Add(new WebEventFieldData("TrustLevel", WebBaseEvent.ApplicationInformation.TrustLevel, WebEventFieldType.String));
328             fields.Add(new WebEventFieldData("ApplicationVirtualPath", WebBaseEvent.ApplicationInformation.ApplicationVirtualPath, WebEventFieldType.String));
329             fields.Add(new WebEventFieldData("ApplicationPath", WebBaseEvent.ApplicationInformation.ApplicationPath, WebEventFieldType.String));
330             fields.Add(new WebEventFieldData("MachineName", WebBaseEvent.ApplicationInformation.MachineName, WebEventFieldType.String));
331             fields.Add(new WebEventFieldData("EventCode", EventCode.ToString(CultureInfo.InstalledUICulture), WebEventFieldType.Int));
332             fields.Add(new WebEventFieldData("EventDetailCode", EventDetailCode.ToString(CultureInfo.InstalledUICulture), WebEventFieldType.Int));
333             fields.Add(new WebEventFieldData("SequenceNumber", EventSequence.ToString(CultureInfo.InstalledUICulture), WebEventFieldType.Long));
334             fields.Add(new WebEventFieldData("Occurrence", EventOccurrence.ToString(CultureInfo.InstalledUICulture), WebEventFieldType.Long));
335         }
336
337         internal virtual void PreProcessEventInit() {
338         }
339
340         static void FindEventCode(Exception e, ref int eventCode, ref int eventDetailsCode, ref Exception eStack) {
341             eventDetailsCode = WebEventCodes.UndefinedEventDetailCode;
342
343             if (e is ConfigurationException) {
344                 eventCode = WebEventCodes.WebErrorConfigurationError;
345             }
346             else if (e is HttpRequestValidationException) {
347                 eventCode = WebEventCodes.RuntimeErrorValidationFailure;
348             }
349             else if (e is HttpCompileException) {
350                 eventCode = WebEventCodes.WebErrorCompilationError;
351             }
352             else if (e is SecurityException) {
353                 eventCode = WebEventCodes.AuditUnhandledSecurityException;
354             }
355             else if (e is UnauthorizedAccessException) {
356                 eventCode = WebEventCodes.AuditUnhandledAccessException;
357             }
358             else  if (e is HttpParseException) {
359                 eventCode = WebEventCodes.WebErrorParserError;
360             }
361             else if (e is HttpException && e.InnerException is ViewStateException) {
362                 ViewStateException vse = (ViewStateException)e.InnerException;
363                 eventCode = WebEventCodes.AuditInvalidViewStateFailure;
364                 if (vse._macValidationError) {
365                     eventDetailsCode = WebEventCodes.InvalidViewStateMac;
366                 }
367                 else {
368                     eventDetailsCode = WebEventCodes.InvalidViewState;
369                 }
370
371                 eStack = vse;
372             }
373             else if (e is HttpException && ((HttpException)e).WebEventCode != WebEventCodes.UndefinedEventCode) {
374                 eventCode = ((HttpException)e).WebEventCode;
375             }
376             else {
377                 // We don't know what it is.  Let's see if we can find it out by using the inner exception.
378
379                 if (e.InnerException != null) {
380                     // We will call FindEventCode recusively to find out if e.InnerException is the real one.
381
382                     if (eStack == null) {
383                         // Set eStack here.  If the recursive call ends up landing in
384                         // WebEventCodes.RuntimeErrorUnhandledException, we'll use the original
385                         // inner exception as our final result.
386                         eStack = e.InnerException;
387                     }
388
389                     FindEventCode(e.InnerException, ref eventCode, ref eventDetailsCode, ref eStack);
390                 }
391                 else {
392                     // It doesn't have an inner exception.  Just return the generic unhandled-exception
393                     eventCode = WebEventCodes.RuntimeErrorUnhandledException;
394                 }
395             }
396
397             if (eStack == null) {
398                 eStack = e;
399             }
400         }
401
402         static internal void RaiseRuntimeError(Exception e, object source) {
403             Debug.Trace("WebEventRaiseError", "Error Event is raised; type=" + e.GetType().Name);
404
405             if (!HealthMonitoringManager.Enabled) {
406                 return;
407             }
408
409             try {
410                 int         eventCode = WebEventCodes.UndefinedEventCode;
411                 int         eventDetailsCode = WebEventCodes.UndefinedEventDetailCode;
412                 HttpContext context = HttpContext.Current;
413                 Exception   eStack = null;
414
415                 if (context != null) {
416                     Page    page = context.Handler as Page;
417
418                     // Errors from Transacted pages can be wrapped by a
419                     // HttpException
420                     if (page != null &&
421                         page.IsTransacted &&
422                         e.GetType() == typeof(HttpException) &&
423                         e.InnerException != null) {
424
425                         e = e.InnerException;
426                     }
427                 }
428
429                 FindEventCode(e, ref eventCode, ref eventDetailsCode, ref eStack);
430                 WebBaseEvent.RaiseSystemEvent(source, eventCode, eventDetailsCode, eStack);
431             }
432             catch {
433             }
434         }
435
436         virtual internal protected void IncrementPerfCounters() {
437             PerfCounters.IncrementCounter(AppPerfCounter.EVENTS_TOTAL);
438         }
439
440         class CustomEventCodeOccurrence {
441             internal long    _occurrence;
442         }
443
444         internal void IncrementTotalCounters(int index0, int index1) {
445             _sequenceNumber = Interlocked.Increment(ref s_globalSequenceNumber);
446
447             if (index0 != -1) {
448                 _occurrenceNumber = Interlocked.Increment(ref s_eventCodeOccurrence[index0, index1]);
449             }
450             else {
451                 CustomEventCodeOccurrence ceco = (CustomEventCodeOccurrence)s_customEventCodeOccurrence[_code];
452
453                 if (ceco == null) {
454                     s_lockCustomEventCodeOccurrence.AcquireWriterLock();
455                     try {
456                         ceco = (CustomEventCodeOccurrence)s_customEventCodeOccurrence[_code];
457                         if (ceco == null) {
458                             ceco = new CustomEventCodeOccurrence();
459                             s_customEventCodeOccurrence[_code] = ceco;
460                         }
461                     }
462                     finally {
463                         s_lockCustomEventCodeOccurrence.ReleaseWriterLock();
464                     }
465                 }
466
467                 _occurrenceNumber = Interlocked.Increment(ref ceco._occurrence);
468             }
469         }
470
471         [AspNetHostingPermission(SecurityAction.Demand, Level=AspNetHostingPermissionLevel.Medium)]
472         virtual public void Raise() {
473             Raise(this);
474         }
475
476         // Internally raised events don't go thru this method.  They go directly to RaiseSystemEvent --> RaiseInternal
477         [AspNetHostingPermission(SecurityAction.Demand, Level=AspNetHostingPermissionLevel.Medium)]
478         static public void Raise(WebBaseEvent eventRaised) {
479             if (eventRaised.EventCode < WebEventCodes.WebExtendedBase) {
480                 throw new HttpException(SR.GetString(SR.System_eventCode_not_allowed,
481                         eventRaised.EventCode.ToString(CultureInfo.CurrentCulture),
482                         WebEventCodes.WebExtendedBase.ToString(CultureInfo.CurrentCulture)));
483             }
484
485             if (!HealthMonitoringManager.Enabled) {
486                 Debug.Trace(
487                     "WebEventRaiseDetails", "Can't fire event because we are disabled or we can't configure HealthMonManager");
488                 return;
489             }
490
491             RaiseInternal(eventRaised, null, -1, -1);
492         }
493
494         static internal void RaiseInternal(WebBaseEvent eventRaised, ArrayList firingRuleInfos, int index0, int index1) {
495             bool    preProcessEventInitCalled = false;
496             bool    inProgressSet = false;
497             object  o;
498             ProcessImpersonationContext ictx = null;
499             HttpContext context = HttpContext.Current;
500
501             Debug.Trace(
502                 "WebEventRaiseDetails", "Event is raised; event class = " + eventRaised.GetType().Name);
503
504             // Use CallContext to make sure we detect an infinite loop where a provider calls Raise().
505             o = CallContext.GetData(WEBEVENT_RAISE_IN_PROGRESS);
506             if (o != null && (bool)o) {
507                 Debug.Trace(
508                     "WebEventRaiseDetails", "An event is raised while we're raising an event.  Ignore it.");
509                 return;
510             }
511
512             eventRaised.IncrementPerfCounters();
513             eventRaised.IncrementTotalCounters(index0, index1);
514
515             // Find the list of rules that match this event
516             if (firingRuleInfos == null) {
517                 HealthMonitoringManager manager = HealthMonitoringManager.Manager();
518
519                 Debug.Assert(manager != null, "manager != null");
520
521                 firingRuleInfos = manager._sectionHelper.FindFiringRuleInfos(eventRaised.GetType(), eventRaised.EventCode);
522             }
523
524             if (firingRuleInfos.Count == 0) {
525                 return;
526             }
527
528             try {
529                 bool[]  matchingProviderArray = null;
530
531                 if (EtwTrace.IsTraceEnabled(EtwTraceLevel.Verbose, EtwTraceFlags.Infrastructure) && context != null)
532                     EtwTrace.Trace(EtwTraceType.ETW_TYPE_WEB_EVENT_RAISE_START,
533                                    context.WorkerRequest,
534                                    eventRaised.GetType().FullName,
535                                    eventRaised.EventCode.ToString(CultureInfo.InstalledUICulture),
536                                    eventRaised.EventDetailCode.ToString(CultureInfo.InstalledUICulture),
537                                    null);
538
539                 try {
540                     foreach (HealthMonitoringSectionHelper.FiringRuleInfo firingRuleInfo in firingRuleInfos) {
541                         HealthMonitoringSectionHelper.RuleInfo  ruleInfo = firingRuleInfo._ruleInfo;
542                         RuleFiringRecord record = ruleInfo._ruleFiringRecord;
543
544                         // Check if we should fire the event based on its throttling settings
545                         if (!record.CheckAndUpdate(eventRaised)) {
546                             Debug.Trace("WebEventRaiseDetails",
547                                     "Throttling settings not met; not fired");
548                             continue;
549                         }
550
551                         // It's valid for a rule to have no referenced provider
552                         if (ruleInfo._referencedProvider != null) {
553                             if (!preProcessEventInitCalled) {
554                                 // The event may need to do pre-ProcessEvent initialization
555                                 eventRaised.PreProcessEventInit();
556                                 preProcessEventInitCalled = true;
557                             }
558
559                             // For rule infos that share the same provider, the _indexOfFirstRuleInfoWithSameProvider field
560                             // is the index of the first ruleInfo among them.  We use that index in the boolean array
561                             // matchingProviderArray to remember if we've already fired that provider.
562                             // This is for the scenario where several rules are pointing to the same provider,
563                             // and even if >1 rule actually fire and pass all throttling check,
564                             // the provider is stilled fired only once.
565                             if (firingRuleInfo._indexOfFirstRuleInfoWithSameProvider != -1) {
566                                 if (matchingProviderArray == null) {
567                                     matchingProviderArray = new bool[firingRuleInfos.Count];
568                                 }
569
570                                 if (matchingProviderArray[firingRuleInfo._indexOfFirstRuleInfoWithSameProvider]) {
571                                     Debug.Trace("WebEventRaiseDetails",
572                                             "Rule with a matching provider already fired.");
573                                     continue;
574                                 }
575
576                                 matchingProviderArray[firingRuleInfo._indexOfFirstRuleInfoWithSameProvider] = true;
577                             }
578
579                             if (EtwTrace.IsTraceEnabled(EtwTraceLevel.Verbose, EtwTraceFlags.Infrastructure) && context != null)
580                                 EtwTrace.Trace(EtwTraceType.ETW_TYPE_WEB_EVENT_DELIVER_START,
581                                                context.WorkerRequest,
582                                                ruleInfo._ruleSettings.Provider,
583                                                ruleInfo._ruleSettings.Name,
584                                                ruleInfo._ruleSettings.EventName,
585                                                null);
586
587                             // In retail build, ignore errors from provider
588                             try {
589                                 if (ictx == null) {
590                                     ictx = new ProcessImpersonationContext();
591                                 }
592
593                                 if (!inProgressSet) {
594                                     CallContext.SetData(WEBEVENT_RAISE_IN_PROGRESS, true);
595                                     inProgressSet = true;
596                                 }
597
598                                 Debug.Trace("WebEventRaiseDetails", "Calling ProcessEvent under " + HttpApplication.GetCurrentWindowsIdentityWithAssert().Name);
599                                 ruleInfo._referencedProvider.ProcessEvent(eventRaised);
600                             }
601                             catch (Exception e) {
602                                 try {
603                                     ruleInfo._referencedProvider.LogException(e);
604                                 }
605                                 catch {
606                                     // ignore all errors
607                                 }
608                             }
609                             finally {
610                                 if (EtwTrace.IsTraceEnabled(EtwTraceLevel.Verbose, EtwTraceFlags.Infrastructure) && context != null)
611                                     EtwTrace.Trace(EtwTraceType.ETW_TYPE_WEB_EVENT_DELIVER_END,
612                                                    context.WorkerRequest);
613                             }
614                         }
615                     }
616                 }
617                 finally {
618                     // Resume client impersonation
619                     if (ictx != null) {
620                         ictx.Undo();
621                     }
622
623                     if (inProgressSet) {
624                         CallContext.FreeNamedDataSlot(WEBEVENT_RAISE_IN_PROGRESS);
625                     }
626
627                     if (EtwTrace.IsTraceEnabled(EtwTraceLevel.Verbose, EtwTraceFlags.Infrastructure) && context != null)
628                         EtwTrace.Trace(EtwTraceType.ETW_TYPE_WEB_EVENT_RAISE_END,
629                                        context.WorkerRequest);
630                 }
631             }
632             catch { throw; }    // Prevent Exception Filter Security Issue (ASURT 122835)
633         }
634
635         internal static void RaiseSystemEvent(string message, object source, int eventCode, int eventDetailCode, Exception exception) {
636             RaiseSystemEventInternal(message, source, eventCode, eventDetailCode, exception, null);
637         }
638
639         internal static void RaiseSystemEvent(object source, int eventCode) {
640             RaiseSystemEventInternal(null, source, eventCode, WebEventCodes.UndefinedEventDetailCode, null, null);
641         }
642
643         internal static void RaiseSystemEvent(object source, int eventCode, int eventDetailCode) {
644             RaiseSystemEventInternal(null, source, eventCode, eventDetailCode, null, null);
645         }
646
647         internal static void RaiseSystemEvent(object source, int eventCode, int eventDetailCode, Exception exception) {
648             RaiseSystemEventInternal(null, source, eventCode, eventDetailCode, exception, null);
649         }
650
651         internal static void RaiseSystemEvent(object source, int eventCode, string nameToAuthenticate) {
652             RaiseSystemEventInternal(null, source, eventCode, WebEventCodes.UndefinedEventDetailCode, null, nameToAuthenticate);
653         }
654
655         [PermissionSet(SecurityAction.Assert, Unrestricted = true)]
656         static void RaiseSystemEventInternal(string message, object source,
657                         int eventCode, int eventDetailCode, Exception exception,
658                         string nameToAuthenticate) {
659             HealthMonitoringManager manager;
660             ArrayList       firingRuleInfos;
661             SystemEventTypeInfo typeInfo;
662             SystemEventType     systemEventType;
663             int                 index0, index1;
664
665             Debug.Trace(
666                 "WebEventRaiseDetails", "RaiseSystemEventInternal called; eventCode=" + eventCode + "; eventDetailCode=" + eventDetailCode);
667
668             if (!HealthMonitoringManager.Enabled) {
669                 Debug.Trace(
670                     "WebEventRaiseDetails", "Can't fire event because we are disabled or we can't configure HealthMonManager");
671                 return;
672             }
673
674             WebEventCodes.GetEventArrayIndexsFromEventCode(eventCode, out index0, out index1);
675
676             GetSystemEventTypeInfo(eventCode, index0, index1, out typeInfo, out systemEventType);
677             if (typeInfo == null) {
678                 Debug.Assert(false, "Unexpected system event code = " + eventCode);
679                 return;
680             }
681
682             manager = HealthMonitoringManager.Manager();
683
684             // Figure out if there is any provider that subscribes to it
685             firingRuleInfos = manager._sectionHelper.FindFiringRuleInfos(typeInfo._type, eventCode);
686             if (firingRuleInfos.Count == 0) {
687                 // Even if we're not firing it, we still have to increment some global counters
688                 typeInfo._dummyEvent.IncrementPerfCounters();
689                 typeInfo._dummyEvent.IncrementTotalCounters(index0, index1);
690             }
691             else {
692                 // We will fire the event
693                 WebBaseEvent.RaiseInternal(
694                                 NewEventFromSystemEventType(false, systemEventType, message, source, eventCode, eventDetailCode,
695                                                         exception, nameToAuthenticate),
696                                 firingRuleInfos, index0, index1);
697             }
698         }
699
700         // An enum of all the types of web event we will fire
701         enum SystemEventType {
702             Unknown = -1,
703             WebApplicationLifetimeEvent,
704             WebHeartbeatEvent,
705             WebRequestEvent,
706             WebRequestErrorEvent,
707             WebErrorEvent,
708             WebAuthenticationSuccessAuditEvent,
709             WebSuccessAuditEvent,
710             WebAuthenticationFailureAuditEvent,
711             WebFailureAuditEvent,
712             WebViewStateFailureAuditEvent,
713             Last
714         };
715
716         class SystemEventTypeInfo {
717             internal WebBaseEvent       _dummyEvent;    // For calling IncrementPerfCounters. See RaiseSystemEventInternal for details.
718             internal Type               _type;
719
720             internal SystemEventTypeInfo(WebBaseEvent dummyEvent) {
721                 _dummyEvent = dummyEvent;
722                 _type = dummyEvent.GetType();
723             }
724         };
725
726         // An array to cache the event type info for each system event type
727         static SystemEventTypeInfo[]    s_systemEventTypeInfos = new SystemEventTypeInfo[(int)SystemEventType.Last];
728
729         static void GetSystemEventTypeInfo(int eventCode, int index0, int index1,
730                         out SystemEventTypeInfo info, out SystemEventType systemEventType) {
731
732             // Figure out what SystemEventType this eventCode maps to.
733             // For each eventCode, we store the result in a cache.
734             systemEventType = s_eventCodeToSystemEventTypeMappings[index0, index1];
735             if (systemEventType == SystemEventType.Unknown) {
736                 systemEventType = SystemEventTypeFromEventCode(eventCode);
737                 s_eventCodeToSystemEventTypeMappings[index0, index1] = systemEventType;
738             }
739
740             // Based on the systemEventType, we read the SystemEventTypeInfo.  For each
741             // event type, we also cache the info
742             info = s_systemEventTypeInfos[(int)systemEventType];
743             if (info != null) {
744                 return;
745             }
746
747             info = new SystemEventTypeInfo(CreateDummySystemEvent(systemEventType));
748             s_systemEventTypeInfos[(int)systemEventType] = info;
749         }
750
751         static SystemEventType SystemEventTypeFromEventCode(int eventCode) {
752             if (eventCode >= WebEventCodes.ApplicationCodeBase &&
753                 eventCode <= WebEventCodes.ApplicationCodeBaseLast) {
754                 switch(eventCode) {
755                     case WebEventCodes.ApplicationStart:
756                     case WebEventCodes.ApplicationShutdown:
757                     case WebEventCodes.ApplicationCompilationStart:
758                     case WebEventCodes.ApplicationCompilationEnd:
759                         return SystemEventType.WebApplicationLifetimeEvent;
760
761                     case WebEventCodes.ApplicationHeartbeat:
762                         return SystemEventType.WebHeartbeatEvent;
763                 }
764             }
765
766             if (eventCode >= WebEventCodes.RequestCodeBase &&
767                 eventCode <= WebEventCodes.RequestCodeBaseLast) {
768                 switch(eventCode) {
769
770                     case WebEventCodes.RequestTransactionComplete:
771                     case WebEventCodes.RequestTransactionAbort:
772                         return SystemEventType.WebRequestEvent;
773                 }
774             }
775
776             if (eventCode >= WebEventCodes.ErrorCodeBase &&
777                 eventCode <= WebEventCodes.ErrorCodeBaseLast) {
778                 switch(eventCode) {
779                     case WebEventCodes.RuntimeErrorRequestAbort:
780                     case WebEventCodes.RuntimeErrorViewStateFailure:
781                     case WebEventCodes.RuntimeErrorValidationFailure:
782                     case WebEventCodes.RuntimeErrorPostTooLarge:
783                     case WebEventCodes.RuntimeErrorUnhandledException:
784                     case WebEventCodes.RuntimeErrorWebResourceFailure:
785                         return SystemEventType.WebRequestErrorEvent;
786
787                     case WebEventCodes.WebErrorParserError:
788                     case WebEventCodes.WebErrorCompilationError:
789                     case WebEventCodes.WebErrorConfigurationError:
790                     case WebEventCodes.WebErrorOtherError:
791                     case WebEventCodes.WebErrorPropertyDeserializationError:
792                     case WebEventCodes.WebErrorObjectStateFormatterDeserializationError:
793                         return SystemEventType.WebErrorEvent;
794                 }
795             }
796
797             if (eventCode >= WebEventCodes.AuditCodeBase &&
798                 eventCode <= WebEventCodes.AuditCodeBaseLast) {
799                 switch(eventCode) {
800                     case WebEventCodes.AuditFormsAuthenticationSuccess:
801                     case WebEventCodes.AuditMembershipAuthenticationSuccess:
802                         return SystemEventType.WebAuthenticationSuccessAuditEvent;
803
804                     case WebEventCodes.AuditUrlAuthorizationSuccess:
805                     case WebEventCodes.AuditFileAuthorizationSuccess:
806                         return SystemEventType.WebSuccessAuditEvent;
807
808                     case WebEventCodes.AuditFormsAuthenticationFailure:
809                     case WebEventCodes.AuditMembershipAuthenticationFailure:
810                         return SystemEventType.WebAuthenticationFailureAuditEvent;
811
812                     case WebEventCodes.AuditUrlAuthorizationFailure:
813                     case WebEventCodes.AuditFileAuthorizationFailure:
814                     case WebEventCodes.AuditUnhandledSecurityException:
815                     case WebEventCodes.AuditUnhandledAccessException:
816                         return SystemEventType.WebFailureAuditEvent;
817
818                     case WebEventCodes.AuditInvalidViewStateFailure:
819                         return SystemEventType.WebViewStateFailureAuditEvent;
820                 }
821             }
822
823             if (eventCode >= WebEventCodes.MiscCodeBase &&
824                 eventCode <= WebEventCodes.MiscCodeBaseLast) {
825                 switch(eventCode) {
826                     case WebEventCodes.WebEventProviderInformation:
827                         Debug.Assert(false, "WebEventProviderInformation shouldn't be used to Raise an event");
828                         return SystemEventType.Unknown;
829                 }
830             }
831
832             return SystemEventType.Unknown;
833         }
834
835         static WebBaseEvent CreateDummySystemEvent(SystemEventType systemEventType) {
836             return NewEventFromSystemEventType(true, systemEventType, null,
837                         null, 0, 0, null, null);
838         }
839
840         static WebBaseEvent NewEventFromSystemEventType(bool createDummy, SystemEventType systemEventType, string message,
841                         object source,int eventCode, int eventDetailCode, Exception exception,
842                         string nameToAuthenticate) {
843             // If createDummy == true, it means we're only creating a dummy event for the sake of using
844             // it to call IncrementPerfCounters()
845
846             if (!createDummy && message == null) {
847                 message = WebEventCodes.MessageFromEventCode(eventCode, eventDetailCode);
848             }
849
850             // Code view note for the future:
851             // If the number of systemEventType increases tremendoulsy, we may need to
852             // avoid using switch, and change to use a "factory" to create new event.
853
854             switch(systemEventType) {
855                 case SystemEventType.WebApplicationLifetimeEvent:
856                     return createDummy ? new WebApplicationLifetimeEvent() : new WebApplicationLifetimeEvent(message, source, eventCode, eventDetailCode);
857
858                 case SystemEventType.WebHeartbeatEvent:
859                     return createDummy ? new WebHeartbeatEvent() : new WebHeartbeatEvent(message, eventCode);
860
861                 case SystemEventType.WebRequestEvent:
862                     return createDummy ? new WebRequestEvent() : new WebRequestEvent(message, source, eventCode, eventDetailCode);
863
864                 case SystemEventType. WebRequestErrorEvent:
865                     return createDummy ? new WebRequestErrorEvent() : new WebRequestErrorEvent(message, source, eventCode, eventDetailCode, exception);
866
867                 case SystemEventType.WebErrorEvent:
868                     return createDummy ? new WebErrorEvent() : new WebErrorEvent(message, source, eventCode, eventDetailCode, exception);
869
870                 case SystemEventType.WebAuthenticationSuccessAuditEvent:
871                     return createDummy ? new WebAuthenticationSuccessAuditEvent() : new WebAuthenticationSuccessAuditEvent(message, source, eventCode, eventDetailCode, nameToAuthenticate);
872
873                 case SystemEventType.WebSuccessAuditEvent:
874                     return createDummy ? new WebSuccessAuditEvent() : new WebSuccessAuditEvent(message, source, eventCode, eventDetailCode);
875
876                 case SystemEventType.WebAuthenticationFailureAuditEvent:
877                     return createDummy ? new WebAuthenticationFailureAuditEvent() : new WebAuthenticationFailureAuditEvent(message, source, eventCode, eventDetailCode, nameToAuthenticate);
878
879                 case SystemEventType.WebFailureAuditEvent:
880                     return createDummy ? new WebFailureAuditEvent() : new WebFailureAuditEvent(message, source, eventCode, eventDetailCode);
881
882                 case SystemEventType.WebViewStateFailureAuditEvent:
883                     return createDummy ? new WebViewStateFailureAuditEvent() : new WebViewStateFailureAuditEvent(message, source, eventCode, eventDetailCode, (System.Web.UI.ViewStateException)exception);
884
885                 default:
886                     Debug.Assert(false, "Unexpected event type = " + systemEventType);
887                     return null;
888             }
889         }
890
891         static string CreateWebEventResourceCacheKey(String key) {
892             return CacheInternal.PrefixWebEventResource + key;
893         }
894
895         internal static String FormatResourceStringWithCache(String key) {
896             // HealthMonitoring, in some scenarios, can call into the cache hundreds of 
897             // times during shutdown, after the cache has been disposed.  To improve 
898             // shutdown performance, skip the cache when it is disposed.
899             if (HealthMonitoringManager.IsCacheDisposed) {
900                 return SR.Resources.GetString(key, CultureInfo.InstalledUICulture);
901             }
902
903             CacheStoreProvider cacheInternal = HttpRuntime.Cache.InternalCache;
904             string s;
905
906             string cacheKey = CreateWebEventResourceCacheKey(key);
907
908             s = (string) cacheInternal.Get(cacheKey);
909             if (s != null) {
910                 return s;
911             }
912
913             s = SR.Resources.GetString(key, CultureInfo.InstalledUICulture);
914             if (s != null) {
915                 cacheInternal.Insert(cacheKey, s, null);
916             }
917
918             return s;
919         }
920
921         internal static String FormatResourceStringWithCache(String key, String arg0) {
922             string fmt = FormatResourceStringWithCache(key);
923             return(fmt != null) ? String.Format(fmt, arg0) : null;
924         }
925
926         internal static WebEventType WebEventTypeFromWebEvent(WebBaseEvent eventRaised) {
927             // Note:
928             // eventRaised can belong to one of the following classes, or can inherit from one of them.
929             // In order to figure out precisely the WebEventType closest to the type of eventRaised,
930             // we will start our comparison from the leaf nodes in the class hierarchy and work our
931             // way up.
932
933             // Webevent class hierarchy (with the info contained in each class):
934
935             /*
936
937             - WebBaseEvent (basic)
938                 - WebManagementEvent (+ WebProcessInformation)
939                     - WebHeartbeatEvent (+ WebProcessStatistics)
940                     - WebApplicationLifetimeEvent
941                     - WebRequestEvent (+ WebRequestInformation)
942                     - WebBaseErrorEvent (+ Exception)
943                         - WebRequestErrorEvent (+ WebRequestInformation + WebThreadInformation)
944                         - WebErrorEvent (+ WebRequestInformation + WebThreadInformation)
945                     - WebAuditEvent (+ WebRequestInformation)
946                         - WebSuccessAuditEvent
947                             - WebAuthenticationSuccessAuditEvent (+ NameToAuthenticate)
948                         - WebFailureAuditEvent
949                             - WebAuthenticationFailureAuditEvent (+ NameToAuthenticate)
950                             - WebViewStateFailureAuditEvent (+ ViewStateException)
951             */
952
953             // Hierarchy level 5
954
955             if (eventRaised is WebAuthenticationSuccessAuditEvent) {
956                 return WebEventType.WEBEVENT_AUTHENTICATION_SUCCESS_AUDIT_EVENT;
957             }
958
959             if (eventRaised is WebAuthenticationFailureAuditEvent) {
960                 return WebEventType.WEBEVENT_AUTHENTICATION_FAILURE_AUDIT_EVENT;
961             }
962
963             if (eventRaised is WebViewStateFailureAuditEvent) {
964                 return WebEventType.WEBEVENT_VIEWSTATE_FAILURE_AUDIT_EVENT;
965             }
966
967             // Hierarchy level 4
968
969             if (eventRaised is WebRequestErrorEvent) {
970                 return WebEventType.WEBEVENT_REQUEST_ERROR_EVENT;
971             }
972
973             if (eventRaised is WebErrorEvent) {
974                 return WebEventType.WEBEVENT_ERROR_EVENT;
975             }
976
977             if (eventRaised is WebSuccessAuditEvent) {
978                 return WebEventType.WEBEVENT_SUCCESS_AUDIT_EVENT;
979             }
980
981             if (eventRaised is WebFailureAuditEvent) {
982                 return WebEventType.WEBEVENT_FAILURE_AUDIT_EVENT;
983             }
984
985             // Hierarchy level 3
986
987             if (eventRaised is WebHeartbeatEvent) {
988                 return WebEventType.WEBEVENT_HEARTBEAT_EVENT;
989             }
990
991             if (eventRaised is WebApplicationLifetimeEvent) {
992                 return WebEventType.WEBEVENT_APP_LIFETIME_EVENT;
993             }
994
995             if (eventRaised is WebRequestEvent) {
996                 return WebEventType.WEBEVENT_REQUEST_EVENT;
997             }
998
999             if (eventRaised is WebBaseErrorEvent) {
1000                 return WebEventType.WEBEVENT_BASE_ERROR_EVENT;
1001             }
1002
1003             if (eventRaised is WebAuditEvent) {
1004                 return WebEventType.WEBEVENT_AUDIT_EVENT;
1005             }
1006
1007             // Hierarchy level 2
1008
1009             if (eventRaised is WebManagementEvent) {
1010                 return WebEventType.WEBEVENT_MANAGEMENT_EVENT;
1011             }
1012
1013             // Hierarchy level 1
1014
1015             return WebEventType.WEBEVENT_BASE_EVENT;
1016         }
1017
1018         static internal void RaisePropertyDeserializationWebErrorEvent(SettingsProperty property, object source, Exception exception) {
1019             if (HttpContext.Current == null) {
1020                 return;
1021             }
1022
1023             WebBaseEvent.RaiseSystemEvent(
1024                 SR.GetString(SR.Webevent_msg_Property_Deserialization,
1025                             property.Name, property.SerializeAs.ToString(), property.PropertyType.AssemblyQualifiedName ),
1026                 source,
1027                 WebEventCodes.WebErrorPropertyDeserializationError,
1028                 WebEventCodes.UndefinedEventDetailCode,
1029                 exception);
1030         }
1031     }
1032
1033     public class WebEventFormatter {
1034         int             _level;
1035         StringBuilder   _sb;
1036         int             _tabSize;
1037
1038         void AddTab() {
1039             int level = _level;
1040
1041             while (level > 0) {
1042                 _sb.Append(' ', _tabSize);
1043                 level--;
1044             }
1045         }
1046
1047         internal WebEventFormatter() {
1048             _level = 0;
1049             _sb = new StringBuilder();
1050             _tabSize = 4;
1051         }
1052
1053         public void AppendLine(string s) {
1054             AddTab();
1055             _sb.Append(s);
1056             _sb.Append('\n');
1057         }
1058
1059         new public string ToString() {
1060             return _sb.ToString();
1061         }
1062
1063         public int IndentationLevel {
1064             get { return _level; }
1065             set { _level = Math.Max(value, 0); }
1066         }
1067
1068         public int TabSize {
1069             get { return _tabSize; }
1070             set { _tabSize = Math.Max(value, 0); }
1071         }
1072     }
1073
1074     // This class is a base class for all events that require application and process information.
1075     //
1076     // WebManagementEvent is the base class for all our webevent classes (except for WebBaseEvent)
1077     // Please note that we allow customer to inherit from our webevent classes to make it easier to
1078     // create custom webevent that contains useful information.
1079     // However, WebManagementEvent (and other child events) contains sensitive information (e.g. process id, process account name)
1080     // that cannot be obtained unless in full-trust.
1081     //
1082     // In non-fulltrust app, we still want code inside system.web.dll to create these webevents
1083     // even if there is user code on the stack (we either assert or call unmanaged code to get those info).
1084     // So to protect these full-trust information from non-fulltrust app, we InheritanceDemand FullTrust
1085     // if the customer wants to inherit from WebManagementEvent.
1086     //
1087     // For details, see VSWhidbey 256684.
1088     //
1089     [PermissionSet(SecurityAction.InheritanceDemand, Unrestricted = true)]
1090     public class WebManagementEvent : WebBaseEvent {
1091         static WebProcessInformation        s_processInfo = new WebProcessInformation();
1092
1093         internal protected WebManagementEvent(string message, object eventSource, int eventCode)
1094             :base(message, eventSource, eventCode) {
1095         }
1096
1097         internal protected WebManagementEvent(string message, object eventSource, int eventCode, int eventDetailCode)
1098             :base(message, eventSource, eventCode, eventDetailCode) {
1099         }
1100
1101         internal WebManagementEvent() {
1102             // For creating dummy event.  See GetSystemDummyEvent()
1103         }
1104
1105         // properties
1106         public WebProcessInformation ProcessInformation {
1107             get { return s_processInfo; }
1108         }
1109
1110         internal override void GenerateFieldsForMarshal(List<WebEventFieldData> fields) {
1111             base.GenerateFieldsForMarshal(fields);
1112             fields.Add(new WebEventFieldData("AccountName", ProcessInformation.AccountName, WebEventFieldType.String));
1113             fields.Add(new WebEventFieldData("ProcessName", ProcessInformation.ProcessName, WebEventFieldType.String));
1114             fields.Add(new WebEventFieldData("ProcessID", ProcessInformation.ProcessID.ToString(CultureInfo.InstalledUICulture), WebEventFieldType.Int));
1115         }
1116
1117         override internal void FormatToString(WebEventFormatter formatter, bool includeAppInfo) {
1118             base.FormatToString(formatter, includeAppInfo);
1119
1120             formatter.AppendLine(String.Empty);
1121             formatter.AppendLine(WebBaseEvent.FormatResourceStringWithCache(SR.Webevent_event_process_information));
1122
1123             formatter.IndentationLevel += 1;
1124             ProcessInformation.FormatToString(formatter);
1125             formatter.IndentationLevel -= 1;
1126         }
1127
1128     }
1129
1130
1131     // This event is raised at periodic intervals (default 30 seconds) and provides information
1132     // relative to the state of the running appdomin.
1133
1134     public class WebHeartbeatEvent : WebManagementEvent {
1135         static WebProcessStatistics    s_procStats = new WebProcessStatistics();
1136
1137         internal protected WebHeartbeatEvent(string message, int eventCode)
1138             :base(message, null, eventCode)
1139         {
1140         }
1141
1142         internal WebHeartbeatEvent() {
1143             // For creating dummy event.  See GetSystemDummyEvent()
1144         }
1145
1146
1147         public WebProcessStatistics ProcessStatistics {get {return s_procStats;}}
1148
1149         override internal void FormatToString(WebEventFormatter formatter, bool includeAppInfo) {
1150             base.FormatToString(formatter, includeAppInfo);
1151
1152             formatter.AppendLine(String.Empty);
1153             formatter.AppendLine(WebBaseEvent.FormatResourceStringWithCache(SR.Webevent_event_process_statistics));
1154
1155             formatter.IndentationLevel += 1;
1156             s_procStats.FormatToString(formatter);
1157             formatter.IndentationLevel -= 1;
1158         }
1159     }
1160
1161
1162     // This event represents a notable event in the lifetime of an application (app domain)
1163     // including startup and shutdown events.  When an app domain is terminated, the reason
1164     // will be expressed in the Message field (e.g. compilation threshold exceed, Shutdown
1165     // called explicitly, etc.).
1166
1167     public class WebApplicationLifetimeEvent : WebManagementEvent {
1168
1169         internal protected WebApplicationLifetimeEvent(string message, object eventSource, int eventCode)
1170             :base(message, eventSource, eventCode)
1171         {
1172         }
1173
1174
1175         internal protected WebApplicationLifetimeEvent(string message, object eventSource, int eventCode, int eventDetailCode)
1176             :base(message, eventSource, eventCode, eventDetailCode)
1177         {
1178         }
1179
1180         internal WebApplicationLifetimeEvent() {
1181             // For creating dummy event.  See GetSystemDummyEvent()
1182         }
1183
1184         static internal int DetailCodeFromShutdownReason(ApplicationShutdownReason reason) {
1185             switch (reason) {
1186             case ApplicationShutdownReason.HostingEnvironment:
1187                 return WebEventCodes.ApplicationShutdownHostingEnvironment;
1188
1189             case ApplicationShutdownReason.ChangeInGlobalAsax:
1190                 return WebEventCodes.ApplicationShutdownChangeInGlobalAsax;
1191
1192             case ApplicationShutdownReason.ConfigurationChange:
1193                 return WebEventCodes.ApplicationShutdownConfigurationChange;
1194
1195             case ApplicationShutdownReason.UnloadAppDomainCalled:
1196                 return WebEventCodes.ApplicationShutdownUnloadAppDomainCalled;
1197
1198             case ApplicationShutdownReason.ChangeInSecurityPolicyFile:
1199                 return WebEventCodes.ApplicationShutdownChangeInSecurityPolicyFile;
1200
1201             case ApplicationShutdownReason.BinDirChangeOrDirectoryRename:
1202                 return WebEventCodes.ApplicationShutdownBinDirChangeOrDirectoryRename;
1203
1204             case ApplicationShutdownReason.BrowsersDirChangeOrDirectoryRename:
1205                 return WebEventCodes.ApplicationShutdownBrowsersDirChangeOrDirectoryRename;
1206
1207             case ApplicationShutdownReason.CodeDirChangeOrDirectoryRename:
1208                 return WebEventCodes.ApplicationShutdownCodeDirChangeOrDirectoryRename;
1209
1210             case ApplicationShutdownReason.ResourcesDirChangeOrDirectoryRename:
1211                 return WebEventCodes.ApplicationShutdownResourcesDirChangeOrDirectoryRename;
1212
1213             case ApplicationShutdownReason.IdleTimeout:
1214                 return WebEventCodes.ApplicationShutdownIdleTimeout;
1215
1216             case ApplicationShutdownReason.PhysicalApplicationPathChanged:
1217                 return WebEventCodes.ApplicationShutdownPhysicalApplicationPathChanged;
1218
1219             case ApplicationShutdownReason.HttpRuntimeClose:
1220                 return WebEventCodes.ApplicationShutdownHttpRuntimeClose;
1221
1222             case ApplicationShutdownReason.InitializationError:
1223                 return WebEventCodes.ApplicationShutdownInitializationError;
1224
1225             case ApplicationShutdownReason.MaxRecompilationsReached:
1226                 return WebEventCodes.ApplicationShutdownMaxRecompilationsReached;
1227
1228             case ApplicationShutdownReason.BuildManagerChange:
1229                 return WebEventCodes.ApplicationShutdownBuildManagerChange;
1230
1231             default:
1232                 return WebEventCodes.ApplicationShutdownUnknown;
1233             }
1234         }
1235
1236         override internal protected void IncrementPerfCounters() {
1237             base.IncrementPerfCounters();
1238             PerfCounters.IncrementCounter(AppPerfCounter.EVENTS_APP);
1239         }
1240     }
1241
1242     // This class serves as a base for non-error events that provide 
1243     public class WebRequestEvent : WebManagementEvent {
1244         WebRequestInformation   _requestInfo;
1245
1246         override internal void PreProcessEventInit() {
1247             base.PreProcessEventInit();
1248             InitRequestInformation();
1249         }
1250
1251         internal protected WebRequestEvent(string message, object eventSource, int eventCode)
1252         :base(message, eventSource, eventCode)
1253         {
1254         }
1255
1256         internal protected WebRequestEvent(string message, object eventSource, int eventCode, int eventDetailCode)
1257             :base(message, eventSource, eventCode, eventDetailCode)
1258         {
1259         }
1260
1261         internal WebRequestEvent() {
1262             // For creating dummy event.  See GetSystemDummyEvent()
1263         }
1264
1265         void InitRequestInformation() {
1266             if (_requestInfo == null) {
1267                 _requestInfo = new WebRequestInformation();
1268             }
1269         }
1270
1271         public WebRequestInformation RequestInformation {
1272             get {
1273                 InitRequestInformation();
1274                 return _requestInfo;
1275             }
1276         }
1277
1278         internal override void GenerateFieldsForMarshal(List<WebEventFieldData> fields) {
1279             base.GenerateFieldsForMarshal(fields);
1280             fields.Add(new WebEventFieldData("RequestUrl", RequestInformation.RequestUrl, WebEventFieldType.String));
1281             fields.Add(new WebEventFieldData("RequestPath", RequestInformation.RequestPath, WebEventFieldType.String));
1282             fields.Add(new WebEventFieldData("UserHostAddress", RequestInformation.UserHostAddress, WebEventFieldType.String));
1283             fields.Add(new WebEventFieldData("UserName", RequestInformation.Principal.Identity.Name, WebEventFieldType.String));
1284             fields.Add(new WebEventFieldData("UserAuthenticated", RequestInformation.Principal.Identity.IsAuthenticated.ToString(), WebEventFieldType.Bool));
1285             fields.Add(new WebEventFieldData("UserAuthenticationType", RequestInformation.Principal.Identity.AuthenticationType, WebEventFieldType.String));
1286             fields.Add(new WebEventFieldData("RequestThreadAccountName", RequestInformation.ThreadAccountName, WebEventFieldType.String));
1287         }
1288
1289         override internal void FormatToString(WebEventFormatter formatter, bool includeAppInfo) {
1290             base.FormatToString(formatter, includeAppInfo);
1291
1292             formatter.AppendLine(String.Empty);
1293             formatter.AppendLine(WebBaseEvent.FormatResourceStringWithCache(SR.Webevent_event_request_information));
1294
1295             formatter.IndentationLevel += 1;
1296             RequestInformation.FormatToString(formatter);
1297             formatter.IndentationLevel -= 1;
1298         }
1299
1300         override internal protected void IncrementPerfCounters() {
1301             base.IncrementPerfCounters();
1302             PerfCounters.IncrementCounter(AppPerfCounter.EVENTS_WEB_REQ);
1303         }
1304     }
1305
1306     // This is the base class for all error events.
1307     public class WebBaseErrorEvent : WebManagementEvent {
1308         Exception               _exception;
1309
1310         void Init(Exception e) {
1311             _exception = e;
1312         }
1313
1314         internal protected WebBaseErrorEvent(string message, object eventSource, int eventCode, Exception e)
1315             :base(message, eventSource, eventCode)
1316         {
1317             Init(e);
1318         }
1319
1320         internal protected WebBaseErrorEvent(string message, object eventSource, int eventCode, int eventDetailCode, Exception e)
1321             :base(message, eventSource, eventCode, eventDetailCode)
1322         {
1323             Init(e);
1324         }
1325
1326         internal WebBaseErrorEvent() {
1327             // For creating dummy event.  See GetSystemDummyEvent()
1328         }
1329
1330         public Exception ErrorException {
1331             get { return _exception; }
1332         }
1333
1334         override internal void FormatToString(WebEventFormatter formatter, bool includeAppInfo) {
1335             base.FormatToString(formatter, includeAppInfo);
1336
1337             if (_exception == null) {
1338                 return;
1339             }
1340
1341             Exception   ex = _exception;
1342
1343             // Please note we arbitrary pick a level limit per bug VSWhidbey 143859
1344             for (int level = 0;
1345                   ex != null && level <= 2;
1346                   ex = ex.InnerException, level++)  {
1347
1348                 formatter.AppendLine(String.Empty);
1349
1350                 if (level == 0) {
1351                     formatter.AppendLine(WebBaseEvent.FormatResourceStringWithCache(SR.Webevent_event_exception_information));
1352                 }
1353                 else {
1354                     formatter.AppendLine(WebBaseEvent.FormatResourceStringWithCache(SR.Webevent_event_inner_exception_information, level.ToString(CultureInfo.InstalledUICulture)));
1355                 }
1356
1357                 formatter.IndentationLevel += 1;
1358                 formatter.AppendLine(WebBaseEvent.FormatResourceStringWithCache(SR.Webevent_event_exception_type, ex.GetType().ToString()));
1359                 formatter.AppendLine(WebBaseEvent.FormatResourceStringWithCache(SR.Webevent_event_exception_message, ex.Message));
1360                 formatter.IndentationLevel -= 1;
1361             }
1362         }
1363
1364         internal override void GenerateFieldsForMarshal(List<WebEventFieldData> fields) {
1365             base.GenerateFieldsForMarshal(fields);
1366             fields.Add(new WebEventFieldData("ExceptionType", ErrorException.GetType().ToString(), WebEventFieldType.String));
1367             fields.Add(new WebEventFieldData("ExceptionMessage", ErrorException.Message, WebEventFieldType.String));
1368         }
1369
1370         override internal protected void IncrementPerfCounters() {
1371             base.IncrementPerfCounters();
1372             PerfCounters.IncrementCounter(AppPerfCounter.EVENTS_ERROR);
1373             PerfCounters.IncrementGlobalCounter(GlobalPerfCounter.GLOBAL_EVENTS_ERROR);
1374         }
1375     }
1376
1377     // This class contains information about systemic errors, e.g. things related to
1378     // configuration or application code (parser errors, compilation errors).
1379
1380     public class WebErrorEvent : WebBaseErrorEvent {
1381         WebRequestInformation   _requestInfo;
1382         WebThreadInformation    _threadInfo;
1383
1384         void Init(Exception e) {
1385         }
1386
1387         override internal void PreProcessEventInit() {
1388             base.PreProcessEventInit();
1389             InitRequestInformation();
1390             InitThreadInformation();
1391         }
1392
1393         internal protected WebErrorEvent(string message, object eventSource, int eventCode, Exception exception)
1394             :base(message, eventSource, eventCode, exception)
1395         {
1396             Init(exception);
1397         }
1398
1399         internal protected WebErrorEvent(string message, object eventSource, int eventCode, int eventDetailCode, Exception exception)
1400             :base(message, eventSource, eventCode, eventDetailCode, exception)
1401         {
1402             Init(exception);
1403         }
1404
1405         internal WebErrorEvent() {
1406             // For creating dummy event.  See GetSystemDummyEvent()
1407         }
1408
1409         void InitRequestInformation() {
1410             if (_requestInfo == null) {
1411                 _requestInfo = new WebRequestInformation();
1412             }
1413         }
1414
1415         public WebRequestInformation RequestInformation {
1416             get {
1417                 InitRequestInformation();
1418                 return _requestInfo;
1419             }
1420         }
1421
1422         void InitThreadInformation() {
1423             if (_threadInfo == null) {
1424                 _threadInfo = new WebThreadInformation(base.ErrorException);
1425             }
1426         }
1427
1428         public WebThreadInformation ThreadInformation {
1429             get {
1430                 InitThreadInformation();
1431                 return _threadInfo;
1432             }
1433         }
1434
1435         override internal void FormatToString(WebEventFormatter formatter, bool includeAppInfo) {
1436             base.FormatToString(formatter, includeAppInfo);
1437
1438             formatter.AppendLine(String.Empty);
1439             formatter.AppendLine(WebBaseEvent.FormatResourceStringWithCache(SR.Webevent_event_request_information));
1440
1441             formatter.IndentationLevel += 1;
1442             RequestInformation.FormatToString(formatter);
1443             formatter.IndentationLevel -= 1;
1444
1445             formatter.AppendLine(String.Empty);
1446             formatter.AppendLine(WebBaseEvent.FormatResourceStringWithCache(SR.Webevent_event_thread_information));
1447
1448             formatter.IndentationLevel += 1;
1449             ThreadInformation.FormatToString(formatter);
1450             formatter.IndentationLevel -= 1;
1451         }
1452
1453         internal override void GenerateFieldsForMarshal(List<WebEventFieldData> fields) {
1454             base.GenerateFieldsForMarshal(fields);
1455             fields.Add(new WebEventFieldData("RequestUrl", RequestInformation.RequestUrl, WebEventFieldType.String));
1456             fields.Add(new WebEventFieldData("RequestPath", RequestInformation.RequestPath, WebEventFieldType.String));
1457             fields.Add(new WebEventFieldData("UserHostAddress", RequestInformation.UserHostAddress, WebEventFieldType.String));
1458             fields.Add(new WebEventFieldData("UserName", RequestInformation.Principal.Identity.Name, WebEventFieldType.String));
1459             fields.Add(new WebEventFieldData("UserAuthenticated", RequestInformation.Principal.Identity.IsAuthenticated.ToString(), WebEventFieldType.Bool));
1460             fields.Add(new WebEventFieldData("UserAuthenticationType", RequestInformation.Principal.Identity.AuthenticationType, WebEventFieldType.String));
1461             fields.Add(new WebEventFieldData("RequestThreadAccountName", RequestInformation.ThreadAccountName, WebEventFieldType.String));
1462             fields.Add(new WebEventFieldData("ThreadID", ThreadInformation.ThreadID.ToString(CultureInfo.InstalledUICulture), WebEventFieldType.Int));
1463             fields.Add(new WebEventFieldData("ThreadAccountName", ThreadInformation.ThreadAccountName, WebEventFieldType.String));
1464             fields.Add(new WebEventFieldData("StackTrace", ThreadInformation.StackTrace, WebEventFieldType.String));
1465             fields.Add(new WebEventFieldData("IsImpersonating", ThreadInformation.IsImpersonating.ToString(), WebEventFieldType.Bool));
1466         }
1467
1468         override internal protected void IncrementPerfCounters() {
1469             base.IncrementPerfCounters();
1470             PerfCounters.IncrementCounter(AppPerfCounter.EVENTS_HTTP_INFRA_ERROR);
1471             PerfCounters.IncrementGlobalCounter(GlobalPerfCounter.GLOBAL_EVENTS_HTTP_INFRA_ERROR);
1472         }
1473     }
1474
1475     // This class provides information about errors that occur while servicing a request.
1476     // This include unhandled exceptions, viewstate errors, input validation errors, etc.
1477     public class WebRequestErrorEvent : WebBaseErrorEvent {
1478         WebRequestInformation   _requestInfo;
1479         WebThreadInformation    _threadInfo;
1480
1481         void Init(Exception e) {
1482         }
1483
1484         override internal void PreProcessEventInit() {
1485             base.PreProcessEventInit();
1486             InitRequestInformation();
1487             InitThreadInformation();
1488         }
1489
1490         internal protected WebRequestErrorEvent(string message, object eventSource, int eventCode, Exception exception)
1491             :base(message, eventSource, eventCode, exception)
1492         {
1493             Init(exception);
1494         }
1495
1496         internal protected WebRequestErrorEvent(string message, object eventSource, int eventCode, int eventDetailCode, Exception exception)
1497             :base(message, eventSource, eventCode, eventDetailCode, exception)
1498         {
1499             Init(exception);
1500         }
1501
1502         internal WebRequestErrorEvent() {
1503             // For creating dummy event.  See GetSystemDummyEvent()
1504         }
1505
1506         // properties
1507
1508         void InitRequestInformation() {
1509             if (_requestInfo == null) {
1510                 _requestInfo = new WebRequestInformation();
1511             }
1512         }
1513
1514         public WebRequestInformation RequestInformation {
1515             get {
1516                 InitRequestInformation();
1517                 return _requestInfo;
1518             }
1519         }
1520
1521         void InitThreadInformation() {
1522             if (_threadInfo == null) {
1523                 _threadInfo = new WebThreadInformation(base.ErrorException);
1524             }
1525         }
1526
1527         public WebThreadInformation ThreadInformation {
1528             get {
1529                 InitThreadInformation();
1530                 return _threadInfo;
1531             }
1532         }
1533
1534         override internal void FormatToString(WebEventFormatter formatter, bool includeAppInfo) {
1535             base.FormatToString(formatter, includeAppInfo);
1536
1537             formatter.AppendLine(String.Empty);
1538             formatter.AppendLine(WebBaseEvent.FormatResourceStringWithCache(SR.Webevent_event_request_information));
1539
1540             formatter.IndentationLevel += 1;
1541             RequestInformation.FormatToString(formatter);
1542             formatter.IndentationLevel -= 1;
1543
1544             formatter.AppendLine(String.Empty);
1545             formatter.AppendLine(WebBaseEvent.FormatResourceStringWithCache(SR.Webevent_event_thread_information));
1546
1547             formatter.IndentationLevel += 1;
1548             ThreadInformation.FormatToString(formatter);
1549             formatter.IndentationLevel -= 1;
1550         }
1551
1552         internal override void GenerateFieldsForMarshal(List<WebEventFieldData> fields) {
1553             base.GenerateFieldsForMarshal(fields);
1554             fields.Add(new WebEventFieldData("RequestUrl", RequestInformation.RequestUrl, WebEventFieldType.String));
1555             fields.Add(new WebEventFieldData("RequestPath", RequestInformation.RequestPath, WebEventFieldType.String));
1556             fields.Add(new WebEventFieldData("UserHostAddress", RequestInformation.UserHostAddress, WebEventFieldType.String));
1557             fields.Add(new WebEventFieldData("UserName", RequestInformation.Principal.Identity.Name, WebEventFieldType.String));
1558             fields.Add(new WebEventFieldData("UserAuthenticated", RequestInformation.Principal.Identity.IsAuthenticated.ToString(), WebEventFieldType.Bool));
1559             fields.Add(new WebEventFieldData("UserAuthenticationType", RequestInformation.Principal.Identity.AuthenticationType, WebEventFieldType.String));
1560             fields.Add(new WebEventFieldData("RequestThreadAccountName", RequestInformation.ThreadAccountName, WebEventFieldType.String));
1561             fields.Add(new WebEventFieldData("ThreadID", ThreadInformation.ThreadID.ToString(CultureInfo.InstalledUICulture), WebEventFieldType.Int));
1562             fields.Add(new WebEventFieldData("ThreadAccountName", ThreadInformation.ThreadAccountName, WebEventFieldType.String));
1563             fields.Add(new WebEventFieldData("StackTrace", ThreadInformation.StackTrace, WebEventFieldType.String));
1564             fields.Add(new WebEventFieldData("IsImpersonating", ThreadInformation.IsImpersonating.ToString(), WebEventFieldType.Bool));
1565         }
1566
1567         override internal protected void IncrementPerfCounters() {
1568             base.IncrementPerfCounters();
1569             PerfCounters.IncrementCounter(AppPerfCounter.EVENTS_HTTP_REQ_ERROR);
1570             PerfCounters.IncrementGlobalCounter(GlobalPerfCounter.GLOBAL_EVENTS_HTTP_REQ_ERROR);
1571         }
1572     }
1573
1574
1575     // The base class for all audit events.
1576
1577     public class WebAuditEvent : WebManagementEvent {
1578         WebRequestInformation   _requestInfo;
1579
1580         override internal void PreProcessEventInit() {
1581             base.PreProcessEventInit();
1582             InitRequestInformation();
1583         }
1584
1585         internal protected WebAuditEvent(string message, object eventSource, int eventCode)
1586             :base(message, eventSource, eventCode)
1587         {
1588         }
1589
1590         internal protected WebAuditEvent(string message, object eventSource, int eventCode, int eventDetailCode)
1591             :base(message, eventSource, eventCode, eventDetailCode)
1592         {
1593         }
1594
1595         internal WebAuditEvent() {
1596             // For creating dummy event.  See GetSystemDummyEvent()
1597         }
1598
1599         void InitRequestInformation() {
1600             if (_requestInfo == null) {
1601                 _requestInfo = new WebRequestInformation();
1602             }
1603         }
1604
1605         public WebRequestInformation RequestInformation {
1606             get {
1607                 InitRequestInformation();
1608                 return _requestInfo;
1609             }
1610         }
1611
1612         internal override void GenerateFieldsForMarshal(List<WebEventFieldData> fields) {
1613             base.GenerateFieldsForMarshal(fields);
1614             fields.Add(new WebEventFieldData("RequestUrl", RequestInformation.RequestUrl, WebEventFieldType.String));
1615             fields.Add(new WebEventFieldData("RequestPath", RequestInformation.RequestPath, WebEventFieldType.String));
1616             fields.Add(new WebEventFieldData("UserHostAddress", RequestInformation.UserHostAddress, WebEventFieldType.String));
1617             fields.Add(new WebEventFieldData("UserName", RequestInformation.Principal.Identity.Name, WebEventFieldType.String));
1618             fields.Add(new WebEventFieldData("UserAuthenticated", RequestInformation.Principal.Identity.IsAuthenticated.ToString(), WebEventFieldType.Bool));
1619             fields.Add(new WebEventFieldData("UserAuthenticationType", RequestInformation.Principal.Identity.AuthenticationType, WebEventFieldType.String));
1620             fields.Add(new WebEventFieldData("RequestThreadAccountName", RequestInformation.ThreadAccountName, WebEventFieldType.String));
1621         }
1622
1623         override internal void FormatToString(WebEventFormatter formatter, bool includeAppInfo) {
1624             base.FormatToString(formatter, includeAppInfo);
1625
1626             formatter.AppendLine(String.Empty);
1627             formatter.AppendLine(WebBaseEvent.FormatResourceStringWithCache(SR.Webevent_event_request_information));
1628
1629             formatter.IndentationLevel += 1;
1630             RequestInformation.FormatToString(formatter);
1631             formatter.IndentationLevel -= 1;
1632         }
1633     }
1634
1635
1636     // This class provides information about all failure audits.  In most cases,
1637     // applications will only want to enable failure audits.
1638
1639     public class WebFailureAuditEvent : WebAuditEvent {
1640         internal protected WebFailureAuditEvent(string message, object eventSource, int eventCode)
1641             :base(message, eventSource, eventCode)
1642         {
1643         }
1644
1645         internal protected WebFailureAuditEvent(string message, object eventSource, int eventCode, int eventDetailCode)
1646             :base(message, eventSource, eventCode, eventDetailCode)
1647         {
1648         }
1649
1650         internal WebFailureAuditEvent() {
1651             // For creating dummy event.  See GetSystemDummyEvent()
1652         }
1653
1654         override internal protected void IncrementPerfCounters() {
1655             base.IncrementPerfCounters();
1656             PerfCounters.IncrementCounter(AppPerfCounter.AUDIT_FAIL);
1657             PerfCounters.IncrementGlobalCounter(GlobalPerfCounter.GLOBAL_AUDIT_FAIL);
1658         }
1659     }
1660
1661     public class WebAuthenticationFailureAuditEvent : WebFailureAuditEvent {
1662
1663         string  _nameToAuthenticate;
1664
1665         void Init(string name) {
1666             _nameToAuthenticate = name;
1667         }
1668
1669         internal protected WebAuthenticationFailureAuditEvent(string message, object eventSource, int eventCode, string nameToAuthenticate)
1670             :base(message, eventSource, eventCode)
1671         {
1672             Init(nameToAuthenticate);
1673         }
1674
1675
1676         internal protected WebAuthenticationFailureAuditEvent(string message, object eventSource, int eventCode, int eventDetailCode, string nameToAuthenticate)
1677             :base(message, eventSource, eventCode, eventDetailCode)
1678         {
1679             Init(nameToAuthenticate);
1680         }
1681
1682         internal WebAuthenticationFailureAuditEvent() {
1683             // For creating dummy event.  See GetSystemDummyEvent()
1684         }
1685
1686         public string NameToAuthenticate {
1687             get { return _nameToAuthenticate; }
1688         }
1689
1690         internal override void GenerateFieldsForMarshal(List<WebEventFieldData> fields) {
1691             base.GenerateFieldsForMarshal(fields);
1692             fields.Add(new WebEventFieldData("NameToAuthenticate", NameToAuthenticate, WebEventFieldType.String));
1693         }
1694
1695         override internal void FormatToString(WebEventFormatter formatter, bool includeAppInfo) {
1696             base.FormatToString(formatter, includeAppInfo);
1697
1698             formatter.AppendLine(String.Empty);
1699             formatter.AppendLine(WebBaseEvent.FormatResourceStringWithCache(SR.Webevent_event_name_to_authenticate, _nameToAuthenticate));
1700
1701         }
1702     }
1703
1704     public class WebViewStateFailureAuditEvent : WebFailureAuditEvent {
1705
1706         ViewStateException  _viewStateException;
1707
1708         internal protected WebViewStateFailureAuditEvent(string message, object eventSource, int eventCode, ViewStateException viewStateException)
1709             :base(message, eventSource, eventCode)
1710         {
1711             _viewStateException = viewStateException;
1712         }
1713
1714
1715         internal protected WebViewStateFailureAuditEvent(string message, object eventSource, int eventCode, int eventDetailCode, ViewStateException viewStateException)
1716             :base(message, eventSource, eventCode, eventDetailCode)
1717         {
1718             _viewStateException = viewStateException;
1719         }
1720
1721         internal WebViewStateFailureAuditEvent() {
1722             // For creating dummy event.  See GetSystemDummyEvent()
1723         }
1724
1725         public ViewStateException ViewStateException {
1726             get { return _viewStateException; }
1727         }
1728
1729         internal override void GenerateFieldsForMarshal(List<WebEventFieldData> fields) {
1730             base.GenerateFieldsForMarshal(fields);
1731             fields.Add(new WebEventFieldData("ViewStateExceptionMessage", ViewStateException.Message, WebEventFieldType.String));
1732             fields.Add(new WebEventFieldData("RemoteAddress", ViewStateException.RemoteAddress, WebEventFieldType.String));
1733             fields.Add(new WebEventFieldData("RemotePort", ViewStateException.RemotePort, WebEventFieldType.String));
1734             fields.Add(new WebEventFieldData("UserAgent", ViewStateException.UserAgent, WebEventFieldType.String));
1735             fields.Add(new WebEventFieldData("PersistedState", ViewStateException.PersistedState, WebEventFieldType.String));
1736             fields.Add(new WebEventFieldData("Path", ViewStateException.Path, WebEventFieldType.String));
1737             fields.Add(new WebEventFieldData("Referer", ViewStateException.Referer, WebEventFieldType.String));
1738         }
1739
1740         override internal void FormatToString(WebEventFormatter formatter, bool includeAppInfo) {
1741             base.FormatToString(formatter, includeAppInfo);
1742
1743             formatter.AppendLine(String.Empty);
1744             formatter.AppendLine(WebBaseEvent.FormatResourceStringWithCache(SR.Webevent_event_ViewStateException_information));
1745             formatter.IndentationLevel += 1;
1746             formatter.AppendLine(WebBaseEvent.FormatResourceStringWithCache(SR.Webevent_event_exception_message, _viewStateException.Message));
1747
1748             formatter.IndentationLevel -= 1;
1749         }
1750
1751     }
1752
1753
1754     // This class provides information about all success audits.  In most cases,
1755     // applications will only want to enable failure audits.
1756
1757     public class WebSuccessAuditEvent : WebAuditEvent {
1758         internal protected WebSuccessAuditEvent(string message, object eventSource, int eventCode)
1759             :base(message, eventSource, eventCode)
1760         {
1761         }
1762
1763         internal protected WebSuccessAuditEvent(string message, object eventSource, int eventCode, int eventDetailCode)
1764             :base(message, eventSource, eventCode, eventDetailCode)
1765         {
1766         }
1767
1768         internal WebSuccessAuditEvent() {
1769             // For creating dummy event.  See GetSystemDummyEvent()
1770         }
1771
1772         override internal protected void IncrementPerfCounters() {
1773             base.IncrementPerfCounters();
1774             PerfCounters.IncrementCounter(AppPerfCounter.AUDIT_SUCCESS);
1775             PerfCounters.IncrementGlobalCounter(GlobalPerfCounter.GLOBAL_AUDIT_SUCCESS);
1776         }
1777     }
1778
1779     public class WebAuthenticationSuccessAuditEvent : WebSuccessAuditEvent {
1780
1781         string  _nameToAuthenticate;
1782
1783         void Init(string name) {
1784             _nameToAuthenticate = name;
1785         }
1786
1787         internal protected WebAuthenticationSuccessAuditEvent(string message, object eventSource, int eventCode, string nameToAuthenticate)
1788             :base(message, eventSource, eventCode)
1789         {
1790             Init(nameToAuthenticate);
1791         }
1792
1793         internal protected WebAuthenticationSuccessAuditEvent(string message, object eventSource, int eventCode, int eventDetailCode, string nameToAuthenticate)
1794             :base(message, eventSource, eventCode, eventDetailCode)
1795         {
1796             Init(nameToAuthenticate);
1797         }
1798
1799         internal WebAuthenticationSuccessAuditEvent() {
1800             // For creating dummy event.  See GetSystemDummyEvent()
1801         }
1802
1803         public string NameToAuthenticate {
1804             get { return _nameToAuthenticate; }
1805         }
1806
1807         internal override void GenerateFieldsForMarshal(List<WebEventFieldData> fields) {
1808             base.GenerateFieldsForMarshal(fields);
1809             fields.Add(new WebEventFieldData("NameToAuthenticate", NameToAuthenticate, WebEventFieldType.String));
1810         }
1811
1812         override internal void FormatToString(WebEventFormatter formatter, bool includeAppInfo) {
1813             base.FormatToString(formatter, includeAppInfo);
1814
1815             formatter.AppendLine(String.Empty);
1816             formatter.AppendLine(WebBaseEvent.FormatResourceStringWithCache(SR.Webevent_event_name_to_authenticate, _nameToAuthenticate));
1817         }
1818     }
1819
1820
1821     ////////////////
1822     // Information
1823     ////////////////
1824     
1825     public sealed class WebProcessInformation {
1826         // The information is per worker process instance.
1827
1828         int     _processId;
1829         string  _processName;
1830         string  _accountName;
1831
1832         internal WebProcessInformation() {
1833             // Can't use Process.ProcessName because it requires the running
1834             // account to be part of the Performance Monitor Users group.
1835             StringBuilder buf = new StringBuilder(256);
1836             if (UnsafeNativeMethods.GetModuleFileName(IntPtr.Zero, buf, 256) == 0) {
1837                 _processName = String.Empty;
1838             }
1839             else {
1840                 int lastIndex;
1841
1842                 _processName = buf.ToString();
1843                 lastIndex = _processName.LastIndexOf('\\');
1844                 if (lastIndex != -1) {
1845                     _processName = _processName.Substring(lastIndex + 1);
1846                 }
1847             }
1848
1849             _processId = SafeNativeMethods.GetCurrentProcessId() ;
1850             _accountName = HttpRuntime.WpUserId;
1851         }
1852
1853         public int ProcessID { get { return _processId; } }
1854
1855         public string ProcessName { get { return _processName; } }
1856
1857         public string AccountName { get { return (_accountName != null ? _accountName : String.Empty); } }
1858
1859         public void FormatToString(WebEventFormatter formatter) {
1860             formatter.AppendLine(WebBaseEvent.FormatResourceStringWithCache(SR.Webevent_event_process_id, ProcessID.ToString(CultureInfo.InstalledUICulture)));
1861             formatter.AppendLine(WebBaseEvent.FormatResourceStringWithCache(SR.Webevent_event_process_name, ProcessName));
1862             formatter.AppendLine(WebBaseEvent.FormatResourceStringWithCache(SR.Webevent_event_account_name, AccountName));
1863         }
1864     }
1865
1866     public sealed class WebApplicationInformation {
1867         // The information is per appdomain.
1868
1869         string  _appDomain;
1870         string  _trustLevel;
1871         string  _appUrl;
1872         string  _appPath;
1873         string  _machineName;
1874
1875         internal WebApplicationInformation() {
1876             _appDomain = Thread.GetDomain().FriendlyName;
1877             _trustLevel = HttpRuntime.TrustLevel;
1878             _appUrl = HttpRuntime.AppDomainAppVirtualPath;
1879
1880             try {
1881                 // We will get an exception if it's a non-ASP.NET app.
1882                 _appPath = HttpRuntime.AppDomainAppPathInternal;
1883             }
1884             catch {
1885                 _appPath = null;
1886             }
1887 #if FEATURE_PAL // FEATURE_PAL does not fully implement Environment.MachineName
1888             _machineName = "dummymachinename";
1889 #else // FEATURE_PAL
1890             _machineName = GetMachineNameWithAssert();
1891 #endif // FEATURE_PAL
1892         }
1893
1894         public string ApplicationDomain { get { return _appDomain; } }
1895
1896         public string TrustLevel { get { return _trustLevel; } }
1897
1898         public string ApplicationVirtualPath { get { return _appUrl; } }
1899
1900         public string ApplicationPath { get { return _appPath; } }
1901
1902         public string MachineName { get { return _machineName; } }
1903
1904         public void FormatToString(WebEventFormatter formatter) {
1905             formatter.AppendLine(WebBaseEvent.FormatResourceStringWithCache(SR.Webevent_event_application_domain, ApplicationDomain));
1906             formatter.AppendLine(WebBaseEvent.FormatResourceStringWithCache(SR.Webevent_event_trust_level, TrustLevel));
1907             formatter.AppendLine(WebBaseEvent.FormatResourceStringWithCache(SR.Webevent_event_application_virtual_path, ApplicationVirtualPath));
1908             formatter.AppendLine(WebBaseEvent.FormatResourceStringWithCache(SR.Webevent_event_application_path, ApplicationPath));
1909             formatter.AppendLine(WebBaseEvent.FormatResourceStringWithCache(SR.Webevent_event_machine_name, MachineName));
1910         }
1911
1912         [PermissionSet(SecurityAction.Assert, Unrestricted = true)]
1913         private string GetMachineNameWithAssert() {
1914             return Environment.MachineName;
1915         }
1916
1917         public override string ToString() {
1918             WebEventFormatter formatter = new WebEventFormatter();
1919
1920             FormatToString(formatter);
1921             return formatter.ToString();
1922         }
1923     }
1924
1925     public sealed class WebRequestInformation {
1926
1927         string      _requestUrl;
1928         string      _requestPath;
1929         IPrincipal  _iprincipal;
1930         string      _userHostAddress = null;
1931         string      _accountName;
1932
1933         internal    WebRequestInformation() {
1934             // Need to Assert() in order to get request information regardless of trust level. See VSWhidbey 416733
1935             InternalSecurityPermissions.ControlPrincipal.Assert();
1936
1937             HttpContext context = HttpContext.Current;
1938             HttpRequest request = null;
1939
1940             if (context != null) {
1941                 bool hideRequestResponseOriginal = context.HideRequestResponse;
1942                 context.HideRequestResponse = false;
1943                 request = context.Request;
1944                 context.HideRequestResponse = hideRequestResponseOriginal;
1945
1946                 _iprincipal = context.User;
1947
1948                 // Dev11 #80084 - DTS Bug
1949                 // In integrated pipeline, we are very aggressive about disposing
1950                 // WindowsIdentity's.  If this WebRequestInformation is being used
1951                 // post-request (eg, while formatting data for an email provider
1952                 // that is reporting batched events), then the User.Identity is
1953                 // likely to be disposed.  So lets create a clone that will stick
1954                 // around.  This condition should vaguely match that found in
1955                 // HttpContext.DisposePrincipal().
1956                 if (_iprincipal is WindowsPrincipal
1957                     && _iprincipal != WindowsAuthenticationModule.AnonymousPrincipal
1958                     && (context.WorkerRequest is IIS7WorkerRequest)) {
1959                     WindowsIdentity winIdentity = _iprincipal.Identity as WindowsIdentity;
1960                     if (winIdentity != null) {
1961                         _iprincipal = new WindowsPrincipal(new WindowsIdentity(winIdentity.Token, winIdentity.AuthenticationType));
1962                     }
1963                 }
1964             } else {
1965                 _iprincipal = null;
1966             }
1967
1968             if (request == null) {
1969                 _requestUrl = String.Empty;
1970                 _requestPath = String.Empty;
1971                 _userHostAddress = String.Empty;
1972             }
1973             else {
1974                 _requestUrl = request.UrlInternal;
1975                 _requestPath = request.Path;
1976                 _userHostAddress = request.UserHostAddress;
1977             }
1978             _accountName = WindowsIdentity.GetCurrent().Name;
1979         }
1980
1981         // The information is per request.
1982
1983         public string RequestUrl {get {return _requestUrl;}}
1984
1985         public string RequestPath {get {return _requestPath;}}
1986
1987         public IPrincipal Principal {get {return _iprincipal;}}
1988
1989         public string UserHostAddress { get { return _userHostAddress;} }
1990
1991         public string ThreadAccountName {get {return _accountName;}}
1992
1993         public void FormatToString(WebEventFormatter formatter) {
1994             string      user;
1995             string      authType;
1996             bool        authed;
1997
1998             if (Principal == null) {
1999                 user = String.Empty;
2000                 authType = String.Empty;
2001                 authed = false;
2002             }
2003             else {
2004                 IIdentity    id = Principal.Identity;
2005
2006                 user = id.Name;
2007                 authed = id.IsAuthenticated;
2008                 authType = id.AuthenticationType;
2009             }
2010
2011             formatter.AppendLine(WebBaseEvent.FormatResourceStringWithCache(SR.Webevent_event_request_url, RequestUrl));
2012             formatter.AppendLine(WebBaseEvent.FormatResourceStringWithCache(SR.Webevent_event_request_path, RequestPath));
2013             formatter.AppendLine(WebBaseEvent.FormatResourceStringWithCache(SR.Webevent_event_user_host_address, UserHostAddress));
2014             formatter.AppendLine(WebBaseEvent.FormatResourceStringWithCache(SR.Webevent_event_user, user));
2015
2016             if (authed) {
2017                 formatter.AppendLine(WebBaseEvent.FormatResourceStringWithCache(SR.Webevent_event_is_authenticated));
2018             }
2019             else {
2020                 formatter.AppendLine(WebBaseEvent.FormatResourceStringWithCache(SR.Webevent_event_is_not_authenticated));
2021             }
2022             formatter.AppendLine(WebBaseEvent.FormatResourceStringWithCache(SR.Webevent_event_authentication_type, authType));
2023             formatter.AppendLine(WebBaseEvent.FormatResourceStringWithCache(SR.Webevent_event_thread_account_name, ThreadAccountName));
2024
2025         }
2026     }
2027
2028
2029     // Note that even all the information contained in WebProcessStatistics is obtained from static variables,
2030     // but we still don't want this class to be static.
2031     //
2032     // Currently, WebProcessStatistics can be obtained only thru WebHeartbeatEvent, which in turn can be
2033     // created only by Full-trust app thru class inheritance. (System.Web.dll will also internally create it
2034     // and the object will be available to our provider.)  Thus, WebProcessStatistics is available only
2035     // to Full-trust app or provider.
2036     //
2037     // But if we make WebProcessStatistics static, then all its public methods have to be static, and
2038     // they'll be fully available to all users.  No good.
2039     public class WebProcessStatistics {
2040         static DateTime     s_startTime = DateTime.MinValue;
2041         static DateTime     s_lastUpdated = DateTime.MinValue;
2042         static int          s_threadCount;
2043         static long         s_workingSet;
2044         static long         s_peakWorkingSet;
2045         static long         s_managedHeapSize;
2046         static int          s_appdomainCount;
2047         static int          s_requestsExecuting;
2048         static int          s_requestsQueued;
2049         static int          s_requestsRejected;
2050         static bool         s_getCurrentProcFailed = false;
2051         static object       s_lockObject = new object();
2052
2053         static TimeSpan      TS_ONE_SECOND = new TimeSpan(0, 0, 1);
2054
2055         static WebProcessStatistics() {
2056             try {
2057 #if !FEATURE_PAL // FEATURE_PAL does not support this.  Make into a noop.
2058                 s_startTime = Process.GetCurrentProcess().StartTime;
2059 #endif // !FEATURE_PAL
2060             }
2061             catch {
2062                 s_getCurrentProcFailed = true;
2063             }
2064         }
2065
2066         void Update() {
2067             DateTime    now = DateTime.Now;
2068
2069             if (now - s_lastUpdated < TS_ONE_SECOND) {
2070                 return;
2071             }
2072
2073             lock (s_lockObject) {
2074                 if (now - s_lastUpdated < TS_ONE_SECOND) {
2075                     return;
2076                 }
2077
2078                 if (!s_getCurrentProcFailed) {
2079                     Process process = Process.GetCurrentProcess();
2080 #if !FEATURE_PAL // FEATURE_PAL does not support these Process properties
2081
2082                     s_threadCount = process.Threads.Count;
2083                     s_workingSet = (long)process.WorkingSet64;
2084                     s_peakWorkingSet = (long)process.PeakWorkingSet64;
2085 #else
2086                     throw new NotImplementedException ("ROTORTODO");
2087 #endif
2088                 }
2089
2090                 s_managedHeapSize = GC.GetTotalMemory(false);
2091
2092                 s_appdomainCount = HostingEnvironment.AppDomainsCount;
2093
2094                 s_requestsExecuting = PerfCounters.GetGlobalCounter(GlobalPerfCounter.REQUESTS_CURRENT);
2095                 s_requestsQueued = PerfCounters.GetGlobalCounter(GlobalPerfCounter.REQUESTS_QUEUED);
2096                 s_requestsRejected = PerfCounters.GetGlobalCounter(GlobalPerfCounter.REQUESTS_REJECTED);
2097
2098                 s_lastUpdated = now;
2099             }
2100         }
2101
2102
2103         public DateTime ProcessStartTime {get {Update(); return s_startTime;}}
2104
2105         public int ThreadCount {get {Update(); return s_threadCount;}}
2106
2107         public long WorkingSet {get {Update(); return s_workingSet;}}
2108
2109         public long PeakWorkingSet {get {Update(); return s_peakWorkingSet;}}
2110
2111         public long ManagedHeapSize {get {Update(); return s_managedHeapSize;}}
2112
2113         public int AppDomainCount {get {Update(); return s_appdomainCount;}}
2114
2115         public int RequestsExecuting {get {Update(); return s_requestsExecuting;}}
2116
2117         public int RequestsQueued {get {Update(); return s_requestsQueued;}}
2118
2119         public int RequestsRejected {get {Update(); return s_requestsRejected;}}
2120
2121
2122         virtual public void FormatToString(WebEventFormatter formatter) {
2123             formatter.AppendLine(WebBaseEvent.FormatResourceStringWithCache(SR.Webevent_event_process_start_time, ProcessStartTime.ToString(CultureInfo.InstalledUICulture)));
2124             formatter.AppendLine(WebBaseEvent.FormatResourceStringWithCache(SR.Webevent_event_thread_count, ThreadCount.ToString(CultureInfo.InstalledUICulture)));
2125             formatter.AppendLine(WebBaseEvent.FormatResourceStringWithCache(SR.Webevent_event_working_set, WorkingSet.ToString(CultureInfo.InstalledUICulture)));
2126             formatter.AppendLine(WebBaseEvent.FormatResourceStringWithCache(SR.Webevent_event_peak_working_set, PeakWorkingSet.ToString(CultureInfo.InstalledUICulture)));
2127             formatter.AppendLine(WebBaseEvent.FormatResourceStringWithCache(SR.Webevent_event_managed_heap_size, ManagedHeapSize.ToString(CultureInfo.InstalledUICulture)));
2128
2129             formatter.AppendLine(WebBaseEvent.FormatResourceStringWithCache(SR.Webevent_event_application_domain_count, AppDomainCount.ToString(CultureInfo.InstalledUICulture)));
2130             formatter.AppendLine(WebBaseEvent.FormatResourceStringWithCache(SR.Webevent_event_requests_executing, RequestsExecuting.ToString(CultureInfo.InstalledUICulture)));
2131             formatter.AppendLine(WebBaseEvent.FormatResourceStringWithCache(SR.Webevent_event_request_queued, RequestsQueued.ToString(CultureInfo.InstalledUICulture)));
2132             formatter.AppendLine(WebBaseEvent.FormatResourceStringWithCache(SR.Webevent_event_request_rejected, RequestsRejected.ToString(CultureInfo.InstalledUICulture)));
2133         }
2134     }
2135
2136     public sealed class WebThreadInformation {
2137         int     _threadId;
2138         string  _accountName;
2139         string  _stackTrace;
2140         bool    _isImpersonating;
2141         internal const string IsImpersonatingKey = "ASPIMPERSONATING";
2142
2143         internal WebThreadInformation(Exception exception) {
2144             _threadId = Thread.CurrentThread.ManagedThreadId;
2145             _accountName = HttpApplication.GetCurrentWindowsIdentityWithAssert().Name;
2146
2147             if (exception != null) {
2148                 _stackTrace = new StackTrace(exception, true).ToString();
2149                 _isImpersonating = exception.Data.Contains(IsImpersonatingKey);
2150             }
2151             else {
2152                 _stackTrace = String.Empty;
2153                 _isImpersonating = false;
2154             }
2155         }
2156
2157
2158         public int ThreadID {get {return _threadId;}}
2159
2160         public string ThreadAccountName {get {return _accountName;}}
2161
2162         public string StackTrace {get {return _stackTrace;}}
2163
2164         public bool IsImpersonating {get {return _isImpersonating;}}
2165
2166
2167         public void FormatToString(WebEventFormatter formatter) {
2168             formatter.AppendLine(WebBaseEvent.FormatResourceStringWithCache(SR.Webevent_event_thread_id, ThreadID.ToString(CultureInfo.InstalledUICulture)));
2169             formatter.AppendLine(WebBaseEvent.FormatResourceStringWithCache(SR.Webevent_event_thread_account_name, ThreadAccountName));
2170
2171             if (IsImpersonating) {
2172                 formatter.AppendLine(WebBaseEvent.FormatResourceStringWithCache(SR.Webevent_event_is_impersonating));
2173             }
2174             else {
2175                 formatter.AppendLine(WebBaseEvent.FormatResourceStringWithCache(SR.Webevent_event_is_not_impersonating));
2176             }
2177
2178             formatter.AppendLine(WebBaseEvent.FormatResourceStringWithCache(SR.Webevent_event_stack_trace, StackTrace));
2179         }
2180     }
2181
2182     // Class that represents the firing record (how many times, last firing time, etc)
2183     // for each rule that inherits from WebBaseEvent.
2184
2185     public sealed class RuleFiringRecord {
2186         internal DateTime   _lastFired;
2187         internal int        _timesRaised;
2188         internal int        _updatingLastFired;
2189
2190         static TimeSpan     TS_ONE_SECOND = new TimeSpan(0, 0, 1);
2191
2192         public DateTime LastFired { get { return _lastFired; } }
2193
2194
2195         public int TimesRaised { get { return _timesRaised; } }
2196
2197         // Point to the ruleInfo that is used by this class
2198         internal HealthMonitoringSectionHelper.RuleInfo    _ruleInfo;
2199
2200         internal RuleFiringRecord(HealthMonitoringSectionHelper.RuleInfo ruleInfo) {
2201
2202             Debug.Assert(ruleInfo != null, "ruleInfo != null");
2203
2204             _ruleInfo = ruleInfo;
2205
2206             _lastFired = DateTime.MinValue;
2207             _timesRaised = 0;
2208             _updatingLastFired = 0;
2209         }
2210
2211         void UpdateLastFired(DateTime now, bool alreadyLocked) {
2212             TimeSpan    tsDiff = now - _lastFired;
2213
2214             if (tsDiff < TS_ONE_SECOND) {
2215                 // If _lastFired was updated within one second, don't bother.
2216                 return;
2217             }
2218
2219             if (!alreadyLocked) {
2220                 // If several threads are firing at the same time, only one thread will
2221                 // update record._lastFired.
2222                 if (Interlocked.CompareExchange(ref _updatingLastFired, 1, 0) == 0) {
2223                     try {
2224                         _lastFired = now;
2225                     }
2226                     finally {
2227                         Interlocked.Exchange(ref _updatingLastFired, 0);
2228                     }
2229                 }
2230             }
2231             else {
2232                 _lastFired = now;
2233             }
2234         }
2235
2236         // Note: this method is thread safe
2237         internal bool CheckAndUpdate(WebBaseEvent eventRaised) {
2238             DateTime    now = DateTime.Now;
2239             int         timesRaised;
2240             HealthMonitoringManager manager = HealthMonitoringManager.Manager();
2241
2242             timesRaised = Interlocked.Increment(ref _timesRaised);
2243
2244             if (manager == null) {
2245                 // Won't fire because we cannot configure healthmonitor
2246                 Debug.Trace("RuleFiringRecord", "Can't configure healthmonitor");
2247                 return false;
2248             }
2249
2250             // Call custom evaluator first
2251             if (_ruleInfo._customEvaluatorType != null) {
2252
2253                 IWebEventCustomEvaluator    icustom = (IWebEventCustomEvaluator)
2254                         manager._sectionHelper._customEvaluatorInstances[_ruleInfo._customEvaluatorType];
2255
2256 #if (!DBG)
2257                 try {
2258 #endif
2259                     // The event may need to do pre-ProcessEvent initialization
2260                     eventRaised.PreProcessEventInit();
2261
2262                     if (!icustom.CanFire(eventRaised, this)) {
2263                         Debug.Trace("RuleFiringRecord", "Custom evaluator returns false.");
2264                         return false;
2265                     }
2266 #if (!DBG)
2267                 }
2268                 catch {
2269                     Debug.Trace("RuleFiringRecord", "Hit an exception when calling Custom evaluator");
2270                     // Return if we hit an error
2271                     return false;
2272                 }
2273 #endif
2274             }
2275
2276             if (timesRaised < _ruleInfo._minInstances) {
2277                 Debug.Trace("RuleFiringRecord",
2278                         "MinInterval not met; timesRaised=" + timesRaised +
2279                         "; _minInstances=" + _ruleInfo._minInstances);
2280                 return false;
2281             }
2282
2283             if (timesRaised > _ruleInfo._maxLimit) {
2284                 Debug.Trace("RuleFiringRecord",
2285                         "MaxLimit exceeded; timesRaised=" + timesRaised +
2286                         "; _maxLimit=" + _ruleInfo._maxLimit);
2287                 return false;
2288             }
2289
2290             // Last step: Check MinInterval and update _lastFired
2291
2292             if (_ruleInfo._minInterval == TimeSpan.Zero) {
2293                 UpdateLastFired(now, false);
2294                 return true;
2295             }
2296
2297             if ((now - _lastFired) <= _ruleInfo._minInterval) {
2298                 Debug.Trace("RuleFiringRecord",
2299                         "MinInterval not met; now=" + now +
2300                         "; _lastFired=" + _lastFired +
2301                         "; _ruleInfo._minInterval=" + _ruleInfo._minInterval);
2302                 return false;
2303             }
2304
2305             // The lock is to prevent multiple threads from passing the
2306             // same test simultaneously.
2307             lock (this) {
2308                 if ((now - _lastFired) <= _ruleInfo._minInterval) {
2309                     Debug.Trace("RuleFiringRecord",
2310                             "MinInterval not met; now=" + now +
2311                             "; _lastFired=" + _lastFired +
2312                             "; _ruleInfo._tsMinInterval=" + _ruleInfo._minInterval);
2313                     return false;
2314                 }
2315
2316                 UpdateLastFired(now, true);
2317                 return true;
2318             }
2319         }
2320
2321     }
2322
2323     internal class HealthMonitoringManager {
2324         internal HealthMonitoringSectionHelper          _sectionHelper;
2325         internal bool           _enabled = false;
2326
2327         static Timer            s_heartbeatTimer = null;
2328         static HealthMonitoringManager s_manager = null;
2329         static bool             s_inited = false;
2330         static bool             s_initing = false;
2331         static object           s_lockObject = new object();
2332         static bool             s_isCacheDisposed = false;
2333
2334         // If this method returns null, it means we failed during configuration.
2335         internal static HealthMonitoringManager Manager() {
2336
2337             if (s_initing) {
2338                 Debug.Assert(!s_inited);
2339                 // If this is true, that means we are calling WebEventBase.Raise while
2340                 // we are initializing.  That means Init() has caused a config exception.
2341                 return null;
2342             }
2343
2344             if (s_inited) {
2345                 return s_manager;
2346             }
2347
2348             lock (s_lockObject) {
2349                 if (s_inited) {
2350                     return s_manager;
2351                 }
2352
2353                 try {
2354                     Debug.Assert(s_manager == null);
2355                     s_initing = true;
2356                     s_manager = new HealthMonitoringManager();;
2357                 }
2358                 finally {
2359                     s_initing = false;
2360                     s_inited = true;
2361                 }
2362             }
2363
2364             return s_manager;
2365         }
2366
2367         internal static bool Enabled {
2368             get {
2369                 // DevDiv 92252: Visual Studio 2010 freezes when opening .cs file in App_Code directory
2370                 // Never raise webevents from CBM process
2371                 if (HostingEnvironment.InClientBuildManager) {
2372                     return false;
2373                 }
2374
2375                 HealthMonitoringManager manager = HealthMonitoringManager.Manager();
2376                 if (manager == null) {
2377                     return false;
2378                 }
2379
2380                 return manager._enabled;
2381             }
2382         }
2383
2384         internal static bool IsCacheDisposed { get { return s_isCacheDisposed; } set { s_isCacheDisposed = value; } }
2385
2386         internal static void StartHealthMonitoringHeartbeat() {
2387             HealthMonitoringManager manager = Manager();
2388             if (manager == null) {
2389                 Debug.Trace(
2390                     "HealthMonitoringManager", "Can't fire heartbeat because we cannot configure HealthMon");
2391                 return;
2392             }
2393
2394             if (!manager._enabled) {
2395                 Debug.Trace(
2396                     "WebEventRaiseDetails", "Can't fire heartbeat because we are disabled");
2397                 return;
2398             }
2399
2400             manager.StartHeartbeatTimer();
2401         }
2402
2403         private HealthMonitoringManager() {
2404             _sectionHelper = HealthMonitoringSectionHelper.GetHelper();
2405
2406             _enabled = _sectionHelper.Enabled;
2407
2408             if (!_enabled) {
2409                 return;
2410             }
2411         }
2412
2413         internal static void Shutdown() {
2414             WebEventManager.Shutdown();
2415             Dispose();
2416         }
2417
2418         internal static void Dispose() {
2419             // Make sure this function won't throw
2420             try {
2421                 if (s_heartbeatTimer != null) {
2422                     s_heartbeatTimer.Dispose();
2423                     s_heartbeatTimer = null;
2424                 }
2425             }
2426             catch {
2427             }
2428         }
2429
2430         internal void HeartbeatCallback(object state) {
2431             Debug.Assert(HealthMonitoringManager.Enabled);
2432             WebBaseEvent.RaiseSystemEvent(null, WebEventCodes.ApplicationHeartbeat);
2433         }
2434
2435         internal void StartHeartbeatTimer() {
2436             TimeSpan interval = _sectionHelper.HealthMonitoringSection.HeartbeatInterval;
2437
2438             if (interval == TimeSpan.Zero) {
2439                 return;
2440             }
2441
2442 #if DBG
2443             if (!Debug.IsTagPresent("Timer") || Debug.IsTagEnabled("Timer"))
2444 #endif
2445             {
2446                 s_heartbeatTimer = new Timer(new TimerCallback(this.HeartbeatCallback), null,
2447                     TimeSpan.Zero, interval);
2448             }
2449         }
2450
2451         internal static HealthMonitoringSectionHelper.ProviderInstances ProviderInstances {
2452             get {
2453                 HealthMonitoringManager manager = Manager();
2454
2455                 if (manager == null) {
2456                     return null;
2457                 }
2458
2459                 if (!manager._enabled) {
2460                     return null;
2461                 }
2462
2463                 return manager._sectionHelper._providerInstances;
2464             }
2465         }
2466     }
2467
2468     public sealed class WebBaseEventCollection : ReadOnlyCollectionBase 
2469     {
2470         public WebBaseEventCollection(ICollection events) {
2471             if (events == null) {
2472                 throw new ArgumentNullException("events");
2473             }
2474
2475             foreach (WebBaseEvent eventRaised in events) {
2476                 InnerList.Add(eventRaised);
2477             }
2478         }
2479
2480         internal WebBaseEventCollection(WebBaseEvent eventRaised) {
2481             if (eventRaised == null) {
2482                 throw new ArgumentNullException("eventRaised");
2483             }
2484
2485             InnerList.Add(eventRaised);
2486         }
2487
2488         // overloaded collection access methods
2489         public WebBaseEvent this[int index] {
2490             get {
2491                 return (WebBaseEvent) InnerList[index];
2492             }
2493         }
2494
2495         public int IndexOf(WebBaseEvent value) {
2496             return InnerList.IndexOf(value);
2497         }
2498
2499         public bool Contains(WebBaseEvent value) {
2500             return InnerList.Contains(value);
2501         }
2502     }
2503
2504     public static class WebEventManager
2505     {
2506
2507         [SecurityPermission(SecurityAction.Demand, Unrestricted=true)]
2508         public static void Flush(string providerName) {
2509             HealthMonitoringSectionHelper.ProviderInstances   providers = HealthMonitoringManager.ProviderInstances;
2510
2511             if (providers == null) {
2512                 return;
2513             }
2514
2515             if (!providers.ContainsKey(providerName)) {
2516                 throw new ArgumentException(SR.GetString(SR.Health_mon_provider_not_found, providerName));
2517             }
2518
2519             using (new ApplicationImpersonationContext()) {
2520                 providers[providerName].Flush();
2521             }
2522         }
2523
2524         [SecurityPermission(SecurityAction.Demand, Unrestricted=true)]
2525         public static void Flush() {
2526             HealthMonitoringSectionHelper.ProviderInstances providers = HealthMonitoringManager.ProviderInstances;
2527
2528             if (providers == null) {
2529                 return;
2530             }
2531
2532             using (new ApplicationImpersonationContext()) {
2533                 foreach(DictionaryEntry de in providers) {
2534                     WebEventProvider    provider = (WebEventProvider)de.Value;
2535
2536                     Debug.Trace("WebEventManager", "Flushing provider " + provider.Name);
2537                     provider.Flush();
2538                 }
2539             }
2540         }
2541
2542         internal static void Shutdown() {
2543             HealthMonitoringSectionHelper.ProviderInstances   providers = HealthMonitoringManager.ProviderInstances;
2544
2545             if (providers == null) {
2546                 return;
2547             }
2548
2549             foreach(DictionaryEntry de in providers) {
2550                 WebEventProvider    provider = (WebEventProvider)de.Value;
2551
2552                 Debug.Trace("WebEventManager", "Shutting down provider " + provider.Name);
2553                 provider.Shutdown();
2554             }
2555         }
2556     }
2557
2558 }
2559