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.0.0.tar.gz (8.9 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.0.0-py3-none-any.whl (11.1 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: chime_logger-1.0.0.tar.gz
  • Upload date:
  • Size: 8.9 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.0.0.tar.gz
Algorithm Hash digest
SHA256 52d51ebddac764fcf28a7f1c8c63229068a79993f24d901bb30a7d7df79b7895
MD5 2b4bc6d1c0ad253af62b3250e43b234e
BLAKE2b-256 def401eddc9c860373afc404c00798a9c9580c96c887b93efb52609854674a7b

See more details on using hashes here.

File details

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

File metadata

  • Download URL: chime_logger-1.0.0-py3-none-any.whl
  • Upload date:
  • Size: 11.1 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.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 060ed7bbde0805f96a5e73582aaf6dc12e284698d09db38ca5825df58346fd4a
MD5 c7eb3285a11bee113274f19b291e7758
BLAKE2b-256 30756d6a139434e91342c5ef2534dc98fc16eda605496d3e92a51b7d659f118f

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