Logging Guide¶
Rustvello uses a unified logging model for both runtimes:
Rust (
tracing) emits text lines tagged with[R]or NDJSON with"system": "rust"Python (
logging) emits text lines tagged with[P]or NDJSON with"system": "python"
This keeps search, parsing, and dashboards consistent across the FFI boundary.
Unified Text Format (default)¶
Example output:
2026-03-27T10:23:45.123Z INFO [R] my_app [PTR(a86ab1f8).W(d1241003)cc6c0e34-5678-9abc-def0-123456789abc:core_tasks.recover] rustvello::runner Invocation completed
2026-03-27T10:23:45.456Z INFO [P] my_app [PTR(a86ab1f8)cc6c0e34-5678-9abc-def0-123456789abc:tasks.add] pynenc.my_app Executing task function
Template:
{timestamp} {level:5} [R|P] {app_id} [{context}] {logger} {message}
| Field | Description |
| ———– | —————————————————————- | ——————————————– |
| timestamp | UTC ISO 8601 with milliseconds (YYYY-MM-DDTHH:MM:SS.mmmZ) |
| level | Padded level (TRACE, DEBUG, INFO, WARN, ERROR, CRIT) |
| [R | P] | Runtime origin tag: Rust [R], Python [P] |
| app_id | Pynenc application ID |
| context | Optional execution context (runner, worker, invocation, task) |
| logger | Rust target or Python logger name |
| message | Human-readable log message |
JSON Format¶
Enable NDJSON output:
PYNENC__LOG_FORMAT=json pynenc --app=tasks.app runner start
Example line:
{
"timestamp": "2026-03-27T10:23:45.123Z",
"severity": "INFO",
"system": "rust",
"logger": "rustvello::runner",
"message": "Invocation completed",
"runner_class": "PTR",
"runner_id": "a86ab1f8-1111-2222-3333-444455556666",
"worker_id": "d1241003-1111-2222-3333-444455556666",
"invocation_id": "cc6c0e34-5678-9abc-def0-123456789abc",
"task_id": "core_tasks.recover",
"text": "2026-03-27T10:23:45.123Z INFO [R] my_app [PTR(a86ab1f8).W(d1241003)cc6c0e34-5678-9abc-def0-123456789abc:core_tasks.recover] rustvello::runner Invocation completed"
}
Common fields:
Field |
Type |
Always Present |
Description |
|---|---|---|---|
|
string |
Yes |
UTC timestamp |
|
string |
Yes |
Log level ( |
|
string |
Yes |
|
|
string |
Yes |
Logger/target name |
|
string |
Yes |
Message body |
|
string |
Yes |
Human-readable unified line |
|
string |
No |
Runner context |
|
string |
No |
Worker context |
|
string |
No |
Invocation context |
|
string |
No |
Task context |
Python JSON logs can also include exception and stack_info when present.
Configuration¶
Environment Variables¶
Variable |
Values |
Default |
Description |
|---|---|---|---|
|
|
|
Shared pynenc log level |
|
|
|
Unified text or NDJSON output |
|
|
|
Log destination stream |
|
|
auto-detect |
ANSI colors for text mode |
|
|
|
Compact IDs and class names in context |
Python Builder API¶
from pynenc import PynencBuilder
app = (
PynencBuilder()
.app_id("my-app")
.rustvello(backend="sqlite")
.logging(level="debug", fmt="json", stream="stdout", colors=False)
.build()
)
Notes¶
Pynenc initializes Python logging and then calls
rustvello.init_logging(...)for Rust.If
RUST_LOGis set, Rust’stracingfilter followsRUST_LOGprecedence.
Integration Examples¶
ELK Stack¶
# filebeat.yml
filebeat.inputs:
- type: log
paths:
- /var/log/pynenc/*.log
json:
keys_under_root: true
add_error_key: true
output.logstash:
hosts: ["logstash:5044"]
# logstash filter
filter {
if [system] == "rust" {
mutate { add_tag => ["rust_runtime"] }
} else if [system] == "python" {
mutate { add_tag => ["python_runtime"] }
}
}
Datadog¶
# conf.d/pynenc.d/conf.yaml
logs:
- type: file
path: /var/log/pynenc/*.log
service: pynenc
source: pynenc
Grafana Loki (Promtail)¶
scrape_configs:
- job_name: pynenc
static_configs:
- targets: [localhost]
labels:
job: pynenc
__path__: /var/log/pynenc/*.log
pipeline_stages:
- json:
expressions:
system: system
severity: severity
logger: logger
- labels:
system:
severity:
Troubleshooting¶
Verify Effective Level¶
PYNENC__LOGGING_LEVEL=debug pynenc --app=tasks.app runner start 2>&1 | head -20
Filter by Runtime¶
# Text logs
grep "\[R\]" app.log
grep "\[P\]" app.log
# JSON logs
jq 'select(.system == "rust")' app.log
jq 'select(.system == "python")' app.log
Common Issues¶
Symptom |
Likely Cause |
Fix |
|---|---|---|
Rust and Python levels differ |
|
Unset |
Only |
Running without Rust backends |
Use |
Mixed text and JSON output |
Format changed after app init |
Set |
JSON parser misses context fields |
Log line has no runner/invocation context |
Expected for app-level or startup logs |
See also: Pynenc Docs
To see how logging behaves in the higher-level Python system and runners, check out the Pynenc Getting Started and Pynenc Runner Usage Guide.