Skip to content

Log the agent conversation through ILogger - #38

Open
darinkes wants to merge 1 commit into
chore/modernize-samplefrom
feat/agent-logging
Open

Log the agent conversation through ILogger#38
darinkes wants to merge 1 commit into
chore/modernize-samplefrom
feat/agent-logging

Conversation

@darinkes

Copy link
Copy Markdown
Owner

Summary

Wire-level logging for the agent conversation, done the ILogger way: the library logs the data, the attached logger owns the representation.

  • SshAgent.Logger (Microsoft.Extensions.Logging.Abstractions, default NullLogger.Instance): at Trace level, every raw protocol message is logged with EventId(1, "AgentMessage").
  • SshAgentTraceMessage is the structured log state: it carries Direction and the complete framed Data, and implements IReadOnlyList<KeyValuePair<string, object?>> with Direction/DataLength/Data/{OriginalFormat} properties. Consequences:
    • plain text sinks render only the safe default — Request agent message, 128 bytes — no accidental byte dumps in logs,
    • structured sinks (Serilog, OTel, …) see the raw byte[] as a property and apply their own destructuring/redaction,
    • a custom ILogger pattern-matches the state and renders however it wants — the sample's --verbose does exactly that with a ~25-line HexDumpLogger.
  • The XML docs warn that add-identity requests contain private key material; Trace is off in every default logging configuration.
  • Dependency note: Microsoft.Extensions.Logging.Abstractions 8.0.3 is the exact version SSH.NET 2025.1.0 already depends on, so consumers on newer SSH.NET pay nothing extra; it is netstandard2.0 and works on all four target frameworks.
  • Plumbing: both send paths now share buffered Serialize/ReadMessage/Parse helpers — as a side effect the sync path gains the message-length validation the async path already had.

Sample output of SshNet.Agent.Sample --pageant --verbose:

-> 5 bytes
   0000  00 00 00 01 0b                                   .....
<- 9 bytes
   0000  00 00 00 05 0c 00 00 00 00                       .........
Adding the sample keys ...
-> 128 bytes
   0000  00 00 00 7c 11 00 00 00 0b 73 73 68 2d 65 64 32  ...|.....ssh-ed2
   0010  35 35 31 39 00 00 00 20 4e 56 e8 17 0d 9c cb 8d  5519... NV......

Stacked on #37 (the sample's --verbose builds on the System.CommandLine parser): merge #37 first; GitHub retargets this PR to main automatically when the branch is deleted.

Test plan

  • New tests: sync and async sends log exactly two entries with the exact framed bytes, correct level/event id and the summary text; a disabled logger sees nothing (and costs nothing); the structured properties enumerate as documented
  • Full suite passes (46 tests); builds on all four target frameworks with CS1591-as-error
  • Ran live against a real Pageant with --verbose — hex dump above, including through the Pageant WM_COPYDATA transport

SshAgent gets a Logger property (Microsoft.Extensions.Logging
.Abstractions, which newer SSH.NET already depends on; default
NullLogger). At Trace level every raw protocol message is logged as
structured SshAgentTraceMessage state carrying the direction and the
complete framed payload: plain text sinks render only the summary
line, structured sinks and custom loggers get the raw bytes and
choose their own representation. The docs warn that add requests
contain private key material.

Both send paths now share the same buffered serialize/read helpers,
which also gives the sync path the message length validation the
async path already had.

The sample hex-dumps the traffic with --verbose through a small
HexDumpLogger.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant