Forja.Telemetry (Forja v0.4.0)

View Source

Telemetry event emission and default logger for Forja.

All events follow the [:forja, resource, action] convention and are emitted via :telemetry.execute/3.

Default Logger

Forja ships with an opt-in default logger that converts telemetry events into structured Logger calls. Activate it in your application.ex:

Forja.Telemetry.attach_default_logger(level: :info)

The :level option controls which categories of events are logged:

LevelEvents logged
:debugAll events (emitted, processed, deduplicated, reconciled, failed, validation_failed, dead_letter, abandoned)
:infoLifecycle + problems (emitted, processed, reconciled, failed, validation_failed, dead_letter, abandoned)
:warningProblems only (failed, validation_failed, dead_letter, abandoned)
:errorCritical only (dead_letter, abandoned)

Options

  • :level - Logger level tier (default: :info)
  • :include_payload - Include event payload in logs (default: false)
  • :encode - JSON-encode log output (default: false)
  • :events - :all (default) or explicit list like [:emitted, :processed]

Example

# Development: see everything including payloads
Forja.Telemetry.attach_default_logger(level: :debug, include_payload: true)

# Production: only problems
Forja.Telemetry.attach_default_logger(level: :warning, encode: true)

All log calls use domain: [:forja], so you can filter them:

# Suppress all Forja logs via Erlang logger filters
:logger.add_primary_filter(:no_forja, {&:logger_filters.domain/2, {:stop, :sub, [:forja]}})

Emitted events

  • emit_emitted(name, %{type: type} = attrs) emits [:forja, :event, :emitted]

    • Measurements: %{count: 1}
    • Metadata: %{name: atom, type: string, source: string, payload: map | nil, correlation_id: string | nil}

  • emit_processed(name, %{type: type, handler: handler, path: path, duration: duration}) emits [:forja, :event, :processed] when a handler processes successfully

    • Measurements: %{duration: native_time}
    • Metadata: %{name: atom, type: string, handler: module, path: atom()}
  • emit_failed(name, %{type: type, handler: handler, path: path, reason: reason}) emits [:forja, :event, :failed] when a handler fails

    • Measurements: %{count: 1}
    • Metadata: %{name: atom, type: string, handler: module, path: atom, reason: term}
  • [:forja, :event, :dead_letter] - When Oban discards a job (all attempts exhausted)

    • Measurements: %{count: 1}
    • Metadata: %{name: atom, event_id: binary, reason: term}
  • [:forja, :event, :abandoned] - When reconciliation also exhausts its retries

    • Measurements: %{count: 1}
    • Metadata: %{name: atom, event_id: binary, reconciliation_attempts: integer}
  • [:forja, :event, :reconciled] - When reconciliation successfully processes an event

    • Measurements: %{count: 1}
    • Metadata: %{name: atom, event_id: binary}
  • [:forja, :event, :deduplicated] - When an idempotency key prevents a duplicate emission

    • Measurements: %{count: 1}
    • Metadata: %{name: atom, idempotency_key: string, existing_event_id: binary}
  • [:forja, :event, :validation_failed] - When payload validation fails at emit-time

    • Measurements: %{count: 1}
    • Metadata: %{name: atom, type: string | module, errors: term}

Summary

Functions

Attaches the default logger that converts Forja telemetry events into structured Logger calls with domain: [:forja].

Returns the telemetry handler ID used by the default logger.

Detaches the default logger.

Emits a telemetry event when reconciliation exhausts all retries (abandoned).

Emits a telemetry event when Oban discards a job (dead letter).

Emits a telemetry event when an idempotency key prevents a duplicate emission.

Emits a telemetry event for event emission.

Emits a telemetry event for handler failure.

Emits a telemetry event for successful handler processing.

Emits a telemetry event when reconciliation successfully processes an event.

Emits a telemetry event when payload validation fails at emit-time.

Functions

attach_default_logger(opts \\ [])

@spec attach_default_logger(keyword()) :: :ok | {:error, :already_exists}

Attaches the default logger that converts Forja telemetry events into structured Logger calls with domain: [:forja].

Options

  • :level - Controls which event categories are logged. One of :debug, :info, :warning, :error. Default: :info.
  • :include_payload - When true, includes the event payload in :emitted log entries. Default: false.
  • :encode - When true, JSON-encodes the log output. Default: false.
  • :events - :all to use the level tier (default), or an explicit list of category atoms like [:emitted, :processed, :failed].

default_handler_id()

@spec default_handler_id() :: String.t()

Returns the telemetry handler ID used by the default logger.

detach_default_logger()

@spec detach_default_logger() :: :ok | {:error, :not_found}

Detaches the default logger.

emit_abandoned(name, event_id, reconciliation_attempts)

@spec emit_abandoned(atom(), String.t(), non_neg_integer()) :: :ok

Emits a telemetry event when reconciliation exhausts all retries (abandoned).

emit_dead_letter(name, event_id, reason)

@spec emit_dead_letter(atom(), String.t(), term()) :: :ok

Emits a telemetry event when Oban discards a job (dead letter).

emit_deduplicated(name, idempotency_key, existing_event_id)

@spec emit_deduplicated(atom(), String.t(), String.t()) :: :ok

Emits a telemetry event when an idempotency key prevents a duplicate emission.

emit_emitted(name, attrs)

@spec emit_emitted(atom(), map()) :: :ok

Emits a telemetry event for event emission.

emit_failed(name, map)

@spec emit_failed(atom(), map()) :: :ok

Emits a telemetry event for handler failure.

emit_processed(name, map)

@spec emit_processed(atom(), map()) :: :ok

Emits a telemetry event for successful handler processing.

emit_reconciled(name, event_id)

@spec emit_reconciled(atom(), String.t()) :: :ok

Emits a telemetry event when reconciliation successfully processes an event.

emit_validation_failed(name, type, errors)

@spec emit_validation_failed(atom(), String.t() | module(), [map()]) :: :ok

Emits a telemetry event when payload validation fails at emit-time.