Skip to content
This repository was archived by the owner on Jun 10, 2020. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
namespace Microsoft.Extensions.DependencyInjection
using System.Linq;

namespace Microsoft.Extensions.DependencyInjection
{
using System;
using System.Collections.Generic;
Expand Down Expand Up @@ -122,54 +124,57 @@ public static IServiceCollection AddApplicationInsightsTelemetry(this IServiceCo
/// </returns>
public static IServiceCollection AddApplicationInsightsTelemetry(this IServiceCollection services)
{
if (!IsApplicationInsightsAdded(services))
{
services.TryAddSingleton<IHttpContextAccessor, HttpContextAccessor>();

services.AddSingleton<ITelemetryInitializer, AzureWebAppRoleEnvironmentTelemetryInitializer>();
services.AddSingleton<ITelemetryInitializer, DomainNameRoleInstanceTelemetryInitializer>();
services.AddSingleton<ITelemetryInitializer, ComponentVersionTelemetryInitializer>();
services.AddSingleton<ITelemetryInitializer, ClientIpHeaderTelemetryInitializer>();
services.AddSingleton<ITelemetryInitializer, OperationNameTelemetryInitializer>();
services.AddSingleton<ITelemetryInitializer, ApplicationInsights.AspNetCore.TelemetryInitializers.OperationCorrelationTelemetryInitializer>();
services.AddSingleton<ITelemetryInitializer, SyntheticTelemetryInitializer>();
services.AddSingleton<ITelemetryInitializer, WebSessionTelemetryInitializer>();
services.AddSingleton<ITelemetryInitializer, WebUserTelemetryInitializer>();
services.AddSingleton<ITelemetryInitializer, AspNetCoreEnvironmentTelemetryInitializer>();
services.AddSingleton<ITelemetryInitializer, HttpDependenciesParsingTelemetryInitializer>();
services.AddSingleton<ITelemetryModule, DependencyTrackingTelemetryModule>(provider => {
var module = new DependencyTrackingTelemetryModule();
var excludedDomains = module.ExcludeComponentCorrelationHttpHeadersOnDomains;
excludedDomains.Add("core.windows.net");
excludedDomains.Add("core.chinacloudapi.cn");
excludedDomains.Add("core.cloudapi.de");
excludedDomains.Add("core.usgovcloudapi.net");

return module;
});
services.AddSingleton<ITelemetryInitializer, AzureWebAppRoleEnvironmentTelemetryInitializer>();
services.AddSingleton<ITelemetryInitializer, DomainNameRoleInstanceTelemetryInitializer>();
services.AddSingleton<ITelemetryInitializer, ComponentVersionTelemetryInitializer>();
services.AddSingleton<ITelemetryInitializer, ClientIpHeaderTelemetryInitializer>();
services.AddSingleton<ITelemetryInitializer, OperationNameTelemetryInitializer>();
services.AddSingleton<ITelemetryInitializer, ApplicationInsights.AspNetCore.TelemetryInitializers.OperationCorrelationTelemetryInitializer>();
services.AddSingleton<ITelemetryInitializer, SyntheticTelemetryInitializer>();
services.AddSingleton<ITelemetryInitializer, WebSessionTelemetryInitializer>();
services.AddSingleton<ITelemetryInitializer, WebUserTelemetryInitializer>();
services.AddSingleton<ITelemetryInitializer, AspNetCoreEnvironmentTelemetryInitializer>();
services.AddSingleton<ITelemetryInitializer, HttpDependenciesParsingTelemetryInitializer>();
services.AddSingleton<ITelemetryModule, DependencyTrackingTelemetryModule>(provider => {
var module = new DependencyTrackingTelemetryModule();
var excludedDomains = module.ExcludeComponentCorrelationHttpHeadersOnDomains;
excludedDomains.Add("core.windows.net");
excludedDomains.Add("core.chinacloudapi.cn");
excludedDomains.Add("core.cloudapi.de");
excludedDomains.Add("core.usgovcloudapi.net");

return module;
});

#if NET451
services.AddSingleton<ITelemetryModule, PerformanceCollectorModule>();
services.AddSingleton<ITelemetryModule, PerformanceCollectorModule>();
#endif
services.AddSingleton<TelemetryConfiguration>(provider => provider.GetService<IOptions<TelemetryConfiguration>>().Value);
services.AddSingleton<TelemetryConfiguration>(provider => provider.GetService<IOptions<TelemetryConfiguration>>().Value);

services.AddSingleton<ICorrelationIdLookupHelper>(provider => new CorrelationIdLookupHelper(() => provider.GetService<IOptions<TelemetryConfiguration>>().Value));
services.AddSingleton<ICorrelationIdLookupHelper>(provider => new CorrelationIdLookupHelper(() => provider.GetService<IOptions<TelemetryConfiguration>>().Value));

services.AddSingleton<TelemetryClient>();
services.AddSingleton<TelemetryClient>();

services.AddSingleton<ApplicationInsightsInitializer, ApplicationInsightsInitializer>();
services.AddSingleton<IApplicationInsightDiagnosticListener, HostingDiagnosticListener>();
services.AddSingleton<IApplicationInsightDiagnosticListener, MvcDiagnosticsListener>();
services.AddSingleton<ApplicationInsightsInitializer, ApplicationInsightsInitializer>();
services.AddSingleton<IApplicationInsightDiagnosticListener, HostingDiagnosticListener>();
services.AddSingleton<IApplicationInsightDiagnosticListener, MvcDiagnosticsListener>();

// 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>();
// 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<JavaScriptSnippet>();
services.AddSingleton<DebugLoggerControl>();
services.AddSingleton<JavaScriptSnippet>();
services.AddSingleton<ApplicationInsightsLoggerEvents>();

services.AddOptions();
services.AddSingleton<IOptions<TelemetryConfiguration>, TelemetryConfigurationOptions>();
services.AddSingleton<IConfigureOptions<TelemetryConfiguration>, TelemetryConfigurationOptionsSetup>();
services.AddOptions();
services.AddSingleton<IOptions<TelemetryConfiguration>, TelemetryConfigurationOptions>();
services.AddSingleton<IConfigureOptions<TelemetryConfiguration>, TelemetryConfigurationOptionsSetup>();
}
return services;
}

Expand Down Expand Up @@ -278,5 +283,11 @@ internal static void AddTelemetryConfiguration(IConfiguration config, Applicatio
serviceOptions.ApplicationVersion = version;
}
}

private static bool IsApplicationInsightsAdded(IServiceCollection services)
{
// We treat ApplicationInsightsInitializer as a marker that AI services were added to service collection
return services.Any(service => service.ServiceType == typeof(ApplicationInsightsInitializer));
}
}
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
namespace Microsoft.AspNetCore.Hosting
{
using System;
using Microsoft.ApplicationInsights.AspNetCore.Extensions;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Options;

/// <summary>
Expand All @@ -20,7 +20,7 @@ public static IWebHostBuilder UseApplicationInsights(this IWebHostBuilder webHos
webHostBuilder.ConfigureServices(collection =>
{
collection.AddApplicationInsightsTelemetry();
collection.AddSingleton<IConfigureOptions<ApplicationInsightsServiceOptions>, DefaultApplicationInsightsServiceConfigureOptions>();
collection.TryAddSingleton<IConfigureOptions<ApplicationInsightsServiceOptions>, DefaultApplicationInsightsServiceConfigureOptions>();
});

return webHostBuilder;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ namespace Microsoft.ApplicationInsights.AspNetCore
using System.Diagnostics;
using Extensions;
using Microsoft.ApplicationInsights.AspNetCore.DiagnosticListeners;
using Microsoft.ApplicationInsights.AspNetCore.Logging;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;

Expand All @@ -24,8 +23,7 @@ public ApplicationInsightsInitializer(
IOptions<ApplicationInsightsServiceOptions> options,
IEnumerable<IApplicationInsightDiagnosticListener> diagnosticListeners,
ILoggerFactory loggerFactory,
DebugLoggerControl debugLoggerControl,
TelemetryClient client)
IServiceProvider serviceProvider)
{
this.diagnosticListeners = diagnosticListeners;
this.subscriptions = new List<IDisposable>();
Expand All @@ -34,7 +32,8 @@ public ApplicationInsightsInitializer(
if (options.Value.EnableDebugLogger && string.IsNullOrEmpty(options.Value.InstrumentationKey))
{
// Do not use extension method here or it will disable debug logger we currently adding
loggerFactory.AddProvider(new ApplicationInsightsLoggerProvider(client, (s, level) => debugLoggerControl.EnableDebugLogger && Debugger.IsAttached));
var enableDebugLogger = true;
loggerFactory.AddApplicationInsights(serviceProvider, (s, level) => enableDebugLogger && Debugger.IsAttached, () => enableDebugLogger = false);
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
namespace Microsoft.ApplicationInsights.AspNetCore.Logging
{
using System;

/// <summary>
/// Class to provide ApplicationInsights logger events
/// </summary>
internal class ApplicationInsightsLoggerEvents
{
/// <summary>
/// Event that is fired when new ApplicationInsights logger is added.
/// </summary>
public event Action LoggerAdded;

/// <summary>
/// Invokes LoggerAdded event.
/// </summary>
public void OnLoggerAdded()
{
LoggerAdded?.Invoke();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -49,12 +49,34 @@ public static ILoggerFactory AddApplicationInsights(
this ILoggerFactory factory,
IServiceProvider serviceProvider,
Func<string, LogLevel, bool> filter)
{
return factory.AddApplicationInsights(serviceProvider, filter, null);
}

/// <summary>
/// Adds an ApplicationInsights logger that is enabled as defined by the filter function.
/// </summary>
/// <param name="factory"></param>
/// <param name="filter"></param>
/// <param name="serviceProvider">The instance of <see cref="IServiceProvider"/> to use for service resolution.</param>
/// <param name="loggerAddedCallback">The callback that gets executed when another ApplicationInsights logger is added.</param>
public static ILoggerFactory AddApplicationInsights(
this ILoggerFactory factory,
IServiceProvider serviceProvider,
Func<string, LogLevel, bool> filter,
Action loggerAddedCallback)
{
var client = serviceProvider.GetService<TelemetryClient>();
var debugLoggerControl = serviceProvider.GetService<DebugLoggerControl>();
var debugLoggerControl = serviceProvider.GetService<ApplicationInsightsLoggerEvents>();

if (debugLoggerControl != null)
{
debugLoggerControl.EnableDebugLogger = false;
debugLoggerControl.OnLoggerAdded();

if (loggerAddedCallback != null)
{
debugLoggerControl.LoggerAdded += loggerAddedCallback;
}
}

factory.AddProvider(new ApplicationInsightsLoggerProvider(client, filter));
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@ namespace Microsoft.Extensions.DependencyInjection.Test
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using Logging;
using Microsoft.ApplicationInsights;
using Microsoft.ApplicationInsights.AspNetCore.Logging;
using Microsoft.ApplicationInsights.AspNetCore.TelemetryInitializers;
using Microsoft.ApplicationInsights.AspNetCore.Tests;
using Microsoft.ApplicationInsights.Channel;
Expand Down Expand Up @@ -64,6 +66,26 @@ public static void RegistersExpectedServices(Type serviceType, Type implementati
Assert.Equal(lifecycle, service.Lifetime);
}

[Theory]
[InlineData(typeof(ITelemetryInitializer), typeof(AzureWebAppRoleEnvironmentTelemetryInitializer), ServiceLifetime.Singleton)]
[InlineData(typeof(ITelemetryInitializer), typeof(DomainNameRoleInstanceTelemetryInitializer), ServiceLifetime.Singleton)]
[InlineData(typeof(ITelemetryInitializer), typeof(ComponentVersionTelemetryInitializer), ServiceLifetime.Singleton)]
[InlineData(typeof(ITelemetryInitializer), typeof(ClientIpHeaderTelemetryInitializer), ServiceLifetime.Singleton)]
[InlineData(typeof(ITelemetryInitializer), typeof(OperationNameTelemetryInitializer), ServiceLifetime.Singleton)]
[InlineData(typeof(ITelemetryInitializer), typeof(SyntheticTelemetryInitializer), ServiceLifetime.Singleton)]
[InlineData(typeof(ITelemetryInitializer), typeof(WebSessionTelemetryInitializer), ServiceLifetime.Singleton)]
[InlineData(typeof(ITelemetryInitializer), typeof(WebUserTelemetryInitializer), 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)
{
var services = GetServiceCollectionWithContextAccessor();
services.AddApplicationInsightsTelemetry();
services.AddApplicationInsightsTelemetry();
ServiceDescriptor service = services.Single(s => s.ServiceType == serviceType && s.ImplementationType == implementationType);
Assert.Equal(lifecycle, service.Lifetime);
}

[Fact]
public static void DoesNotThrowWithoutInstrumentationKey()
{
Expand Down Expand Up @@ -429,6 +451,38 @@ private static int GetTelemetryProcessorsCountInConfiguration<T>(TelemetryConfig
{
return telemetryConfiguration.TelemetryProcessors.Where(processor => processor.GetType() == typeof(T)).Count();
}

[Fact]
public static void LoggerCallbackIsInvoked()
{
var services = new ServiceCollection();
services.AddSingleton<ApplicationInsightsLoggerEvents>();
var serviceProvider = services.BuildServiceProvider();

var loggerProvider = new MockLoggingFactory();

bool firstLoggerCallback = false;
bool secondLoggerCallback = false;

loggerProvider.AddApplicationInsights(serviceProvider, (s, level) => true, () => firstLoggerCallback = true);
loggerProvider.AddApplicationInsights(serviceProvider, (s, level) => true, () => secondLoggerCallback = true);

Assert.True(firstLoggerCallback);
Assert.False(secondLoggerCallback);
}

[Fact]
public static void NullLoggerCallbackAlowed()
{
var services = new ServiceCollection();
services.AddSingleton<ApplicationInsightsLoggerEvents>();
var serviceProvider = services.BuildServiceProvider();

var loggerProvider = new MockLoggingFactory();

loggerProvider.AddApplicationInsights(serviceProvider, (s, level) => true, null);
loggerProvider.AddApplicationInsights(serviceProvider, (s, level) => true, null);
}
}

public static class AddApplicationInsightsSettings
Expand Down Expand Up @@ -504,5 +558,21 @@ public static ServiceCollection CreateServicesAndAddApplicationinsightsTelemetry
}
return services;
}

private class MockLoggingFactory : ILoggerFactory
{
public void Dispose()
{
}

public ILogger CreateLogger(string categoryName)
{
return null;
}

public void AddProvider(ILoggerProvider provider)
{
}
}
}
}