Skip to main content

Valkey command logs

Valkey 8.1+ keeps three independent, per-node command logs: slow commands, large requests, and large replies. Read and reset them with CommandLogAsync, CommandLogLengthAsync, and ResetCommandLogAsync on the Server facet, or their OnAllNodesAsync counterparts. On Redis, use SlowLogAsync; Redis servers without COMMANDLOG return their error, with no fallback.

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}");
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 a log; 0 records every eligible command. Larger retention uses more server memory. These APIs never change thresholds or retention. See Valkey's GET and LEN references.

Entries​

  • Each entry has its type, ID, Unix timestamp in seconds, raw metric, binary arguments, and binary client address and name.
  • DurationMicroseconds, RequestBytes, and ReplyBytes are set only for the matching log type; the others are null. MetricValue holds the raw metric for generic tooling.
  • Unknown trailing fields go to AdditionalValues as RespireResult values. They need no disposal; disposing one invalidates its views.
  • Entries stay usable after the client is disposed.

Count:

countResult
omitted10 entries
-1All retained entries (unbounded; can transfer large payloads)
0None
below -1Throws before I/O (as do undefined log types)
  • Results keep server order; Valkey 8.1.3 returns newest first (see its implementation).
  • IDs are scoped to a node and log type. Resetting a log does not reset its IDs.
warning

The server limits recorded argument counts and lengths and may omit or redact sensitive commands. Respire returns the bytes as given; it cannot rebuild the original command or guarantee the log contains no secrets.

Scope and resets​

Ordinary calls use one node. With UseCluster, all-node calls discover replicas and slotless members (needs CLUSTER NODES permission); otherwise they query only the connected endpoint. Each result has its endpoint and either a value or the original error. Views can overlap; nothing is 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}");
}
  • Reading does not need AllowAdmin; server ACLs still apply.
  • RESET needs AllowAdmin (checked before I/O) and permanently clears the selected log. Its cost grows with retained entries; see COMMANDLOG RESET.
  • All-node resets return true per successful node and can partly succeed, with no rollback or replication.

Cancellation:

  • Pre-cancelled calls send nothing.
  • Cancellation during discovery throws; after discovery it is reported per node.
  • Cancellation after RESET is sent cannot undo it. Respire never retries a RESET.

These six methods are IRespireServerCommands members. External implementations, decorators, and mocks must implement or forward them. They have no batch or transaction versions.