Ich erstelle meine eigene SeriLog-Senke, die ILogEventSink
unter Verwendung des Building a Simple Sink Beispiels mit der Absicht des Eintragens einiger Informationen von den Benutzeransprüchen einführt. Um Zugriff auf HttpContext in Core zu bekommen, würde ich normalerweise eine Instanz von IHttpContextAccessor
injizieren, aber das Beispiel zeigt das Erstellen einer Instanz der Senke in einer Erweiterungsmethode, z.Wie kann ich den aktuellen HttpContext in einem SeriLog Sink bekommen?
public class MySink : ILogEventSink
{
private readonly IFormatProvider _formatProvider;
public MySink(IFormatProvider formatProvider)
{
_formatProvider = formatProvider;
}
public void Emit(LogEvent logEvent)
{
// How to get HttpContext here?
}
}
public static class MySinkExtensions
{
public static LoggerConfiguration MySink(
this LoggerSinkConfiguration loggerConfiguration,
IFormatProvider formatProvider = null)
{
return loggerConfiguration.Sink(new MySink(formatProvider));
}
}
... dann das Waschbecken zu benutzen ...
var log = new LoggerConfiguration()
.MinimumLevel.Information()
.WriteTo.MySink()
.CreateLogger();
Wie kann ich Zugriff auf den aktuellen Httpcontext in der Emit-Methode des Waschbeckens bekommen? Oder ist es möglich, dass die Senke zum Beispiel vom DI-Framework erstellt wird ?!
Ich habe eine MVC-Site, die Asp.Net Core 2 Framework gegen .Net 4.6.2 Runtime mit Serilog.AspNetCore v2.1.0 läuft.
Update - Umgehung
Nach dem Zeiger von @tsimbalar I erstellt Middleware ähnlich den Code unten. In meiner StartUp.Configure
Methode füge ich es mit app.UseMiddleware<ClaimsMiddleware>();
nach die App Authentifizierung Schritt ist passiert (sonst wird keine Ansprüche geladen werden).
public class ClaimsMiddleware
{
private static readonly ILogger Log = Serilog.Log.ForContext<ClaimsMiddleware>();
private readonly RequestDelegate next;
public ClaimsMiddleware(RequestDelegate next)
{
this.next = next ?? throw new ArgumentNullException(nameof(next));
}
public async Task Invoke(HttpContext httpContext)
{
if (httpContext == null) throw new ArgumentNullException(nameof(httpContext));
// Get values from claims here
var myVal = httpContext
.User
.Claims
.Where(x => x.Type == "MyVal")
.Select(x => x.Value)
.DefaultIfEmpty(string.Empty)
.SingleOrDefault();
using (LogContext.PushProperty("MyVal", myVal))
{
try
{
await next(httpContext);
}
// Never caught, because `LogException()` returns false.
catch (Exception ex) when (LogException(httpContext, ex)) { }
}
}
private static bool LogException(HttpContext httpContext, Exception ex)
{
var logForContext = Log.ForContext("StackTrace", ex.StackTrace);
logForContext.Error(ex, ex.Message);
return false;
}
}
Dank @tsimbalar. Im Schritt ** configure ** übergeben Sie den ContextAccessor in eine Instanz eines MyEnricher-Objekts. Dies verwendet keine Abhängigkeitsinjektion, also wie würde ich den Kontext bekommen, wenn ich die Protokollierung in der Programmhauptmethode konfiguriere, bevor der Startup (und anschließend 'ConfigureServices') aufgerufen wurde? –
oh ja, wenn Sie in Programm Main sind, kann das nicht funktionieren .... mmmm nicht sicher, wie das funktionieren würde – tsimbalar
@gavin Ich habe meine Antwort – tsimbalar