Skip to main content

Pontem edge SDK — logs, metrics, and config for edge devices

Project description

Pontem Python SDK

Pontem Python SDK for logs, metrics, and config on Pontem-managed edge devices. Zero runtime dependencies.

Installation

pip install pontem

Quick Start

Already using stdlib logging? This is the fastest integration — one extra init flag, no call-site changes:

import logging
import pontem

# 1. Your existing logging config runs first — unchanged.
logging.basicConfig(level=logging.INFO)

# 2. One init call enables the integration.
pontem.init(service_name="my-service", stdlib_logging=True)

# 3. Existing call sites keep working, now emit Pontem JSONL on the wire.
logging.getLogger(__name__).info("model loaded", extra={"model": "v3"})

stdlib_logging=True swaps the formatter on every handler currently attached to the root logger. Destinations, rotation policies, and filters stay in place — only the on-the-wire format changes. pontem.logger.* continues to work alongside; records from either path share the same wire shape. SDK-internal records (pontem.sdk, pontem.emit, …) propagate to your chain too — they include useful WARN/ERROR signal (queue overflow, writer errors). Filter the noise via logging.getLogger("pontem").setLevel(logging.WARNING) if you want only the loud ones.

Order matters: run your logging setup (basicConfig, dictConfig, manual addHandler calls, …) before pontem.init(stdlib_logging=True). Otherwise root has no handlers to swap and init raises. See Logging for explicit-handler and dictConfig patterns where this ordering is structural rather than implicit.

Greenfield code, or a hot path? Call pontem.logger.* directly. The direct API is non-blocking, queued, with background-thread I/O — designed for inference loops on edge devices:

import pontem

pontem.init(service_name="my-service")

pontem.logger.info("model loaded", model="scoring_v3")

pontem.metrics.count("detections", class_name="apple")
with pontem.metrics.timer("model.inference"):
    result = model.predict(frame)

pontem.shutdown()

Logging

Structured logs with OTel-aligned severity levels (severityNumber 1/5/9/13/17/21TRACE/DEBUG/INFO/WARN/ERROR/FATAL). The wire format is identical regardless of which path you use — collectors see one shape. See SCHEMA.md for the full record contract.

Drop-in via pontem.init(stdlib_logging=True) (recommended)

The one-flag path is the easiest on-ramp:

import logging
import pontem

logging.basicConfig(level=logging.INFO)
pontem.init(service_name="my-service", stdlib_logging=True)

logging.getLogger(__name__).info("model loaded", extra={"model": "v3"})

What the flag does:

  1. Installs PontemFormatter on every handler currently on the root logger. Records flow through your existing handler chain unchanged, just with a Pontem-shaped wire format.
  2. That's it. No other side effects. SDK-internal records (pontem.sdk, pontem.emit, …) propagate to your chain like any other library's logs — useful for debugging integration issues (queue overflow, writer errors). If you don't want them, filter via standard stdlib mechanisms: logging.getLogger("pontem").setLevel(logging.WARNING) to keep only WARN+, or .propagate = False to drop them entirely.

pontem.logger.* continues to work alongside — it goes through the SDK's emit pipeline and produces the same wire shape. You can mix paths if you want (e.g., direct API on a hot inference path, stdlib elsewhere); the collector sees one schema.

Explicit PontemFormatter (advanced)

When you want to attach the formatter to specific handlers — e.g. a RotatingFileHandler writing to a custom path — use PontemFormatter directly. The flag-based path won't help you here because it only touches root handlers and you may not want all of them reformatted.

from logging.handlers import RotatingFileHandler
from pontem.log import PontemFormatter

handler = RotatingFileHandler("/var/log/myapp/app.log", maxBytes=10_000_000)
handler.setFormatter(PontemFormatter(service_name="my-service"))
logging.getLogger().addHandler(handler)

For logging.config.dictConfig (YAML/JSON config), reference the formatter by class:

formatters:
  pontem:
    (): pontem.log.PontemFormatter
    service_name: my-service
handlers:
  console:
    class: logging.StreamHandler
    formatter: pontem
root:
  handlers: [console]
  level: INFO

Resource attributes (service.name, service.version, device.id, …) come from constructor kwargs first, then fall back to whatever pontem.init() populated. service.name is required from at least one source — the constructor raises if neither provides it.

