Code · 42 lines · 1410 bytes
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42using StackExchange.Redis;
using System.Text.Json;

namespace VanDerHeijden.Logging.Redis;

/// <summary>
/// Writes log entries to a Redis list using RPUSH.
/// Each entry is serialized as JSON. The list grows indefinitely unless
/// a consumer (e.g. Logstash, a worker service) drains it via LPOP/BLPOP.
/// Optionally a TTL can be set to auto-expire the key.
/// </summary>
public sealed class RedisLogWriter(
	IDatabase database,
	string listKey = "logs",
	TimeSpan? ttl = null) : IBatchedLogWriter<RedisLogEntry>
{
	private static readonly JsonSerializerOptions JsonOptions = new()
	{
		PropertyNamingPolicy = JsonNamingPolicy.CamelCase
	};

	/// <summary>
	/// Serializes all entries as JSON and appends them to the Redis list in a single <c>RPUSH</c> command.
	/// If a TTL is configured, <c>EXPIREAT</c> is applied to the key after each write.
	/// </summary>
	/// <param name="entries">The log entries to push.</param>
	/// <param name="ct">A token that can cancel the operation.</param>
	public async Task WriteBatchAsync(List<RedisLogEntry> entries, CancellationToken ct)
	{
		var values = entries
			.Select(e => (RedisValue)JsonSerializer.Serialize(e, JsonOptions))
			.ToArray();

		await database.ListRightPushAsync(listKey, values);

		if (ttl.HasValue)
			await database.KeyExpireAsync(listKey, ttl.Value);
	}

	/// <inheritdoc/>
	public ValueTask DisposeAsync() => ValueTask.CompletedTask;
}