1
0
Форкнуть 0

Add new package for .NET Core WorkerServices (Adds GenericHost support) (#975)

This commit is contained in:
Cijo Thomas 2019-09-12 12:53:39 -07:00 коммит произвёл GitHub
Родитель 1672611a16
Коммит 49fd6dddab
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
30 изменённых файлов: 1759 добавлений и 366 удалений

Просмотреть файл

@ -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&lt;ApplicationInsightsServiceOptions&gt;"/> 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>

13
src/Shared/Shared.shproj Normal file
Просмотреть файл

@ -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
}
}
}