Skip to content

Commit b1efc4f

Browse files
committed
Added Retention
1 parent fe7e3b0 commit b1efc4f

2 files changed

Lines changed: 93 additions & 10 deletions

File tree

Apps/QueryLogsDuckDBApp/App.cs

Lines changed: 88 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -49,15 +49,12 @@ public sealed class App : IDnsApplication, IDnsQueryLogger, IDnsQueryLogs
4949

5050
[ThreadStatic]
5151
private static StringBuilder? _sb;
52-
Config _config;
53-
5452
private Channel<LogEntry>? _channel;
53+
Config? _config;
5554
private DuckDBConnection? _conn;
5655
private Task? _consumerTask;
5756
private bool _disposed;
5857
private IDnsServer? _dnsServer;
59-
private bool _enableLogging;
60-
private int _maxQueueSize; // Maximum number of log entries in the queue, default 200,000
6158
#endregion variables
6259

6360
#region IDisposable
@@ -248,6 +245,83 @@ private async Task ProcessLogsAsync()
248245
BulkInsert(batch);
249246
}
250247

248+
private async Task RetentionLoopAsync()
249+
{
250+
// Initial delay
251+
await Task.Delay(TimeSpan.FromMinutes(1));
252+
253+
while (!_disposed)
254+
{
255+
try
256+
{
257+
await RunRetentionAsync();
258+
}
259+
catch (Exception ex)
260+
{
261+
_dnsServer?.WriteLog(ex);
262+
}
263+
264+
await Task.Delay(TimeSpan.FromMinutes(15));
265+
}
266+
}
267+
268+
private async Task RunRetentionAsync()
269+
{
270+
if (_conn is null || _config is null)
271+
return;
272+
273+
using DuckDBCommand cmd = _conn.CreateCommand();
274+
275+
long deleted = 0;
276+
277+
/* ---------------------------------
278+
Max records
279+
--------------------------------- */
280+
281+
if (_config.MaxLogRecords > 0)
282+
{
283+
cmd.CommandText = @"
284+
DELETE FROM dns_logs
285+
WHERE timestamp NOT IN (
286+
SELECT timestamp
287+
FROM dns_logs
288+
ORDER BY timestamp DESC
289+
LIMIT $limit
290+
);";
291+
292+
cmd.Parameters.Clear();
293+
cmd.Parameters.Add(
294+
new DuckDBParameter("limit", _config.MaxLogRecords));
295+
296+
deleted += await cmd.ExecuteNonQueryAsync();
297+
}
298+
299+
/* ---------------------------------
300+
Max days
301+
--------------------------------- */
302+
303+
if (_config.MaxLogDays > 0)
304+
{
305+
DateTime cutoff =
306+
DateTime.UtcNow.AddDays(-_config.MaxLogDays);
307+
308+
cmd.CommandText =
309+
"DELETE FROM dns_logs WHERE timestamp < $cutoff;";
310+
311+
cmd.Parameters.Clear();
312+
cmd.Parameters.Add(
313+
new DuckDBParameter("cutoff", cutoff));
314+
315+
deleted += await cmd.ExecuteNonQueryAsync();
316+
}
317+
318+
if (deleted > 0)
319+
{
320+
cmd.Parameters.Clear();
321+
cmd.CommandText = "CHECKPOINT;";
322+
await cmd.ExecuteNonQueryAsync();
323+
}
324+
}
251325
#endregion private
252326

253327
#region public
@@ -258,6 +332,7 @@ public async Task InitializeAsync(IDnsServer dnsServer, string config)
258332

259333
JsonSerializerOptions options = new JsonSerializerOptions { PropertyNameCaseInsensitive = true };
260334
_config = JsonSerializer.Deserialize<Config>(config, options);
335+
_config ??= new Config();
261336
Validator.ValidateObject(_config, new ValidationContext(_config), validateAllProperties: true);
262337

263338
if (!System.IO.Path.IsPathRooted(_config.DbPath))
@@ -276,6 +351,7 @@ public async Task InitializeAsync(IDnsServer dnsServer, string config)
276351
await CreateSchemaAsync();
277352

278353
_consumerTask = Task.Run(ProcessLogsAsync);
354+
_ = Task.Run(RetentionLoopAsync);
279355
}
280356

281357
public Task InsertLogAsync(
@@ -285,7 +361,7 @@ public Task InsertLogAsync(
285361
DnsTransportProtocol protocol,
286362
DnsDatagram response)
287363
{
288-
if (_config.EnableLogging)
364+
if (_config!.EnableLogging)
289365
_channel!.Writer.TryWrite(
290366
new LogEntry(timestamp, request, remoteEP, protocol, response));
291367

@@ -588,11 +664,16 @@ public LogEntry(DateTime timestamp, DnsDatagram request, IPEndPoint remoteEP, Dn
588664

589665
private class Config
590666
{
667+
[JsonPropertyName("dbPath")]
668+
public string DbPath { get; set; } = "querylogs.db";
669+
591670
[JsonPropertyName("enableLogging")]
592671
public bool EnableLogging { get; set; } = true;
672+
[JsonPropertyName("maxLogDays")]
673+
public int MaxLogDays { get; set; } = 30;
593674

594-
[JsonPropertyName("dbPath")]
595-
public string DbPath { get; set; } = "querylogs.db";
675+
[JsonPropertyName("maxLogRecords")]
676+
public long MaxLogRecords { get; set; } = 1_000_000;
596677

597678
[JsonPropertyName("maxQueueSize")]
598679
public int MaxQueueSize { get; set; } = 200_000;
Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
{
2-
"enableLogging": true,
3-
"dbPath": "querylogs.db",
4-
"maxQueueSize": 200000
2+
"enableLogging": true,
3+
"dbPath": "querylogs.db",
4+
"maxQueueSize": 200000,
5+
"maxLogDays:" 30,
6+
"maxLogRecords": 1000000
57
}

0 commit comments

Comments
 (0)