Skip to content

v0.9.8

Latest

Choose a tag to compare

@github-actions github-actions released this 11 Jul 13:30
v0.9.8

What's new in v0.9.8

v0.9.8 is a minor release with two ingestion and detection changes, both driven by real production topology from the simulation lab. OTLP ingest now admits OpenTelemetry RPC semantic-convention spans (gRPC and similar frameworks), which the I/O filter previously dropped as non-I/O, so the topological and occurrence detectors were blind on RPC-heavy fleets. Separately, the HTTP normalizer now keeps the callee host in the grouping template, so two calls to the same path on different backend services no longer collapse into a false redundant_http. The host change alters the template of every outbound-HTTP finding, which resets HTTP acknowledgment signatures: existing HTTP acks must be re-created. SQL and RPC findings are unaffected.

Ingestion: OTel RPC semantic-convention spans

An RPC span (gRPC, Dubbo, most RPC frameworks) carries rpc.system, rpc.service, and rpc.method, but neither db.statement/db.query.text nor http.url/url.full. The ingest I/O filter keyed only on the SQL and HTTP attributes, so it dropped every RPC span as non-I/O, and a gRPC-heavy fleet, the most common microservice shape, produced an empty trace stream. The topological detectors (excessive_fanout, chatty_service, serialized_calls) and the occurrence detectors (n_plus_one_http, redundant_http) never saw the exact topology where they deliver the most value.

classify_io_event now admits a span carrying rpc.system as an outbound call. Its target is rpc.service/rpc.method, falling back to the span name (the gRPC package.Service/Method convention) when either key is absent. Only SpanKind::Client is admitted: rpc.* is set on the inbound SERVER handler span as well as the outbound CLIENT span, and admitting both would double-count every hop and invent self-directed edges in the topology detectors. RPC spans reuse the existing outbound path (EventType::HttpOut), so their findings surface under the _http types and travel the HTTP normalize and sanitize path unchanged. They carry no query text, so the SQL normalizer and n_plus_one_sql never apply to them.

Detection: HTTP grouping keeps the callee host

The HTTP normalizer previously stripped the scheme and authority unconditionally, so the grouping template was method path with the host discarded. Two calls to the same path on different backend services, for example http://backend-a/lookup and http://backend-b/lookup, collapsed into one template and raised a false redundant_http with a misleading cache-or-deduplicate suggestion, even though the callees are distinct.

The template now keeps the callee host for DNS-addressed calls (GET user-svc/api/users/{id}). IP-literal authorities, both IPv4 and bracketed IPv6, are still stripped, so load-balanced pod replicas behind one service keep deduping into one template. The port and RFC 3986 userinfo are dropped, a trailing DNS root dot is canonicalized (svc. equals svc), and the host is lowercased. The authority boundary follows RFC 3986 (/, ?, #), so a query or fragment on a path-less URL cannot fold into the host and reach the template.

The reverse cost is that a genuine N+1 can split when one backend is addressed with inconsistent host spelling within a trace (a short name versus its fully-qualified form), or when a per-item loop fans out to distinctly-named backends on the same path. Both are documented in docs/LIMITATIONS.md. Emitting one consistent host spelling per callee keeps N+1 grouping intact.

Operator-visible behavior change

Two changes are visible. First, a fleet instrumented with gRPC or another RPC framework now produces findings where it produced none, with the topological and occurrence detectors reporting on RPC dependencies under the _http finding types. Second, every outbound-HTTP finding's template gains the callee host, so its acknowledgment signature changes, and existing HTTP acknowledgments (in .perf-sentinel-acknowledgments.toml or via the daemon ack API) stop matching and must be re-created. SQL findings, relative-URL findings, and RPC findings are unaffected. No CLI flag, configuration key, output schema, daemon route, or wire shape changes.

Why this is a minor and not a patch

The RPC change admits a span shape the ingest filter previously rejected, so a fleet that produced no findings now produces them, a behavior change wide enough to warrant a minor. The HTTP host change alters the grouping template of every outbound-HTTP finding and resets acknowledgment signatures, which an operator must act on. Neither is a pure bug fix that leaves prior output identical, so both push past a patch. The minimum supported Rust version is unchanged.

Validation

The simulation-lab release gate passed for v0.9.8 (lab commit 06dd232, 2026-07-11). The prod-topology-replay scenario replays 300 real production call graphs from the Alibaba cluster-trace-microservices-v2022 dataset, which are RPC-shaped, and its finding-level diff against the pre-change output removes exactly the ten false redundant_http fusions across distinct callees, dropping the total from 549 to 539 with the four topological classes byte-identical. The rpc-carrier-parity scenario confirms the RPC semconv path produces the same topology as an equivalent URL carrier, with the parity delta at zero. The daemon-ack-workflow scenario stays green because it harvests finding signatures at runtime, so the signature reset is absorbed end to end. CI covers the build, the full test suite (cargo test --workspace), clippy at -D warnings, cargo fmt, and both the default and --no-default-features builds.

Verifying this release

# Binary integrity via SLSA Build L3 attestation
gh attestation verify perf-sentinel-linux-amd64 \
  --owner robintra --repo perf-sentinel

# A periodic disclosure produced by this binary
perf-sentinel verify-hash --report perf-sentinel-report.json \
  --expected-identity "https://github.com/robintra/perf-sentinel/.github/workflows/release.yml@refs/tags/v0.9.8" \
  --expected-issuer "https://token.actions.githubusercontent.com"

gh CLI 2.49 or newer required for gh attestation verify.

Full Changelog: v0.9.7...v0.9.8