Skip to main content

Valkey command logs

Valkey 8.1+ exposes three independent node-local command logs. Respire's Server facet provides CommandLogAsync, CommandLogLengthAsync, and ResetCommandLogAsync, plus explicit OnAllNodesAsync counterparts. Existing Redis SlowLogAsync behavior is unchanged. Redis servers without COMMANDLOG return their command errors; there is no fallback.

RespireCommandLogTypeMeasurementThreshold configurationRetention configuration
SlowExecution microseconds, excluding client I/Ocommandlog-execution-slower-thancommandlog-slow-execution-max-len
LargeRequestRequest bytescommandlog-request-larger-thancommandlog-large-request-max-len
LargeReplyReply bytescommandlog-reply-larger-thancommandlog-large-reply-max-len

Threshold -1 disables the selected log; 0 records every eligible command. Larger retention limits consume more server memory. These APIs do not change thresholds or retention automatically. See Valkey's GET and LEN references.

var entries = await redis.Server.CommandLogAsync(RespireCommandLogType.LargeReply, count: 20);
foreach (var entry in entries)
Console.WriteLine($"{entry.Id}: {entry.ReplyBytes} bytes at {entry.TimestampUnixSeconds}");

Each owned entry includes its type, ID, Unix timestamp in seconds, raw metric, binary arguments, and binary client address/name. DurationMicroseconds, RequestBytes, and ReplyBytes expose only the applicable measurement; the others are null. Select log-specific measurements by Type; the nullable views make units explicit at the cost of a null check, while MetricValue remains available for generic tooling. Unknown trailing fields remain in recursively copied AdditionalValues. Those GC-owned RespireResult values need no disposal; explicitly disposing one invalidates its views. Replies remain usable after the client is disposed.

Count defaults to 10; -1 requests all retained entries and 0 returns none. Values below -1 and undefined log types fail before I/O. Results preserve server order. Pinned Valkey 8.1.3 returns newest first, verified against its implementation. IDs are scoped to a node and log type; resetting a log does not reset its ID sequence.

The server bounds recorded argument counts and lengths and can omit or redact sensitive commands. Respire preserves the returned bytes; it cannot reconstruct the original command or guarantee that logs contain no secrets. Retrieval can transfer large payloads; count: -1 is unbounded by the client. Prefer a count appropriate to the workload.

Scope and resets​

Ordinary calls use one execution node. With UseCluster, all-node discovery includes replicas and slotless members; otherwise it queries only the connected endpoint. Each result carries its endpoint and either a value or the original error. Discovery requires CLUSTER NODES permission. Views can overlap; results are not deduplicated.

var results = await redis.Server.CommandLogLengthOnAllNodesAsync(RespireCommandLogType.Slow);
foreach (var result in results)
{
if (result.IsSuccess) Console.WriteLine($"{result.Endpoint}: {result.Value}");
else Console.WriteLine($"{result.Endpoint}: {result.Error!.Message}");
}

Inspection does not require AllowAdmin locally; server ACLs still apply. RESET requires AllowAdmin before I/O and permanently clears the selected log. Explicit all-node resets can partially succeed, return true for each successful node, and offer no rollback or automatic replication. Reset costs grow with retained entries; see COMMANDLOG RESET.

Pre-cancelled calls send nothing. Discovery cancellation throws; cancellation after discovery is reported per affected node. Cancellation after RESET dispatch cannot undo the operation. No write retry is added by this API.

These six methods extend IServerCommands. External implementations, decorators, and mocks must implement or forward them. No batch/transaction methods are added.