检索日志记录器自定义实现中的标识

本文关键字:标识 实现 自定义 日志 记录器 检索 | 更新日期: 2023-09-27 18:06:05

我正在实现一个自定义的Microsoft.Extensions.Logging.ILogger(和ILoggerProvider)。我想检索当前的身份,但我真的不知道,因为我不能注入任何东西,我也不知道当前的HttpContext。

我的方法可能是错误的…对于这类需求是否有一个典型的解决方案?

下面是几行代码:

factory.AddProvider(new MongoDBLoggerProvider(connectionString, database));

:

public ILogger CreateLogger(string categoryName)
{
    var client = new MongoClient(_connectionString);
    var database = client.GetDatabase(_database);
    return new MongoDBLogger(database, categoryName);
}

日志中:

public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
{
    var now = DateTime.Now;
    var entry = new LogEntry
    {
        Date = now,
        UserId = ?????
        Exception = exception,
        Level = logLevel,
        State = state.ToString(),
        Scope = _categoryName,
        EventId = eventId.Id,
        EventName = eventId.Name,
        FormattedState = formatter != null ? formatter(state, exception) : null
    };
    PushAndForget(entry, _database);
}

检索日志记录器自定义实现中的标识

下面是一个可以访问身份的自定义日志记录器的示例。它应该完成您所寻找的,我只是重命名了我的例子中的一些类的可读性目的。这篇microsoft文章也可以作为您设计客户日志记录器https://learn.microsoft.com/en-us/aspnet/core/fundamentals/logging/?view=aspnetcore-3.1#create-a-custom-logger

的有用资源。

如果您愿意,可以设置配置值:

public class LoggingServiceConfig
{
    public LogLevel LogLevel { get; set; } = LogLevel.Information;
    public int EventId { get; set; } = 0;
    public ConsoleColor Color { get; set; } = ConsoleColor.Yellow;
}

Config类有以下用途:

using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

设置自定义记录器:

public class LoggingService : ILogger
{
    private readonly ILogStore _logStore;
    private readonly Microsoft.AspNetCore.Http.IHttpContextAccessor _httpContextAccessor;
    private readonly LoggingServiceConfig _config;
    public LoggingService(string categoryName, LoggingServiceConfig config,
        Microsoft.AspNetCore.Http.IHttpContextAccessor httpContextAccessor,
        ILogStore logStore)
    {
        _config = config;
        _logStore = logStore;
        _httpContextAccessor = httpContextAccessor;
    }
    public IDisposable BeginScope<TState>(TState state)
    {
        return null;
    }
    public bool IsEnabled(LogLevel logLevel)
    {
        return true; //currently log everything regardless of logLevel
    }
    public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
    {
        LogEntry log = new LogEntry(); //this is your log entry
        if (_httpContextAccessor.HttpContext != null)
        {
            var userManager = _httpContextAccessor.HttpContext.RequestServices.GetService<UserManager<AspNetUser>>(); //this is the user manager you can use to perform identity functions, you can likewise request the signInManager  service as well if needed
            var user = userManager.GetUserAsync(_httpContextAccessor.HttpContext.User);
            if (user != null && user.Result != null)
            {
                //do something with user.Result as this is your identity user record
                log.UserId = user.Result.UserId;
                log.Username = user.Result.UserName;
            }
        }
        
        if (exception != null)
        {
            log.ErrorMessage = exception.Message;
        }
        var signInManager = _httpContextAccessor.HttpContext.RequestServices.GetService<SignInManager<AspNetUser>>(); //I accessed the sign in manager in case you need it to conditionally affect how you write create your LogEntry
        //add other properties you want to the log here
        _logStore.Add(log); //this is where you can call your PushAndForget or any method to write to database assumed you injected it correctly or the like, you can reference the .net core respository pattern for further details on how i did my _logStore
    }
}

自定义记录器有以下用途:

using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;

设置日志提供者:

public class LoggingServiceLoggerProvider : ILoggerProvider
{
    private readonly LoggingServiceConfig _config;
    private readonly ConcurrentDictionary<string, LoggingService> _loggers = new ConcurrentDictionary<string, LoggingService>();
    private readonly ILogStore _logStore;
    private readonly Microsoft.AspNetCore.Http.IHttpContextAccessor _httpContextAccessor;
    public LoggingServiceLoggerProvider(LoggingServiceConfig config,
        Microsoft.AspNetCore.Http.IHttpContextAccessor httpContextAccessor,
        ILogStore logStore)
    {
        _config = config;
        _httpContextAccessor = httpContextAccessor;
        _logStore = logStore; //this is a repository for storing logs
    }
    public ILogger CreateLogger(string categoryName)
    {
        return _loggers.GetOrAdd(categoryName, name => new LoggingService(name, _config,
            _httpContextAccessor,
            _logStore));
    }
    public void Dispose()
    {
        _loggers.Clear();
    }
}

自定义日志提供程序有以下using语句:

using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

在Startup.cs中,确保configure方法有一个ILoggerFactory loggerFactory参数,并包括以下内容:

loggerFactory.AddProvider(new LoggingServiceLoggerProvider(
                                  new LoggingServiceConfig
                                  {
                                      LogLevel = LogLevel.Error,
                                      Color = ConsoleColor.Red
                                  },
                                  new Microsoft.AspNetCore.Http.HttpContextAccessor(),
                                  new LogStore()));