Skip to main content

CHIME/FRB telemetry wrapper around HelixObs — traces and logs via OTLP.

Project description

CHIME Logger

CHIME Logger is a CHIME/FRB telemetry wrapper around HelixObs. It ships traces and logs to the HelixObs herald via OTLP, writes a local rotating file log, and automatically injects CHIME context (resource_name, resource_type, pipeline, site) into every log record — without any boilerplate.

How it works

CHIME Logger wraps the HelixObs Python client with a CHIME-specific CHIMETracer. When you enter an operate() or create() block, the tracer stamps the span with CHIME attributes (chime.resource_type, chime.pipeline, chime.site). A log-record factory — installed at the root logger level, the same way HelixObs injects trace context — reads those attributes from the active span and stamps them onto every LogRecord at creation time, before any handler sees it. This means any logger in the process automatically carries resource_name, resource_type, pipeline, and site inside an operate() or create() block, regardless of its name.

Spans flow to the HelixObs herald, which writes entity rows to TimescaleDB, links provenance, and drives notifications and dashboards. See the HelixObs documentation for the full entity model, provenance DAG, and herald architecture.

Installation

pip install chime_logger
# or
poetry add chime_logger
# or
uv add chime_logger

Usage

Setup

Call setup() once at process start. It returns a CHIMETracer singleton wired to the HelixObs herald.

import chime_logger
import logging

tel = chime_logger.setup(pipeline="datatrail-registration")
log = logging.getLogger(__name__)   # any logger name works

Logger name: you can use any logger — logging.getLogger(__name__), logging.getLogger("CHIME"), or anything else. CHIME context fields are injected at record-creation time via a root-level factory, so the name does not matter for context enrichment or OTLP log shipping. The only distinction is that records from loggers named "CHIME" or "CHIME.*" are also written to the local rotating file.


Creating new entities — create()

Use create() when a new entity enters the pipeline for the first time — a new beam candidate, a new baseband acquisition, a new FRB event. This registers the entity in the HelixObs provenance DAG, making it discoverable in the Entity Inspector and linkable to its parents.

with tel.create("l1-search", resource_name=beam_id, resource_type="n2_acquisition", parents=[block_id]) as token:
    log.info("Processing beam")   # resource_name, resource_type, pipeline, site auto-injected

parents links this entity to its upstream origins. The herald resolves those links into a navigable provenance DAG — so you can trace an FRB event back to the raw data block it came from. See the HelixObs provenance guide for details.


Processing existing entities — operate()

Use operate() when performing a pipeline stage on an entity that already exists — registering it in a catalog, replicating its data, converting its format. Each operate() call creates an operation row in HelixObs, giving you a timestamped history of every stage an entity passed through.

with tel.operate("register", resource_name=event_id, resource_type="event") as token:
    log.info("Registering event")
    register_in_catalog(event_id)

The full operation timeline is visible per-entity in the HelixObs Entity Inspector dashboard.


Marking scientifically notable signals — add_event()

token.add_event() records a named helix event on the entity. Unlike a log line, helix events are stored in a structured entity_events table in TimescaleDB and are queryable across all entities. Use them for domain signals that matter beyond the log stream.

with tel.operate("classify", resource_name=event_id, resource_type="event") as token:
    classification = classify(event_id)
    token.add_event("helix.event.classified", {"classification": classification, "dm": str(dm)})

Helix events appear in the Entity Inspector's event timeline and can be used to drive notifications (see below).


Recording errors — add_error() and error()

These are not log lines — they are helix error events. When the herald receives a helix.error event, it:

  1. Marks the entity with has_error = true in the database.
  2. Surfaces it in the Error Entities Grafana dashboard for immediate visibility.
  3. Triggers a Slack notification and opens a GitHub issue for diagnosis (if configured for your instrument).
  4. Deduplicates repeated occurrences and updates the issue body with running statistics rather than spamming a new alert each time.

token.add_error() — records a recoverable error. The span stays open so the operation can continue or attempt recovery.

