using Microsoft.EntityFrameworkCore; using ROLAC.API.Data.Logging; using ROLAC.API.DTOs.Logging; using ROLAC.API.DTOs.Shared; using ROLAC.API.Entities.Logging; namespace ROLAC.API.Services.Logging; public interface ISystemLogQueryService { Task> GetPagedAsync(SystemLogQuery query); Task GetByIdAsync(long id); } /// Read-only, paged access to the SystemLogs table via the dedicated LogDbContext. public sealed class SystemLogQueryService : ISystemLogQueryService { private readonly LogDbContext _db; public SystemLogQueryService(LogDbContext db) => _db = db; public async Task> GetPagedAsync(SystemLogQuery query) { var page = Math.Max(1, query.Page); var pageSize = Math.Clamp(query.PageSize, 1, 200); var rows = _db.SystemLogs.AsNoTracking().AsQueryable(); if (query.From is not null) rows = rows.Where(l => l.Timestamp >= query.From); if (query.To is not null) rows = rows.Where(l => l.Timestamp <= query.To); if (query.Level is not null) rows = rows.Where(l => l.Level == query.Level); else if (query.MinLevel is not null) rows = rows.Where(l => l.Level >= query.MinLevel); if (!string.IsNullOrWhiteSpace(query.UserId)) rows = rows.Where(l => l.UserId == query.UserId); if (!string.IsNullOrWhiteSpace(query.CorrelationId)) rows = rows.Where(l => l.CorrelationId == query.CorrelationId); if (!string.IsNullOrWhiteSpace(query.Search)) { var term = query.Search.Trim().ToLower(); rows = rows.Where(l => l.Message.ToLower().Contains(term) || l.Category.ToLower().Contains(term)); } var total = await rows.CountAsync(); var items = await rows .OrderByDescending(l => l.Timestamp) .Skip((page - 1) * pageSize).Take(pageSize) .Select(l => new SystemLogListItemDto { Id = l.Id, Timestamp = l.Timestamp, Level = l.Level.ToString(), Category = l.Category, Message = l.Message, HasException = l.Exception != null, StatusCode = l.StatusCode, RequestPath = l.RequestPath, HttpMethod = l.HttpMethod, UserId = l.UserId, CorrelationId = l.CorrelationId, }) .ToListAsync(); return new PagedResult { Items = items, TotalCount = total, Page = page, PageSize = pageSize, }; } public async Task GetByIdAsync(long id) { return await _db.SystemLogs.AsNoTracking() .Where(l => l.Id == id) .Select(l => new SystemLogDetailDto { Id = l.Id, Timestamp = l.Timestamp, Level = l.Level.ToString(), Category = l.Category, Message = l.Message, HasException = l.Exception != null, StatusCode = l.StatusCode, RequestPath = l.RequestPath, HttpMethod = l.HttpMethod, UserId = l.UserId, CorrelationId = l.CorrelationId, EventId = l.EventId, Exception = l.Exception, IpAddress = l.IpAddress, }) .FirstOrDefaultAsync(); } }