Release

Release

Announcing Toise 0.19.0 — two gaps closed from production

Released 2026-10-05 · written up 2026-10-17

0.18.0 gave every entity a name meant to be shown. Three of the fourteen entity types never got one. Separately, on a server carrying several tenants, the ingest counters could say that something had been refused and not whose. Both were found by consumers running 0.18.0 in production, and both are fixed here.

Drop-in: no wire-contract break, no data migration. A 0.18 deployment upgrades in place. If you read the ingest metrics, see the note on the tenant label below.

A name on every type, or a written reason why not

display_name was empty on network.address, db and network.segment. Measured in a production tenant: 0 of 60 addresses and 0 of 10 databases carried one, while every one of them carried an identity_fingerprint. An address now renders its own value, which is what a person says for it, and what network.endpoint already did when composing an address and port out of its identity. A database composes its technology and where it answers:

postgresql@10.0.0.5:5432

because db.instance.id is a PostgreSQL system identifier or a MySQL server UUID, correct as a key and unreadable as a name. A segment declares that it has none: its id is an assigned opaque value that reads no better than the identity, and no producer emits a name to compose from yet.

The omission was invisible because the test suite asserted hand-written cases and nothing enumerated the registry, so a type added after the table was written inherited no name and no failing test. A registry test now requires every type to carry a name, to compose one, or to declare that it has none with the reason. Having no display name is a decision that is written down, not something that can happen by omission.

One consequence for consumers: a fallback of the form "if the name is empty, compose it myself" stops firing for addresses and databases. No value that was already served has moved, but labels change on that day if the fallback produced a different form.

An ingest rejection names its tenant

One OTLP stream can carry several tenants through the tenant.id resource attribute, and the per-record counters were export-wide totals. On a shared server a non-zero rejection count could not be attributed to anyone. The counters now tally where the tenant is resolved, and a tenant's three result series are created at zero the first time it is seen: a missing series and a zero series do not mean the same thing to whoever reads them, and only one of them is an answer.

The warning logged on a rejection carries the tenant beside the first error. It logs one error per batch, so a tenant whose records were all refused was invisible whenever another tenant's error came first.

Two counters stay unlabeled on purpose. The export counter counts requests, and a request is not per-tenant: one rejected before tenant resolution has none at all. The tenant-rejection counter counts ids that failed validation, and on an open server that value is caller-supplied, so labeling it would hand an unauthenticated caller a way to mint unbounded series.

If you read the ingest metrics.

toise_ingest_records_total, toise_ingest_unknown_type_records_total and toise_ingest_attr_values_dropped_total now carry a tenant label. A query that returned one line returns one series per tenant; sum without the label to keep the previous shape. Cardinality is bounded by the tenant count, which is already the unit of the existing tenant gauges.

Documentation: the first participating relay, not the first relay

The relay provenance rule said "first relay wins". That assumes every hop implements the convention; a hop that does not take part leaves no trace, so the next participating hop stamps itself and the value names the wrong relay. The guarantee is reduced rather than patched, because the gap cannot be closed from inside the convention, and the amendment is kept identical to the upstream semantic-conventions discussion. A reader also gets the guidance the rule never gave: a partial set is read as an absence, and the key that is present is not a join key.


Get it

go install github.com/toise-dev/toise/cmd/toise-server@v0.19.0

Binaries for linux and darwin (amd64 / arm64) are on the release, each with a checksum, and the multi-architecture container image is on GHCR. See the 0.19.0 docs and the changelog. Note that 0.20.0 closed security advisories every binary before it carries; if you are installing today, start from the current release.