diff --git a/src/Correlate.AspNetCore/AspNetCore/CorrelateOptions.cs b/src/Correlate.AspNetCore/AspNetCore/CorrelateOptions.cs
index 43336c3..3c09a48 100644
--- a/src/Correlate.AspNetCore/AspNetCore/CorrelateOptions.cs
+++ b/src/Correlate.AspNetCore/AspNetCore/CorrelateOptions.cs
@@ -5,7 +5,7 @@ namespace Correlate.AspNetCore;
///
/// Options for handling correlation id on incoming requests.
///
-public sealed class CorrelateOptions
+public sealed class CorrelateOptions: CorrelationManagerOptions
{
private static readonly string[] DefaultRequestHeaders = { CorrelationHttpHeaders.CorrelationId };
diff --git a/src/Correlate.AspNetCore/DependencyInjection/ServiceCollectionExtensions.cs b/src/Correlate.AspNetCore/DependencyInjection/ServiceCollectionExtensions.cs
index ebf374f..08c69bf 100644
--- a/src/Correlate.AspNetCore/DependencyInjection/ServiceCollectionExtensions.cs
+++ b/src/Correlate.AspNetCore/DependencyInjection/ServiceCollectionExtensions.cs
@@ -1,5 +1,6 @@
using Correlate.AspNetCore;
using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Options;
namespace Correlate.DependencyInjection;
@@ -16,8 +17,18 @@ public static class ServiceCollectionExtensions
/// The so that additional calls can be chained.
public static IServiceCollection AddCorrelate(this IServiceCollection services, Action configureOptions)
{
- return services
- .Configure(configureOptions)
+ services
+ .Configure(configureOptions);
+
+ services.AddOptions()
+ .Configure((CorrelationManagerOptions cmo, IOptions co) =>
+ {
+ cmo.LoggingScopeKey = co.Value.LoggingScopeKey;
+ });
+
+ services
.AddCorrelate();
+
+ return services;
}
}
diff --git a/src/Correlate.Core/CorrelationManager.cs b/src/Correlate.Core/CorrelationManager.cs
index 8dfa3f8..6bffe69 100644
--- a/src/Correlate.Core/CorrelationManager.cs
+++ b/src/Correlate.Core/CorrelationManager.cs
@@ -1,5 +1,6 @@
using System.Diagnostics;
using Microsoft.Extensions.Logging;
+using Microsoft.Extensions.Options;
namespace Correlate;
@@ -13,6 +14,7 @@ public class CorrelationManager : IAsyncCorrelationManager, ICorrelationManager,
private readonly ICorrelationIdFactory _correlationIdFactory;
private readonly DiagnosticListener? _diagnosticListener;
private readonly ILogger _logger;
+ private readonly CorrelationManagerOptions _options = new CorrelationManagerOptions();
///
/// Initializes a new instance of the class.
@@ -55,13 +57,35 @@ DiagnosticListener diagnosticListener
_diagnosticListener = diagnosticListener ?? throw new ArgumentNullException(nameof(diagnosticListener));
}
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The correlation context factory used to create new contexts.
+ /// The correlation id factory used to generate a new correlation id per context.
+ /// The correlation context accessor.
+ /// The logger.
+ /// The diagnostics listener to run activities on.
+ /// The configuration options.
+ public CorrelationManager
+ (
+ ICorrelationContextFactory correlationContextFactory,
+ ICorrelationIdFactory correlationIdFactory,
+ ICorrelationContextAccessor correlationContextAccessor,
+ ILogger logger,
+ DiagnosticListener diagnosticListener,
+ IOptions options
+ ) : this(correlationContextFactory, correlationIdFactory, correlationContextAccessor, logger, diagnosticListener)
+ {
+ _options = options?.Value ?? throw new ArgumentNullException(nameof(options));
+ }
+
///
/// Creates a new activity that can be started and stopped manually.
///
/// The correlated activity.
public IActivity CreateActivity()
{
- return new RootActivity(_correlationContextFactory, _logger, _diagnosticListener);
+ return new RootActivity(_correlationContextFactory, _logger, _diagnosticListener, _options);
}
///
diff --git a/src/Correlate.Core/CorrelationManagerOptions.cs b/src/Correlate.Core/CorrelationManagerOptions.cs
new file mode 100644
index 0000000..eefea83
--- /dev/null
+++ b/src/Correlate.Core/CorrelationManagerOptions.cs
@@ -0,0 +1,12 @@
+namespace Correlate;
+
+///
+/// The options class for configuring .
+///
+public class CorrelationManagerOptions
+{
+ ///
+ /// The scope key that will be used for adding correlation ID to log context. Default is CorrelationId.
+ ///
+ public string LoggingScopeKey { get; set; } = CorrelateConstants.CorrelationIdKey;
+}
\ No newline at end of file
diff --git a/src/Correlate.Core/Extensions/LoggerExtensions.cs b/src/Correlate.Core/Extensions/LoggerExtensions.cs
index e11631b..66e2443 100644
--- a/src/Correlate.Core/Extensions/LoggerExtensions.cs
+++ b/src/Correlate.Core/Extensions/LoggerExtensions.cs
@@ -5,17 +5,19 @@ namespace Correlate.Extensions;
internal static class LoggerExtensions
{
- public static IDisposable? BeginCorrelatedScope(this ILogger logger, string correlationId)
+ public static IDisposable? BeginCorrelatedScope(this ILogger logger, string scopeKey, string correlationId)
{
- return logger.BeginScope(new CorrelatedLogScope(correlationId));
+ return logger.BeginScope(new CorrelatedLogScope(scopeKey, correlationId));
}
private sealed class CorrelatedLogScope : IReadOnlyList>
{
+ private readonly string _scopeKey;
private readonly string _correlationId;
- public CorrelatedLogScope(string correlationId)
+ public CorrelatedLogScope(string scopeKey, string correlationId)
{
+ _scopeKey = scopeKey;
_correlationId = correlationId;
}
@@ -41,7 +43,7 @@ public KeyValuePair this[int index]
{
if (index == 0)
{
- return new KeyValuePair(CorrelateConstants.CorrelationIdKey, _correlationId);
+ return new KeyValuePair(_scopeKey, _correlationId);
}
throw new ArgumentOutOfRangeException(nameof(index));
diff --git a/src/Correlate.Core/RootActivity.cs b/src/Correlate.Core/RootActivity.cs
index 6eb4d0a..f53f41b 100644
--- a/src/Correlate.Core/RootActivity.cs
+++ b/src/Correlate.Core/RootActivity.cs
@@ -8,6 +8,7 @@ internal class RootActivity : IActivity
{
private readonly ICorrelationContextFactory _correlationContextFactory;
private readonly DiagnosticListener? _diagnosticListener;
+ private readonly CorrelationManagerOptions _options;
private readonly ILogger _logger;
private IDisposable? _logScope;
@@ -15,11 +16,13 @@ public RootActivity
(
ICorrelationContextFactory correlationContextFactory,
ILogger logger,
- DiagnosticListener? diagnosticListener)
+ DiagnosticListener? diagnosticListener,
+ CorrelationManagerOptions options)
{
_correlationContextFactory = correlationContextFactory ?? throw new ArgumentNullException(nameof(correlationContextFactory));
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
_diagnosticListener = diagnosticListener;
+ _options = options;
}
///
@@ -49,7 +52,7 @@ public CorrelationContext Start(string correlationId)
if (isLoggingEnabled)
{
- _logScope = _logger.BeginCorrelatedScope(correlationId);
+ _logScope = _logger.BeginCorrelatedScope(_options.LoggingScopeKey, correlationId);
}
return context;
diff --git a/src/Correlate.DependencyInjection/IServiceCollectionExtensions.cs b/src/Correlate.DependencyInjection/IServiceCollectionExtensions.cs
index a5afdbe..b1dc648 100644
--- a/src/Correlate.DependencyInjection/IServiceCollectionExtensions.cs
+++ b/src/Correlate.DependencyInjection/IServiceCollectionExtensions.cs
@@ -9,6 +9,23 @@ namespace Correlate.DependencyInjection;
// ReSharper disable once InconsistentNaming
public static class IServiceCollectionExtensions
{
+ ///
+ /// Adds services required for using correlation.
+ ///
+ /// The to add the services to.
+ /// The callback to customize defaults.
+ /// The so that additional calls can be chained.
+ public static IServiceCollection AddCorrelate(this IServiceCollection services, Action configure)
+ {
+ services
+ .AddOptions()
+ .Configure(configure);
+
+ services.AddCorrelate();
+
+ return services;
+ }
+
///
/// Adds services required for using correlation.
///
diff --git a/test/Correlate.AspNetCore.Tests/AspNetCore/CorrelateFeatureTests.cs b/test/Correlate.AspNetCore.Tests/AspNetCore/CorrelateFeatureTests.cs
index eaa15a9..7b72de7 100644
--- a/test/Correlate.AspNetCore.Tests/AspNetCore/CorrelateFeatureTests.cs
+++ b/test/Correlate.AspNetCore.Tests/AspNetCore/CorrelateFeatureTests.cs
@@ -231,6 +231,7 @@ public async Task When_correlating_has_started_it_should_create_logScope_with_co
.ContainSingle(le => le.MessageTemplate.Text.StartsWith("Setting response header"))
.Which.Properties
.Should()
+ // this tests the {CorrelationId} from log message template in CorrelateFeature.LogRequestHeaderFound, not the one from log scope added by IActivityFactory.CreateActivity
.ContainSingle(p => p.Key == expectedLogProperty)
.Which.Value
.Should()
diff --git a/test/Correlate.Core.Tests/CorrelationManagerTests.cs b/test/Correlate.Core.Tests/CorrelationManagerTests.cs
index 436a48d..422d007 100644
--- a/test/Correlate.Core.Tests/CorrelationManagerTests.cs
+++ b/test/Correlate.Core.Tests/CorrelationManagerTests.cs
@@ -1,7 +1,9 @@
using System.Collections;
+using System.Diagnostics;
using Correlate.Testing;
using Correlate.Testing.TestCases;
using Microsoft.Extensions.Logging;
+using Microsoft.Extensions.Options;
using Serilog;
using Serilog.Core;
using Serilog.Extensions.Logging;
@@ -15,10 +17,12 @@ public class CorrelationManagerTests : IDisposable
private readonly CorrelationContextAccessor _correlationContextAccessor;
private readonly ICorrelationIdFactory _correlationIdFactoryMock;
private readonly ILogger _logger;
+ private readonly DiagnosticListener _diagnosticListener;
+ private readonly IOptions _options;
private readonly SerilogLoggerProvider _logProvider;
private readonly CorrelationManager _sut;
- protected CorrelationManagerTests()
+ protected CorrelationManagerTests(CorrelationManagerOptions options)
{
_correlationContextAccessor = new CorrelationContextAccessor();
@@ -33,12 +37,16 @@ protected CorrelationManagerTests()
_logProvider = new SerilogLoggerProvider(serilogLogger);
_logger = new TestLogger(_logProvider.CreateLogger(nameof(CorrelationManager)));
+ _diagnosticListener = new DiagnosticListener("test");
+ _options = Options.Create(options);
_sut = new CorrelationManager(
new CorrelationContextFactory(_correlationContextAccessor),
_correlationIdFactoryMock,
_correlationContextAccessor,
- _logger
+ _logger,
+ _diagnosticListener,
+ _options
);
}
@@ -50,6 +58,13 @@ public void Dispose()
public class Async : CorrelationManagerTests
{
+ public Async() : base(new()
+ {
+ LoggingScopeKey = "ActivityId"
+ })
+ {
+ }
+
[Fact]
public async Task Given_a_task_should_run_task_inside_correlated_context()
{
@@ -143,7 +158,7 @@ await _sut.CorrelateAsync(() =>
var logEvents = TestCorrelator.GetLogEventsFromCurrentContext().ToList();
logEvents.Should()
.HaveCount(3)
- .And.ContainSingle(ev => ev.MessageTemplate.Text == "Message with correlation id." && ev.Properties.ContainsKey("CorrelationId"));
+ .And.ContainSingle(ev => ev.MessageTemplate.Text == "Message with correlation id." && ev.Properties.ContainsKey("ActivityId"));
}
}
@@ -361,6 +376,10 @@ await _sut.CorrelateAsync(innerContextId,
public class Sync : CorrelationManagerTests
{
+ public Sync() : base(new())
+ {
+ }
+
[Fact]
public void Given_a_action_should_run_action_inside_correlated_context()
{
@@ -674,7 +693,9 @@ public static IEnumerable