Learn / Errors and failures
Diagnostics
A diagnostic is { _tag, source, level, message } plus its facts: source
names the package, level is error when something broke on this side and
warning when the application should change something. Every package reports
through Diagnostics.report, which hands it to the Diagnostics.Reporter in
the Effect context and never fails. By default that is Effect's log: the
browser's console, a server's log, wrangler tail on a Worker. With Effect's
default logger an error is written with console.error (stderr on a server)
and a warning with console.log, so DevTools draws an error red and an
end-to-end check for console errors fails on it, while an offline warning
does not. A server that replaced Effect's logger receives both at their level.
Replace it like any service, in a runtime's resources or a server's layer:
import { Effect, Layer } from 'effect'
import { Diagnostics, Remote } from 'foldkit-remote'
const resources = Layer.mergeAll(
Remote.clientLayer(Remote.http('/remote')),
// Logged as by default, and sent on to the server.
Diagnostics.layer(diagnostic =>
Effect.andThen(
Diagnostics.log(diagnostic),
Effect.sync(() => navigator.sendBeacon('/diagnostics', diagnostic.message)),
),
),
)In a browser, give the reporter with Diagnostics.layer(reporter) rather
than Layer.succeed: Foldkit runs Mounts outside the runtime's resources,
and the layer also claims what a Mount hands the document
(Diagnostics.dispatch), such as MountFailed. A page that should not show
warnings in production picks Diagnostics.quiet (errors only) where it
knows its build mode; in development, foldkit-mixins' DevOverlay lists
every diagnostic on the page.
Diagnostics is foldkit-surface's, re-exported by foldkit-remote. Each
package's variants:
Remote's client also records its diagnostics in the Model
(Data.inspect(model).diagnostics, the newest 256), since its reducer is
pure: Data.wiring and Remote.fold report what each update recorded. An
update that calls Data.reduce by hand keeps them in the Model and reports
nothing.
Development and production report the same unless the application
chooses Diagnostics.quiet; no package switches a diagnostic off in
production. What development adds is checks you opt into:
Remote.make({ verifyPredictions: true }), which costs a comparison per
answer and a fetch per placed list. GuardServer.validate
throws at startup for a guard a server does not apply, and reports
UnpinnedWrites for a write a change can come between.
A definition the application wrote wrong throws instead, when it is
made, naming the call and the option. Theme.make, Theme.set and
Knobs.withValue throw foldkit-mixins' Diagnostics.DiagnosticError with
theme:knob-value (Theme.make: surface.lightness refuses its value: …
Expected a value between 6 and 36 at ["dark"]) or theme:unknown-knob.