public SpanContext Extract <T>(T carrier, Func <T, string, IEnumerable <string> > getter) { var traceParentCollection = getter(carrier, W3CHeaderNames.TraceParent).ToList(); if (traceParentCollection.Count != 1) { Log.Warning("Header {HeaderName} needs exactly 1 value", W3CHeaderNames.TraceParent); return(null); } var traceParentHeader = traceParentCollection.First(); var traceIdString = traceParentHeader.Substring(VersionPrefixIdLength, TraceIdLength); var traceId = TraceId.CreateFromString(traceIdString); if (traceId == TraceId.Zero) { Log.Warning("Could not parse {HeaderName} headers: {HeaderValues}", W3CHeaderNames.TraceParent, string.Join(",", traceParentCollection)); return(null); } var spanIdString = traceParentHeader.Substring(VersionAndTraceIdLength, SpanIdLength); if (!ulong.TryParse(spanIdString, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out var spanId)) { Log.Warning("Could not parse {HeaderName} headers: {HeaderValues}", W3CHeaderNames.TraceParent, string.Join(",", traceParentCollection)); return(null); } var traceStateCollection = getter(carrier, W3CHeaderNames.TraceState); var traceState = ExtractTraceState(traceStateCollection); return(spanId == 0 ? null : new SpanContext(traceId, spanId, samplingPriority: null, serviceName: null, traceState)); }
internal static void LogException(Exception exception) { Log.SafeLogError(exception, exception?.Message, null); if (exception is DuckTypeException) { Log.Warning($"DuckTypeException has been detected, the integration <{typeof(TIntegration)}, {typeof(TTarget)}> will be disabled."); _disableIntegration = true; } else if (exception is CallTargetInvokerException) { Log.Warning($"CallTargetInvokerException has been detected, the integration <{typeof(TIntegration)}, {typeof(TTarget)}> will be disabled."); _disableIntegration = true; } }
public void Dispose() { try { Scope?.Dispose(); } catch (Exception x) { Log.Warning("Disposal exception", x); } }
public static TraceId ParseTraceId <T>(T carrier, Func <T, string, IEnumerable <string> > getter, string headerName, Vendors.Serilog.ILogger logger) { var headerValues = getter(carrier, headerName).ToList(); foreach (var traceId in headerValues.Select(TraceId.CreateFromString).Where(traceId => traceId != TraceId.Zero)) { return(traceId); } logger.Warning("Could not parse {HeaderName} headers: {HeaderValues}", headerName, string.Join(",", headerValues)); return(TraceId.Zero); }
internal RuntimeMetricsWriter(IDogStatsd statsd, int delay, Func <IDogStatsd, IRuntimeMetricsListener> initializeListener) { _delay = delay; _statsd = statsd; _timer = new Timer(_ => PushEvents(), null, delay, delay); try { AppDomain.CurrentDomain.FirstChanceException += FirstChanceException; } catch (Exception ex) { Log.Warning(ex, "First chance exceptions won't be monitored"); } try { ProcessHelpers.GetCurrentProcessRuntimeMetrics(out var userCpu, out var systemCpu, out _, out _); _previousUserCpu = userCpu; _previousSystemCpu = systemCpu; _enableProcessMetrics = true; } catch (Exception ex) { Log.Warning(ex, "Unable to get current process information"); _enableProcessMetrics = false; } try { _listener = initializeListener(statsd); } catch (Exception ex) { Log.Warning(ex, "Unable to initialize runtime listener, some runtime metrics will be missing"); } }
public static Module Get(Guid moduleVersionId) { // First attempt at cached values with no blocking if (_modules.TryGetValue(moduleVersionId, out Module value)) { return(value); } // Block if a population event is happening _populationResetEvent.Wait(); // See if the previous population event populated what we need if (_modules.TryGetValue(moduleVersionId, out value)) { return(value); } if (_failures >= MaxFailures) { // For some unforeseeable reason we have failed on a lot of AppDomain lookups if (!_shortCircuitLogicHasLogged) { Log.Warning("Datadog is unable to continue attempting module lookups for this AppDomain. Falling back to legacy method lookups."); } return(null); } // Block threads on this event _populationResetEvent.Reset(); try { PopulateModules(); } catch (Exception ex) { _failures++; Log.Error(ex, "Error when populating modules."); } finally { // Continue threads blocked on this event _populationResetEvent.Set(); } _modules.TryGetValue(moduleVersionId, out value); return(value); }
private string CompileResourceId() { string resourceId = null; try { var success = true; if (SubscriptionId == null) { success = false; Log.Warning("Could not successfully retrieve the subscription ID from variable: {0}", WebsiteOwnerNameKey); } if (SiteName == null) { success = false; Log.Warning("Could not successfully retrieve the deployment ID from variable: {0}", SiteNameKey); } if (ResourceGroup == null) { success = false; Log.Warning("Could not successfully retrieve the resource group name from variable: {0}", ResourceGroupKey); } if (success) { resourceId = $"/subscriptions/{SubscriptionId}/resourcegroups/{ResourceGroup}/providers/microsoft.web/sites/{SiteName}".ToLowerInvariant(); } } catch (Exception ex) { Log.SafeLogError(ex, "Could not successfully setup the resource ID for Azure App Services."); } return(resourceId); }
public RuntimeMetricsWriter(IDogStatsd statsd, int delay) { _delay = delay; _statsd = statsd; _timer = new Timer(_ => PushEvents(), null, delay, delay); try { AppDomain.CurrentDomain.FirstChanceException += FirstChanceException; } catch (Exception ex) { Log.Warning(ex, "First chance exceptions won't be monitored"); } try { ProcessHelpers.GetCurrentProcessRuntimeMetrics(out var userCpu, out var systemCpu, out _, out _); _previousUserCpu = userCpu; _previousSystemCpu = systemCpu; _enableProcessMetrics = true; } catch (Exception ex) { Log.Warning(ex, "Unable to get current process information"); _enableProcessMetrics = false; } #if NETCOREAPP _listener = new RuntimeEventListener(); _listener.GcHeapStats += GcHeapStats; _listener.GcPauseTime += GcPauseTime; _listener.GcHeapHistory += GcHeapHistory; _listener.Contention += Contention; #endif }
public async Task FlushAndCloseAsync() { if (!_processExit.TrySetResult(true)) { return; } await Task.WhenAny(_flushTask, Task.Delay(TimeSpan.FromSeconds(20))) .ConfigureAwait(false); if (!_flushTask.IsCompleted) { Log.Warning("Could not flush all traces before process exit"); } }
private static ulong ParseUInt64 <T>(T headers, string headerName) where T : IHeadersCollection { var headerValues = headers.GetValues(headerName); bool hasValue = false; foreach (string headerValue in headerValues) { if (ulong.TryParse(headerValue, NumberStyles, InvariantCulture, out var result)) { return(result); } hasValue = true; } if (hasValue) { Log.Warning("Could not parse {0} headers: {1}", headerName, string.Join(",", headerValues)); } return(0); }
/// <summary> /// Initializes global instrumentation values. /// </summary> public static void Initialize() { if (Interlocked.Exchange(ref _firstInitialization, 0) != 1) { // Initialize() was already called before return; } try { _ = Tracer.Instance; } catch { // ignore } #if !NETFRAMEWORK try { if (GlobalSettings.Source.DiagnosticSourceEnabled) { // check if DiagnosticSource is available before trying to use it var type = Type.GetType("System.Diagnostics.DiagnosticSource, System.Diagnostics.DiagnosticSource", throwOnError: false); if (type == null) { Log.Warning("DiagnosticSource type could not be loaded. Skipping diagnostic observers."); } else { // don't call this method unless DiagnosticSource is available StartDiagnosticManager(); } } } catch { // ignore } #endif }
private static string GetContainerIdInternal() { try { var isLinux = string.Equals(FrameworkDescription.Create().OSPlatform, "Linux", StringComparison.OrdinalIgnoreCase); if (isLinux && File.Exists(ControlGroupsFilePath)) { var lines = File.ReadLines(ControlGroupsFilePath); return(ParseCgroupLines(lines)); } } catch (Exception ex) { Log.Warning("Error reading cgroup file. Will not report container id.", ex); } return(null); }
public Encoding GetContentEncoding() { // reduce getter calls var contentType = ContentType; if (contentType == null) { return(null); } if (string.Equals("application/json", contentType, StringComparison.OrdinalIgnoreCase)) { // Default return(Utf8Encoding); } // text/plain; charset=utf-8 string[] pairs = contentType.Split(';'); foreach (string pair in pairs) { string[] parts = pair.Split('='); if (parts.Length == 2 && string.Equals(parts[0].Trim(), "charset", System.StringComparison.OrdinalIgnoreCase)) { switch (parts[1].Trim()) { case "utf-8": return(Utf8Encoding); case "us-ascii": return(Encoding.ASCII); } } } Log.Warning("Assuming default UTF-8, Could not find an encoding for: {0}", contentType); return(Utf8Encoding); }
private static Scope CreateScope(object wireProtocol, object connection) { if (!Tracer.Instance.Settings.IsIntegrationEnabled(IntegrationId)) { // integration disabled, don't create a scope, skip this trace return(null); } string databaseName = null; string host = null; string port = null; try { if (wireProtocol.TryGetFieldValue("_databaseNamespace", out object databaseNamespace)) { databaseNamespace?.TryGetPropertyValue("DatabaseName", out databaseName); } } catch (Exception ex) { Log.Warning(ex, "Unable to access DatabaseName property."); } try { if (connection != null && connection.TryGetPropertyValue("EndPoint", out object endpoint)) { if (endpoint is IPEndPoint ipEndPoint) { host = ipEndPoint.Address.ToString(); port = ipEndPoint.Port.ToString(); } else if (endpoint is DnsEndPoint dnsEndPoint) { host = dnsEndPoint.Host; port = dnsEndPoint.Port.ToString(); } } } catch (Exception ex) { Log.Warning(ex, "Unable to access EndPoint properties."); } string operationName = null; string collectionName = null; string query = null; string resourceName = null; try { if (wireProtocol.TryGetFieldValue("_command", out object command) && command != null) { // the name of the first element in the command BsonDocument will be the operation type (insert, delete, find, etc) // and its value is the collection name if (command.TryCallMethod("GetElement", 0, out object firstElement) && firstElement != null) { firstElement.TryGetPropertyValue("Name", out operationName); if (firstElement.TryGetPropertyValue("Value", out object collectionNameObj) && collectionNameObj != null) { collectionName = collectionNameObj.ToString(); } } query = command.ToString(); resourceName = $"{operationName ?? "operation"} {databaseName ?? "database"}"; } } catch (Exception ex) { Log.Warning(ex, "Unable to access IWireProtocol.Command properties."); } Tracer tracer = Tracer.Instance; string serviceName = tracer.Settings.GetServiceName(tracer, ServiceName); Scope scope = null; try { var tags = new MongoDbTags(); scope = tracer.StartActiveWithTags(OperationName, serviceName: serviceName, tags: tags); var span = scope.Span; span.Type = SpanTypes.MongoDb; span.ResourceName = resourceName; tags.DbName = databaseName; tags.Query = query; tags.Collection = collectionName; tags.Host = host; tags.Port = port; tags.SetAnalyticsSampleRate(IntegrationId, tracer.Settings, enabledWithGlobalSetting: false); } catch (Exception ex) { Log.Error(ex, "Error creating or populating scope."); } return(scope); }
public static object ExecuteAsync( object apiController, object controllerContext, object boxedCancellationToken, int opCode, int mdToken, long moduleVersionPtr) { if (apiController == null) { throw new ArgumentNullException(nameof(apiController)); } var cancellationToken = (CancellationToken)boxedCancellationToken; var callOpCode = (OpCodeValue)opCode; var httpControllerType = apiController.GetInstrumentedInterface(HttpControllerTypeName); Type taskResultType; try { var request = controllerContext.GetProperty <object>("Request").GetValueOrDefault(); var httpRequestMessageType = request.GetInstrumentedType("System.Net.Http.HttpRequestMessage"); // The request should never be null, so get the base type found in System.Net.Http.dll if (httpRequestMessageType != null) { var systemNetHttpAssembly = httpRequestMessageType.Assembly; taskResultType = systemNetHttpAssembly.GetType("System.Net.Http.HttpResponseMessage", true); } // This should never happen, but put in a reasonable fallback of finding the first System.Net.Http.dll in the AppDomain else { Log.Warning($"{nameof(AspNetWebApi2Integration)}.{nameof(ExecuteAsync)}: Unable to find System.Net.Http.HttpResponseMessage Type from method arguments. Using fallback logic to find the Type needed for return type."); var statsd = Tracer.Instance.Statsd; statsd?.Warning(source: $"{nameof(AspNetWebApi2Integration)}.{nameof(ExecuteAsync)}", message: "Unable to find System.Net.Http.HttpResponseMessage Type from method arguments. Using fallback logic to find the Type needed for return type.", null); var systemNetHttpAssemblies = AppDomain.CurrentDomain.GetAssemblies().Where(assembly => assembly.GetName().Name.Equals("System.Net.Http", StringComparison.OrdinalIgnoreCase)); var firstSystemNetHttpAssembly = systemNetHttpAssemblies.First(); taskResultType = firstSystemNetHttpAssembly.GetType("System.Net.Http.HttpResponseMessage", true); } } catch (Exception ex) { // This shouldn't happen because the System.Net.Http assembly should have been loaded if this method was called // The profiled app will not continue working as expected without this method Log.Error(ex, "Error finding types in the user System.Net.Http assembly."); throw; } Func <object, object, CancellationToken, object> instrumentedMethod = null; try { instrumentedMethod = MethodBuilder <Func <object, object, CancellationToken, object> > .Start(moduleVersionPtr, mdToken, opCode, nameof(ExecuteAsync)) .WithConcreteType(httpControllerType) .WithParameters(controllerContext, cancellationToken) .WithNamespaceAndNameFilters( ClrNames.GenericTask, HttpControllerContextTypeName, ClrNames.CancellationToken) .Build(); } catch (Exception ex) { Log.ErrorRetrievingMethod( exception: ex, moduleVersionPointer: moduleVersionPtr, mdToken: mdToken, opCode: opCode, instrumentedType: HttpControllerTypeName, methodName: nameof(ExecuteAsync), instanceType: apiController.GetType().AssemblyQualifiedName); throw; } return(AsyncHelper.InvokeGenericTaskDelegate( owningType: apiController.GetType(), taskResultType: taskResultType, nameOfIntegrationMethod: nameof(ExecuteAsyncInternal), integrationType: typeof(AspNetWebApi2Integration), instrumentedMethod, apiController, controllerContext, cancellationToken)); }
internal Tracer(TracerSettings settings, IAgentWriter agentWriter, ISampler sampler, IScopeManager scopeManager, IStatsd statsd) { // update the count of Tracer instances Interlocked.Increment(ref _liveTracerCount); Settings = settings ?? TracerSettings.FromDefaultSources(); // if not configured, try to determine an appropriate service name DefaultServiceName = Settings.ServiceName ?? GetApplicationName() ?? UnknownServiceName; // only set DogStatsdClient if tracer metrics are enabled if (Settings.TracerMetricsEnabled) { // Run this first in case the port override is ready TracingProcessManager.SubscribeToDogStatsDPortOverride( port => { Log.Debug("Attempting to override dogstatsd port with {0}", port); Statsd = CreateDogStatsdClient(Settings, DefaultServiceName, port); }); Statsd = statsd ?? CreateDogStatsdClient(Settings, DefaultServiceName, Settings.DogStatsdPort); } // Run this first in case the port override is ready TracingProcessManager.SubscribeToTraceAgentPortOverride( port => { Log.Debug("Attempting to override trace agent port with {0}", port); var builder = new UriBuilder(Settings.AgentUri) { Port = port }; var baseEndpoint = builder.Uri; IApi overridingApiClient = new Api(baseEndpoint, delegatingHandler: null, Statsd); if (_agentWriter == null) { _agentWriter = _agentWriter ?? new AgentWriter(overridingApiClient, Statsd); } else { _agentWriter.OverrideApi(overridingApiClient); } }); // fall back to default implementations of each dependency if not provided _agentWriter = agentWriter ?? new AgentWriter(new Api(Settings.AgentUri, delegatingHandler: null, Statsd), Statsd); _scopeManager = scopeManager ?? new AsyncLocalScopeManager(); Sampler = sampler ?? new RuleBasedSampler(new RateLimiter(Settings.MaxTracesSubmittedPerSecond)); if (!string.IsNullOrWhiteSpace(Settings.CustomSamplingRules)) { // User has opted in, ensure rate limiter is used RuleBasedSampler.OptInTracingWithoutLimits(); foreach (var rule in CustomSamplingRule.BuildFromConfigurationString(Settings.CustomSamplingRules)) { Sampler.RegisterRule(rule); } } if (Settings.GlobalSamplingRate != null) { var globalRate = (float)Settings.GlobalSamplingRate; if (globalRate < 0f || globalRate > 1f) { Log.Warning("{0} configuration of {1} is out of range", ConfigurationKeys.GlobalSamplingRate, Settings.GlobalSamplingRate); } else { Sampler.RegisterRule(new GlobalSamplingRule(globalRate)); } } // Register callbacks to make sure we flush the traces before exiting AppDomain.CurrentDomain.ProcessExit += CurrentDomain_ProcessExit; AppDomain.CurrentDomain.DomainUnload += CurrentDomain_DomainUnload; AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException; Console.CancelKeyPress += Console_CancelKeyPress; // start the heartbeat loop _heartbeatTimer = new Timer(HeartbeatCallback, state: null, dueTime: TimeSpan.Zero, period: TimeSpan.FromMinutes(1)); // If configured, add/remove the correlation identifiers into the // LibLog logging context when a scope is activated/closed if (Settings.LogsInjectionEnabled) { InitializeLibLogScopeEventSubscriber(_scopeManager, DefaultServiceName, Settings.ServiceVersion, Settings.Environment); } }
internal static DynamicMethod CreateAsyncEndMethodDelegate(Type integrationType, Type targetType, Type returnType) { /* * OnAsyncMethodEnd signatures with 3 or 4 parameters with 1 or 2 generics: * - TReturn OnAsyncMethodEnd<TTarget, TReturn>(TTarget instance, TReturn returnValue, Exception exception, CallTargetState state); * - TReturn OnAsyncMethodEnd<TTarget, TReturn>(TReturn returnValue, Exception exception, CallTargetState state); * - [Type] OnAsyncMethodEnd<TTarget>([Type] returnValue, Exception exception, CallTargetState state); * * In case the continuation is for a Task/ValueTask, the returnValue type will be an object and the value null. * In case the continuation is for a Task<T>/ValueTask<T>, the returnValue type will be T with the instance value after the task completes. * */ Log.Debug($"Creating AsyncEndMethod Dynamic Method for '{integrationType.FullName}' integration. [Target={targetType.FullName}, ReturnType={returnType.FullName}]"); MethodInfo onAsyncMethodEndMethodInfo = integrationType.GetMethod(EndAsyncMethodName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static); if (onAsyncMethodEndMethodInfo is null) { Log.Warning($"Couldn't find the method: {EndAsyncMethodName} in type: {integrationType.FullName}"); return(null); } if (!onAsyncMethodEndMethodInfo.ReturnType.IsGenericParameter && onAsyncMethodEndMethodInfo.ReturnType != returnType) { throw new ArgumentException($"The return type of the method: {EndAsyncMethodName} in type: {integrationType.FullName} is not {returnType}"); } Type[] genericArgumentsTypes = onAsyncMethodEndMethodInfo.GetGenericArguments(); if (genericArgumentsTypes.Length < 1 || genericArgumentsTypes.Length > 2) { throw new ArgumentException($"The method: {EndAsyncMethodName} in type: {integrationType.FullName} must have the generic type for the instance type."); } ParameterInfo[] onAsyncMethodEndParameters = onAsyncMethodEndMethodInfo.GetParameters(); if (onAsyncMethodEndParameters.Length < 3) { throw new ArgumentException($"The method: {EndAsyncMethodName} with {onAsyncMethodEndParameters.Length} parameters in type: {integrationType.FullName} has less parameters than required."); } else if (onAsyncMethodEndParameters.Length > 4) { throw new ArgumentException($"The method: {EndAsyncMethodName} with {onAsyncMethodEndParameters.Length} parameters in type: {integrationType.FullName} has more parameters than required."); } if (onAsyncMethodEndParameters[onAsyncMethodEndParameters.Length - 2].ParameterType != typeof(Exception)) { throw new ArgumentException($"The Exception type parameter of the method: {EndAsyncMethodName} in type: {integrationType.FullName} is missing."); } if (onAsyncMethodEndParameters[onAsyncMethodEndParameters.Length - 1].ParameterType != typeof(CallTargetState)) { throw new ArgumentException($"The CallTargetState type parameter of the method: {EndAsyncMethodName} in type: {integrationType.FullName} is missing."); } List <Type> callGenericTypes = new List <Type>(); bool mustLoadInstance = onAsyncMethodEndParameters.Length == 4; Type instanceGenericType = genericArgumentsTypes[0]; Type instanceGenericConstraint = instanceGenericType.GetGenericParameterConstraints().FirstOrDefault(); Type instanceProxyType = null; if (instanceGenericConstraint != null) { var result = DuckType.GetOrCreateProxyType(instanceGenericConstraint, targetType); instanceProxyType = result.ProxyType; callGenericTypes.Add(instanceProxyType); } else { callGenericTypes.Add(targetType); } int returnParameterIndex = onAsyncMethodEndParameters.Length == 4 ? 1 : 0; bool isAGenericReturnValue = onAsyncMethodEndParameters[returnParameterIndex].ParameterType.IsGenericParameter; Type returnValueGenericType = null; Type returnValueGenericConstraint = null; Type returnValueProxyType = null; if (isAGenericReturnValue) { returnValueGenericType = genericArgumentsTypes[1]; returnValueGenericConstraint = returnValueGenericType.GetGenericParameterConstraints().FirstOrDefault(); if (returnValueGenericConstraint != null) { var result = DuckType.GetOrCreateProxyType(returnValueGenericConstraint, returnType); returnValueProxyType = result.ProxyType; callGenericTypes.Add(returnValueProxyType); } else { callGenericTypes.Add(returnType); } } else if (onAsyncMethodEndParameters[returnParameterIndex].ParameterType != returnType) { throw new ArgumentException($"The ReturnValue type parameter of the method: {EndAsyncMethodName} in type: {integrationType.FullName} is invalid. [{onAsyncMethodEndParameters[returnParameterIndex].ParameterType} != {returnType}]"); } DynamicMethod callMethod = new DynamicMethod( $"{onAsyncMethodEndMethodInfo.DeclaringType.Name}.{onAsyncMethodEndMethodInfo.Name}.{targetType.Name}.{returnType.Name}", returnType, new Type[] { targetType, returnType, typeof(Exception), typeof(CallTargetState) }, onAsyncMethodEndMethodInfo.Module, true); ILGenerator ilWriter = callMethod.GetILGenerator(); // Load the instance if is needed if (mustLoadInstance) { ilWriter.Emit(OpCodes.Ldarg_0); if (instanceGenericConstraint != null) { WriteCreateNewProxyInstance(ilWriter, instanceProxyType, targetType); } } // Load the return value ilWriter.Emit(OpCodes.Ldarg_1); if (returnValueProxyType != null) { WriteCreateNewProxyInstance(ilWriter, returnValueProxyType, returnType); } // Load the exception ilWriter.Emit(OpCodes.Ldarg_2); // Load the state ilWriter.Emit(OpCodes.Ldarg_3); // Call Method onAsyncMethodEndMethodInfo = onAsyncMethodEndMethodInfo.MakeGenericMethod(callGenericTypes.ToArray()); ilWriter.EmitCall(OpCodes.Call, onAsyncMethodEndMethodInfo, null); // Unwrap return value proxy if (returnValueProxyType != null) { MethodInfo unwrapReturnValue = UnwrapReturnValueMethodInfo.MakeGenericMethod(returnValueProxyType, returnType); ilWriter.EmitCall(OpCodes.Call, unwrapReturnValue, null); } ilWriter.Emit(OpCodes.Ret); Log.Debug($"Created AsyncEndMethod Dynamic Method for '{integrationType.FullName}' integration. [Target={targetType.FullName}, ReturnType={returnType.FullName}]"); return(callMethod); }
internal Tracer(TracerSettings settings, IAgentWriter agentWriter, ISampler sampler, IScopeManager scopeManager, IDogStatsd statsd) { // update the count of Tracer instances Interlocked.Increment(ref _liveTracerCount); Settings = settings ?? TracerSettings.FromDefaultSources(); // if not configured, try to determine an appropriate service name DefaultServiceName = Settings.ServiceName ?? GetApplicationName() ?? UnknownServiceName; // only set DogStatsdClient if tracer metrics are enabled if (Settings.TracerMetricsEnabled) { // Run this first in case the port override is ready TracingProcessManager.SubscribeToDogStatsDPortOverride( port => { Log.Debug("Attempting to override dogstatsd port with {0}", port); Statsd = CreateDogStatsdClient(Settings, DefaultServiceName, port); }); Statsd = statsd ?? CreateDogStatsdClient(Settings, DefaultServiceName, Settings.DogStatsdPort); } // Run this first in case the port override is ready TracingProcessManager.SubscribeToTraceAgentPortOverride( port => { Log.Debug("Attempting to override trace agent port with {0}", port); var builder = new UriBuilder(Settings.AgentUri) { Port = port }; var baseEndpoint = builder.Uri; if (_agentWriter == null) { IApi overridingApiClient = new Api(baseEndpoint, apiRequestFactory: null, Statsd); _agentWriter = _agentWriter ?? new AgentWriter(overridingApiClient, Statsd, queueSize: Settings.TraceQueueSize); } else { _agentWriter.SetApiBaseEndpoint(baseEndpoint); } }); // fall back to default implementations of each dependency if not provided _agentWriter = agentWriter ?? new AgentWriter(new Api(Settings.AgentUri, apiRequestFactory: null, Statsd), Statsd, queueSize: Settings.TraceQueueSize); _scopeManager = scopeManager ?? new AsyncLocalScopeManager(); Sampler = sampler ?? new RuleBasedSampler(new RateLimiter(Settings.MaxTracesSubmittedPerSecond)); if (!string.IsNullOrWhiteSpace(Settings.CustomSamplingRules)) { foreach (var rule in CustomSamplingRule.BuildFromConfigurationString(Settings.CustomSamplingRules)) { Sampler.RegisterRule(rule); } } if (Settings.GlobalSamplingRate != null) { var globalRate = (float)Settings.GlobalSamplingRate; if (globalRate < 0f || globalRate > 1f) { Log.Warning("{0} configuration of {1} is out of range", ConfigurationKeys.GlobalSamplingRate, Settings.GlobalSamplingRate); } else { Sampler.RegisterRule(new GlobalSamplingRule(globalRate)); } } // Register callbacks to make sure we flush the traces before exiting AppDomain.CurrentDomain.ProcessExit += CurrentDomain_ProcessExit; AppDomain.CurrentDomain.DomainUnload += CurrentDomain_DomainUnload; try { // Registering for the AppDomain.UnhandledException event cannot be called by a security transparent method // This will only happen if the Tracer is not run full-trust AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException; } catch (Exception ex) { Log.Warning(ex, "Unable to register a callback to the AppDomain.UnhandledException event."); } try { // Registering for the cancel key press event requires the System.Security.Permissions.UIPermission Console.CancelKeyPress += Console_CancelKeyPress; } catch (Exception ex) { Log.Warning(ex, "Unable to register a callback to the Console.CancelKeyPress event."); } // start the heartbeat loop _heartbeatTimer = new Timer(HeartbeatCallback, state: null, dueTime: TimeSpan.Zero, period: TimeSpan.FromMinutes(1)); // If configured, add/remove the correlation identifiers into the // LibLog logging context when a scope is activated/closed if (Settings.LogsInjectionEnabled) { InitializeLibLogScopeEventSubscriber(_scopeManager, DefaultServiceName, Settings.ServiceVersion, Settings.Environment); } if (Interlocked.Exchange(ref _firstInitialization, 0) == 1) { if (Settings.StartupDiagnosticLogEnabled) { _ = WriteDiagnosticLog(); } if (Settings.RuntimeMetricsEnabled) { _runtimeMetricsWriter = new RuntimeMetricsWriter(Statsd ?? CreateDogStatsdClient(Settings, DefaultServiceName, Settings.DogStatsdPort), 10000); } } }
public static IEnumerable <RegexSamplingRule> BuildFromConfigurationString(string configuration) { if (!string.IsNullOrEmpty(configuration)) { var ruleStrings = configuration.Split(new[] { ";", ":" }, StringSplitOptions.RemoveEmptyEntries); var index = 0; foreach (var ruleString in ruleStrings) { index++; var ruleParts = ruleString.Split(new[] { "," }, StringSplitOptions.RemoveEmptyEntries); var rateSet = false; float rate = 0; string serviceNameRegex = null, operationNameRegex = null, ruleName = $"config_rule_{index}"; foreach (var rulePart in ruleParts) { var kvp = rulePart.Split(new[] { "=" }, StringSplitOptions.None); if (kvp.Length != 2 || string.IsNullOrWhiteSpace(kvp[0]) || string.IsNullOrWhiteSpace(kvp[1])) { Log.Warning("Rule {0} is malformed, skipping.", ruleName); continue; } var key = kvp[0].Trim(); var value = kvp[1].Trim(); if (key.Equals("rate", StringComparison.OrdinalIgnoreCase) && float.TryParse(value, out rate)) { if (rate < 0 || rate > 1) { // invalid rate Log.Warning("Invalid rate {0} specified for sampling rule {1}, skipping.", rate, ruleName); break; } rateSet = true; } else if (key.Equals("service", StringComparison.OrdinalIgnoreCase)) { serviceNameRegex = WrapWithLineCharacters(value); } else if (key.Equals("operation", StringComparison.OrdinalIgnoreCase)) { operationNameRegex = WrapWithLineCharacters(value); } else if (key.Equals("name", StringComparison.OrdinalIgnoreCase)) { ruleName = value; } } if (rateSet == false) { // Need a valid rate to be set to use a rule Log.Warning("Rule {0} is missing the required rate, skipping.", ruleName); continue; } yield return(new RegexSamplingRule( rate: rate, name: ruleName, serviceNameRegex: serviceNameRegex, operationNameRegex: operationNameRegex)); } } }
private static Scope CreateScope(object wireProtocol, object connection) { if (!Tracer.Instance.Settings.IsIntegrationEnabled(IntegrationName)) { // integration disabled, don't create a scope, skip this trace return(null); } string databaseName = null; string host = null; string port = null; try { if (wireProtocol.TryGetFieldValue("_databaseNamespace", out object databaseNamespace)) { databaseNamespace?.TryGetPropertyValue("DatabaseName", out databaseName); } } catch (Exception ex) { Log.Warning(ex, "Unable to access DatabaseName property."); } try { if (connection != null && connection.TryGetPropertyValue("EndPoint", out object endpoint)) { if (endpoint is IPEndPoint ipEndPoint) { host = ipEndPoint.Address.ToString(); port = ipEndPoint.Port.ToString(); } else if (endpoint is DnsEndPoint dnsEndPoint) { host = dnsEndPoint.Host; port = dnsEndPoint.Port.ToString(); } } } catch (Exception ex) { Log.Warning(ex, "Unable to access EndPoint properties."); } string operationName = null; string collectionName = null; string query = null; string resourceName = null; try { if (wireProtocol.TryGetFieldValue("_command", out object command) && command != null) { // the name of the first element in the command BsonDocument will be the operation type (insert, delete, find, etc) // and its value is the collection name if (command.TryCallMethod("GetElement", 0, out object firstElement) && firstElement != null) { firstElement.TryGetPropertyValue("Name", out operationName); if (firstElement.TryGetPropertyValue("Value", out object collectionNameObj) && collectionNameObj != null) { collectionName = collectionNameObj.ToString(); } } // get the "query" element from the command BsonDocument, if it exists if (command.TryCallMethod("Contains", "query", out bool found) && found) { if (command.TryCallMethod("GetElement", "query", out object queryElement) && queryElement != null) { if (queryElement.TryGetPropertyValue("Value", out object queryValue) && queryValue != null) { query = queryValue.ToString(); } } } resourceName = $"{operationName ?? "operation"} {databaseName ?? "database"} {query ?? "query"}"; } } catch (Exception ex) { Log.Warning(ex, "Unable to access IWireProtocol.Command properties."); } Tracer tracer = Tracer.Instance; string serviceName = string.Join("-", tracer.DefaultServiceName, ServiceName); Scope scope = null; try { scope = tracer.StartActive(OperationName, serviceName: serviceName); var span = scope.Span; span.Type = SpanTypes.MongoDb; span.ResourceName = resourceName; span.SetTag(Tags.DbName, databaseName); span.SetTag(Tags.MongoDbQuery, query); span.SetTag(Tags.MongoDbCollection, collectionName); span.SetTag(Tags.OutHost, host); span.SetTag(Tags.OutPort, port); // set analytics sample rate if enabled var analyticsSampleRate = tracer.Settings.GetIntegrationAnalyticsSampleRate(IntegrationName, enabledWithGlobalSetting: false); span.SetMetric(Tags.Analytics, analyticsSampleRate); } catch (Exception ex) { Log.Error(ex, "Error creating or populating scope."); } return(scope); }
protected override void OnEventWritten(EventWrittenEventArgs eventData) { if (_statsd == null) { // I know it sounds crazy at first, but because OnEventSourceCreated is called from the base constructor, // and EnableEvents is called from OnEventSourceCreated, it's entirely possible that OnEventWritten // gets called before the child constructor is called. // In that case, just bail out. return; } try { if (eventData.EventId == EventGcSuspendBegin) { _gcStart = eventData.TimeStamp; } else if (eventData.EventId == EventGcRestartEnd) { var start = _gcStart; if (start != null) { _statsd.Timer(MetricsNames.GcPauseTime, (eventData.TimeStamp - start.Value).TotalMilliseconds); } } else { if (eventData.EventId == EventGcHeapStats) { var stats = HeapStats.FromPayload(eventData.Payload); _statsd.Gauge(MetricsNames.Gen0HeapSize, stats.Gen0Size); _statsd.Gauge(MetricsNames.Gen1HeapSize, stats.Gen1Size); _statsd.Gauge(MetricsNames.Gen2HeapSize, stats.Gen2Size); _statsd.Gauge(MetricsNames.LohSize, stats.LohSize); } else if (eventData.EventId == EventContentionStop) { var durationInNanoseconds = (double)eventData.Payload[2]; _contentionTime.Time(durationInNanoseconds / 1_000_000); Interlocked.Increment(ref _contentionCount); } else if (eventData.EventId == EventGcGlobalHeapHistory) { var heapHistory = HeapHistory.FromPayload(eventData.Payload); if (heapHistory.MemoryLoad != null) { _statsd.Gauge(MetricsNames.GcMemoryLoad, heapHistory.MemoryLoad.Value); } _statsd.Increment(GcCountMetricNames[heapHistory.Generation], 1, tags: heapHistory.Compacting ? CompactingGcTags : NotCompactingGcTags); } } } catch (Exception ex) { Log.Warning(ex, "Error while processing event {0} {1}", eventData.EventId, eventData.EventName); } }