diff --git a/sample/SampleWebApp/SampleWebApp.csproj b/sample/SampleWebApp/SampleWebApp.csproj
index 1d6aebc..95007a8 100644
--- a/sample/SampleWebApp/SampleWebApp.csproj
+++ b/sample/SampleWebApp/SampleWebApp.csproj
@@ -8,9 +8,12 @@
-
+
+
+
+
diff --git a/sample/SampleWebApp/appsettings.json b/sample/SampleWebApp/appsettings.json
index c21e1ca..09b7466 100644
--- a/sample/SampleWebApp/appsettings.json
+++ b/sample/SampleWebApp/appsettings.json
@@ -31,7 +31,8 @@
{
"Name": "WithCorrelationId",
"Args": {
- "addValueIfHeaderAbsence": true
+ "addValueIfHeaderAbsence": true,
+ "addCorrelationIdToResponse": true
}
},
{
diff --git a/src/Serilog.Enrichers.ClientInfo/Enrichers/CorrelationIdEnricher.cs b/src/Serilog.Enrichers.ClientInfo/Enrichers/CorrelationIdEnricher.cs
index 9083eda..877f661 100644
--- a/src/Serilog.Enrichers.ClientInfo/Enrichers/CorrelationIdEnricher.cs
+++ b/src/Serilog.Enrichers.ClientInfo/Enrichers/CorrelationIdEnricher.cs
@@ -11,6 +11,7 @@ public class CorrelationIdEnricher : ILogEventEnricher
{
private const string CorrelationIdItemKey = "Serilog_CorrelationId";
private const string PropertyName = "CorrelationId";
+ private readonly bool _addCorrelationIdToResponse;
private readonly bool _addValueIfHeaderAbsence;
private readonly IHttpContextAccessor _contextAccessor;
private readonly string _headerKey;
@@ -24,15 +25,30 @@ public class CorrelationIdEnricher : ILogEventEnricher
///
/// Determines whether to add a new correlation ID value if the header is absent.
///
- public CorrelationIdEnricher(string headerKey, bool addValueIfHeaderAbsence)
- : this(headerKey, addValueIfHeaderAbsence, new HttpContextAccessor())
+ ///
+ /// Determines whether to add correlation ID value to header collection.
+ ///
+ public CorrelationIdEnricher(
+ string headerKey,
+ bool addValueIfHeaderAbsence,
+ bool addCorrelationIdToResponse)
+ : this(
+ headerKey,
+ addValueIfHeaderAbsence,
+ addCorrelationIdToResponse,
+ new HttpContextAccessor())
{
}
- internal CorrelationIdEnricher(string headerKey, bool addValueIfHeaderAbsence, IHttpContextAccessor contextAccessor)
+ internal CorrelationIdEnricher(
+ string headerKey,
+ bool addValueIfHeaderAbsence,
+ bool addCorrelationIdToResponse,
+ IHttpContextAccessor contextAccessor)
{
_headerKey = headerKey;
_addValueIfHeaderAbsence = addValueIfHeaderAbsence;
+ _addCorrelationIdToResponse = addCorrelationIdToResponse;
_contextAccessor = contextAccessor;
}
@@ -57,19 +73,9 @@ public void Enrich(LogEvent logEvent, ILogEventPropertyFactory propertyFactory)
return;
}
- StringValues requestHeader = httpContext.Request.Headers[_headerKey];
- StringValues responseHeader = httpContext.Response.Headers[_headerKey];
+ string correlationId = PrepareCorrelationId(httpContext);
- string correlationId;
-
- if (!string.IsNullOrWhiteSpace(requestHeader))
- correlationId = requestHeader;
- else if (!string.IsNullOrWhiteSpace(responseHeader))
- correlationId = responseHeader;
- else if (_addValueIfHeaderAbsence)
- correlationId = Guid.NewGuid().ToString();
- else
- correlationId = null;
+ AddCorrelationIdToResponse(httpContext, correlationId);
LogEventProperty correlationIdProperty = new(PropertyName, new ScalarValue(correlationId));
logEvent.AddOrUpdateProperty(correlationIdProperty);
@@ -77,4 +83,37 @@ public void Enrich(LogEvent logEvent, ILogEventPropertyFactory propertyFactory)
httpContext.Items.Add(CorrelationIdItemKey, correlationIdProperty);
httpContext.Items.Add(Constants.CorrelationIdValueKey, correlationId);
}
+
+ private void AddCorrelationIdToResponse(HttpContext httpContext, string correlationId)
+ {
+ if (_addCorrelationIdToResponse
+ && !httpContext.Response.Headers.ContainsKey(_headerKey))
+ {
+ httpContext.Response.Headers[_headerKey] = correlationId;
+ }
+ }
+
+ private string PrepareCorrelationId(HttpContext httpContext)
+ {
+ StringValues requestHeader = httpContext.Request.Headers[_headerKey];
+
+ if (!string.IsNullOrWhiteSpace(requestHeader))
+ {
+ return requestHeader;
+ }
+
+ StringValues responseHeader = httpContext.Response.Headers[_headerKey];
+
+ if (!string.IsNullOrWhiteSpace(responseHeader))
+ {
+ return responseHeader;
+ }
+
+ if (_addValueIfHeaderAbsence)
+ {
+ return Guid.NewGuid().ToString();
+ }
+
+ return null;
+ }
}
\ No newline at end of file
diff --git a/src/Serilog.Enrichers.ClientInfo/Extensions/ClientInfoLoggerConfigurationExtensions.cs b/src/Serilog.Enrichers.ClientInfo/Extensions/ClientInfoLoggerConfigurationExtensions.cs
index e943688..bbcf8d2 100644
--- a/src/Serilog.Enrichers.ClientInfo/Extensions/ClientInfoLoggerConfigurationExtensions.cs
+++ b/src/Serilog.Enrichers.ClientInfo/Extensions/ClientInfoLoggerConfigurationExtensions.cs
@@ -56,16 +56,20 @@ public static LoggerConfiguration WithClientIp(
/// Add generated correlation id value if correlation id header not available in
/// header collection.
///
+ ///
+ /// Add correlation id value to header collection.
+ ///
/// enrichmentConfiguration
/// The logger configuration so that multiple calls can be chained.
public static LoggerConfiguration WithCorrelationId(
this LoggerEnrichmentConfiguration enrichmentConfiguration,
string headerName = "x-correlation-id",
- bool addValueIfHeaderAbsence = false)
+ bool addValueIfHeaderAbsence = false,
+ bool addCorrelationIdToResponse = false)
{
ArgumentNullException.ThrowIfNull(enrichmentConfiguration, nameof(enrichmentConfiguration));
- return enrichmentConfiguration.With(new CorrelationIdEnricher(headerName, addValueIfHeaderAbsence));
+ return enrichmentConfiguration.With(new CorrelationIdEnricher(headerName, addValueIfHeaderAbsence, addCorrelationIdToResponse));
}
///
diff --git a/test/Serilog.Enrichers.ClientInfo.Tests/CorrelationIdEnricherTests.cs b/test/Serilog.Enrichers.ClientInfo.Tests/CorrelationIdEnricherTests.cs
index 77021e0..76b48c5 100644
--- a/test/Serilog.Enrichers.ClientInfo.Tests/CorrelationIdEnricherTests.cs
+++ b/test/Serilog.Enrichers.ClientInfo.Tests/CorrelationIdEnricherTests.cs
@@ -26,31 +26,7 @@ public void EnrichLogWithCorrelationId_WhenHttpRequestContainCorrelationHeader_S
// Arrange
string correlationId = Guid.NewGuid().ToString();
_contextAccessor.HttpContext!.Request!.Headers[HeaderKey] = correlationId;
- CorrelationIdEnricher correlationIdEnricher = new(HeaderKey, false, _contextAccessor);
-
- LogEvent evt = null;
- Logger log = new LoggerConfiguration()
- .Enrich.With(correlationIdEnricher)
- .WriteTo.Sink(new DelegatingSink(e => evt = e))
- .CreateLogger();
-
- // Act
- log.Information("Has a correlation id.");
-
- // Assert
- Assert.NotNull(evt);
- Assert.True(evt.Properties.ContainsKey(LogPropertyName));
- Assert.Equal(correlationId, evt.Properties[LogPropertyName].LiteralValue().ToString());
- }
-
- [Fact]
- public void
- EnrichLogWithCorrelationId_WhenHttpRequestContainCorrelationHeader_ShouldCreateCorrelationIdPropertyHasValue()
- {
- // Arrange
- string correlationId = Guid.NewGuid().ToString();
- _contextAccessor.HttpContext!.Request!.Headers[HeaderKey] = correlationId;
- CorrelationIdEnricher correlationIdEnricher = new(HeaderKey, false, _contextAccessor);
+ CorrelationIdEnricher correlationIdEnricher = new(HeaderKey, false, true, _contextAccessor);
LogEvent evt = null;
Logger log = new LoggerConfiguration()
@@ -65,6 +41,7 @@ public void
Assert.NotNull(evt);
Assert.True(evt.Properties.ContainsKey(LogPropertyName));
Assert.Equal(correlationId, evt.Properties[LogPropertyName].LiteralValue().ToString());
+ Assert.Equal(correlationId, _contextAccessor.HttpContext!.Response.Headers[HeaderKey]);
}
[Fact]
@@ -72,7 +49,7 @@ public void
EnrichLogWithCorrelationId_WhenHttpRequestNotContainCorrelationHeaderAndAddDefaultValueIsFalse_ShouldCreateCorrelationIdPropertyWithNoValue()
{
// Arrange
- CorrelationIdEnricher correlationIdEnricher = new(HeaderKey, false, _contextAccessor);
+ CorrelationIdEnricher correlationIdEnricher = new(HeaderKey, false, false, _contextAccessor);
LogEvent evt = null;
Logger log = new LoggerConfiguration()
@@ -87,6 +64,7 @@ public void
Assert.NotNull(evt);
Assert.True(evt.Properties.ContainsKey(LogPropertyName));
Assert.Null(evt.Properties[LogPropertyName].LiteralValue());
+ Assert.False(_contextAccessor.HttpContext!.Response.Headers.ContainsKey(HeaderKey));
}
[Fact]
@@ -94,7 +72,7 @@ public void
EnrichLogWithCorrelationId_WhenHttpRequestNotContainCorrelationHeaderAndAddDefaultValueIsTrue_ShouldCreateCorrelationIdPropertyHasValue()
{
// Arrange
- CorrelationIdEnricher correlationIdEnricher = new(HeaderKey, true, _contextAccessor);
+ CorrelationIdEnricher correlationIdEnricher = new(HeaderKey, true, true, _contextAccessor);
LogEvent evt = null;
Logger log = new LoggerConfiguration()
@@ -109,6 +87,8 @@ public void
Assert.NotNull(evt);
Assert.True(evt.Properties.ContainsKey(LogPropertyName));
Assert.NotNull(evt.Properties[LogPropertyName].LiteralValue().ToString());
+ Assert.NotNull(_contextAccessor.HttpContext!.Response.Headers[HeaderKey]);
+ Assert.Equal(evt.Properties[LogPropertyName].LiteralValue(), _contextAccessor.HttpContext!.Response.Headers[HeaderKey].ToString());
}
[Fact]
@@ -118,7 +98,7 @@ public void
// Arrange
string correlationId = Guid.NewGuid().ToString();
_contextAccessor.HttpContext!.Request!.Headers[HeaderKey] = correlationId;
- CorrelationIdEnricher correlationIdEnricher = new(HeaderKey, false, _contextAccessor);
+ CorrelationIdEnricher correlationIdEnricher = new(HeaderKey, false, true, _contextAccessor);
LogEvent evt = null;
Logger log = new LoggerConfiguration()
@@ -133,6 +113,7 @@ public void
Assert.NotNull(evt);
Assert.True(evt.Properties.ContainsKey(LogPropertyName));
Assert.Equal(correlationId, evt.Properties[LogPropertyName].LiteralValue().ToString());
+ Assert.Equal(correlationId, _contextAccessor.HttpContext!.Response.Headers[HeaderKey]);
}
[Fact]
@@ -144,7 +125,7 @@ public void
string responseCorrelationId = Guid.NewGuid().ToString();
_contextAccessor.HttpContext!.Request!.Headers[HeaderKey] = requestCorrelationId;
_contextAccessor.HttpContext!.Response!.Headers[HeaderKey] = responseCorrelationId;
- CorrelationIdEnricher correlationIdEnricher = new(HeaderKey, false, _contextAccessor);
+ CorrelationIdEnricher correlationIdEnricher = new(HeaderKey, false, true, _contextAccessor);
LogEvent evt = null;
Logger log = new LoggerConfiguration()
@@ -159,6 +140,7 @@ public void
Assert.NotNull(evt);
Assert.True(evt.Properties.ContainsKey(LogPropertyName));
Assert.Equal(requestCorrelationId, evt.Properties[LogPropertyName].LiteralValue().ToString());
+ Assert.Equal(responseCorrelationId, _contextAccessor.HttpContext!.Response.Headers[HeaderKey]);
}
[Fact]
@@ -167,7 +149,7 @@ public void GetCorrelationId_WhenHttpRequestContainCorrelationHeader_ShouldRetur
// Arrange
string correlationId = Guid.NewGuid().ToString();
_contextAccessor.HttpContext!.Request!.Headers[HeaderKey] = correlationId;
- CorrelationIdEnricher correlationIdEnricher = new(HeaderKey, false, _contextAccessor);
+ CorrelationIdEnricher correlationIdEnricher = new(HeaderKey, false, true, _contextAccessor);
LogEvent evt = null;
Logger log = new LoggerConfiguration()
@@ -182,6 +164,7 @@ public void GetCorrelationId_WhenHttpRequestContainCorrelationHeader_ShouldRetur
// Assert
Assert.NotNull(evt);
Assert.Equal(correlationId, retrievedCorrelationId);
+ Assert.Equal(correlationId, _contextAccessor.HttpContext!.Response.Headers[HeaderKey]);
}
[Fact]
@@ -189,7 +172,7 @@ public void
GetCorrelationId_WhenHttpRequestNotContainCorrelationHeaderAndAddDefaultValueIsTrue_ShouldReturnGeneratedCorrelationIdFromHttpContext()
{
// Arrange
- CorrelationIdEnricher correlationIdEnricher = new(HeaderKey, true, _contextAccessor);
+ CorrelationIdEnricher correlationIdEnricher = new(HeaderKey, true, true, _contextAccessor);
LogEvent evt = null;
Logger log = new LoggerConfiguration()
@@ -200,11 +183,13 @@ public void
// Act
log.Information("Has a correlation id.");
string retrievedCorrelationId = _contextAccessor.HttpContext!.GetCorrelationId();
+ string correlationIdFromResponse = _contextAccessor.HttpContext!.Response.Headers[HeaderKey];
// Assert
Assert.NotNull(evt);
Assert.NotNull(retrievedCorrelationId);
Assert.NotEmpty(retrievedCorrelationId);
+ Assert.Equal(retrievedCorrelationId, correlationIdFromResponse);
// Verify it's a valid GUID format
Assert.True(Guid.TryParse(retrievedCorrelationId, out _));
}
@@ -214,7 +199,7 @@ public void
GetCorrelationId_WhenHttpRequestNotContainCorrelationHeaderAndAddDefaultValueIsFalse_ShouldReturnNullFromHttpContext()
{
// Arrange
- CorrelationIdEnricher correlationIdEnricher = new(HeaderKey, false, _contextAccessor);
+ CorrelationIdEnricher correlationIdEnricher = new(HeaderKey, false, false, _contextAccessor);
LogEvent evt = null;
Logger log = new LoggerConfiguration()
@@ -229,6 +214,7 @@ public void
// Assert
Assert.NotNull(evt);
Assert.Null(retrievedCorrelationId);
+ Assert.False(_contextAccessor.HttpContext!.Response.Headers.ContainsKey(HeaderKey));
}
[Fact]
@@ -237,7 +223,7 @@ public void GetCorrelationId_WhenCalledMultipleTimes_ShouldReturnSameCorrelation
// Arrange
string correlationId = Guid.NewGuid().ToString();
_contextAccessor.HttpContext!.Request!.Headers[HeaderKey] = correlationId;
- CorrelationIdEnricher correlationIdEnricher = new(HeaderKey, false, _contextAccessor);
+ CorrelationIdEnricher correlationIdEnricher = new(HeaderKey, false, false, _contextAccessor);
Logger log = new LoggerConfiguration()
.Enrich.With(correlationIdEnricher)
@@ -255,6 +241,7 @@ public void GetCorrelationId_WhenCalledMultipleTimes_ShouldReturnSameCorrelation
Assert.Equal(correlationId, firstRetrieval);
Assert.Equal(correlationId, secondRetrieval);
Assert.Equal(firstRetrieval, secondRetrieval);
+ Assert.False(_contextAccessor.HttpContext!.Response.Headers.ContainsKey(HeaderKey));
}
[Fact]
@@ -273,7 +260,7 @@ public void EnrichLogWithCorrelationId_BackwardCompatibility_OldRetrievalMethodS
// Arrange
string correlationId = Guid.NewGuid().ToString();
_contextAccessor.HttpContext!.Request!.Headers[HeaderKey] = correlationId;
- CorrelationIdEnricher correlationIdEnricher = new(HeaderKey, false, _contextAccessor);
+ CorrelationIdEnricher correlationIdEnricher = new(HeaderKey, false, true, _contextAccessor);
LogEvent evt = null;
Logger log = new LoggerConfiguration()
@@ -300,6 +287,7 @@ public void EnrichLogWithCorrelationId_BackwardCompatibility_OldRetrievalMethodS
Assert.Equal(correlationId, retrievedCorrelationIdOldWay);
Assert.Equal(correlationId, retrievedCorrelationIdNewWay);
Assert.Equal(retrievedCorrelationIdOldWay, retrievedCorrelationIdNewWay);
+ Assert.Equal(correlationId, _contextAccessor.HttpContext!.Response.Headers[HeaderKey]);
}
[Fact]