health, error, metric, and outcome.
OpenFeature and the wire still say flagKey when a signal names a control point. Capture uses type: "signal". These are not the in-app Log / Alert / Block severities.
Why it exists
Evaluation says what value was chosen. Signals say what happened next — a component is degraded, an error you already classified, a numeric observation, or a user-visible result. Messages are secret-redacted. Attributes pass an allowlist so arbitrary PII does not go on the wire.When to use it
Do not invent extra kinds. Do not map console Block onto
recordError.
How it relates
Whether signals always reach fw-server is NEEDS VERIFICATION (compatibility known gap: Go/Java sink vs Node/Python in-process record). Check
capabilities.get().runtime.features and do not claim universal delivery.Shared envelope
Required byspec/signal.schema.json: kind + name (1–256 chars). Optional correlation: targetingKey, rolloutId, changeId, stampId, flagKey, variant. Optional status, errorKind, message, value, unit (language-specific), attributes.
- Calls are opt-in per invocation — nothing is emitted until you call a
record*method. - Empty
nameis rejected (InvalidContexton Node). - Extension lifecycle gate: degrade before READY / after shutdown; never throw (Go returns
error). - Node/Python keep an in-process list (
getRecorded()/signals.recorded) useful for tests.
Health
Purpose: “Is this component ok?” Typical fields:name, status (spec examples: ok, degraded).
- Node
- Python
- Go
- Java
Error
Purpose: A classified failure.errorKind uses the SDK’s 15-kind taxonomy (for example Timeout). message is redacted.
- Node
- Python
- Go
- Java
Metric
Purpose: A named observation. Specvalue is number, boolean, or string. Python’s helper types value as float. Optional unit.
- Node
- Python
- Go
- Java
recordMetric or recordOutcome.
Outcome
Purpose: Record that a result happened. This is a signal kind, not its own product object and not a separate docs page.signals.recordOutcome / record_outcome / RecordOutcome takes a name + status and optional rollout correlation (rolloutId, changeId on Python).
Node releases.complete() / fail() also records { kind: 'outcome', name: 'release', status: 'completed' | 'failed' }. Completing a release is still a different call from recording an application outcome (for example checkout completed).
- Node
- Python
- Go
- Java
signals.record({ kind, name, ... }). Java has signals().record(Signal).
Attribute allowlist
Unknown attribute keys are dropped, not rejected. String values are secret-redacted. Node default (DEFAULT_SIGNAL_ATTRIBUTE_ALLOWLIST, on unless you override telemetry.attributeAllowlist) and Python _SIGNAL_ATTRIBUTE_ALLOWLIST:
name, kind, status, value, unit, rolloutId, changeId, stampId, errorKind, message, flagKey, variant, environment, service
Go’s emission allowlist is slightly different: flagKey, variant, value, rolloutId, changeId, stampId, stampIds, status, name, kind, errorKind, message, metricValue.
Java signals use a fixed canonical field set; FireweaveConfig.telemetryAttributeAllowlist can filter further.
Do not send arbitrary PII as signal attributes and expect it to survive.
Batching and failure
- Signals are recorded when you call
record*. Remote adapters capture viaPOST /v1/capturewhen a sink is attached. - Node calls
adapter.recordSignalwhen present. Python callsdeliver_signaland swallows sink exceptions. - Telemetry loss must not break evaluate or login paths.
- After shutdown, calls degrade with
AlreadyClosed.
Related
- Releases — lifecycle vs
recordOutcome - Exposures — assignment proof
- Errors — the 15
errorKindvalues - Quickstart — record an outcome in the first-hour path