This commit is contained in:
2026-01-08 15:18:34 +01:00
parent d385119ca2
commit 33a0b77bf1
111 changed files with 85489 additions and 24 deletions

View File

@@ -0,0 +1,37 @@
using LogCentral.Server.Data;
using LogCentral.Server.Services;
using Microsoft.EntityFrameworkCore;
public interface IAnalyticsService
{
Task<Dictionary<string, object>> GetAnalyticsAsync(DateTime startDate, DateTime endDate);
}
public class AnalyticsService : IAnalyticsService
{
private readonly LogCentralDbContext _context;
public AnalyticsService(LogCentralDbContext context)
{
_context = context;
}
public async Task<Dictionary<string, object>> GetAnalyticsAsync(DateTime startDate, DateTime endDate)
{
var logs = await _context.LogEntries
.Where(l => l.Timestamp >= startDate && l.Timestamp <= endDate)
.ToListAsync();
return new Dictionary<string, object>
{
["totalEvents"] = logs.Count(l => l.Level == 7),
["topEvents"] = logs
.Where(l => l.Level == 7)
.GroupBy(l => l.Message)
.Select(g => new { Event = g.Key, Count = g.Count() })
.OrderByDescending(x => x.Count)
.Take(10)
.ToList()
};
}
}

View File

@@ -0,0 +1,33 @@
using LogCentral.Server.Models;
namespace LogCentral.Server.Services;
public interface ILogService
{
Task AddLogsAsync(List<LogEntry> entries);
Task<LogEntry?> GetLogByIdAsync(string id);
Task<PagedResult<LogEntry>> GetLogsAsync(LogQueryParams queryParams);
Task<Dictionary<string, object>> GetStatsAsync(string? app, string? env);
Task<bool> ValidateApiKeyAsync(string apiKey);
}
public class LogQueryParams
{
public string? Search { get; set; }
public string? Application { get; set; }
public string? Environment { get; set; }
public int? Level { get; set; }
public DateTime? StartDate { get; set; }
public DateTime? EndDate { get; set; }
public int Page { get; set; } = 1;
public int PageSize { get; set; } = 50;
}
public class PagedResult<T>
{
public List<T> Items { get; set; } = new();
public int TotalCount { get; set; }
public int Page { get; set; }
public int PageSize { get; set; }
public int TotalPages => (int)Math.Ceiling((double)TotalCount / PageSize);
}

View File

@@ -0,0 +1,30 @@
using LogCentral.Server.Data;
using LogCentral.Server.Models;
using Microsoft.EntityFrameworkCore;
namespace LogCentral.Server.Services;
public interface ISearchService
{
Task<List<LogEntry>> SearchAsync(string query, int limit = 100);
}
public class SearchService : ISearchService
{
private readonly LogCentralDbContext _context;
public SearchService(LogCentralDbContext context)
{
_context = context;
}
public async Task<List<LogEntry>> SearchAsync(string query, int limit = 100)
{
return await _context.LogEntries
.Where(l => EF.Functions.Like(l.Message, $"%{query}%") ||
EF.Functions.Like(l.Exception ?? "", $"%{query}%"))
.OrderByDescending(l => l.Timestamp)
.Take(limit)
.ToListAsync();
}
}

View File

@@ -0,0 +1,106 @@
using Microsoft.EntityFrameworkCore;
using LogCentral.Server.Data;
using LogCentral.Server.Models;
using System.Text.Json;
namespace LogCentral.Server.Services;
public class LogService : ILogService
{
private readonly LogCentralDbContext _context;
public LogService(LogCentralDbContext context)
{
_context = context;
}
public async Task AddLogsAsync(List<LogEntry> entries)
{
await _context.LogEntries.AddRangeAsync(entries);
await _context.SaveChangesAsync();
}
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))
{
query = query.Where(l =>
l.Message.Contains(queryParams.Search) ||
l.Exception!.Contains(queryParams.Search) ||
l.Category.Contains(queryParams.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 (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);
var totalCount = await query.CountAsync();
var items = await query
.OrderByDescending(l => l.Timestamp)
.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 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 stats = new Dictionary<string, object>
{
["totalLogs"] = await query.CountAsync(),
["last24Hours"] = await query.Where(l => l.Timestamp >= last24Hours).CountAsync(),
["errorCount"] = await query.Where(l => l.Level >= 4).CountAsync(),
["warningCount"] = await query.Where(l => l.Level == 3).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()
};
return stats;
}
public async Task<bool> ValidateApiKeyAsync(string apiKey)
{
return await _context.Applications
.AnyAsync(a => a.ApiKey == apiKey && a.IsActive);
}
}