114 lines
3.7 KiB
C#
114 lines
3.7 KiB
C#
using System.Text.Json;
|
||
using GetFromLoki.Models;
|
||
using Microsoft.Extensions.Options;
|
||
|
||
namespace GetFromLoki.Services;
|
||
|
||
public class LokiService : ILokiService
|
||
{
|
||
private readonly HttpClient _httpClient;
|
||
private readonly LokiOptions _options;
|
||
|
||
public LokiService(HttpClient httpClient, IOptions<LokiOptions> options)
|
||
{
|
||
_httpClient = httpClient;
|
||
_options = options.Value;
|
||
_httpClient.BaseAddress = new Uri(_options.BaseUrl);
|
||
_httpClient.Timeout = TimeSpan.FromSeconds(_options.QueryTimeout);
|
||
}
|
||
|
||
public async Task<List<LogEntry>> GetLogsAsync(LogQueryRequest request)
|
||
{
|
||
var logs = new List<LogEntry>();
|
||
|
||
// Формируем LogQL запрос
|
||
var query = BuildLogQLQuery(request);
|
||
|
||
// Формируем URL с параметрами
|
||
var queryParams = new List<string>
|
||
{
|
||
$"query={Uri.EscapeDataString(query)}",
|
||
$"limit={request.Limit ?? 100}"
|
||
};
|
||
|
||
if (request.StartTime.HasValue)
|
||
{
|
||
var startTimeNs = ((DateTimeOffset)request.StartTime.Value).ToUnixTimeMilliseconds() * 1_000_000;
|
||
queryParams.Add($"start={startTimeNs}");
|
||
}
|
||
|
||
if (request.EndTime.HasValue)
|
||
{
|
||
var endTimeNs = ((DateTimeOffset)request.EndTime.Value).ToUnixTimeMilliseconds() * 1_000_000;
|
||
queryParams.Add($"end={endTimeNs}");
|
||
}
|
||
|
||
var url = $"/loki/api/v1/query_range?{string.Join("&", queryParams)}";
|
||
|
||
try
|
||
{
|
||
var response = await _httpClient.GetAsync(url);
|
||
response.EnsureSuccessStatusCode();
|
||
|
||
var jsonResponse = await response.Content.ReadAsStringAsync();
|
||
var lokiResponse = JsonSerializer.Deserialize<LokiQueryResponse>(
|
||
jsonResponse,
|
||
new JsonSerializerOptions { PropertyNameCaseInsensitive = true }
|
||
);
|
||
|
||
if (lokiResponse?.Data?.Result != null)
|
||
{
|
||
foreach (var result in lokiResponse.Data.Result)
|
||
{
|
||
foreach (var value in result.Values)
|
||
{
|
||
if (value.Count >= 2)
|
||
{
|
||
// Loki возвращает timestamp в наносекундах
|
||
if (long.TryParse(value[0], out var timestampNs))
|
||
{
|
||
var timestamp = DateTimeOffset.FromUnixTimeMilliseconds(timestampNs / 1000000).DateTime;
|
||
logs.Add(new LogEntry
|
||
{
|
||
Timestamp = timestamp,
|
||
Message = value[1]
|
||
});
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
throw new InvalidOperationException($"Ошибка при получении логов из Loki: {ex.Message}", ex);
|
||
}
|
||
|
||
return logs.OrderBy(l => l.Timestamp).ToList();
|
||
}
|
||
|
||
private static string BuildLogQLQuery(LogQueryRequest request)
|
||
{
|
||
var query = "{";
|
||
var conditions = new List<string>();
|
||
|
||
// Добавляем все лейблы
|
||
foreach (var label in request.Labels)
|
||
{
|
||
if (!string.IsNullOrEmpty(label.Value))
|
||
{
|
||
conditions.Add($"{label.Key}=\"{label.Value}\"");
|
||
}
|
||
else
|
||
{
|
||
conditions.Add($"{label.Key}!=\"\"");
|
||
}
|
||
}
|
||
|
||
query += string.Join(",", conditions);
|
||
query += "}";
|
||
|
||
return query;
|
||
}
|
||
}
|