支持自定义连接池大小 日志分等级存储

This commit is contained in:
root 2024-12-01 23:29:05 +08:00
parent 5bf3549522
commit d34b491c11
8 changed files with 120 additions and 48 deletions

View file

@ -2,7 +2,6 @@
using Serilog;
using System.Text.Json;
using System.Text.Json.Serialization;
using MySql.Data.MySqlClient;
namespace iFileProxy.Config
{
@ -93,6 +92,9 @@ namespace iFileProxy.Config
public partial class Database
{
[JsonPropertyName("MaxConnectionPoolSize")]
public uint MaxConnectionPoolSize { get; set; } = 50;
[JsonPropertyName("Common")]
public Common Common { get; set; }

View file

@ -15,7 +15,7 @@ namespace iFileProxy.Controllers
{
public TaskManager _taskManager = taskManager;
public DatabaseGateService _dbGateService = dbGateService;
private readonly Serilog.ILogger _logger = Log.Logger.ForContext<DatabaseGateService>();
private readonly Serilog.ILogger _logger = Log.Logger.ForContext<ManagementController>();
// 查看任务详情
@ -362,6 +362,7 @@ namespace iFileProxy.Controllers
/// <summary>
/// 获取数据库连接池状态
/// </summary>
[Authorize(UserMask.SuperAdmin)]
[HttpGet("GetConnectionPoolInfo")]
public async Task<ActionResult<CommonRsp>> GetConnectionPoolInfo()
{

View file

@ -8,16 +8,10 @@ namespace iFileProxy.Controllers
{
[Route("[controller]")]
[ApiController]
public class UserController : ControllerBase
public class UserController(AuthService authService, ILogger<UserController> logger) : ControllerBase
{
private readonly AuthService _authService;
private readonly ILogger<UserController> _logger;
public UserController(AuthService authService, ILogger<UserController> logger)
{
_authService = authService;
_logger = logger;
}
private readonly AuthService _authService = authService;
private readonly ILogger<UserController> _logger = logger;
/// <summary>
/// 用户注册

View file

@ -130,7 +130,7 @@ namespace iFileProxy.Models
/// <summary>
/// 连接池最大连接数
/// </summary>
public int MaxPoolSize { get; set; }
public uint MaxPoolSize { get; set; }
/// <summary>
/// 连接详情列表

View file

@ -8,7 +8,14 @@
{
public static void CreateLogger()
{
var filePath = Path.Combine(AppContext.BaseDirectory, $"logs/dispatch.api.log");
var baseLogPath = Path.Combine(AppContext.BaseDirectory, "logs");
var appName = AppDomain.CurrentDomain.FriendlyName;
// 确保日志目录存在
if (!Directory.Exists(baseLogPath))
{
Directory.CreateDirectory(baseLogPath);
}
Log.Logger = new LoggerConfiguration()
#if RELEASE
@ -19,12 +26,41 @@
.MinimumLevel.Override("Microsoft", LogEventLevel.Information)
.MinimumLevel.Override("Microsoft.AspNetCore", LogEventLevel.Warning)
.Enrich.FromLogContext()
// 控制台输出所有日志
.WriteTo.Console(
outputTemplate: "{Timestamp:HH:mm:ss.fff} [{Level:u3}] [{SourceContext}] {ClientIp} {Message:lj} {contentType}{NewLine} {Exception}")
.WriteTo.File(filePath,
outputTemplate: "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level:u3}] [{SourceContext}] {ClientIp} {Message:lj} {contentType} {queryString}{NewLine}{Exception}",
rollingInterval: RollingInterval.Day,
fileSizeLimitBytes: 1073741824) //1GB
outputTemplate: "{Timestamp:HH:mm:ss.fff} [{Level:u3}] [{SourceContext}] {ClientIp} {Message:lj} {contentType}{NewLine} {Exception}")
// 错误和致命错误写入单独的文件
.WriteTo.Logger(lc => lc
.Filter.ByIncludingOnly(evt => evt.Level >= LogEventLevel.Error)
.WriteTo.File(
Path.Combine(baseLogPath, $"{appName}.error.log"),
outputTemplate: "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level:u3}] [{SourceContext}] {ClientIp} {Message:lj} {contentType} {queryString}{NewLine}{Exception}",
rollingInterval: RollingInterval.Day,
fileSizeLimitBytes: 1073741824)) // 1GB
// 警告日志写入单独的文件
.WriteTo.Logger(lc => lc
.Filter.ByIncludingOnly(evt => evt.Level == LogEventLevel.Warning)
.WriteTo.File(
Path.Combine(baseLogPath, $"{appName}.warning.log"),
outputTemplate: "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level:u3}] [{SourceContext}] {ClientIp} {Message:lj} {contentType} {queryString}{NewLine}{Exception}",
rollingInterval: RollingInterval.Day,
fileSizeLimitBytes: 1073741824))
// 信息日志写入单独的文件
.WriteTo.Logger(lc => lc
.Filter.ByIncludingOnly(evt => evt.Level == LogEventLevel.Information)
.WriteTo.File(
Path.Combine(baseLogPath, $"{appName}.info.log"),
outputTemplate: "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level:u3}] [{SourceContext}] {ClientIp} {Message:lj} {contentType} {queryString}{NewLine}{Exception}",
rollingInterval: RollingInterval.Day,
fileSizeLimitBytes: 1073741824))
// 调试日志写入单独的文件
.WriteTo.Logger(lc => lc
.Filter.ByIncludingOnly(evt => evt.Level == LogEventLevel.Debug)
.WriteTo.File(
Path.Combine(baseLogPath, $"{appName}.debug.log"),
outputTemplate: "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level:u3}] [{SourceContext}] {ClientIp} {Message:lj} {contentType} {queryString}{NewLine}{Exception}",
rollingInterval: RollingInterval.Day,
fileSizeLimitBytes: 1073741824))
.Enrich.WithProperty("node_ip", GetIpAddress())
.CreateLogger();
}

View file

@ -6,7 +6,6 @@ using MySql.Data.MySqlClient;
using iFileProxy.Models;
using Newtonsoft.Json;
using System.Text;
using System.Threading.Tasks;
namespace iFileProxy.Services
{
@ -124,7 +123,7 @@ namespace iFileProxy.Services
Password = db_password,
Pooling = true,
MinimumPoolSize = 1,
MaximumPoolSize = 50,
MaximumPoolSize = AppConfig.GetCurrConfig().Database.MaxConnectionPoolSize,
ConnectionLifeTime = 300 // 连接最大生命周期(秒)
};
@ -929,27 +928,27 @@ namespace iFileProxy.Services
// 获取总连接数
var totalSql = @"SELECT COUNT(*)
FROM information_schema.processlist
WHERE info LIKE @appName OR host LIKE @appName";
WHERE `USER` LIKE @appName OR `DB` LIKE @appName";
var totalConnections = await ExecuteScalarAsync<long>(totalSql, parameters);
// 获取活跃连接数
var activeSql = @"SELECT COUNT(*)
FROM information_schema.processlist
WHERE Command != 'Sleep'
AND (info LIKE @appName OR host LIKE @appName)";
AND ( `USER` LIKE @appName OR `DB` LIKE @appName)";
var activeConnections = await ExecuteScalarAsync<long>(activeSql, parameters);
// 获取睡眠连接数
var sleepingSql = @"SELECT COUNT(*)
FROM information_schema.processlist
WHERE Command = 'Sleep'
AND (info LIKE @appName OR host LIKE @appName)";
AND ( `USER` LIKE @appName OR `DB` LIKE @appName)";
var sleepingConnections = await ExecuteScalarAsync<long>(sleepingSql, parameters);
// 获取连接详情
var detailSql = @"SELECT id, user, host, db, command, time, state, info
FROM information_schema.processlist
WHERE info LIKE @appName OR host LIKE @appName";
WHERE `USER` LIKE @appName OR `DB` LIKE @appName";
var connections = await ExecuteQueryAsync<ProcessListInfo>(detailSql, parameters);
return new ConnectionPoolInfo
@ -957,7 +956,7 @@ namespace iFileProxy.Services
TotalConnections = totalConnections,
ActiveConnections = activeConnections,
SleepingConnections = sleepingConnections,
MaxPoolSize = 50, // 从配置中获取的最大连接数
MaxPoolSize = AppConfig.GetCurrConfig().Database.MaxConnectionPoolSize, // 从配置中获取的最大连接数
Connections = connections
};
}

View file

@ -3,6 +3,8 @@ using iFileProxy.Helpers;
using iFileProxy.Models;
using Newtonsoft.Json;
using Serilog;
using MySql.Data.MySqlClient;
using System.Data;
namespace iFileProxy.Services
{
@ -16,6 +18,7 @@ namespace iFileProxy.Services
private readonly AppConfig _appConfig = AppConfig.GetCurrConfig();
private readonly static Serilog.ILogger _logger = Log.Logger.ForContext<LocalCacheManager>();
private readonly object _lock = new object();
private readonly Timer _timer;
private readonly DatabaseGateService _dbGateService;
private readonly int CACHE_LIFETIME;
@ -29,46 +32,82 @@ namespace iFileProxy.Services
CACHE_LIFETIME = _appConfig.DownloadOptions.CacheLifetime;
_dbGateService = serviceProvider.GetRequiredService<DatabaseGateService>();
// 开始定时清理任务
_timer = new Timer(CheckAndCleanCache, null, TimeSpan.FromSeconds(6), TimeSpan.FromSeconds(60));
_timer = new Timer((obj) => {
lock (_lock)
{
CheckAndCleanCache();
}
}, null, TimeSpan.FromSeconds(6), TimeSpan.FromSeconds(60));
_logger.Information("succ.");
}
/// <summary>
/// 检查并且清理缓存数据
/// </summary>
public void CheckAndCleanCache(object state)
public void CheckAndCleanCache()
{
// 初始化并打开一个MySQL连接 防止后续数据过多导致程序crush
using var dbConn = _dbGateService.GetAndOpenDBConn(DbConfigName.iFileProxy);
// 获取数据库中超出生命周期的缓存数据
string result = _dbGateService.QueryTableData($"SELECT * FROM t_tasks_info WHERE UNIX_TIMESTAMP(NOW()) - UNIX_TIMESTAMP(update_time) > {CACHE_LIFETIME} AND (tag <> 'CLEANED' OR tag IS NULL)", DbConfigName.iFileProxy);
List<TaskInfo>? taskInfos = JsonConvert.DeserializeObject<List<TaskInfo>>(result);
if (taskInfos != null)
try
{
foreach (TaskInfo taskInfo in taskInfos)
// 获取数据库中超出生命周期的缓存数据
string sql = $@"SELECT * FROM t_tasks_info
WHERE UNIX_TIMESTAMP(NOW()) - UNIX_TIMESTAMP(update_time) > {CACHE_LIFETIME}
AND (tag <> 'CLEANED' OR tag IS NULL)";
List<TaskInfo>? taskInfos;
using (var conn = _dbGateService.GetAndOpenDBConn(DbConfigName.iFileProxy))
{
string cacheFileName = Path.Combine(_appConfig.DownloadOptions.SavePath, taskInfo.FileName);
if (File.Exists(cacheFileName))
using var cmd = new MySqlCommand(sql, conn);
using var adapter = new MySqlDataAdapter(cmd);
var dataTable = new DataTable();
adapter.Fill(dataTable);
taskInfos = JsonConvert.DeserializeObject<List<TaskInfo>>(
JsonConvert.SerializeObject(dataTable)
);
}
if (taskInfos != null)
{
foreach (TaskInfo taskInfo in taskInfos)
{
_logger.Information($"正在清理缓存文件: {cacheFileName}");
try
string cacheFileName = Path.Combine(_appConfig.DownloadOptions.SavePath, taskInfo.FileName);
if (File.Exists(cacheFileName))
{
File.Delete(cacheFileName);
_logger.Information($"正在清理缓存文件: {cacheFileName}");
try
{
File.Delete(cacheFileName);
}
catch (Exception e)
{
_logger.Error($"缓存文件删除失败: {e.Message}");
continue;
}
}
catch (Exception e)
// 更新数据库状态
using (var conn = _dbGateService.GetAndOpenDBConn(DbConfigName.iFileProxy))
{
_logger.Error("缓存文件删除失败: {e}", e);
throw;
// 更新标签
using (var cmd = new MySqlCommand(
"UPDATE t_tasks_info SET tag = @tag WHERE tid = @tid",
conn))
{
cmd.Parameters.AddWithValue("@tag", "CLEANED");
cmd.Parameters.AddWithValue("@tid", taskInfo.TaskId);
cmd.ExecuteNonQuery();
}
// 更新状态
taskInfo.Status = TaskState.Cleaned;
_dbGateService.UpdateTaskStatus(taskInfo);
}
}
_dbGateService.Query($"UPDATE t_tasks_info SET `tag` = \"CLEANED\" WHERE `tid` = '{taskInfo.TaskId}'", dbConn);
taskInfo.Status = TaskState.Cleaned;
_dbGateService.UpdateTaskStatus(taskInfo,dbConn);
}
}
catch (Exception ex)
{
_logger.Error($"清理缓存时发生错误: {ex.Message}");
}
}
/// <summary>

View file

@ -1,5 +1,6 @@
{
"Database": {
"MaxConnectionPoolSize": 100,
"Common": {
"Host": "47.243.56.137",
"Port": 3306,