Skip to content

fix: Propagate muted flag to :error telemetry events#174

Merged
crbelaus merged 1 commit intoelixir-error-tracker:mainfrom
reciproco:fix/propagate-muted-flag-to-error-telemetry
May 1, 2026
Merged

fix: Propagate muted flag to :error telemetry events#174
crbelaus merged 1 commit intoelixir-error-tracker:mainfrom
reciproco:fix/propagate-muted-flag-to-error-telemetry

Conversation

@reciproco
Copy link
Copy Markdown
Contributor

Hi @crbelaus,

We're a team that has been using your library in production for a few months now, and we're very happy with it. Thank you very much for your work.

We ran into a situation where the mute action exposed in the dashboard wasn't being respected by our notifier. Our handler subscribes to [:error_tracker, :error, :new] and [:error_tracker, :error, :unresolved] and inspects metadata.error.muted before sending an alert, so muted errors should silently pass through. In practice it never did: every dispatched %Error{} struct carried muted: false, regardless of the row's real state in the DB, so errors that operators had explicitly silenced from the UI kept paging us.

The [:error_tracker, :occurrence, :new] event does expose a working :muted metadata key, but it isn't the right signal for our use case — we only want to react to genuinely new errors and to regressions (resolved → unresolved), not to every individual occurrence.

After digging in we found that upsert_error!/5 already reads both existing_status and muted from the DB before the upsert, but it never stamps muted onto the in-memory struct it hands to Telemetry.new_error/1 /Telemetry.unresolved_error/1. Because Repo.insert!(_, on_conflict: [set: [...]]) doesn't round-trip the columns it didn't set, the struct keeps the schema default (muted: false) even when the DB row is muted.

We've been running a fork with this fix for a while and it's worked well for us. We wanted to offer it upstream in case you find the direction acceptable. We're happy to adjust the approach if you'd prefer a different shape or semantics — please consider this a humble proposal rather than a prescription.

Changes

  • Stamp the in-memory Error struct with the muted value already fetched from the DB, right before dispatching the :new and :unresolved telemetry events.
  • No public API change: the Error schema already declares muted, so existing subscribers that read metadata.error.muted start receiving the real value without any code change on their side.
  • The [:error_tracker, :occurrence, :new] event is untouched (it already exposes :muted as a separate metadata key, and that path was working correctly).

Why this shape, and not a separate metadata key

The Error schema already declares muted as a field, so the struct felt like the natural place for that information to live. Updating the struct keeps consistency with how the rest of the code treats %Error{} and avoids changing the metadata shape on existing subscribers. That said, if you'd rather expose :muted as a separate metadata key on the :new / :unresolved events to mirror :occurrence, :new, we're happy to switch to that.

Test plan

  • New regression test added in test/error_tracker/telemetry_test.exs that mutes and resolves an error, triggers it again, and asserts the :unresolved payload reflects muted: true.
  • Confirmed the test fails on main (the dispatched struct shows muted: nil) and passes with the fix applied.
  • Full suite passes with --warnings-as-errors.

Regards

`Repo.insert!(_, on_conflict: [set: [...]])` only round-trips the
columns it sets, so the in-memory `Error` struct dispatched to
subscribers of `[:error_tracker, :error, :new]` and
`[:error_tracker, :error, :unresolved]` always carried the schema
default (`muted: false`), regardless of the row's real state in the
database. This made the dashboard mute action effectively a no-op for
those two events.

The DB row is already queried for `existing_status` and `muted` at the
top of `upsert_error!/5`, so stamp the in-memory struct with that
value before dispatching the telemetry events. Two-line change, no
public API surface modified — subscribers that already read
`metadata.error.muted` start working without any change on their side.
Copy link
Copy Markdown
Contributor

@crbelaus crbelaus left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is looking great. Thanks for your contribution! 🙇

@crbelaus crbelaus merged commit b866592 into elixir-error-tracker:main May 1, 2026
5 of 6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants