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 options) { _httpClient = httpClient; _options = options.Value; _httpClient.BaseAddress = new Uri(_options.BaseUrl); _httpClient.Timeout = TimeSpan.FromSeconds(_options.QueryTimeout); } public async Task> GetLogsAsync(LogQueryRequest request) { var logs = new List(); // Формируем LogQL запрос var query = BuildLogQLQuery(request); // Формируем URL с параметрами var queryParams = new List { $"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( 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(); // Добавляем все лейблы 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; } }