Add new package for .NET Core WorkerServices (Adds GenericHost support) (#975)
This commit is contained in:
Родитель
1672611a16
Коммит
49fd6dddab
|
@ -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:
|
||||
|
|
|
@ -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}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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.
|
|||
/// <summary>
|
||||
/// Logs an event when a TelemetryModule is not found to configure.
|
||||
/// </summary>
|
||||
[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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Logs an event when QuickPulseTelemetryModule is not found in service collection.
|
||||
/// </summary>
|
||||
[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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Logs an event when telemetry is not tracked as the Listener is not active.
|
||||
/// </summary>
|
||||
|
@ -256,6 +249,18 @@ namespace Microsoft.ApplicationInsights.AspNetCore.Extensibility.Implementation.
|
|||
this.WriteEvent(22, message, exception, this.ApplicationName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Logs an informational event.
|
||||
/// </summary>
|
||||
[Event(
|
||||
23,
|
||||
Message = "Message : {0}",
|
||||
Level = EventLevel.Informational)]
|
||||
public void LogInformational(string message, string appDomainName = "Incorrect")
|
||||
{
|
||||
this.WriteEvent(23, message, this.ApplicationName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Keywords for the AspNetEventSource.
|
||||
/// </summary>
|
||||
|
|
|
@ -35,17 +35,8 @@
|
|||
/// <summary>
|
||||
/// Extension methods for <see cref="IServiceCollection"/> that allow adding Application Insights services to application.
|
||||
/// </summary>
|
||||
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<IHttpContextAccessor, HttpContextAccessor>();
|
||||
AddAspNetCoreWebTelemetryInitializers(services);
|
||||
AddCommonInitializers(services);
|
||||
|
||||
services
|
||||
.AddSingleton<ITelemetryInitializer, ApplicationInsights.AspNetCore.TelemetryInitializers.
|
||||
DomainNameRoleInstanceTelemetryInitializer>();
|
||||
services.AddSingleton<ITelemetryInitializer, AzureWebAppRoleEnvironmentTelemetryInitializer>();
|
||||
services.AddSingleton<ITelemetryInitializer, ComponentVersionTelemetryInitializer>();
|
||||
services.AddSingleton<ITelemetryInitializer, ClientIpHeaderTelemetryInitializer>();
|
||||
services.AddSingleton<ITelemetryInitializer, OperationNameTelemetryInitializer>();
|
||||
services.AddSingleton<ITelemetryInitializer, SyntheticTelemetryInitializer>();
|
||||
services.AddSingleton<ITelemetryInitializer, WebSessionTelemetryInitializer>();
|
||||
services.AddSingleton<ITelemetryInitializer, WebUserTelemetryInitializer>();
|
||||
services.AddSingleton<ITelemetryInitializer, AspNetCoreEnvironmentTelemetryInitializer>();
|
||||
services.AddSingleton<ITelemetryInitializer, HttpDependenciesParsingTelemetryInitializer>();
|
||||
services.TryAddSingleton<ITelemetryChannel, ServerTelemetryChannel>();
|
||||
|
||||
services.AddSingleton<ITelemetryModule, DependencyTrackingTelemetryModule>();
|
||||
services.ConfigureTelemetryModule<DependencyTrackingTelemetryModule>((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<ITelemetryModule, RequestTrackingTelemetryModule>();
|
||||
services.ConfigureTelemetryModule<RequestTrackingTelemetryModule>((module, options) =>
|
||||
{
|
||||
module.CollectionOptions = options.RequestCollectionOptions;
|
||||
});
|
||||
|
||||
services.AddSingleton<ITelemetryModule, PerformanceCollectorModule>();
|
||||
services.AddSingleton<ITelemetryModule, AppServicesHeartbeatTelemetryModule>();
|
||||
services.AddSingleton<ITelemetryModule, AzureInstanceMetadataTelemetryModule>();
|
||||
services.AddSingleton<ITelemetryModule, QuickPulseTelemetryModule>();
|
||||
services.AddSingleton<ITelemetryModule, RequestTrackingTelemetryModule>();
|
||||
AddCommonTelemetryModules(services);
|
||||
AddTelemetryChannel(services);
|
||||
|
||||
#if NETSTANDARD2_0
|
||||
services.AddSingleton<ITelemetryModule, EventCounterCollectionModule>();
|
||||
services.ConfigureTelemetryModule<EventCounterCollectionModule>((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<TelemetryConfiguration>(provider =>
|
||||
provider.GetService<IOptions<TelemetryConfiguration>>().Value);
|
||||
|
||||
services.TryAddSingleton<IApplicationIdProvider, ApplicationInsightsApplicationIdProvider>();
|
||||
|
||||
services.AddSingleton<TelemetryClient>();
|
||||
|
||||
services
|
||||
.TryAddSingleton<IConfigureOptions<ApplicationInsightsServiceOptions>,
|
||||
services.TryAddSingleton<IConfigureOptions<ApplicationInsightsServiceOptions>,
|
||||
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<IStartupFilter, ApplicationInsightsStartupFilter>();
|
||||
services.AddSingleton<IJavaScriptSnippet, JavaScriptSnippet>();
|
||||
services.AddSingleton<JavaScriptSnippet>(); // Add 'JavaScriptSnippet' "Service" for backwards compatibility. To remove in favour of 'IJavaScriptSnippet'.
|
||||
|
||||
services.AddOptions();
|
||||
services.AddSingleton<IOptions<TelemetryConfiguration>, TelemetryConfigurationOptions>();
|
||||
services
|
||||
.AddSingleton<IConfigureOptions<TelemetryConfiguration>, TelemetryConfigurationOptionsSetup>();
|
||||
// Add 'JavaScriptSnippet' "Service" for backwards compatibility. To remove in favour of 'IJavaScriptSnippet'.
|
||||
services.AddSingleton<JavaScriptSnippet>();
|
||||
|
||||
// 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<Microsoft.Extensions.Logging.ApplicationInsights.ApplicationInsightsLoggerProvider>("",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<LoggerFilterOptions>(
|
||||
options => options.Rules.Insert(
|
||||
0,
|
||||
new LoggerFilterRule(
|
||||
"Microsoft.Extensions.Logging.ApplicationInsights.ApplicationInsightsLoggerProvider", null,
|
||||
LogLevel.Warning, null)));
|
||||
});
|
||||
AddApplicationInsightsLoggerProvider(services);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -295,210 +187,14 @@
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds an Application Insights Telemetry Processor into a service collection via a <see cref="ITelemetryProcessorFactory"/>.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Type of the telemetry processor to add.</typeparam>
|
||||
/// <param name="services">The <see cref="IServiceCollection"/> instance.</param>
|
||||
/// <returns>
|
||||
/// The <see cref="IServiceCollection"/>.
|
||||
/// </returns>
|
||||
public static IServiceCollection AddApplicationInsightsTelemetryProcessor<T>(this IServiceCollection services)
|
||||
where T : ITelemetryProcessor
|
||||
private static void AddAspNetCoreWebTelemetryInitializers(IServiceCollection services)
|
||||
{
|
||||
return services.AddSingleton<ITelemetryProcessorFactory>(serviceProvider =>
|
||||
new TelemetryProcessorFactory(serviceProvider, typeof(T)));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds an Application Insights Telemetry Processor into a service collection via a <see cref="ITelemetryProcessorFactory"/>.
|
||||
/// </summary>
|
||||
/// <param name="services">The <see cref="IServiceCollection"/> instance.</param>
|
||||
/// <param name="telemetryProcessorType">Type of the telemetry processor to add.</param>
|
||||
/// <returns>
|
||||
/// The <see cref="IServiceCollection"/>.
|
||||
/// </returns>
|
||||
/// <exception cref="ArgumentNullException">The <paramref name="telemetryProcessorType"/> argument is null.</exception>
|
||||
/// <exception cref="ArgumentException">The <paramref name="telemetryProcessorType"/> type does not implement <see cref="ITelemetryProcessor"/>.</exception>
|
||||
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<ITelemetryProcessorFactory>(serviceProvider =>
|
||||
new TelemetryProcessorFactory(serviceProvider, telemetryProcessorType));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Extension method to provide configuration logic for application insights telemetry module.
|
||||
/// </summary>
|
||||
/// <param name="services">The <see cref="IServiceCollection"/> instance.</param>
|
||||
/// <param name="configModule">Action used to configure the module.</param>
|
||||
/// <returns>
|
||||
/// The <see cref="IServiceCollection"/>.
|
||||
/// </returns>
|
||||
[Obsolete("Use ConfigureTelemetryModule overload that accepts ApplicationInsightsServiceOptions.")]
|
||||
public static IServiceCollection ConfigureTelemetryModule<T>(this IServiceCollection services, Action<T> 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)));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Extension method to provide configuration logic for application insights telemetry module.
|
||||
/// </summary>
|
||||
/// <param name="services">The <see cref="IServiceCollection"/> instance.</param>
|
||||
/// <param name="configModule">Action used to configure the module.</param>
|
||||
/// <returns>
|
||||
/// The <see cref="IServiceCollection"/>.
|
||||
/// </returns>
|
||||
public static IServiceCollection ConfigureTelemetryModule<T>(
|
||||
this IServiceCollection services,
|
||||
Action<T, ApplicationInsightsServiceOptions> 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)));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds Application Insight specific configuration properties to <see cref="IConfigurationBuilder"/>.
|
||||
/// </summary>
|
||||
/// <param name="configurationSourceRoot">The <see cref="IConfigurationBuilder"/> instance.</param>
|
||||
/// <param name="developerMode">Enables or disables developer mode.</param>
|
||||
/// <param name="endpointAddress">Sets telemetry endpoint address.</param>
|
||||
/// <param name="instrumentationKey">Sets instrumentation key.</param>
|
||||
/// <returns>The <see cref="IConfigurationBuilder"/>.</returns>
|
||||
public static IConfigurationBuilder AddApplicationInsightsSettings(
|
||||
this IConfigurationBuilder configurationSourceRoot,
|
||||
bool? developerMode = null,
|
||||
string endpointAddress = null,
|
||||
string instrumentationKey = null)
|
||||
{
|
||||
var telemetryConfigValues = new List<KeyValuePair<string, string>>();
|
||||
|
||||
bool wasAnythingSet = false;
|
||||
|
||||
if (developerMode != null)
|
||||
{
|
||||
telemetryConfigValues.Add(new KeyValuePair<string, string>(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<string, string>(InstrumentationKeyForWebSites,
|
||||
instrumentationKey));
|
||||
wasAnythingSet = true;
|
||||
}
|
||||
|
||||
if (endpointAddress != null)
|
||||
{
|
||||
telemetryConfigValues.Add(new KeyValuePair<string, string>(
|
||||
EndpointAddressForWebSites,
|
||||
endpointAddress));
|
||||
wasAnythingSet = true;
|
||||
}
|
||||
|
||||
if (wasAnythingSet)
|
||||
{
|
||||
configurationSourceRoot.Add(new MemoryConfigurationSource() { InitialData = telemetryConfigValues });
|
||||
}
|
||||
|
||||
return configurationSourceRoot;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read from configuration
|
||||
/// Config.json will look like this:
|
||||
/// <para>
|
||||
/// "ApplicationInsights": {
|
||||
/// "InstrumentationKey": "11111111-2222-3333-4444-555555555555"
|
||||
/// "TelemetryChannel": {
|
||||
/// "EndpointAddress": "http://dc.services.visualstudio.com/v2/track",
|
||||
/// "DeveloperMode": true
|
||||
/// }
|
||||
/// }.
|
||||
/// </para>
|
||||
/// Values can also be read from environment variables to support azure web sites configuration.
|
||||
/// </summary>
|
||||
/// <param name="config">Configuration to read variables from.</param>
|
||||
/// <param name="serviceOptions">Telemetry configuration to populate.</param>
|
||||
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<ITelemetryInitializer, ClientIpHeaderTelemetryInitializer>();
|
||||
services.AddSingleton<ITelemetryInitializer, OperationNameTelemetryInitializer>();
|
||||
services.AddSingleton<ITelemetryInitializer, SyntheticTelemetryInitializer>();
|
||||
services.AddSingleton<ITelemetryInitializer, WebSessionTelemetryInitializer>();
|
||||
services.AddSingleton<ITelemetryInitializer, WebUserTelemetryInitializer>();
|
||||
services.AddSingleton<ITelemetryInitializer, AspNetCoreEnvironmentTelemetryInitializer>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,12 +3,13 @@
|
|||
<AssemblyName>Microsoft.ApplicationInsights.AspNetCore</AssemblyName>
|
||||
<VersionPrefix>2.8.0-beta3</VersionPrefix>
|
||||
<LangVersion>7.2</LangVersion>
|
||||
<TargetFrameworks>net451;net46;netstandard1.6;netstandard2.0</TargetFrameworks>
|
||||
<TargetFrameworks>netstandard2.0;net451;net46;netstandard1.6</TargetFrameworks>
|
||||
<TargetFrameworks Condition=" '$(OS)' != 'Windows_NT' ">netstandard1.6;netstandard2.0</TargetFrameworks>
|
||||
|
||||
<NetStandardImplicitPackageVersion Condition=" '$(TargetFramework)' == 'netstandard1.6' ">1.6.1</NetStandardImplicitPackageVersion>
|
||||
<OutputPath Condition="'$(OutputPath)'=='' ">..\..\artifacts\src\$(MSBuildProjectName)</OutputPath>
|
||||
<IntermediateOutputPath Condition="'$(IntermediateOutputPath)'=='' ">..\..\artifacts\obj\src\$(MSBuildProjectName)</IntermediateOutputPath>
|
||||
<DefineConstants>$(DefineConstants);AI_ASPNETCORE_WEB;</DefineConstants>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
|
@ -72,6 +73,9 @@
|
|||
</PackageReference>
|
||||
</ItemGroup>
|
||||
|
||||
<Import Project="..\Shared\Shared.projitems" Label="Shared" />
|
||||
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.ApplicationInsights" Version="2.11.0-beta2" />
|
||||
<PackageReference Include="Microsoft.ApplicationInsights.DependencyCollector" Version="2.11.0-beta2" />
|
||||
|
@ -90,8 +94,8 @@
|
|||
|
||||
<ItemGroup Condition=" '$(TargetFramework)' == 'netstandard2.0' ">
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="2.1.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.ApplicationInsights" Version="2.11.0-beta1" />
|
||||
<PackageReference Include="Microsoft.ApplicationInsights.EventCounterCollector" Version="2.11.0-beta1" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.ApplicationInsights" Version="2.11.0-beta2" />
|
||||
<PackageReference Include="Microsoft.ApplicationInsights.EventCounterCollector" Version="2.11.0-beta2" />
|
||||
<PackageReference Include="System.Text.Encodings.Web" Version="4.3.1" />
|
||||
</ItemGroup>
|
||||
|
||||
|
|
|
@ -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
|
||||
{
|
||||
/// <summary>
|
||||
/// Extension methods for <see cref="IServiceCollection"/> that allow adding Application Insights services to application.
|
||||
/// </summary>
|
||||
public static partial class ApplicationInsightsExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Adds Application Insights services into service collection.
|
||||
/// </summary>
|
||||
/// <param name="services">The <see cref="IServiceCollection"/> instance.</param>
|
||||
/// <param name="instrumentationKey">Instrumentation key to use for telemetry.</param>
|
||||
/// <returns>The <see cref="IServiceCollection"/>.</returns>
|
||||
public static IServiceCollection AddApplicationInsightsTelemetryWorkerService(
|
||||
this IServiceCollection services,
|
||||
string instrumentationKey)
|
||||
{
|
||||
services.AddApplicationInsightsTelemetryWorkerService(options => options.InstrumentationKey = instrumentationKey);
|
||||
return services;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds Application Insights services into service collection.
|
||||
/// </summary>
|
||||
/// <param name="services">The <see cref="IServiceCollection"/> instance.</param>
|
||||
/// <param name="configuration">Configuration to use for sending telemetry.</param>
|
||||
/// <returns>The <see cref="IServiceCollection"/>.</returns>
|
||||
public static IServiceCollection AddApplicationInsightsTelemetryWorkerService(
|
||||
this IServiceCollection services,
|
||||
IConfiguration configuration)
|
||||
{
|
||||
services.AddApplicationInsightsTelemetryWorkerService(options => AddTelemetryConfiguration(configuration, options));
|
||||
return services;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds Application Insights services into service collection.
|
||||
/// </summary>
|
||||
/// <param name="services">The <see cref="IServiceCollection"/> instance.</param>
|
||||
/// <param name="options">The action used to configure the options.</param>
|
||||
/// <returns>
|
||||
/// The <see cref="IServiceCollection"/>.
|
||||
/// </returns>
|
||||
public static IServiceCollection AddApplicationInsightsTelemetryWorkerService(
|
||||
this IServiceCollection services,
|
||||
Action<ApplicationInsightsServiceOptions> options)
|
||||
{
|
||||
services.AddApplicationInsightsTelemetryWorkerService();
|
||||
services.Configure(options);
|
||||
return services;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds Application Insights services into service collection.
|
||||
/// </summary>
|
||||
/// <param name="services">The <see cref="IServiceCollection"/> instance.</param>
|
||||
/// <param name="options">The options instance used to configure with.</param>
|
||||
/// <returns>
|
||||
/// The <see cref="IServiceCollection"/>.
|
||||
/// </returns>
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds Application Insights services into service collection.
|
||||
/// </summary>
|
||||
/// <param name="services">The <see cref="IServiceCollection"/> instance.</param>
|
||||
/// <returns>
|
||||
/// The <see cref="IServiceCollection"/>.
|
||||
/// </returns>
|
||||
public static IServiceCollection AddApplicationInsightsTelemetryWorkerService(this IServiceCollection services)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!IsApplicationInsightsAdded(services))
|
||||
{
|
||||
AddCommonInitializers(services);
|
||||
AddCommonTelemetryModules(services);
|
||||
AddTelemetryChannel(services);
|
||||
|
||||
ConfigureEventCounterModuleWithSystemCounters(services);
|
||||
|
||||
|
||||
services
|
||||
.TryAddSingleton<IConfigureOptions<ApplicationInsightsServiceOptions>,
|
||||
DefaultApplicationInsightsServiceConfigureOptions>();
|
||||
|
||||
AddDefaultApplicationIdProvider(services);
|
||||
AddTelemetryConfigAndClient(services);
|
||||
AddApplicationInsightsLoggerProvider(services);
|
||||
}
|
||||
|
||||
return services;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
WorkerServiceEventSource.Instance.LogError(e.ToInvariantString());
|
||||
return services;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
|
||||
/// <summary>
|
||||
/// <see cref="IConfigureOptions<ApplicationInsightsServiceOptions>"/> implementation that reads options from provided IConfiguration
|
||||
/// </summary>
|
||||
internal class DefaultApplicationInsightsServiceConfigureOptions : IConfigureOptions<ApplicationInsightsServiceOptions>
|
||||
{
|
||||
private readonly IConfiguration configuration;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance of <see cref="DefaultApplicationInsightsServiceConfigureOptions"/>
|
||||
/// </summary>
|
||||
/// <param name="configuration"><see cref="IConfiguration"/> from which configuraion for ApplicationInsights can be retrieved.</param>
|
||||
public DefaultApplicationInsightsServiceConfigureOptions(IConfiguration configuration = null)
|
||||
{
|
||||
this.configuration = configuration;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Configure(ApplicationInsightsServiceOptions options)
|
||||
{
|
||||
if (configuration != null)
|
||||
{
|
||||
ApplicationInsightsExtensions.AddTelemetryConfiguration(configuration, options);
|
||||
}
|
||||
|
||||
if (Debugger.IsAttached)
|
||||
{
|
||||
options.DeveloperMode = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
namespace Microsoft.Extensions.DependencyInjection
|
||||
{
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Microsoft.ApplicationInsights.Extensibility;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="IOptions{TelemetryConfiguration}"/> implementation that create new <see cref="TelemetryConfiguration"/> every time when called".
|
||||
/// </summary>
|
||||
internal class TelemetryConfigurationOptions : IOptions<TelemetryConfiguration>
|
||||
{
|
||||
private static readonly object lockObject = new object();
|
||||
|
||||
public TelemetryConfigurationOptions(IEnumerable<IConfigureOptions<TelemetryConfiguration>> configureOptions)
|
||||
{
|
||||
this.Value = TelemetryConfiguration.CreateDefault();
|
||||
|
||||
var configureOptionsArray = configureOptions.ToArray();
|
||||
foreach (var c in configureOptionsArray)
|
||||
{
|
||||
c.Configure(this.Value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public TelemetryConfiguration Value { get; }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,120 @@
|
|||
//-----------------------------------------------------------------------
|
||||
// <copyright file="WorkerServiceEventSource.cs" company="Microsoft">
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// </copyright>
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
namespace Microsoft.ApplicationInsights.WorkerService.Implementation.Tracing
|
||||
{
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Diagnostics.Tracing;
|
||||
|
||||
/// <summary>
|
||||
/// Event source for Application Insights Worker Service SDK.
|
||||
/// </summary>
|
||||
[EventSource(Name = "Microsoft-ApplicationInsights-WorkerService")]
|
||||
[SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", Justification = "appDomainName is required")]
|
||||
internal sealed class WorkerServiceEventSource : EventSource
|
||||
{
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
public static readonly WorkerServiceEventSource Instance = new WorkerServiceEventSource();
|
||||
|
||||
/// <summary>
|
||||
/// Prevents a default instance of the <see cref="WorkerServiceEventSource"/> class from being created.
|
||||
/// </summary>
|
||||
private WorkerServiceEventSource()
|
||||
: base()
|
||||
{
|
||||
try
|
||||
{
|
||||
this.ApplicationName = System.Reflection.Assembly.GetEntryAssembly().GetName().Name;
|
||||
}
|
||||
catch (Exception exp)
|
||||
{
|
||||
this.ApplicationName = "Undefined " + exp.Message;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the application name for use in logging events.
|
||||
/// </summary>
|
||||
public string ApplicationName
|
||||
{
|
||||
[NonEvent]
|
||||
get;
|
||||
[NonEvent]
|
||||
private set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Logs informational message.
|
||||
/// </summary>
|
||||
/// <param name="message">Message</param>
|
||||
/// <param name="appDomainName">An ignored placeholder to make EventSource happy.</param>
|
||||
[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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Logs warning message.
|
||||
/// </summary>
|
||||
/// <param name="message">Message</param>
|
||||
/// <param name="appDomainName">An ignored placeholder to make EventSource happy.</param>
|
||||
[Event(2, Message = "Message : {0}", Level = EventLevel.Warning)]
|
||||
public void LogWarning(string message, string appDomainName = "Incorrect")
|
||||
{
|
||||
this.WriteEvent(2, message, this.ApplicationName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Logs error message.
|
||||
/// </summary>
|
||||
/// <param name="message">Message</param>
|
||||
/// <param name="appDomainName">An ignored placeholder to make EventSource happy.</param>
|
||||
[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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Logs an event when a TelemetryModule is not found to configure.
|
||||
/// </summary>
|
||||
[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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Logs an event when TelemetryConfiguration configure has failed.
|
||||
/// </summary>
|
||||
[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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Keywords for the AspNetEventSource.
|
||||
/// </summary>
|
||||
public sealed class Keywords
|
||||
{
|
||||
/// <summary>
|
||||
/// Keyword for errors that trace at Verbose level.
|
||||
/// </summary>
|
||||
public const EventKeywords Diagnostics = (EventKeywords)0x1;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,94 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<AssemblyName>Microsoft.ApplicationInsights.WorkerService</AssemblyName>
|
||||
<VersionPrefix>2.8.0-beta3</VersionPrefix>
|
||||
<LangVersion>7.2</LangVersion>
|
||||
<TargetFrameworks>netstandard2.0</TargetFrameworks>
|
||||
<OutputPath Condition="'$(OutputPath)'=='' ">..\..\artifacts\src\$(MSBuildProjectName)</OutputPath>
|
||||
<IntermediateOutputPath Condition="'$(IntermediateOutputPath)'=='' ">..\..\artifacts\obj\src\$(MSBuildProjectName)</IntermediateOutputPath>
|
||||
<DefineConstants>$(DefineConstants);AI_ASPNETCORE_WORKER;</DefineConstants>
|
||||
</PropertyGroup>
|
||||
|
||||
|
||||
<PropertyGroup>
|
||||
<!--Nupkg properties-->
|
||||
<PackageId>Microsoft.ApplicationInsights.WorkerService</PackageId>
|
||||
<AssemblyTitle>Application Insights for .NET Core Worker Service Applications</AssemblyTitle>
|
||||
<Title>Application Insights for .NET Core Worker Service Applications</Title>
|
||||
<Description>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</Description>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<!--Normalized Nupkg properties. I will remove this PropertyGroup in a follow up PR.-->
|
||||
<Authors>Microsoft</Authors>
|
||||
<Copyright>© Microsoft Corporation. All rights reserved.</Copyright>
|
||||
<RepositoryType>git</RepositoryType>
|
||||
<RepositoryUrl>https://github.com/Microsoft/ApplicationInsights-aspnetcore.git</RepositoryUrl>
|
||||
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
|
||||
<IncludeSymbols>True</IncludeSymbols>
|
||||
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
|
||||
<PackageTags>Azure;Monitoring;Analytics;ApplicationInsights;Telemetry;AppInsights;aspnetcore;worker;console;backgroundtasks</PackageTags>
|
||||
<PackageIconUrl>https://appanacdn.blob.core.windows.net/cdn/icons/aic.png</PackageIconUrl>
|
||||
<PackageLicenseExpression>MIT</PackageLicenseExpression>
|
||||
<PackageProjectUrl>https://go.microsoft.com/fwlink/?LinkId=392727</PackageProjectUrl>
|
||||
<PackageRequireLicenseAcceptance>true</PackageRequireLicenseAcceptance>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<!--Package Settings-->
|
||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
|
||||
<!--Symbols Settings-->
|
||||
<DebugType>full</DebugType>
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup Condition=" '$(Configuration)' == 'Release' And $(OS) == 'Windows_NT'">
|
||||
<!--Analyzers-->
|
||||
<PackageReference Include="Desktop.Analyzers" Version="1.1.0">
|
||||
<PrivateAssets>All</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118">
|
||||
<PrivateAssets>All</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.FxCopAnalyzers" Version="2.9.2">
|
||||
<PrivateAssets>All</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="2.9.2">
|
||||
<PrivateAssets>All</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Roslyn.Diagnostics.Analyzers" Version="2.9.2">
|
||||
<PrivateAssets>All</PrivateAssets>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<!--Build Infrastructure-->
|
||||
<PackageReference Include="MicroBuild.Core" Version="0.3.0">
|
||||
<PrivateAssets>All</PrivateAssets>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
|
||||
<Import Project="..\Shared\Shared.projitems" Label="Shared" />
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.ApplicationInsights" Version="2.11.0-beta2" />
|
||||
<PackageReference Include="Microsoft.ApplicationInsights.DependencyCollector" Version="2.11.0-beta2" />
|
||||
<PackageReference Include="Microsoft.ApplicationInsights.PerfCounterCollector" Version="2.11.0-beta2" />
|
||||
<PackageReference Include="Microsoft.ApplicationInsights.WindowsServer" Version="2.11.0-beta2" />
|
||||
<PackageReference Include="Microsoft.ApplicationInsights.WindowsServer.TelemetryChannel" Version="2.11.0-beta2" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.ApplicationInsights" Version="2.11.0-beta2" />
|
||||
<PackageReference Include="Microsoft.ApplicationInsights.EventCounterCollector" Version="2.11.0-beta2" />
|
||||
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="2.2.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ImportGroup Condition=" '$(OS)' == 'Windows_NT' ">
|
||||
<!-- 1 file is required for signing: Signing.props -->
|
||||
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), 'Signing.props'))\Signing.props" />
|
||||
</ImportGroup>
|
||||
|
||||
</Project>
|
|
@ -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;
|
||||
|
||||
/// <summary>
|
||||
/// Extension methods for <see cref="IServiceCollection"/> that allow adding Application Insights services to application.
|
||||
/// </summary>
|
||||
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";
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Adds an Application Insights Telemetry Processor into a service collection via a <see cref="ITelemetryProcessorFactory"/>.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Type of the telemetry processor to add.</typeparam>
|
||||
/// <param name="services">The <see cref="IServiceCollection"/> instance.</param>
|
||||
/// <returns>
|
||||
/// The <see cref="IServiceCollection"/>.
|
||||
/// </returns>
|
||||
public static IServiceCollection AddApplicationInsightsTelemetryProcessor<T>(this IServiceCollection services)
|
||||
where T : ITelemetryProcessor
|
||||
{
|
||||
return services.AddSingleton<ITelemetryProcessorFactory>(serviceProvider =>
|
||||
new TelemetryProcessorFactory(serviceProvider, typeof(T)));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds an Application Insights Telemetry Processor into a service collection via a <see cref="ITelemetryProcessorFactory"/>.
|
||||
/// </summary>
|
||||
/// <param name="services">The <see cref="IServiceCollection"/> instance.</param>
|
||||
/// <param name="telemetryProcessorType">Type of the telemetry processor to add.</param>
|
||||
/// <returns>
|
||||
/// The <see cref="IServiceCollection"/>.
|
||||
/// </returns>
|
||||
/// <exception cref="ArgumentNullException">The <paramref name="telemetryProcessorType"/> argument is null.</exception>
|
||||
/// <exception cref="ArgumentException">The <paramref name="telemetryProcessorType"/> type does not implement <see cref="ITelemetryProcessor"/>.</exception>
|
||||
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<ITelemetryProcessorFactory>(serviceProvider =>
|
||||
new TelemetryProcessorFactory(serviceProvider, telemetryProcessorType));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Extension method to provide configuration logic for application insights telemetry module.
|
||||
/// </summary>
|
||||
/// <param name="services">The <see cref="IServiceCollection"/> instance.</param>
|
||||
/// <param name="configModule">Action used to configure the module.</param>
|
||||
/// <returns>
|
||||
/// The <see cref="IServiceCollection"/>.
|
||||
/// </returns>
|
||||
[Obsolete("Use ConfigureTelemetryModule overload that accepts ApplicationInsightsServiceOptions.")]
|
||||
public static IServiceCollection ConfigureTelemetryModule<T>(this IServiceCollection services, Action<T> 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)));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Extension method to provide configuration logic for application insights telemetry module.
|
||||
/// </summary>
|
||||
/// <param name="services">The <see cref="IServiceCollection"/> instance.</param>
|
||||
/// <param name="configModule">Action used to configure the module.</param>
|
||||
/// <returns>
|
||||
/// The <see cref="IServiceCollection"/>.
|
||||
/// </returns>
|
||||
public static IServiceCollection ConfigureTelemetryModule<T>(
|
||||
this IServiceCollection services,
|
||||
Action<T, ApplicationInsightsServiceOptions> 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)));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds Application Insight specific configuration properties to <see cref="IConfigurationBuilder"/>.
|
||||
/// </summary>
|
||||
/// <param name="configurationSourceRoot">The <see cref="IConfigurationBuilder"/> instance.</param>
|
||||
/// <param name="developerMode">Enables or disables developer mode.</param>
|
||||
/// <param name="endpointAddress">Sets telemetry endpoint address.</param>
|
||||
/// <param name="instrumentationKey">Sets instrumentation key.</param>
|
||||
/// <returns>The <see cref="IConfigurationBuilder"/>.</returns>
|
||||
public static IConfigurationBuilder AddApplicationInsightsSettings(
|
||||
this IConfigurationBuilder configurationSourceRoot,
|
||||
bool? developerMode = null,
|
||||
string endpointAddress = null,
|
||||
string instrumentationKey = null)
|
||||
{
|
||||
var telemetryConfigValues = new List<KeyValuePair<string, string>>();
|
||||
|
||||
bool wasAnythingSet = false;
|
||||
|
||||
if (developerMode != null)
|
||||
{
|
||||
telemetryConfigValues.Add(new KeyValuePair<string, string>(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<string, string>(InstrumentationKeyForWebSites,
|
||||
instrumentationKey));
|
||||
wasAnythingSet = true;
|
||||
}
|
||||
|
||||
if (endpointAddress != null)
|
||||
{
|
||||
telemetryConfigValues.Add(new KeyValuePair<string, string>(
|
||||
EndpointAddressForWebSites,
|
||||
endpointAddress));
|
||||
wasAnythingSet = true;
|
||||
}
|
||||
|
||||
if (wasAnythingSet)
|
||||
{
|
||||
configurationSourceRoot.Add(new MemoryConfigurationSource() { InitialData = telemetryConfigValues });
|
||||
}
|
||||
|
||||
return configurationSourceRoot;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read from configuration
|
||||
/// Config.json will look like this:
|
||||
/// <para>
|
||||
/// "ApplicationInsights": {
|
||||
/// "InstrumentationKey": "11111111-2222-3333-4444-555555555555"
|
||||
/// "TelemetryChannel": {
|
||||
/// "EndpointAddress": "http://dc.services.visualstudio.com/v2/track",
|
||||
/// "DeveloperMode": true
|
||||
/// }
|
||||
/// }.
|
||||
/// </para>
|
||||
/// Values can also be read from environment variables to support azure web sites configuration.
|
||||
/// </summary>
|
||||
/// <param name="config">Configuration to read variables from.</param>
|
||||
/// <param name="serviceOptions">Telemetry configuration to populate.</param>
|
||||
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<ITelemetryInitializer, Microsoft.ApplicationInsights.AspNetCore.TelemetryInitializers.DomainNameRoleInstanceTelemetryInitializer>();
|
||||
#else
|
||||
services.AddSingleton<ITelemetryInitializer, Microsoft.ApplicationInsights.WorkerService.TelemetryInitializers.DomainNameRoleInstanceTelemetryInitializer>();
|
||||
#endif
|
||||
services.AddSingleton<ITelemetryInitializer, AzureWebAppRoleEnvironmentTelemetryInitializer>();
|
||||
services.AddSingleton<ITelemetryInitializer, HttpDependenciesParsingTelemetryInitializer>();
|
||||
services.AddSingleton<ITelemetryInitializer, ComponentVersionTelemetryInitializer>();
|
||||
}
|
||||
|
||||
private static void AddCommonTelemetryModules(IServiceCollection services)
|
||||
{
|
||||
services.AddSingleton<ITelemetryModule, PerformanceCollectorModule>();
|
||||
services.AddSingleton<ITelemetryModule, AppServicesHeartbeatTelemetryModule>();
|
||||
services.AddSingleton<ITelemetryModule, AzureInstanceMetadataTelemetryModule>();
|
||||
services.AddSingleton<ITelemetryModule, QuickPulseTelemetryModule>();
|
||||
AddAndConfigureDependencyTracking(services);
|
||||
#if NETSTANDARD2_0
|
||||
services.AddSingleton<ITelemetryModule, EventCounterCollectionModule>();
|
||||
#endif
|
||||
}
|
||||
|
||||
private static void AddTelemetryChannel(IServiceCollection services)
|
||||
{
|
||||
services.TryAddSingleton<ITelemetryChannel, ServerTelemetryChannel>();
|
||||
}
|
||||
|
||||
private static void AddDefaultApplicationIdProvider(IServiceCollection services)
|
||||
{
|
||||
services.TryAddSingleton<IApplicationIdProvider, ApplicationInsightsApplicationIdProvider>();
|
||||
}
|
||||
|
||||
private static void AddTelemetryConfigAndClient(IServiceCollection services)
|
||||
{
|
||||
services.AddOptions();
|
||||
services.AddSingleton<IOptions<TelemetryConfiguration>, TelemetryConfigurationOptions>();
|
||||
services.AddSingleton<IConfigureOptions<TelemetryConfiguration>, TelemetryConfigurationOptionsSetup>();
|
||||
services.AddSingleton<TelemetryConfiguration>(provider =>
|
||||
provider.GetService<IOptions<TelemetryConfiguration>>().Value);
|
||||
services.AddSingleton<TelemetryClient>();
|
||||
}
|
||||
|
||||
private static void AddAndConfigureDependencyTracking(IServiceCollection services)
|
||||
{
|
||||
services.AddSingleton<ITelemetryModule, DependencyTrackingTelemetryModule>();
|
||||
services.ConfigureTelemetryModule<DependencyTrackingTelemetryModule>((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<EventCounterCollectionModule>((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<EventCounterCollectionModule>((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<Microsoft.Extensions.Logging.ApplicationInsights.ApplicationInsightsLoggerProvider>("",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<LoggerFilterOptions>(
|
||||
options => options.Rules.Insert(
|
||||
0,
|
||||
new LoggerFilterRule(
|
||||
"Microsoft.Extensions.Logging.ApplicationInsights.ApplicationInsightsLoggerProvider", null,
|
||||
LogLevel.Warning, null)));
|
||||
});
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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 @@
|
|||
/// </summary>
|
||||
public bool AddAutoCollectedMetricExtractor { get; set; }
|
||||
|
||||
#if AI_ASPNETCORE_WEB
|
||||
/// <summary>
|
||||
/// Gets <see cref="RequestCollectionOptions"/> that allow to manage <see cref="RequestTrackingTelemetryModule"/>
|
||||
/// </summary>
|
||||
public RequestCollectionOptions RequestCollectionOptions { get; }
|
||||
#endif
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets <see cref="DependencyCollectionOptions"/> that allow to manage <see cref="DependencyTrackingTelemetryModule"/>
|
|
@ -1,4 +1,8 @@
|
|||
namespace Microsoft.ApplicationInsights.AspNetCore.Extensions
|
||||
#if AI_ASPNETCORE_WEB
|
||||
namespace Microsoft.ApplicationInsights.AspNetCore.Extensions
|
||||
#else
|
||||
namespace Microsoft.ApplicationInsights.WorkerService
|
||||
#endif
|
||||
{
|
||||
/// <summary>
|
||||
/// Default collection options define the custom behavior or non-default features of dependency collection.
|
|
@ -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;
|
||||
|
|
@ -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;
|
|
@ -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;
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
|
||||
/// <summary>
|
|
@ -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;
|
|
@ -0,0 +1,23 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<MSBuildAllProjects>$(MSBuildAllProjects);$(MSBuildThisFileFullPath)</MSBuildAllProjects>
|
||||
<HasSharedItems>true</HasSharedItems>
|
||||
<SharedGUID>d56f2979-d6bc-4ef2-bb9b-4077b3290599</SharedGUID>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Label="Configuration">
|
||||
<Import_RootNamespace>Shared</Import_RootNamespace>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Extensions\ApplicationInsightsExtensions.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Extensions\ApplicationInsightsServiceOptions.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Extensions\DependencyCollectionOptions.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Implementation\ITelemetryModuleConfigurator.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Implementation\ITelemetryProcessorFactory.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Implementation\TelemetryConfigurationOptionsSetup.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Implementation\TelemetryModuleConfigurator.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Implementation\TelemetryProcessorFactory.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)TelemetryInitializers\ComponentVersionTelemetryInitializer.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)TelemetryInitializers\DomainNameRoleInstanceTelemetryInitializer.cs" />
|
||||
</ItemGroup>
|
||||
</Project>
|
|
@ -0,0 +1,13 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>d56f2979-d6bc-4ef2-bb9b-4077b3290599</ProjectGuid>
|
||||
<MinimumVisualStudioVersion>14.0</MinimumVisualStudioVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\CodeSharing\Microsoft.CodeSharing.Common.Default.props" />
|
||||
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\CodeSharing\Microsoft.CodeSharing.Common.props" />
|
||||
<PropertyGroup />
|
||||
<Import Project="Shared.projitems" Label="Shared" />
|
||||
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\CodeSharing\Microsoft.CodeSharing.CSharp.targets" />
|
||||
</Project>
|
|
@ -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;
|
||||
|
||||
/// <summary>
|
|
@ -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;
|
||||
|
||||
/// <summary>
|
||||
/// 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;
|
|
@ -47,8 +47,6 @@ namespace Microsoft.Extensions.DependencyInjection.Test
|
|||
public static ServiceCollection GetServiceCollectionWithContextAccessor()
|
||||
{
|
||||
var services = new ServiceCollection();
|
||||
IHttpContextAccessor contextAccessor = new HttpContextAccessor();
|
||||
services.AddSingleton<IHttpContextAccessor>(contextAccessor);
|
||||
services.AddSingleton<IHostingEnvironment>(new HostingEnvironment() { ContentRootPath = Directory.GetCurrentDirectory()});
|
||||
services.AddSingleton<DiagnosticListener>(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>(
|
||||
|
||||
// sanity check with a sample counter.
|
||||
var cpuCounterRequest = eventCounterModule.Counters.FirstOrDefault<EventCounterCollectionRequest>(
|
||||
eventCounterCollectionRequest => eventCounterCollectionRequest.EventSourceName == "System.Runtime"
|
||||
&& eventCounterCollectionRequest.EventCounterName == "cpu-usage");
|
||||
Assert.NotNull(cpuCounterRequest);
|
||||
|
||||
eventCounterModule.Counters.FirstOrDefault<EventCounterCollectionRequest>(
|
||||
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 => 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<T>(TelemetryConfiguration telemetryConfiguration)
|
||||
|
|
|
@ -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<ApplicationInsightsServiceOptions> 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<TelemetryConfiguration>();
|
||||
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<IConfiguration>(config);
|
||||
|
||||
// ACT
|
||||
services.AddApplicationInsightsTelemetryWorkerService();
|
||||
|
||||
// VALIDATE
|
||||
IServiceProvider serviceProvider = services.BuildServiceProvider();
|
||||
var telemetryConfiguration = serviceProvider.GetRequiredService<TelemetryConfiguration>();
|
||||
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<IConfiguration>(config);
|
||||
|
||||
// ACT
|
||||
services.AddApplicationInsightsTelemetryWorkerService();
|
||||
|
||||
// VALIDATE
|
||||
IServiceProvider serviceProvider = services.BuildServiceProvider();
|
||||
var telemetryConfiguration = serviceProvider.GetRequiredService<TelemetryConfiguration>();
|
||||
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<IConfiguration>(config);
|
||||
|
||||
// ACT
|
||||
services.AddApplicationInsightsTelemetryWorkerService("userkey");
|
||||
|
||||
// VALIDATE
|
||||
IServiceProvider serviceProvider = services.BuildServiceProvider();
|
||||
var telemetryConfiguration = serviceProvider.GetRequiredService<TelemetryConfiguration>();
|
||||
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<IConfiguration>(config);
|
||||
|
||||
// ACT
|
||||
services.AddApplicationInsightsTelemetryWorkerService();
|
||||
|
||||
// VALIDATE
|
||||
IServiceProvider serviceProvider = services.BuildServiceProvider();
|
||||
var telemetryConfiguration = serviceProvider.GetRequiredService<TelemetryConfiguration>();
|
||||
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<TelemetryConfiguration>();
|
||||
Assert.Equal("ikey", telemetryConfiguration.InstrumentationKey);
|
||||
|
||||
// AppID
|
||||
var appIdProvider = serviceProvider.GetRequiredService<IApplicationIdProvider>();
|
||||
Assert.NotNull(appIdProvider);
|
||||
Assert.True(appIdProvider is ApplicationInsightsApplicationIdProvider);
|
||||
|
||||
// AppID
|
||||
var channel = serviceProvider.GetRequiredService<ITelemetryChannel>();
|
||||
Assert.NotNull(channel);
|
||||
Assert.True(channel is ServerTelemetryChannel);
|
||||
|
||||
// TelemetryModules
|
||||
var modules = serviceProvider.GetServices<ITelemetryModule>();
|
||||
Assert.NotNull(modules);
|
||||
Assert.Equal(6, modules.Count());
|
||||
|
||||
var perfCounterModule = modules.FirstOrDefault<ITelemetryModule>(t => t.GetType() == typeof(PerformanceCollectorModule));
|
||||
Assert.NotNull(perfCounterModule);
|
||||
|
||||
var qpModule = modules.FirstOrDefault<ITelemetryModule>(t => t.GetType() == typeof(QuickPulseTelemetryModule));
|
||||
Assert.NotNull(qpModule);
|
||||
|
||||
var evtCounterModule = modules.FirstOrDefault<ITelemetryModule>(t => t.GetType() == typeof(EventCounterCollectionModule));
|
||||
Assert.NotNull(evtCounterModule);
|
||||
|
||||
var depModule = modules.FirstOrDefault<ITelemetryModule>(t => t.GetType() == typeof(DependencyTrackingTelemetryModule));
|
||||
Assert.NotNull(depModule);
|
||||
|
||||
var hbModule = modules.FirstOrDefault<ITelemetryModule>(t => t.GetType() == typeof(AppServicesHeartbeatTelemetryModule));
|
||||
Assert.NotNull(hbModule);
|
||||
|
||||
var azMetadataModule = modules.FirstOrDefault<ITelemetryModule>(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<TelemetryClient>();
|
||||
Assert.NotNull(tc);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public static void RegistersTelemetryConfigurationFactoryMethodThatPopulatesEventCounterCollectorWithDefaultListOfCounters()
|
||||
{
|
||||
//ARRANGE
|
||||
var services = new ServiceCollection();
|
||||
services.AddApplicationInsightsTelemetryWorkerService();
|
||||
|
||||
//ACT
|
||||
IServiceProvider serviceProvider = services.BuildServiceProvider();
|
||||
var modules = serviceProvider.GetServices<ITelemetryModule>();
|
||||
var telemetryConfiguration = serviceProvider.GetRequiredService<TelemetryConfiguration>();
|
||||
var eventCounterModule = modules.OfType<EventCounterCollectionModule>().Single();
|
||||
|
||||
//VALIDATE
|
||||
Assert.Equal(19, eventCounterModule.Counters.Count);
|
||||
|
||||
// sanity check with a sample counter.
|
||||
var cpuCounterRequest = eventCounterModule.Counters.FirstOrDefault<EventCounterCollectionRequest>(
|
||||
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 => 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<ITelemetryInitializer>(telemetryInitializer);
|
||||
|
||||
|
||||
// VALIDATE
|
||||
IServiceProvider serviceProvider = services.BuildServiceProvider();
|
||||
var telemetryConfiguration = serviceProvider.GetRequiredService<TelemetryConfiguration>();
|
||||
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<ITelemetryChannel>(telChannel);
|
||||
|
||||
// VALIDATE
|
||||
IServiceProvider serviceProvider = services.BuildServiceProvider();
|
||||
var telemetryConfiguration = serviceProvider.GetRequiredService<TelemetryConfiguration>();
|
||||
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<TelemetryConfiguration>();
|
||||
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"));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sanity check to validate that node name and roleinstance are populated
|
||||
/// </summary>
|
||||
[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<TelemetryClient>();
|
||||
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)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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<ITelemetry> sentItems = new ConcurrentBag<ITelemetry>();
|
||||
|
||||
var host = new HostBuilder()
|
||||
.ConfigureServices((hostContext, services) =>
|
||||
{
|
||||
services.AddSingleton<ITelemetryChannel>(new StubChannel()
|
||||
{
|
||||
OnSend = (item) => sentItems.Add(item)
|
||||
}); ;
|
||||
services.AddApplicationInsightsTelemetryWorkerService("ikey");
|
||||
services.AddHostedService<Worker>();
|
||||
}).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<RequestTelemetry>(sentItems);
|
||||
Assert.True(reqs.Count >= 1);
|
||||
var traces = GetTelemetryOfType<TraceTelemetry>(sentItems);
|
||||
Assert.True(traces.Count >= 1);
|
||||
var deps = GetTelemetryOfType<DependencyTelemetry>(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<T> GetTelemetryOfType<T>(ConcurrentBag<ITelemetry> items)
|
||||
{
|
||||
List<T> foundItems = new List<T>();
|
||||
foreach (var item in items)
|
||||
{
|
||||
if (item is T)
|
||||
{
|
||||
foundItems.Add((T)item);
|
||||
}
|
||||
}
|
||||
|
||||
return foundItems;
|
||||
}
|
||||
|
||||
private void PrintItems(ConcurrentBag<ITelemetry> 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<ITelemetry> 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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netcoreapp2.1</TargetFramework>
|
||||
<OutputPath Condition="'$(OutputPath)'=='' ">..\..\artifacts\test\$(MSBuildProjectName)</OutputPath>
|
||||
<IntermediateOutputPath Condition="'$(IntermediateOutputPath)'=='' ">..\..\artifacts\obj\test\$(MSBuildProjectName)</IntermediateOutputPath>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\src\Microsoft.ApplicationInsights.WorkerService\Microsoft.ApplicationInsights.WorkerService.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.2.0" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.1">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="xunit" Version="2.4.1" />
|
||||
<DotNetCliToolReference Include="dotnet-xunit" Version="2.3.1" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="2.1.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="2.1.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="2.1.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Update="content\config-instrumentation-key-new.json">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="content\sample-appsettings.json">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
|
@ -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<Worker> 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<RequestTelemetry>("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();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"ApplicationInsights": {
|
||||
"InstrumentationKey": "33333333-4444-5555-6666-777777777777"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"ApplicationInsights": {
|
||||
"InstrumentationKey": "11111111-2222-3333-4444-555555555555",
|
||||
"TelemetryChannel": {
|
||||
"EndpointAddress": "http://testendpoint/v2/track",
|
||||
"DeveloperMode": true
|
||||
}
|
||||
}
|
||||
}
|
Загрузка…
Ссылка в новой задаче