dramaling-vocab-learning/backend/DramaLing.Api/Services/Infrastructure/Monitoring/OptionsVocabularyMetrics.cs

149 lines
5.3 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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