Report a startup event to trace, off the main thread and with an opt-out - #22
Merged
Merged
Conversation
A startup event (program name and version only) and a backup-completed event (nothing else) are sent to the trace service through the vendored trace-client-java, from a daemon thread that never delays a backup and never holds up exit by more than the client's 5-second timeout. Nothing about the users, organizations or repositories being backed up is sent. Reporting is on by default and is turned off with usage.reporting.enabled=false (a -D property, application.properties, or USAGE_REPORTING_ENABLED in the environment, which docker-compose.yml now passes through). A one-line notice is logged the first time it runs on a machine and recorded in ~/.config/gh-backup/ so it is not repeated; gh-backup has no settings file of its own, which is why a marker is used. The program version comes from spring.application.version, filled in by Maven resource filtering from the POM. Every test that starts a Spring context runs with reporting off, and surefire pins the same for any test added later, so nothing here ever reaches the real service from a build. Closes #21 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WYoD9SsaRz8PjakTSHhmn6
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
gh-backup is wired into the maintainers' trace usage-reporting service. trace-client-java is vendored unmodified apart from its package line as
com.github.backup.trace.TraceClient(with its tests), and a newUsageReportingServicebean builds the client from gh-backup's existing Spring properties, sends the events, and closes the client when the context shuts down.Closes #21
Guarantees
Reporting is done from a single daemon thread owned by the client:
report()returns immediately, never throws, and queues at most 256 events before dropping new ones, so a trace server that is down, slow or rejecting the key costs a dropped report and nothing else. A blank endpoint, an unwritable home directory or an emptyUSAGE_REPORTING_ENABLEDare all handled without an exception reaching a backup. On shutdown, Spring Boot's shutdown hook callsclose(), which waits at most the client's 5-second read timeout for an event in flight, so a short CLI run does not exit before its startup event has left the machine, and a hung server cannot hold exit for longer than that.What is sent
startup, once per process, taggedversion= the program version (spring.application.version, filled in by Maven resource filtering from the POM; if the placeholder is ever left unfiltered, the tag is omitted rather than sent as@project.version@)backup-completed, when a backup run finishes, with no tags: the end of a CLI run, an interactivebackupcommand, a scheduled daemon run, and a webPOST /api/backupsWhat is not sent
No user or organization names, no repository names, no counts, no paths, no usernames, hostnames or IP addresses. The body of a startup event is exactly
{"application":"gh-backup","name":"startup","tags":{"version":"2.0.0-SNAPSHOT-8-8-2026"}}.Where the opt-out is
usage.reporting.enabled=false, through the same mechanism as every other gh-backup property:-Dusage.reporting.enabled=false, anapplication.propertiesnext to the JAR, orUSAGE_REPORTING_ENABLED=falsein the environment (whichdocker-compose.ymlnow passes through from.env, defaulting totrue).usage.reporting.endpointandusage.reporting.keyare documented alongside it inCONFIG.md.The first time reporting runs on a machine, one
INFOline is logged:Usage reporting is on: gh-backup sends a startup event (program name and version only) and a backup-completed event (nothing else) to trace.danielstephenson.dev. Turn it off with -Dusage.reporting.enabled=false or USAGE_REPORTING_ENABLED=false.A marker file at~/.config/gh-backup/usage-reporting-notice-shownkeeps it from being repeated. gh-backup has no settings file of its own to record this in, which is why a marker file under the user's config directory is used. When reporting is off, nothing is logged and no marker is written.Test plan
mvn clean verifyon JDK 17 (CI's toolchain): 54 tests (1 skipped, pre-existing) before → 72 tests (1 skipped) after,BUILD SUCCESS. The 18 new tests are the 10 vendoredTraceClientTestcases and 8UsageReportingServiceTestcases driving the wiring against a loopback JDKHttpServer: startup body and bearer key, backup-completed body, unfiltered-version fallback, notice logged once and not on a second run, disabled sends nothing and writes no marker, blank/absent enabled means on, bad endpoint and unwritable marker never throw.sh docker-entrypoint-test.sh:All docker-entrypoint.sh tests passed.unzip -l target/gh-backup-2.0.0-SNAPSHOT-8-8-2026.jarlistsBOOT-INF/classes/com/github/backup/trace/TraceClient.class; the bundledapplication.propertiesinside the JAR carriesspring.application.version=2.0.0-SNAPSHOT-8-8-2026and the key byte-for-byte.@SpringBootTestcontext setsusage.reporting.enabled=false, and surefire sets the same system property for any test added later, so no test ever reaches the real service.Local stub proof (a 12-line Python
http.serverrecording POSTs,-Duser.homepointed at an empty directory,-Dusage.reporting.endpointat the stub; production was never contacted):🤖 Generated with Claude Code
https://claude.ai/code/session_01WYoD9SsaRz8PjakTSHhmn6
drafted by Claude on behalf of Daniel Stephenson