在ILogger自定义实现中检索标识

时间:2016-09-07 10:11:34

标签: c# logging asp.net-core asp.net-core-mvc

我正在实现一个自定义的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);
}

1 个答案:

答案 0 :(得分:0)

这里是可以访问身份的工作自定义记录器的示例。它应该可以满足您的需求,在我的示例中,出于可读性考虑,我刚刚重命名了一些类。在设计客户记录器https://docs.microsoft.com/en-us/aspnet/core/fundamentals/logging/?view=aspnetcore-3.1#create-a-custom-logger

时,这篇Microsoft文章对您可能也是有用的资源。

如果需要,您可以设置配置值:

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()));