1
0
Форкнуть 0

Merge pull request #858 from Microsoft/develop

merge DEVELOP to MASTER (prep 2.7.0-beta3)
This commit is contained in:
Timothy Mothra 2019-04-01 13:32:42 -07:00 коммит произвёл GitHub
Родитель 1d90711294 cbbf53dd20
Коммит c9b04f5d2f
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
23 изменённых файлов: 484 добавлений и 95 удалений

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

@ -1,5 +1,10 @@
# Changelog
## Version 2.7.0-beta3
- [Enables Microsoft.Extensions.Logging.ApplicationInsights.ApplicationInsightsLoggerProvider by default. If ApplicationInsightsLoggerProvider was enabled previously using ILoggerFactory extension method, please remove it to prevent duplicate logs.](https://github.com/Microsoft/ApplicationInsights-aspnetcore/issues/854)
- [Remove reference to Microsoft.Extensions.DiagnosticAdapter and use DiagnosticSource subscription APIs directly](https://github.com/Microsoft/ApplicationInsights-aspnetcore/pull/852)
- [Fix: NullReferenceException in ApplicationInsightsLogger.Log when exception contains a Data entry with a null value](https://github.com/Microsoft/ApplicationInsights-aspnetcore/issues/848)
## Version 2.7.0-beta2
- Added NetStandard2.0 target.
- Updated Web/Base SDK version dependency to 2.10.0-beta2

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

@ -3,6 +3,10 @@
- [Microsoft.ApplicationInsights.AspNetCore](https://www.nuget.org/packages/Microsoft.ApplicationInsights.AspNetCore/)
[![Nuget](https://img.shields.io/nuget/vpre/Microsoft.ApplicationInsights.AspNetCore.svg)](https://nuget.org/packages/Microsoft.ApplicationInsights.AspNetCore)
Windows: [![Build Status](https://mseng.visualstudio.com/AppInsights/_apis/build/status/ChuckNorris/AI_ASPNETCore_Develop?branchName=develop)](https://mseng.visualstudio.com/AppInsights/_build/latest?definitionId=3717&branchName=develop)
Linux :[![Build Status](https://mseng.visualstudio.com/AppInsights/_apis/build/status/ChuckNorris/AI-AspNetCoreSDK-develop-linux?branchName=develop)](https://mseng.visualstudio.com/AppInsights/_build/latest?definitionId=6273&branchName=develop)
Microsoft Application Insights for ASP.NET Core applications
=============================================================

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

@ -1,12 +1,14 @@
namespace Microsoft.ApplicationInsights.AspNetCore.DiagnosticListeners
{
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using System.Net.Http.Headers;
using System.Text;
using Extensibility.Implementation.Tracing;
using Microsoft.ApplicationInsights.AspNetCore.DiagnosticListeners.Implementation;
using Microsoft.ApplicationInsights.AspNetCore.Extensions;
using Microsoft.ApplicationInsights.Common;
using Microsoft.ApplicationInsights.DataContracts;
@ -14,7 +16,6 @@
using Microsoft.ApplicationInsights.Extensibility.Implementation;
using Microsoft.ApplicationInsights.Extensibility.W3C;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DiagnosticAdapter;
using Microsoft.Extensions.Primitives;
/// <summary>
@ -38,6 +39,24 @@
private static readonly ActiveSubsciptionManager SubscriptionManager = new ActiveSubsciptionManager();
private const string ActivityCreatedByHostingDiagnosticListener = "ActivityCreatedByHostingDiagnosticListener";
#region fetchers
// fetch is unique per event and per property
private readonly PropertyFetcher httpContextFetcherStart = new PropertyFetcher("HttpContext");
private readonly PropertyFetcher httpContextFetcherStop = new PropertyFetcher("HttpContext");
private readonly PropertyFetcher httpContextFetcherBeginRequest = new PropertyFetcher("httpContext");
private readonly PropertyFetcher httpContextFetcherEndRequest = new PropertyFetcher("httpContext");
private readonly PropertyFetcher httpContextFetcherDiagExceptionUnhandled = new PropertyFetcher("httpContext");
private readonly PropertyFetcher httpContextFetcherDiagExceptionHandled = new PropertyFetcher("httpContext");
private readonly PropertyFetcher httpContextFetcherHostingExceptionUnhandled = new PropertyFetcher("httpContext");
private readonly PropertyFetcher exceptionFetcherDiagExceptionUnhandled = new PropertyFetcher("exception");
private readonly PropertyFetcher exceptionFetcherDiagExceptionHandled = new PropertyFetcher("exception");
private readonly PropertyFetcher exceptionFetcherHostingExceptionUnhandled = new PropertyFetcher("exception");
private readonly PropertyFetcher timestampFetcherBeginRequest = new PropertyFetcher("timestamp");
private readonly PropertyFetcher timestampFetcherEndRequest = new PropertyFetcher("timestamp");
#endregion
/// <summary>
/// Initializes a new instance of the <see cref="T:HostingDiagnosticListener"/> class.
/// </summary>
@ -72,19 +91,9 @@
/// <inheritdoc/>
public string ListenerName { get; } = "Microsoft.AspNetCore";
/// <summary>
/// Diagnostic event handler method for 'Microsoft.AspNetCore.Hosting.HttpRequestIn' event.
/// </summary>
[DiagnosticName("Microsoft.AspNetCore.Hosting.HttpRequestIn")]
public void OnHttpRequestIn()
{
// do nothing, just enable the diagnostic source
}
/// <summary>
/// Diagnostic event handler method for 'Microsoft.AspNetCore.Hosting.HttpRequestIn.Start' event.
/// </summary>
[DiagnosticName("Microsoft.AspNetCore.Hosting.HttpRequestIn.Start")]
public void OnHttpRequestInStart(HttpContext httpContext)
{
if (this.client.IsEnabled())
@ -176,7 +185,6 @@
/// <summary>
/// Diagnostic event handler method for 'Microsoft.AspNetCore.Hosting.HttpRequestIn.Stop' event.
/// </summary>
[DiagnosticName("Microsoft.AspNetCore.Hosting.HttpRequestIn.Stop")]
public void OnHttpRequestInStop(HttpContext httpContext)
{
EndRequest(httpContext, Stopwatch.GetTimestamp());
@ -185,7 +193,6 @@
/// <summary>
/// Diagnostic event handler method for 'Microsoft.AspNetCore.Hosting.BeginRequest' event.
/// </summary>
[DiagnosticName("Microsoft.AspNetCore.Hosting.BeginRequest")]
public void OnBeginRequest(HttpContext httpContext, long timestamp)
{
if (this.client.IsEnabled() && !this.enableNewDiagnosticEvents)
@ -282,7 +289,6 @@
/// <summary>
/// Diagnostic event handler method for 'Microsoft.AspNetCore.Hosting.EndRequest' event.
/// </summary>
[DiagnosticName("Microsoft.AspNetCore.Hosting.EndRequest")]
public void OnEndRequest(HttpContext httpContext, long timestamp)
{
if (!this.enableNewDiagnosticEvents)
@ -294,7 +300,6 @@
/// <summary>
/// Diagnostic event handler method for 'Microsoft.AspNetCore.Hosting.UnhandledException' event.
/// </summary>
[DiagnosticName("Microsoft.AspNetCore.Hosting.UnhandledException")]
public void OnHostingException(HttpContext httpContext, Exception exception)
{
this.OnException(httpContext, exception);
@ -310,7 +315,6 @@
/// <summary>
/// Diagnostic event handler method for 'Microsoft.AspNetCore.Hosting.HandledException' event.
/// </summary>
[DiagnosticName("Microsoft.AspNetCore.Diagnostics.HandledException")]
public void OnDiagnosticsHandledException(HttpContext httpContext, Exception exception)
{
this.OnException(httpContext, exception);
@ -319,7 +323,6 @@
/// <summary>
/// Diagnostic event handler method for 'Microsoft.AspNetCore.Diagnostics.UnhandledException' event.
/// </summary>
[DiagnosticName("Microsoft.AspNetCore.Diagnostics.UnhandledException")]
public void OnDiagnosticsUnhandledException(HttpContext httpContext, Exception exception)
{
this.OnException(httpContext, exception);
@ -559,5 +562,81 @@
{
SubscriptionManager.Detach(this);
}
public void OnNext(KeyValuePair<string, object> value)
{
HttpContext httpContext = null;
Exception exception = null;
long? timestamp = null;
switch (value.Key)
{
case "Microsoft.AspNetCore.Hosting.HttpRequestIn.Start":
httpContext = this.httpContextFetcherStart.Fetch(value.Value) as HttpContext;
if (httpContext != null)
{
this.OnHttpRequestInStart(httpContext);
}
break;
case "Microsoft.AspNetCore.Hosting.HttpRequestIn.Stop":
httpContext = this.httpContextFetcherStop.Fetch(value.Value) as HttpContext;
if (httpContext != null)
{
this.OnHttpRequestInStop(httpContext);
}
break;
case "Microsoft.AspNetCore.Hosting.BeginRequest":
httpContext = this.httpContextFetcherBeginRequest.Fetch(value.Value) as HttpContext;
timestamp = this.timestampFetcherBeginRequest.Fetch(value.Value) as long?;
if (httpContext != null && timestamp.HasValue)
{
this.OnBeginRequest(httpContext, timestamp.Value);
}
break;
case "Microsoft.AspNetCore.Hosting.EndRequest":
httpContext = this.httpContextFetcherEndRequest.Fetch(value.Value) as HttpContext;
timestamp = this.timestampFetcherEndRequest.Fetch(value.Value) as long?;
if (httpContext != null && timestamp.HasValue)
{
this.OnEndRequest(httpContext, timestamp.Value);
}
break;
case "Microsoft.AspNetCore.Diagnostics.UnhandledException":
httpContext = this.httpContextFetcherDiagExceptionUnhandled.Fetch(value.Value) as HttpContext;
exception = this.exceptionFetcherDiagExceptionUnhandled.Fetch(value.Value) as Exception;
if (httpContext != null && exception != null)
{
this.OnDiagnosticsUnhandledException(httpContext, exception);
}
break;
case "Microsoft.AspNetCore.Diagnostics.HandledException":
httpContext = this.httpContextFetcherDiagExceptionHandled.Fetch(value.Value) as HttpContext;
exception = this.exceptionFetcherDiagExceptionHandled.Fetch(value.Value) as Exception;
if (httpContext != null && exception != null)
{
this.OnDiagnosticsHandledException(httpContext, exception);
}
break;
case "Microsoft.AspNetCore.Hosting.UnhandledException":
httpContext = this.httpContextFetcherHostingExceptionUnhandled.Fetch(value.Value) as HttpContext;
exception = this.exceptionFetcherHostingExceptionUnhandled.Fetch(value.Value) as Exception;
if (httpContext != null && exception != null)
{
this.OnHostingException(httpContext, exception);
}
break;
}
}
/// <inheritdoc />
public void OnError(Exception error)
{
}
/// <inheritdoc />
public void OnCompleted()
{
}
}
}

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

@ -1,11 +1,12 @@
namespace Microsoft.ApplicationInsights.AspNetCore.DiagnosticListeners
{
using System;
using System.Collections.Generic;
/// <summary>
/// Base diagnostic listener type for Application Insight
/// </summary>
internal interface IApplicationInsightDiagnosticListener : IDisposable
internal interface IApplicationInsightDiagnosticListener : IDisposable, IObserver<KeyValuePair<string, object>>
{
/// <summary>
/// Gets a value indicating which listener this instance should be subscribed to

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

@ -3,9 +3,9 @@ namespace Microsoft.ApplicationInsights.AspNetCore.DiagnosticListeners
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.ApplicationInsights.AspNetCore.DiagnosticListeners.Implementation;
using Microsoft.ApplicationInsights.DataContracts;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DiagnosticAdapter;
/// <summary>
/// <see cref="IApplicationInsightDiagnosticListener"/> implementation that listens for evens specific to AspNetCore Mvc layer
@ -15,17 +15,20 @@ namespace Microsoft.ApplicationInsights.AspNetCore.DiagnosticListeners
/// <inheritdoc />
public string ListenerName { get; } = "Microsoft.AspNetCore";
private readonly PropertyFetcher httpContextFetcher = new PropertyFetcher("httpContext");
private readonly PropertyFetcher routeDataFetcher = new PropertyFetcher("routeData");
private readonly PropertyFetcher routeValuesFetcher = new PropertyFetcher("Values");
/// <summary>
/// Diagnostic event handler method for 'Microsoft.AspNetCore.Mvc.BeforeAction' event
/// </summary>
[DiagnosticName("Microsoft.AspNetCore.Mvc.BeforeAction")]
public void OnBeforeAction(HttpContext httpContext, IRouteData routeData)
public void OnBeforeAction(HttpContext httpContext, IDictionary<string, object> routeValues)
{
var telemetry = httpContext.Features.Get<RequestTelemetry>();
if (telemetry != null && string.IsNullOrEmpty(telemetry.Name))
{
string name = this.GetNameFromRouteContext(routeData);
string name = this.GetNameFromRouteContext(routeValues);
if (!string.IsNullOrEmpty(name))
{
@ -35,19 +38,12 @@ namespace Microsoft.ApplicationInsights.AspNetCore.DiagnosticListeners
}
}
/// <inheritdoc />
public void OnSubscribe()
{
}
private string GetNameFromRouteContext(IRouteData routeData)
private string GetNameFromRouteContext(IDictionary<string, object> routeValues)
{
string name = null;
if (routeData.Values.Count > 0)
if (routeValues.Count > 0)
{
var routeValues = routeData.Values;
object controller;
routeValues.TryGetValue("controller", out controller);
string controllerString = (controller == null) ? string.Empty : controller.ToString();
@ -98,19 +94,40 @@ namespace Microsoft.ApplicationInsights.AspNetCore.DiagnosticListeners
return name;
}
public void Dispose()
/// <inheritdoc />
public void OnSubscribe()
{
}
/// <summary>
/// Proxy interface for <c>RouteData</c> class from Microsoft.AspNetCore.Routing.Abstractions
/// </summary>
public interface IRouteData
/// <inheritdoc />
public void OnNext(KeyValuePair<string, object> value)
{
if (value.Key == "Microsoft.AspNetCore.Mvc.BeforeAction")
{
var context = httpContextFetcher.Fetch(value.Value) as HttpContext;
var routeData = routeDataFetcher.Fetch(value.Value);
var routeValues = routeValuesFetcher.Fetch(routeData) as IDictionary<string, object>;
if (context != null && routeValues != null)
{
this.OnBeforeAction(context, routeValues);
}
}
}
/// <inheritdoc />
public void OnError(Exception error)
{
}
/// <inheritdoc />
public void OnCompleted()
{
}
/// <inheritdoc />
public void Dispose()
{
/// <summary>
/// Gets the set of values produced by routes on the current routing path.
/// </summary>
IDictionary<string, object> Values { get; }
}
}
}

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

@ -0,0 +1,76 @@
namespace Microsoft.ApplicationInsights.AspNetCore.DiagnosticListeners.Implementation
{
using System;
using System.Reflection;
// see https://github.com/dotnet/corefx/blob/master/src/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/DiagnosticSourceEventSource.cs
/// <summary>
/// Efficient implementation of fetching properties of anonymous types with reflection.
/// </summary>
internal class PropertyFetcher
{
private readonly string propertyName;
private PropertyFetch innerFetcher;
public PropertyFetcher(string propertyName)
{
this.propertyName = propertyName;
}
public object Fetch(object obj)
{
if (this.innerFetcher == null)
{
this.innerFetcher = PropertyFetch.FetcherForProperty(obj.GetType().GetTypeInfo().GetDeclaredProperty(this.propertyName));
}
return this.innerFetcher?.Fetch(obj);
}
private class PropertyFetch
{
/// <summary>
/// Create a property fetcher from a .NET Reflection PropertyInfo class that
/// represents a property of a particular type.
/// </summary>
public static PropertyFetch FetcherForProperty(PropertyInfo propertyInfo)
{
if (propertyInfo == null)
{
// returns null on any fetch.
return new PropertyFetch();
}
var typedPropertyFetcher = typeof(TypedFetchProperty<,>);
var instantiatedTypedPropertyFetcher = typedPropertyFetcher.GetTypeInfo().MakeGenericType(
propertyInfo.DeclaringType, propertyInfo.PropertyType);
return (PropertyFetch)Activator.CreateInstance(instantiatedTypedPropertyFetcher, propertyInfo);
}
/// <summary>
/// Given an object, fetch the property that this propertyFetch represents.
/// </summary>
public virtual object Fetch(object obj)
{
return null;
}
private class TypedFetchProperty<TObject, TProperty> : PropertyFetch
{
private readonly Func<TObject, TProperty> propertyFetch;
public TypedFetchProperty(PropertyInfo property)
{
this.propertyFetch =
(Func<TObject, TProperty>)
property.GetMethod.CreateDelegate(typeof(Func<TObject, TProperty>));
}
public override object Fetch(object obj)
{
return this.propertyFetch((TObject)obj);
}
}
}
}
}

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

@ -22,8 +22,10 @@
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Configuration.Memory;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Options;
using Microsoft.Extensions.Logging;
/// <summary>
/// Extension methods for <see cref="IServiceCollection"/> that allow adding Application Insights services to application.
@ -190,8 +192,6 @@
services.AddSingleton<TelemetryClient>();
services.AddSingleton<ApplicationInsightsDebugLogger, ApplicationInsightsDebugLogger>();
services
.TryAddSingleton<IConfigureOptions<ApplicationInsightsServiceOptions>,
DefaultApplicationInsightsServiceConfigureOptions>();
@ -201,12 +201,38 @@
// that requires IOptions infrastructure to run and initialize
services.AddSingleton<IStartupFilter, ApplicationInsightsStartupFilter>();
services.AddSingleton<JavaScriptSnippet>();
services.AddSingleton<ApplicationInsightsLoggerEvents>();
services.AddSingleton<JavaScriptSnippet>();
services.AddOptions();
services.AddSingleton<IOptions<TelemetryConfiguration>, TelemetryConfigurationOptions>();
services.AddSingleton<IConfigureOptions<TelemetryConfiguration>, TelemetryConfigurationOptionsSetup>();
// 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:
//"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
}
return services;
@ -406,8 +432,8 @@
private static bool IsApplicationInsightsAdded(IServiceCollection services)
{
// We treat ApplicationInsightsDebugLogger as a marker that AI services were added to service collection
return services.Any(service => service.ServiceType == typeof(ApplicationInsightsDebugLogger));
// We treat TelemetryClient as a marker that AI services were added to service collection
return services.Any(service => service.ServiceType == typeof(TelemetryClient));
}
}
}

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

@ -69,7 +69,7 @@
exceptionTelemetry.Message = formatter(state, exception);
exceptionTelemetry.SeverityLevel = this.GetSeverityLevel(logLevel);
exceptionTelemetry.Properties["Exception"] = exception.ToString();
exception.Data.Cast<DictionaryEntry>().ToList().ForEach((item) => exceptionTelemetry.Properties[item.Key.ToString()] = item.Value.ToString());
exception.Data.Cast<DictionaryEntry>().ToList().ForEach((item) => exceptionTelemetry.Properties[item.Key.ToString()] = (item.Value ?? "null").ToString());
PopulateTelemetry(exceptionTelemetry, stateDictionary, eventId);
this.telemetryClient.TrackException(exceptionTelemetry);
}

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

@ -2,7 +2,7 @@
{
using System;
using ApplicationInsights;
using ApplicationInsights.AspNetCore.Logging;
using Microsoft.ApplicationInsights;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
@ -16,7 +16,7 @@
/// </summary>
/// <param name="factory"></param>
/// <param name="serviceProvider">The instance of <see cref="IServiceProvider"/> to use for service resolution.</param>
[Obsolete("Use Microsoft.Extensions.Logging.ApplicationInsightsLoggingBuilderExtensions.AddApplicationInsights from Microsoft.Extensions.Logging.ApplicationInsights package")]
[Obsolete("ApplicationInsightsLoggerProvider is now enabled by default when enabling ApplicationInsights monitoring using UseApplicationInsights extension method on IWebHostBuilder or AddApplicationInsightsTelemetry extension method on IServiceCollection. From 2.7.0-beta3 onwards, calling this method will result in double logging and filters applied will not get applied. If interested in using just logging provider, then please use Microsoft.Extensions.Logging.ApplicationInsightsLoggingBuilderExtensions.AddApplicationInsights from Microsoft.Extensions.Logging.ApplicationInsights package. Read more https://aka.ms/ApplicationInsightsILoggerFaq")]
public static ILoggerFactory AddApplicationInsights(this ILoggerFactory factory, IServiceProvider serviceProvider)
{
return factory.AddApplicationInsights(serviceProvider, LogLevel.Warning);
@ -28,7 +28,7 @@
/// <param name="factory"></param>
/// <param name="serviceProvider">The instance of <see cref="IServiceProvider"/> to use for service resolution.</param>
/// <param name="minLevel">The minimum <see cref="LogLevel"/> to be logged</param>
[Obsolete("Use Microsoft.Extensions.Logging.ApplicationInsightsLoggingBuilderExtensions.AddApplicationInsights from Microsoft.Extensions.Logging.ApplicationInsights package")]
[Obsolete("ApplicationInsightsLoggerProvider is now enabled by default when enabling ApplicationInsights monitoring using UseApplicationInsights extension method on IWebHostBuilder or AddApplicationInsightsTelemetry extension method on IServiceCollection. From 2.7.0-beta3 onwards, calling this method will result in double logging and filters applied will not get applied. If interested in using just logging provider, then please use Microsoft.Extensions.Logging.ApplicationInsightsLoggingBuilderExtensions.AddApplicationInsights from Microsoft.Extensions.Logging.ApplicationInsights package. Read more https://aka.ms/ApplicationInsightsILoggerFaq")]
public static ILoggerFactory AddApplicationInsights(
this ILoggerFactory factory,
IServiceProvider serviceProvider,
@ -44,7 +44,7 @@
/// <param name="factory"></param>
/// <param name="filter"></param>
/// <param name="serviceProvider">The instance of <see cref="IServiceProvider"/> to use for service resolution.</param>
[Obsolete("Use Microsoft.Extensions.Logging.ApplicationInsightsLoggingBuilderExtensions.AddApplicationInsights from Microsoft.Extensions.Logging.ApplicationInsights package")]
[Obsolete("ApplicationInsightsLoggerProvider is now enabled by default when enabling ApplicationInsights monitoring using UseApplicationInsights extension method on IWebHostBuilder or AddApplicationInsightsTelemetry extension method on IServiceCollection. From 2.7.0-beta3 onwards, calling this method will result in double logging and filters applied will not get applied. If interested in using just logging provider, then please use Microsoft.Extensions.Logging.ApplicationInsightsLoggingBuilderExtensions.AddApplicationInsights from Microsoft.Extensions.Logging.ApplicationInsights package. Read more https://aka.ms/ApplicationInsightsILoggerFaq")]
public static ILoggerFactory AddApplicationInsights(
this ILoggerFactory factory,
IServiceProvider serviceProvider,
@ -60,20 +60,21 @@
/// <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>
[Obsolete("Use Microsoft.Extensions.Logging.ApplicationInsightsLoggingBuilderExtensions.AddApplicationInsights from Microsoft.Extensions.Logging.ApplicationInsights package")]
[Obsolete("ApplicationInsightsLoggerProvider is now enabled by default when enabling ApplicationInsights monitoring using UseApplicationInsights extension method on IWebHostBuilder or AddApplicationInsightsTelemetry extension method on IServiceCollection. From 2.7.0-beta3 onwards, calling this method will result in double logging and filters applied will not get applied. If interested in using just logging provider, then please use Microsoft.Extensions.Logging.ApplicationInsightsLoggingBuilderExtensions.AddApplicationInsights from Microsoft.Extensions.Logging.ApplicationInsights package. Read more https://aka.ms/ApplicationInsightsILoggerFaq")]
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<ApplicationInsightsLoggerEvents>();
var options = serviceProvider.GetService<IOptions<ApplicationInsightsLoggerOptions>>();
var debugLoggerControl = serviceProvider.GetService<Microsoft.ApplicationInsights.AspNetCore.Logging.ApplicationInsightsLoggerEvents>();
var options = serviceProvider.GetService<IOptions<Microsoft.ApplicationInsights.AspNetCore.Logging.ApplicationInsightsLoggerOptions>>();
if (options == null)
{
options = Options.Create(new ApplicationInsightsLoggerOptions());
options = Options.Create(new Microsoft.ApplicationInsights.AspNetCore.Logging.ApplicationInsightsLoggerOptions());
}
if (debugLoggerControl != null)
@ -85,8 +86,8 @@
debugLoggerControl.LoggerAdded += loggerAddedCallback;
}
}
factory.AddProvider(new ApplicationInsightsLoggerProvider(client, filter, options));
factory.AddProvider(new Microsoft.ApplicationInsights.AspNetCore.Logging.ApplicationInsightsLoggerProvider(client, filter, options));
return factory;
}
}

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

@ -7,7 +7,10 @@
/// <summary>
/// <see cref="ILoggerProvider"/> implementation that creates returns instances of <see cref="ApplicationInsightsLogger"/>
/// </summary>
#if !NETSTANDARD2_0
// For NETSTANDARD2.0 We take dependency on Microsoft.Extensions.Logging.ApplicationInsights which has ApplicationInsightsProvider having the same ProviderAlias and don't want to clash with this ProviderAlias.
[ProviderAlias("ApplicationInsights")]
#endif
internal class ApplicationInsightsLoggerProvider : ILoggerProvider
{
private readonly TelemetryClient telemetryClient;

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

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<AssemblyName>Microsoft.ApplicationInsights.AspNetCore</AssemblyName>
<VersionPrefix>2.7.0-beta2</VersionPrefix>
<VersionPrefix>2.7.0-beta3</VersionPrefix>
<Authors>Microsoft</Authors>
<Copyright>© Microsoft Corporation. All rights reserved.</Copyright>
<AssemblyTitle>Application Insights for ASP.NET Core Web Applications</AssemblyTitle>
@ -81,24 +81,23 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.ApplicationInsights" Version="2.10.0-beta2" />
<PackageReference Include="Microsoft.ApplicationInsights.DependencyCollector" Version="2.10.0-beta2" />
<PackageReference Include="Microsoft.ApplicationInsights.PerfCounterCollector" Version="2.10.0-beta2" />
<PackageReference Include="Microsoft.ApplicationInsights.WindowsServer" Version="2.10.0-beta2" />
<PackageReference Include="Microsoft.ApplicationInsights.WindowsServer.TelemetryChannel" Version="2.10.0-beta2" />
<PackageReference Include="Microsoft.AspNetCore.Hosting" Version="1.0.2" />
<PackageReference Include="Microsoft.Extensions.Configuration" Version="1.0.2" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="1.0.2" />
<PackageReference Include="Microsoft.Extensions.DiagnosticAdapter" Version="1.1.0" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="1.0.2" />
<PackageReference Include="Microsoft.ApplicationInsights" Version="2.10.0-beta3" />
<PackageReference Include="Microsoft.ApplicationInsights.DependencyCollector" Version="2.10.0-beta3" />
<PackageReference Include="Microsoft.ApplicationInsights.PerfCounterCollector" Version="2.10.0-beta3" />
<PackageReference Include="Microsoft.ApplicationInsights.WindowsServer" Version="2.10.0-beta3" />
<PackageReference Include="Microsoft.ApplicationInsights.WindowsServer.TelemetryChannel" Version="2.10.0-beta3" />
<PackageReference Include="Microsoft.AspNetCore.Hosting" Version="1.0.2" />
<PackageReference Include="System.Text.Encodings.Web" Version="4.3.1" />
</ItemGroup>
<ItemGroup Condition=" '$(TargetFramework)' == 'netstandard2.0' ">
<PackageReference Include="Microsoft.Extensions.Configuration" Version="2.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="2.0.0" />
<PackageReference Include="Microsoft.Extensions.DiagnosticAdapter" Version="2.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="2.0.0" />
<ItemGroup Condition=" '$(TargetFramework)' != 'netstandard2.0' ">
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="1.0.2" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="1.0.2" />
</ItemGroup>
<ItemGroup Condition=" '$(TargetFramework)' == 'netstandard2.0' ">
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="2.1.0" />
<PackageReference Include="Microsoft.Extensions.Logging.ApplicationInsights" Version="2.9.1" />
<PackageReference Include="System.Text.Encodings.Web" Version="4.3.1" />
</ItemGroup>

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

@ -105,7 +105,7 @@ namespace Microsoft.ApplicationInsights.AspNetCore
{
if (applicationInsightDiagnosticListener.ListenerName == value.Name)
{
subs.Add(value.SubscribeWithAdapter(applicationInsightDiagnosticListener));
subs.Add(value.Subscribe(applicationInsightDiagnosticListener));
applicationInsightDiagnosticListener.OnSubscribe();
}
}

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

@ -13,11 +13,13 @@
{
private readonly IHttpContextAccessor httpContextAccessor;
/// <inheritdoc />
public TelemetryInitializerBase(IHttpContextAccessor httpContextAccessor)
{
this.httpContextAccessor = httpContextAccessor ?? throw new ArgumentNullException(nameof(httpContextAccessor));
}
/// <inheritdoc />
public void Initialize(ITelemetry telemetry)
{
var context = this.httpContextAccessor.HttpContext;

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

@ -9,6 +9,7 @@
{
private const string WebSessionCookieName = "ai_session";
/// <inheritdoc />
public WebSessionTelemetryInitializer(IHttpContextAccessor httpContextAccessor)
: base(httpContextAccessor)
{

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

@ -5,15 +5,18 @@
using Microsoft.ApplicationInsights.DataContracts;
using Microsoft.AspNetCore.Http;
/// <inheritdoc />
public class WebUserTelemetryInitializer : TelemetryInitializerBase
{
private const string WebUserCookieName = "ai_user";
/// <inheritdoc />
public WebUserTelemetryInitializer(IHttpContextAccessor httpContextAccessor)
: base(httpContextAccessor)
{
}
/// <inheritdoc />
protected override void OnInitializeTelemetry(HttpContext platformContext, RequestTelemetry requestTelemetry, ITelemetry telemetry)
{
if (!string.IsNullOrEmpty(telemetry.Context.User.Id))

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

@ -40,8 +40,9 @@ namespace FunctionalTestUtils
private TelemetryHttpListenerObservable listener;
private readonly Func<IWebHostBuilder, IWebHostBuilder> configureHost;
private readonly Action<IServiceCollection> configureServices;
public InProcessServer(string assemblyName, ITestOutputHelper output, Func<IWebHostBuilder, IWebHostBuilder> configureHost = null)
public InProcessServer(string assemblyName, ITestOutputHelper output, Func<IWebHostBuilder, IWebHostBuilder> configureHost = null, Action<IServiceCollection> configureServices = null)
{
this.output = output;
@ -49,6 +50,7 @@ namespace FunctionalTestUtils
var machineName = "localhost";
this.url = "http://" + machineName + ":" + random.Next(5000, 14000).ToString();
this.configureHost = configureHost;
this.configureServices = configureServices;
this.httpListenerConnectionString = LauchApplicationAndStartListener(assemblyName);
}
@ -155,7 +157,12 @@ namespace FunctionalTestUtils
{
builder = this.configureHost(builder);
}
if (this.configureServices != null)
{
builder.ConfigureServices(services => this.configureServices(services));
}
this.hostingEngine = builder.Build();
this.hostingEngine.Start();

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

@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<VersionPrefix>2.0.0</VersionPrefix>
@ -56,10 +56,10 @@
<PackageReference Include="Microsoft.AspNetCore.Server.Kestrel" Version="2.0.0" />
<PackageReference Include="Microsoft.AspNetCore.StaticFiles" Version="2.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="2.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.FileExtensions" Version="2.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="2.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.FileExtensions" Version="2.1.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="2.1.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="2.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging" Version="2.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging" Version="2.1.0" />
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="2.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="2.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.7.0" />

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

@ -145,10 +145,10 @@ namespace Microsoft.Extensions.DependencyInjection.Test
/// <summary>
/// We determine if Active telemtery needs to be configured based on the assumptions that 'default' configuration
// created by base SDK has single preset ITelemetryIntitializer. If it ever changes, change TelemetryConfigurationOptions.IsActiveConfigured method as well.
// created by base SDK has single preset ITelemetryInitializer. If it ever changes, change TelemetryConfigurationOptions.IsActiveConfigured method as well.
/// </summary>
[Fact]
public static void DefaultTelemetryconfigurationHasOneTelemetryInitializer()
public static void DefaultTelemetryConfigurationHasOneTelemetryInitializer()
{
//
var defaultConfig = TelemetryConfiguration.CreateDefault();

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

@ -35,15 +35,18 @@
<PackageReference Include="Microsoft.AspNetCore.Http.Extensions" Version="1.0.2" />
<PackageReference Include="Microsoft.AspNetCore.Http.Features" Version="1.0.2" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Core" Version="1.0.3" />
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="1.0.2" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="1.0.2" />
<PackageReference Include="Microsoft.Extensions.Logging" Version="1.0.2" />
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="1.0.2" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.7.0" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.3.1" />
<PackageReference Include="xunit" Version="2.3.1" />
<DotNetCliToolReference Include="dotnet-xunit" Version="2.3.1" />
</ItemGroup>
<ItemGroup Condition=" '$(TargetFramework)' != 'netcoreapp2.0' ">
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="1.0.2" />
<PackageReference Include="Microsoft.Extensions.Logging" Version="1.0.2" />
</ItemGroup>
<ItemGroup Condition=" '$(TargetFramework)' == 'netcoreapp2.0' ">
<PackageReference Include="Microsoft.AspNetCore.Hosting" Version="2.0.0" />
<PackageReference Include="Microsoft.AspNetCore.Http" Version="2.0.0" />
@ -51,8 +54,8 @@
<PackageReference Include="Microsoft.AspNetCore.Http.Features" Version="2.0.0" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Core" Version="2.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="2.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="2.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging" Version="2.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="2.1.0" />
<PackageReference Include="Microsoft.Extensions.Logging" Version="2.1.0" />
</ItemGroup>
<ItemGroup Condition=" '$(TargetFramework)' == 'net46' ">

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

@ -86,7 +86,7 @@ namespace Microsoft.ApplicationInsights.AspNetCore.Tests.TelemetryInitializers
var telemetryListener = new DiagnosticListener(TestListenerName);
var initializer = new MvcDiagnosticsListener();
telemetryListener.SubscribeWithAdapter(initializer);
telemetryListener.Subscribe(initializer);
telemetryListener.Write("Microsoft.AspNetCore.Mvc.BeforeAction",
new { httpContext = contextAccessor.HttpContext, routeData = actionContext.RouteData });
@ -107,7 +107,7 @@ namespace Microsoft.ApplicationInsights.AspNetCore.Tests.TelemetryInitializers
var telemetryListener = new DiagnosticListener(TestListenerName);
var initializer = new MvcDiagnosticsListener();
telemetryListener.SubscribeWithAdapter(initializer);
telemetryListener.Subscribe(initializer);
telemetryListener.Write("Microsoft.AspNetCore.Mvc.BeforeAction",
new { httpContext = contextAccessor.HttpContext, routeData = actionContext.RouteData });
@ -127,7 +127,7 @@ namespace Microsoft.ApplicationInsights.AspNetCore.Tests.TelemetryInitializers
var telemetryListener = new DiagnosticListener(TestListenerName);
var initializer = new MvcDiagnosticsListener();
telemetryListener.SubscribeWithAdapter(initializer);
telemetryListener.Subscribe(initializer);
telemetryListener.Write("Microsoft.AspNetCore.Mvc.BeforeAction",
new { httpContext = contextAccessor.HttpContext, routeData = actionContext.RouteData });
@ -149,7 +149,7 @@ namespace Microsoft.ApplicationInsights.AspNetCore.Tests.TelemetryInitializers
var telemetryListener = new DiagnosticListener(TestListenerName);
var initializer = new MvcDiagnosticsListener();
telemetryListener.SubscribeWithAdapter(initializer);
telemetryListener.Subscribe(initializer);
telemetryListener.Write("Microsoft.AspNetCore.Mvc.BeforeAction",
new { httpContext = contextAccessor.HttpContext, routeData = actionContext.RouteData });
@ -173,7 +173,7 @@ namespace Microsoft.ApplicationInsights.AspNetCore.Tests.TelemetryInitializers
var telemetryListener = new DiagnosticListener(TestListenerName);
var initializer = new MvcDiagnosticsListener();
telemetryListener.SubscribeWithAdapter(initializer);
telemetryListener.Subscribe(initializer);
telemetryListener.Write("Microsoft.AspNetCore.Mvc.BeforeAction",
new { httpContext = contextAccessor.HttpContext, routeData = actionContext.RouteData });
@ -194,7 +194,7 @@ namespace Microsoft.ApplicationInsights.AspNetCore.Tests.TelemetryInitializers
var contextAccessor = HttpContextAccessorHelper.CreateHttpContextAccessor(new RequestTelemetry(), actionContext);
var telemetryListener = new DiagnosticListener(TestListenerName);
var initializer = new MvcDiagnosticsListener();
telemetryListener.SubscribeWithAdapter(initializer);
telemetryListener.Subscribe(initializer);
telemetryListener.Write("Microsoft.AspNetCore.Mvc.BeforeAction",
new { httpContext = contextAccessor.HttpContext, routeData = actionContext.RouteData });

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

@ -3,12 +3,20 @@ using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
namespace WebApi20.FunctionalTests.Controllers
{
[Route("api/[controller]")]
public class ValuesController : Controller
{
ILogger<ValuesController> logger;
public ValuesController(ILogger<ValuesController> logger)
{
this.logger = logger;
}
// GET api/values
[HttpGet]
public IEnumerable<string> Get()
@ -20,6 +28,10 @@ namespace WebApi20.FunctionalTests.Controllers
[HttpGet("{id}")]
public string Get(int id)
{
logger.LogError("error logged");
logger.LogWarning("warning logged");
logger.LogInformation("information logged");
logger.LogTrace("trace logged");
return "value";
}

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

@ -0,0 +1,150 @@
namespace FunctionalTests
{
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text.RegularExpressions;
using FunctionalTestUtils;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.ApplicationInsights.DataContracts;
using Microsoft.ApplicationInsights.DependencyCollector;
using Xunit;
using Xunit.Abstractions;
using AI;
using Microsoft.Extensions.Logging;
/// <summary>
/// These are Functional Tests validating E2E ILogger integration. Though filtering mechanism is done by the ILogger framework itself, we
/// are here testing that the integration is done in correct ways.
/// Specifically,
/// 1. By Default, Warning and above from All categories is expected to captured.
/// 2. Any overriding done by user is respected and will override default behaviour
/// </summary>
public class LoggerTests : TelemetryTestsBase, IDisposable
{
private const string assemblyName = "WebApi20.FunctionalTests20";
public LoggerTests(ITestOutputHelper output) : base (output)
{
}
[Fact]
public void TestIloggerWarningOrAboveIsCapturedByDefault()
{
#if NETCOREAPP2_0
using (var server = new InProcessServer(assemblyName, this.output))
{
// Make request to this path, which sents one log of each severity Error, Warning, Information, Trace
this.ExecuteRequest(server.BaseHost + "/api/values/5");
// By default, AI is expected to capture Warning, Error
var actual = server.Listener.ReceiveItemsOfType<TelemetryItem<MessageData>>(2, TestListenerTimeoutInMs);
this.DebugTelemetryItems(actual);
// Expect 2 items.
Assert.Equal(2, actual.Count());
ValidateMessage(actual[0], new string[] {"error", "warning" });
ValidateMessage(actual[1], new string[] { "error", "warning" });
}
#endif
}
[Fact]
public void TestIloggerDefaultsCanBeOverridenByUserForAllCategories()
{
#if NETCOREAPP2_0
void ConfigureServices(IServiceCollection services)
{
// ARRANGE
// AddFilter to capture only Error. This is expected to override default behavior.
services.AddLogging(builder => builder.AddFilter<Microsoft.Extensions.Logging.ApplicationInsights.ApplicationInsightsLoggerProvider>("", LogLevel.Error));
}
using (var server = new InProcessServer(assemblyName, this.output,null, ConfigureServices))
{
// Make request to this path, which sents one log of each severity Error, Warning, Information, Trace
this.ExecuteRequest(server.BaseHost + "/api/values/5");
// AI is now expected to capture only Error
var actual = server.Listener.ReceiveItemsOfType<TelemetryItem<MessageData>>(1, TestListenerTimeoutInMs);
this.DebugTelemetryItems(actual);
// Expect 1 item1.
Assert.Equal(1, actual.Count());
ValidateMessage(actual[0], new string[] { "error"});
}
#endif
}
[Fact]
public void TestIloggerDefaultsCanBeOverridenByUserForSpecificCategory()
{
#if NETCOREAPP2_0
void ConfigureServices(IServiceCollection services)
{
// ARRANGE
// AddFilter to capture Trace or above for user category. This is expected to override default behavior.
services.AddLogging(builder => builder.AddFilter<Microsoft.Extensions.Logging.ApplicationInsights.ApplicationInsightsLoggerProvider>("WebApi20.FunctionalTests.Controllers", LogLevel.Trace));
}
using (var server = new InProcessServer(assemblyName, this.output, null, ConfigureServices))
{
// Make request to this path, which sents one log of each severity Error, Warning, Information, Trace
this.ExecuteRequest(server.BaseHost + "/api/values/5");
// AI is now expected to capture Warning or above for all categories (default behavior), except 'WebApi20.FunctionalTests.Controllers' category where Trace of above
// is captured. (overridden behavior)
var actual = server.Listener.ReceiveItemsOfType<TelemetryItem<MessageData>>(4, TestListenerTimeoutInMs);
this.DebugTelemetryItems(actual);
// Expect 4 items.
Assert.Equal(4, actual.Count());
ValidateMessage(actual[0], new string[] { "error" });
ValidateMessage(actual[1], new string[] { "warning" });
ValidateMessage(actual[2], new string[] { "information" });
ValidateMessage(actual[3], new string[] { "trace" });
}
#endif
}
private bool ValidateMessage(Envelope item, string[] expectedMessages)
{
if (!(item is TelemetryItem<MessageData> trace))
{
return false;
}
var actualMessage = trace.data.baseData.message;
bool foundMessage = false;
foreach (var msg in expectedMessages)
{
if(actualMessage.Contains(msg))
{
foundMessage = true;
break;
}
}
return foundMessage;
}
public void Dispose()
{
while (Activity.Current != null)
{
Activity.Current.Stop();
}
}
}
}

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

@ -35,7 +35,7 @@
<PackageReference Include="Microsoft.AspNetCore.Mvc" Version="2.0.0" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.WebApiCompatShim" Version="2.0.0" />
<PackageReference Include="Microsoft.AspNetCore.StaticFiles" Version="2.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="2.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="2.1.0" />
<PackageReference Include="Microsoft.AspNetCore.Diagnostics" Version="2.0.0" />
<PackageReference Include="Microsoft.AspNetCore.Server.Kestrel" Version="2.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.7.0" />