mirror of
https://github.com/GeWuYou/GFramework.git
synced 2026-05-06 16:16:44 +08:00
refactor(cqrs): 移除旧日志行为并添加CQRS运行时模块
- 删除 LoggingBehavior 类及其相关实现 - 新增 CqrsRuntimeModule 用于注册CQRS运行时组件 - 添加 ArchitectureComponentRegistryBehaviorTests 测试组件注册行为 - 添加 ArchitectureContextTests 测试架构上下文功能 - 完善CQRS运行时的并发安全性和生命周期管理
This commit is contained in:
parent
e36c80229a
commit
1c7558aeb8
250
GFramework.Core.Abstractions/Logging/LoggerFactoryResolver.cs
Normal file
250
GFramework.Core.Abstractions/Logging/LoggerFactoryResolver.cs
Normal file
@ -0,0 +1,250 @@
|
||||
namespace GFramework.Core.Abstractions.Logging;
|
||||
|
||||
/// <summary>
|
||||
/// 提供全局日志工厂访问入口。
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 该类型位于抽象层,是为了让上层模块可以在不依赖 <c>GFramework.Core</c> 实现程序集的前提下
|
||||
/// 获取日志记录器。默认 provider 会优先通过反射解析 <c>GFramework.Core</c> 中的控制台实现,
|
||||
/// 若宿主未加载该程序集,则退回到静默 provider,避免抽象层形成实现层循环依赖。
|
||||
/// </remarks>
|
||||
public static class LoggerFactoryResolver
|
||||
{
|
||||
private const string DefaultProviderTypeName =
|
||||
"GFramework.Core.Logging.ConsoleLoggerFactoryProvider, GFramework.Core";
|
||||
|
||||
/// <summary>
|
||||
/// 获取或设置当前日志工厂提供程序。
|
||||
/// </summary>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// 当赋值为 <see langword="null" /> 时抛出。
|
||||
/// </exception>
|
||||
public static ILoggerFactoryProvider Provider
|
||||
{
|
||||
get => field ??= CreateDefaultProvider();
|
||||
set => field = value ?? throw new ArgumentNullException(nameof(value));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取或设置新创建日志记录器的最小日志级别。
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 该属性直接代理到当前 <see cref="Provider" />,确保调用方调整级别后立即影响后续创建的日志器。
|
||||
/// </remarks>
|
||||
public static LogLevel MinLevel
|
||||
{
|
||||
get => Provider.MinLevel;
|
||||
set => Provider.MinLevel = value;
|
||||
}
|
||||
|
||||
private static ILoggerFactoryProvider CreateDefaultProvider()
|
||||
{
|
||||
if (Type.GetType(DefaultProviderTypeName, throwOnError: false) is { } providerType &&
|
||||
Activator.CreateInstance(providerType) is ILoggerFactoryProvider provider)
|
||||
{
|
||||
provider.MinLevel = LogLevel.Info;
|
||||
return provider;
|
||||
}
|
||||
|
||||
return new SilentLoggerFactoryProvider();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 当宿主未提供默认日志实现时使用的静默 provider。
|
||||
/// </summary>
|
||||
private sealed class SilentLoggerFactoryProvider : ILoggerFactoryProvider
|
||||
{
|
||||
public LogLevel MinLevel { get; set; } = LogLevel.Info;
|
||||
|
||||
public ILogger CreateLogger(string name)
|
||||
{
|
||||
return new SilentLogger(name);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 默认日志实现不可用时的 no-op 日志器。
|
||||
/// </summary>
|
||||
private sealed class SilentLogger(string name) : ILogger
|
||||
{
|
||||
public string Name()
|
||||
{
|
||||
return name;
|
||||
}
|
||||
|
||||
public bool IsTraceEnabled()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool IsDebugEnabled()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool IsInfoEnabled()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool IsWarnEnabled()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool IsErrorEnabled()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool IsFatalEnabled()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool IsEnabledForLevel(LogLevel level)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public void Trace(string msg)
|
||||
{
|
||||
}
|
||||
|
||||
public void Trace(string format, object arg)
|
||||
{
|
||||
}
|
||||
|
||||
public void Trace(string format, object arg1, object arg2)
|
||||
{
|
||||
}
|
||||
|
||||
public void Trace(string format, params object[] arguments)
|
||||
{
|
||||
}
|
||||
|
||||
public void Trace(string msg, Exception t)
|
||||
{
|
||||
}
|
||||
|
||||
public void Debug(string msg)
|
||||
{
|
||||
}
|
||||
|
||||
public void Debug(string format, object arg)
|
||||
{
|
||||
}
|
||||
|
||||
public void Debug(string format, object arg1, object arg2)
|
||||
{
|
||||
}
|
||||
|
||||
public void Debug(string format, params object[] arguments)
|
||||
{
|
||||
}
|
||||
|
||||
public void Debug(string msg, Exception t)
|
||||
{
|
||||
}
|
||||
|
||||
public void Info(string msg)
|
||||
{
|
||||
}
|
||||
|
||||
public void Info(string format, object arg)
|
||||
{
|
||||
}
|
||||
|
||||
public void Info(string format, object arg1, object arg2)
|
||||
{
|
||||
}
|
||||
|
||||
public void Info(string format, params object[] arguments)
|
||||
{
|
||||
}
|
||||
|
||||
public void Info(string msg, Exception t)
|
||||
{
|
||||
}
|
||||
|
||||
public void Warn(string msg)
|
||||
{
|
||||
}
|
||||
|
||||
public void Warn(string format, object arg)
|
||||
{
|
||||
}
|
||||
|
||||
public void Warn(string format, object arg1, object arg2)
|
||||
{
|
||||
}
|
||||
|
||||
public void Warn(string format, params object[] arguments)
|
||||
{
|
||||
}
|
||||
|
||||
public void Warn(string msg, Exception t)
|
||||
{
|
||||
}
|
||||
|
||||
public void Error(string msg)
|
||||
{
|
||||
}
|
||||
|
||||
public void Error(string format, object arg)
|
||||
{
|
||||
}
|
||||
|
||||
public void Error(string format, object arg1, object arg2)
|
||||
{
|
||||
}
|
||||
|
||||
public void Error(string format, params object[] arguments)
|
||||
{
|
||||
}
|
||||
|
||||
public void Error(string msg, Exception t)
|
||||
{
|
||||
}
|
||||
|
||||
public void Fatal(string msg)
|
||||
{
|
||||
}
|
||||
|
||||
public void Fatal(string format, object arg)
|
||||
{
|
||||
}
|
||||
|
||||
public void Fatal(string format, object arg1, object arg2)
|
||||
{
|
||||
}
|
||||
|
||||
public void Fatal(string format, params object[] arguments)
|
||||
{
|
||||
}
|
||||
|
||||
public void Fatal(string msg, Exception t)
|
||||
{
|
||||
}
|
||||
|
||||
public void Log(LogLevel level, string message)
|
||||
{
|
||||
}
|
||||
|
||||
public void Log(LogLevel level, string format, object arg)
|
||||
{
|
||||
}
|
||||
|
||||
public void Log(LogLevel level, string format, object arg1, object arg2)
|
||||
{
|
||||
}
|
||||
|
||||
public void Log(LogLevel level, string format, params object[] arguments)
|
||||
{
|
||||
}
|
||||
|
||||
public void Log(LogLevel level, string message, Exception exception)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,11 +1,11 @@
|
||||
using GFramework.Core.Abstractions.Architectures;
|
||||
using GFramework.Core.Abstractions.Enums;
|
||||
using GFramework.Core.Abstractions.Logging;
|
||||
using GFramework.Core.Abstractions.Model;
|
||||
using GFramework.Core.Abstractions.Systems;
|
||||
using GFramework.Core.Abstractions.Utility;
|
||||
using GFramework.Core.Architectures;
|
||||
using GFramework.Core.Logging;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace GFramework.Core.Tests.Architectures;
|
||||
|
||||
@ -714,4 +714,4 @@ public class ArchitectureComponentRegistryBehaviorTests
|
||||
return _context;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -5,6 +5,7 @@ using GFramework.Core.Abstractions.Cqrs;
|
||||
using GFramework.Core.Abstractions.Enums;
|
||||
using GFramework.Core.Abstractions.Environment;
|
||||
using GFramework.Core.Abstractions.Ioc;
|
||||
using GFramework.Core.Abstractions.Logging;
|
||||
using GFramework.Core.Abstractions.Model;
|
||||
using GFramework.Core.Abstractions.Query;
|
||||
using GFramework.Core.Abstractions.Systems;
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
using GFramework.Core.Abstractions.Enums;
|
||||
using GFramework.Core.Abstractions.Events;
|
||||
using GFramework.Core.Abstractions.Logging;
|
||||
using GFramework.Core.Architectures;
|
||||
using GFramework.Core.Environment;
|
||||
using GFramework.Core.Logging;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace GFramework.Core.Tests.Architectures;
|
||||
|
||||
@ -185,4 +185,4 @@ public class ArchitectureInitializationPipelineTests
|
||||
private sealed class BootstrapMarker
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,12 +2,12 @@ using System.Reflection;
|
||||
using GFramework.Core.Abstractions.Architectures;
|
||||
using GFramework.Core.Abstractions.Enums;
|
||||
using GFramework.Core.Abstractions.Lifecycle;
|
||||
using GFramework.Core.Abstractions.Logging;
|
||||
using GFramework.Core.Abstractions.Model;
|
||||
using GFramework.Core.Abstractions.Systems;
|
||||
using GFramework.Core.Abstractions.Utility;
|
||||
using GFramework.Core.Architectures;
|
||||
using GFramework.Core.Logging;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace GFramework.Core.Tests.Architectures;
|
||||
|
||||
@ -460,4 +460,4 @@ public class ArchitectureLifecycleBehaviorTests
|
||||
return _context;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
using GFramework.Core.Abstractions.Architectures;
|
||||
using GFramework.Core.Abstractions.Logging;
|
||||
using GFramework.Core.Abstractions.Utility;
|
||||
using GFramework.Core.Architectures;
|
||||
using GFramework.Core.Logging;
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
using System.Reflection;
|
||||
using GFramework.Core.Abstractions.Bases;
|
||||
using GFramework.Core.Abstractions.Logging;
|
||||
using GFramework.Core.Abstractions.Model;
|
||||
using GFramework.Core.Abstractions.Systems;
|
||||
using GFramework.Core.Abstractions.Utility;
|
||||
@ -244,4 +245,4 @@ public class PriorityTestUtilityC : IPriorityTestUtility, IPrioritized
|
||||
public int Priority => 30;
|
||||
}
|
||||
|
||||
#endregion
|
||||
#endregion
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
using System.Reflection;
|
||||
using GFramework.Core.Abstractions.Bases;
|
||||
using GFramework.Core.Abstractions.Cqrs;
|
||||
using GFramework.Core.Abstractions.Logging;
|
||||
using GFramework.Core.Ioc;
|
||||
using GFramework.Core.Logging;
|
||||
using GFramework.Core.Tests.Cqrs;
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
using System.Reflection;
|
||||
using GFramework.Core.Abstractions.Enums;
|
||||
using GFramework.Core.Abstractions.Logging;
|
||||
using GFramework.Core.Abstractions.State;
|
||||
using GFramework.Core.Abstractions.Systems;
|
||||
using GFramework.Core.Architectures;
|
||||
@ -373,4 +374,4 @@ public class TestStateV5_2 : IState
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
#endregion
|
||||
|
||||
@ -1,26 +0,0 @@
|
||||
using GFramework.Core.Abstractions.Logging;
|
||||
|
||||
namespace GFramework.Core.Logging;
|
||||
|
||||
/// <summary>
|
||||
/// 日志工厂提供程序解析器,用于管理和提供日志工厂提供程序实例
|
||||
/// </summary>
|
||||
public static class LoggerFactoryResolver
|
||||
{
|
||||
/// <summary>
|
||||
/// 获取或设置当前的日志工厂提供程序
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// 日志工厂提供程序实例,默认为控制台日志工厂提供程序
|
||||
/// </value>
|
||||
public static ILoggerFactoryProvider Provider { get; set; }
|
||||
= new ConsoleLoggerFactoryProvider();
|
||||
|
||||
/// <summary>
|
||||
/// 获取或设置日志记录的最小级别
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// 日志级别枚举值,默认为Info级别
|
||||
/// </value>
|
||||
public static LogLevel MinLevel { get; set; } = LogLevel.Info;
|
||||
}
|
||||
4
GFramework.Core/Properties/TypeForwarders.cs
Normal file
4
GFramework.Core/Properties/TypeForwarders.cs
Normal file
@ -0,0 +1,4 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
using GFramework.Core.Abstractions.Logging;
|
||||
|
||||
[assembly: TypeForwardedTo(typeof(LoggerFactoryResolver))]
|
||||
@ -1,7 +1,7 @@
|
||||
using GFramework.Core.Abstractions.Architectures;
|
||||
using GFramework.Core.Abstractions.Cqrs;
|
||||
using GFramework.Core.Abstractions.Ioc;
|
||||
using GFramework.Core.Logging;
|
||||
using GFramework.Core.Abstractions.Logging;
|
||||
using GFramework.Cqrs;
|
||||
using GFramework.Cqrs.Abstractions.Cqrs;
|
||||
|
||||
|
||||
@ -20,6 +20,7 @@ global using System.Reflection;
|
||||
global using System.Runtime.CompilerServices;
|
||||
global using System.Threading;
|
||||
global using System.Threading.Tasks;
|
||||
global using System.Diagnostics;
|
||||
global using GFramework.Tests.Common;
|
||||
global using Microsoft.Extensions.DependencyInjection;
|
||||
global using Moq;
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
using GFramework.Core.Abstractions.Logging;
|
||||
using GFramework.Core.Architectures;
|
||||
using GFramework.Core.Ioc;
|
||||
using GFramework.Core.Logging;
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
using GFramework.Core.Abstractions.Architectures;
|
||||
using GFramework.Core.Abstractions.Logging;
|
||||
using GFramework.Core.Architectures;
|
||||
using GFramework.Core.Command;
|
||||
using GFramework.Core.Ioc;
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
using GFramework.Core.Abstractions.Architectures;
|
||||
using GFramework.Core.Abstractions.Events;
|
||||
using GFramework.Core.Abstractions.Logging;
|
||||
using GFramework.Core.Architectures;
|
||||
using GFramework.Core.Command;
|
||||
using GFramework.Core.Environment;
|
||||
|
||||
@ -11,19 +11,20 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
using System.Diagnostics;
|
||||
using GFramework.Core.Abstractions.Logging;
|
||||
using GFramework.Core.Logging;
|
||||
using GFramework.Cqrs.Abstractions.Cqrs;
|
||||
|
||||
namespace GFramework.Core.Cqrs.Behaviors;
|
||||
namespace GFramework.Cqrs.Cqrs.Behaviors;
|
||||
|
||||
/// <summary>
|
||||
/// 日志记录行为类,用于在CQRS管道中记录请求处理的日志信息
|
||||
/// 实现IPipelineBehavior接口,为请求处理提供日志记录功能
|
||||
/// 在 CQRS 请求管道中记录请求开始、完成、取消与失败日志。
|
||||
/// </summary>
|
||||
/// <typeparam name="TRequest">请求类型,必须实现IRequest接口</typeparam>
|
||||
/// <typeparam name="TResponse">响应类型</typeparam>
|
||||
/// <typeparam name="TRequest">请求类型。</typeparam>
|
||||
/// <typeparam name="TResponse">响应类型。</typeparam>
|
||||
/// <remarks>
|
||||
/// 该行为保留在 <c>GFramework.Core.Cqrs.Behaviors</c> 命名空间以兼容现有调用点,
|
||||
/// 但实现已迁入 <c>GFramework.Cqrs</c> 程序集,避免继续由 <c>GFramework.Core</c> 承载 CQRS runtime 细节。
|
||||
/// </remarks>
|
||||
public sealed class LoggingBehavior<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse>
|
||||
where TRequest : IRequest<TResponse>
|
||||
{
|
||||
@ -31,13 +32,12 @@ public sealed class LoggingBehavior<TRequest, TResponse> : IPipelineBehavior<TRe
|
||||
LoggerFactoryResolver.Provider.CreateLogger(nameof(LoggingBehavior<TRequest, TResponse>));
|
||||
|
||||
/// <summary>
|
||||
/// 处理请求并记录日志
|
||||
/// 在请求处理前后记录调试信息,处理异常时记录错误日志
|
||||
/// 执行日志包装后的下一段请求处理逻辑。
|
||||
/// </summary>
|
||||
/// <param name="message">要处理的请求消息</param>
|
||||
/// <param name="next">下一个处理委托,用于继续管道执行</param>
|
||||
/// <param name="cancellationToken">取消令牌,用于取消操作</param>
|
||||
/// <returns>处理结果的ValueTask</returns>
|
||||
/// <param name="message">当前请求消息。</param>
|
||||
/// <param name="next">后续处理委托。</param>
|
||||
/// <param name="cancellationToken">取消令牌。</param>
|
||||
/// <returns>请求处理结果。</returns>
|
||||
public async ValueTask<TResponse> Handle(
|
||||
TRequest message,
|
||||
MessageHandlerDelegate<TRequest, TResponse> next,
|
||||
@ -11,33 +11,34 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
using System.Diagnostics;
|
||||
using GFramework.Core.Abstractions.Logging;
|
||||
using GFramework.Core.Logging;
|
||||
using GFramework.Cqrs.Abstractions.Cqrs;
|
||||
|
||||
namespace GFramework.Core.Cqrs.Behaviors;
|
||||
namespace GFramework.Cqrs.Cqrs.Behaviors;
|
||||
|
||||
/// <summary>
|
||||
/// 性能监控行为类,用于监控CQRS请求的执行时间
|
||||
/// 实现IPipelineBehavior接口,检测并记录执行时间过长的请求
|
||||
/// 在 CQRS 请求管道中监控处理耗时,并对长耗时请求发出告警。
|
||||
/// </summary>
|
||||
/// <typeparam name="TRequest">请求类型,必须实现IRequest接口</typeparam>
|
||||
/// <typeparam name="TResponse">响应类型</typeparam>
|
||||
/// <typeparam name="TRequest">请求类型。</typeparam>
|
||||
/// <typeparam name="TResponse">响应类型。</typeparam>
|
||||
/// <remarks>
|
||||
/// 该行为保留现有公开命名空间以维持消费端兼容性,但实现已迁入 <c>GFramework.Cqrs</c> 程序集。
|
||||
/// </remarks>
|
||||
public sealed class PerformanceBehavior<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse>
|
||||
where TRequest : IRequest<TResponse>
|
||||
{
|
||||
private const double SlowRequestThresholdMilliseconds = 500;
|
||||
|
||||
private readonly ILogger _logger =
|
||||
LoggerFactoryResolver.Provider.CreateLogger(nameof(PerformanceBehavior<TRequest, TResponse>));
|
||||
|
||||
/// <summary>
|
||||
/// 处理请求并监控执行时间
|
||||
/// 使用Stopwatch测量请求处理耗时,超过500ms时记录警告日志
|
||||
/// 统计当前请求处理耗时,并在超阈值时记录警告日志。
|
||||
/// </summary>
|
||||
/// <param name="message">要处理的请求消息</param>
|
||||
/// <param name="next">下一个处理委托,用于继续管道执行</param>
|
||||
/// <param name="cancellationToken">取消令牌,用于取消操作</param>
|
||||
/// <returns>处理结果的ValueTask</returns>
|
||||
/// <param name="message">当前请求消息。</param>
|
||||
/// <param name="next">后续处理委托。</param>
|
||||
/// <param name="cancellationToken">取消令牌。</param>
|
||||
/// <returns>请求处理结果。</returns>
|
||||
public async ValueTask<TResponse> Handle(
|
||||
TRequest message,
|
||||
MessageHandlerDelegate<TRequest, TResponse> next,
|
||||
@ -53,11 +54,10 @@ public sealed class PerformanceBehavior<TRequest, TResponse> : IPipelineBehavior
|
||||
{
|
||||
var elapsed = Stopwatch.GetElapsedTime(start);
|
||||
|
||||
if (elapsed.TotalMilliseconds > 500)
|
||||
if (elapsed.TotalMilliseconds > SlowRequestThresholdMilliseconds)
|
||||
{
|
||||
var requestName = typeof(TRequest).Name;
|
||||
_logger.Warn(
|
||||
$"Long Running Request: {requestName} ({elapsed.TotalMilliseconds:F2} ms)");
|
||||
_logger.Warn($"Long Running Request: {requestName} ({elapsed.TotalMilliseconds:F2} ms)");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -4,3 +4,4 @@ global using System.Linq;
|
||||
global using System.Threading;
|
||||
global using System.Threading.Tasks;
|
||||
global using Microsoft.Extensions.DependencyInjection;
|
||||
global using System.Diagnostics;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user