Usage⚓︎
Tracing options⚓︎
Fine-grained control with the @trace() decorator:
@trace(
message="Custom trace message",
stack=True, # Include stack trace on errors
sample_rate=0.5, # Optional local override for this trace
adaptive_sampling=True, # Optional local adaptive override
adaptive_slow_threshold=0.25, # Optional local slow-threshold override (seconds)
modules_or_classes=[my_module],
include=["specific_function_*"],
exclude=["ignored_function_*"],
recursive_depth=2,
module_pattern="myapp.*",
)
def function():
pass
Sampling⚓︎
Global env controls:
EZTRACE_SAMPLE_RATE(0.0to1.0, default1.0)EZTRACE_ADAPTIVE_SAMPLING(true/false, defaultfalse)EZTRACE_ADAPTIVE_SLOW_THRESHOLD(seconds,>= 0.0, default1.0)
Local override:
@trace(
sample_rate=1.0, # Force this trace to always be kept
adaptive_sampling=True, # Local adaptive mode override
adaptive_slow_threshold=0.1 # Local slow threshold override
)
def critical_path():
pass
Adaptive mode keeps slow/error traces at 100% and samples normal traces using the configured rate.
Recursive tracing⚓︎
Trace the function and functions in imported modules:
@trace(recursive_depth=1, module_pattern="myapp.*")
def app_entry():
# Traces this and matching imported modules
pass
Use module_pattern to avoid tracing system or third-party code.
Redacting sensitive data⚓︎
@trace(
redact_keys=["password", "token"],
redact_value_patterns=[r"secret\d+"],
redact_presets=["pii"],
)
def process(user, password, token):
return {"user": user, "status": "ok"}
Environment defaults: EZTRACE_REDACT_KEYS, EZTRACE_REDACT_PATTERN, EZTRACE_REDACT_VALUE_PATTERNS, EZTRACE_REDACT_PRESETS.
Context management⚓︎
Thread-safe context propagation:
with log.with_context(user_id="123", action="login"):
log.log_info("User logged in") # Includes context
with log.with_context(session="abc"):
log.log_info("Session started") # Inherits parent context
Output formats⚓︎
| Format | Use case |
|---|---|
color |
Default console; hierarchical tree |
json |
Machine-readable; required for the viewer |
plain |
Simple text |
csv |
Spreadsheet analysis |
logfmt |
System-style key=value |
Per-sink: set console_format and file_format via Setup.initialize(..., console_format="color", file_format="json") or env EZTRACE_CONSOLE_LOG_FORMAT / EZTRACE_FILE_LOG_FORMAT.
Interactive viewer⚓︎
- Enable JSON file logging (e.g.
Setup.initialize(..., file_format="json", disable_file_logging=False)). - Run your app to produce logs.
- Start the viewer:
Open http://127.0.0.1:8765. You get:
- Hierarchical tree (parent/child calls)
- Input/output previews, duration, CPU, memory
- Filters (function, error, min duration), auto-refresh
Note: The trace viewer UI (
pyeztrace serve) is designed for local development and analysis—it is not intended to be used as a hosted or production solution.
Async support⚓︎
Setup and level tracking are async-safe.
Redirecting print to logging⚓︎
from pyeztrace import print # noqa: A001
Setup.initialize("MyApp")
print("Hello") # INFO
print("Warning", level="WARNING") # WARNING
Falls back to built-in print if EzTrace is not initialized or when writing to a custom file.
Performance metrics⚓︎
At exit, a summary is printed: calls, total time, average per function.
Error handling⚓︎
log.log_debug("Debug")
log.log_info("Info")
log.log_warning("Warning")
log.log_error("Error")
try:
risky()
except Exception as e:
log.raise_exception_to_log(e, "Custom message", stack=True)
Applying @trace to classes⚓︎
Decorate a class to trace all its methods (including __init__):
from pyeztrace import trace
@trace()
class MyService:
def __init__(self, name):
self.name = name
def process(self, data):
return data.upper()
def analyze(self, data):
return len(data)
Each method gets full tracing (start/end, duration, args/result preview).
Double-tracing prevention⚓︎
PyEzTrace avoids duplicate trace entries when:
- A function is decorated with
@traceand also called from another traced function - A class is decorated and also traced via recursive tracing
- The same function is traced from multiple parent functions (recursive tracing)
Only one trace is emitted per call, so logs stay clean while coverage stays full.
Thread-safe high-volume logging⚓︎
The logger and tracer are thread-safe. Example with a thread pool:
from concurrent.futures import ThreadPoolExecutor
from pyeztrace import trace
from pyeztrace.custom_logging import Logging
log = Logging()
@trace()
def worker(worker_id):
with log.with_context(worker_id=worker_id):
log.log_info("Started")
# ... work ...
log.log_info("Finished")
with ThreadPoolExecutor(max_workers=5) as executor:
executor.map(worker, range(5))
Global redaction (programmatic)⚓︎
Set default redaction for all traces in code:
from pyeztrace import set_global_redaction
set_global_redaction(
redact_keys=["password", "token"],
redact_pattern=r"(?i)secret",
redact_value_patterns=[r"secret\d+"],
presets=["pii"],
)
Same options as per-decorator redact_keys, redact_pattern, redact_value_patterns, and redact_presets.
CLI⚓︎
| Command | Description |
|---|---|
pyeztrace serve <log_file> |
Start the interactive trace viewer (default: http://127.0.0.1:8765) |
pyeztrace print <log_file> |
Print or filter log entries from a file |
Viewer:
Optional env: EZTRACE_VIEW_HOST, EZTRACE_VIEW_PORT.
Print / analyze logs:
pyeztrace print logs/app.log
pyeztrace print logs/app.log --analyze
pyeztrace print logs/app.log --function my_func --format json
Use --level, --since, --until to filter. --analyze shows performance metrics; --function limits analysis to that function.
OpenTelemetry (optional)⚓︎
Install: pip install "pyeztrace[otel]". Enable with environment variables.
OTLP (collector):
export EZTRACE_OTEL_ENABLED=true
export EZTRACE_OTEL_EXPORTER=otlp
export EZTRACE_OTLP_ENDPOINT="http://localhost:4318/v1/traces"
# optional: export EZTRACE_SERVICE_NAME="my-service"
Google Cloud Trace (OTLP + ADC):
pip install "pyeztrace[otel,gcp]"
export EZTRACE_OTEL_ENABLED=true
export EZTRACE_OTEL_EXPORTER=gcp
# optional override; defaults to telemetry endpoint for exporter=gcp
export EZTRACE_OTLP_ENDPOINT="https://telemetry.googleapis.com/v1/traces"
# optional explicit toggle
export EZTRACE_OTLP_GCP_AUTH=true
If Cloud Trace returns Resource is missing required attribute "gcp.project_id", set:
EZTRACE_GCP_PROJECT_ID (or GOOGLE_CLOUD_PROJECT / GCLOUD_PROJECT / GCP_PROJECT).
Console (local dev):
S3 / Azure: Install pyeztrace[s3] or pyeztrace[azure], set EZTRACE_OTEL_EXPORTER=s3 or azure, and the bucket/container and credential env vars. See the README OpenTelemetry section for full S3/Azure options.
The bridge is lazy-loaded; if OTEL packages are missing, the library still works without spans. Spans use function __qualname__; exceptions are recorded on the active span.
For troubleshooting, enable OTEL diagnostics:
And inspect runtime OTEL state in code:
otel.get_otel_status() is available in newer builds after 0.1.1.