//------------------------------------------------------------ // Copyright (c) Microsoft Corporation. All rights reserved. //------------------------------------------------------------ namespace System.ServiceModel.Diagnostics { using System.Diagnostics; using System.Globalization; using System.Runtime; static class PerformanceCountersFactory { private static bool categoriesExist = false; static internal ServicePerformanceCountersBase CreateServiceCounters(ServiceHostBase serviceHost) { if (!CheckPermissions()) { return null; } if (OSEnvironmentHelper.IsVistaOrGreater) { try { EnsureCategoriesExistIfNeeded(); var counters = new ServicePerformanceCountersV2(serviceHost); // Workaround Sys.Diag.PerformanceData problem: // Ensure that all three categories are initialized so other processes can still // expose endpoint/operation perf counters event if this one doesn't EndpointPerformanceCountersV2.EnsureCounterSet(); OperationPerformanceCountersV2.EnsureCounterSet(); return counters; } #pragma warning suppress 56500 // covered by FxCOP catch (Exception e) { if (Fx.IsFatal(e)) { throw; } PerformanceCounters.Scope = PerformanceCounterScope.Off; if (DiagnosticUtility.ShouldTraceError) { TraceUtility.TraceEvent(TraceEventType.Error, TraceCode.PerformanceCountersFailedForService, SR.GetString(SR.TraceCodePerformanceCountersFailedForService), null, e); } return null; } } return new ServicePerformanceCounters(serviceHost); } static internal EndpointPerformanceCountersBase CreateEndpointCounters(string service, string contract, string uri) { if (!CheckPermissions()) { return null; } if (OSEnvironmentHelper.IsVistaOrGreater) { try { EnsureCategoriesExistIfNeeded(); return new EndpointPerformanceCountersV2(service, contract, uri); } #pragma warning suppress 56500 // covered by FxCOP catch (Exception e) { if (Fx.IsFatal(e)) { throw; } PerformanceCounters.Scope = PerformanceCounterScope.Off; if (DiagnosticUtility.ShouldTraceError) { TraceUtility.TraceEvent(TraceEventType.Error, TraceCode.PerformanceCountersFailedForService, SR.GetString(SR.TraceCodePerformanceCountersFailedForService), null, e); } return null; } } return new EndpointPerformanceCounters(service, contract, uri); } static internal OperationPerformanceCountersBase CreateOperationCounters(string service, string contract, string operationName, string uri) { if (!CheckPermissions()) { return null; } if (OSEnvironmentHelper.IsVistaOrGreater) { try { EnsureCategoriesExistIfNeeded(); return new OperationPerformanceCountersV2(service, contract, operationName, uri); } #pragma warning suppress 56500 // covered by FxCOP catch (Exception e) { if (Fx.IsFatal(e)) { throw; } PerformanceCounters.Scope = PerformanceCounterScope.Off; if (DiagnosticUtility.ShouldTraceError) { TraceUtility.TraceEvent(TraceEventType.Error, TraceCode.PerformanceCountersFailedForService, SR.GetString(SR.TraceCodePerformanceCountersFailedForService), null, e); } return null; } } return new OperationPerformanceCounters(service, contract, operationName, uri); } /// /// Returns true if we're running in full trust. Otherwise turns off performance counters and returns false. /// private static bool CheckPermissions() { // At this time (.net 4.5), performance counters require Unrestricted permissions to be created. if (PartialTrustHelpers.AppDomainFullyTrusted) { return true; } PerformanceCounters.Scope = PerformanceCounterScope.Off; if (DiagnosticUtility.ShouldTraceWarning) { TraceUtility.TraceEvent(TraceEventType.Warning, TraceCode.PerformanceCountersFailedForService, SR.GetString(SR.PartialTrustPerformanceCountersNotEnabled)); } return false; } // If EnsureUniquePerformanceCounterInstanceName is enabled, PerformanceCountersBase.cs will be checking if instances // exist in each of these categories, so we need to ensure the categories all exist. This works around System.Diagnostics // calls using PerformanceCounterLib to cache which categories do/don't exist. private static void EnsureCategoriesExistIfNeeded() { if (categoriesExist || !ServiceModelAppSettings.EnsureUniquePerformanceCounterInstanceNames) { return; } OperationPerformanceCountersV2 operationCounter = null; EndpointPerformanceCountersV2 endpointCounter = null; ServicePerformanceCountersV2 serviceCounter = null; try { if (PerformanceCounterCategory.Exists(PerformanceCounterStrings.SERVICEMODELOPERATION.OperationPerfCounters) && PerformanceCounterCategory.Exists(PerformanceCounterStrings.SERVICEMODELENDPOINT.EndpointPerfCounters) && PerformanceCounterCategory.Exists(PerformanceCounterStrings.SERVICEMODELSERVICE.ServicePerfCounters)) { categoriesExist = true; return; } // Categories do not exist. Update PerformanceCounterLib's cache using dummy counters. const string dummyValue = "_WCF_Admin"; // Older operating systems (such as windows 7) report the category as not existing unless a counter instance // has been created in it. Create one instance in each of the categories to ensure they will exist in the cache // that System.Diagnostics calls use. ServiceHost dummyServiceHost = new ServiceHost(typeof(object), new Uri("http://" + dummyValue)); operationCounter = new OperationPerformanceCountersV2(dummyValue, dummyValue, dummyValue, dummyValue); endpointCounter = new EndpointPerformanceCountersV2(dummyValue, dummyValue, dummyValue); serviceCounter = new ServicePerformanceCountersV2(dummyServiceHost); // Throw away cached categories, then read from the categories to cause the cache to be repopulated. PerformanceCounter.CloseSharedResources(); PerformanceCounterCategory.Exists(dummyValue); } catch (UnauthorizedAccessException) { // Don't have permission to read performance counters. Trace a warning. if (DiagnosticUtility.ShouldTraceWarning) { TraceUtility.TraceEvent(TraceEventType.Warning, TraceCode.PerformanceCountersFailedForService, SR.GetString(SR.EnsureCategoriesExistFailedPermission)); } } catch { // Failed to ensure all of the categories exist. Catch the exception and try to create the counter anyway. } finally { // Delete the dummy counters, we don't need them anymore. if (operationCounter != null) { operationCounter.DeleteInstance(); } if (endpointCounter != null) { endpointCounter.DeleteInstance(); } if (serviceCounter != null) { serviceCounter.DeleteInstance(); } categoriesExist = true; } } } }