193 lines
6.8 KiB
C#
193 lines
6.8 KiB
C#
using EonaCat.Logger.Server.Data;
|
|
using EonaCat.Logger.Server.Models;
|
|
using Microsoft.EntityFrameworkCore;
|
|
using Microsoft.Extensions.Caching.Memory;
|
|
using System.Text.Json;
|
|
|
|
namespace EonaCat.Logger.Server.Services;
|
|
|
|
public class LogService : ILogService
|
|
{
|
|
private readonly LoggerDbContext _context;
|
|
private readonly IMemoryCache _cache;
|
|
|
|
public LogService(LoggerDbContext context, IMemoryCache cache)
|
|
{
|
|
_context = context;
|
|
_cache = cache;
|
|
}
|
|
|
|
public async Task AddLogsAsync(List<LogEntry> entries)
|
|
{
|
|
await _context.LogEntries.AddRangeAsync(entries);
|
|
await _context.SaveChangesAsync();
|
|
_cache.Remove("stats");
|
|
}
|
|
|
|
public async Task<LogEntry?> GetLogByIdAsync(string id)
|
|
{
|
|
return await _context.LogEntries.FindAsync(id);
|
|
}
|
|
|
|
public async Task<PagedResult<LogEntry>> GetLogsAsync(LogQueryParams queryParams)
|
|
{
|
|
var query = _context.LogEntries.AsQueryable();
|
|
|
|
if (!string.IsNullOrEmpty(queryParams.Search))
|
|
{
|
|
var search = queryParams.Search.ToLower();
|
|
query = query.Where(l =>
|
|
l.Message.ToLower().Contains(search) ||
|
|
(l.Exception != null && l.Exception.ToLower().Contains(search)) ||
|
|
l.Category.ToLower().Contains(search) ||
|
|
l.ApplicationName.ToLower().Contains(search));
|
|
}
|
|
|
|
if (!string.IsNullOrEmpty(queryParams.Application))
|
|
query = query.Where(l => l.ApplicationName == queryParams.Application);
|
|
|
|
if (!string.IsNullOrEmpty(queryParams.Environment))
|
|
query = query.Where(l => l.Environment == queryParams.Environment);
|
|
|
|
if (!string.IsNullOrEmpty(queryParams.Category))
|
|
query = query.Where(l => l.Category == queryParams.Category);
|
|
|
|
if (queryParams.Level.HasValue)
|
|
query = query.Where(l => l.Level == queryParams.Level.Value);
|
|
|
|
if (queryParams.StartDate.HasValue)
|
|
query = query.Where(l => l.Timestamp >= queryParams.StartDate.Value);
|
|
|
|
if (queryParams.EndDate.HasValue)
|
|
query = query.Where(l => l.Timestamp <= queryParams.EndDate.Value);
|
|
|
|
if (!string.IsNullOrEmpty(queryParams.UserId))
|
|
query = query.Where(l => l.UserId == queryParams.UserId);
|
|
|
|
if (!string.IsNullOrEmpty(queryParams.CorrelationId))
|
|
query = query.Where(l => l.CorrelationId == queryParams.CorrelationId);
|
|
|
|
var totalCount = await query.CountAsync();
|
|
|
|
query = queryParams.SortOrder?.ToLower() == "asc"
|
|
? query.OrderBy(l => l.Timestamp)
|
|
: query.OrderByDescending(l => l.Timestamp);
|
|
|
|
var items = await query
|
|
.Skip((queryParams.Page - 1) * queryParams.PageSize)
|
|
.Take(queryParams.PageSize)
|
|
.ToListAsync();
|
|
|
|
return new PagedResult<LogEntry>
|
|
{
|
|
Items = items,
|
|
TotalCount = totalCount,
|
|
Page = queryParams.Page,
|
|
PageSize = queryParams.PageSize
|
|
};
|
|
}
|
|
|
|
public async Task<Dictionary<string, object>> GetStatsAsync(string? app, string? env)
|
|
{
|
|
var cacheKey = $"stats_{app}_{env}";
|
|
if (_cache.TryGetValue(cacheKey, out Dictionary<string, object>? cachedStats))
|
|
return cachedStats!;
|
|
|
|
var query = _context.LogEntries.AsQueryable();
|
|
|
|
if (!string.IsNullOrEmpty(app))
|
|
query = query.Where(l => l.ApplicationName == app);
|
|
|
|
if (!string.IsNullOrEmpty(env))
|
|
query = query.Where(l => l.Environment == env);
|
|
|
|
var last24Hours = DateTime.UtcNow.AddHours(-24);
|
|
var lastHour = DateTime.UtcNow.AddHours(-1);
|
|
|
|
var stats = new Dictionary<string, object>
|
|
{
|
|
["totalLogs"] = await query.CountAsync(),
|
|
["last24Hours"] = await query.Where(l => l.Timestamp >= last24Hours).CountAsync(),
|
|
["lastHour"] = await query.Where(l => l.Timestamp >= lastHour).CountAsync(),
|
|
["errorCount"] = await query.Where(l => l.Level >= 4).CountAsync(),
|
|
["warningCount"] = await query.Where(l => l.Level == 3).CountAsync(),
|
|
["criticalCount"] = await query.Where(l => l.Level == 5).CountAsync(),
|
|
["securityCount"] = await query.Where(l => l.Level == 6).CountAsync(),
|
|
["applications"] = await _context.LogEntries.Select(l => l.ApplicationName).Distinct().CountAsync(),
|
|
["byLevel"] = await query
|
|
.GroupBy(l => l.Level)
|
|
.Select(g => new { Level = g.Key, Count = g.Count() })
|
|
.ToListAsync(),
|
|
["topErrors"] = await query
|
|
.Where(l => l.Level >= 4 && l.Timestamp >= last24Hours)
|
|
.GroupBy(l => l.Message)
|
|
.Select(g => new { Message = g.Key, Count = g.Count() })
|
|
.OrderByDescending(x => x.Count)
|
|
.Take(5)
|
|
.ToListAsync(),
|
|
["topApplications"] = await query
|
|
.Where(l => l.Timestamp >= last24Hours)
|
|
.GroupBy(l => l.ApplicationName)
|
|
.Select(g => new { Application = g.Key, Count = g.Count() })
|
|
.OrderByDescending(x => x.Count)
|
|
.Take(5)
|
|
.ToListAsync()
|
|
};
|
|
|
|
_cache.Set(cacheKey, stats, TimeSpan.FromSeconds(30));
|
|
return stats;
|
|
}
|
|
|
|
public async Task<bool> ValidateApiKeyAsync(string apiKey)
|
|
{
|
|
return await _context.Applications.AnyAsync(a => a.ApiKey == apiKey && a.IsActive);
|
|
}
|
|
|
|
public async Task<List<string>> GetApplicationsAsync()
|
|
{
|
|
return await _context.LogEntries
|
|
.Select(l => l.ApplicationName)
|
|
.Distinct()
|
|
.OrderBy(a => a)
|
|
.ToListAsync();
|
|
}
|
|
|
|
public async Task<List<string>> GetEnvironmentsAsync()
|
|
{
|
|
return await _context.LogEntries
|
|
.Select(l => l.Environment)
|
|
.Distinct()
|
|
.OrderBy(e => e)
|
|
.ToListAsync();
|
|
}
|
|
|
|
public async Task<List<TrendPoint>> GetLogTrendAsync(int hours)
|
|
{
|
|
var startTime = DateTime.UtcNow.AddHours(-hours);
|
|
var interval = hours > 24 ? 60 : hours > 6 ? 30 : 15;
|
|
|
|
var logs = await _context.LogEntries
|
|
.Where(l => l.Timestamp >= startTime)
|
|
.ToListAsync();
|
|
|
|
var trend = logs
|
|
.GroupBy(l => new DateTime(
|
|
l.Timestamp.Year,
|
|
l.Timestamp.Month,
|
|
l.Timestamp.Day,
|
|
l.Timestamp.Hour,
|
|
(l.Timestamp.Minute / interval) * interval,
|
|
0))
|
|
.Select(g => new TrendPoint
|
|
{
|
|
Timestamp = g.Key,
|
|
Count = g.Count(),
|
|
ByLevel = g.GroupBy(l => l.Level)
|
|
.ToDictionary(lg => lg.Key, lg => lg.Count())
|
|
})
|
|
.OrderBy(t => t.Timestamp)
|
|
.ToList();
|
|
|
|
return trend;
|
|
}
|
|
} |