Skip to content

Commit 8bda8fd

Browse files
author
Timothy Dodd
committed
Add new API endpoints and settings page for log management
Updated LogController to include endpoints for deployment and pod summaries, and added a purge logs endpoint. Implemented new methods in LogRepo and LogSummaryRepo for log purging by deployment and pod with time range filtering. Updated project dependencies and improved component styles. Created a new settings page for managing pod logs, including UI and logic for selecting pods and confirming log purges. Added unit tests for the settings page component.
1 parent 41948b1 commit 8bda8fd

21 files changed

Lines changed: 1578 additions & 486 deletions

src/LogMkApi/Controllers/LogController.cs

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -390,6 +390,112 @@ public async Task<IEnumerable<Pod>> GetPods()
390390
var entries = await _logRepo.GetPods();
391391
return entries;
392392
}
393+
394+
[HttpGet("deployment-summaries")]
395+
public async Task<IActionResult> GetDeploymentSummaries()
396+
{
397+
try
398+
{
399+
var summaries = await _logSummaryRepo.GetDeploymentSummaries();
400+
return Ok(summaries);
401+
}
402+
catch (Exception ex)
403+
{
404+
_logger.LogError(ex, "Error getting deployment summaries");
405+
return StatusCode(500, new { Error = "Failed to retrieve deployment summaries" });
406+
}
407+
}
408+
409+
[HttpGet("pod-summaries")]
410+
public async Task<IActionResult> GetPodSummaries()
411+
{
412+
try
413+
{
414+
var summaries = await _logSummaryRepo.GetPodSummaries();
415+
return Ok(summaries);
416+
}
417+
catch (Exception ex)
418+
{
419+
_logger.LogError(ex, "Error getting pod summaries");
420+
return StatusCode(500, new { Error = "Failed to retrieve pod summaries" });
421+
}
422+
}
423+
424+
[HttpPost("purge")]
425+
public async Task<IActionResult> PurgeLogs([FromBody] PurgeLogsRequest request)
426+
{
427+
// Support both deployment and pod-based purging for backward compatibility
428+
if (string.IsNullOrWhiteSpace(request?.Deployment) && string.IsNullOrWhiteSpace(request?.Pod))
429+
{
430+
return BadRequest(new { Error = "Either deployment name or pod name is required" });
431+
}
432+
433+
try
434+
{
435+
var identifier = !string.IsNullOrWhiteSpace(request.Pod) ? request.Pod : request.Deployment;
436+
var identifierType = !string.IsNullOrWhiteSpace(request.Pod) ? "pod" : "deployment";
437+
438+
_logger.LogInformation("Purging logs for {IdentifierType} {Identifier} with time range {TimeRange}",
439+
identifierType, identifier, request.TimeRange);
440+
441+
// Calculate the date filter based on time range
442+
DateTime? startDate = null;
443+
switch (request.TimeRange?.ToLower())
444+
{
445+
case "hour":
446+
startDate = DateTime.UtcNow.AddHours(-1);
447+
break;
448+
case "day":
449+
startDate = DateTime.UtcNow.AddDays(-1);
450+
break;
451+
case "week":
452+
startDate = DateTime.UtcNow.AddDays(-7);
453+
break;
454+
case "month":
455+
startDate = DateTime.UtcNow.AddMonths(-1);
456+
break;
457+
case "all":
458+
default:
459+
startDate = null;
460+
break;
461+
}
462+
463+
int deletedLogsCount;
464+
465+
if (!string.IsNullOrWhiteSpace(request.Pod))
466+
{
467+
// Pod-based purging
468+
deletedLogsCount = await _logRepo.PurgeLogsByPod(request.Pod, startDate);
469+
await _logSummaryRepo.PurgeByPod(request.Pod, startDate);
470+
await _logSummaryRepo.PurgeHourlyByPod(request.Pod, startDate);
471+
}
472+
else
473+
{
474+
// Deployment-based purging (backward compatibility)
475+
deletedLogsCount = await _logRepo.PurgeLogsByDeployment(request.Deployment, startDate);
476+
await _logSummaryRepo.PurgeByDeployment(request.Deployment, startDate);
477+
await _logSummaryRepo.PurgeHourlyByDeployment(request.Deployment, startDate);
478+
}
479+
480+
_logger.LogInformation("Successfully purged {Count} logs for {IdentifierType} {Identifier}",
481+
deletedLogsCount, identifierType, identifier);
482+
483+
return Ok(new
484+
{
485+
Success = true,
486+
DeletedCount = deletedLogsCount,
487+
Deployment = request.Deployment,
488+
Pod = request.Pod,
489+
TimeRange = request.TimeRange
490+
});
491+
}
492+
catch (Exception ex)
493+
{
494+
var identifier = !string.IsNullOrWhiteSpace(request?.Pod) ? request.Pod : request?.Deployment;
495+
_logger.LogError(ex, "Error purging logs for {Identifier}", identifier);
496+
return StatusCode(500, new { Error = "Failed to purge logs" });
497+
}
498+
}
393499
}
394500

