public static int Main(string[] args) { // The library we want to run was built and copied to the ApplicationFiles subdirectory // Create an AppDomain with that directory as the appBasePath var entryDirectory = Directory.GetParent(Assembly.GetEntryAssembly().Location); var applicationFilesDirectory = Path.Combine(entryDirectory.FullName, "ApplicationFiles"); var applicationAppDomain = AppDomain.CreateDomain("ApplicationAppDomain", null, applicationFilesDirectory, applicationFilesDirectory, false); try { // Test that when transition back to this AppDomain, there are no serialization problems // This would happen if any values were stored in data slots Console.WriteLine("Calling the ApplicationWithLog4Net.Program in a separate AppDomain"); AppDomainProxy.Call(applicationAppDomain, "ApplicationWithLog4Net", "ApplicationWithLog4Net.Program", "Invoke", null); AppDomain.Unload(applicationAppDomain); } catch (Exception ex) { Console.Error.WriteLine(ex); return((int)ExitCode.UnknownError); } #if NETCOREAPP2_1 // Add a delay to avoid a race condition on shutdown: https://github.com/dotnet/coreclr/pull/22712 // This would cause a segmentation fault on .net core 2.x System.Threading.Thread.Sleep(5000); #endif return((int)ExitCode.Success); }
public static int RunLoggingProcedure(Action <string> logAction) { #if NETFRAMEWORK // Set up the secondary AppDomain first // The plugin application we'll call was built and copied to the ApplicationFiles subdirectory // Create an AppDomain with that directory as the appBasePath var entryDirectory = Directory.GetParent(Assembly.GetEntryAssembly().Location); var applicationFilesDirectory = Path.Combine(entryDirectory.FullName, "ApplicationFiles"); var applicationAppDomain = AppDomain.CreateDomain("ApplicationAppDomain", null, applicationFilesDirectory, applicationFilesDirectory, false); #endif // Set up Tracer and start a trace // Do not explicitly set LogsInjectionEnabled = true, use DD_LOGS_INJECTION environment variable to enable var settings = TracerSettings.FromDefaultSources(); settings.Environment ??= "dev"; // Ensure that we have an env value. In CI, this will automatically be assigned. Later we can test that everything is fine when Environment=null settings.ServiceVersion ??= "1.0.0"; // Ensure that we have an env value. In CI, this will automatically be assigned. Later we can test that everything is fine when when ServiceVersion=null Tracer.Configure(settings); try { logAction($"{ExcludeMessagePrefix}Entering Datadog scope."); using (var scope = Tracer.Instance.StartActive("transaction")) { // In the middle of the trace, make a call across AppDomains // Unless handled properly, this can cause the following error due // to the way log4net stores "AsyncLocal" state in the // System.Runtime.Remoting.Messaging.CallContext: // System.Runtime.Serialization.SerializationException: Type is not resolved for member 'log4net.Util.PropertiesDictionary,log4net, Version=2.0.12.0, Culture=neutral, PublicKeyToken=669e0ddf0bb1aa2a'. #if NETFRAMEWORK logAction("Calling the PluginApplication.Program in a separate AppDomain"); AppDomainProxy.Call(applicationAppDomain, "PluginApplication", "PluginApplication.Program", "Invoke", null); #else logAction("Skipping the cross-AppDomain call on .NET Core"); #endif } logAction($"{ExcludeMessagePrefix}Exited Datadog scope."); #if NETFRAMEWORK AppDomain.Unload(applicationAppDomain); #endif } catch (Exception ex) { Console.Error.WriteLine(ex); return((int)ExitCode.UnknownError); } #if NETCOREAPP2_1 // Add a delay to avoid a race condition on shutdown: https://github.com/dotnet/coreclr/pull/22712 // This would cause a segmentation fault on .net core 2.x System.Threading.Thread.Sleep(5000); #endif return((int)ExitCode.Success); }