feat: opt-in tracing instrumentation on generated entity methods#119
Merged
Conversation
Make logger output pinpoint *which entity* failed without any per-call
boilerplate. Every generated async method on the repository, transaction
adapter, projection lookups, and stream subscriber is now wrapped with
`#[cfg_attr(feature = "tracing", ::tracing::instrument(...))]` carrying:
- `entity = "<EntityName>"` field
- `op = "<operation>"` field (stable label, e.g. `create`, `find_by_id`,
`find_by_email`, `tx.update`, `stream.recv`)
- `skip_all` so DTOs and pool handles stay out of the span
- `err(Debug)` to auto-emit an ERROR event on `Err` with the formatted
source error
The attribute is gated on the consumer crate's `tracing` feature, so
users who don't enable it pay zero cost — the generated code is
bit-for-bit identical to before this PR.
Coverage (18 generator sites + 2 hand-written `entity-core` methods):
- crates/entity-derive-impl/src/utils/tracing.rs — new helper
`instrument(entity, op)` with 5 unit tests covering shape, fields,
err mode, and absolute-path resolution.
- crates/entity-derive-impl/src/entity/sql/postgres/crud.rs — create,
find_by_id, update, delete (soft + hard), list.
- crates/entity-derive-impl/src/entity/sql/postgres/lookup.rs —
find_by_<field>, exists_by_<field> (dynamic op names).
- crates/entity-derive-impl/src/entity/sql/postgres/projections.rs —
find_by_id_<projection> (dynamic op names).
- crates/entity-derive-impl/src/entity/sql/postgres/save.rs — save
(aggregate root).
- crates/entity-derive-impl/src/entity/transaction.rs — tx.create,
tx.find_by_id, tx.update, tx.delete / tx.soft_delete, tx.list.
- crates/entity-derive-impl/src/entity/streams/subscriber.rs —
stream.subscribe, stream.recv, stream.try_recv.
- crates/entity-core/src/transaction.rs — `Transaction::run` and
`run_with_commit` carry `op = "tx.run"` / `op = "tx.run_with_commit"`
spans (manually, since these are not generated). Generic `E` gains a
`core::fmt::Debug` bound so `err(Debug)` can format it.
Cargo wiring:
- `entity-core` gains feature `tracing = ["dep:tracing"]` + optional
`tracing` dep.
- `entity-derive` gains feature `tracing = ["entity-core/tracing"]`.
- `entity-derive` adds `tracing` as a dev-dep so the local test crate
resolves `::tracing::instrument` when `--all-features` is set.
- All 10 example crates declare `tracing = []` to acknowledge the
cfg-check and stay warning-free in Rust 1.80+.
Version bump (new feature → minor):
- entity-core: 0.5.4 -> 0.6.0
- entity-derive-impl: 0.5.2 -> 0.6.0
- entity-derive: 0.7.3 -> 0.8.0
Usage:
```toml
[dependencies]
entity-derive = { version = "0.8", features = ["tracing"] }
tracing = "0.1"
tracing-subscriber = "0.3"
```
No code changes required beyond initializing a subscriber. Logs of the
shape `entity=User op=create error=duplicate key …` appear automatically.
Closes #118
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
RAprogramm
added a commit
that referenced
this pull request
May 11, 2026
…ctions example (#121) README had drifted from the current crates: - Installation block still pinned `entity-derive = "0.4"`. Updated to `0.8` (latest published). - Added a "Feature flags" section enumerating every Cargo feature: `postgres`, `clickhouse`, `mongodb`, `streams`, `api`, `validate`, `tracing`. Each gets a one-line description so users can pick what they need without reading the source. - Added a "Transactions" subsection under Quick Reference with a current, copy-pasteable `.run(async |ctx| { ... })` example. The previous text mentioned transactions only as a feature-table bullet; the API changed in 0.7.0 (#103) and the README never demonstrated the fixed signature. Cross-links to `run_with_commit` for conditional-commit use cases. - Added a "Tracing" subsection showing the feature flag, expected dependencies, sample log output, and the zero-cost guarantee when the flag is off — the feature was added in 0.8.0 (#118 / #119) and was previously undocumented at the README level. - Added "Structured Logging" to the Features table. Closes #120
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.
Closes #118
Summary
Make logger output pinpoint which entity failed without per-call boilerplate. Every generated async method (CRUD on `Repository`, transaction adapter, projection lookups, save, stream subscriber) is now wrapped with:
```rust
#[cfg_attr(
feature = "tracing",
::tracing::instrument(
skip_all,
fields(entity = "User", op = "create"),
err(Debug),
)
)]
```
Opt-in via Cargo feature → zero cost when off, identical bits to today.
What's covered
Helper
`crates/entity-derive-impl/src/utils/tracing.rs` — single source for the attribute emission. 5 unit tests lock the shape:
Cargo wiring
Version bump (new feature → minor)
Breaking change in entity-core
`Transaction::run` and `run_with_commit` gain a `core::fmt::Debug` bound on the closure's error type `E`. `sqlx::Error` and all standard error types already satisfy it, so most users won't notice — but technically it is breaking. Justifies the minor bump from 0.5 to 0.6.
Usage
```toml
[dependencies]
entity-derive = { version = "0.8", features = ["tracing"] }
tracing = "0.1"
tracing-subscriber = "0.3"
```
Initialize a subscriber and you get logs like:
```
ERROR entity.User.create: error=database error: duplicate key value violates unique constraint
in entity.User.create with entity="User" op="create"
```
Test plan