Ejemplo n.º 1
0
        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));
        }
Ejemplo n.º 2
0
 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;
     }
 }
Ejemplo n.º 3
0
 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);
        }
Ejemplo n.º 5
0
        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");
            }
        }
Ejemplo n.º 6
0
        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);
        }
Ejemplo n.º 7
0
        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
        }
Ejemplo n.º 9
0
        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");
            }
        }
Ejemplo n.º 10
0
        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);
        }
Ejemplo n.º 11
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
        }
Ejemplo n.º 12
0
        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);
        }
Ejemplo n.º 13
0
        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);
        }
Ejemplo n.º 14
0
        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);
        }
Ejemplo n.º 15
0
        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));
        }
Ejemplo n.º 16
0
        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);
            }
        }
Ejemplo n.º 17
0
        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);
        }
Ejemplo n.º 18
0
        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);
                }
            }
        }
Ejemplo n.º 19
0
        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);
        }
Ejemplo n.º 21
0
        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);
            }
        }