private static Assembly AssemblyResolve_ManagedProfilerDependencies(object sender, ResolveEventArgs args)
        {
            var assemblyName = new AssemblyName(args.Name);

            // On .NET Framework, having a non-US locale can cause mscorlib
            // to enter the AssemblyResolve event when searching for resources
            // in its satellite assemblies. This seems to have been fixed in
            // .NET Core in the 2.0 servicing branch, so we should not see this
            // occur, but guard against it anyways. If we do see it, exit early
            // so we don't cause infinite recursion.
            if (string.Equals(assemblyName.Name, "System.Private.CoreLib.resources", StringComparison.OrdinalIgnoreCase) ||
                string.Equals(assemblyName.Name, "System.Net.Http", StringComparison.OrdinalIgnoreCase))
            {
                return(null);
            }

            var path = Path.Combine(ManagedProfilerDirectory, $"{assemblyName.Name}.dll");

            // Only load the main profiler into the default Assembly Load Context.
            // If Datadog.Trace or other libraries are provided by the NuGet package their loads are handled in the following two ways.
            // 1) The AssemblyVersion is greater than or equal to the version used by Datadog.Trace, the assembly
            //    will load successfully and will not invoke this resolve event.
            // 2) The AssemblyVersion is lower than the version used by Datadog.Trace, the assembly will fail to load
            //    and invoke this resolve event. It must be loaded in a separate AssemblyLoadContext since the application will only
            //    load the originally referenced version
            if (File.Exists(path))
            {
                StartupLogger.Debug("Loading {0} with DependencyLoadContext.LoadFromAssemblyPath", path);
                return(DependencyLoadContext.LoadFromAssemblyPath(path)); // Load unresolved framework and third-party dependencies into a custom Assembly Load Context
            }

            return(null);
        }
        private static string ResolveManagedProfilerDirectory()
        {
            string tracerFrameworkDirectory = "netstandard2.0";

            var version = Environment.Version;

            // Old versions of .net core have a major version of 4
            if ((version.Major == 3 && version.Minor >= 1) || version.Major >= 5)
            {
                tracerFrameworkDirectory = "netcoreapp3.1";
            }

            var tracerHomeDirectory = ReadEnvironmentVariable("DD_DOTNET_TRACER_HOME") ?? string.Empty;
            var fullPath            = Path.Combine(tracerHomeDirectory, tracerFrameworkDirectory);

            // We use the List/Array approach due the number of files in the tracer home folder (7 in netstandard, 2 netcoreapp3.1)
            var assemblies = new List <CachedAssembly>();

            foreach (var file in Directory.EnumerateFiles(fullPath, "*.dll", SearchOption.TopDirectoryOnly))
            {
                assemblies.Add(new CachedAssembly(file, null));
            }

            _assemblies = assemblies.ToArray();
            StartupLogger.Debug("Total number of assemblies: {0}", _assemblies.Length);

            return(fullPath);
        }
        private static Assembly ResolveAssembly(string name)
        {
            var assemblyName = new AssemblyName(name);

            StartupLogger.Debug("Assembly Resolve event received for: {0}", name);

            // On .NET Framework, having a non-US locale can cause mscorlib
            // to enter the AssemblyResolve event when searching for resources
            // in its satellite assemblies. Exit early so we don't cause
            // infinite recursion.
            if (string.Equals(assemblyName.Name, "mscorlib.resources", StringComparison.OrdinalIgnoreCase) ||
                string.Equals(assemblyName.Name, "System.Net.Http", StringComparison.OrdinalIgnoreCase))
            {
                return(null);
            }

            var path = Path.Combine(ManagedProfilerDirectory, $"{assemblyName.Name}.dll");

            StartupLogger.Debug("Looking for: {0}", path);

            if (File.Exists(path))
            {
                if (name.StartsWith("SignalFx.Tracing, Version=") && name != AssemblyName)
                {
                    StartupLogger.Debug("Trying to load {0} which does not match the expected version ({1}). [Path={2}]", name, AssemblyName, path);
                    return(null);
                }

                StartupLogger.Debug("Resolving {0}, loading {1}", name, path);
                return(Assembly.LoadFrom(path));
            }

            StartupLogger.Debug("Assembly not found in path: {0}", path);
            return(null);
        }
        private static Assembly AssemblyResolve_ManagedProfilerDependencies(object sender, ResolveEventArgs args)
        {
            var assemblyName = new AssemblyName(args.Name);

            // On .NET Framework, having a non-US locale can cause mscorlib
            // to enter the AssemblyResolve event when searching for resources
            // in its satellite assemblies. This seems to have been fixed in
            // .NET Core in the 2.0 servicing branch, so we should not see this
            // occur, but guard against it anyways. If we do see it, exit early
            // so we don't cause infinite recursion.
            if (string.Equals(assemblyName.Name, "System.Private.CoreLib.resources", StringComparison.OrdinalIgnoreCase) ||
                string.Equals(assemblyName.Name, "System.Net.Http", StringComparison.OrdinalIgnoreCase))
            {
                return(null);
            }

            var path = Path.Combine(ManagedProfilerDirectory, $"{assemblyName.Name}.dll");

            if (assemblyName.Name.StartsWith("Datadog.Trace", StringComparison.OrdinalIgnoreCase) &&
                assemblyName.FullName.IndexOf("PublicKeyToken=def86d061d0d2eeb", StringComparison.OrdinalIgnoreCase) >= 0 &&
                File.Exists(path))
            {
                StartupLogger.Debug("Loading {0} with Assembly.LoadFrom", path);
                return(Assembly.LoadFrom(path)); // Load the main profiler and tracer into the default Assembly Load Context
            }
            else if (File.Exists(path))
            {
                StartupLogger.Debug("Loading {0} with DependencyLoadContext.LoadFromAssemblyPath", path);
                return(DependencyLoadContext.LoadFromAssemblyPath(path)); // Load unresolved framework and third-party dependencies into a custom Assembly Load Context
            }

            return(null);
        }
