Skip to content

Log every dropped report, at a bounded length - #27

Merged
dmccoystephenson merged 2 commits into
mainfrom
feature/log-every-drop
Nov 4, 2026
Merged

dmccoystephenson merged 2 commits into
mainfrom
feature/log-every-drop

Conversation

@dmccoystephenson

@dmccoystephenson dmccoystephenson commented Nov 4, 2026 •

Copy link
Copy Markdown
Member

Summary

Every drop is now logged, and at a bounded length. The change is confined to log messages: the wire format, Close()'s time bound and the public API are untouched.

  • Reports still queued when Close() times out are counted in the log. Drain used to swallow the cancellation, so everything behind the in-flight request was lost silently, against the README's "Drops go to the optional log callback". One line is now logged: close timed out, dropped N queued report(s).
  • An overlong event name is cut at MaxLength in the log. dropped <name> and could not queue <name> used to copy the whole name. A name within the limit is logged unchanged, and a longer one ends in ....
  • The Close XML doc and the README Close() row now say that the dropped remainder is logged.

Closes #25
Closes #26

Test plan

  • Build workflow red on the test-only first commit, naming Close_LogsHowManyReportsItGaveUpOn, Report_LogsAnOverlongNameCutAtTheLimit and Report_NeverThrowsWhenTheTagsDoAndLogsAnOverlongNameCut (run 41763538443; Failed: 3, Total: 102 on ubuntu-latest, with the windows-latest leg cancelled by fail-fast)
  • Build workflow green on the fix commit on ubuntu-latest (net8.0), 102 tests against 97 on main
  • Build workflow green on the fix commit on windows-latest (net8.0 + net48), 102 tests each against 97 on main

The local anchor is UNVERIFIED: no .NET SDK is installed in the dispatch sandbox, so the CI matrix is the gate. The first commit was pushed alone on purpose, so that FAIL→PASS is recorded by CI without a temporary revert or a force-push.

The Unity (Mono/IL2CPP) runtime is not covered by CI. No threading or HTTP behaviour is changed here, so no Unity-specific risk is expected.

Deferred

This PR description was drafted during a Gardener session (https://github.com/Stephenson-Software/gardener).

🤖 Generated with Claude Code


drafted by Claude on behalf of Daniel Stephenson

dmccoystephenson and others added 2 commits November 3, 2026 19:52
These fail until the client logs the reports Close gives up on and cuts
an overlong name, so CI records them red before the fix lands.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Drain swallowed the cancellation, so reports still queued behind the
in-flight request were the one drop nothing logged. An overlong event
name reached the log whole, though the same size check cuts a tag key.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@dmccoystephenson

Copy link
Copy Markdown
Member Author

Self-review rubric (plain comment; not an independent review):

  • Scope: PASS. Only README.md, TraceClient.cs and TraceClientTest.cs changed, and each hunk serves Reports still queued when Close() times out are dropped without a log line #25 or Overlong event name is copied whole into the dropped and could-not-queue log messages #26.
  • Tests-new: PASS. No public member was added. The private ForLog is exercised by three new tests, and the new Drain branch by two.
  • Tests-fix: PASS on ubuntu/net8.0 only. Commit 915b5b1 (tests without the fix) ran as 41763538443 and failed with Failed: 3, Passed: 99, Total: 102, naming Close_LogsHowManyReportsItGaveUpOn, Report_LogsAnOverlongNameCutAtTheLimit and Report_NeverThrowsWhenTheTagsDoAndLogsAnOverlongNameCut. Commit 0ae185e (with the fix) ran as 41763735770 and passed. The tests-first order replaced the temporary-revert rung of the ladder, and gave the same FAIL→PASS evidence without a force-push. The windows-latest leg of the red run was cancelled by fail-fast, so RED was not observed on net48; GREEN was.
  • Sibling structure: PASS. No file was added; the new tests follow Subject_BehaviourInPlainWords, StubServer and log.Enqueue.
  • Sibling renames: PASS. Nothing was renamed.
  • Docs: PASS. The Close XML doc and the README Close() row were updated, and the README's "Drops go to the optional log callback" is now true of this path.
  • Issue resolution: PASS. Reports still queued when Close() times out are dropped without a log line #25: Drain logs the count. Overlong event name is copied whole into the dropped and could-not-queue log messages #26: both Report messages go through ForLog.
  • CI: PASS. Run 41763735770 is green on head 0ae185e. Totals went from 97 on main (41281221836) to 102 on ubuntu net8.0, windows net8.0 and windows net48, so all 5 new tests ran on every target.
  • No dependencies: PASS. The csproj is untouched and no using was added.
  • Single file: PASS. git ls-files src/TraceClient lists TraceClient.cs and TraceClient.csproj.
  • Vendoring floor: PASS. The csproj is untouched and the net48 leg is green.
  • Never throws: PASS, with one point checked by reading. The Drain catch block sits outside any further try, and an exception escaping it would end the process. _queue.Count throws only ObjectDisposedException, _queue is never disposed, and Log cannot throw. ForLog runs in Report's catch block too, but name was already checked as not null or blank.
  • Non-blocking and bounded: PASS. Report gains only a string cut on the path where a report is already being dropped. One summary line is logged at close rather than one per report.
  • Environment seam: PASS. System.Environment is still used only by the EnvironmentSource initializer.
  • Version agreement: not applicable. No version changed.
  • Opt-out contract: not applicable. No opt-out code changed.

Findings noted, not changed:

  • src/TraceClient/TraceClient.cs:461: the Drain catch also receives anything other than cancellation, in which case "close timed out" would be inaccurate. Send catches everything itself, so cancellation is the only expected path; on Mono a thread abort at domain reload would be the exception, and it would produce only a misworded debug line.
  • The log text is not a listed contract, and no do-not-auto-merge path was touched: the changed README row is outside "Turning it off" and "Keys", and no constant, signature, wire-format or opt-out code changed.
  • Unity (Mono/IL2CPP) is not covered by CI. No threading or HTTP behaviour changed.

Local anchor: UNVERIFIED (no .NET SDK in the dispatch sandbox), so CI on the exact head SHA was used as the gate.

This comment was drafted during a Gardener session (https://github.com/Stephenson-Software/gardener).


drafted by Claude on behalf of Daniel Stephenson

@dmccoystephenson
dmccoystephenson merged commit d92c55d into main Nov 4, 2026
2 checks passed
@dmccoystephenson
dmccoystephenson deleted the feature/log-every-drop branch November 4, 2026 02:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant