refactor(metering): split into subpackages + pluggable backend#62
Merged
Conversation
…uggable backend
- metering/{file,stderr,capture}/ subpackages mirror hypervisor/snapshot
pattern: interface lives in main metering package, backends are
subpackage Recorder types exposing a New ctor.
- config.MeteringConfig selects the backend ("file" default, "nop",
"stderr"); empty config keeps v0.4.x behavior.
- cmd/core/metering.go switches over conf.Metering.Backend instead of
hard-coding NewFileRecorder.
- stderr/Recorder is a new debug backend; capture/Recorder keeps the
Entries/Reset test helpers (package doc flags it as testing-only).
- file/Recorder.New no longer takes ctx (unused) and surfaces open
errors so the cmd/core factory owns the NopRecorder fallback.
- config.MeteringBackend typed enum + constants (MeteringFile/Nop/Stderr) mirror the HypervisorType pattern; cmd/core switch now uses typed cases. - MeteringConfig.Validate() rejects unknown backends at startup (hooked into config.Config.Validate) instead of warn-and-nop at first emit. - stderr.Recorder.Emit uses Write with appended newline (matches file.Recorder.Emit shape, drops fmt.Fprintln + nolint:errcheck). - Tighten godocs: stderr.Emit doc removed (impl is obvious), capture package doc collapsed to one sentence, MeteringRecorder godoc trimmed to the lazy-init contract.
Entry now implements io.WriterTo; file and stderr recorders share the same encoding path instead of each calling json.Marshal + appending \n. Wire-format changes (encoder swap, framing, compression) are now one diff in metering.go rather than scattered across backends. file.Emit collapses two log paths (marshal-error vs write-error) into one — the wrapped error already carries the cause, and downstream cares only that the entry failed.
- WriteTo: "writes one JSONL record" (was: wire-format + downstream tools). - file.Recorder / file.Emit: drop the JSON-encoding narrative now that it lives on Entry.WriteTo; keep only the file-specific WHY (O_APPEND atomicity, swallow rationale). - stderr.Recorder: routes to os.Stderr instead of restating the wire format. - config: drop v0.4.x backstory; the default-behavior sentence carries the same information. - metering_test: drop the comment that just paraphrased the test name.
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
Reshape `metering/` to match cocoon's interface-in-main + backend-in-subpackage pattern (hypervisor / snapshot / images / network). Backend is now configurable via `config.MeteringConfig` instead of hard-coded in `cmd/core`.
New layout
```
config/
└── metering.go (MeteringConfig / FileMeteringConfig)
metering/
├── metering.go (Recorder interface, Entry/Shape/Kind/Reason, NopRecorder)
├── file/ (production: JSONL append on disk)
├── stderr/ (dev/debug: JSON line to stderr)
└── capture/ (testing-only: buffered with Entries/Reset)
```
Each subpackage exposes `Recorder` struct + `New` ctor + compile-time `var _ metering.Recorder = (*Recorder)(nil)`.
Config
```jsonc
// default — equivalent to v0.4.x file behavior, no config change needed
{}
// explicit
{"metering": {"backend": "file", "file": {"path": ""}}}
// disable
{"metering": {"backend": "nop"}}
// dev
{"metering": {"backend": "stderr"}}
```
Factory
`cmd/core/metering.go` switches over `conf.Metering.Backend`; unknown backend warns + falls back to NopRecorder. Adding a new backend (HTTP webhook, Pub/Sub, Kafka, …) is one new subpackage exposing a Recorder + adding one case to the switch.
Other notable changes
Backward compat
Test plan