149 lines
5.3 KiB
C#
149 lines
5.3 KiB
C#
using System.Diagnostics;
|
||
using System.Diagnostics.Metrics;
|
||
|
||
namespace DramaLing.Api.Services.Monitoring;
|
||
|
||
/// <summary>
|
||
/// 選項詞彙庫服務的效能指標收集
|
||
/// </summary>
|
||
public class OptionsVocabularyMetrics : IDisposable
|
||
{
|
||
private readonly Meter _meter;
|
||
private readonly Counter<long> _generationRequestsCounter;
|
||
private readonly Counter<long> _cacheHitsCounter;
|
||
private readonly Counter<long> _cacheMissesCounter;
|
||
private readonly Histogram<double> _generationDurationHistogram;
|
||
private readonly Histogram<double> _databaseQueryDurationHistogram;
|
||
private readonly Counter<long> _errorCounter;
|
||
// Note: Gauge is not available in .NET 8, using Counter instead
|
||
|
||
public OptionsVocabularyMetrics()
|
||
{
|
||
_meter = new Meter("DramaLing.OptionsVocabulary", "1.0");
|
||
|
||
// 計數器:統計各種事件的次數
|
||
_generationRequestsCounter = _meter.CreateCounter<long>(
|
||
"options_vocabulary_generation_requests_total",
|
||
description: "選項生成請求總數");
|
||
|
||
_cacheHitsCounter = _meter.CreateCounter<long>(
|
||
"options_vocabulary_cache_hits_total",
|
||
description: "快取命中總數");
|
||
|
||
_cacheMissesCounter = _meter.CreateCounter<long>(
|
||
"options_vocabulary_cache_misses_total",
|
||
description: "快取未命中總數");
|
||
|
||
_errorCounter = _meter.CreateCounter<long>(
|
||
"options_vocabulary_errors_total",
|
||
description: "錯誤總數");
|
||
|
||
// 直方圖:測量持續時間分佈
|
||
_generationDurationHistogram = _meter.CreateHistogram<double>(
|
||
"options_vocabulary_generation_duration_ms",
|
||
"ms",
|
||
"選項生成耗時分佈");
|
||
|
||
_databaseQueryDurationHistogram = _meter.CreateHistogram<double>(
|
||
"options_vocabulary_database_query_duration_ms",
|
||
"ms",
|
||
"資料庫查詢耗時分佈");
|
||
|
||
// Note: Gauge not available in .NET 8, functionality moved to logging
|
||
}
|
||
|
||
/// <summary>
|
||
/// 記錄選項生成請求
|
||
/// </summary>
|
||
public void RecordGenerationRequest(string cefrLevel, string partOfSpeech, int requestedCount)
|
||
{
|
||
_generationRequestsCounter.Add(1,
|
||
new KeyValuePair<string, object?>("cefr_level", cefrLevel),
|
||
new KeyValuePair<string, object?>("part_of_speech", partOfSpeech),
|
||
new KeyValuePair<string, object?>("requested_count", requestedCount));
|
||
}
|
||
|
||
/// <summary>
|
||
/// 記錄快取命中
|
||
/// </summary>
|
||
public void RecordCacheHit(string cacheKey)
|
||
{
|
||
_cacheHitsCounter.Add(1,
|
||
new KeyValuePair<string, object?>("cache_key_type", GetCacheKeyType(cacheKey)));
|
||
}
|
||
|
||
/// <summary>
|
||
/// 記錄快取未命中
|
||
/// </summary>
|
||
public void RecordCacheMiss(string cacheKey)
|
||
{
|
||
_cacheMissesCounter.Add(1,
|
||
new KeyValuePair<string, object?>("cache_key_type", GetCacheKeyType(cacheKey)));
|
||
}
|
||
|
||
/// <summary>
|
||
/// 記錄選項生成耗時
|
||
/// </summary>
|
||
public void RecordGenerationDuration(TimeSpan duration, int generatedCount, bool usedFallback = false)
|
||
{
|
||
_generationDurationHistogram.Record(duration.TotalMilliseconds,
|
||
new KeyValuePair<string, object?>("generated_count", generatedCount),
|
||
new KeyValuePair<string, object?>("used_fallback", usedFallback));
|
||
}
|
||
|
||
/// <summary>
|
||
/// 記錄資料庫查詢耗時
|
||
/// </summary>
|
||
public void RecordDatabaseQueryDuration(TimeSpan duration, int resultCount)
|
||
{
|
||
_databaseQueryDurationHistogram.Record(duration.TotalMilliseconds,
|
||
new KeyValuePair<string, object?>("result_count", resultCount));
|
||
}
|
||
|
||
/// <summary>
|
||
/// 記錄錯誤
|
||
/// </summary>
|
||
public void RecordError(string errorType, string? operation = null)
|
||
{
|
||
_errorCounter.Add(1,
|
||
new KeyValuePair<string, object?>("error_type", errorType),
|
||
new KeyValuePair<string, object?>("operation", operation ?? "unknown"));
|
||
}
|
||
|
||
/// <summary>
|
||
/// 更新可用詞彙數量 (使用日誌記錄,因為 Gauge 在 .NET 8 中不可用)
|
||
/// </summary>
|
||
public void UpdateAvailableVocabularyCount(int count, string cefrLevel, string partOfSpeech)
|
||
{
|
||
// Log the vocabulary count instead of using Gauge
|
||
Console.WriteLine($"Available vocabulary count: {count} for {cefrLevel} {partOfSpeech}");
|
||
}
|
||
|
||
/// <summary>
|
||
/// 計算快取命中率
|
||
/// </summary>
|
||
public double CalculateCacheHitRate()
|
||
{
|
||
// 這只是一個簡化的計算,實際應該使用更複雜的統計方法
|
||
// 在生產環境中,應該使用專門的監控系統來計算這些指標
|
||
return 0.0; // 暫時返回0,實際應該從監控系統獲取
|
||
}
|
||
|
||
/// <summary>
|
||
/// 從快取鍵提取類型
|
||
/// </summary>
|
||
private static string GetCacheKeyType(string cacheKey)
|
||
{
|
||
if (cacheKey.StartsWith("vocab_distractors:"))
|
||
return "distractors";
|
||
if (cacheKey.StartsWith("vocab_count:"))
|
||
return "count";
|
||
return "unknown";
|
||
}
|
||
|
||
public void Dispose()
|
||
{
|
||
_meter.Dispose();
|
||
GC.SuppressFinalize(this);
|
||
}
|
||
} |