Esempio n. 5
0
        private static Assembly AssemblyResolve_ManagedProfilerDependencies(object sender, ResolveEventArgs args)
        {
            var assemblyName = new AssemblyName(args.Name).Name;

            // On .NET Framework, having a non-US locale can cause mscorlib
            // to enter the AssemblyResolve event when searching for resources
            // in its satellite assemblies. Exit early so we don't cause
            // infinite recursion.
            if (string.Equals(assemblyName, "mscorlib.resources", StringComparison.OrdinalIgnoreCase) ||
                string.Equals(assemblyName, "System.Net.Http", StringComparison.OrdinalIgnoreCase))
            {
                return(null);
            }

            var path = Path.Combine(ManagedProfilerDirectory, $"{assemblyName}.dll");

            if (File.Exists(path))
            {
                if (args.Name.StartsWith("Datadog.Trace, Version=") && args.Name != AssemblyName)
                {
                    StartupLogger.Debug("Trying to load {0} which does not match the expected version ({1})", args.Name, AssemblyName);
                    return(null);
                }

                StartupLogger.Debug("Resolving {0}, loading {1}", args.Name, path);
                return(Assembly.LoadFrom(path));
            }

            return(null);
        }
Esempio n. 6
0
        private static string ReadEnvironmentVariable(string key)
        {
            try
            {
                return(Environment.GetEnvironmentVariable(key));
            }
            catch (Exception ex)
            {
                StartupLogger.Log(ex, "Error while loading environment variable " + key);
            }

            return(null);
        }
Esempio n. 7
0
        /// <summary>
        /// Initializes static members of the <see cref="Startup"/> class.
        /// This method also attempts to load the Datadog.Trace.ClrProfiler.Managed .NET assembly.
        /// </summary>
        static Startup()
        {
            ManagedProfilerDirectory = ResolveManagedProfilerDirectory();

            try
            {
                AppDomain.CurrentDomain.AssemblyResolve += AssemblyResolve_ManagedProfilerDependencies;
            }
            catch (Exception ex)
            {
                StartupLogger.Log(ex, "Unable to register a callback to the CurrentDomain.AssemblyResolve event.");
            }

            TryLoadManagedAssembly();
        }
Esempio n. 8
0
        private static void TryInvokeManagedMethod(string typeName, string methodName)
        {
            try
            {
                var assembly = Assembly.Load(AssemblyName);

                if (assembly != null)
                {
                    var type   = assembly.GetType(typeName, throwOnError: false);
                    var method = type?.GetRuntimeMethod(methodName, parameters: Type.EmptyTypes);
                    method?.Invoke(obj: null, parameters: null);
                }
            }
            catch (Exception ex)
            {
                StartupLogger.Log(ex, "Error when invoking managed method: {0}.{1}", typeName, methodName);
            }
        }
