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);
}
}