e79aa3c0ed
Former-commit-id: a2155e9bd80020e49e72e86c44da02a8ac0e57a4
531 lines
18 KiB
C#
531 lines
18 KiB
C#
//------------------------------------------------------------
|
|
// 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<string, string> values = new Dictionary<string, string>(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<string, string> values = new Dictionary<string, string>(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();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|