ecs-dotnet
ecs-dotnet copied to clipboard
[BUG] HttpContext.User is not used in Serilog EcsTextFormatter
ECS integration/library project(s): Elastic.CommonSchema.Serilog 8.6.1, Serilog 3.1.1
ECS .NET assembly version (e.g. 1.4.2): 8.6.1
.NET framework / OS: .NET 6 / Windows 11
Description of the problem, including expected versus actual behavior:
Steps to reproduce:
- Use ASP.NET Core with authentication and ClaimsIdentity (e.g. a user is logged in)
- The user claims are not included in the ecs output
Cause:
The logEvent.AddPropertyIfAbsent(propertyFactory.CreateProperty(PropertyName, r));
in the HttpContextEnricher
doesn't store the raw object, instead the default propertyFactory
does a .ToString()
of the r
-value, which makes the value of the property: Elastic.CommonSchema.Serilog.HttpContextEnricher,Elastic.CommonSchema.Serilog
instead or the original object. In the LogEventConverter
, the object cannot be retrieved in (for example) the GetUser
method
if (e.TryGetScalarPropertyValue(SpecialKeys.HttpContext, out var httpContext)
&& httpContext.Value is HttpContextEnricher.HttpContextEnrichments enriched) // httpContext.Value is a string!!
return enriched.User; // <-- never returned
This causes that the reported user is always the environment user instead of the user doing the request.
A workaround is to override the enricher:
using Elastic.CommonSchema.Serilog;
using Serilog.Core;
using Serilog.Events;
public class PatchedHttpContextEnricher : HttpContextEnricher, ILogEventEnricher
{
private readonly RawPropertyFactory _rawPropertyFactory;
public PatchedHttpContextEnricher(IHttpContextAccessor httpContextAccessor) : base(httpContextAccessor)
{
_rawPropertyFactory = new RawPropertyFactory();
}
void ILogEventEnricher.Enrich(LogEvent logEvent, ILogEventPropertyFactory propertyFactory)
{
base.Enrich(logEvent, _rawPropertyFactory);
}
private class RawPropertyFactory : ILogEventPropertyFactory
{
public LogEventProperty CreateProperty(
string name,
object? value,
bool destructureObjects = false)
{
return new LogEventProperty(name, new ScalarValue(value));
}
}
}
builder.Host.UseSerilog((ctx, config) =>
{
// Ensure HttpContextAccessor is accessible
var httpAccessor = ctx.Configuration.Get<HttpContextAccessor>();
config
.ReadFrom.Configuration(ctx.Configuration)
//.Enrich.WithEcsHttpContext(httpAccessor) <-- this is the unpatched code
.Enrich.With(new PatchedHttpContextEnricher(httpAccessor));
});
Thanks I also ran into this issue and this helped me get httpContext information
One minor change was that for me the following line in the RawPropertyFactory has to be
return new LogEventProperty(name, new ScalarValue(value));
Thanks I also ran into this issue and this helped me get httpContext information
One minor change was that for me the following line in the RawPropertyFactory has to be
return new LogEventProperty(name, new ScalarValue(value));
You're right, I've updated the original post with your comment.