395501

@@ -419,3 +525,10 @@ public class LogValidationResult
419525
public bool IsValid { get; set; }
420526
public string[] Errors { get; set; } = Array.Empty<string>();
421527
}
528+
529+
public class PurgeLogsRequest
530+
{
531+
public string Deployment { get; set; } = string.Empty;
532+
public string Pod { get; set; } = string.Empty;
533+
public string TimeRange { get; set; } = "all";
534+
}

src/LogMkApi/Data/LogRepo.cs

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,5 +141,43 @@ FROM Log
141141
}
142142
}
143143

144+
public async Task<int> PurgeLogsByDeployment(string deployment, DateTime? startDate)
145+
{
146+
using (var db = _dbFactory.OpenDbConnection())
147+
{
148+
var query = new StringBuilder("DELETE FROM Log WHERE Deployment = @deployment");
149+
var parameters = new DynamicParameters();
150+
parameters.Add("deployment", deployment);
151+
152+
if (startDate.HasValue)
153+
{
154+
query.Append(" AND TimeStamp >= @startDate");
155+
parameters.Add("startDate", startDate.Value);
156+
}
157+
158+
var deletedCount = await db.ExecuteAsync(query.ToString(), parameters);
159+
return deletedCount;
160+
}
161+
}
162+
163+
public async Task<int> PurgeLogsByPod(string pod, DateTime? startDate)
164+
{
165+
using (var db = _dbFactory.OpenDbConnection())
166+
{
167+
var query = new StringBuilder("DELETE FROM Log WHERE Pod = @pod");
168+
var parameters = new DynamicParameters();
169+
parameters.Add("pod", pod);
170+
171+
if (startDate.HasValue)
172+
{
173+
query.Append(" AND TimeStamp >= @startDate");
174+
parameters.Add("startDate", startDate.Value);
175+
}
176+
177+
var deletedCount = await db.ExecuteAsync(query.ToString(), parameters);
178+
return deletedCount;
179+
}
180+
}
181+
144182

145183
}

src/LogMkApi/Data/LogSummaryRepo.cs

Lines changed: 146 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
using LogMkApi.Common;
1+
using System.Text;
2+
using LogMkApi.Common;
23
using ServiceStack.Data;
34
using ServiceStack.OrmLite.Dapper;
45
using static ServiceStack.OrmLite.Dapper.SqlMapper;
@@ -118,6 +119,150 @@ ORDER BY
118119
}
119120
}
120121

