mirror of
https://github.com/DrizzleTime/Foxel.git
synced 2026-06-06 16:14:40 +08:00
feat(logManagement): implement log management service
This commit is contained in:
112
Services/Logging/DatabaseLogger.cs
Normal file
112
Services/Logging/DatabaseLogger.cs
Normal file
@@ -0,0 +1,112 @@
|
||||
using System.Text.Json;
|
||||
using Foxel.Models.DataBase;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace Foxel.Services.Logging;
|
||||
|
||||
public class DatabaseLogger(string categoryName, IServiceProvider serviceProvider, DatabaseLoggerConfiguration config)
|
||||
: ILogger
|
||||
{
|
||||
private static volatile bool _isDatabaseReady;
|
||||
|
||||
public static void SetDatabaseReady(bool isReady)
|
||||
{
|
||||
_isDatabaseReady = isReady;
|
||||
}
|
||||
|
||||
public IDisposable BeginScope<TState>(TState state) where TState : notnull => null!;
|
||||
|
||||
public bool IsEnabled(LogLevel logLevel) => logLevel >= config.MinLevel;
|
||||
|
||||
public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception? exception,
|
||||
Func<TState, Exception?, string> formatter)
|
||||
{
|
||||
if (!IsEnabled(logLevel) || !_isDatabaseReady)
|
||||
return;
|
||||
|
||||
var message = formatter(state, exception);
|
||||
if (string.IsNullOrEmpty(message))
|
||||
return;
|
||||
|
||||
_ = Task.Run(async () =>
|
||||
{
|
||||
try
|
||||
{
|
||||
using var scope = serviceProvider.CreateScope();
|
||||
var contextFactory = scope.ServiceProvider.GetRequiredService<IDbContextFactory<MyDbContext>>();
|
||||
var httpContextAccessor = scope.ServiceProvider.GetService<IHttpContextAccessor>();
|
||||
|
||||
await using var context = await contextFactory.CreateDbContextAsync();
|
||||
|
||||
if (!await IsDatabaseAvailableAsync(context))
|
||||
return;
|
||||
|
||||
var httpContext = httpContextAccessor?.HttpContext;
|
||||
|
||||
var log = new Log
|
||||
{
|
||||
Level = logLevel,
|
||||
Message = message.Length > 4000 ? message[..4000] : message,
|
||||
Category = categoryName,
|
||||
EventId = eventId.Id,
|
||||
Timestamp = DateTime.UtcNow,
|
||||
Exception = exception?.ToString(),
|
||||
RequestPath = httpContext?.Request.Path.ToString(),
|
||||
RequestMethod = httpContext?.Request.Method,
|
||||
StatusCode = httpContext?.Response.StatusCode,
|
||||
IPAddress = httpContext?.Connection.RemoteIpAddress?.ToString(),
|
||||
Properties = SerializeState(state)
|
||||
};
|
||||
if (httpContext?.User.Identity?.IsAuthenticated == true)
|
||||
{
|
||||
var userIdClaim = httpContext.User.FindFirst("UserId");
|
||||
if (userIdClaim != null && int.TryParse(userIdClaim.Value, out var userId))
|
||||
{
|
||||
log.UserId = userId;
|
||||
}
|
||||
}
|
||||
|
||||
context.Logs.Add(log);
|
||||
await context.SaveChangesAsync();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"写入数据库日志时出错: {ex.Message}");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static async Task<bool> IsDatabaseAvailableAsync(MyDbContext context)
|
||||
{
|
||||
try
|
||||
{
|
||||
await context.Database.ExecuteSqlRawAsync("SELECT 1 FROM \"Logs\" LIMIT 1");
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static string? SerializeState<TState>(TState state)
|
||||
{
|
||||
if (state is string)
|
||||
return null;
|
||||
|
||||
try
|
||||
{
|
||||
var options = new JsonSerializerOptions
|
||||
{
|
||||
WriteIndented = false,
|
||||
DefaultIgnoreCondition = System.Text.Json.Serialization.JsonIgnoreCondition.WhenWritingNull
|
||||
};
|
||||
|
||||
return JsonSerializer.Serialize(state, options);
|
||||
}
|
||||
catch
|
||||
{
|
||||
return state?.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
7
Services/Logging/DatabaseLoggerConfiguration.cs
Normal file
7
Services/Logging/DatabaseLoggerConfiguration.cs
Normal file
@@ -0,0 +1,7 @@
|
||||
namespace Foxel.Services.Logging;
|
||||
|
||||
public class DatabaseLoggerConfiguration
|
||||
{
|
||||
public LogLevel MinLevel { get; set; } = LogLevel.Information;
|
||||
public bool Enabled { get; set; } = true;
|
||||
}
|
||||
23
Services/Logging/DatabaseLoggerProvider.cs
Normal file
23
Services/Logging/DatabaseLoggerProvider.cs
Normal file
@@ -0,0 +1,23 @@
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
namespace Foxel.Services.Logging;
|
||||
|
||||
[ProviderAlias("Database")]
|
||||
public class DatabaseLoggerProvider : ILoggerProvider
|
||||
{
|
||||
private readonly IServiceProvider _serviceProvider;
|
||||
private readonly DatabaseLoggerConfiguration _config;
|
||||
|
||||
public DatabaseLoggerProvider(IServiceProvider serviceProvider, IOptions<DatabaseLoggerConfiguration> config)
|
||||
{
|
||||
_serviceProvider = serviceProvider;
|
||||
_config = config.Value;
|
||||
}
|
||||
|
||||
public ILogger CreateLogger(string categoryName)
|
||||
{
|
||||
return new DatabaseLogger(categoryName, _serviceProvider, _config);
|
||||
}
|
||||
|
||||
public void Dispose() { }
|
||||
}
|
||||
Reference in New Issue
Block a user