Skip to content
This repository was archived by the owner on Dec 13, 2018. It is now read-only.

Commit e94b64f

Browse files
authored
Add scopes to azure loggers (#928)
1 parent ae50265 commit e94b64f

File tree

8 files changed

+117
-8
lines changed

8 files changed

+117
-8
lines changed

src/Microsoft.Extensions.Logging.AzureAppServices/AzureAppServicesLoggerFactoryExtensions.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
using Microsoft.Extensions.DependencyInjection.Extensions;
77
using Microsoft.Extensions.Logging.AzureAppServices;
88
using Microsoft.Extensions.Logging.AzureAppServices.Internal;
9+
using Microsoft.Extensions.Logging.Configuration;
910
using Microsoft.Extensions.Options;
1011
using static Microsoft.Extensions.DependencyInjection.ServiceDescriptor;
1112

@@ -54,6 +55,7 @@ internal static ILoggingBuilder AddAzureWebAppDiagnostics(this ILoggingBuilder b
5455
services.AddSingleton<IConfigureOptions<AzureFileLoggerOptions>>(new FileLoggerConfigureOptions(config, context));
5556
services.AddSingleton<IOptionsChangeTokenSource<AzureFileLoggerOptions>>(
5657
new ConfigurationChangeTokenSource<AzureFileLoggerOptions>(config));
58+
LoggerProviderOptions.RegisterProviderOptions<AzureFileLoggerOptions, FileLoggerProvider>(builder.Services);
5759
}
5860

5961
if (addedBlobLogger)
@@ -62,6 +64,7 @@ internal static ILoggingBuilder AddAzureWebAppDiagnostics(this ILoggingBuilder b
6264
services.AddSingleton<IConfigureOptions<AzureBlobLoggerOptions>>(new BlobLoggerConfigureOptions(config, context));
6365
services.AddSingleton<IOptionsChangeTokenSource<AzureBlobLoggerOptions>>(
6466
new ConfigurationChangeTokenSource<AzureBlobLoggerOptions>(config));
67+
LoggerProviderOptions.RegisterProviderOptions<AzureBlobLoggerOptions, BlobLoggerProvider>(builder.Services);
6568
}
6669

6770
return builder;

src/Microsoft.Extensions.Logging.AzureAppServices/Internal/BatchingLogger.cs

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,22 @@ public void Log<TState>(DateTimeOffset timestamp, LogLevel logLevel, EventId eve
4040
builder.Append(logLevel.ToString());
4141
builder.Append("] ");
4242
builder.Append(_category);
43-
builder.Append(": ");
43+
44+
var scopeProvider = _provider.ScopeProvider;
45+
if (scopeProvider != null)
46+
{
47+
scopeProvider.ForEachScope((scope, stringBuilder) =>
48+
{
49+
stringBuilder.Append(" => ").Append(scope);
50+
}, builder);
51+
52+
builder.AppendLine(":");
53+
}
54+
else
55+
{
56+
builder.Append(": ");
57+
}
58+
4459
builder.AppendLine(formatter(state, exception));
4560

4661
if (exception != null)

src/Microsoft.Extensions.Logging.AzureAppServices/Internal/BatchingLoggerOptions.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,5 +66,11 @@ public int? BatchSize
6666
/// Gets or sets value indicating if logger accepts and queues writes.
6767
/// </summary>
6868
public bool IsEnabled { get; set; }
69+
70+
/// <summary>
71+
/// Gets or sets a value indicating whether scopes should be included in the message.
72+
/// Defaults to <c>false</c>.
73+
/// </summary>
74+
public bool IncludeScopes { get; set; } = false;
6975
}
7076
}

