//------------------------------------------------------------ // Copyright (c) Microsoft Corporation. All rights reserved. //------------------------------------------------------------ namespace System.ServiceModel.Diagnostics { using System.Diagnostics; using System.Runtime; using System.ServiceModel; using System.ServiceModel.Administration; using System.Diagnostics.PerformanceData; abstract class OperationPerformanceCountersBase : PerformanceCountersBase { protected string instanceName; protected string operationName; protected enum PerfCounters : int { Calls = 0, CallsPerSecond, CallsOutstanding, CallsFailed, CallsFailedPerSecond, CallsFaulted, CallsFaultedPerSecond, CallDuration, CallDurationBase, SecurityValidationAuthenticationFailures, SecurityValidationAuthenticationFailuresPerSecond, CallsNotAuthorized, CallsNotAuthorizedPerSecond, TxFlowed, TxFlowedPerSecond, TotalCounters = TxFlowedPerSecond + 1 } protected static readonly string[] perfCounterNames = { PerformanceCounterStrings.SERVICEMODELOPERATION.Calls, PerformanceCounterStrings.SERVICEMODELOPERATION.CallsPerSecond, PerformanceCounterStrings.SERVICEMODELOPERATION.CallsOutstanding, PerformanceCounterStrings.SERVICEMODELOPERATION.CallsFailed, PerformanceCounterStrings.SERVICEMODELOPERATION.CallsFailedPerSecond, PerformanceCounterStrings.SERVICEMODELOPERATION.CallsFaulted, PerformanceCounterStrings.SERVICEMODELOPERATION.CallsFaultedPerSecond, PerformanceCounterStrings.SERVICEMODELOPERATION.CallDuration, PerformanceCounterStrings.SERVICEMODELOPERATION.CallDurationBase, PerformanceCounterStrings.SERVICEMODELOPERATION.SecurityValidationAuthenticationFailures, PerformanceCounterStrings.SERVICEMODELOPERATION.SecurityValidationAuthenticationFailuresPerSecond, PerformanceCounterStrings.SERVICEMODELOPERATION.SecurityCallsNotAuthorized, PerformanceCounterStrings.SERVICEMODELOPERATION.SecurityCallsNotAuthorizedPerSecond, PerformanceCounterStrings.SERVICEMODELOPERATION.TxFlowed, PerformanceCounterStrings.SERVICEMODELOPERATION.TxFlowedPerSecond, }; const int maxCounterLength = 64; const int hashLength = 2; [Flags] enum truncOptions : uint { NoBits = 0, service7 = 0x01, contract7 = 0x02, operation15 = 0x04, uri32 = 0x08 } internal OperationPerformanceCountersBase(string service, string contract, string operationName, string uri) { this.operationName = operationName; this.instanceName = CreateFriendlyInstanceName(service, contract, operationName, uri); } private static string GetFullInstanceName(string service, string contract, string operation, string uri) { // instance name is: serviceName.interfaceName.operationName@uri return String.Format("{0}.{1}.{2}@{3}", service, contract, operation, uri); } private static string GetShortInstanceName(string service, string contract, string operation, string uri) { int length = service.Length + contract.Length + operation.Length + uri.Length + 3; if (length > maxCounterLength) { int count = 0; truncOptions tasks = OperationPerformanceCounters.GetCompressionTasks( length, service.Length, contract.Length, operation.Length, uri.Length); //if necessary, compress service name to 5 chars with a 2 char hash code if ((tasks & truncOptions.service7) > 0) { count = 7; service = GetHashedString(service, count - hashLength, service.Length - count + hashLength, true); } //if necessary, compress contract name to 5 chars with a 2 char hash code if ((tasks & truncOptions.contract7) > 0) { count = 7; contract = GetHashedString(contract, count - hashLength, contract.Length - count + hashLength, true); } //if necessary, compress operation name to 13 chars with a 2 char hash code if ((tasks & truncOptions.operation15) > 0) { count = 15; operation = GetHashedString(operation, count - hashLength, operation.Length - count + hashLength, true); } //if necessary, compress uri to 30 chars with a 2 char hash code if ((tasks & truncOptions.uri32) > 0) { count = 32; uri = GetHashedString(uri, 0, uri.Length - count + hashLength, false); } } // replace '/' with '|' because perfmon fails when '/' is in perfcounter instance name return service + "." + contract + "." + operation + "@" + uri.Replace('/', '|'); } internal static string CreateFriendlyInstanceName(string service, string contract, string operation, string uri) { string shortInstanceName = GetShortInstanceName(service, contract, operation, uri); if (!ServiceModelAppSettings.EnsureUniquePerformanceCounterInstanceNames) { return shortInstanceName; } string fullInstanceName = GetFullInstanceName(service, contract, operation, uri); return EnsureUniqueInstanceName(PerformanceCounterStrings.SERVICEMODELOPERATION.OperationPerfCounters, shortInstanceName, fullInstanceName); } internal static string GetFriendlyInstanceName(string service, string contract, string operation, string uri) { string shortInstanceName = GetShortInstanceName(service, contract, operation, uri); if (!ServiceModelAppSettings.EnsureUniquePerformanceCounterInstanceNames) { return shortInstanceName; } string fullInstanceName = GetFullInstanceName(service, contract, operation, uri); return GetUniqueInstanceName(PerformanceCounterStrings.SERVICEMODELOPERATION.OperationPerfCounters, shortInstanceName, fullInstanceName); } static truncOptions GetCompressionTasks(int totalLen, int serviceLen, int contractLen, int operationLen, int uriLen) { truncOptions bitmask = 0; if (totalLen > maxCounterLength) { int workingLen = totalLen; //note: order of if statements important (see spec)! if (workingLen > maxCounterLength && serviceLen > 8) { bitmask |= truncOptions.service7; //compress service name to 8 chars workingLen -= serviceLen - 7; } if (workingLen > maxCounterLength && contractLen > 7) { bitmask |= truncOptions.contract7; //compress contract name to 8 chars workingLen -= contractLen - 7; } if (workingLen > maxCounterLength && operationLen > 15) { bitmask |= truncOptions.operation15; //compress operation name to 16 chars workingLen -= operationLen - 15; } if (workingLen > maxCounterLength && uriLen > 32) { bitmask |= truncOptions.uri32; //compress uri to 32 chars } } return bitmask; } internal override string InstanceName { get { return this.instanceName; } } internal string OperationName { get { return this.operationName; } } internal override string[] CounterNames { get { return perfCounterNames; } } internal override int PerfCounterStart { get { return (int)PerfCounters.Calls; } } internal override int PerfCounterEnd { get { return (int)PerfCounters.TotalCounters; } } internal abstract void MethodCalled(); internal abstract void MethodReturnedSuccess(); internal abstract void MethodReturnedError(); internal abstract void MethodReturnedFault(); internal abstract void SaveCallDuration(long time); internal abstract void AuthenticationFailed(); internal abstract void AuthorizationFailed(); internal abstract void TxFlowed(); } }