Notes (apply to both paths):

  • Set the root level. Stdlib's default is WARNING, so info/debug records are filtered before reaching any handler. basicConfig(level=logging.INFO) or logging.getLogger().setLevel(...) is the standard fix.
  • Records do not flow through Pontem's emit pipeline. They take whatever path your existing handler already uses (sync I/O for FileHandler, etc.). For non-blocking, queued, rotation-and-gzip behavior, use the direct API on hot paths.

Direct API

For greenfield code or hot paths where you want the SDK's non-blocking emit pipeline (bounded queue, background-thread serialization, rotation + gzip in file mode):

pontem.logger.info("model loaded", model="scoring_v3")
pontem.logger.warn("high latency", latency_ms=120)
pontem.logger.error("inference failed", error=str(e))

Available levels: trace, debug, info, warn, error, fatal.

In file mode (default), each log is written to logs.jsonl in the emit directory. In stdout mode, records are written one-per-line to sys.stdout. See Stdout emit below.

Stdout emit (Docker / compose)

This setting only affects the direct API. The Formatter path always writes through the user's own handler chain and is unaffected.

For containerized deployments where a sidecar log collector tails the container's stdout, switch the direct API from file mode to stdout mode:

import pontem

pontem.init(service_name="my-service", emit_target="stdout")

Equivalently, set the env var (useful when the same image runs on both edge devices and compose hosts):

PONTEM_EMIT_TARGET=stdout

Selection precedence: init(emit_target=...) kwarg > PONTEM_EMIT_TARGET env var > default "file". In stdout mode emit_dir, file rotation, and gzip compression are no-ops — the docker daemon's json-file driver handles container log rotation.

Metrics

Metrics are aggregated in memory and flushed periodically to metrics.jsonl. No I/O on the caller's thread.

# Counters — incremented, flushed as a single sum
pontem.metrics.count("detections", class_name="apple")
pontem.metrics.count("bytes_sent", len(payload))

# Histograms — records min/max/sum/count summary
pontem.metrics.record("payload_size", len(data), unit="bytes")

# Gauges — last value wins
pontem.metrics.set_gauge("gpu_temp", 72.0, unit="celsius", gpu="0")

# Timers — context manager or decorator, records to histogram
with pontem.metrics.timer("model.inference"):
    result = model.predict(frame)

@pontem.metrics.timer("preprocessing")
def preprocess(frame):
    ...

Config

Reads agent-managed config from /opt/pontem/config/config.json (or $PONTEM_CONFIG_DIR).

threshold = pontem.config("my_namespace", "model_threshold", default=0.85)

# Reload after agent signals a config update
pontem.config.reload()

Shutdown

Flushes remaining metrics and logs. Also registered via atexit.

pontem.shutdown()

Documentation

See docs/getting-started.md for a comprehensive guide including full API reference, configuration options, and troubleshooting.

License

Apache 2.0 — see LICENSE.

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

pontem-0.2.0.tar.gz (21.4 kB view details)

Uploaded Source

Built Distribution

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

pontem-0.2.0-py3-none-any.whl (22.3 kB view details)

Uploaded Python 3

File details

Details for the file pontem-0.2.0.tar.gz.

File metadata

  • Download URL: pontem-0.2.0.tar.gz
  • Upload date:
  • Size: 21.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for pontem-0.2.0.tar.gz
Algorithm Hash digest
SHA256 1925be73cf858c03291c6712e68358065bf43c37fbc3d28870aad693e9f67896
MD5 c4a2c7cf74bd3b06b759955b405291c6
BLAKE2b-256 9201b7af82377c97be9aca6e554e5c1ee2b1d0b8c4ef6942767ba24210ead228

See more details on using hashes here.

File details

Details for the file pontem-0.2.0-py3-none-any.whl.

File metadata

  • Download URL: pontem-0.2.0-py3-none-any.whl
  • Upload date:
  • Size: 22.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for pontem-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 4a8c8697a2b019be513b2d779c6087d9ad0c91de9a572fc1ee83115bf0de2af3
MD5 3631678e44c6c6d76a2a9ffc08e117ee
BLAKE2b-256 76ad5e21fc5b6dcc3053b80864b0deccd062cf85e4e18cedb527c040d7e45519

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