[AppInsights] moving to newer .NET logging dependencies
This commit is contained in:
Родитель
7b19acdfa6
Коммит
b945a81fb0
|
@ -3,6 +3,7 @@
|
|||
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
|
@ -22,16 +23,22 @@ namespace SampleHost
|
|||
.AddServiceBus()
|
||||
.AddEventHubs();
|
||||
})
|
||||
.AddApplicationInsights()
|
||||
.ConfigureAppConfiguration(b =>
|
||||
{
|
||||
// Adding command line as a configuration source
|
||||
b.AddCommandLine(args);
|
||||
})
|
||||
.ConfigureLogging(b =>
|
||||
.ConfigureLogging((context, b) =>
|
||||
{
|
||||
b.SetMinimumLevel(LogLevel.Debug);
|
||||
b.AddConsole();
|
||||
|
||||
// If this key exists in any config, use it to enable App Insights
|
||||
string appInsightsKey = context.Configuration["APPINSIGHTS_INSTRUMENTATIONKEY"];
|
||||
if (!string.IsNullOrEmpty(appInsightsKey))
|
||||
{
|
||||
b.AddApplicationInsights(o => o.InstrumentationKey = appInsightsKey);
|
||||
}
|
||||
})
|
||||
.UseConsoleLifetime();
|
||||
|
||||
|
|
|
@ -1,33 +0,0 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using Microsoft.Azure.WebJobs.Logging;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
|
||||
namespace SampleHost
|
||||
{
|
||||
public static class SampleLoggingExtensions
|
||||
{
|
||||
public static IHostBuilder AddApplicationInsights(this IHostBuilder builder)
|
||||
{
|
||||
// If AppInsights is enabled, build up a LoggerFactory
|
||||
string instrumentationKey = Environment.GetEnvironmentVariable("APPINSIGHTS_INSTRUMENTATIONKEY");
|
||||
if (!string.IsNullOrEmpty(instrumentationKey))
|
||||
{
|
||||
var filter = new LogCategoryFilter
|
||||
{
|
||||
DefaultLevel = LogLevel.Debug
|
||||
};
|
||||
|
||||
filter.CategoryLevels[LogCategories.Results] = LogLevel.Debug;
|
||||
filter.CategoryLevels[LogCategories.Aggregator] = LogLevel.Debug;
|
||||
|
||||
builder.AddApplicationInsights(instrumentationKey, filter.Filter, null);
|
||||
}
|
||||
|
||||
return builder;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -11,8 +11,6 @@ namespace Microsoft.Azure.WebJobs
|
|||
/// </summary>
|
||||
public sealed class JobHostOptions
|
||||
{
|
||||
private string _hostId;
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if <see cref="UseDevelopmentSettings"/> has been called on this instance.
|
||||
/// </summary>
|
||||
|
|
|
@ -3,9 +3,6 @@
|
|||
|
||||
using System;
|
||||
using Microsoft.Azure.WebJobs;
|
||||
using Microsoft.Azure.WebJobs.Host.Bindings;
|
||||
using Microsoft.Azure.WebJobs.Host.Config;
|
||||
using Microsoft.Azure.WebJobs.Host.Loggers;
|
||||
using Microsoft.Azure.WebJobs.Hosting;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
|
|
@ -1,55 +0,0 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace Microsoft.Azure.WebJobs.Logging
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides a filter for use with an <see cref="ILogger"/>.
|
||||
/// </summary>
|
||||
public class LogCategoryFilter
|
||||
{
|
||||
/// <summary>
|
||||
/// The minimum <see cref="LogLevel"/> required for logs with categories that do not match
|
||||
/// any category in <see cref="CategoryLevels"/>.
|
||||
/// </summary>
|
||||
public LogLevel DefaultLevel { get; set; } = LogLevel.Information;
|
||||
|
||||
/// <summary>
|
||||
/// A collection of filters that are used by <see cref="Filter"/> to determine if a log
|
||||
/// will be written or filtered.
|
||||
/// </summary>
|
||||
public IDictionary<string, LogLevel> CategoryLevels { get; } = new Dictionary<string, LogLevel> { };
|
||||
|
||||
/// <summary>
|
||||
/// Pass this function as a filter parameter to a <see cref="ILoggerProvider"/> to enable filtering
|
||||
/// based on the specified <see cref="CategoryLevels"/>. The filter will match the longest possible key in
|
||||
/// <see cref="CategoryLevels"/> and return true if the level is equal to or greater than the filter. If
|
||||
/// there is no match, the value of <see cref="DefaultLevel"/> is used.
|
||||
/// </summary>
|
||||
/// <param name="category">The category of the current log message.</param>
|
||||
/// <param name="level">The <see cref="LogLevel"/> of the current log message.</param>
|
||||
/// <returns>True if the level is equal to or greater than the matched filter. Otherwise, false.</returns>
|
||||
public bool Filter(string category, LogLevel level)
|
||||
{
|
||||
// find the longest loglevel that matches the category
|
||||
IEnumerable<string> matches = CategoryLevels.Keys.Where(k => category.StartsWith(k, System.StringComparison.CurrentCulture));
|
||||
string longestMatch = matches?.Max();
|
||||
|
||||
LogLevel requestedLevel;
|
||||
if (string.IsNullOrEmpty(longestMatch))
|
||||
{
|
||||
requestedLevel = DefaultLevel;
|
||||
}
|
||||
else
|
||||
{
|
||||
requestedLevel = CategoryLevels[longestMatch];
|
||||
}
|
||||
|
||||
return level >= requestedLevel;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -16,6 +16,7 @@
|
|||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="2.1.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging" Version="2.1.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Configuration" Version="2.1.0" />
|
||||
<PackageReference Include="StyleCop.Analyzers" Version="1.1.0-beta004">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
|
|
|
@ -1,228 +0,0 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using Microsoft.ApplicationInsights;
|
||||
using Microsoft.ApplicationInsights.Channel;
|
||||
using Microsoft.ApplicationInsights.DependencyCollector;
|
||||
using Microsoft.ApplicationInsights.Extensibility;
|
||||
using Microsoft.ApplicationInsights.Extensibility.Implementation;
|
||||
using Microsoft.ApplicationInsights.Extensibility.PerfCounterCollector.QuickPulse;
|
||||
using Microsoft.ApplicationInsights.SnapshotCollector;
|
||||
using Microsoft.ApplicationInsights.WindowsServer;
|
||||
using Microsoft.ApplicationInsights.WindowsServer.Channel.Implementation;
|
||||
using Microsoft.ApplicationInsights.WindowsServer.TelemetryChannel;
|
||||
using Microsoft.Azure.WebJobs;
|
||||
using Microsoft.Azure.WebJobs.Logging;
|
||||
using Microsoft.Azure.WebJobs.Logging.ApplicationInsights;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
|
||||
namespace Microsoft.Extensions.Logging
|
||||
{
|
||||
/// <summary>
|
||||
/// Extensions for ApplicationInsights configurationon an <see cref="IHostBuilder"/>.
|
||||
/// </summary>
|
||||
public static class ApplicationInsightsHostBuilderExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Registers Application Insights and <see cref="ApplicationInsightsLoggerProvider"/> with an <see cref="IHostBuilder"/>.
|
||||
/// </summary>
|
||||
/// <param name="builder">The host builder.</param>
|
||||
/// <param name="instrumentationKey">The Application Insights instrumentation key.</param>
|
||||
/// <param name="samplingSettings">The <see cref="SamplingPercentageEstimatorSettings"/> to use for configuring adaptive sampling. If null, sampling is disabled.</param>
|
||||
/// <returns>A <see cref="IHostBuilder"/> for chaining additional operations.</returns>
|
||||
public static IHostBuilder AddApplicationInsights(this IHostBuilder builder, string instrumentationKey, SamplingPercentageEstimatorSettings samplingSettings)
|
||||
{
|
||||
return AddApplicationInsights(builder, instrumentationKey, (_, level) => level > LogLevel.Debug, samplingSettings);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Registers Application Insights and <see cref="ApplicationInsightsLoggerProvider"/> with an <see cref="IHostBuilder"/>。
|
||||
/// </summary>
|
||||
/// <param name="builder">The host builder.</param>
|
||||
/// <param name="instrumentationKey">The Application Insights instrumentation key.</param>
|
||||
/// <param name="samplingSettings">Sampling settings</param>
|
||||
/// <param name="snapshotCollectorConfiguration">Snapshot collector configuration.</param>
|
||||
/// <returns>A <see cref="IHostBuilder"/> for chaining additional operations.</returns>
|
||||
public static IHostBuilder AddApplicationInsights(this IHostBuilder builder, string instrumentationKey, SamplingPercentageEstimatorSettings samplingSettings, SnapshotCollectorConfiguration snapshotCollectorConfiguration)
|
||||
{
|
||||
return AddApplicationInsights(builder, instrumentationKey, (_, level) => level > LogLevel.Debug, samplingSettings, snapshotCollectorConfiguration);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Registers Application Insights and <see cref="ApplicationInsightsLoggerProvider"/> with an <see cref="IHostBuilder"/>.
|
||||
/// </summary>
|
||||
/// <param name="builder">The host builder.</param>
|
||||
/// <param name="instrumentationKey">The Application Insights instrumentation key.</param>
|
||||
/// <param name="filter">A filter that returns true if a message with the specified <see cref="LogLevel"/>
|
||||
/// and category should be logged. You can use <see cref="LogCategoryFilter.Filter(string, LogLevel)"/>
|
||||
/// or write a custom filter.</param>
|
||||
/// <param name="samplingSettings">The <see cref="SamplingPercentageEstimatorSettings"/> to use for configuring adaptive sampling. If null, sampling is disabled.</param>
|
||||
/// <param name="snapshotCollectorConfiguration">The <see cref="SnapshotCollectorConfiguration" /> to use for configuring snapshot collector. If null, snapshot collector is disabled.</param>
|
||||
/// <returns>A <see cref="IHostBuilder"/> for chaining additional operations.</returns>
|
||||
public static IHostBuilder AddApplicationInsights(
|
||||
this IHostBuilder builder,
|
||||
string instrumentationKey,
|
||||
Func<string, LogLevel, bool> filter,
|
||||
SamplingPercentageEstimatorSettings samplingSettings,
|
||||
SnapshotCollectorConfiguration snapshotCollectorConfiguration = null)
|
||||
{
|
||||
if (string.IsNullOrEmpty(instrumentationKey))
|
||||
{
|
||||
return builder;
|
||||
}
|
||||
|
||||
builder.ConfigureServices((context, services) =>
|
||||
{
|
||||
services.AddSingleton<ITelemetryInitializer, HttpDependenciesParsingTelemetryInitializer>();
|
||||
services.AddSingleton<ITelemetryInitializer, WebJobsRoleEnvironmentTelemetryInitializer>();
|
||||
services.AddSingleton<ITelemetryInitializer, WebJobsTelemetryInitializer>();
|
||||
services.AddSingleton<ITelemetryInitializer, WebJobsSanitizingInitializer>();
|
||||
services.AddSingleton<ITelemetryModule, QuickPulseTelemetryModule>();
|
||||
services.AddSingleton<ITelemetryModule, DependencyTrackingTelemetryModule>(provider =>
|
||||
{
|
||||
var dependencyCollector = new DependencyTrackingTelemetryModule();
|
||||
var excludedDomains = dependencyCollector.ExcludeComponentCorrelationHttpHeadersOnDomains;
|
||||
excludedDomains.Add("core.windows.net");
|
||||
excludedDomains.Add("core.chinacloudapi.cn");
|
||||
excludedDomains.Add("core.cloudapi.de");
|
||||
excludedDomains.Add("core.usgovcloudapi.net");
|
||||
excludedDomains.Add("localhost");
|
||||
excludedDomains.Add("127.0.0.1");
|
||||
|
||||
return dependencyCollector;
|
||||
});
|
||||
services.AddSingleton<ITelemetryModule, AppServicesHeartbeatTelemetryModule>();
|
||||
|
||||
ServerTelemetryChannel serverChannel = new ServerTelemetryChannel();
|
||||
services.AddSingleton<ITelemetryChannel>(serverChannel);
|
||||
services.AddSingleton<TelemetryConfiguration>(provider =>
|
||||
{
|
||||
// Because of https://github.com/Microsoft/ApplicationInsights-dotnet-server/issues/943
|
||||
// we have to touch (and create) Active configuration before initializing telemetry modules
|
||||
TelemetryConfiguration activeConfig = TelemetryConfiguration.Active;
|
||||
|
||||
ITelemetryChannel channel = provider.GetService<ITelemetryChannel>();
|
||||
TelemetryConfiguration config = TelemetryConfiguration.CreateDefault();
|
||||
SetupTelemetryConfiguration(
|
||||
config,
|
||||
instrumentationKey,
|
||||
filter,
|
||||
samplingSettings,
|
||||
snapshotCollectorConfiguration,
|
||||
channel,
|
||||
provider.GetServices<ITelemetryInitializer>(),
|
||||
provider.GetServices<ITelemetryModule>());
|
||||
|
||||
// Function users have no access to TelemetryConfiguration from host DI container,
|
||||
// so we'll expect user to work with TelemetryConfiguration.Active
|
||||
// Also, some ApplicationInsights internal operations (heartbeats) depend on
|
||||
// the TelemetryConfiguration.Active being set so, we'll set up Active once per process lifetime.
|
||||
if (string.IsNullOrEmpty(activeConfig.InstrumentationKey))
|
||||
{
|
||||
SetupTelemetryConfiguration(
|
||||
activeConfig,
|
||||
instrumentationKey,
|
||||
filter,
|
||||
samplingSettings,
|
||||
snapshotCollectorConfiguration,
|
||||
new ServerTelemetryChannel(),
|
||||
provider.GetServices<ITelemetryInitializer>(),
|
||||
provider.GetServices<ITelemetryModule>());
|
||||
}
|
||||
return config;
|
||||
});
|
||||
services.AddSingleton<TelemetryClient>(provider =>
|
||||
{
|
||||
TelemetryConfiguration configuration = provider.GetService<TelemetryConfiguration>();
|
||||
TelemetryClient client = new TelemetryClient(configuration);
|
||||
|
||||
string assemblyVersion = GetAssemblyFileVersion(typeof(JobHost).Assembly);
|
||||
client.Context.GetInternalContext().SdkVersion = $"webjobs: {assemblyVersion}";
|
||||
|
||||
return client;
|
||||
});
|
||||
|
||||
services.AddSingleton<ILoggerProvider, ApplicationInsightsLoggerProvider>();
|
||||
});
|
||||
|
||||
return builder;
|
||||
}
|
||||
|
||||
internal static string GetAssemblyFileVersion(Assembly assembly)
|
||||
{
|
||||
AssemblyFileVersionAttribute fileVersionAttr = assembly.GetCustomAttribute<AssemblyFileVersionAttribute>();
|
||||
return fileVersionAttr?.Version ?? LoggingConstants.Unknown;
|
||||
}
|
||||
|
||||
private static void SetupTelemetryConfiguration(
|
||||
TelemetryConfiguration configuration,
|
||||
string instrumentationKey,
|
||||
Func<string, LogLevel, bool> filter,
|
||||
SamplingPercentageEstimatorSettings samplingSettings,
|
||||
SnapshotCollectorConfiguration snapshotCollectorConfiguration,
|
||||
ITelemetryChannel channel,
|
||||
IEnumerable<ITelemetryInitializer> telemetryInitializers,
|
||||
IEnumerable<ITelemetryModule> telemetryModules)
|
||||
{
|
||||
if (instrumentationKey != null)
|
||||
{
|
||||
configuration.InstrumentationKey = instrumentationKey;
|
||||
}
|
||||
|
||||
configuration.TelemetryChannel = channel;
|
||||
|
||||
foreach (ITelemetryInitializer initializer in telemetryInitializers)
|
||||
{
|
||||
configuration.TelemetryInitializers.Add(initializer);
|
||||
}
|
||||
|
||||
(channel as ServerTelemetryChannel)?.Initialize(configuration);
|
||||
|
||||
QuickPulseTelemetryModule quickPulseModule = null;
|
||||
foreach (ITelemetryModule module in telemetryModules)
|
||||
{
|
||||
if (module is QuickPulseTelemetryModule telemetryModule)
|
||||
{
|
||||
quickPulseModule = telemetryModule;
|
||||
}
|
||||
|
||||
module.Initialize(configuration);
|
||||
}
|
||||
|
||||
QuickPulseTelemetryProcessor quickPulseProcessor = null;
|
||||
configuration.TelemetryProcessorChainBuilder
|
||||
.Use((next) =>
|
||||
{
|
||||
quickPulseProcessor = new QuickPulseTelemetryProcessor(next);
|
||||
return quickPulseProcessor;
|
||||
})
|
||||
.Use((next) => new FilteringTelemetryProcessor(filter, next));
|
||||
|
||||
if (samplingSettings != null)
|
||||
{
|
||||
configuration.TelemetryProcessorChainBuilder.Use((next) =>
|
||||
new AdaptiveSamplingTelemetryProcessor(samplingSettings, null, next));
|
||||
}
|
||||
|
||||
if (snapshotCollectorConfiguration != null)
|
||||
{
|
||||
configuration.TelemetryProcessorChainBuilder.UseSnapshotCollector(snapshotCollectorConfiguration);
|
||||
}
|
||||
|
||||
configuration.TelemetryProcessorChainBuilder.Build();
|
||||
quickPulseModule?.RegisterTelemetryProcessor(quickPulseProcessor);
|
||||
|
||||
foreach (ITelemetryProcessor processor in configuration.TelemetryProcessors)
|
||||
{
|
||||
if (processor is ITelemetryModule module)
|
||||
{
|
||||
module.Initialize(configuration);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.Azure.WebJobs.Logging.ApplicationInsights;
|
||||
|
||||
namespace Microsoft.Extensions.Logging
|
||||
{
|
||||
/// <summary>
|
||||
/// This rule is used to replace any rules registered for the App Insights provider and store
|
||||
/// them all in ChildRules. When constructing the <see cref="FilteringTelemetryProcessor"/>, these
|
||||
/// rules are pulled out and applied. This allows the .NET logging infrastructure and configuration
|
||||
/// to work as usual, but still allow the logs to flow through the QuickPulse processor.
|
||||
/// </summary>
|
||||
internal class ApplicationInsightsLoggerFilterRule : LoggerFilterRule
|
||||
{
|
||||
public ApplicationInsightsLoggerFilterRule(IList<LoggerFilterRule> childRules)
|
||||
: base(typeof(ApplicationInsightsLoggerProvider).FullName, null, Logging.LogLevel.Trace, null)
|
||||
{
|
||||
ChildRules = childRules;
|
||||
}
|
||||
|
||||
public IList<LoggerFilterRule> ChildRules { get; }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
|
||||
using Microsoft.ApplicationInsights.SnapshotCollector;
|
||||
using Microsoft.ApplicationInsights.WindowsServer.Channel.Implementation;
|
||||
|
||||
namespace Microsoft.Azure.WebJobs.Logging.ApplicationInsights
|
||||
{
|
||||
public class ApplicationInsightsLoggerOptions
|
||||
{
|
||||
public string InstrumentationKey { get; set; }
|
||||
|
||||
public SamplingPercentageEstimatorSettings SamplingSettings { get; set; }
|
||||
|
||||
public SnapshotCollectorConfiguration SnapshotConfiguration { get; set; }
|
||||
}
|
||||
}
|
|
@ -8,8 +8,12 @@ using Microsoft.Extensions.Logging;
|
|||
|
||||
namespace Microsoft.Azure.WebJobs.Logging.ApplicationInsights
|
||||
{
|
||||
|
||||
[ProviderAlias(Alias)]
|
||||
public class ApplicationInsightsLoggerProvider : ILoggerProvider
|
||||
{
|
||||
internal const string Alias = "ApplicationInsights";
|
||||
|
||||
private readonly TelemetryClient _client;
|
||||
private bool _disposed;
|
||||
|
||||
|
|
|
@ -0,0 +1,60 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Microsoft.Azure.WebJobs.Logging.ApplicationInsights;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging.Configuration;
|
||||
|
||||
namespace Microsoft.Extensions.Logging
|
||||
{
|
||||
/// <summary>
|
||||
/// Extensions for ApplicationInsights configuration on an <see cref="ILoggingBuilder"/>.
|
||||
/// </summary>
|
||||
public static class ApplicationInsightsLoggingBuilderExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Registers Application Insights and <see cref="ApplicationInsightsLoggerProvider"/> with an <see cref="ILoggingBuilder"/>.
|
||||
/// </summary>
|
||||
public static ILoggingBuilder AddApplicationInsights(
|
||||
this ILoggingBuilder builder)
|
||||
{
|
||||
return builder.AddApplicationInsights(null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Registers Application Insights and <see cref="ApplicationInsightsLoggerProvider"/> with an <see cref="ILoggingBuilder"/>.
|
||||
/// </summary>
|
||||
public static ILoggingBuilder AddApplicationInsights(
|
||||
this ILoggingBuilder builder,
|
||||
Action<ApplicationInsightsLoggerOptions> configure)
|
||||
{
|
||||
builder.AddConfiguration();
|
||||
builder.Services.AddApplicationInsights(configure);
|
||||
|
||||
builder.Services.PostConfigure<LoggerFilterOptions>(o =>
|
||||
{
|
||||
// We want all logs to flow through the logger so they show up in QuickPulse.
|
||||
// To do that, we'll hide all registered rules inside of this one. They will be re-populated
|
||||
// and used by the FilteringTelemetryProcessor futher down the pipeline.
|
||||
string fullTypeName = typeof(ApplicationInsightsLoggerProvider).FullName;
|
||||
IList<LoggerFilterRule> matchingRules = o.Rules.Where(r =>
|
||||
{
|
||||
return r.ProviderName == fullTypeName
|
||||
|| r.ProviderName == ApplicationInsightsLoggerProvider.Alias;
|
||||
}).ToList();
|
||||
|
||||
foreach (var rule in matchingRules)
|
||||
{
|
||||
o.Rules.Remove(rule);
|
||||
}
|
||||
|
||||
o.Rules.Add(new ApplicationInsightsLoggerFilterRule(matchingRules));
|
||||
});
|
||||
|
||||
return builder;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,227 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using Microsoft.ApplicationInsights;
|
||||
using Microsoft.ApplicationInsights.Channel;
|
||||
using Microsoft.ApplicationInsights.DependencyCollector;
|
||||
using Microsoft.ApplicationInsights.Extensibility;
|
||||
using Microsoft.ApplicationInsights.Extensibility.Implementation;
|
||||
using Microsoft.ApplicationInsights.Extensibility.PerfCounterCollector.QuickPulse;
|
||||
using Microsoft.ApplicationInsights.SnapshotCollector;
|
||||
using Microsoft.ApplicationInsights.WindowsServer;
|
||||
using Microsoft.ApplicationInsights.WindowsServer.Channel.Implementation;
|
||||
using Microsoft.ApplicationInsights.WindowsServer.TelemetryChannel;
|
||||
using Microsoft.Azure.WebJobs;
|
||||
using Microsoft.Azure.WebJobs.Logging.ApplicationInsights;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Logging.Configuration;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
namespace Microsoft.Extensions.DependencyInjection
|
||||
{
|
||||
internal static class ApplicationInsightsServiceCollectionExtensions
|
||||
{
|
||||
public static IServiceCollection AddApplicationInsights(this IServiceCollection services, Action<ApplicationInsightsLoggerOptions> configure)
|
||||
{
|
||||
services.AddApplicationInsights();
|
||||
if (configure != null)
|
||||
{
|
||||
services.Configure<ApplicationInsightsLoggerOptions>(configure);
|
||||
}
|
||||
return services;
|
||||
}
|
||||
|
||||
public static IServiceCollection AddApplicationInsights(this IServiceCollection services)
|
||||
{
|
||||
// Bind to the configuration section registered with
|
||||
services.AddOptions<ApplicationInsightsLoggerOptions>()
|
||||
.Configure<ILoggerProviderConfiguration<ApplicationInsightsLoggerProvider>>((options, config) =>
|
||||
{
|
||||
config.Configuration?.Bind(options);
|
||||
});
|
||||
|
||||
services.AddSingleton<ITelemetryInitializer, HttpDependenciesParsingTelemetryInitializer>();
|
||||
services.AddSingleton<ITelemetryInitializer, WebJobsRoleEnvironmentTelemetryInitializer>();
|
||||
services.AddSingleton<ITelemetryInitializer, WebJobsTelemetryInitializer>();
|
||||
services.AddSingleton<ITelemetryInitializer, WebJobsSanitizingInitializer>();
|
||||
services.AddSingleton<ITelemetryModule, QuickPulseTelemetryModule>();
|
||||
services.AddSingleton<ITelemetryModule, DependencyTrackingTelemetryModule>(provider =>
|
||||
{
|
||||
var dependencyCollector = new DependencyTrackingTelemetryModule();
|
||||
var excludedDomains = dependencyCollector.ExcludeComponentCorrelationHttpHeadersOnDomains;
|
||||
excludedDomains.Add("core.windows.net");
|
||||
excludedDomains.Add("core.chinacloudapi.cn");
|
||||
excludedDomains.Add("core.cloudapi.de");
|
||||
excludedDomains.Add("core.usgovcloudapi.net");
|
||||
excludedDomains.Add("localhost");
|
||||
excludedDomains.Add("127.0.0.1");
|
||||
|
||||
return dependencyCollector;
|
||||
});
|
||||
services.AddSingleton<ITelemetryModule, AppServicesHeartbeatTelemetryModule>();
|
||||
|
||||
ServerTelemetryChannel serverChannel = new ServerTelemetryChannel();
|
||||
services.AddSingleton<ITelemetryChannel>(serverChannel);
|
||||
services.AddSingleton<TelemetryConfiguration>(provider =>
|
||||
{
|
||||
ApplicationInsightsLoggerOptions options = provider.GetService<IOptions<ApplicationInsightsLoggerOptions>>().Value;
|
||||
LoggerFilterOptions filterOptions = CreateFilterOptions(provider.GetService<IOptions<LoggerFilterOptions>>().Value);
|
||||
|
||||
// Because of https://github.com/Microsoft/ApplicationInsights-dotnet-server/issues/943
|
||||
// we have to touch (and create) Active configuration before initializing telemetry modules
|
||||
TelemetryConfiguration activeConfig = TelemetryConfiguration.Active;
|
||||
|
||||
|
||||
ITelemetryChannel channel = provider.GetService<ITelemetryChannel>();
|
||||
TelemetryConfiguration config = TelemetryConfiguration.CreateDefault();
|
||||
SetupTelemetryConfiguration(
|
||||
config,
|
||||
options.InstrumentationKey,
|
||||
options.SamplingSettings,
|
||||
options.SnapshotConfiguration,
|
||||
channel,
|
||||
provider.GetServices<ITelemetryInitializer>(),
|
||||
provider.GetServices<ITelemetryModule>(),
|
||||
filterOptions);
|
||||
|
||||
// Function users have no access to TelemetryConfiguration from host DI container,
|
||||
// so we'll expect user to work with TelemetryConfiguration.Active
|
||||
// Also, some ApplicationInsights internal operations (heartbeats) depend on
|
||||
// the TelemetryConfiguration.Active being set so, we'll set up Active once per process lifetime.
|
||||
if (string.IsNullOrEmpty(activeConfig.InstrumentationKey))
|
||||
{
|
||||
SetupTelemetryConfiguration(
|
||||
activeConfig,
|
||||
options.InstrumentationKey,
|
||||
options.SamplingSettings,
|
||||
options.SnapshotConfiguration,
|
||||
new ServerTelemetryChannel(),
|
||||
provider.GetServices<ITelemetryInitializer>(),
|
||||
provider.GetServices<ITelemetryModule>(),
|
||||
filterOptions);
|
||||
}
|
||||
return config;
|
||||
});
|
||||
|
||||
services.AddSingleton<TelemetryClient>(provider =>
|
||||
{
|
||||
TelemetryConfiguration configuration = provider.GetService<TelemetryConfiguration>();
|
||||
TelemetryClient client = new TelemetryClient(configuration);
|
||||
|
||||
string assemblyVersion = GetAssemblyFileVersion(typeof(JobHost).Assembly);
|
||||
client.Context.GetInternalContext().SdkVersion = $"webjobs: {assemblyVersion}";
|
||||
|
||||
return client;
|
||||
});
|
||||
|
||||
services.AddSingleton<ILoggerProvider, ApplicationInsightsLoggerProvider>();
|
||||
|
||||
return services;
|
||||
}
|
||||
|
||||
internal static LoggerFilterOptions CreateFilterOptions(LoggerFilterOptions registeredOptions)
|
||||
{
|
||||
// We want our own copy of the rules, excluding the 'allow-all' rule that we added for this provider.
|
||||
LoggerFilterOptions customFilterOptions = new LoggerFilterOptions
|
||||
{
|
||||
MinLevel = registeredOptions.MinLevel
|
||||
};
|
||||
|
||||
ApplicationInsightsLoggerFilterRule allowAllRule = registeredOptions.Rules.OfType<ApplicationInsightsLoggerFilterRule>().Single();
|
||||
|
||||
// Copy all existing rules
|
||||
foreach (LoggerFilterRule rule in registeredOptions.Rules)
|
||||
{
|
||||
if (rule != allowAllRule)
|
||||
{
|
||||
customFilterOptions.Rules.Add(rule);
|
||||
}
|
||||
}
|
||||
|
||||
// Copy 'hidden' rules
|
||||
foreach (LoggerFilterRule rule in allowAllRule.ChildRules)
|
||||
{
|
||||
customFilterOptions.Rules.Add(rule);
|
||||
}
|
||||
|
||||
return customFilterOptions;
|
||||
}
|
||||
|
||||
private static void SetupTelemetryConfiguration(
|
||||
TelemetryConfiguration configuration,
|
||||
string instrumentationKey,
|
||||
SamplingPercentageEstimatorSettings samplingSettings,
|
||||
SnapshotCollectorConfiguration snapshotCollectorConfiguration,
|
||||
ITelemetryChannel channel,
|
||||
IEnumerable<ITelemetryInitializer> telemetryInitializers,
|
||||
IEnumerable<ITelemetryModule> telemetryModules,
|
||||
LoggerFilterOptions filterOptions)
|
||||
{
|
||||
if (instrumentationKey != null)
|
||||
{
|
||||
configuration.InstrumentationKey = instrumentationKey;
|
||||
}
|
||||
|
||||
configuration.TelemetryChannel = channel;
|
||||
|
||||
foreach (ITelemetryInitializer initializer in telemetryInitializers)
|
||||
{
|
||||
configuration.TelemetryInitializers.Add(initializer);
|
||||
}
|
||||
|
||||
(channel as ServerTelemetryChannel)?.Initialize(configuration);
|
||||
|
||||
QuickPulseTelemetryModule quickPulseModule = null;
|
||||
foreach (ITelemetryModule module in telemetryModules)
|
||||
{
|
||||
if (module is QuickPulseTelemetryModule telemetryModule)
|
||||
{
|
||||
quickPulseModule = telemetryModule;
|
||||
}
|
||||
|
||||
module.Initialize(configuration);
|
||||
}
|
||||
|
||||
QuickPulseTelemetryProcessor quickPulseProcessor = null;
|
||||
configuration.TelemetryProcessorChainBuilder
|
||||
.Use((next) =>
|
||||
{
|
||||
quickPulseProcessor = new QuickPulseTelemetryProcessor(next);
|
||||
return quickPulseProcessor;
|
||||
})
|
||||
.Use((next) => new FilteringTelemetryProcessor(filterOptions, next));
|
||||
|
||||
if (samplingSettings != null)
|
||||
{
|
||||
configuration.TelemetryProcessorChainBuilder.Use((next) =>
|
||||
new AdaptiveSamplingTelemetryProcessor(samplingSettings, null, next));
|
||||
}
|
||||
|
||||
if (snapshotCollectorConfiguration != null)
|
||||
{
|
||||
configuration.TelemetryProcessorChainBuilder.UseSnapshotCollector(snapshotCollectorConfiguration);
|
||||
}
|
||||
|
||||
configuration.TelemetryProcessorChainBuilder.Build();
|
||||
quickPulseModule?.RegisterTelemetryProcessor(quickPulseProcessor);
|
||||
|
||||
foreach (ITelemetryProcessor processor in configuration.TelemetryProcessors)
|
||||
{
|
||||
if (processor is ITelemetryModule module)
|
||||
{
|
||||
module.Initialize(configuration);
|
||||
}
|
||||
}
|
||||
}
|
||||
internal static string GetAssemblyFileVersion(Assembly assembly)
|
||||
{
|
||||
AssemblyFileVersionAttribute fileVersionAttr = assembly.GetCustomAttribute<AssemblyFileVersionAttribute>();
|
||||
return fileVersionAttr?.Version ?? LoggingConstants.Unknown;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,6 +2,7 @@
|
|||
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using Microsoft.ApplicationInsights.Channel;
|
||||
using Microsoft.ApplicationInsights.DataContracts;
|
||||
using Microsoft.ApplicationInsights.Extensibility;
|
||||
|
@ -12,12 +13,16 @@ namespace Microsoft.Azure.WebJobs.Logging.ApplicationInsights
|
|||
{
|
||||
internal class FilteringTelemetryProcessor : ITelemetryProcessor
|
||||
{
|
||||
private readonly Func<string, LogLevel, bool> _filter;
|
||||
private static readonly LoggerRuleSelector RuleSelector = new LoggerRuleSelector();
|
||||
private static readonly Type ProviderType = typeof(ApplicationInsightsLoggerProvider);
|
||||
|
||||
private readonly ConcurrentDictionary<string, LoggerFilterRule> _ruleMap = new ConcurrentDictionary<string, LoggerFilterRule>();
|
||||
private readonly LoggerFilterOptions _filterOptions;
|
||||
private ITelemetryProcessor _next;
|
||||
|
||||
public FilteringTelemetryProcessor(Func<string, LogLevel, bool> filter, ITelemetryProcessor next)
|
||||
public FilteringTelemetryProcessor(LoggerFilterOptions filterOptions, ITelemetryProcessor next)
|
||||
{
|
||||
_filter = filter;
|
||||
_filterOptions = filterOptions;
|
||||
_next = next;
|
||||
}
|
||||
|
||||
|
@ -33,7 +38,7 @@ namespace Microsoft.Azure.WebJobs.Logging.ApplicationInsights
|
|||
{
|
||||
bool enabled = true;
|
||||
|
||||
if (item is ISupportProperties telemetry && _filter != null)
|
||||
if (item is ISupportProperties telemetry && _filterOptions != null)
|
||||
{
|
||||
if (!telemetry.Properties.TryGetValue(LogConstants.CategoryNameKey, out string categoryName))
|
||||
{
|
||||
|
@ -55,11 +60,28 @@ namespace Microsoft.Azure.WebJobs.Logging.ApplicationInsights
|
|||
if (telemetry.Properties.TryGetValue(LogConstants.LogLevelKey, out string logLevelString) &&
|
||||
Enum.TryParse(logLevelString, out LogLevel logLevel))
|
||||
{
|
||||
enabled = _filter(categoryName, logLevel);
|
||||
LoggerFilterRule filterRule = _ruleMap.GetOrAdd(categoryName, SelectRule(categoryName));
|
||||
|
||||
if (filterRule.LogLevel != null && logLevel < filterRule.LogLevel)
|
||||
{
|
||||
enabled = false;
|
||||
}
|
||||
else if (filterRule.Filter != null)
|
||||
{
|
||||
enabled = filterRule.Filter(ProviderType.FullName, categoryName, logLevel);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return enabled;
|
||||
}
|
||||
|
||||
private LoggerFilterRule SelectRule(string categoryName)
|
||||
{
|
||||
RuleSelector.Select(_filterOptions, ProviderType, categoryName,
|
||||
out LogLevel? minLevel, out Func<string, string, LogLevel, bool> filter);
|
||||
|
||||
return new LoggerFilterRule(ProviderType.FullName, categoryName, minLevel, filter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,90 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
|
||||
// This file is copied directly from:
|
||||
// https://github.com/aspnet/Logging/blob/cc350d7ef616ef292c1b4ae7130b8c2b45fc1164/src/Microsoft.Extensions.Logging/LoggerRuleSelector.cs.
|
||||
|
||||
using System;
|
||||
|
||||
namespace Microsoft.Extensions.Logging
|
||||
{
|
||||
internal class LoggerRuleSelector
|
||||
{
|
||||
public void Select(LoggerFilterOptions options, Type providerType, string category, out LogLevel? minLevel, out Func<string, string, LogLevel, bool> filter)
|
||||
{
|
||||
filter = null;
|
||||
minLevel = options.MinLevel;
|
||||
|
||||
// Filter rule selection:
|
||||
// 1. Select rules for current logger type, if there is none, select ones without logger type specified
|
||||
// 2. Select rules with longest matching categories
|
||||
// 3. If there nothing matched by category take all rules without category
|
||||
// 3. If there is only one rule use it's level and filter
|
||||
// 4. If there are multiple rules use last
|
||||
// 5. If there are no applicable rules use global minimal level
|
||||
|
||||
var providerAlias = ProviderAliasUtilities.GetAlias(providerType);
|
||||
LoggerFilterRule current = null;
|
||||
foreach (var rule in options.Rules)
|
||||
{
|
||||
if (IsBetter(rule, current, providerType.FullName, category)
|
||||
|| (!string.IsNullOrEmpty(providerAlias) && IsBetter(rule, current, providerAlias, category)))
|
||||
{
|
||||
current = rule;
|
||||
}
|
||||
}
|
||||
|
||||
if (current != null)
|
||||
{
|
||||
filter = current.Filter;
|
||||
minLevel = current.LogLevel;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static bool IsBetter(LoggerFilterRule rule, LoggerFilterRule current, string logger, string category)
|
||||
{
|
||||
// Skip rules with inapplicable type or category
|
||||
if (rule.ProviderName != null && rule.ProviderName != logger)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (rule.CategoryName != null && !category.StartsWith(rule.CategoryName, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (current?.ProviderName != null)
|
||||
{
|
||||
if (rule.ProviderName == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// We want to skip category check when going from no provider to having provider
|
||||
if (rule.ProviderName != null)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (current?.CategoryName != null)
|
||||
{
|
||||
if (rule.CategoryName == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (current.CategoryName.Length > rule.CategoryName.Length)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Microsoft.Extensions.Logging
|
||||
{
|
||||
internal static class ProviderAliasUtilities
|
||||
{
|
||||
internal static string GetAlias(Type providerType)
|
||||
{
|
||||
var attribute = providerType.GetCustomAttributes<ProviderAliasAttribute>(inherit: false).FirstOrDefault();
|
||||
return attribute?.Alias;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -26,12 +26,8 @@ namespace Microsoft.Azure.WebJobs.EventHubs.UnitTests
|
|||
public EventHubConfigurationTests()
|
||||
{
|
||||
_loggerFactory = new LoggerFactory();
|
||||
var filter = new LogCategoryFilter
|
||||
{
|
||||
DefaultLevel = LogLevel.Debug
|
||||
};
|
||||
|
||||
_loggerProvider = new TestLoggerProvider(filter.Filter);
|
||||
_loggerProvider = new TestLoggerProvider();
|
||||
_loggerFactory.AddProvider(_loggerProvider);
|
||||
}
|
||||
|
||||
|
|
|
@ -42,16 +42,8 @@ namespace Microsoft.Azure.WebJobs.Host.EndToEndTests
|
|||
|
||||
private const string _dateFormat = "HH':'mm':'ss'.'fffK";
|
||||
|
||||
private IHost ConfigureHost(LogCategoryFilter filter = null)
|
||||
private IHost ConfigureHost(LogLevel minLevel = LogLevel.Information)
|
||||
{
|
||||
if (filter == null)
|
||||
{
|
||||
filter = new LogCategoryFilter
|
||||
{
|
||||
DefaultLevel = LogLevel.Information
|
||||
};
|
||||
}
|
||||
|
||||
var host = new HostBuilder()
|
||||
.ConfigureDefaultTestHost<ApplicationInsightsEndToEndTests>()
|
||||
.ConfigureServices(services =>
|
||||
|
@ -61,7 +53,11 @@ namespace Microsoft.Azure.WebJobs.Host.EndToEndTests
|
|||
o.IsEnabled = false;
|
||||
});
|
||||
})
|
||||
.AddApplicationInsights(_mockApplicationInsightsKey, filter.Filter, null)
|
||||
.ConfigureLogging(b =>
|
||||
{
|
||||
b.SetMinimumLevel(minLevel);
|
||||
b.AddApplicationInsights(o => o.InstrumentationKey = _mockApplicationInsightsKey);
|
||||
})
|
||||
.ConfigureServices(services =>
|
||||
{
|
||||
var quickPulse = services.Single(s => s.ImplementationType == typeof(QuickPulseTelemetryModule));
|
||||
|
@ -192,13 +188,8 @@ namespace Microsoft.Azure.WebJobs.Host.EndToEndTests
|
|||
[InlineData(LogLevel.Warning, 2, 0)] // 2x warning trace per request
|
||||
public async Task QuickPulse_Works_EvenIfFiltered(LogLevel defaultLevel, int tracesPerRequest, int additionalTraces)
|
||||
{
|
||||
LogCategoryFilter filter = new LogCategoryFilter
|
||||
{
|
||||
DefaultLevel = defaultLevel
|
||||
};
|
||||
|
||||
using (var qpListener = new QuickPulseEventListener())
|
||||
using (IHost host = ConfigureHost(filter))
|
||||
using (IHost host = ConfigureHost(defaultLevel))
|
||||
{
|
||||
var listener = new ApplicationInsightsTestListener();
|
||||
int functionsCalled = 0;
|
||||
|
|
|
@ -94,7 +94,7 @@ namespace Microsoft.Azure.WebJobs.Host.EndToEndTests.ApplicationInsights
|
|||
{
|
||||
ValidateBlobDependency(
|
||||
inputDep,
|
||||
_inputContainerName,
|
||||
_inputContainerName,
|
||||
"in",
|
||||
nameof(BlobInputAndOutputBindings),
|
||||
request.Context.Operation.Id,
|
||||
|
@ -104,7 +104,7 @@ namespace Microsoft.Azure.WebJobs.Host.EndToEndTests.ApplicationInsights
|
|||
foreach (var outputDep in outDependencies)
|
||||
{
|
||||
ValidateBlobDependency(
|
||||
outputDep,
|
||||
outputDep,
|
||||
_outputContainerName,
|
||||
"out",
|
||||
nameof(BlobInputAndOutputBindings),
|
||||
|
@ -270,7 +270,7 @@ namespace Microsoft.Azure.WebJobs.Host.EndToEndTests.ApplicationInsights
|
|||
_functionWaitHandle.Set();
|
||||
}
|
||||
|
||||
|
||||
|
||||
[NoAutomaticTrigger]
|
||||
public static async Task UserCodeHttpCall()
|
||||
{
|
||||
|
@ -307,16 +307,16 @@ namespace Microsoft.Azure.WebJobs.Host.EndToEndTests.ApplicationInsights
|
|||
}
|
||||
|
||||
private void ValidateBlobDependency(
|
||||
DependencyTelemetry dependency,
|
||||
string containerName,
|
||||
string blobName,
|
||||
DependencyTelemetry dependency,
|
||||
string containerName,
|
||||
string blobName,
|
||||
string operationName,
|
||||
string operationId,
|
||||
string requestId)
|
||||
{
|
||||
Assert.Equal("Azure blob", dependency.Type);
|
||||
Assert.Equal(containerName, dependency.Properties["Container"]);
|
||||
|
||||
|
||||
// container creation does not have blob info
|
||||
if (dependency.Properties.ContainsKey("Blob"))
|
||||
{
|
||||
|
@ -361,7 +361,6 @@ namespace Microsoft.Azure.WebJobs.Host.EndToEndTests.ApplicationInsights
|
|||
|
||||
public IHost ConfigureHost(LogLevel logLevel)
|
||||
{
|
||||
var filter = new LogCategoryFilter { DefaultLevel = logLevel };
|
||||
_resolver = new RandomNameResolver();
|
||||
|
||||
IHost host = new HostBuilder()
|
||||
|
@ -377,7 +376,11 @@ namespace Microsoft.Azure.WebJobs.Host.EndToEndTests.ApplicationInsights
|
|||
o.IsEnabled = false;
|
||||
});
|
||||
})
|
||||
.AddApplicationInsights(_mockApplicationInsightsKey, filter.Filter, null)
|
||||
.ConfigureLogging(b =>
|
||||
{
|
||||
b.SetMinimumLevel(logLevel);
|
||||
b.AddApplicationInsights(o => o.InstrumentationKey = _mockApplicationInsightsKey);
|
||||
})
|
||||
.Build();
|
||||
|
||||
TelemetryConfiguration telemteryConfiguration = host.Services.GetService<TelemetryConfiguration>();
|
||||
|
|
|
@ -102,9 +102,7 @@ namespace Microsoft.Azure.WebJobs.Host.UnitTests.Singleton
|
|||
public SingletonManagerTests()
|
||||
{
|
||||
ILoggerFactory loggerFactory = new LoggerFactory();
|
||||
// We want to see all logs, so set the default level to Trace.
|
||||
LogCategoryFilter filter = new LogCategoryFilter { DefaultLevel = Microsoft.Extensions.Logging.LogLevel.Trace };
|
||||
_loggerProvider = new TestLoggerProvider(filter.Filter);
|
||||
_loggerProvider = new TestLoggerProvider();
|
||||
loggerFactory.AddProvider(_loggerProvider);
|
||||
|
||||
var logger = loggerFactory?.CreateLogger(LogCategories.Singleton);
|
||||
|
|
|
@ -10,17 +10,15 @@ namespace Microsoft.Azure.WebJobs.Host.TestCommon
|
|||
{
|
||||
public class TestLogger : ILogger
|
||||
{
|
||||
private readonly Func<string, LogLevel, bool> _filter;
|
||||
private readonly Action<LogMessage> _logAction;
|
||||
private IList<LogMessage> _logMessages = new List<LogMessage>();
|
||||
|
||||
// protect against changes to logMessages while enumerating
|
||||
private object _syncLock = new object();
|
||||
|
||||
public TestLogger(string category, Func<string, LogLevel, bool> filter = null, Action<LogMessage> logAction = null)
|
||||
public TestLogger(string category, Action<LogMessage> logAction = null)
|
||||
{
|
||||
Category = category;
|
||||
_filter = filter;
|
||||
_logAction = logAction;
|
||||
}
|
||||
|
||||
|
@ -33,7 +31,7 @@ namespace Microsoft.Azure.WebJobs.Host.TestCommon
|
|||
|
||||
public bool IsEnabled(LogLevel logLevel)
|
||||
{
|
||||
return _filter?.Invoke(Category, logLevel) ?? true;
|
||||
return true;
|
||||
}
|
||||
|
||||
public IList<LogMessage> GetLogMessages()
|
||||
|
|
|
@ -4,20 +4,19 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Microsoft.Azure.WebJobs.Logging;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace Microsoft.Azure.WebJobs.Host.TestCommon
|
||||
{
|
||||
public class TestLoggerProvider : ILoggerProvider
|
||||
{
|
||||
private readonly Func<string, LogLevel, bool> _filter;
|
||||
private readonly LoggerFilterOptions _filter;
|
||||
private readonly Action<LogMessage> _logAction;
|
||||
private Dictionary<string, TestLogger> _loggerCache { get; } = new Dictionary<string, TestLogger>();
|
||||
|
||||
public TestLoggerProvider(Func<string, LogLevel, bool> filter = null, Action<LogMessage> logAction = null)
|
||||
public TestLoggerProvider(Action<LogMessage> logAction = null)
|
||||
{
|
||||
_filter = filter ?? new LogCategoryFilter().Filter;
|
||||
_filter = new LoggerFilterOptions();
|
||||
_logAction = logAction;
|
||||
}
|
||||
|
||||
|
@ -27,7 +26,7 @@ namespace Microsoft.Azure.WebJobs.Host.TestCommon
|
|||
{
|
||||
if (!_loggerCache.TryGetValue(categoryName, out TestLogger logger))
|
||||
{
|
||||
logger = new TestLogger(categoryName, _filter, _logAction);
|
||||
logger = new TestLogger(categoryName, _logAction);
|
||||
_loggerCache.Add(categoryName, logger);
|
||||
}
|
||||
|
||||
|
|
|
@ -246,7 +246,7 @@ namespace Microsoft.Azure.WebJobs.Host.UnitTests.Listeners
|
|||
public async Task FunctionListener_DoesNotThrow_IfHandled()
|
||||
{
|
||||
ILoggerFactory handlingLoggerFactory = new LoggerFactory();
|
||||
TestLoggerProvider handlingLoggerProvider = new TestLoggerProvider(null, (m) => (m.Exception as RecoverableException).Handled = true);
|
||||
TestLoggerProvider handlingLoggerProvider = new TestLoggerProvider((m) => (m.Exception as RecoverableException).Handled = true);
|
||||
handlingLoggerFactory.AddProvider(handlingLoggerProvider);
|
||||
|
||||
Mock<IListener> badListener = new Mock<IListener>(MockBehavior.Strict);
|
||||
|
@ -272,7 +272,7 @@ namespace Microsoft.Azure.WebJobs.Host.UnitTests.Listeners
|
|||
public async Task FunctionListener_DoesNotStop_IfNotStarted()
|
||||
{
|
||||
ILoggerFactory handlingLoggerFactory = new LoggerFactory();
|
||||
TestLoggerProvider handlingLoggerProvider = new TestLoggerProvider(null, (m) => (m.Exception as RecoverableException).Handled = true);
|
||||
TestLoggerProvider handlingLoggerProvider = new TestLoggerProvider((m) => (m.Exception as RecoverableException).Handled = true);
|
||||
handlingLoggerFactory.AddProvider(handlingLoggerProvider);
|
||||
|
||||
Mock<IListener> badListener = new Mock<IListener>(MockBehavior.Strict);
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using Microsoft.ApplicationInsights;
|
||||
|
@ -15,9 +16,11 @@ using Microsoft.ApplicationInsights.WindowsServer;
|
|||
using Microsoft.ApplicationInsights.WindowsServer.Channel.Implementation;
|
||||
using Microsoft.ApplicationInsights.WindowsServer.TelemetryChannel;
|
||||
using Microsoft.Azure.WebJobs.Logging.ApplicationInsights;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.Azure.WebJobs.Host.UnitTests.Loggers
|
||||
|
@ -27,7 +30,13 @@ namespace Microsoft.Azure.WebJobs.Host.UnitTests.Loggers
|
|||
[Fact]
|
||||
public void DependencyInjectionConfiguration_Configures()
|
||||
{
|
||||
using (var host = new HostBuilder().AddApplicationInsights("some key", (c, l) => true, null).Build())
|
||||
var builder = new HostBuilder()
|
||||
.ConfigureLogging(b =>
|
||||
{
|
||||
b.AddApplicationInsights(o => o.InstrumentationKey = "some key");
|
||||
});
|
||||
|
||||
using (var host = builder.Build())
|
||||
{
|
||||
var config = host.Services.GetService<TelemetryConfiguration>();
|
||||
|
||||
|
@ -73,9 +82,16 @@ namespace Microsoft.Azure.WebJobs.Host.UnitTests.Loggers
|
|||
[Fact]
|
||||
public void DependencyInjectionConfiguration_ConfiguresSampling()
|
||||
{
|
||||
var samplingSettings = new SamplingPercentageEstimatorSettings {MaxTelemetryItemsPerSecond = 1};
|
||||
var samplingSettings = new SamplingPercentageEstimatorSettings { MaxTelemetryItemsPerSecond = 1 };
|
||||
using (var host = new HostBuilder()
|
||||
.AddApplicationInsights("some key", (c, l) => true, samplingSettings)
|
||||
.ConfigureLogging(b =>
|
||||
{
|
||||
b.AddApplicationInsights(o =>
|
||||
{
|
||||
o.InstrumentationKey = "some key";
|
||||
o.SamplingSettings = samplingSettings;
|
||||
});
|
||||
})
|
||||
.Build())
|
||||
{
|
||||
var config = host.Services.GetService<TelemetryConfiguration>();
|
||||
|
@ -84,7 +100,7 @@ namespace Microsoft.Azure.WebJobs.Host.UnitTests.Loggers
|
|||
Assert.IsType<FilteringTelemetryProcessor>(config.TelemetryProcessors[1]);
|
||||
Assert.IsType<AdaptiveSamplingTelemetryProcessor>(config.TelemetryProcessors[2]);
|
||||
|
||||
Assert.Equal(samplingSettings.MaxTelemetryItemsPerSecond, ((AdaptiveSamplingTelemetryProcessor) config.TelemetryProcessors[2]).MaxTelemetryItemsPerSecond);
|
||||
Assert.Equal(samplingSettings.MaxTelemetryItemsPerSecond, ((AdaptiveSamplingTelemetryProcessor)config.TelemetryProcessors[2]).MaxTelemetryItemsPerSecond);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -93,8 +109,14 @@ namespace Microsoft.Azure.WebJobs.Host.UnitTests.Loggers
|
|||
{
|
||||
var samplingSettings = new SamplingPercentageEstimatorSettings { MaxTelemetryItemsPerSecond = 1 };
|
||||
using (var host = new HostBuilder()
|
||||
.AddApplicationInsights("some key", samplingSettings)
|
||||
.Build())
|
||||
.ConfigureLogging(b =>
|
||||
{
|
||||
b.AddApplicationInsights(o =>
|
||||
{
|
||||
o.InstrumentationKey = "some key";
|
||||
o.SamplingSettings = samplingSettings;
|
||||
});
|
||||
}).Build())
|
||||
{
|
||||
var config = host.Services.GetService<TelemetryConfiguration>();
|
||||
Assert.Equal(4, config.TelemetryProcessors.Count);
|
||||
|
@ -111,8 +133,14 @@ namespace Microsoft.Azure.WebJobs.Host.UnitTests.Loggers
|
|||
{
|
||||
var snapshotConfiguration = new SnapshotCollectorConfiguration();
|
||||
using (var host = new HostBuilder()
|
||||
.AddApplicationInsights("some key", (c, l) => true, null, snapshotConfiguration)
|
||||
.Build())
|
||||
.ConfigureLogging(b =>
|
||||
{
|
||||
b.AddApplicationInsights(o =>
|
||||
{
|
||||
o.InstrumentationKey = "some key";
|
||||
o.SnapshotConfiguration = snapshotConfiguration;
|
||||
});
|
||||
}).Build())
|
||||
{
|
||||
var config = host.Services.GetService<TelemetryConfiguration>();
|
||||
Assert.Equal(4, config.TelemetryProcessors.Count);
|
||||
|
@ -126,8 +154,13 @@ namespace Microsoft.Azure.WebJobs.Host.UnitTests.Loggers
|
|||
public void DependencyInjectionConfiguration_ConfiguresActive()
|
||||
{
|
||||
using (var host = new HostBuilder()
|
||||
.AddApplicationInsights("some key", (c, l) => true, null)
|
||||
.Build())
|
||||
.ConfigureLogging(b =>
|
||||
{
|
||||
b.AddApplicationInsights(o =>
|
||||
{
|
||||
o.InstrumentationKey = "some key";
|
||||
});
|
||||
}).Build())
|
||||
{
|
||||
var config = TelemetryConfiguration.Active;
|
||||
// Verify Initializers
|
||||
|
@ -169,6 +202,167 @@ namespace Microsoft.Azure.WebJobs.Host.UnitTests.Loggers
|
|||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CreateFilterOptions_MinLevel()
|
||||
{
|
||||
using (var host = CreateHost((c, b) => b.SetMinimumLevel(LogLevel.None)))
|
||||
{
|
||||
var options = GetInternalLoggerFilterOptions(host.Services);
|
||||
var rule = SelectAppInsightsRule(options, "Any");
|
||||
Assert.Equal(LogLevel.None, rule.LogLevel);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CreateFilterOptions_CategoryFilter()
|
||||
{
|
||||
// Only return true if the category matches
|
||||
using (var host = CreateHost((c, b) => b.AddFilter("MyFakeCategory", LogLevel.Error)))
|
||||
{
|
||||
var options = GetInternalLoggerFilterOptions(host.Services);
|
||||
var rule = SelectAppInsightsRule(options, "MyFakeCategory");
|
||||
Assert.Equal(LogLevel.Error, rule.LogLevel);
|
||||
|
||||
// Make sure the default still applies to other categories
|
||||
rule = SelectAppInsightsRule(options, "AnotherCategory");
|
||||
Assert.Equal(LogLevel.Information, rule.LogLevel);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CreateFilterOptions_CustomFilter()
|
||||
{
|
||||
// Only return true if the category matches
|
||||
using (var host = CreateHost((c, b) => b.AddFilter((cat, l) => cat == "MyFakeCategory")))
|
||||
{
|
||||
var options = GetInternalLoggerFilterOptions(host.Services);
|
||||
var rule = SelectAppInsightsRule(options, null);
|
||||
Assert.Null(rule.LogLevel);
|
||||
Assert.False(rule.Filter(null, "SomeOtherCategory", LogLevel.Information));
|
||||
Assert.True(rule.Filter(null, "MyFakeCategory", LogLevel.Information));
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CreateFilterOptions_AppInsightsFilter()
|
||||
{
|
||||
// Make sure we allow custom filters for our logger
|
||||
using (var host = CreateHost((c, b) => b.AddFilter<ApplicationInsightsLoggerProvider>((cat, l) => cat == "MyFakeCategory")))
|
||||
{
|
||||
var options = GetInternalLoggerFilterOptions(host.Services);
|
||||
var rule = SelectAppInsightsRule(options, null);
|
||||
Assert.Null(rule.LogLevel);
|
||||
Assert.False(rule.Filter(null, "SomeOtherCategory", LogLevel.Information));
|
||||
Assert.True(rule.Filter(null, "MyFakeCategory", LogLevel.Information));
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CreateFilterOptions_AppInsightsMinLevel()
|
||||
{
|
||||
// Make sure we allow custom filters for our logger
|
||||
using (var host = CreateHost((c, b) => b.AddFilter<ApplicationInsightsLoggerProvider>("MyFakeCategory", LogLevel.Critical)))
|
||||
{
|
||||
var options = GetInternalLoggerFilterOptions(host.Services);
|
||||
var rule = SelectAppInsightsRule(options, "MyFakeCategory");
|
||||
Assert.Equal(LogLevel.Critical, rule.LogLevel);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CreateFilterOptions_AppInsightsMultipleCustomFilters()
|
||||
{
|
||||
using (var host = CreateHost((c, b) =>
|
||||
{
|
||||
// Last one should win
|
||||
b.AddFilter<ApplicationInsightsLoggerProvider>((cat, l) => cat == "1");
|
||||
b.AddFilter<ApplicationInsightsLoggerProvider>((cat, l) => cat == "2");
|
||||
b.AddFilter<ApplicationInsightsLoggerProvider>((cat, l) => cat == "3");
|
||||
}))
|
||||
{
|
||||
var options = GetInternalLoggerFilterOptions(host.Services);
|
||||
var rule = SelectAppInsightsRule(options, "MyFakeCategory");
|
||||
|
||||
Assert.Null(rule.LogLevel);
|
||||
Assert.False(rule.Filter(null, "1", LogLevel.Critical));
|
||||
Assert.False(rule.Filter(null, "2", LogLevel.Critical));
|
||||
Assert.True(rule.Filter(null, "3", LogLevel.Critical));
|
||||
}
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("Logging")]
|
||||
[InlineData("Multiple:Sections")]
|
||||
public void Filter_BindsToConfiguration(string configSection)
|
||||
{
|
||||
using (var host = CreateHost(
|
||||
configureLogging: (c, b) =>
|
||||
{
|
||||
// This is how logging config sections are registered by applications
|
||||
b.AddConfiguration(c.Configuration.GetSection(configSection));
|
||||
},
|
||||
configureConfiguration: b =>
|
||||
{
|
||||
b.AddInMemoryCollection(new Dictionary<string, string>
|
||||
{
|
||||
{ $"{configSection}:{ApplicationInsightsLoggerProvider.Alias}:LogLevel:Default", LogLevel.Warning.ToString() }
|
||||
});
|
||||
}))
|
||||
{
|
||||
var options = GetInternalLoggerFilterOptions(host.Services);
|
||||
var rule = SelectAppInsightsRule(options, "MyFakeCategory");
|
||||
Assert.Equal(LogLevel.Warning, rule.LogLevel);
|
||||
}
|
||||
}
|
||||
|
||||
private static IHost CreateHost(Action<HostBuilderContext, ILoggingBuilder> configureLogging = null, Action<IConfigurationBuilder> configureConfiguration = null)
|
||||
{
|
||||
var builder = new HostBuilder()
|
||||
.ConfigureWebJobs()
|
||||
.ConfigureLogging((c, b) =>
|
||||
{
|
||||
b.AddApplicationInsights(o =>
|
||||
{
|
||||
o.InstrumentationKey = "some key";
|
||||
});
|
||||
|
||||
configureLogging?.Invoke(c, b);
|
||||
});
|
||||
|
||||
if (configureConfiguration != null)
|
||||
{
|
||||
builder.ConfigureAppConfiguration(configureConfiguration);
|
||||
}
|
||||
|
||||
return builder.Build();
|
||||
}
|
||||
|
||||
private static LoggerFilterOptions GetInternalLoggerFilterOptions(IServiceProvider services)
|
||||
{
|
||||
var filterOptions = services.GetService<IOptions<LoggerFilterOptions>>().Value;
|
||||
|
||||
// The previous options will set the level to Trace
|
||||
var rule = SelectAppInsightsRule(filterOptions, "UnknownCategory");
|
||||
Assert.Equal(LogLevel.Trace, rule.LogLevel);
|
||||
|
||||
// These are the options to be used by the filtering processor
|
||||
var internalOptions = ApplicationInsightsServiceCollectionExtensions.CreateFilterOptions(filterOptions);
|
||||
Assert.NotSame(filterOptions, internalOptions);
|
||||
|
||||
return internalOptions;
|
||||
}
|
||||
|
||||
// Helper to pull out the calculated rule
|
||||
private static LoggerFilterRule SelectAppInsightsRule(LoggerFilterOptions options, string category)
|
||||
{
|
||||
var providerType = typeof(ApplicationInsightsLoggerProvider);
|
||||
|
||||
var ruleSelector = new LoggerRuleSelector();
|
||||
ruleSelector.Select(options, providerType, category, out LogLevel? minLevel, out Func<string, string, LogLevel, bool> filter);
|
||||
|
||||
return new LoggerFilterRule(providerType.FullName, category, minLevel, filter);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
TelemetryConfiguration.Active.Dispose();
|
||||
|
|
|
@ -55,8 +55,14 @@ namespace Microsoft.Azure.WebJobs.Host.UnitTests.Loggers
|
|||
};
|
||||
|
||||
_host = new HostBuilder()
|
||||
.AddApplicationInsights("some key", (c, l) => true, null)
|
||||
.Build();
|
||||
.ConfigureLogging(b =>
|
||||
{
|
||||
b.SetMinimumLevel(LogLevel.Trace);
|
||||
b.AddApplicationInsights(o =>
|
||||
{
|
||||
o.InstrumentationKey = "some key";
|
||||
});
|
||||
}).Build();
|
||||
|
||||
TelemetryConfiguration telemteryConfiguration = _host.Services.GetService<TelemetryConfiguration>();
|
||||
telemteryConfiguration.TelemetryChannel = _channel;
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.ApplicationInsights.Channel;
|
||||
|
@ -31,14 +32,13 @@ namespace Microsoft.Azure.WebJobs.Host.UnitTests.Loggers
|
|||
[InlineData(LogLevel.Trace, LogLevel.None, LogLevel.Information, false)]
|
||||
public void Processor_UsesFilter(LogLevel defaultLevel, LogLevel categoryLevel, LogLevel telemetryLevel, bool isEnabled)
|
||||
{
|
||||
var filter = new LogCategoryFilter
|
||||
var filter = new LoggerFilterOptions
|
||||
{
|
||||
DefaultLevel = defaultLevel
|
||||
MinLevel = defaultLevel
|
||||
};
|
||||
filter.AddFilter(LogCategories.Results, categoryLevel);
|
||||
|
||||
filter.CategoryLevels[LogCategories.Results] = categoryLevel;
|
||||
|
||||
var processor = new FilteringTelemetryProcessor(filter.Filter, _nextTelemetryProcessorMock.Object);
|
||||
var processor = new FilteringTelemetryProcessor(filter, _nextTelemetryProcessorMock.Object);
|
||||
|
||||
var telemetry = new TestTelemetry();
|
||||
telemetry.Properties[LogConstants.CategoryNameKey] = LogCategories.Results;
|
||||
|
@ -59,9 +59,9 @@ namespace Microsoft.Azure.WebJobs.Host.UnitTests.Loggers
|
|||
[Fact]
|
||||
public void Processor_No_ISupportProperties_DoesNotFilter()
|
||||
{
|
||||
var filter = new LogCategoryFilter();
|
||||
var filter = new LoggerFilterOptions();
|
||||
|
||||
var processor = new FilteringTelemetryProcessor(filter.Filter, _nextTelemetryProcessorMock.Object);
|
||||
var processor = new FilteringTelemetryProcessor(filter, _nextTelemetryProcessorMock.Object);
|
||||
|
||||
var telemetry = new Mock<ITelemetry>(MockBehavior.Strict);
|
||||
|
||||
|
@ -75,12 +75,12 @@ namespace Microsoft.Azure.WebJobs.Host.UnitTests.Loggers
|
|||
[InlineData(LogLevel.Error, true)]
|
||||
public void Processor_MissingCategory_FiltersAsDefault(LogLevel telemetryLevel, bool isEnabled)
|
||||
{
|
||||
var filter = new LogCategoryFilter
|
||||
var filter = new LoggerFilterOptions
|
||||
{
|
||||
DefaultLevel = LogLevel.Information
|
||||
MinLevel = LogLevel.Information
|
||||
};
|
||||
|
||||
var processor = new FilteringTelemetryProcessor(filter.Filter, _nextTelemetryProcessorMock.Object);
|
||||
var processor = new FilteringTelemetryProcessor(filter, _nextTelemetryProcessorMock.Object);
|
||||
|
||||
var telemetry = new TestTelemetry();
|
||||
telemetry.Properties[LogConstants.LogLevelKey] = telemetryLevel.ToString();
|
||||
|
@ -102,12 +102,12 @@ namespace Microsoft.Azure.WebJobs.Host.UnitTests.Loggers
|
|||
public void Processor_MissingLogLevel_DoesNotFilter()
|
||||
{
|
||||
// If no loglevel, we're not sure what to do, so just let it through
|
||||
var filter = new LogCategoryFilter
|
||||
var filter = new LoggerFilterOptions
|
||||
{
|
||||
DefaultLevel = LogLevel.Information
|
||||
MinLevel = LogLevel.Information
|
||||
};
|
||||
|
||||
var processor = new FilteringTelemetryProcessor(filter.Filter, _nextTelemetryProcessorMock.Object);
|
||||
var processor = new FilteringTelemetryProcessor(filter, _nextTelemetryProcessorMock.Object);
|
||||
|
||||
var telemetry = new TestTelemetry();
|
||||
telemetry.Properties[LogConstants.CategoryNameKey] = LogCategories.Results;
|
||||
|
@ -121,12 +121,12 @@ namespace Microsoft.Azure.WebJobs.Host.UnitTests.Loggers
|
|||
public void Processor_InvalidLogLevel_DoesNotFilter()
|
||||
{
|
||||
// If no valid loglevel, we're not sure what to do, so just let it through
|
||||
var filter = new LogCategoryFilter
|
||||
var filter = new LoggerFilterOptions
|
||||
{
|
||||
DefaultLevel = LogLevel.Information
|
||||
MinLevel = LogLevel.Information
|
||||
};
|
||||
|
||||
var processor = new FilteringTelemetryProcessor(filter.Filter, _nextTelemetryProcessorMock.Object);
|
||||
var processor = new FilteringTelemetryProcessor(filter, _nextTelemetryProcessorMock.Object);
|
||||
|
||||
var telemetry = new TestTelemetry();
|
||||
telemetry.Properties[LogConstants.CategoryNameKey] = LogCategories.Results;
|
||||
|
|
|
@ -1,34 +0,0 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
|
||||
using Microsoft.Azure.WebJobs.Logging;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.Azure.WebJobs.Host.UnitTests.Loggers
|
||||
{
|
||||
public class LogCategoryFilterTests
|
||||
{
|
||||
[Fact]
|
||||
public void Filter_MatchesLongestCategory()
|
||||
{
|
||||
var filter = new LogCategoryFilter();
|
||||
filter.DefaultLevel = LogLevel.Error;
|
||||
filter.CategoryLevels.Add("Microsoft", LogLevel.Critical);
|
||||
filter.CategoryLevels.Add("Microsoft.Azure", LogLevel.Error);
|
||||
filter.CategoryLevels.Add("Microsoft.Azure.WebJobs", LogLevel.Information);
|
||||
filter.CategoryLevels.Add("Microsoft.Azure.WebJobs.Host", LogLevel.Trace);
|
||||
|
||||
Assert.False(filter.Filter("Microsoft", LogLevel.Information));
|
||||
Assert.False(filter.Filter("Microsoft.Azure", LogLevel.Information));
|
||||
Assert.False(filter.Filter("Microsoft.Azure.WebJob", LogLevel.Information));
|
||||
Assert.False(filter.Filter("NoMatch", LogLevel.Information));
|
||||
|
||||
Assert.True(filter.Filter("Microsoft", LogLevel.Critical));
|
||||
Assert.True(filter.Filter("Microsoft.Azure", LogLevel.Critical));
|
||||
Assert.True(filter.Filter("Microsoft.Azure.WebJobs.Extensions", LogLevel.Information));
|
||||
Assert.True(filter.Filter("Microsoft.Azure.WebJobs.Host", LogLevel.Debug));
|
||||
Assert.True(filter.Filter("NoMatch", LogLevel.Error));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,10 +1,6 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using Microsoft.Azure.WebJobs.Host.TestCommon;
|
||||
using Microsoft.Azure.WebJobs.Logging;
|
||||
using Microsoft.Azure.WebJobs.Logging.ApplicationInsights;
|
||||
|
@ -18,7 +14,7 @@ namespace Microsoft.Azure.WebJobs.Host.UnitTests
|
|||
/// we review such additions carefully.
|
||||
/// </summary>
|
||||
public class PublicSurfaceTests
|
||||
{
|
||||
{
|
||||
[Fact]
|
||||
public void AssemblyReferences_InJobsHostAssembly()
|
||||
{
|
||||
|
@ -188,7 +184,6 @@ namespace Microsoft.Azure.WebJobs.Host.UnitTests
|
|||
"JobHostService",
|
||||
"ListenerFactoryContext",
|
||||
"LogCategories",
|
||||
"LogCategoryFilter",
|
||||
"LogConstants",
|
||||
"LoggerExtensions",
|
||||
"NameResolverExtensions",
|
||||
|
@ -227,11 +222,12 @@ namespace Microsoft.Azure.WebJobs.Host.UnitTests
|
|||
|
||||
var expected = new[]
|
||||
{
|
||||
"ApplicationInsightsLoggerOptions",
|
||||
"ApplicationInsightsLoggerProvider",
|
||||
"ApplicationInsightsHostBuilderExtensions"
|
||||
"ApplicationInsightsLoggingBuilderExtensions"
|
||||
};
|
||||
|
||||
TestHelpers.AssertPublicTypes(expected, assembly);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration" Version="2.1.0" />
|
||||
<PackageReference Include="StyleCop.Analyzers" Version="1.1.0-beta004">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
|
|
|
@ -20,9 +20,7 @@ namespace Microsoft.Azure.WebJobs.ServiceBus.UnitTests.Config
|
|||
public ServiceBusConfigurationTests()
|
||||
{
|
||||
_loggerFactory = new LoggerFactory();
|
||||
var filter = new LogCategoryFilter();
|
||||
filter.DefaultLevel = LogLevel.Debug;
|
||||
_loggerProvider = new TestLoggerProvider(filter.Filter);
|
||||
_loggerProvider = new TestLoggerProvider();
|
||||
_loggerFactory.AddProvider(_loggerProvider);
|
||||
}
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче