Skip to content

Capture and message ​

capture ​

capture() reports a failure. It is synchronous, it never throws, and it accepts anything, because JavaScript lets anything be thrown.

ts
try {
  await save();
} catch (error) {
  flare.capture(error, {
    tags: { area: "editor" },
    contexts: { document: { id: "doc_7", revision: 12 } },
    operation: "save-document",
    level: "error",
  });
}
OptionWhat it does
tagsTags for this report only, merged over the session tags by key.
contextsContexts for this report only. A context replaces a session context of the same name.
operationA short name for what the application was doing, scrubbed and bounded like any string.
levelfatal, error, warning or info. A capture defaults to error. Any other value is an invalid loss, and the default stands.
userOverrides the session user for this report only. null reports it as anonymous.
toSends this report to exactly these destinations. See routing.
dedupe.keyNames the failure so that repeats are dropped. See below.

message ​

message() reports an abnormal condition that is not an exception. It takes the same options and defaults to the info level.

ts
flare.message("Payment returned an unknown state", {
  level: "warning",
  tags: { area: "checkout" },
});

Flare is not a logger. A message is for something a person should look at, not for a record of normal activity. A provider that has no notion of a message says so: Crashlytics, Datadog RUM and PostHog skip messages, and Bugsnag does by default, with the reason unsupported-report-kind. Datadog Logs and OpenTelemetry send them. See provider limitations.

What happens to the thrown value ​

The value is turned into bounded plain data at once, and the original goes no further. No adapter, buffer or devtools panel ever holds your error object.

What was thrownHow it is reported
An ErrorIts name, message and stack, its cause chain, and an AggregateError's errors, all bounded.
An object shaped like an errorThe same, with the origin error-like.
A DOMExceptionThe same, with the origin dom-exception.
A string, number or booleanA NonError whose message is the value.
null or undefinedA NonError whose message is null or undefined.
Any other objectA NonError that lists the object's keys, never its values.
A functionA NonError with the message Function thrown.

Reading a hostile value is contained. A getter that throws, a Proxy that throws, or a cause chain that loops costs the part that could not be read, and the report still goes out.

Duplicates ​

The same error object is often caught twice, once where it happened and once in an error boundary. Flare drops the second report of the same object to the same destination when it arrives within one second.

When the failure has no stable object, name it:

ts
flare.capture(new Error("Socket closed"), { dedupe: { key: "socket-closed" } });

A key is remembered per destination and per signed-in account, so a repeat after an account switch is reported again. Unlike the same-object check, a key has no time window: it stays remembered until 100 newer keys push it out, so use a key for a failure you want reported once, not once a second.

A dropped duplicate is visible on its receipt as dropped with the reason deduped. The dedupe option sets window, the same-object window in milliseconds, 1000 by default, where 0 turns that check off:

ts
import { Flare } from "@priemskiyyy/flare";
import { console } from "@priemskiyyy/flare-console";

const flare = new Flare({
  destinations: { console: console() },
  dedupe: { window: 0 },
});

Error storms ​

A render loop that throws can produce thousands of reports. Flare admits 120 reports a minute by default and drops the rest with the reason rate-limited, recording one diagnostic event when the limit is first reached. A report dropped as stale-scope spends none of that budget. Change it with rateLimits: { perMinute }.

Released under the MIT License.