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