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/21 → TRACE/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:
- Installs
PontemFormatteron every handler currently on the root logger. Records flow through your existing handler chain unchanged, just with a Pontem-shaped wire format. - 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 = Falseto 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, soinfo/debugrecords are filtered before reaching any handler.basicConfig(level=logging.INFO)orlogging.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
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1925be73cf858c03291c6712e68358065bf43c37fbc3d28870aad693e9f67896
|
|
| MD5 |
c4a2c7cf74bd3b06b759955b405291c6
|
|
| BLAKE2b-256 |
9201b7af82377c97be9aca6e554e5c1ee2b1d0b8c4ef6942767ba24210ead228
|
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4a8c8697a2b019be513b2d779c6087d9ad0c91de9a572fc1ee83115bf0de2af3
|
|
| MD5 |
3631678e44c6c6d76a2a9ffc08e117ee
|
|
| BLAKE2b-256 |
76ad5e21fc5b6dcc3053b80864b0deccd062cf85e4e18cedb527c040d7e45519
|