Esempio n. 9
0
        private static void TryLoadManagedAssembly()
        {
            try
            {
                var assembly = Assembly.Load("Datadog.Trace.ClrProfiler.Managed, Version=1.26.3.0, Culture=neutral, PublicKeyToken=def86d061d0d2eeb");

                if (assembly != null)
                {
                    // call method Datadog.Trace.ClrProfiler.Instrumentation.Initialize()
                    var type   = assembly.GetType("Datadog.Trace.ClrProfiler.Instrumentation", throwOnError: false);
                    var method = type?.GetRuntimeMethod("Initialize", parameters: new Type[0]);
                    method?.Invoke(obj: null, parameters: null);
                }
            }
            catch (Exception ex)
            {
                StartupLogger.Log(ex, "Error when loading managed assemblies.");
            }
        }
Esempio n. 10
0
        private static Assembly LoadAssembly(string assemblyString)
        {
            try
            {
                return(Assembly.Load(assemblyString));
            }
            catch (FileNotFoundException ex)
            {
                // In some IIS scenarios the `AssemblyResolve` event doesn't get triggered and we received this exception.
                // We will try to resolve it manually as a last chance.
                StartupLogger.Log(ex, "Error on assembly load: {0}, Trying to solve it manually...", assemblyString);

                var assembly = ResolveAssembly(assemblyString);
                if (assembly is not null)
                {
                    StartupLogger.Log("Assembly resolved manually.");
                }

                return(assembly);
            }
        }
Esempio n. 11
0
        private static void TryInvokeManagedMethod(string typeName, string methodName)
        {
            try
            {
                var assembly = LoadAssembly(AssemblyName);

                if (assembly == null)
                {
                    StartupLogger.Log("Assembly '{0}' cannot be loaded. The managed method ({1}.{2}) cannot be invoked", AssemblyName, typeName, methodName);
                    return;
                }

                var type   = assembly.GetType(typeName, throwOnError: false);
                var method = type?.GetRuntimeMethod(methodName, parameters: Type.EmptyTypes);
                method?.Invoke(obj: null, parameters: null);
            }
            catch (Exception ex)
            {
                StartupLogger.Log(ex, "Error when invoking managed method: {0}.{1}", typeName, methodName);
            }
        }
Esempio n. 12
0
        /// <summary>
        /// Initializes static members of the <see cref="Startup"/> class.
        /// This method also attempts to load the SignalFx.TracingTrace .NET assembly.
        /// </summary>
        static Startup()
        {
            ManagedProfilerDirectory = ResolveManagedProfilerDirectory();
            StartupLogger.Debug("Resolving managed profiler directory to: {0}", ManagedProfilerDirectory);

            try
            {
                AppDomain.CurrentDomain.AssemblyResolve += AssemblyResolve_ManagedProfilerDependencies;
            }
            catch (Exception ex)
            {
                StartupLogger.Log(ex, "Unable to register a callback to the CurrentDomain.AssemblyResolve event.");
            }

            var runInAas = ReadBooleanEnvironmentVariable(AzureAppServicesKey, false);

            if (!runInAas)
            {
                TryInvokeManagedMethod("Datadog.Trace.ClrProfiler.Instrumentation", "Initialize");
                return;
            }

            // In AAS, the loader can be used to load the tracer, the traceagent only (if only custom tracing is enabled),
            // dogstatsd or all of them.
            var customTracingEnabled  = ReadBooleanEnvironmentVariable(AasCustomTracingKey, false);
            var needsDogStatsD        = ReadBooleanEnvironmentVariable(AasCustomMetricsKey, false);
            var automaticTraceEnabled = ReadBooleanEnvironmentVariable(TraceEnabledKey, true);

            if (automaticTraceEnabled || customTracingEnabled || needsDogStatsD)
            {
                StartupLogger.Log("Invoking managed method to start external processes.");
                TryInvokeManagedMethod("Datadog.Trace.AgentProcessManager", "Initialize");
            }

            if (automaticTraceEnabled)
            {
                StartupLogger.Log("Invoking managed tracer.");
                TryInvokeManagedMethod("Datadog.Trace.ClrProfiler.Instrumentation", "Initialize");
            }
        }