with tel.operate("replicate", resource_name=event_id, resource_type="event") as token:
    for dest in destinations:
        try:
            replicate_to(dest)
        except TimeoutError as e:
            token.add_error({"destination": dest, "reason": str(e)})
            log.warning(f"Replication to {dest} timed out, continuing")
    # span completes normally after the loop

token.error() — records the error and immediately closes the span as failed. Use this when the operation cannot recover.

with tel.operate("register", resource_name=event_id, resource_type="event") as token:
    try:
        register_in_catalog(event_id)
    except Exception as e:
        token.error({"reason": str(e)})   # closes span as failed
        raise

Note: The context manager calls token.error() automatically if an unhandled exception escapes the with block, so explicit token.error() is only needed when you want to attach structured metadata to the error.


Child spans

Use child_span() for internal steps that should appear in the Tempo trace view but don't need their own entity row in HelixObs.

with tel.operate("register", resource_name=event_id, resource_type="event") as token:
    with tel.child_span("catalog-lookup"):
        result = lookup_catalog(event_id)
    with tel.child_span("db-write"):
        write_to_db(result)

This keeps the Tempo trace detailed without polluting the entity provenance DAG with internal implementation steps.


Automatic log context injection

Inside any operate() or create() block, every log call from any logger in the process automatically carries:

Field Source
resource_name helix.entity.id from the active span
resource_type chime.resource_type from the active span
pipeline chime.pipeline from the active span, then CHIME_LOGGER_PIPELINE_NAME
site chime.site from the active span, then CHIME_LOGGER_SITE

Outside any span, logging still works — context fields fall back to the environment variables above, then to unknown_name / unknown_type / unknown_pipeline / unknown_site.

Accessing the singleton

tel = chime_logger.get_tracer()   # None if setup() has not been called yet

Configuration

All connection and site parameters come from environment variables.

Variable Default Description
HERALD_ENDPOINT localhost:4317 OTLP gRPC address for traces
LOGS_ENDPOINT localhost:4317 OTLP gRPC address for logs
CHIME_LOGGER_SITE (unset) Site name: chime, kko, gbo, hco
CHIME_LOGGER_PIPELINE_NAME (unset) Pipeline name fallback when not passed to setup()
CHIME_LOGGER_FILE_LOG_PATH logs/chime_pipeline.log Path for the rotating file log
HERALD_INSECURE true Set to false for TLS connections
HERALD_CREDENTIAL (unset) Registration secret or existing JWT
HERALD_AUTH_ENDPOINT (unset) Herald /auth/token URL (required when HERALD_CREDENTIAL is set)

License

See LICENSE for details.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

chime_logger-1.1.0.tar.gz (9.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

chime_logger-1.1.0-py3-none-any.whl (11.2 kB view details)

Uploaded Python 3

File details

Details for the file chime_logger-1.1.0.tar.gz.

File metadata

  • Download URL: chime_logger-1.1.0.tar.gz
  • Upload date:
  • Size: 9.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/2.2.1 CPython/3.9.25 Linux/6.17.0-1015-azure

File hashes

Hashes for chime_logger-1.1.0.tar.gz
Algorithm Hash digest
SHA256 0422dd616814d4b6e0f537dc71d6357e3858c64633578e47a7bbc4f327034da5
MD5 09332a263731cae3549a53e13ecaefcf
BLAKE2b-256 d38b9e3f02d158921b5d6ab53af0d486353085fc9e151e1122cfc54d5a348a88

See more details on using hashes here.

File details

Details for the file chime_logger-1.1.0-py3-none-any.whl.

File metadata

  • Download URL: chime_logger-1.1.0-py3-none-any.whl
  • Upload date:
  • Size: 11.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/2.2.1 CPython/3.9.25 Linux/6.17.0-1015-azure

File hashes

Hashes for chime_logger-1.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 b2fb42000fa5eecadb240cf5bc238b137f14e523c7d8adcfd5d939b0e8832fc0
MD5 93c19d8cdfcf83a116652038b2b6e94d
BLAKE2b-256 cafa4329c068d14d83fe0a0ab7cd4cbc11766ec335c1c9b4593bab655e872864

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page