//------------------------------------------------------------ // Copyright (c) Microsoft Corporation. All rights reserved. //------------------------------------------------------------ namespace System.ServiceModel.Diagnostics { using System.Collections.Generic; using System.Diagnostics.PerformanceData; using System.Runtime; using System.Security; using System.ServiceModel; using System.ServiceModel.Administration; sealed class OperationPerformanceCountersV2 : OperationPerformanceCountersBase { static object syncRoot = new object(); static Guid serviceModelProviderId = new Guid("{890c10c3-8c2a-4fe3-a36a-9eca153d47cb}"); static Guid operationCounterSetId = new Guid("{8ebb0470-da6d-485b-8441-8e06b049157a}"); private static readonly CounterSetInstanceCache counterSetInstanceCache = new CounterSetInstanceCache(); // Double-checked locking pattern requires volatile for read/write synchronization static volatile CounterSet operationCounterSet; // Defines the counter set CounterSetInstance operationCounterSetInstance; // Instance of the counter set CounterData[] counters; internal OperationPerformanceCountersV2(string service, string contract, string operationName, string uri) : base(service, contract, operationName, uri) { EnsureCounterSet(); // Create an instance of the counter set (contains the counter data). this.operationCounterSetInstance = CreateCounterSetInstance(this.InstanceName); this.counters = new CounterData[(int)PerfCounters.TotalCounters]; // Cache to dodge dictionary lookups in ServiceModelInstance for (int i = 0; i < (int)PerfCounters.TotalCounters; i++) { this.counters[i] = this.operationCounterSetInstance.Counters[i]; this.counters[i].Value = 0; } } internal static void EnsureCounterSet() { if (operationCounterSet == null) { lock (syncRoot) { if (operationCounterSet == null) { CounterSet localCounterSet = CreateCounterSet(); // Add the counters to the counter set definition. localCounterSet.AddCounter((int)PerfCounters.Calls, CounterType.RawData32, perfCounterNames[(int)PerfCounters.Calls]); localCounterSet.AddCounter((int)PerfCounters.CallsPerSecond, CounterType.RateOfCountPerSecond32, perfCounterNames[(int)PerfCounters.CallsPerSecond]); localCounterSet.AddCounter((int)PerfCounters.CallsOutstanding, CounterType.RawData32, perfCounterNames[(int)PerfCounters.CallsOutstanding]); localCounterSet.AddCounter((int)PerfCounters.CallsFailed, CounterType.RawData32, perfCounterNames[(int)PerfCounters.CallsFailed]); localCounterSet.AddCounter((int)PerfCounters.CallsFailedPerSecond, CounterType.RateOfCountPerSecond32, perfCounterNames[(int)PerfCounters.CallsFailedPerSecond]); localCounterSet.AddCounter((int)PerfCounters.CallsFaulted, CounterType.RawData32, perfCounterNames[(int)PerfCounters.CallsFaulted]); localCounterSet.AddCounter((int)PerfCounters.CallsFaultedPerSecond, CounterType.RateOfCountPerSecond32, perfCounterNames[(int)PerfCounters.CallsFaultedPerSecond]); localCounterSet.AddCounter((int)PerfCounters.CallDurationBase, CounterType.AverageBase, perfCounterNames[(int)PerfCounters.CallDurationBase]); localCounterSet.AddCounter((int)PerfCounters.CallDuration, CounterType.AverageTimer32, perfCounterNames[(int)PerfCounters.CallDuration]); localCounterSet.AddCounter((int)PerfCounters.SecurityValidationAuthenticationFailures, CounterType.RawData32, perfCounterNames[(int)PerfCounters.SecurityValidationAuthenticationFailures]); localCounterSet.AddCounter((int)PerfCounters.SecurityValidationAuthenticationFailuresPerSecond, CounterType.RateOfCountPerSecond32, perfCounterNames[(int)PerfCounters.SecurityValidationAuthenticationFailuresPerSecond]); localCounterSet.AddCounter((int)PerfCounters.CallsNotAuthorized, CounterType.RawData32, perfCounterNames[(int)PerfCounters.CallsNotAuthorized]); localCounterSet.AddCounter((int)PerfCounters.CallsNotAuthorizedPerSecond, CounterType.RateOfCountPerSecond32, perfCounterNames[(int)PerfCounters.CallsNotAuthorizedPerSecond]); localCounterSet.AddCounter((int)PerfCounters.TxFlowed, CounterType.RawData32, perfCounterNames[(int)PerfCounters.TxFlowed]); localCounterSet.AddCounter((int)PerfCounters.TxFlowedPerSecond, CounterType.RateOfCountPerSecond32, perfCounterNames[(int)PerfCounters.TxFlowedPerSecond]); operationCounterSet = localCounterSet; } } } } [Fx.Tag.SecurityNote(Critical = "Calls into Sys.Diag.PerformanceData.CounterSet..ctor marked as SecurityCritical", Safe = "No user provided data is passed to the call")] [SecuritySafeCritical] static CounterSet CreateCounterSet() { return new CounterSet(serviceModelProviderId, operationCounterSetId, CounterSetInstanceType.Multiple); } [Fx.Tag.SecurityNote(Critical = "Calls into Sys.Diag.PerformanceData.CounterSetInstance.CreateCounterSetInstance marked as SecurityCritical", Safe = "No user provided data is passed to the call, instance name parameter is generated by Sys.ServiceModel.Diagnostics code from service description")] [SecuritySafeCritical] static CounterSetInstance CreateCounterSetInstance(string name) { return counterSetInstanceCache.Get(name) ?? operationCounterSet.CreateCounterSetInstance(name); } internal override void MethodCalled() { this.counters[(int)PerfCounters.Calls].Increment(); this.counters[(int)PerfCounters.CallsPerSecond].Increment(); this.counters[(int)PerfCounters.CallsOutstanding].Increment(); } internal override void MethodReturnedSuccess() { this.counters[(int)PerfCounters.CallsOutstanding].Decrement(); } internal override void MethodReturnedError() { this.counters[(int)PerfCounters.CallsFailed].Increment(); this.counters[(int)PerfCounters.CallsFailedPerSecond].Increment(); this.counters[(int)PerfCounters.CallsOutstanding].Decrement(); } internal override void MethodReturnedFault() { this.counters[(int)PerfCounters.CallsFaulted].Increment(); this.counters[(int)PerfCounters.CallsFaultedPerSecond].Increment(); this.counters[(int)PerfCounters.CallsOutstanding].Decrement(); } internal override void SaveCallDuration(long time) { this.counters[(int)PerfCounters.CallDuration].IncrementBy(time); this.counters[(int)PerfCounters.CallDurationBase].Increment(); } internal override void AuthenticationFailed() { this.counters[(int)PerfCounters.SecurityValidationAuthenticationFailures].Increment(); this.counters[(int)PerfCounters.SecurityValidationAuthenticationFailuresPerSecond].Increment(); } internal override void AuthorizationFailed() { this.counters[(int)PerfCounters.CallsNotAuthorized].Increment(); this.counters[(int)PerfCounters.CallsNotAuthorizedPerSecond].Increment(); } internal override void TxFlowed() { this.counters[(int)PerfCounters.TxFlowed].Increment(); this.counters[(int)PerfCounters.TxFlowedPerSecond].Increment(); } internal override bool Initialized { get { return this.operationCounterSetInstance != null; } } // Immediately disposes and nulls the CounterSetInstance. This differs from Dispose because Dispose is "lazy" in that // it holds weak references to the instances so we don't get corrupted state if the values are updated later. This // method is used in situations when we need to delete the instance immediately and know the values won't be updated. internal void DeleteInstance() { if (this.operationCounterSetInstance != null) { this.operationCounterSetInstance.Dispose(); this.operationCounterSetInstance = null; } } protected override void Dispose(bool disposing) { try { if (disposing && PerformanceCounters.PerformanceCountersEnabled && this.operationCounterSetInstance != null) { counterSetInstanceCache.Add(this.InstanceName, this.operationCounterSetInstance); } } finally { // Not really necessary as base.Dispose(bool) does nothing // But forced to leave this with try/finally by unability to suspend FxCop 1.35 warning base.Dispose(disposing); } } internal static void CleanupCache() { counterSetInstanceCache.Cleanup(); } } }