diff --git a/GFramework.Core/logging/appenders/StatisticsAppender.cs b/GFramework.Core/logging/appenders/StatisticsAppender.cs
new file mode 100644
index 0000000..664c497
--- /dev/null
+++ b/GFramework.Core/logging/appenders/StatisticsAppender.cs
@@ -0,0 +1,163 @@
+using System.Collections.Concurrent;
+using System.Text;
+using GFramework.Core.Abstractions.logging;
+
+namespace GFramework.Core.logging.appenders;
+
+///
+/// 日志统计 Appender,用于收集日志指标
+/// 线程安全:所有方法都是线程安全的
+///
+public sealed class StatisticsAppender : ILogAppender
+{
+ private readonly ConcurrentDictionary _levelCounts = new();
+ private readonly ConcurrentDictionary _loggerCounts = new();
+ private long _errorCount;
+ private DateTime _startTime = DateTime.UtcNow;
+ private long _totalCount;
+
+ ///
+ /// 获取总日志数量
+ ///
+ public long TotalCount => Interlocked.Read(ref _totalCount);
+
+ ///
+ /// 获取错误日志数量(Error + Fatal)
+ ///
+ public long ErrorCount => Interlocked.Read(ref _errorCount);
+
+ ///
+ /// 获取统计开始时间
+ ///
+ public DateTime StartTime => _startTime;
+
+ ///
+ /// 获取运行时长
+ ///
+ public TimeSpan Uptime => DateTime.UtcNow - _startTime;
+
+ ///
+ /// 获取错误率(错误数 / 总数)
+ ///
+ public double ErrorRate
+ {
+ get
+ {
+ var total = TotalCount;
+ return total == 0 ? 0 : (double)ErrorCount / total;
+ }
+ }
+
+ ///
+ /// 追加日志条目
+ ///
+ public void Append(LogEntry entry)
+ {
+ // 增加总计数
+ Interlocked.Increment(ref _totalCount);
+
+ // 增加级别计数
+ _levelCounts.AddOrUpdate(entry.Level, 1, (_, count) => count + 1);
+
+ // 增加日志记录器计数
+ _loggerCounts.AddOrUpdate(entry.LoggerName, 1, (_, count) => count + 1);
+
+ // 如果是错误级别,增加错误计数
+ if (entry.Level >= LogLevel.Error)
+ {
+ Interlocked.Increment(ref _errorCount);
+ }
+ }
+
+ ///
+ /// 刷新缓冲区(此 Appender 无需刷新)
+ ///
+ public void Flush()
+ {
+ // 统计 Appender 不需要刷新
+ }
+
+ ///
+ /// 获取指定级别的日志数量
+ ///
+ public long GetCountByLevel(LogLevel level)
+ {
+ return _levelCounts.TryGetValue(level, out var count) ? count : 0;
+ }
+
+ ///
+ /// 获取指定日志记录器的日志数量
+ ///
+ public long GetCountByLogger(string loggerName)
+ {
+ return _loggerCounts.TryGetValue(loggerName, out var count) ? count : 0;
+ }
+
+ ///
+ /// 获取所有级别的日志数量
+ ///
+ public IReadOnlyDictionary GetLevelCounts()
+ {
+ return new Dictionary(_levelCounts);
+ }
+
+ ///
+ /// 获取所有日志记录器的日志数量
+ ///
+ public IReadOnlyDictionary GetLoggerCounts()
+ {
+ return new Dictionary(_loggerCounts);
+ }
+
+ ///
+ /// 重置所有统计数据
+ ///
+ public void Reset()
+ {
+ Interlocked.Exchange(ref _totalCount, 0);
+ Interlocked.Exchange(ref _errorCount, 0);
+ _levelCounts.Clear();
+ _loggerCounts.Clear();
+ _startTime = DateTime.UtcNow;
+ }
+
+ ///
+ /// 生成统计报告
+ ///
+ public string GenerateReport()
+ {
+ var report = new StringBuilder();
+ report.AppendLine("=== 日志统计报告 ===");
+ report.AppendLine($"统计时间: {_startTime:yyyy-MM-dd HH:mm:ss} - {DateTime.UtcNow:yyyy-MM-dd HH:mm:ss}");
+ report.AppendLine($"运行时长: {Uptime}");
+ report.AppendLine($"总日志数: {TotalCount}");
+ report.AppendLine($"错误日志数: {ErrorCount}");
+ report.AppendLine($"错误率: {ErrorRate:P2}");
+ report.AppendLine();
+
+ report.AppendLine("按级别统计:");
+ foreach (var level in Enum.GetValues())
+ {
+ var count = GetCountByLevel(level);
+ if (count > 0)
+ {
+ var percentage = (double)count / TotalCount;
+ report.AppendLine($" {level}: {count} ({percentage:P2})");
+ }
+ }
+
+ report.AppendLine();
+ report.AppendLine("按日志记录器统计 (Top 10):");
+ var topLoggers = _loggerCounts
+ .OrderByDescending(kvp => kvp.Value)
+ .Take(10);
+
+ foreach (var (logger, count) in topLoggers)
+ {
+ var percentage = (double)count / TotalCount;
+ report.AppendLine($" {logger}: {count} ({percentage:P2})");
+ }
+
+ return report.ToString();
+ }
+}
\ No newline at end of file
diff --git a/GFramework.Core/logging/filters/SamplingFilter.cs b/GFramework.Core/logging/filters/SamplingFilter.cs
new file mode 100644
index 0000000..23da89e
--- /dev/null
+++ b/GFramework.Core/logging/filters/SamplingFilter.cs
@@ -0,0 +1,74 @@
+using System.Collections.Concurrent;
+using GFramework.Core.Abstractions.logging;
+
+namespace GFramework.Core.logging.filters;
+
+///
+/// 日志采样过滤器,用于限制高频日志的输出
+/// 线程安全:所有方法都是线程安全的
+///
+public sealed class SamplingFilter : ILogFilter
+{
+ private readonly int _sampleRate;
+ private readonly ConcurrentDictionary _samplingStates = new();
+ private readonly TimeSpan _timeWindow;
+
+ ///
+ /// 创建日志采样过滤器
+ ///
+ /// 采样率(每 N 条日志保留 1 条)
+ /// 时间窗口(在此时间内应用采样)
+ public SamplingFilter(int sampleRate, TimeSpan timeWindow)
+ {
+ if (sampleRate <= 0)
+ throw new ArgumentException("Sample rate must be greater than 0", nameof(sampleRate));
+
+ if (timeWindow <= TimeSpan.Zero)
+ throw new ArgumentException("Time window must be greater than zero", nameof(timeWindow));
+
+ _sampleRate = sampleRate;
+ _timeWindow = timeWindow;
+ }
+
+ ///
+ /// 判断是否应该记录该日志条目
+ ///
+ public bool ShouldLog(LogEntry entry)
+ {
+ // 为每个日志记录器维护独立的采样状态
+ var key = entry.LoggerName;
+ var state = _samplingStates.GetOrAdd(key, _ => new SamplingState());
+
+ return state.ShouldLog(_sampleRate, _timeWindow);
+ }
+
+ ///
+ /// 采样状态
+ ///
+ private sealed class SamplingState
+ {
+ private readonly object _lock = new();
+ private long _count;
+ private DateTime _windowStart = DateTime.UtcNow;
+
+ public bool ShouldLog(int sampleRate, TimeSpan timeWindow)
+ {
+ lock (_lock)
+ {
+ var now = DateTime.UtcNow;
+
+ // 检查是否需要重置时间窗口
+ if (now - _windowStart >= timeWindow)
+ {
+ _windowStart = now;
+ _count = 0;
+ }
+
+ _count++;
+
+ // 每 N 条保留 1 条
+ return _count % sampleRate == 1;
+ }
+ }
+ }
+}
\ No newline at end of file