diff --git a/.vsts/linux-build.yml b/.vsts/linux-build.yml
index 61f57ba..535bf8d 100644
--- a/.vsts/linux-build.yml
+++ b/.vsts/linux-build.yml
@@ -42,13 +42,21 @@ steps:
arguments: "--configuration Release -l trx"
- task: DotNetCoreCLI@1
- displayName: Unit Tests
+ displayName: Unit Tests for AspNetCore
continueOnError: true
inputs:
command: "test"
projects: "test/**/*AspNetCore.Tests.csproj"
arguments: "--configuration Release -l trx"
+- task: DotNetCoreCLI@1
+ displayName: Unit Tests + Func Tests for WorkerService
+ continueOnError: true
+ inputs:
+ command: "test"
+ projects: "test/**/*WorkerService.Tests.csproj"
+ arguments: "--configuration Release -l trx"
+
- task: PublishTestResults@2
inputs:
diff --git a/ApplicationInsights.AspNetCore.sln b/ApplicationInsights.AspNetCore.sln
index 4e57950..c7fe554 100644
--- a/ApplicationInsights.AspNetCore.sln
+++ b/ApplicationInsights.AspNetCore.sln
@@ -52,7 +52,16 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestApp30", "test\TestApp30
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestApp30.Tests30", "test\TestApp30.Tests\TestApp30.Tests30.csproj", "{FE9DB9A7-D9AE-4188-945C-393D70022D9A}"
EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.ApplicationInsights.WorkerService", "src\Microsoft.ApplicationInsights.WorkerService\Microsoft.ApplicationInsights.WorkerService.csproj", "{AECEE8DD-09AE-4DEA-8690-F76A37C0534B}"
+EndProject
+Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "Shared", "src\Shared\Shared.shproj", "{D56F2979-D6BC-4EF2-BB9B-4077B3290599}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.ApplicationInsights.WorkerService.Tests", "test\Microsoft.ApplicationInsights.WorkerService.Tests\Microsoft.ApplicationInsights.WorkerService.Tests.csproj", "{A41D3299-5E41-4B73-8C8E-DD64824BC9E6}"
+EndProject
Global
+ GlobalSection(SharedMSBuildProjectFiles) = preSolution
+ src\Shared\Shared.projitems*{d56f2979-d6bc-4ef2-bb9b-4077b3290599}*SharedItemsImports = 13
+ EndGlobalSection
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
@@ -110,6 +119,14 @@ Global
{FE9DB9A7-D9AE-4188-945C-393D70022D9A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{FE9DB9A7-D9AE-4188-945C-393D70022D9A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{FE9DB9A7-D9AE-4188-945C-393D70022D9A}.Release|Any CPU.Build.0 = Release|Any CPU
+ {AECEE8DD-09AE-4DEA-8690-F76A37C0534B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {AECEE8DD-09AE-4DEA-8690-F76A37C0534B}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {AECEE8DD-09AE-4DEA-8690-F76A37C0534B}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {AECEE8DD-09AE-4DEA-8690-F76A37C0534B}.Release|Any CPU.Build.0 = Release|Any CPU
+ {A41D3299-5E41-4B73-8C8E-DD64824BC9E6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {A41D3299-5E41-4B73-8C8E-DD64824BC9E6}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {A41D3299-5E41-4B73-8C8E-DD64824BC9E6}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {A41D3299-5E41-4B73-8C8E-DD64824BC9E6}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -129,6 +146,9 @@ Global
{9DA7024F-216F-4FA5-9B6D-CE4216C2DD72} = {8B5230E5-8138-44D6-839F-DF9248F195EE}
{8E71FECF-E090-409E-8551-C597F9DFB91C} = {8B5230E5-8138-44D6-839F-DF9248F195EE}
{FE9DB9A7-D9AE-4188-945C-393D70022D9A} = {8B5230E5-8138-44D6-839F-DF9248F195EE}
+ {AECEE8DD-09AE-4DEA-8690-F76A37C0534B} = {2E6DDE9E-8C75-4F9C-8906-08EBDD6E73EF}
+ {D56F2979-D6BC-4EF2-BB9B-4077B3290599} = {2E6DDE9E-8C75-4F9C-8906-08EBDD6E73EF}
+ {A41D3299-5E41-4B73-8C8E-DD64824BC9E6} = {8B5230E5-8138-44D6-839F-DF9248F195EE}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {047855A4-470F-43B1-8B74-69651DD6B8A6}
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 0fa13e5..28afbb6 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -8,9 +8,11 @@
- [Support correlation-context in absence of request-id or traceparent.](https://github.com/microsoft/ApplicationInsights-aspnetcore/issues/901)
- [Non Product - Asp.Net Core 3.0 Functional Tests Added. This leverages the built-in integration test capability of ASP.NET Core via Microsoft.AspNetCore.MVC.Testing](https://github.com/microsoft/ApplicationInsights-aspnetcore/issues/539)
- [Fix: System.NullReferenceException in WebSessionTelemetryInitializer.](https://github.com/microsoft/ApplicationInsights-aspnetcore/issues/903)
-- Updated Base SDK version dependency to 2.11.0-beta2
+- Updated Base SDK/Web SDK/Logging Adaptor SDK version dependency to 2.11.0-beta2
- Updated System.Diagnostics.DiagnosticSource to 4.6.0-preview8.
+- [Add new package for .NET Core WorkerServices (Adds GenericHost support)](https://github.com/microsoft/ApplicationInsights-aspnetcore/issues/708)
+
## Version 2.8.0-beta2
- [Fix MVCBeforeAction property fetcher to work with .NET Core 3.0 changes.](https://github.com/microsoft/ApplicationInsights-aspnetcore/issues/936)
- [Catch generic exception from DiagnosticSourceListeners and log instead of failing user request.](https://github.com/microsoft/ApplicationInsights-aspnetcore/issues/957)
diff --git a/src/Microsoft.ApplicationInsights.AspNetCore/Extensibility/Implementation/Tracing/AspNetCoreEventSource.cs b/src/Microsoft.ApplicationInsights.AspNetCore/Extensibility/Implementation/Tracing/AspNetCoreEventSource.cs
index 25541f6..6f97790 100644
--- a/src/Microsoft.ApplicationInsights.AspNetCore/Extensibility/Implementation/Tracing/AspNetCoreEventSource.cs
+++ b/src/Microsoft.ApplicationInsights.AspNetCore/Extensibility/Implementation/Tracing/AspNetCoreEventSource.cs
@@ -6,7 +6,9 @@
namespace Microsoft.ApplicationInsights.AspNetCore.Extensibility.Implementation.Tracing
{
+#if AI_ASPNETCORE_WEB
using Microsoft.ApplicationInsights.AspNetCore.Implementation;
+#endif
using System;
using System.Diagnostics.CodeAnalysis;
using System.Diagnostics.Tracing;
@@ -115,21 +117,12 @@ namespace Microsoft.ApplicationInsights.AspNetCore.Extensibility.Implementation.
///
/// Logs an event when a TelemetryModule is not found to configure.
///
- [Event(11, Message = "Unable to configure module {0} as it is not found in service collection.", Level = EventLevel.Warning, Keywords = Keywords.Diagnostics)]
+ [Event(11, Message = "Unable to configure module {0} as it is not found in service collection.", Level = EventLevel.Error, Keywords = Keywords.Diagnostics)]
public void UnableToFindModuleToConfigure(string moduleType, string appDomainName = "Incorrect")
{
this.WriteEvent(11, moduleType, this.ApplicationName);
}
- ///
- /// Logs an event when QuickPulseTelemetryModule is not found in service collection.
- ///
- [Event(12, Message = "Unable to find QuickPulseTelemetryModule in service collection. LiveMetrics feature will not be available. Please add QuickPulseTelemetryModule to services collection in the ConfigureServices method of your application Startup class.", Level = EventLevel.Error, Keywords = Keywords.Diagnostics)]
- public void UnableToFindQuickPulseModuleInDI(string appDomainName = "Incorrect")
- {
- this.WriteEvent(12, this.ApplicationName);
- }
-
///
/// Logs an event when telemetry is not tracked as the Listener is not active.
///
@@ -256,6 +249,18 @@ namespace Microsoft.ApplicationInsights.AspNetCore.Extensibility.Implementation.
this.WriteEvent(22, message, exception, this.ApplicationName);
}
+ ///
+ /// Logs an informational event.
+ ///
+ [Event(
+ 23,
+ Message = "Message : {0}",
+ Level = EventLevel.Informational)]
+ public void LogInformational(string message, string appDomainName = "Incorrect")
+ {
+ this.WriteEvent(23, message, this.ApplicationName);
+ }
+
///
/// Keywords for the AspNetEventSource.
///
diff --git a/src/Microsoft.ApplicationInsights.AspNetCore/Extensions/ApplicationInsightsExtensions.cs b/src/Microsoft.ApplicationInsights.AspNetCore/Extensions/ApplicationInsightsExtensions.cs
index 3afcbf1..7d2658e 100644
--- a/src/Microsoft.ApplicationInsights.AspNetCore/Extensions/ApplicationInsightsExtensions.cs
+++ b/src/Microsoft.ApplicationInsights.AspNetCore/Extensions/ApplicationInsightsExtensions.cs
@@ -35,17 +35,8 @@
///
/// Extension methods for that allow adding Application Insights services to application.
///
- public static class ApplicationInsightsExtensions
+ public static partial class ApplicationInsightsExtensions
{
- private const string VersionKeyFromConfig = "version";
- private const string InstrumentationKeyFromConfig = "ApplicationInsights:InstrumentationKey";
- private const string DeveloperModeFromConfig = "ApplicationInsights:TelemetryChannel:DeveloperMode";
- private const string EndpointAddressFromConfig = "ApplicationInsights:TelemetryChannel:EndpointAddress";
-
- private const string InstrumentationKeyForWebSites = "APPINSIGHTS_INSTRUMENTATIONKEY";
- private const string DeveloperModeForWebSites = "APPINSIGHTS_DEVELOPER_MODE";
- private const string EndpointAddressForWebSites = "APPINSIGHTS_ENDPOINTADDRESS";
-
[SuppressMessage(category: "", checkId: "CS1591:MissingXmlComment", Justification = "Obsolete method.")]
[Obsolete("This middleware is no longer needed. Enable Request monitoring using services.AddApplicationInsights")]
public static IApplicationBuilder UseApplicationInsightsRequestTelemetry(this IApplicationBuilder app)
@@ -148,141 +139,42 @@
if (!IsApplicationInsightsAdded(services))
{
services.TryAddSingleton();
+ AddAspNetCoreWebTelemetryInitializers(services);
+ AddCommonInitializers(services);
- services
- .AddSingleton();
- services.AddSingleton();
- services.AddSingleton();
- services.AddSingleton();
- services.AddSingleton();
- services.AddSingleton();
- services.AddSingleton();
- services.AddSingleton();
- services.AddSingleton();
- services.AddSingleton();
- services.TryAddSingleton();
-
- services.AddSingleton();
- services.ConfigureTelemetryModule((module, o) =>
- {
- module.EnableLegacyCorrelationHeadersInjection =
- o.DependencyCollectionOptions.EnableLegacyCorrelationHeadersInjection;
-
- var excludedDomains = module.ExcludeComponentCorrelationHttpHeadersOnDomains;
- excludedDomains.Add("core.windows.net");
- excludedDomains.Add("core.chinacloudapi.cn");
- excludedDomains.Add("core.cloudapi.de");
- excludedDomains.Add("core.usgovcloudapi.net");
-
- if (module.EnableLegacyCorrelationHeadersInjection)
- {
- excludedDomains.Add("localhost");
- excludedDomains.Add("127.0.0.1");
- }
-
- var includedActivities = module.IncludeDiagnosticSourceActivities;
- includedActivities.Add("Microsoft.Azure.EventHubs");
- includedActivities.Add("Microsoft.Azure.ServiceBus");
-
- module.EnableW3CHeadersInjection = o.RequestCollectionOptions.EnableW3CDistributedTracing;
- });
-
+ // Request Tracking.
+ services.AddSingleton();
services.ConfigureTelemetryModule((module, options) =>
{
module.CollectionOptions = options.RequestCollectionOptions;
});
- services.AddSingleton();
- services.AddSingleton();
- services.AddSingleton();
- services.AddSingleton();
- services.AddSingleton();
+ AddCommonTelemetryModules(services);
+ AddTelemetryChannel(services);
+
#if NETSTANDARD2_0
- services.AddSingleton();
- services.ConfigureTelemetryModule((eventCounterModule, options) =>
- {
- // Ref this code for actual names. https://github.com/dotnet/coreclr/blob/dbc5b56c48ce30635ee8192c9814c7de998043d5/src/System.Private.CoreLib/src/System/Diagnostics/Eventing/RuntimeEventSource.cs
- eventCounterModule.Counters.Add(new EventCounterCollectionRequest("System.Runtime", "cpu-usage"));
- eventCounterModule.Counters.Add(new EventCounterCollectionRequest("System.Runtime", "working-set"));
- eventCounterModule.Counters.Add(new EventCounterCollectionRequest("System.Runtime", "gc-heap-size"));
- eventCounterModule.Counters.Add(new EventCounterCollectionRequest("System.Runtime", "gen-0-gc-count"));
- eventCounterModule.Counters.Add(new EventCounterCollectionRequest("System.Runtime", "gen-1-gc-count"));
- eventCounterModule.Counters.Add(new EventCounterCollectionRequest("System.Runtime", "gen-2-gc-count"));
- eventCounterModule.Counters.Add(new EventCounterCollectionRequest("System.Runtime", "time-in-gc"));
- eventCounterModule.Counters.Add(new EventCounterCollectionRequest("System.Runtime", "gen-0-size"));
- eventCounterModule.Counters.Add(new EventCounterCollectionRequest("System.Runtime", "gen-1-size"));
- eventCounterModule.Counters.Add(new EventCounterCollectionRequest("System.Runtime", "gen-2-size"));
- eventCounterModule.Counters.Add(new EventCounterCollectionRequest("System.Runtime", "loh-size"));
- eventCounterModule.Counters.Add(new EventCounterCollectionRequest("System.Runtime", "alloc-rate"));
- eventCounterModule.Counters.Add(new EventCounterCollectionRequest("System.Runtime", "assembly-count"));
- eventCounterModule.Counters.Add(new EventCounterCollectionRequest("System.Runtime", "exception-count"));
- eventCounterModule.Counters.Add(new EventCounterCollectionRequest("System.Runtime", "threadpool-thread-count"));
- eventCounterModule.Counters.Add(new EventCounterCollectionRequest("System.Runtime", "monitor-lock-contention-count"));
- eventCounterModule.Counters.Add(new EventCounterCollectionRequest("System.Runtime", "threadpool-queue-length"));
- eventCounterModule.Counters.Add(new EventCounterCollectionRequest("System.Runtime", "threadpool-completed-items-count"));
- eventCounterModule.Counters.Add(new EventCounterCollectionRequest("System.Runtime", "active-timer-count"));
-
- // Ref this code for actual names. https://github.com/aspnet/AspNetCore/blob/f3f9a1cdbcd06b298035b523732b9f45b1408461/src/Hosting/Hosting/src/Internal/HostingEventSource.cs
- eventCounterModule.Counters.Add(new EventCounterCollectionRequest("Microsoft.AspNetCore.Hosting", "requests-per-second"));
- eventCounterModule.Counters.Add(new EventCounterCollectionRequest("Microsoft.AspNetCore.Hosting", "total-requests"));
- eventCounterModule.Counters.Add(new EventCounterCollectionRequest("Microsoft.AspNetCore.Hosting", "current-requests"));
- eventCounterModule.Counters.Add(new EventCounterCollectionRequest("Microsoft.AspNetCore.Hosting", "failed-requests"));
- });
+ ConfigureEventCounterModuleWithSystemCounters(services);
+ ConfigureEventCounterModuleWithAspNetCounters(services);
#endif
- services.AddSingleton(provider =>
- provider.GetService>().Value);
- services.TryAddSingleton();
-
- services.AddSingleton();
-
- services
- .TryAddSingleton,
+ services.TryAddSingleton,
DefaultApplicationInsightsServiceConfigureOptions>();
+ AddTelemetryConfigAndClient(services);
+ AddDefaultApplicationIdProvider(services);
+
// Using startup filter instead of starting DiagnosticListeners directly because
// AspNetCoreHostingDiagnosticListener injects TelemetryClient that injects TelemetryConfiguration
// that requires IOptions infrastructure to run and initialize
services.AddSingleton();
services.AddSingleton();
- services.AddSingleton(); // Add 'JavaScriptSnippet' "Service" for backwards compatibility. To remove in favour of 'IJavaScriptSnippet'.
-
- services.AddOptions();
- services.AddSingleton, TelemetryConfigurationOptions>();
- services
- .AddSingleton, TelemetryConfigurationOptionsSetup>();
+ // Add 'JavaScriptSnippet' "Service" for backwards compatibility. To remove in favour of 'IJavaScriptSnippet'.
+ services.AddSingleton();
// NetStandard2.0 has a package reference to Microsoft.Extensions.Logging.ApplicationInsights, and
// enables ApplicationInsightsLoggerProvider by default.
#if NETSTANDARD2_0
- services.AddLogging(loggingBuilder =>
- {
- loggingBuilder.AddApplicationInsights();
-
- // The default behavior is to capture only logs above Warning level from all categories.
- // This can achieved with this code level filter -> loggingBuilder.AddFilter("",LogLevel.Warning);
- // However, this will make it impossible to override this behavior from Configuration like below using appsettings.json:
- // {
- // "Logging": {
- // "ApplicationInsights": {
- // "LogLevel": {
- // "": "Error"
- // }
- // }
- // },
- // ...
- // }
- // The reason is as both rules will match the filter, the last one added wins.
- // To ensure that the default filter is in the beginning of filter rules, so that user override from Configuration will always win,
- // we add code filter rule to the 0th position as below.
- loggingBuilder.Services.Configure(
- options => options.Rules.Insert(
- 0,
- new LoggerFilterRule(
- "Microsoft.Extensions.Logging.ApplicationInsights.ApplicationInsightsLoggerProvider", null,
- LogLevel.Warning, null)));
- });
+ AddApplicationInsightsLoggerProvider(services);
#endif
}
@@ -295,210 +187,14 @@
}
}
- ///
- /// Adds an Application Insights Telemetry Processor into a service collection via a .
- ///
- /// Type of the telemetry processor to add.
- /// The instance.
- ///
- /// The .
- ///
- public static IServiceCollection AddApplicationInsightsTelemetryProcessor(this IServiceCollection services)
- where T : ITelemetryProcessor
+ private static void AddAspNetCoreWebTelemetryInitializers(IServiceCollection services)
{
- return services.AddSingleton(serviceProvider =>
- new TelemetryProcessorFactory(serviceProvider, typeof(T)));
- }
-
- ///
- /// Adds an Application Insights Telemetry Processor into a service collection via a .
- ///
- /// The instance.
- /// Type of the telemetry processor to add.
- ///
- /// The .
- ///
- /// The argument is null.
- /// The type does not implement .
- public static IServiceCollection AddApplicationInsightsTelemetryProcessor(this IServiceCollection services,
- Type telemetryProcessorType)
- {
- if (telemetryProcessorType == null)
- {
- throw new ArgumentNullException(nameof(telemetryProcessorType));
- }
-
- if (!telemetryProcessorType.GetTypeInfo().ImplementedInterfaces.Contains(typeof(ITelemetryProcessor)))
- {
- throw new ArgumentException(nameof(telemetryProcessorType) + "does not implement ITelemetryProcessor.");
- }
-
- return services.AddSingleton(serviceProvider =>
- new TelemetryProcessorFactory(serviceProvider, telemetryProcessorType));
- }
-
- ///
- /// Extension method to provide configuration logic for application insights telemetry module.
- ///
- /// The instance.
- /// Action used to configure the module.
- ///
- /// The .
- ///
- [Obsolete("Use ConfigureTelemetryModule overload that accepts ApplicationInsightsServiceOptions.")]
- public static IServiceCollection ConfigureTelemetryModule(this IServiceCollection services, Action configModule)
- where T : ITelemetryModule
- {
- if (configModule == null)
- {
- throw new ArgumentNullException(nameof(configModule));
- }
-
- return services.AddSingleton(typeof(ITelemetryModuleConfigurator),
- new TelemetryModuleConfigurator((config, options) => configModule((T)config), typeof(T)));
- }
-
- ///
- /// Extension method to provide configuration logic for application insights telemetry module.
- ///
- /// The instance.
- /// Action used to configure the module.
- ///
- /// The .
- ///
- public static IServiceCollection ConfigureTelemetryModule(
- this IServiceCollection services,
- Action configModule)
- where T : ITelemetryModule
- {
- if (configModule == null)
- {
- throw new ArgumentNullException(nameof(configModule));
- }
-
- return services.AddSingleton(typeof(ITelemetryModuleConfigurator),
- new TelemetryModuleConfigurator((config, options) => configModule((T)config, options), typeof(T)));
- }
-
- ///
- /// Adds Application Insight specific configuration properties to .
- ///
- /// The instance.
- /// Enables or disables developer mode.
- /// Sets telemetry endpoint address.
- /// Sets instrumentation key.
- /// The .
- public static IConfigurationBuilder AddApplicationInsightsSettings(
- this IConfigurationBuilder configurationSourceRoot,
- bool? developerMode = null,
- string endpointAddress = null,
- string instrumentationKey = null)
- {
- var telemetryConfigValues = new List>();
-
- bool wasAnythingSet = false;
-
- if (developerMode != null)
- {
- telemetryConfigValues.Add(new KeyValuePair(DeveloperModeForWebSites,
-#if !NETSTANDARD1_6
- developerMode.Value.ToString(System.Globalization.CultureInfo.InvariantCulture)));
-#else
- developerMode.Value.ToString()));
-#endif
- wasAnythingSet = true;
- }
-
- if (instrumentationKey != null)
- {
- telemetryConfigValues.Add(new KeyValuePair(InstrumentationKeyForWebSites,
- instrumentationKey));
- wasAnythingSet = true;
- }
-
- if (endpointAddress != null)
- {
- telemetryConfigValues.Add(new KeyValuePair(
- EndpointAddressForWebSites,
- endpointAddress));
- wasAnythingSet = true;
- }
-
- if (wasAnythingSet)
- {
- configurationSourceRoot.Add(new MemoryConfigurationSource() { InitialData = telemetryConfigValues });
- }
-
- return configurationSourceRoot;
- }
-
- ///
- /// Read from configuration
- /// Config.json will look like this:
- ///
- /// "ApplicationInsights": {
- /// "InstrumentationKey": "11111111-2222-3333-4444-555555555555"
- /// "TelemetryChannel": {
- /// "EndpointAddress": "http://dc.services.visualstudio.com/v2/track",
- /// "DeveloperMode": true
- /// }
- /// }.
- ///
- /// Values can also be read from environment variables to support azure web sites configuration.
- ///
- /// Configuration to read variables from.
- /// Telemetry configuration to populate.
- internal static void AddTelemetryConfiguration(IConfiguration config,
- ApplicationInsightsServiceOptions serviceOptions)
- {
- string instrumentationKey = config[InstrumentationKeyForWebSites];
- if (string.IsNullOrWhiteSpace(instrumentationKey))
- {
- instrumentationKey = config[InstrumentationKeyFromConfig];
- }
-
- if (!string.IsNullOrWhiteSpace(instrumentationKey))
- {
- serviceOptions.InstrumentationKey = instrumentationKey;
- }
-
- string developerModeValue = config[DeveloperModeForWebSites];
- if (string.IsNullOrWhiteSpace(developerModeValue))
- {
- developerModeValue = config[DeveloperModeFromConfig];
- }
-
- if (!string.IsNullOrWhiteSpace(developerModeValue))
- {
- bool developerMode = false;
- if (bool.TryParse(developerModeValue, out developerMode))
- {
- serviceOptions.DeveloperMode = developerMode;
- }
- }
-
- string endpointAddress = config[EndpointAddressForWebSites];
- if (string.IsNullOrWhiteSpace(endpointAddress))
- {
- endpointAddress = config[EndpointAddressFromConfig];
- }
-
- if (!string.IsNullOrWhiteSpace(endpointAddress))
- {
- serviceOptions.EndpointAddress = endpointAddress;
- }
-
- var version = config[VersionKeyFromConfig];
- if (!string.IsNullOrWhiteSpace(version))
- {
- serviceOptions.ApplicationVersion = version;
- }
- }
-
- private static bool IsApplicationInsightsAdded(IServiceCollection services)
- {
- // We treat TelemetryClient as a marker that AI services were added to service collection
- return services.Any(service => service.ServiceType == typeof(TelemetryClient));
+ services.AddSingleton();
+ services.AddSingleton();
+ services.AddSingleton();
+ services.AddSingleton();
+ services.AddSingleton();
+ services.AddSingleton();
}
}
}
diff --git a/src/Microsoft.ApplicationInsights.AspNetCore/Microsoft.ApplicationInsights.AspNetCore.csproj b/src/Microsoft.ApplicationInsights.AspNetCore/Microsoft.ApplicationInsights.AspNetCore.csproj
index 048b538..12cc926 100644
--- a/src/Microsoft.ApplicationInsights.AspNetCore/Microsoft.ApplicationInsights.AspNetCore.csproj
+++ b/src/Microsoft.ApplicationInsights.AspNetCore/Microsoft.ApplicationInsights.AspNetCore.csproj
@@ -3,12 +3,13 @@
Microsoft.ApplicationInsights.AspNetCore
2.8.0-beta3
7.2
- net451;net46;netstandard1.6;netstandard2.0
+ netstandard2.0;net451;net46;netstandard1.6
netstandard1.6;netstandard2.0
1.6.1
..\..\artifacts\src\$(MSBuildProjectName)
- ..\..\artifacts\obj\src\$(MSBuildProjectName)
+ ..\..\artifacts\obj\src\$(MSBuildProjectName)
+ $(DefineConstants);AI_ASPNETCORE_WEB;
@@ -72,6 +73,9 @@
+
+
+
@@ -90,8 +94,8 @@
-
-
+
+
diff --git a/src/Microsoft.ApplicationInsights.WorkerService/ApplicationInsightsExtensions.cs b/src/Microsoft.ApplicationInsights.WorkerService/ApplicationInsightsExtensions.cs
new file mode 100644
index 0000000..87ce2c9
--- /dev/null
+++ b/src/Microsoft.ApplicationInsights.WorkerService/ApplicationInsightsExtensions.cs
@@ -0,0 +1,143 @@
+using Microsoft.ApplicationInsights;
+using Microsoft.ApplicationInsights.WorkerService.TelemetryInitializers;
+using Microsoft.ApplicationInsights.WorkerService;
+using Microsoft.ApplicationInsights.Channel;
+using Microsoft.ApplicationInsights.DependencyCollector;
+using Microsoft.ApplicationInsights.Extensibility;
+using Microsoft.ApplicationInsights.Extensibility.EventCounterCollector;
+using Microsoft.ApplicationInsights.Extensibility.Implementation.ApplicationId;
+using Microsoft.ApplicationInsights.Extensibility.PerfCounterCollector;
+using Microsoft.ApplicationInsights.Extensibility.PerfCounterCollector.QuickPulse;
+using Microsoft.ApplicationInsights.WindowsServer;
+using Microsoft.ApplicationInsights.WindowsServer.TelemetryChannel;
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.DependencyInjection.Extensions;
+using Microsoft.Extensions.Logging;
+using Microsoft.Extensions.Options;
+using System;
+using System.Collections.Generic;
+using System.Text;
+using Microsoft.ApplicationInsights.Extensibility.Implementation.Tracing;
+using Microsoft.ApplicationInsights.WorkerService.Implementation.Tracing;
+
+namespace Microsoft.Extensions.DependencyInjection
+{
+ ///
+ /// Extension methods for that allow adding Application Insights services to application.
+ ///
+ public static partial class ApplicationInsightsExtensions
+ {
+ ///
+ /// Adds Application Insights services into service collection.
+ ///
+ /// The instance.
+ /// Instrumentation key to use for telemetry.
+ /// The .
+ public static IServiceCollection AddApplicationInsightsTelemetryWorkerService(
+ this IServiceCollection services,
+ string instrumentationKey)
+ {
+ services.AddApplicationInsightsTelemetryWorkerService(options => options.InstrumentationKey = instrumentationKey);
+ return services;
+ }
+
+ ///
+ /// Adds Application Insights services into service collection.
+ ///
+ /// The instance.
+ /// Configuration to use for sending telemetry.
+ /// The .
+ public static IServiceCollection AddApplicationInsightsTelemetryWorkerService(
+ this IServiceCollection services,
+ IConfiguration configuration)
+ {
+ services.AddApplicationInsightsTelemetryWorkerService(options => AddTelemetryConfiguration(configuration, options));
+ return services;
+ }
+
+ ///
+ /// Adds Application Insights services into service collection.
+ ///
+ /// The instance.
+ /// The action used to configure the options.
+ ///
+ /// The .
+ ///
+ public static IServiceCollection AddApplicationInsightsTelemetryWorkerService(
+ this IServiceCollection services,
+ Action options)
+ {
+ services.AddApplicationInsightsTelemetryWorkerService();
+ services.Configure(options);
+ return services;
+ }
+
+ ///
+ /// Adds Application Insights services into service collection.
+ ///
+ /// The instance.
+ /// The options instance used to configure with.
+ ///
+ /// The .
+ ///
+ public static IServiceCollection AddApplicationInsightsTelemetryWorkerService(
+ this IServiceCollection services,
+ ApplicationInsightsServiceOptions options)
+ {
+ services.AddApplicationInsightsTelemetryWorkerService();
+ services.Configure((ApplicationInsightsServiceOptions o) =>
+ {
+ o.ApplicationVersion = options.ApplicationVersion;
+ o.DeveloperMode = options.DeveloperMode;
+ o.EnableAdaptiveSampling = options.EnableAdaptiveSampling;
+ o.EnableAuthenticationTrackingJavaScript = options.EnableAuthenticationTrackingJavaScript;
+ o.EnableDebugLogger = options.EnableDebugLogger;
+ o.EnableQuickPulseMetricStream = options.EnableQuickPulseMetricStream;
+ o.EndpointAddress = options.EndpointAddress;
+ o.InstrumentationKey = options.InstrumentationKey;
+ o.EnableHeartbeat = options.EnableHeartbeat;
+ o.AddAutoCollectedMetricExtractor = options.AddAutoCollectedMetricExtractor;
+ });
+ return services;
+ }
+
+ ///
+ /// Adds Application Insights services into service collection.
+ ///
+ /// The instance.
+ ///
+ /// The .
+ ///
+ public static IServiceCollection AddApplicationInsightsTelemetryWorkerService(this IServiceCollection services)
+ {
+ try
+ {
+ if (!IsApplicationInsightsAdded(services))
+ {
+ AddCommonInitializers(services);
+ AddCommonTelemetryModules(services);
+ AddTelemetryChannel(services);
+
+ ConfigureEventCounterModuleWithSystemCounters(services);
+
+
+ services
+ .TryAddSingleton,
+ DefaultApplicationInsightsServiceConfigureOptions>();
+
+ AddDefaultApplicationIdProvider(services);
+ AddTelemetryConfigAndClient(services);
+ AddApplicationInsightsLoggerProvider(services);
+ }
+
+ return services;
+ }
+ catch (Exception e)
+ {
+ WorkerServiceEventSource.Instance.LogError(e.ToInvariantString());
+ return services;
+ }
+ }
+ }
+}
diff --git a/src/Microsoft.ApplicationInsights.WorkerService/DefaultApplicationInsightsServiceConfigureOptions.cs b/src/Microsoft.ApplicationInsights.WorkerService/DefaultApplicationInsightsServiceConfigureOptions.cs
new file mode 100644
index 0000000..5a07502
--- /dev/null
+++ b/src/Microsoft.ApplicationInsights.WorkerService/DefaultApplicationInsightsServiceConfigureOptions.cs
@@ -0,0 +1,40 @@
+namespace Microsoft.ApplicationInsights.WorkerService
+{
+ using System.Diagnostics;
+ using System.Globalization;
+ using System.IO;
+ using Microsoft.Extensions.Configuration;
+ using Microsoft.Extensions.DependencyInjection;
+ using Microsoft.Extensions.Options;
+
+ ///
+ /// implementation that reads options from provided IConfiguration
+ ///
+ internal class DefaultApplicationInsightsServiceConfigureOptions : IConfigureOptions
+ {
+ private readonly IConfiguration configuration;
+
+ ///
+ /// Creates a new instance of
+ ///
+ /// from which configuraion for ApplicationInsights can be retrieved.
+ public DefaultApplicationInsightsServiceConfigureOptions(IConfiguration configuration = null)
+ {
+ this.configuration = configuration;
+ }
+
+ ///
+ public void Configure(ApplicationInsightsServiceOptions options)
+ {
+ if (configuration != null)
+ {
+ ApplicationInsightsExtensions.AddTelemetryConfiguration(configuration, options);
+ }
+
+ if (Debugger.IsAttached)
+ {
+ options.DeveloperMode = true;
+ }
+ }
+ }
+}
diff --git a/src/Microsoft.ApplicationInsights.WorkerService/Implementation/TelemetryConfigurationOptions.cs b/src/Microsoft.ApplicationInsights.WorkerService/Implementation/TelemetryConfigurationOptions.cs
new file mode 100644
index 0000000..5c152b7
--- /dev/null
+++ b/src/Microsoft.ApplicationInsights.WorkerService/Implementation/TelemetryConfigurationOptions.cs
@@ -0,0 +1,29 @@
+namespace Microsoft.Extensions.DependencyInjection
+{
+ using System.Collections.Generic;
+ using System.Linq;
+ using Microsoft.ApplicationInsights.Extensibility;
+ using Microsoft.Extensions.Options;
+
+ ///
+ /// The implementation that create new every time when called".
+ ///
+ internal class TelemetryConfigurationOptions : IOptions
+ {
+ private static readonly object lockObject = new object();
+
+ public TelemetryConfigurationOptions(IEnumerable> configureOptions)
+ {
+ this.Value = TelemetryConfiguration.CreateDefault();
+
+ var configureOptionsArray = configureOptions.ToArray();
+ foreach (var c in configureOptionsArray)
+ {
+ c.Configure(this.Value);
+ }
+ }
+
+ ///
+ public TelemetryConfiguration Value { get; }
+ }
+}
\ No newline at end of file
diff --git a/src/Microsoft.ApplicationInsights.WorkerService/Implementation/Tracing/WorkerServiceEventSource.cs b/src/Microsoft.ApplicationInsights.WorkerService/Implementation/Tracing/WorkerServiceEventSource.cs
new file mode 100644
index 0000000..4bb20e3
--- /dev/null
+++ b/src/Microsoft.ApplicationInsights.WorkerService/Implementation/Tracing/WorkerServiceEventSource.cs
@@ -0,0 +1,120 @@
+//-----------------------------------------------------------------------
+//
+// Copyright (c) Microsoft Corporation. All rights reserved.
+//
+//-----------------------------------------------------------------------
+
+namespace Microsoft.ApplicationInsights.WorkerService.Implementation.Tracing
+{
+ using System;
+ using System.Diagnostics.CodeAnalysis;
+ using System.Diagnostics.Tracing;
+
+ ///
+ /// Event source for Application Insights Worker Service SDK.
+ ///
+ [EventSource(Name = "Microsoft-ApplicationInsights-WorkerService")]
+ [SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", Justification = "appDomainName is required")]
+ internal sealed class WorkerServiceEventSource : EventSource
+ {
+ ///
+ /// The singleton instance of this event source.
+ /// Due to how EventSource initialization works this has to be a public field and not
+ /// a property otherwise the internal state of the event source will not be enabled.
+ ///
+ public static readonly WorkerServiceEventSource Instance = new WorkerServiceEventSource();
+
+ ///
+ /// Prevents a default instance of the class from being created.
+ ///
+ private WorkerServiceEventSource()
+ : base()
+ {
+ try
+ {
+ this.ApplicationName = System.Reflection.Assembly.GetEntryAssembly().GetName().Name;
+ }
+ catch (Exception exp)
+ {
+ this.ApplicationName = "Undefined " + exp.Message;
+ }
+ }
+
+ ///
+ /// Gets the application name for use in logging events.
+ ///
+ public string ApplicationName
+ {
+ [NonEvent]
+ get;
+ [NonEvent]
+ private set;
+ }
+
+ ///
+ /// Logs informational message.
+ ///
+ /// Message
+ /// An ignored placeholder to make EventSource happy.
+ [Event(1, Message = "Message : {0}", Level = EventLevel.Warning, Keywords = Keywords.Diagnostics)]
+ public void LogInformational(string message, string appDomainName = "Incorrect")
+ {
+ this.WriteEvent(1, message, this.ApplicationName);
+ }
+
+ ///
+ /// Logs warning message.
+ ///
+ /// Message
+ /// An ignored placeholder to make EventSource happy.
+ [Event(2, Message = "Message : {0}", Level = EventLevel.Warning)]
+ public void LogWarning(string message, string appDomainName = "Incorrect")
+ {
+ this.WriteEvent(2, message, this.ApplicationName);
+ }
+
+ ///
+ /// Logs error message.
+ ///
+ /// Message
+ /// An ignored placeholder to make EventSource happy.
+ [Event(3, Message = "An error has occured which may prevent application insights from functioning. Error message: '{0}'", Level = EventLevel.Error)]
+ public void LogError(string message, string appDomainName = "Incorrect")
+ {
+ this.WriteEvent(3, message, this.ApplicationName);
+ }
+
+ ///
+ /// Logs an event when a TelemetryModule is not found to configure.
+ ///
+ [Event(4, Message = "Unable to configure module {0} as it is not found in service collection.", Level = EventLevel.Error, Keywords = Keywords.Diagnostics)]
+ public void UnableToFindModuleToConfigure(string moduleType, string appDomainName = "Incorrect")
+ {
+ this.WriteEvent(4, moduleType, this.ApplicationName);
+ }
+
+ ///
+ /// Logs an event when TelemetryConfiguration configure has failed.
+ ///
+ [Event(
+ 5,
+ Keywords = Keywords.Diagnostics,
+ Message = "An error has occured while setting up TelemetryConfiguration. Error message: '{0}' ",
+ Level = EventLevel.Error)]
+ public void TelemetryConfigurationSetupFailure(string errorMessage, string appDomainName = "Incorrect")
+ {
+ this.WriteEvent(5, errorMessage, this.ApplicationName);
+ }
+
+ ///
+ /// Keywords for the AspNetEventSource.
+ ///
+ public sealed class Keywords
+ {
+ ///
+ /// Keyword for errors that trace at Verbose level.
+ ///
+ public const EventKeywords Diagnostics = (EventKeywords)0x1;
+ }
+ }
+}
diff --git a/src/Microsoft.ApplicationInsights.WorkerService/Microsoft.ApplicationInsights.WorkerService.csproj b/src/Microsoft.ApplicationInsights.WorkerService/Microsoft.ApplicationInsights.WorkerService.csproj
new file mode 100644
index 0000000..d9c8206
--- /dev/null
+++ b/src/Microsoft.ApplicationInsights.WorkerService/Microsoft.ApplicationInsights.WorkerService.csproj
@@ -0,0 +1,94 @@
+
+
+
+ Microsoft.ApplicationInsights.WorkerService
+ 2.8.0-beta3
+ 7.2
+ netstandard2.0
+ ..\..\artifacts\src\$(MSBuildProjectName)
+ ..\..\artifacts\obj\src\$(MSBuildProjectName)
+ $(DefineConstants);AI_ASPNETCORE_WORKER;
+
+
+
+
+
+ Microsoft.ApplicationInsights.WorkerService
+ Application Insights for .NET Core Worker Service Applications
+ Application Insights for .NET Core Worker Service Applications
+ Application Insights for .NET Core Worker Service (messaging, background tasks, and any non-HTTP workloads) applications. See https://azure.microsoft.com/documentation/articles/app-insights-asp-net-five/ for more information. Privacy statement: https://go.microsoft.com/fwlink/?LinkId=512156
+
+
+
+
+ Microsoft
+ © Microsoft Corporation. All rights reserved.
+ git
+ https://github.com/Microsoft/ApplicationInsights-aspnetcore.git
+ True
+ True
+ snupkg
+ Azure;Monitoring;Analytics;ApplicationInsights;Telemetry;AppInsights;aspnetcore;worker;console;backgroundtasks
+ https://appanacdn.blob.core.windows.net/cdn/icons/aic.png
+ MIT
+ https://go.microsoft.com/fwlink/?LinkId=392727
+ true
+
+
+
+
+ true
+
+
+
+
+ full
+ true
+
+
+
+
+
+ All
+
+
+ All
+
+
+ All
+
+
+ All
+
+
+ All
+
+
+
+
+
+
+ All
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Shared/Extensions/ApplicationInsightsExtensions.cs b/src/Shared/Extensions/ApplicationInsightsExtensions.cs
new file mode 100644
index 0000000..10ca3db
--- /dev/null
+++ b/src/Shared/Extensions/ApplicationInsightsExtensions.cs
@@ -0,0 +1,421 @@
+namespace Microsoft.Extensions.DependencyInjection
+{
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+ using System.Reflection;
+ using Microsoft.ApplicationInsights;
+#if AI_ASPNETCORE_WEB
+ using Microsoft.ApplicationInsights.AspNetCore;
+ using Microsoft.ApplicationInsights.AspNetCore.TelemetryInitializers;
+ using Microsoft.ApplicationInsights.AspNetCore.Extensibility.Implementation.Tracing;
+ using Microsoft.ApplicationInsights.AspNetCore.Extensions;
+#else
+ using Microsoft.ApplicationInsights.WorkerService;
+ using Microsoft.ApplicationInsights.WorkerService.TelemetryInitializers;
+ using Microsoft.ApplicationInsights.WorkerService.Implementation.Tracing;
+#endif
+ using Microsoft.ApplicationInsights.Extensibility;
+ using Microsoft.ApplicationInsights.Extensibility.Implementation.Tracing;
+ using Microsoft.ApplicationInsights.WindowsServer;
+ using Microsoft.Extensions.Configuration;
+ using Microsoft.Extensions.Configuration.Memory;
+ using Microsoft.Extensions.Logging;
+ using Microsoft.ApplicationInsights.DependencyCollector;
+ using Microsoft.ApplicationInsights.Channel;
+ using Microsoft.Extensions.DependencyInjection.Extensions;
+ using Microsoft.ApplicationInsights.WindowsServer.TelemetryChannel;
+ using Microsoft.ApplicationInsights.Extensibility.PerfCounterCollector;
+ using Microsoft.ApplicationInsights.Extensibility.PerfCounterCollector.QuickPulse;
+#if NETSTANDARD2_0
+ using Microsoft.ApplicationInsights.Extensibility.EventCounterCollector;
+#endif
+ using Microsoft.Extensions.Options;
+ using Microsoft.ApplicationInsights.Extensibility.Implementation.ApplicationId;
+
+ ///
+ /// Extension methods for that allow adding Application Insights services to application.
+ ///
+ public static partial class ApplicationInsightsExtensions
+ {
+ private const string VersionKeyFromConfig = "version";
+ private const string InstrumentationKeyFromConfig = "ApplicationInsights:InstrumentationKey";
+ private const string DeveloperModeFromConfig = "ApplicationInsights:TelemetryChannel:DeveloperMode";
+ private const string EndpointAddressFromConfig = "ApplicationInsights:TelemetryChannel:EndpointAddress";
+
+ private const string InstrumentationKeyForWebSites = "APPINSIGHTS_INSTRUMENTATIONKEY";
+ private const string DeveloperModeForWebSites = "APPINSIGHTS_DEVELOPER_MODE";
+ private const string EndpointAddressForWebSites = "APPINSIGHTS_ENDPOINTADDRESS";
+ private const string EventSourceNameForSystemRuntime = "System.Runtime";
+ private const string EventSourceNameForAspNetCoreHosting = "Microsoft.AspNetCore.Hosting";
+
+
+ ///
+ /// Adds an Application Insights Telemetry Processor into a service collection via a .
+ ///
+ /// Type of the telemetry processor to add.
+ /// The instance.
+ ///
+ /// The .
+ ///
+ public static IServiceCollection AddApplicationInsightsTelemetryProcessor(this IServiceCollection services)
+ where T : ITelemetryProcessor
+ {
+ return services.AddSingleton(serviceProvider =>
+ new TelemetryProcessorFactory(serviceProvider, typeof(T)));
+ }
+
+ ///
+ /// Adds an Application Insights Telemetry Processor into a service collection via a .
+ ///
+ /// The instance.
+ /// Type of the telemetry processor to add.
+ ///
+ /// The .
+ ///
+ /// The argument is null.
+ /// The type does not implement .
+ public static IServiceCollection AddApplicationInsightsTelemetryProcessor(this IServiceCollection services,
+ Type telemetryProcessorType)
+ {
+ if (telemetryProcessorType == null)
+ {
+ throw new ArgumentNullException(nameof(telemetryProcessorType));
+ }
+
+ if (!telemetryProcessorType.GetTypeInfo().ImplementedInterfaces.Contains(typeof(ITelemetryProcessor)))
+ {
+ throw new ArgumentException(nameof(telemetryProcessorType) + "does not implement ITelemetryProcessor.");
+ }
+
+ return services.AddSingleton(serviceProvider =>
+ new TelemetryProcessorFactory(serviceProvider, telemetryProcessorType));
+ }
+
+ ///
+ /// Extension method to provide configuration logic for application insights telemetry module.
+ ///
+ /// The instance.
+ /// Action used to configure the module.
+ ///
+ /// The .
+ ///
+ [Obsolete("Use ConfigureTelemetryModule overload that accepts ApplicationInsightsServiceOptions.")]
+ public static IServiceCollection ConfigureTelemetryModule(this IServiceCollection services, Action configModule)
+ where T : ITelemetryModule
+ {
+ if (configModule == null)
+ {
+ throw new ArgumentNullException(nameof(configModule));
+ }
+
+ return services.AddSingleton(typeof(ITelemetryModuleConfigurator),
+ new TelemetryModuleConfigurator((config, options) => configModule((T)config), typeof(T)));
+ }
+
+ ///
+ /// Extension method to provide configuration logic for application insights telemetry module.
+ ///
+ /// The instance.
+ /// Action used to configure the module.
+ ///
+ /// The .
+ ///
+ public static IServiceCollection ConfigureTelemetryModule(
+ this IServiceCollection services,
+ Action configModule)
+ where T : ITelemetryModule
+ {
+ if (configModule == null)
+ {
+ throw new ArgumentNullException(nameof(configModule));
+ }
+
+ return services.AddSingleton(typeof(ITelemetryModuleConfigurator),
+ new TelemetryModuleConfigurator((config, options) => configModule((T)config, options), typeof(T)));
+ }
+
+ ///
+ /// Adds Application Insight specific configuration properties to .
+ ///
+ /// The instance.
+ /// Enables or disables developer mode.
+ /// Sets telemetry endpoint address.
+ /// Sets instrumentation key.
+ /// The .
+ public static IConfigurationBuilder AddApplicationInsightsSettings(
+ this IConfigurationBuilder configurationSourceRoot,
+ bool? developerMode = null,
+ string endpointAddress = null,
+ string instrumentationKey = null)
+ {
+ var telemetryConfigValues = new List>();
+
+ bool wasAnythingSet = false;
+
+ if (developerMode != null)
+ {
+ telemetryConfigValues.Add(new KeyValuePair(DeveloperModeForWebSites,
+#if !NETSTANDARD1_6
+ developerMode.Value.ToString(System.Globalization.CultureInfo.InvariantCulture)));
+#else
+ developerMode.Value.ToString()));
+#endif
+ wasAnythingSet = true;
+ }
+
+ if (instrumentationKey != null)
+ {
+ telemetryConfigValues.Add(new KeyValuePair(InstrumentationKeyForWebSites,
+ instrumentationKey));
+ wasAnythingSet = true;
+ }
+
+ if (endpointAddress != null)
+ {
+ telemetryConfigValues.Add(new KeyValuePair(
+ EndpointAddressForWebSites,
+ endpointAddress));
+ wasAnythingSet = true;
+ }
+
+ if (wasAnythingSet)
+ {
+ configurationSourceRoot.Add(new MemoryConfigurationSource() { InitialData = telemetryConfigValues });
+ }
+
+ return configurationSourceRoot;
+ }
+
+ ///
+ /// Read from configuration
+ /// Config.json will look like this:
+ ///
+ /// "ApplicationInsights": {
+ /// "InstrumentationKey": "11111111-2222-3333-4444-555555555555"
+ /// "TelemetryChannel": {
+ /// "EndpointAddress": "http://dc.services.visualstudio.com/v2/track",
+ /// "DeveloperMode": true
+ /// }
+ /// }.
+ ///
+ /// Values can also be read from environment variables to support azure web sites configuration.
+ ///
+ /// Configuration to read variables from.
+ /// Telemetry configuration to populate.
+ internal static void AddTelemetryConfiguration(IConfiguration config,
+ ApplicationInsightsServiceOptions serviceOptions)
+ {
+ try
+ {
+ string instrumentationKey = config[InstrumentationKeyForWebSites];
+ if (string.IsNullOrWhiteSpace(instrumentationKey))
+ {
+ instrumentationKey = config[InstrumentationKeyFromConfig];
+ }
+
+ if (!string.IsNullOrWhiteSpace(instrumentationKey))
+ {
+ serviceOptions.InstrumentationKey = instrumentationKey;
+ }
+
+ string developerModeValue = config[DeveloperModeForWebSites];
+ if (string.IsNullOrWhiteSpace(developerModeValue))
+ {
+ developerModeValue = config[DeveloperModeFromConfig];
+ }
+
+ if (!string.IsNullOrWhiteSpace(developerModeValue))
+ {
+ bool developerMode = false;
+ if (bool.TryParse(developerModeValue, out developerMode))
+ {
+ serviceOptions.DeveloperMode = developerMode;
+ }
+ }
+
+ string endpointAddress = config[EndpointAddressForWebSites];
+ if (string.IsNullOrWhiteSpace(endpointAddress))
+ {
+ endpointAddress = config[EndpointAddressFromConfig];
+ }
+
+ if (!string.IsNullOrWhiteSpace(endpointAddress))
+ {
+ serviceOptions.EndpointAddress = endpointAddress;
+ }
+
+ var version = config[VersionKeyFromConfig];
+ if (!string.IsNullOrWhiteSpace(version))
+ {
+ serviceOptions.ApplicationVersion = version;
+ }
+ }
+ catch(Exception ex)
+ {
+#if AI_ASPNETCORE_WEB
+ AspNetCoreEventSource.Instance.LogError(ex.ToInvariantString());
+#else
+ WorkerServiceEventSource.Instance.LogError(ex.ToInvariantString());
+#endif
+ }
+ }
+
+ private static bool IsApplicationInsightsAdded(IServiceCollection services)
+ {
+ // We treat TelemetryClient as a marker that AI services were added to service collection
+ return services.Any(service => service.ServiceType == typeof(TelemetryClient));
+ }
+
+ private static void AddCommonInitializers(IServiceCollection services)
+ {
+#if AI_ASPNETCORE_WEB
+ services.AddSingleton();
+#else
+ services.AddSingleton();
+#endif
+ services.AddSingleton();
+ services.AddSingleton();
+ services.AddSingleton();
+ }
+
+ private static void AddCommonTelemetryModules(IServiceCollection services)
+ {
+ services.AddSingleton();
+ services.AddSingleton();
+ services.AddSingleton();
+ services.AddSingleton();
+ AddAndConfigureDependencyTracking(services);
+#if NETSTANDARD2_0
+ services.AddSingleton();
+#endif
+ }
+
+ private static void AddTelemetryChannel(IServiceCollection services)
+ {
+ services.TryAddSingleton();
+ }
+
+ private static void AddDefaultApplicationIdProvider(IServiceCollection services)
+ {
+ services.TryAddSingleton();
+ }
+
+ private static void AddTelemetryConfigAndClient(IServiceCollection services)
+ {
+ services.AddOptions();
+ services.AddSingleton, TelemetryConfigurationOptions>();
+ services.AddSingleton, TelemetryConfigurationOptionsSetup>();
+ services.AddSingleton(provider =>
+ provider.GetService>().Value);
+ services.AddSingleton();
+ }
+
+ private static void AddAndConfigureDependencyTracking(IServiceCollection services)
+ {
+ services.AddSingleton();
+ services.ConfigureTelemetryModule((module, o) =>
+ {
+ module.EnableLegacyCorrelationHeadersInjection =
+ o.DependencyCollectionOptions.EnableLegacyCorrelationHeadersInjection;
+
+ var excludedDomains = module.ExcludeComponentCorrelationHttpHeadersOnDomains;
+ excludedDomains.Add("core.windows.net");
+ excludedDomains.Add("core.chinacloudapi.cn");
+ excludedDomains.Add("core.cloudapi.de");
+ excludedDomains.Add("core.usgovcloudapi.net");
+
+ if (module.EnableLegacyCorrelationHeadersInjection)
+ {
+ excludedDomains.Add("localhost");
+ excludedDomains.Add("127.0.0.1");
+ }
+
+ var includedActivities = module.IncludeDiagnosticSourceActivities;
+ includedActivities.Add("Microsoft.Azure.EventHubs");
+ includedActivities.Add("Microsoft.Azure.ServiceBus");
+ });
+ }
+
+#if NETSTANDARD2_0
+ private static void AddEventCounterIfNotExist(EventCounterCollectionModule eventCounterModule, string eventSource, string eventCounterName)
+ {
+ if (!eventCounterModule.Counters.Any(req => req.EventSourceName.Equals(eventSource) && req.EventCounterName.Equals(eventCounterName)))
+ {
+ eventCounterModule.Counters.Add(new EventCounterCollectionRequest(eventSource, eventCounterName));
+ }
+ }
+ private static void ConfigureEventCounterModuleWithSystemCounters(IServiceCollection services)
+ {
+ services.ConfigureTelemetryModule((eventCounterModule, options) =>
+ {
+ // Ref this code for actual names. https://github.com/dotnet/coreclr/blob/dbc5b56c48ce30635ee8192c9814c7de998043d5/src/System.Private.CoreLib/src/System/Diagnostics/Eventing/RuntimeEventSource.cs
+ AddEventCounterIfNotExist(eventCounterModule, EventSourceNameForSystemRuntime, "cpu-usage");
+ AddEventCounterIfNotExist(eventCounterModule, EventSourceNameForSystemRuntime, "working-set");
+ AddEventCounterIfNotExist(eventCounterModule, EventSourceNameForSystemRuntime, "gc-heap-size");
+ AddEventCounterIfNotExist(eventCounterModule, EventSourceNameForSystemRuntime, "gen-0-gc-count");
+ AddEventCounterIfNotExist(eventCounterModule, EventSourceNameForSystemRuntime, "gen-1-gc-count");
+ AddEventCounterIfNotExist(eventCounterModule, EventSourceNameForSystemRuntime, "gen-2-gc-count");
+ AddEventCounterIfNotExist(eventCounterModule, EventSourceNameForSystemRuntime, "time-in-gc");
+ AddEventCounterIfNotExist(eventCounterModule, EventSourceNameForSystemRuntime, "gen-0-size");
+ AddEventCounterIfNotExist(eventCounterModule, EventSourceNameForSystemRuntime, "gen-1-size");
+ AddEventCounterIfNotExist(eventCounterModule, EventSourceNameForSystemRuntime, "gen-2-size");
+ AddEventCounterIfNotExist(eventCounterModule, EventSourceNameForSystemRuntime, "loh-size");
+ AddEventCounterIfNotExist(eventCounterModule, EventSourceNameForSystemRuntime, "alloc-rate");
+ AddEventCounterIfNotExist(eventCounterModule, EventSourceNameForSystemRuntime, "assembly-count");
+ AddEventCounterIfNotExist(eventCounterModule, EventSourceNameForSystemRuntime, "exception-count");
+ AddEventCounterIfNotExist(eventCounterModule, EventSourceNameForSystemRuntime, "threadpool-thread-count");
+ AddEventCounterIfNotExist(eventCounterModule, EventSourceNameForSystemRuntime, "monitor-lock-contention-count");
+ AddEventCounterIfNotExist(eventCounterModule, EventSourceNameForSystemRuntime, "threadpool-queue-length");
+ AddEventCounterIfNotExist(eventCounterModule, EventSourceNameForSystemRuntime, "threadpool-completed-items-count");
+ AddEventCounterIfNotExist(eventCounterModule, EventSourceNameForSystemRuntime, "active-timer-count");
+ });
+ }
+
+ private static void ConfigureEventCounterModuleWithAspNetCounters(IServiceCollection services)
+ {
+ services.ConfigureTelemetryModule((eventCounterModule, options) =>
+ {
+ // Ref this code for actual names. https://github.com/aspnet/AspNetCore/blob/f3f9a1cdbcd06b298035b523732b9f45b1408461/src/Hosting/Hosting/src/Internal/HostingEventSource.cs
+ AddEventCounterIfNotExist(eventCounterModule, EventSourceNameForAspNetCoreHosting, "requests-per-second");
+ AddEventCounterIfNotExist(eventCounterModule, EventSourceNameForAspNetCoreHosting, "total-requests");
+ AddEventCounterIfNotExist(eventCounterModule, EventSourceNameForAspNetCoreHosting, "current-requests");
+ AddEventCounterIfNotExist(eventCounterModule, EventSourceNameForAspNetCoreHosting, "failed-requests");
+ });
+ }
+#endif
+
+ private static void AddApplicationInsightsLoggerProvider(IServiceCollection services)
+ {
+#if NETSTANDARD2_0
+ services.AddLogging(loggingBuilder =>
+ {
+ loggingBuilder.AddApplicationInsights();
+
+ // The default behavior is to capture only logs above Warning level from all categories.
+ // This can achieved with this code level filter -> loggingBuilder.AddFilter("",LogLevel.Warning);
+ // However, this will make it impossible to override this behavior from Configuration like below using appsettings.json:
+ // {
+ // "Logging": {
+ // "ApplicationInsights": {
+ // "LogLevel": {
+ // "": "Error"
+ // }
+ // }
+ // },
+ // ...
+ // }
+ // The reason is as both rules will match the filter, the last one added wins.
+ // To ensure that the default filter is in the beginning of filter rules, so that user override from Configuration will always win,
+ // we add code filter rule to the 0th position as below.
+ loggingBuilder.Services.Configure(
+ options => options.Rules.Insert(
+ 0,
+ new LoggerFilterRule(
+ "Microsoft.Extensions.Logging.ApplicationInsights.ApplicationInsightsLoggerProvider", null,
+ LogLevel.Warning, null)));
+ });
+#endif
+ }
+ }
+}
diff --git a/src/Microsoft.ApplicationInsights.AspNetCore/Extensions/ApplicationInsightsServiceOptions.cs b/src/Shared/Extensions/ApplicationInsightsServiceOptions.cs
similarity index 94%
rename from src/Microsoft.ApplicationInsights.AspNetCore/Extensions/ApplicationInsightsServiceOptions.cs
rename to src/Shared/Extensions/ApplicationInsightsServiceOptions.cs
index 86b470e..ac9d81e 100644
--- a/src/Microsoft.ApplicationInsights.AspNetCore/Extensions/ApplicationInsightsServiceOptions.cs
+++ b/src/Shared/Extensions/ApplicationInsightsServiceOptions.cs
@@ -1,4 +1,8 @@
-namespace Microsoft.ApplicationInsights.AspNetCore.Extensions
+#if AI_ASPNETCORE_WEB
+ namespace Microsoft.ApplicationInsights.AspNetCore.Extensions
+#else
+ namespace Microsoft.ApplicationInsights.WorkerService
+#endif
{
using System.Reflection;
using Microsoft.ApplicationInsights.DependencyCollector;
@@ -20,7 +24,9 @@
this.EnableAuthenticationTrackingJavaScript = false;
this.EnableHeartbeat = true;
this.AddAutoCollectedMetricExtractor = true;
+#if AI_ASPNETCORE_WEB
this.RequestCollectionOptions = new RequestCollectionOptions();
+#endif
this.DependencyCollectionOptions = new DependencyCollectionOptions();
this.ApplicationVersion = Assembly.GetEntryAssembly()?.GetName().Version.ToString();
}
@@ -78,10 +84,13 @@
///
public bool AddAutoCollectedMetricExtractor { get; set; }
+#if AI_ASPNETCORE_WEB
///
/// Gets that allow to manage
///
public RequestCollectionOptions RequestCollectionOptions { get; }
+#endif
+
///
/// Gets that allow to manage
diff --git a/src/Microsoft.ApplicationInsights.AspNetCore/Extensions/DependencyCollectionOptions.cs b/src/Shared/Extensions/DependencyCollectionOptions.cs
similarity index 81%
rename from src/Microsoft.ApplicationInsights.AspNetCore/Extensions/DependencyCollectionOptions.cs
rename to src/Shared/Extensions/DependencyCollectionOptions.cs
index 15b0f77..236aa06 100644
--- a/src/Microsoft.ApplicationInsights.AspNetCore/Extensions/DependencyCollectionOptions.cs
+++ b/src/Shared/Extensions/DependencyCollectionOptions.cs
@@ -1,4 +1,8 @@
-namespace Microsoft.ApplicationInsights.AspNetCore.Extensions
+#if AI_ASPNETCORE_WEB
+ namespace Microsoft.ApplicationInsights.AspNetCore.Extensions
+#else
+namespace Microsoft.ApplicationInsights.WorkerService
+#endif
{
///
/// Default collection options define the custom behavior or non-default features of dependency collection.
diff --git a/src/Microsoft.ApplicationInsights.AspNetCore/ITelemetryModuleConfigurator.cs b/src/Shared/Implementation/ITelemetryModuleConfigurator.cs
similarity index 80%
rename from src/Microsoft.ApplicationInsights.AspNetCore/ITelemetryModuleConfigurator.cs
rename to src/Shared/Implementation/ITelemetryModuleConfigurator.cs
index d8d8f3e..2dae3af 100644
--- a/src/Microsoft.ApplicationInsights.AspNetCore/ITelemetryModuleConfigurator.cs
+++ b/src/Shared/Implementation/ITelemetryModuleConfigurator.cs
@@ -1,6 +1,14 @@
-namespace Microsoft.ApplicationInsights.AspNetCore
+#if AI_ASPNETCORE_WEB
+ namespace Microsoft.ApplicationInsights.AspNetCore
+#else
+ namespace Microsoft.ApplicationInsights.WorkerService
+#endif
{
+#if AI_ASPNETCORE_WEB
using Microsoft.ApplicationInsights.AspNetCore.Extensions;
+#else
+ using Microsoft.ApplicationInsights.WorkerService;
+#endif
using Microsoft.ApplicationInsights.Extensibility;
using System;
diff --git a/src/Microsoft.ApplicationInsights.AspNetCore/ITelemetryProcessorFactory.cs b/src/Shared/Implementation/ITelemetryProcessorFactory.cs
similarity index 79%
rename from src/Microsoft.ApplicationInsights.AspNetCore/ITelemetryProcessorFactory.cs
rename to src/Shared/Implementation/ITelemetryProcessorFactory.cs
index 57eb084..205b774 100644
--- a/src/Microsoft.ApplicationInsights.AspNetCore/ITelemetryProcessorFactory.cs
+++ b/src/Shared/Implementation/ITelemetryProcessorFactory.cs
@@ -1,4 +1,8 @@
-namespace Microsoft.ApplicationInsights.AspNetCore
+#if AI_ASPNETCORE_WEB
+ namespace Microsoft.ApplicationInsights.AspNetCore
+#else
+namespace Microsoft.ApplicationInsights.WorkerService
+#endif
{
using Microsoft.ApplicationInsights.Channel;
using Microsoft.ApplicationInsights.Extensibility;
diff --git a/src/Microsoft.ApplicationInsights.AspNetCore/Implementation/TelemetryConfigurationOptionsSetup.cs b/src/Shared/Implementation/TelemetryConfigurationOptionsSetup.cs
similarity index 89%
rename from src/Microsoft.ApplicationInsights.AspNetCore/Implementation/TelemetryConfigurationOptionsSetup.cs
rename to src/Shared/Implementation/TelemetryConfigurationOptionsSetup.cs
index d77cbb9..213b1d9 100644
--- a/src/Microsoft.ApplicationInsights.AspNetCore/Implementation/TelemetryConfigurationOptionsSetup.cs
+++ b/src/Shared/Implementation/TelemetryConfigurationOptionsSetup.cs
@@ -3,9 +3,14 @@ namespace Microsoft.Extensions.DependencyInjection
using System;
using System.Collections.Generic;
using System.Linq;
+#if AI_ASPNETCORE_WEB
+ using Microsoft.ApplicationInsights.AspNetCore.Extensions;
using Microsoft.ApplicationInsights.AspNetCore;
using Microsoft.ApplicationInsights.AspNetCore.Extensibility.Implementation.Tracing;
- using Microsoft.ApplicationInsights.AspNetCore.Extensions;
+#else
+ using Microsoft.ApplicationInsights.WorkerService;
+ using Microsoft.ApplicationInsights.WorkerService.Implementation.Tracing;
+#endif
using Microsoft.ApplicationInsights.Channel;
using Microsoft.ApplicationInsights.Extensibility;
using Microsoft.ApplicationInsights.Extensibility.Implementation;
@@ -14,7 +19,7 @@ namespace Microsoft.Extensions.DependencyInjection
using Microsoft.ApplicationInsights.Extensibility.W3C;
using Microsoft.Extensions.Options;
using Microsoft.ApplicationInsights.WindowsServer.Channel.Implementation;
- using Microsoft.ApplicationInsights.DataContracts;
+ using Microsoft.ApplicationInsights.DataContracts;
///
/// Initializes TelemetryConfiguration based on values in
@@ -71,7 +76,11 @@ namespace Microsoft.Extensions.DependencyInjection
}
else
{
+#if AI_ASPNETCORE_WEB
AspNetCoreEventSource.Instance.UnableToFindModuleToConfigure(telemetryModuleConfigurator.TelemetryModuleType.ToString());
+#else
+ WorkerServiceEventSource.Instance.UnableToFindModuleToConfigure(telemetryModuleConfigurator.TelemetryModuleType.ToString());
+#endif
}
}
}
@@ -127,10 +136,20 @@ namespace Microsoft.Extensions.DependencyInjection
// Microsoft.ApplicationInsights.DependencyCollector.DependencyTrackingTelemetryModule depends on this nullable configuration to support Correlation.
configuration.ApplicationIdProvider = this.applicationIdProvider;
+
+#if AI_ASPNETCORE_WEB
+ AspNetCoreEventSource.Instance.LogInformational("Successfully configured TelemetryConfiguration.");
+#else
+ WorkerServiceEventSource.Instance.LogInformational("Successfully configured TelemetryConfiguration.");
+#endif
}
catch (Exception ex)
{
+#if AI_ASPNETCORE_WEB
AspNetCoreEventSource.Instance.TelemetryConfigurationSetupFailure(ex.ToInvariantString());
+#else
+ WorkerServiceEventSource.Instance.TelemetryConfigurationSetupFailure(ex.ToInvariantString());
+#endif
}
}
@@ -151,7 +170,11 @@ namespace Microsoft.Extensions.DependencyInjection
}
else
{
- AspNetCoreEventSource.Instance.UnableToFindQuickPulseModuleInDI();
+#if AI_ASPNETCORE_WEB
+ AspNetCoreEventSource.Instance.UnableToFindModuleToConfigure("QuickPulseTelemetryModule");
+#else
+ WorkerServiceEventSource.Instance.UnableToFindModuleToConfigure("QuickPulseTelemetryModule");
+#endif
}
}
}
diff --git a/src/Microsoft.ApplicationInsights.AspNetCore/Implementation/TelemetryModuleConfigurator.cs b/src/Shared/Implementation/TelemetryModuleConfigurator.cs
similarity index 88%
rename from src/Microsoft.ApplicationInsights.AspNetCore/Implementation/TelemetryModuleConfigurator.cs
rename to src/Shared/Implementation/TelemetryModuleConfigurator.cs
index 32ca9db..bf8f2fb 100644
--- a/src/Microsoft.ApplicationInsights.AspNetCore/Implementation/TelemetryModuleConfigurator.cs
+++ b/src/Shared/Implementation/TelemetryModuleConfigurator.cs
@@ -1,7 +1,15 @@
-namespace Microsoft.ApplicationInsights.AspNetCore
+#if AI_ASPNETCORE_WEB
+ namespace Microsoft.ApplicationInsights.AspNetCore
+#else
+ namespace Microsoft.ApplicationInsights.WorkerService
+#endif
{
using System;
+#if AI_ASPNETCORE_WEB
using Microsoft.ApplicationInsights.AspNetCore.Extensions;
+#else
+ using Microsoft.ApplicationInsights.WorkerService;
+#endif
using Microsoft.ApplicationInsights.Extensibility;
///
diff --git a/src/Microsoft.ApplicationInsights.AspNetCore/Implementation/TelemetryProcessorFactory.cs b/src/Shared/Implementation/TelemetryProcessorFactory.cs
similarity index 90%
rename from src/Microsoft.ApplicationInsights.AspNetCore/Implementation/TelemetryProcessorFactory.cs
rename to src/Shared/Implementation/TelemetryProcessorFactory.cs
index ac47a40..e0e899e 100644
--- a/src/Microsoft.ApplicationInsights.AspNetCore/Implementation/TelemetryProcessorFactory.cs
+++ b/src/Shared/Implementation/TelemetryProcessorFactory.cs
@@ -1,4 +1,8 @@
-namespace Microsoft.ApplicationInsights.AspNetCore
+#if AI_ASPNETCORE_WEB
+ namespace Microsoft.ApplicationInsights.AspNetCore
+#else
+ namespace Microsoft.ApplicationInsights.WorkerService
+#endif
{
using System;
using Microsoft.ApplicationInsights.Extensibility;
diff --git a/src/Shared/Shared.projitems b/src/Shared/Shared.projitems
new file mode 100644
index 0000000..2bc3741
--- /dev/null
+++ b/src/Shared/Shared.projitems
@@ -0,0 +1,23 @@
+
+
+
+ $(MSBuildAllProjects);$(MSBuildThisFileFullPath)
+ true
+ d56f2979-d6bc-4ef2-bb9b-4077b3290599
+
+
+ Shared
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Shared/Shared.shproj b/src/Shared/Shared.shproj
new file mode 100644
index 0000000..13f549d
--- /dev/null
+++ b/src/Shared/Shared.shproj
@@ -0,0 +1,13 @@
+
+
+
+ d56f2979-d6bc-4ef2-bb9b-4077b3290599
+ 14.0
+
+
+
+
+
+
+
+
diff --git a/src/Microsoft.ApplicationInsights.AspNetCore/TelemetryInitializers/ComponentVersionTelemetryInitializer.cs b/src/Shared/TelemetryInitializers/ComponentVersionTelemetryInitializer.cs
similarity index 82%
rename from src/Microsoft.ApplicationInsights.AspNetCore/TelemetryInitializers/ComponentVersionTelemetryInitializer.cs
rename to src/Shared/TelemetryInitializers/ComponentVersionTelemetryInitializer.cs
index 02af3a9..a1af0e1 100644
--- a/src/Microsoft.ApplicationInsights.AspNetCore/TelemetryInitializers/ComponentVersionTelemetryInitializer.cs
+++ b/src/Shared/TelemetryInitializers/ComponentVersionTelemetryInitializer.cs
@@ -1,8 +1,16 @@
-namespace Microsoft.ApplicationInsights.AspNetCore.TelemetryInitializers
+#if AI_ASPNETCORE_WEB
+namespace Microsoft.ApplicationInsights.AspNetCore.TelemetryInitializers
+#else
+namespace Microsoft.ApplicationInsights.WorkerService.TelemetryInitializers
+#endif
{
using ApplicationInsights.Extensibility;
using Channel;
+#if AI_ASPNETCORE_WEB
using Microsoft.ApplicationInsights.AspNetCore.Extensions;
+#else
+ using Microsoft.ApplicationInsights.WorkerService;
+#endif
using Microsoft.Extensions.Options;
///
diff --git a/src/Microsoft.ApplicationInsights.AspNetCore/TelemetryInitializers/DomainNameRoleInstanceTelemetryInitializer.cs b/src/Shared/TelemetryInitializers/DomainNameRoleInstanceTelemetryInitializer.cs
similarity index 89%
rename from src/Microsoft.ApplicationInsights.AspNetCore/TelemetryInitializers/DomainNameRoleInstanceTelemetryInitializer.cs
rename to src/Shared/TelemetryInitializers/DomainNameRoleInstanceTelemetryInitializer.cs
index b3990dc..70c6f0a 100644
--- a/src/Microsoft.ApplicationInsights.AspNetCore/TelemetryInitializers/DomainNameRoleInstanceTelemetryInitializer.cs
+++ b/src/Shared/TelemetryInitializers/DomainNameRoleInstanceTelemetryInitializer.cs
@@ -1,4 +1,8 @@
-namespace Microsoft.ApplicationInsights.AspNetCore.TelemetryInitializers
+#if AI_ASPNETCORE_WEB
+namespace Microsoft.ApplicationInsights.AspNetCore.TelemetryInitializers
+#else
+namespace Microsoft.ApplicationInsights.WorkerService.TelemetryInitializers
+#endif
{
using System;
using System.Globalization;
@@ -7,7 +11,6 @@
using System.Threading;
using Channel;
using Microsoft.ApplicationInsights.Extensibility;
- using Microsoft.ApplicationInsights.Extensibility.Implementation;
///
/// A telemetry initializer that populates cloud context role instance.
@@ -32,7 +35,6 @@
private string GetMachineName()
{
string hostName = Dns.GetHostName();
-
// Issue #61: For dnxcore machine name does not have domain name like in full framework
#if NET451 || NET46
string domainName = IPGlobalProperties.GetIPGlobalProperties().DomainName;
diff --git a/test/Microsoft.ApplicationInsights.AspNetCore.Tests/Extensions/ApplicationInsightsExtensionsTests.cs b/test/Microsoft.ApplicationInsights.AspNetCore.Tests/Extensions/ApplicationInsightsExtensionsTests.cs
index f5f9c7a..3f7ab1e 100644
--- a/test/Microsoft.ApplicationInsights.AspNetCore.Tests/Extensions/ApplicationInsightsExtensionsTests.cs
+++ b/test/Microsoft.ApplicationInsights.AspNetCore.Tests/Extensions/ApplicationInsightsExtensionsTests.cs
@@ -47,8 +47,6 @@ namespace Microsoft.Extensions.DependencyInjection.Test
public static ServiceCollection GetServiceCollectionWithContextAccessor()
{
var services = new ServiceCollection();
- IHttpContextAccessor contextAccessor = new HttpContextAccessor();
- services.AddSingleton(contextAccessor);
services.AddSingleton(new HostingEnvironment() { ContentRootPath = Directory.GetCurrentDirectory()});
services.AddSingleton(new DiagnosticListener("TestListener"));
return services;
@@ -65,6 +63,7 @@ namespace Microsoft.Extensions.DependencyInjection.Test
[InlineData(typeof(ITelemetryInitializer), typeof(SyntheticTelemetryInitializer), ServiceLifetime.Singleton)]
[InlineData(typeof(ITelemetryInitializer), typeof(WebSessionTelemetryInitializer), ServiceLifetime.Singleton)]
[InlineData(typeof(ITelemetryInitializer), typeof(WebUserTelemetryInitializer), ServiceLifetime.Singleton)]
+ [InlineData(typeof(ITelemetryInitializer), typeof(HttpDependenciesParsingTelemetryInitializer), ServiceLifetime.Singleton)]
[InlineData(typeof(TelemetryConfiguration), null, ServiceLifetime.Singleton)]
[InlineData(typeof(TelemetryClient), typeof(TelemetryClient), ServiceLifetime.Singleton)]
public static void RegistersExpectedServices(Type serviceType, Type implementationType, ServiceLifetime lifecycle)
@@ -83,6 +82,7 @@ namespace Microsoft.Extensions.DependencyInjection.Test
[InlineData(typeof(ITelemetryInitializer), typeof(SyntheticTelemetryInitializer), ServiceLifetime.Singleton)]
[InlineData(typeof(ITelemetryInitializer), typeof(WebSessionTelemetryInitializer), ServiceLifetime.Singleton)]
[InlineData(typeof(ITelemetryInitializer), typeof(WebUserTelemetryInitializer), ServiceLifetime.Singleton)]
+ [InlineData(typeof(ITelemetryInitializer), typeof(HttpDependenciesParsingTelemetryInitializer), ServiceLifetime.Singleton)]
[InlineData(typeof(TelemetryConfiguration), null, ServiceLifetime.Singleton)]
[InlineData(typeof(TelemetryClient), typeof(TelemetryClient), ServiceLifetime.Singleton)]
public static void RegistersExpectedServicesOnlyOnce(Type serviceType, Type implementationType, ServiceLifetime lifecycle)
@@ -542,13 +542,18 @@ namespace Microsoft.Extensions.DependencyInjection.Test
//VALIDATE
Assert.Equal(23, eventCounterModule.Counters.Count);
- eventCounterModule.Counters.FirstOrDefault(
- eventCounterCollectionRequest => eventCounterCollectionRequest.EventSourceName == "System.Runtime"
+
+ // sanity check with a sample counter.
+ var cpuCounterRequest = eventCounterModule.Counters.FirstOrDefault(
+ eventCounterCollectionRequest => eventCounterCollectionRequest.EventSourceName == "System.Runtime"
&& eventCounterCollectionRequest.EventCounterName == "cpu-usage");
+ Assert.NotNull(cpuCounterRequest);
- eventCounterModule.Counters.FirstOrDefault(
- eventCounterCollectionRequest => eventCounterCollectionRequest.EventSourceName == "Microsoft.AspNetCore"
- && eventCounterCollectionRequest.EventCounterName == "requests-per-second");
+ // sanity check - asp.net counters should be added
+ var aspnetCounterRequest = eventCounterModule.Counters.Where(
+ eventCounterCollectionRequest => eventCounterCollectionRequest.EventSourceName == "Microsoft.AspNetCore.Hosting");
+ Assert.NotNull(aspnetCounterRequest);
+ Assert.True(aspnetCounterRequest.Count() == 4);
}
#endif
@@ -1066,8 +1071,8 @@ namespace Microsoft.Extensions.DependencyInjection.Test
Assert.Single(requestTracking);
Assert.Single(dependencyTracking);
- Assert.True(requestTracking.Single().CollectionOptions.EnableW3CDistributedTracing);
- Assert.True(dependencyTracking.Single().EnableW3CHeadersInjection);
+ Assert.True(Activity.DefaultIdFormat == ActivityIdFormat.W3C);
+ Assert.True(Activity.ForceDefaultIdFormat);
}
private static int GetTelemetryProcessorsCountInConfiguration(TelemetryConfiguration telemetryConfiguration)
diff --git a/test/Microsoft.ApplicationInsights.WorkerService.Tests/ExtensionsTest.cs b/test/Microsoft.ApplicationInsights.WorkerService.Tests/ExtensionsTest.cs
new file mode 100644
index 0000000..9f3fbf1
--- /dev/null
+++ b/test/Microsoft.ApplicationInsights.WorkerService.Tests/ExtensionsTest.cs
@@ -0,0 +1,408 @@
+using Microsoft.ApplicationInsights.WorkerService.TelemetryInitializers;
+using Microsoft.ApplicationInsights.Channel;
+using Microsoft.ApplicationInsights.DataContracts;
+using Microsoft.ApplicationInsights.DependencyCollector;
+using Microsoft.ApplicationInsights.Extensibility;
+using Microsoft.ApplicationInsights.Extensibility.EventCounterCollector;
+using Microsoft.ApplicationInsights.Extensibility.Implementation.ApplicationId;
+using Microsoft.ApplicationInsights.Extensibility.PerfCounterCollector;
+using Microsoft.ApplicationInsights.Extensibility.PerfCounterCollector.QuickPulse;
+using Microsoft.ApplicationInsights.WindowsServer;
+using Microsoft.ApplicationInsights.WindowsServer.TelemetryChannel;
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.DependencyInjection;
+using System;
+using System.IO;
+using System.Linq;
+using Xunit;
+using Xunit.Abstractions;
+
+namespace Microsoft.ApplicationInsights.WorkerService.Tests
+{
+ public class ExtensionsTests
+ {
+ private readonly ITestOutputHelper output;
+ public const string TestInstrumentationKey = "11111111-2222-3333-4444-555555555555";
+ public const string TestInstrumentationKeyEnv = "AAAAAAAA-BBBB-CCCC-DDDD-DDDDDDDDDD";
+ public const string TestEndPoint = "http://testendpoint/v2/track";
+ public const string TestEndPointEnv = "http://testendpointend/v2/track";
+ public ExtensionsTests(ITestOutputHelper output)
+ {
+ this.output = output;
+ this.output.WriteLine("Initialized");
+ }
+
+ private static ServiceCollection CreateServicesAndAddApplicationinsightsWorker(Action serviceOptions = null)
+ {
+ var services = new ServiceCollection();
+ services.AddApplicationInsightsTelemetryWorkerService();
+ if (serviceOptions != null)
+ {
+ services.Configure(serviceOptions);
+ }
+ return services;
+ }
+
+ [Theory]
+ [InlineData(typeof(ITelemetryInitializer), typeof(ApplicationInsights.WorkerService.TelemetryInitializers.DomainNameRoleInstanceTelemetryInitializer), ServiceLifetime.Singleton)]
+ [InlineData(typeof(ITelemetryInitializer), typeof(AzureWebAppRoleEnvironmentTelemetryInitializer), ServiceLifetime.Singleton)]
+ [InlineData(typeof(ITelemetryInitializer), typeof(ComponentVersionTelemetryInitializer), ServiceLifetime.Singleton)]
+ [InlineData(typeof(ITelemetryInitializer), typeof(HttpDependenciesParsingTelemetryInitializer), ServiceLifetime.Singleton)]
+ [InlineData(typeof(TelemetryConfiguration), null, ServiceLifetime.Singleton)]
+ [InlineData(typeof(TelemetryClient), typeof(TelemetryClient), ServiceLifetime.Singleton)]
+ [InlineData(typeof(ITelemetryChannel), typeof(ServerTelemetryChannel), ServiceLifetime.Singleton)]
+ public void RegistersExpectedServices(Type serviceType, Type implementationType, ServiceLifetime lifecycle)
+ {
+ var services = CreateServicesAndAddApplicationinsightsWorker(null);
+ ServiceDescriptor service = services.Single(s => s.ServiceType == serviceType && s.ImplementationType == implementationType);
+ Assert.Equal(lifecycle, service.Lifetime);
+ }
+
+ [Theory]
+ [InlineData(typeof(ITelemetryInitializer), typeof(ApplicationInsights.WorkerService.TelemetryInitializers.DomainNameRoleInstanceTelemetryInitializer), ServiceLifetime.Singleton)]
+ [InlineData(typeof(ITelemetryInitializer), typeof(AzureWebAppRoleEnvironmentTelemetryInitializer), ServiceLifetime.Singleton)]
+ [InlineData(typeof(ITelemetryInitializer), typeof(ComponentVersionTelemetryInitializer), ServiceLifetime.Singleton)]
+ [InlineData(typeof(ITelemetryInitializer), typeof(HttpDependenciesParsingTelemetryInitializer), ServiceLifetime.Singleton)]
+ [InlineData(typeof(TelemetryConfiguration), null, ServiceLifetime.Singleton)]
+ [InlineData(typeof(TelemetryClient), typeof(TelemetryClient), ServiceLifetime.Singleton)]
+ [InlineData(typeof(ITelemetryChannel), typeof(ServerTelemetryChannel), ServiceLifetime.Singleton)]
+ public void RegistersExpectedServicesOnlyOnce(Type serviceType, Type implementationType, ServiceLifetime lifecycle)
+ {
+ var services = CreateServicesAndAddApplicationinsightsWorker(null);
+ services.AddApplicationInsightsTelemetryWorkerService();
+ ServiceDescriptor service = services.Single(s => s.ServiceType == serviceType && s.ImplementationType == implementationType);
+ Assert.Equal(lifecycle, service.Lifetime);
+ }
+
+ [Fact]
+ public void DoesNotThrowWithoutInstrumentationKey()
+ {
+ var services = CreateServicesAndAddApplicationinsightsWorker(null);
+ }
+
+ [Fact]
+ public void ReadsSettingsFromSuppliedConfiguration()
+ {
+ var jsonFullPath = Path.Combine(Directory.GetCurrentDirectory(), "content", "sample-appsettings.json");
+
+ this.output.WriteLine("json:" + jsonFullPath);
+ var config = new ConfigurationBuilder().AddJsonFile(jsonFullPath).Build();
+ var services = new ServiceCollection();
+
+ services.AddApplicationInsightsTelemetryWorkerService(config);
+ IServiceProvider serviceProvider = services.BuildServiceProvider();
+ var telemetryConfiguration = serviceProvider.GetRequiredService();
+ Assert.Equal(TestInstrumentationKey, telemetryConfiguration.InstrumentationKey);
+ Assert.Equal(TestEndPoint, telemetryConfiguration.TelemetryChannel.EndpointAddress);
+ Assert.Equal(true, telemetryConfiguration.TelemetryChannel.DeveloperMode);
+ }
+
+ [Fact]
+ public void ReadsSettingsFromDefaultConfiguration()
+ {
+ // Host.CreateDefaultBuilder() in .NET Core 3.0 adds appsetting.json and env variable
+ // to configuration and is made available for constructor injection.
+ // this test validates that SDK reads settings from this configuration by default.
+ // ARRANGE
+ var jsonFullPath = Path.Combine(Directory.GetCurrentDirectory(), "content", "sample-appsettings.json");
+ this.output.WriteLine("json:" + jsonFullPath);
+ var config = new ConfigurationBuilder().AddJsonFile(jsonFullPath).Build();
+ var services = new ServiceCollection();
+ // This line mimics the default behavior by CreateDefaultBuilder
+ services.AddSingleton(config);
+
+ // ACT
+ services.AddApplicationInsightsTelemetryWorkerService();
+
+ // VALIDATE
+ IServiceProvider serviceProvider = services.BuildServiceProvider();
+ var telemetryConfiguration = serviceProvider.GetRequiredService();
+ Assert.Equal(TestInstrumentationKey, telemetryConfiguration.InstrumentationKey);
+ Assert.Equal(TestEndPoint, telemetryConfiguration.TelemetryChannel.EndpointAddress);
+ Assert.Equal(true, telemetryConfiguration.TelemetryChannel.DeveloperMode);
+ }
+
+ [Fact]
+ public void ReadsSettingsFromDefaultConfigurationWithEnvOverridingConfig()
+ {
+ // Host.CreateDefaultBuilder() in .NET Core 3.0 adds appsetting.json and env variable
+ // to configuration and is made available for constructor injection.
+ // this test validates that SDK reads settings from this configuration by default
+ // and gives priority to the ENV variables than the one from config.
+
+ // ARRANGE
+ Environment.SetEnvironmentVariable("APPINSIGHTS_INSTRUMENTATIONKEY", TestInstrumentationKeyEnv);
+ Environment.SetEnvironmentVariable("APPINSIGHTS_ENDPOINTADDRESS", TestEndPointEnv);
+ try
+ {
+ var jsonFullPath = Path.Combine(Directory.GetCurrentDirectory(), "content", "sample-appsettings.json");
+ this.output.WriteLine("json:" + jsonFullPath);
+
+ // This config will have ikey,endpoint from json and env. ENV one is expected to win.
+ var config = new ConfigurationBuilder().AddJsonFile(jsonFullPath).AddEnvironmentVariables().Build();
+ var services = new ServiceCollection();
+
+ // This line mimics the default behavior by CreateDefaultBuilder
+ services.AddSingleton(config);
+
+ // ACT
+ services.AddApplicationInsightsTelemetryWorkerService();
+
+ // VALIDATE
+ IServiceProvider serviceProvider = services.BuildServiceProvider();
+ var telemetryConfiguration = serviceProvider.GetRequiredService();
+ Assert.Equal(TestInstrumentationKeyEnv, telemetryConfiguration.InstrumentationKey);
+ Assert.Equal(TestEndPointEnv, telemetryConfiguration.TelemetryChannel.EndpointAddress);
+ }
+ finally
+ {
+ Environment.SetEnvironmentVariable("APPINSIGHTS_INSTRUMENTATIONKEY", null);
+ Environment.SetEnvironmentVariable("APPINSIGHTS_ENDPOINTADDRESS", null);
+ }
+ }
+
+ [Fact]
+ public void VerifiesIkeyProvidedInAddApplicationInsightsAlwaysWinsOverOtherOptions()
+ {
+ // ARRANGE
+ Environment.SetEnvironmentVariable("APPINSIGHTS_INSTRUMENTATIONKEY", TestInstrumentationKeyEnv);
+ try
+ {
+ var jsonFullPath = Path.Combine(Directory.GetCurrentDirectory(), "content", "sample-appsettings.json");
+ this.output.WriteLine("json:" + jsonFullPath);
+
+ // This config will have ikey,endpoint from json and env. But the one
+ // user explicitly provider is expected to win.
+ var config = new ConfigurationBuilder().AddJsonFile(jsonFullPath).AddEnvironmentVariables().Build();
+ var services = new ServiceCollection();
+
+ // This line mimics the default behavior by CreateDefaultBuilder
+ services.AddSingleton(config);
+
+ // ACT
+ services.AddApplicationInsightsTelemetryWorkerService("userkey");
+
+ // VALIDATE
+ IServiceProvider serviceProvider = services.BuildServiceProvider();
+ var telemetryConfiguration = serviceProvider.GetRequiredService();
+ Assert.Equal("userkey", telemetryConfiguration.InstrumentationKey);
+ }
+ finally
+ {
+ Environment.SetEnvironmentVariable("APPINSIGHTS_INSTRUMENTATIONKEY", null);
+ }
+ }
+
+ [Fact]
+ public void DoesNoThrowIfNoSettingsFound()
+ {
+ // Host.CreateDefaultBuilder() in .NET Core 3.0 adds appsetting.json and env variable
+ // to configuration and is made available for constructor injection.
+ // This test validates that SDK does not throw any error if it cannot find
+ // application insights configuration in default IConfiguration.
+ // ARRANGE
+ var jsonFullPath = Path.Combine(Directory.GetCurrentDirectory(), "content", "sample-appsettings_dontexist.json");
+ this.output.WriteLine("json:" + jsonFullPath);
+ var config = new ConfigurationBuilder().AddJsonFile(jsonFullPath, true).Build();
+ var services = new ServiceCollection();
+ // This line mimics the default behavior by CreateDefaultBuilder
+ services.AddSingleton(config);
+
+ // ACT
+ services.AddApplicationInsightsTelemetryWorkerService();
+
+ // VALIDATE
+ IServiceProvider serviceProvider = services.BuildServiceProvider();
+ var telemetryConfiguration = serviceProvider.GetRequiredService();
+ Assert.True(string.IsNullOrEmpty(telemetryConfiguration.InstrumentationKey));
+ }
+
+ [Fact]
+ public void VerifyAddAIWorkerServiceSetsUpDefaultConfigurationAndModules()
+ {
+ var services = new ServiceCollection();
+
+ // ACT
+ services.AddApplicationInsightsTelemetryWorkerService("ikey");
+
+ // VALIDATE
+ IServiceProvider serviceProvider = services.BuildServiceProvider();
+ var telemetryConfiguration = serviceProvider.GetRequiredService();
+ Assert.Equal("ikey", telemetryConfiguration.InstrumentationKey);
+
+ // AppID
+ var appIdProvider = serviceProvider.GetRequiredService();
+ Assert.NotNull(appIdProvider);
+ Assert.True(appIdProvider is ApplicationInsightsApplicationIdProvider);
+
+ // AppID
+ var channel = serviceProvider.GetRequiredService();
+ Assert.NotNull(channel);
+ Assert.True(channel is ServerTelemetryChannel);
+
+ // TelemetryModules
+ var modules = serviceProvider.GetServices();
+ Assert.NotNull(modules);
+ Assert.Equal(6, modules.Count());
+
+ var perfCounterModule = modules.FirstOrDefault(t => t.GetType() == typeof(PerformanceCollectorModule));
+ Assert.NotNull(perfCounterModule);
+
+ var qpModule = modules.FirstOrDefault(t => t.GetType() == typeof(QuickPulseTelemetryModule));
+ Assert.NotNull(qpModule);
+
+ var evtCounterModule = modules.FirstOrDefault(t => t.GetType() == typeof(EventCounterCollectionModule));
+ Assert.NotNull(evtCounterModule);
+
+ var depModule = modules.FirstOrDefault(t => t.GetType() == typeof(DependencyTrackingTelemetryModule));
+ Assert.NotNull(depModule);
+
+ var hbModule = modules.FirstOrDefault(t => t.GetType() == typeof(AppServicesHeartbeatTelemetryModule));
+ Assert.NotNull(hbModule);
+
+ var azMetadataModule = modules.FirstOrDefault(t => t.GetType() == typeof(AzureInstanceMetadataTelemetryModule));
+ Assert.NotNull(azMetadataModule);
+
+ // TelemetryProcessors
+ Assert.Contains(telemetryConfiguration.DefaultTelemetrySink.TelemetryProcessors, proc => proc.GetType().Name.Contains("AutocollectedMetricsExtractor"));
+ Assert.Contains(telemetryConfiguration.DefaultTelemetrySink.TelemetryProcessors, proc => proc.GetType().Name.Contains("AdaptiveSamplingTelemetryProcessor"));
+ Assert.Contains(telemetryConfiguration.DefaultTelemetrySink.TelemetryProcessors, proc => proc.GetType().Name.Contains("QuickPulseTelemetryProcessor"));
+
+ // TelemetryInitializers
+ // 4 added by WorkerService SDK, 1 from Base Sdk
+ Assert.Equal(5, telemetryConfiguration.TelemetryInitializers.Count);
+ Assert.Contains(telemetryConfiguration.TelemetryInitializers, initializer => initializer.GetType().Name.Contains("DomainNameRoleInstanceTelemetryInitializer"));
+ Assert.Contains(telemetryConfiguration.TelemetryInitializers, initializer => initializer.GetType().Name.Contains("AzureWebAppRoleEnvironmentTelemetryInitializer"));
+ Assert.Contains(telemetryConfiguration.TelemetryInitializers, initializer => initializer.GetType().Name.Contains("ComponentVersionTelemetryInitializer"));
+ Assert.Contains(telemetryConfiguration.TelemetryInitializers, initializer => initializer.GetType().Name.Contains("HttpDependenciesParsingTelemetryInitializer"));
+ Assert.Contains(telemetryConfiguration.TelemetryInitializers, initializer => initializer.GetType().Name.Contains("OperationCorrelationTelemetryInitializer"));
+
+ // TelemetryClient
+ var tc = serviceProvider.GetRequiredService();
+ Assert.NotNull(tc);
+ }
+
+ [Fact]
+ public static void RegistersTelemetryConfigurationFactoryMethodThatPopulatesEventCounterCollectorWithDefaultListOfCounters()
+ {
+ //ARRANGE
+ var services = new ServiceCollection();
+ services.AddApplicationInsightsTelemetryWorkerService();
+
+ //ACT
+ IServiceProvider serviceProvider = services.BuildServiceProvider();
+ var modules = serviceProvider.GetServices();
+ var telemetryConfiguration = serviceProvider.GetRequiredService();
+ var eventCounterModule = modules.OfType().Single();
+
+ //VALIDATE
+ Assert.Equal(19, eventCounterModule.Counters.Count);
+
+ // sanity check with a sample counter.
+ var cpuCounterRequest = eventCounterModule.Counters.FirstOrDefault(
+ eventCounterCollectionRequest => eventCounterCollectionRequest.EventSourceName == "System.Runtime"
+ && eventCounterCollectionRequest.EventCounterName == "cpu-usage");
+ Assert.NotNull(cpuCounterRequest);
+
+ // sanity check - no asp.net counters should be added
+ var aspnetCounterRequest = eventCounterModule.Counters.FirstOrDefault(
+ eventCounterCollectionRequest => eventCounterCollectionRequest.EventSourceName == "Microsoft.AspNetCore.Hosting");
+ Assert.Null(aspnetCounterRequest);
+ }
+
+ [Fact]
+ public void VerifyAddAIWorkerServiceUsesTelemetryInitializerAddedToDI()
+ {
+ var services = new ServiceCollection();
+ var telemetryInitializer = new FakeTelemetryInitializer();
+
+ // ACT
+ services.AddApplicationInsightsTelemetryWorkerService();
+ services.AddSingleton(telemetryInitializer);
+
+
+ // VALIDATE
+ IServiceProvider serviceProvider = services.BuildServiceProvider();
+ var telemetryConfiguration = serviceProvider.GetRequiredService();
+ Assert.Contains(telemetryInitializer, telemetryConfiguration.TelemetryInitializers);
+ }
+
+ [Fact]
+ public void VerifyAddAIWorkerServiceUsesTelemetryChannelAddedToDI()
+ {
+ var services = new ServiceCollection();
+ var telChannel = new ServerTelemetryChannel() {StorageFolder = "c:\\mycustom" };
+
+ // ACT
+ services.AddApplicationInsightsTelemetryWorkerService("ikey");
+ services.AddSingleton(telChannel);
+
+ // VALIDATE
+ IServiceProvider serviceProvider = services.BuildServiceProvider();
+ var telemetryConfiguration = serviceProvider.GetRequiredService();
+ Assert.Equal(telChannel, telemetryConfiguration.TelemetryChannel);
+ Assert.Equal("c:\\mycustom", ((ServerTelemetryChannel) telemetryConfiguration.TelemetryChannel).StorageFolder);
+
+ }
+
+
+ [Fact]
+ public void VerifyAddAIWorkerServiceRespectsAIOptions()
+ {
+ var services = new ServiceCollection();
+
+ // ACT
+ var aiOptions = new ApplicationInsightsServiceOptions();
+ aiOptions.AddAutoCollectedMetricExtractor = false;
+ aiOptions.EnableAdaptiveSampling = false;
+ aiOptions.EnableQuickPulseMetricStream = false;
+ aiOptions.InstrumentationKey = "keyfromaioption";
+ services.AddApplicationInsightsTelemetryWorkerService(aiOptions);
+
+ // VALIDATE
+ IServiceProvider serviceProvider = services.BuildServiceProvider();
+ var telemetryConfiguration = serviceProvider.GetRequiredService();
+ Assert.Equal("keyfromaioption", telemetryConfiguration.InstrumentationKey);
+ Assert.DoesNotContain(telemetryConfiguration.DefaultTelemetrySink.TelemetryProcessors, proc => proc.GetType().Name.Contains("AutocollectedMetricsExtractor"));
+ Assert.DoesNotContain(telemetryConfiguration.DefaultTelemetrySink.TelemetryProcessors, proc => proc.GetType().Name.Contains("AdaptiveSamplingTelemetryProcessor"));
+ Assert.DoesNotContain(telemetryConfiguration.DefaultTelemetrySink.TelemetryProcessors, proc => proc.GetType().Name.Contains("QuickPulseTelemetryProcessor"));
+ }
+
+ ///
+ /// Sanity check to validate that node name and roleinstance are populated
+ ///
+ [Fact]
+ public static void SanityCheckRoleInstance()
+ {
+ // ARRANGE
+ string expected = Environment.MachineName;
+ var services = new ServiceCollection();
+ services.AddApplicationInsightsTelemetryWorkerService();
+ IServiceProvider serviceProvider = services.BuildServiceProvider();
+
+ // Request TC from DI which would be made with the default TelemetryConfiguration which should
+ // contain the telemetry initializer capable of populate node name and role instance name.
+ var tc = serviceProvider.GetRequiredService();
+ var mockItem = new EventTelemetry();
+
+ // ACT
+ // This is expected to run all TI and populate the node name and role instance.
+ tc.Initialize(mockItem);
+
+ // VERIFY
+ Assert.Contains(expected, mockItem.Context.Cloud.RoleInstance, StringComparison.CurrentCultureIgnoreCase);
+ }
+ }
+
+ internal class FakeTelemetryInitializer : ITelemetryInitializer
+ {
+ public FakeTelemetryInitializer()
+ {
+ }
+
+ public void Initialize(ITelemetry telemetry)
+ {
+
+ }
+ }
+}
diff --git a/test/Microsoft.ApplicationInsights.WorkerService.Tests/FunctionalTests.cs b/test/Microsoft.ApplicationInsights.WorkerService.Tests/FunctionalTests.cs
new file mode 100644
index 0000000..3441284
--- /dev/null
+++ b/test/Microsoft.ApplicationInsights.WorkerService.Tests/FunctionalTests.cs
@@ -0,0 +1,180 @@
+using Microsoft.ApplicationInsights.Channel;
+using Microsoft.ApplicationInsights.DataContracts;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Hosting;
+using System;
+using System.Collections.Concurrent;
+using System.Collections.Generic;
+using System.Text;
+using System.Threading.Tasks;
+using Xunit;
+using Xunit.Abstractions;
+
+namespace Microsoft.ApplicationInsights.WorkerService.Tests
+{
+ public class FunctionalTests
+ {
+ protected readonly ITestOutputHelper output;
+
+ public FunctionalTests(ITestOutputHelper output)
+ {
+ this.output = output;
+ }
+
+ [Fact]
+ public void BasicCollectionTest()
+ {
+ ConcurrentBag sentItems = new ConcurrentBag();
+
+ var host = new HostBuilder()
+ .ConfigureServices((hostContext, services) =>
+ {
+ services.AddSingleton(new StubChannel()
+ {
+ OnSend = (item) => sentItems.Add(item)
+ }); ;
+ services.AddApplicationInsightsTelemetryWorkerService("ikey");
+ services.AddHostedService();
+ }).Build();
+
+ host.Start();
+
+ // Run the worker for ~5 secs.
+ Task.Delay(5000).Wait();
+
+ host.StopAsync();
+
+ // The worker would have completed 5 loops in 5 sec,
+ // each look making dependency call and some ilogger logs,
+ // inside "myoperation"
+ Assert.True(sentItems.Count > 0);
+ PrintItems(sentItems);
+
+ // Validate
+ var reqs = GetTelemetryOfType(sentItems);
+ Assert.True(reqs.Count >= 1);
+ var traces = GetTelemetryOfType(sentItems);
+ Assert.True(traces.Count >= 1);
+ var deps = GetTelemetryOfType(sentItems);
+ Assert.True(deps.Count >= 1);
+
+ // Pick one RequestTelemetry and validate that trace/deps are found which are child of the parent request.
+ var reqOperationId = reqs[0].Context.Operation.Id;
+ var reqId = reqs[0].Id;
+ var trace = traces.Find((tr) => tr.Context.Operation.Id != null && tr.Context.Operation.Id.Equals(reqOperationId));
+ Assert.NotNull(trace);
+ trace = traces.Find((tr) => tr.Context.Operation.ParentId != null && tr.Context.Operation.ParentId.Equals(reqId));
+ Assert.NotNull(trace);
+
+ var dep = deps.Find((de) => de.Context.Operation.Id.Equals(reqOperationId));
+ Assert.NotNull(dep);
+ dep = deps.Find((de) => de.Context.Operation.ParentId.Equals(reqId));
+ Assert.NotNull(dep);
+ }
+
+ private List GetTelemetryOfType(ConcurrentBag items)
+ {
+ List foundItems = new List();
+ foreach (var item in items)
+ {
+ if (item is T)
+ {
+ foundItems.Add((T)item);
+ }
+ }
+
+ return foundItems;
+ }
+
+ private void PrintItems(ConcurrentBag items)
+ {
+ int i = 1;
+ foreach (var item in items)
+ {
+ this.output.WriteLine("Item " + (i++) + ".");
+
+ if (item is RequestTelemetry req)
+ {
+ this.output.WriteLine("RequestTelemetry");
+ this.output.WriteLine(req.Name);
+ this.output.WriteLine(req.Id);
+ PrintOperation(item);
+ this.output.WriteLine(req.Duration.ToString());
+ }
+ else if (item is DependencyTelemetry dep)
+ {
+ this.output.WriteLine("DependencyTelemetry");
+ this.output.WriteLine(dep.Name);
+ this.output.WriteLine(dep.Data);
+ PrintOperation(item);
+ }
+ else if (item is TraceTelemetry trace)
+ {
+ this.output.WriteLine("TraceTelemetry");
+ this.output.WriteLine(trace.Message);
+ PrintOperation(item);
+ }
+ else if (item is ExceptionTelemetry exc)
+ {
+ this.output.WriteLine("ExceptionTelemetry");
+ this.output.WriteLine(exc.Message);
+ PrintOperation(item);
+ }
+ else if (item is MetricTelemetry met)
+ {
+ this.output.WriteLine("MetricTelemetry");
+ this.output.WriteLine(met.Name + "" + met.Sum);
+ PrintOperation(item);
+ }
+
+ PrintProperties(item as ISupportProperties);
+ this.output.WriteLine("----------------------------");
+ }
+ }
+
+ private void PrintProperties(ISupportProperties itemProps)
+ {
+ foreach (var prop in itemProps.Properties)
+ {
+ this.output.WriteLine(prop.Key + ":" + prop.Value);
+ }
+ }
+
+ private void PrintOperation(ITelemetry item)
+ {
+ if(item.Context.Operation.Id != null)
+ this.output.WriteLine(item.Context.Operation.Id);
+ if(item.Context.Operation.ParentId != null)
+ this.output.WriteLine(item.Context.Operation.ParentId);
+ }
+ }
+
+ internal class StubChannel : ITelemetryChannel
+ {
+ public Action OnSend = t => { };
+
+ public string EndpointAddress
+ {
+ get;
+ set;
+ }
+
+ public bool? DeveloperMode { get; set; }
+
+ public void Dispose()
+ {
+ }
+
+ public void Flush()
+ {
+ }
+
+ public void Send(ITelemetry item)
+ {
+ this.OnSend(item);
+ }
+ }
+
+
+
+}
diff --git a/test/Microsoft.ApplicationInsights.WorkerService.Tests/Microsoft.ApplicationInsights.WorkerService.Tests.csproj b/test/Microsoft.ApplicationInsights.WorkerService.Tests/Microsoft.ApplicationInsights.WorkerService.Tests.csproj
new file mode 100644
index 0000000..084026a
--- /dev/null
+++ b/test/Microsoft.ApplicationInsights.WorkerService.Tests/Microsoft.ApplicationInsights.WorkerService.Tests.csproj
@@ -0,0 +1,38 @@
+
+
+
+ netcoreapp2.1
+ ..\..\artifacts\test\$(MSBuildProjectName)
+ ..\..\artifacts\obj\test\$(MSBuildProjectName)
+
+
+
+
+
+
+
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Always
+
+
+ Always
+
+
+
+
diff --git a/test/Microsoft.ApplicationInsights.WorkerService.Tests/Worker.cs b/test/Microsoft.ApplicationInsights.WorkerService.Tests/Worker.cs
new file mode 100644
index 0000000..69ac9f8
--- /dev/null
+++ b/test/Microsoft.ApplicationInsights.WorkerService.Tests/Worker.cs
@@ -0,0 +1,60 @@
+using Microsoft.ApplicationInsights.DataContracts;
+using Microsoft.Extensions.Hosting;
+using Microsoft.Extensions.Logging;
+using System;
+using System.Net.Http;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace Microsoft.ApplicationInsights.WorkerService.Tests
+{
+ internal class Worker : IHostedService
+ {
+ private readonly ILogger _logger;
+ private static HttpClient httpClient = new HttpClient();
+ private Timer _timer;
+ private TelemetryClient tc;
+
+ public Worker(ILogger logger, TelemetryClient tc)
+ {
+ _logger = logger;
+ this.tc = tc;
+ }
+
+ public Task StartAsync(CancellationToken cancellationToken)
+ {
+ _logger.LogInformation("information level log - starting");
+ _logger.LogWarning("warning level log - starting");
+
+ _timer = new Timer(DoWork, null, TimeSpan.Zero,
+ TimeSpan.FromSeconds(1));
+
+ return Task.CompletedTask;
+ }
+
+ private void DoWork(object state)
+ {
+ using (tc.StartOperation("myoperation"))
+ {
+ _logger.LogInformation("information level log - running");
+ _logger.LogWarning("warning level log - calling bing");
+ var res = httpClient.GetAsync("http://bing.com").Result.StatusCode;
+ _logger.LogWarning("warning level log - calling bing completed with status:" + res);
+ }
+ }
+
+ public Task StopAsync(CancellationToken cancellationToken)
+ {
+ _logger.LogInformation("Timed Background Service is stopping.");
+
+ _timer?.Change(Timeout.Infinite, 0);
+
+ return Task.CompletedTask;
+ }
+
+ public void Dispose()
+ {
+ _timer?.Dispose();
+ }
+ }
+}
\ No newline at end of file
diff --git a/test/Microsoft.ApplicationInsights.WorkerService.Tests/content/config-instrumentation-key-new.json b/test/Microsoft.ApplicationInsights.WorkerService.Tests/content/config-instrumentation-key-new.json
new file mode 100644
index 0000000..9032cd4
--- /dev/null
+++ b/test/Microsoft.ApplicationInsights.WorkerService.Tests/content/config-instrumentation-key-new.json
@@ -0,0 +1,5 @@
+{
+ "ApplicationInsights": {
+ "InstrumentationKey": "33333333-4444-5555-6666-777777777777"
+ }
+}
\ No newline at end of file
diff --git a/test/Microsoft.ApplicationInsights.WorkerService.Tests/content/sample-appsettings.json b/test/Microsoft.ApplicationInsights.WorkerService.Tests/content/sample-appsettings.json
new file mode 100644
index 0000000..cf17474
--- /dev/null
+++ b/test/Microsoft.ApplicationInsights.WorkerService.Tests/content/sample-appsettings.json
@@ -0,0 +1,9 @@
+{
+ "ApplicationInsights": {
+ "InstrumentationKey": "11111111-2222-3333-4444-555555555555",
+ "TelemetryChannel": {
+ "EndpointAddress": "http://testendpoint/v2/track",
+ "DeveloperMode": true
+ }
+ }
+}
\ No newline at end of file