github robintra/perf-sentinel v0.5.7

latest releases: chart-v0.2.58, v0.8.12, chart-v0.2.57...
one month ago

What's new in v0.5.7

OpenTelemetry agents collapse SQL literals to ? by default to keep PII out of trace attributes. Until now, that put perf-sentinel in a frustrating spot on every ORM stack: the standard distinct_params >= threshold rule could not see distinct values, so an ORM-induced N+1 would land in redundant_sql with the wrong remediation ("cache or deduplicate") instead of n_plus_one_sql ("batch fetch / @EntityGraph"). v0.5.7 closes the gap with a two-signal heuristic, gated by a TOML toggle, that recovers the correct classification on every sanitized SQL group without forcing operators to disable PII protection.

The heuristic activates only when every span in a (event_type, template) group has empty params and a ? placeholder in its template (the on-wire signature of an OTel-sanitized N+1). It then evaluates two independent signals: a case-insensitive, word-bounded match of the spans' instrumentation_scopes against a list of ORM markers (Spring Data, Hibernate, JPA, Micronaut Data, JDBI, R2DBC, EF Core, SQLAlchemy, Django, ActiveRecord, GORM, sqlx, Sequelize, Prisma, TypeORM, Mongoose, SeaORM, Diesel), and as a fallback the coefficient of variation of duration_us (CV > 0.5 indicates distinct row lookups, threshold empirical). The word-boundary check prevents short markers like jpa and sqlx from false-positive matching unrelated substrings (mysqlxapackage, myappjpastats). Findings reclassified by the heuristic carry a new classification_method = "sanitizer_heuristic" so consumers can spot where it fires.

After upgrading, a Spring Boot + JPA app instrumented with the default OTel Java agent (sanitizer ON, the production-realistic posture) produces N+1 findings classified as n_plus_one_sql instead of redundant_sql, with the framework-aware suggested_fix pointing at JOIN FETCH / @EntityGraph. The same applies to every ORM stack listed above. Operators who want to keep the pre-0.5.7 behavior can set [detection] sanitizer_aware_classification = "never".

Added

  • [detection] sanitizer_aware_classification = "auto" | "always" | "never" (default "auto"). New TOML toggle controlling the sanitizer-aware reclassification heuristic. "auto" requires either the ORM scope signal or the timing variance signal, "always" reclassifies any sanitized group with >= n_plus_one_min_occurrences spans (most aggressive), "never" disables the heuristic entirely. Unknown values warn (with the offending value sanitized: control characters replaced, length capped at 32 bytes) and fall back to "auto". See docs/CONFIGURATION.md and docs/design/04-DETECTION.md.
  • classification_method field on Finding with values direct (omitted from JSON when None) and sanitizer_heuristic. Findings produced by the standard distinct_params >= threshold rule omit the field, findings reclassified by the heuristic are stamped sanitizer_heuristic. The new ClassificationMethod enum is parallel to Confidence, not nested in it, so the runtime-context signal (CI vs production daemon) and the classification-method signal stay orthogonal in the API.
  • New sanitizer_aware module in crates/sentinel-core/src/detect/ exposing SanitizerAwareMode, SanitizerVerdict, looks_sanitized, has_orm_scope (allocation-free word-bounded ASCII match), collect_scopes, timing_variance_suggests_n_plus_one, classify_sanitized_sql_group. All functions are pure, with no allocation on the gate (looks_sanitized_indexed) so the heavy verdict only runs on groups that already pass the fast sanitized-shape check.

Fixed

  • Sanitized N+1 SQL groups now classify as n_plus_one_sql instead of redundant_sql. Affects every ORM stack with a real OTel agent (Java JPA / Hibernate / Micronaut Data, .NET EF Core, Python SQLAlchemy / Django, Ruby ActiveRecord, Go database/sql with GORM or sqlx, Node.js Prisma / TypeORM / Sequelize, Rust Diesel / SeaORM, ...) running with the default sanitizer ON. Operators get the correct remediation (batch fetch, @EntityGraph, eager loading) instead of "cache result or deduplicate".
  • detect_redundant now skips templates already flagged as N+1. Takes the slice of N+1 findings already produced for the trace as a new parameter, so the same template is never double-reported as both n_plus_one_sql and redundant_sql (whether the N+1 came from the standard rule or from the heuristic).

Changed

  • BREAKING (perf-sentinel-core, pre-1.0 so minor-bump allowed): detect::detect_n_plus_one gains a mode: SanitizerAwareMode parameter and detect::detect_redundant gains an n_plus_one_findings: &[Finding] parameter. DetectConfig and Config gain a sanitizer_aware_classification field. PerTraceFindingArgs gains a classification_method field. External consumers calling these directly must update accordingly.
  • Behavior change: users with the OpenTelemetry SQL sanitizer ON (the default posture) will see findings move from redundant_sql to n_plus_one_sql on upgrade, with classification_method = sanitizer_heuristic. This is not a regression: the new classification carries the correct remediation. Set [detection] sanitizer_aware_classification = "never" to keep the pre-0.5.7 behavior.
  • Helm chart 0.2.10 bumps appVersion and the default daemon image tag to 0.5.7. Chart templates are unchanged.

Install

Prebuilt binaries (Linux amd64 / arm64, macOS arm64, Windows amd64):

curl -LO https://github.com/robintra/perf-sentinel/releases/download/v0.5.7/perf-sentinel-linux-amd64
chmod +x perf-sentinel-linux-amd64
sudo mv perf-sentinel-linux-amd64 /usr/local/bin/perf-sentinel

Linux binaries are statically linked against musl and run on any distribution (Alpine, Debian, RHEL, Ubuntu any version) regardless of glibc version, and inside FROM scratch images.

From crates.io:

cargo install perf-sentinel

Docker:

docker run --rm -p 4317:4317 -p 4318:4318 \
  ghcr.io/robintra/perf-sentinel:0.5.7 watch --listen-address 0.0.0.0

Also available on Docker Hub: robintrassard/perf-sentinel:0.5.7.

Helm (chart 0.2.10 ships 0.5.7 as its appVersion default):

helm install perf-sentinel oci://ghcr.io/robintra/charts/perf-sentinel \
  --version 0.2.10 \
  --namespace observability --create-namespace

Verify the binary against SHA256SUMS.txt:

curl -LO https://github.com/robintra/perf-sentinel/releases/download/v0.5.7/SHA256SUMS.txt
sha256sum -c SHA256SUMS.txt --ignore-missing

Full diff: v0.5.6...v0.5.7

Don't miss a new perf-sentinel release

NewReleases is sending notifications on new releases.