src/Microsoft.Extensions.Logging.AzureAppServices/Internal/BatchingLoggerProvider.cs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111
namespace Microsoft.Extensions.Logging.AzureAppServices.Internal
1212
{
13-
public abstract class BatchingLoggerProvider: ILoggerProvider
13+
public abstract class BatchingLoggerProvider: ILoggerProvider, ISupportExternalScope
1414
{
1515
private readonly List<LogMessage> _currentBatch = new List<LogMessage>();
1616
private readonly TimeSpan _interval;
@@ -22,6 +22,11 @@ public abstract class BatchingLoggerProvider: ILoggerProvider
2222
private Task _outputTask;
2323
private CancellationTokenSource _cancellationTokenSource;
2424

25+
private bool _includeScopes;
26+
private IExternalScopeProvider _scopeProvider;
27+
28+
internal IExternalScopeProvider ScopeProvider => _includeScopes ? _scopeProvider : null;
29+
2530
protected BatchingLoggerProvider(IOptionsMonitor<BatchingLoggerOptions> options)
2631
{
2732
// NOTE: Only IsEnabled is monitored
@@ -50,6 +55,8 @@ private void UpdateOptions(BatchingLoggerOptions options)
5055
{
5156
var oldIsEnabled = IsEnabled;
5257
IsEnabled = options.IsEnabled;
58+
_includeScopes = options.IncludeScopes;
59+
5360
if (oldIsEnabled != IsEnabled)
5461
{
5562
if (IsEnabled)
@@ -159,5 +166,10 @@ public ILogger CreateLogger(string categoryName)
159166
{
160167
return new BatchingLogger(this, categoryName);
161168
}
169+
170+
void ISupportExternalScope.SetScopeProvider(IExternalScopeProvider scopeProvider)
171+
{
172+
_scopeProvider = scopeProvider;
173+
}
162174
}
163175
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3+
4+
using Microsoft.Extensions.DependencyInjection;
5+
using Microsoft.Extensions.DependencyInjection.Extensions;
6+
using Microsoft.Extensions.Options;
7+
8+
namespace Microsoft.Extensions.Logging.Configuration
9+
{
10+
/// <summary>
11+
/// Provides a set of helpers to initialize options objects from logger provider configuration.
12+
/// </summary>
13+
public static class LoggerProviderOptions
14+
{
15+
/// <summary>
16+
/// Indicates that settings for <typeparamref name="TProvider"/> should be loaded into <typeparamref name="TOptions"/> type.
17+
/// </summary>
18+
/// <typeparam name="TOptions">The options class </typeparam>
19+
/// <typeparam name="TProvider">The provider class</typeparam>
20+
public static void RegisterProviderOptions<TOptions, TProvider>(IServiceCollection services) where TOptions : class
21+
{
22+
services.TryAddEnumerable(ServiceDescriptor.Singleton<IConfigureOptions<TOptions>, LoggerProviderConfigureOptions<TOptions, TProvider>>());
23+
services.TryAddEnumerable(ServiceDescriptor.Singleton<IOptionsChangeTokenSource<TOptions>, LoggerProviderOptionsChangeTokenSource<TOptions, TProvider>>());
24+
}
25+
}
26+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3+
4+
using Microsoft.Extensions.Options;
5+
6+
namespace Microsoft.Extensions.Logging.Configuration
7+
{
8+
/// <summary>
9+
/// Loads settings for <typeparamref name="TProvider"/> into <typeparamref name="TOptions"/> type.
10+
/// </summary>
11+
internal class LoggerProviderConfigureOptions<TOptions, TProvider> : ConfigureFromConfigurationOptions<TOptions> where TOptions : class
12+
{
13+
public LoggerProviderConfigureOptions(ILoggerProviderConfiguration<TProvider> providerConfiguration)
14+
: base(providerConfiguration.Configuration)
15+
{
16+
}
17+
}
18+
}

src/Microsoft.Extensions.Logging.Console/ConsoleLoggerFactoryExtensions.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,7 @@ public static ILoggingBuilder AddConsole(this ILoggingBuilder builder)
2222
builder.AddConfiguration();
2323

2424
builder.Services.TryAddEnumerable(ServiceDescriptor.Singleton<ILoggerProvider, ConsoleLoggerProvider>());
25-
builder.Services.TryAddEnumerable(ServiceDescriptor.Singleton<IConfigureOptions<ConsoleLoggerOptions>, ConsoleLoggerOptionsSetup>());
26-
builder.Services.TryAddEnumerable(ServiceDescriptor.Singleton<IOptionsChangeTokenSource<ConsoleLoggerOptions>, LoggerProviderOptionsChangeTokenSource<ConsoleLoggerOptions, ConsoleLoggerProvider>>());
25+
LoggerProviderOptions.RegisterProviderOptions<ConsoleLoggerOptions, ConsoleLoggerProvider>(builder.Services);
2726
return builder;
2827
}
2928

test/Microsoft.Extensions.Logging.AzureAppServices.Test/BatchingLoggerProviderTests.cs

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
using System;
55
using System.Collections.Generic;
66
using System.Linq;
7+
using System.Text.RegularExpressions;
78
using System.Threading;
89
using System.Threading.Tasks;
910
using Microsoft.Extensions.Logging.AzureAppServices.Internal;
@@ -13,8 +14,9 @@ namespace Microsoft.Extensions.Logging.AzureAppServices.Test
1314
{
1415
public class BatchingLoggerProviderTests
1516
{
16-
DateTimeOffset _timestampOne = new DateTimeOffset(2016, 05, 04, 03, 02, 01, TimeSpan.Zero);
17-
string _nl = Environment.NewLine;
17+
private DateTimeOffset _timestampOne = new DateTimeOffset(2016, 05, 04, 03, 02, 01, TimeSpan.Zero);
18+
private string _nl = Environment.NewLine;
19+
private Regex _timeStampRegex = new Regex(@"^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}.\d{3} .\d{2}:\d{2} ");
1820

1921
[Fact]
2022
public async Task LogsInIntervals()
@@ -34,6 +36,33 @@ public async Task LogsInIntervals()
3436
Assert.Equal("2016-05-04 04:02:01.000 +00:00 [Error] Cat: Error message" + _nl, provider.Batches[0][1].Message);
3537
}
3638

39+
[Fact]
40+
public async Task IncludesScopes()
41+
{
42+
var provider = new TestBatchingLoggingProvider(includeScopes: true);
43+
var factory = new LoggerFactory(new [] { provider });
44+
var logger = factory.CreateLogger("Cat");
45+
46+
await provider.IntervalControl.Pause;
47+
48+
using (logger.BeginScope("Scope"))
49+
{
50+
using (logger.BeginScope("Scope2"))
51+
{
52+
logger.Log(LogLevel.Information, 0, "Info message", null, (state, ex) => state);
53+
}
54+
}
55+
56+
provider.IntervalControl.Resume();
57+
await provider.IntervalControl.Pause;
58+
59+
Assert.Matches(_timeStampRegex, provider.Batches[0][0].Message);
60+
Assert.EndsWith(
61+
" [Information] Cat => Scope => Scope2:" + _nl +
62+
"Info message" + _nl,
63+
provider.Batches[0][0].Message);
64+
}
65+
3766
[Fact]
3867
public async Task RespectsBatchSize()
3968
{
@@ -85,13 +114,14 @@ private class TestBatchingLoggingProvider: BatchingLoggerProvider
85114
public List<LogMessage[]> Batches { get; } = new List<LogMessage[]>();
86115
public ManualIntervalControl IntervalControl { get; } = new ManualIntervalControl();
87116

88-
public TestBatchingLoggingProvider(TimeSpan? interval = null, int? maxBatchSize = null, int? maxQueueSize = null)
117+
public TestBatchingLoggingProvider(TimeSpan? interval = null, int? maxBatchSize = null, int? maxQueueSize = null, bool includeScopes = false)
89118
: base(new OptionsWrapperMonitor<BatchingLoggerOptions>(new BatchingLoggerOptions
90119
{
91120
FlushPeriod = interval ?? TimeSpan.FromSeconds(1),
92121
BatchSize = maxBatchSize,
93122
BackgroundQueueSize = maxQueueSize,
94-
IsEnabled = true
123+
IsEnabled = true,
124+
IncludeScopes = includeScopes
95125
}))
96126
{
97127
}

0 commit comments

Comments
 (0)