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); }
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); }
/// <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"); } }