122+
public async Task<IEnumerable<dynamic>> GetDeploymentSummaries()
123+
{
124+
using (var db = _dbFactory.OpenDbConnection())
125+
{
126+
var query = @"
127+
SELECT
128+
Deployment,
129+
SUM(Count) as TotalCount,
130+
LogDate as Date,
131+
SUM(Count) as DailyCount
132+
FROM LogSummary
133+
WHERE LogDate >= DATE_SUB(CURDATE(), INTERVAL 7 DAY)
134+
GROUP BY Deployment, LogDate
135+
ORDER BY Deployment, LogDate DESC
136+
";
137+
138+
var results = await db.QueryAsync<dynamic>(query);
139+
140+
// Group by deployment and format the response
141+
var grouped = results.GroupBy(r => r.Deployment)
142+
.Select(g => new
143+
{
144+
deployment = g.Key,
145+
totalCount = g.Sum(x => (long)x.DailyCount),
146+
dailyCounts = g.Select(x => new
147+
{
148+
date = ((DateTime)x.Date).ToString("yyyy-MM-dd"),
149+
count = (long)x.DailyCount
150+
}).Take(7).ToList()
151+
});
152+
153+
return grouped;
154+
}
155+
}
156+
157+
public async Task<IEnumerable<dynamic>> GetPodSummaries()
158+
{
159+
using (var db = _dbFactory.OpenDbConnection())
160+
{
161+
var query = @"
162+
SELECT
163+
Pod,
164+
Deployment,
165+
SUM(Count) as TotalCount,
166+
LogDate as Date,
167+
SUM(Count) as DailyCount
168+
FROM LogSummary
169+
WHERE LogDate >= DATE_SUB(CURDATE(), INTERVAL 7 DAY)
170+
GROUP BY Pod, Deployment, LogDate
171+
ORDER BY Pod, LogDate DESC
172+
";
173+
174+
var results = await db.QueryAsync<dynamic>(query);
175+
176+
// Group by pod and format the response
177+
var grouped = results.GroupBy(r => r.Pod)
178+
.Select(g => new
179+
{
180+
pod = g.Key,
181+
deployment = g.First().Deployment,
182+
totalCount = g.Sum(x => (long)x.DailyCount),
183+
dailyCounts = g.Select(x => new
184+
{
185+
date = ((DateTime)x.Date).ToString("yyyy-MM-dd"),
186+
count = (long)x.DailyCount
187+
}).Take(7).ToList()
188+
});
189+
190+
return grouped;
191+
}
192+
}
193+
194+
public async Task PurgeByDeployment(string deployment, DateTime? startDate)
195+
{
196+
using (var db = _dbFactory.OpenDbConnection())
197+
{
198+
var query = new StringBuilder("DELETE FROM LogSummary WHERE Deployment = @deployment");
199+
var parameters = new DynamicParameters();
200+
parameters.Add("deployment", deployment);
201+
202+
if (startDate.HasValue)
203+
{
204+
query.Append(" AND LogDate >= @startDate");
205+
parameters.Add("startDate", startDate.Value.Date);
206+
}
207+
208+
await db.ExecuteAsync(query.ToString(), parameters);
209+
}
210+
}
211+
212+
public async Task PurgeHourlyByDeployment(string deployment, DateTime? startDate)
213+
{
214+
using (var db = _dbFactory.OpenDbConnection())
215+
{
216+
var query = new StringBuilder("DELETE FROM LogSummaryHour WHERE Deployment = @deployment");
217+
var parameters = new DynamicParameters();
218+
parameters.Add("deployment", deployment);
219+
220+
if (startDate.HasValue)
221+
{
222+
query.Append(" AND LogDate >= @startDate");
223+
parameters.Add("startDate", startDate.Value.Date);
224+
}
225+
226+
await db.ExecuteAsync(query.ToString(), parameters);
227+
}
228+
}
229+
230+
public async Task PurgeByPod(string pod, DateTime? startDate)
231+
{
232+
using (var db = _dbFactory.OpenDbConnection())
233+
{
234+
var query = new StringBuilder("DELETE FROM LogSummary WHERE Pod = @pod");
235+
var parameters = new DynamicParameters();
236+
parameters.Add("pod", pod);
237+
238+
if (startDate.HasValue)
239+
{
240+
query.Append(" AND LogDate >= @startDate");
241+
parameters.Add("startDate", startDate.Value.Date);
242+
}
243+
244+
await db.ExecuteAsync(query.ToString(), parameters);
245+
}
246+
}
247+
248+
public async Task PurgeHourlyByPod(string pod, DateTime? startDate)
249+
{
250+
using (var db = _dbFactory.OpenDbConnection())
251+
{
252+
var query = new StringBuilder("DELETE FROM LogSummaryHour WHERE Pod = @pod");
253+
var parameters = new DynamicParameters();
254+
parameters.Add("pod", pod);
255+
256+
if (startDate.HasValue)
257+
{
258+
query.Append(" AND LogDate >= @startDate");
259+
parameters.Add("startDate", startDate.Value.Date);
260+
}
261+
262+
await db.ExecuteAsync(query.ToString(), parameters);
263+
}
264+
}
265+
121266

122267
}
123268

src/LogMkApi/LogMkApi.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616

1717
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="9.0.7" />
1818
<PackageReference Include="Microsoft.Extensions.Diagnostics.HealthChecks" Version="9.0.7" />
19-
<PackageReference Include="MySql.Data" Version="9.3.0" />
19+
<PackageReference Include="MySql.Data" Version="9.4.0" />
2020
<PackageReference Include="ServiceStack.OrmLite.MySql" Version="8.8.0" />
2121
<PackageReference Include="System.Text.Json" Version="9.0.7" />
2222
<PackageReference Include="Microsoft.AspNetCore.SpaProxy">

0 commit comments

Comments
 (0)