//------------------------------------------------------------ // Copyright (c) Microsoft Corporation. All rights reserved. //------------------------------------------------------------ namespace System.ServiceModel.Diagnostics { using System; using System.Diagnostics; using System.Runtime.Remoting.Messaging; using System.Threading; using System.Globalization; using System.Collections.Generic; using System.ServiceModel.Diagnostics.Application; using System.Runtime.Diagnostics; class ServiceModelActivity : IDisposable { [ThreadStatic] static ServiceModelActivity currentActivity; static string[] ActivityTypeNames = new string[(int)ActivityType.NumItems]; ServiceModelActivity previousActivity = null; static string activityBoundaryDescription = null; ActivityState lastState = ActivityState.Unknown; string name = null; bool autoStop = false; bool autoResume = false; Guid activityId; bool disposed = false; bool isAsync = false; int stopCount = 0; const int AsyncStopCount = 2; TransferActivity activity = null; ActivityType activityType = ActivityType.Unknown; static ServiceModelActivity() { ActivityTypeNames[(int)ActivityType.Unknown] = "Unknown"; ActivityTypeNames[(int)ActivityType.Close] = "Close"; ActivityTypeNames[(int)ActivityType.Construct] = "Construct"; ActivityTypeNames[(int)ActivityType.ExecuteUserCode] = "ExecuteUserCode"; ActivityTypeNames[(int)ActivityType.ListenAt] = "ListenAt"; ActivityTypeNames[(int)ActivityType.Open] = "Open"; ActivityTypeNames[(int)ActivityType.OpenClient] = "Open"; ActivityTypeNames[(int)ActivityType.ProcessMessage] = "ProcessMessage"; ActivityTypeNames[(int)ActivityType.ProcessAction] = "ProcessAction"; ActivityTypeNames[(int)ActivityType.ReceiveBytes] = "ReceiveBytes"; ActivityTypeNames[(int)ActivityType.SecuritySetup] = "SecuritySetup"; ActivityTypeNames[(int)ActivityType.TransferToComPlus] = "TransferToComPlus"; ActivityTypeNames[(int)ActivityType.WmiGetObject] = "WmiGetObject"; ActivityTypeNames[(int)ActivityType.WmiPutInstance] = "WmiPutInstance"; } ServiceModelActivity(Guid activityId) { this.activityId = activityId; this.previousActivity = ServiceModelActivity.Current; } static string ActivityBoundaryDescription { get { if (ServiceModelActivity.activityBoundaryDescription == null) { ServiceModelActivity.activityBoundaryDescription = TraceSR.GetString(TraceSR.ActivityBoundary); } return ServiceModelActivity.activityBoundaryDescription; } } internal ActivityType ActivityType { get { return this.activityType; } } internal ServiceModelActivity PreviousActivity { get { return this.previousActivity; } } static internal Activity BoundOperation(ServiceModelActivity activity) { if (!DiagnosticUtility.ShouldUseActivity) { return null; } return ServiceModelActivity.BoundOperation(activity, false); } static internal Activity BoundOperation(ServiceModelActivity activity, bool addTransfer) { return activity == null ? null : ServiceModelActivity.BoundOperationCore(activity, addTransfer); } static Activity BoundOperationCore(ServiceModelActivity activity, bool addTransfer) { if (!DiagnosticUtility.ShouldUseActivity) { return null; } TransferActivity retval = null; if (activity != null) { retval = TransferActivity.CreateActivity(activity.activityId, addTransfer); if (retval != null) { retval.SetPreviousServiceModelActivity(ServiceModelActivity.Current); } ServiceModelActivity.Current = activity; } return retval; } internal static ServiceModelActivity CreateActivity() { if (!DiagnosticUtility.ShouldUseActivity) { return null; } return ServiceModelActivity.CreateActivity(Guid.NewGuid(), true); } internal static ServiceModelActivity CreateActivity(bool autoStop) { if (!DiagnosticUtility.ShouldUseActivity) { return null; } ServiceModelActivity activity = ServiceModelActivity.CreateActivity(Guid.NewGuid(), true); if (activity != null) { activity.autoStop = autoStop; } return activity; } internal static ServiceModelActivity CreateActivity(bool autoStop, string activityName, ActivityType activityType) { if (!DiagnosticUtility.ShouldUseActivity) { return null; } ServiceModelActivity activity = ServiceModelActivity.CreateActivity(autoStop); ServiceModelActivity.Start(activity, activityName, activityType); return activity; } internal static ServiceModelActivity CreateAsyncActivity() { if (!DiagnosticUtility.ShouldUseActivity) { return null; } ServiceModelActivity activity = ServiceModelActivity.CreateActivity(true); if (activity != null) { activity.isAsync = true; } return activity; } internal static ServiceModelActivity CreateBoundedActivity() { return ServiceModelActivity.CreateBoundedActivity(false); } internal static ServiceModelActivity CreateBoundedActivity(bool suspendCurrent) { if (!DiagnosticUtility.ShouldUseActivity) { return null; } ServiceModelActivity activityToSuspend = ServiceModelActivity.Current; ServiceModelActivity retval = ServiceModelActivity.CreateActivity(true); if (retval != null) { retval.activity = (TransferActivity)ServiceModelActivity.BoundOperation(retval, true); retval.activity.SetPreviousServiceModelActivity(activityToSuspend); if (suspendCurrent) { retval.autoResume = true; } } if (suspendCurrent && activityToSuspend != null) { activityToSuspend.Suspend(); } return retval; } internal static ServiceModelActivity CreateBoundedActivity(Guid activityId) { if (!DiagnosticUtility.ShouldUseActivity) { return null; } ServiceModelActivity retval = ServiceModelActivity.CreateActivity(activityId, true); if (retval != null) { retval.activity = (TransferActivity)ServiceModelActivity.BoundOperation(retval, true); } return retval; } internal static ServiceModelActivity CreateBoundedActivityWithTransferInOnly(Guid activityId) { if (!DiagnosticUtility.ShouldUseActivity) { return null; } ServiceModelActivity retval = ServiceModelActivity.CreateActivity(activityId, true); if (retval != null) { if (null != FxTrace.Trace) { FxTrace.Trace.TraceTransfer(activityId); } retval.activity = (TransferActivity)ServiceModelActivity.BoundOperation(retval); } return retval; } internal static ServiceModelActivity CreateLightWeightAsyncActivity(Guid activityId) { return new ServiceModelActivity(activityId); } internal static ServiceModelActivity CreateActivity(Guid activityId) { if (!DiagnosticUtility.ShouldUseActivity) { return null; } ServiceModelActivity retval = null; if (activityId != Guid.Empty) { retval = new ServiceModelActivity(activityId); } if (retval != null) { ServiceModelActivity.Current = retval; } return retval; } internal static ServiceModelActivity CreateActivity(Guid activityId, bool autoStop) { if (!DiagnosticUtility.ShouldUseActivity) { return null; } ServiceModelActivity retval = ServiceModelActivity.CreateActivity(activityId); if (retval != null) { retval.autoStop = autoStop; } return retval; } internal static ServiceModelActivity Current { get { return ServiceModelActivity.currentActivity; } private set { ServiceModelActivity.currentActivity = value; } } public void Dispose() { if (!this.disposed) { this.disposed = true; try { if (this.activity != null) { this.activity.Dispose(); } if (this.autoStop) { this.Stop(); } if (this.autoResume && ServiceModelActivity.Current != null) { ServiceModelActivity.Current.Resume(); } } finally { ServiceModelActivity.Current = this.previousActivity; GC.SuppressFinalize(this); } } } internal Guid Id { get { return this.activityId; } } ActivityState LastState { get { return this.lastState; } set { this.lastState = value; } } internal string Name { get { return this.name; } set { this.name = value; } } internal void Resume() { if (this.LastState == ActivityState.Suspend) { this.LastState = ActivityState.Resume; this.TraceMilestone(TraceEventType.Resume); } } internal void Resume(string activityName) { if (string.IsNullOrEmpty(this.Name)) { this.name = activityName; } this.Resume(); } static internal void Start(ServiceModelActivity activity, string activityName, ActivityType activityType) { if (activity != null && activity.LastState == ActivityState.Unknown) { activity.LastState = ActivityState.Start; activity.name = activityName; activity.activityType = activityType; activity.TraceMilestone(TraceEventType.Start); } } internal void Stop() { int newStopCount = 0; if (this.isAsync) { newStopCount = Interlocked.Increment(ref this.stopCount); } if (this.LastState != ActivityState.Stop && (!this.isAsync || (this.isAsync && newStopCount >= ServiceModelActivity.AsyncStopCount))) { this.LastState = ActivityState.Stop; this.TraceMilestone(TraceEventType.Stop); } } static internal void Stop(ServiceModelActivity activity) { if (activity != null) { activity.Stop(); } } internal void Suspend() { if (this.LastState != ActivityState.Stop) { this.LastState = ActivityState.Suspend; this.TraceMilestone(TraceEventType.Suspend); } } public override string ToString() { return this.Id.ToString(); } void TraceMilestone(TraceEventType type) { if (string.IsNullOrEmpty(this.Name)) { if (null != FxTrace.Trace) { CallEtwMileStoneEvent(type, null); } if (null != DiagnosticUtility.DiagnosticTrace) { TraceUtility.TraceEventNoCheck(type, TraceCode.ActivityBoundary, ServiceModelActivity.ActivityBoundaryDescription, null, ServiceModelActivity.ActivityBoundaryDescription, (Exception)null); } } else { if (null != FxTrace.Trace) { Dictionary values = new Dictionary(2); values["ActivityName"] = this.Name; values["ActivityType"] = ServiceModelActivity.ActivityTypeNames[(int)this.activityType]; using (DiagnosticUtility.ShouldUseActivity && Guid.Empty == activityId ? null : Activity.CreateActivity(this.Id)) { CallEtwMileStoneEvent(type, new DictionaryTraceRecord(values)); } } if (null != DiagnosticUtility.DiagnosticTrace) { Dictionary values = new Dictionary(2); values["ActivityName"] = this.Name; values["ActivityType"] = ServiceModelActivity.ActivityTypeNames[(int)this.activityType]; TraceUtility.TraceEventNoCheck(type, TraceCode.ActivityBoundary, ServiceModelActivity.ActivityBoundaryDescription, new DictionaryTraceRecord(values), null, null, this.Id); } } } void CallEtwMileStoneEvent(TraceEventType type, DictionaryTraceRecord record) { switch (type) { case TraceEventType.Start: if (TD.StartSignpostEventIsEnabled()) { TD.StartSignpostEvent(record); } break; case TraceEventType.Stop: if (TD.StopSignpostEventIsEnabled()) { TD.StopSignpostEvent(record); } break; case TraceEventType.Suspend: if (TD.SuspendSignpostEventIsEnabled()) { TD.SuspendSignpostEvent(record); } break; case TraceEventType.Resume: if (TD.ResumeSignpostEventIsEnabled()) { TD.ResumeSignpostEvent(record); } break; } } enum ActivityState { Unknown, Start, Suspend, Resume, Stop, } class TransferActivity : Activity { bool addTransfer = false; bool changeCurrentServiceModelActivity = false; ServiceModelActivity previousActivity = null; TransferActivity(Guid activityId, Guid parentId) : base(activityId, parentId) { } internal static TransferActivity CreateActivity(Guid activityId, bool addTransfer) { if (!DiagnosticUtility.ShouldUseActivity) { return null; } TransferActivity retval = null; if (DiagnosticUtility.TracingEnabled && activityId != Guid.Empty) { Guid currentActivityId = DiagnosticTraceBase.ActivityId; if (activityId != currentActivityId) { if (addTransfer) { if (null != FxTrace.Trace) { FxTrace.Trace.TraceTransfer(activityId); } } TransferActivity activity = new TransferActivity(activityId, currentActivityId); activity.addTransfer = addTransfer; retval = activity; } } return retval; } internal void SetPreviousServiceModelActivity(ServiceModelActivity previous) { this.previousActivity = previous; this.changeCurrentServiceModelActivity = true; } public override void Dispose() { try { if (addTransfer) { // Make sure that we are transferring from our AID to the // parent. It is possible for someone else to change the ambient // in user code (MB 49318). using (Activity.CreateActivity(this.Id)) { if (null != FxTrace.Trace) { FxTrace.Trace.TraceTransfer(this.parentId); } } } } finally { if (this.changeCurrentServiceModelActivity) { ServiceModelActivity.Current = this.previousActivity; } base.Dispose(); } } } } }