Tero Edge is a lightweight, high-performance telemetry proxy that enables efficient telemetry processing via a set of policies. The repository is structured as modular packages that can be composed to enable multiple use cases and scenarios. The proxy demonstrates how to implement the policy spec described in this OTEP. This project is not meant to replace the opentelemetry collector but rather work in tandem with it, providing a lightweight alternative for solely applying policies. It's expected that a follow up to this project will be a collector processor Policy implementation.
-
Edge data proxy - Receives data in a gateway or sidecar configuration, processes the data through its policy engine, and forwards it to the next destination.
-
OTLP (OpenTelemetry) proxy - Receives OpenTelemetry logs via the
/v1/logsendpoint, applies policy-based filtering (DROP/KEEP), and forwards to OTLP-compatible backends. -
Datadog proxy - Receives OpenTelemetry logs via the
/api/v2/logsendpoint, applies policy-based filtering (DROP/KEEP), and forwards to Datadog. -
Prometheus proxy - Sits as a sidecar next to your application, proxies
/metricsscrapes with streaming policy-based metric filtering, and forwards filtered metrics to Prometheus. -
Tail distribution - Tails files/stdin, applies include/exclude/filter rules, and forwards or writes line-oriented output.
src/
├── main.zig # Default distribution entry point
├── datadog_main.zig # Datadog-focused distribution entry point
├── otlp_main.zig # OTLP-focused distribution entry point
├── prometheus_main.zig # Prometheus-focused distribution entry point
├── edge_tail_main.zig # Tail-focused distribution entry point
├── lambda_main.zig # AWS Lambda extension entry point
├── root.zig # Library root (public API exports)
│
├── modules/ # Protocol-specific processing modules
├── proxy/ # HTTP proxy infrastructure
├── prometheus/ # Prometheus metric parsing and filtering
├── config/ # Configuration parsing (non-policy)
├── lambda/ # AWS Lambda extension support
└── zonfig/ # Comptime configuration with env overrides
Edge consumes the following shared modules from policy-zig:
policy_zig- Policy engine, registry, matchers, transforms, and Hyperscan/Vectorscan bindingsproto- Protobuf types (policy, common, OTLP logs/metrics/trace/resource)o11y- Observability (EventBus, structured logging, spans)
Each package is designed to be as independent as possible, with clear interfaces for integration.
Protocol-specific request processing modules that plug into the proxy infrastructure.
Key exports:
ProxyModule- Vtable interface for request processingModuleRegistration- Module configuration (routes, upstream, etc.)DatadogModule- Datadog log ingestion with policy-based filteringOtlpModule- OpenTelemetry log ingestion with policy-based filteringPrometheusModule- Prometheus metrics scraping with streaming policy-based filteringPassthroughModule- No-op passthrough for unhandled routes
Dependencies: policy_zig, proto, o11y
The OTLP module handles OpenTelemetry log ingestion with policy-based filtering.
It processes the standard OTLP JSON format (ExportLogsServiceRequest).
Supported filter match cases:
log_body- Match against log message bodylog_severity_text- Match against severity text (INFO, DEBUG, ERROR, etc.)log_severity_number- Match against severity number (1-24)log_attribute- Match against log record attributesresource_attribute- Match against resource attributes (e.g.,service.name)scope_name- Match against instrumentation scope namescope_version- Match against instrumentation scope versionscope_attribute- Match against scope attributes
Routes:
POST /v1/logs- OTLP log ingestion endpoint
Core HTTP proxy server and routing infrastructure.
Key exports:
ProxyServer- HTTP server with module-based request routingRouter- Route matching (path patterns, method bitmasks)UpstreamClient- HTTP client for forwarding requestscompress- gzip compression/decompression utilities
Dependencies: o11y, links to httpz
Streaming Prometheus exposition format parsing and policy-based filtering.
Key exports:
PolicyStreamingFilter- Streaming filter that applies policies to metricsFilteringWriter- Writer that filters metrics line-by-lineFieldAccessor- Maps policy field references to Prometheus metric fieldsLineParser- Prometheus exposition format parser
Dependencies: policy_zig, proto, o11y
Application configuration loading and parsing (non-policy configuration).
Key exports:
ProxyConfig- Main proxy configuration structProviderConfig- Policy provider configuration (re-exported from policy-zig)ServiceMetadata- Service metadata (re-exported from policy-zig)
Dependencies: policy_zig
Distributions are pre-configured entry points that compose packages for specific use cases.
Full distribution supporting both Datadog and OTLP ingestion with:
- Handles Datadog
/api/v2/logsand/api/v2/seriesendpoints - Handles OTLP
/v1/logsand/v1/metricsendpoints - Policy-based filtering (DROP/KEEP) for logs and metrics
- Separate upstream URLs for logs and metrics (optional)
- Async policy loading (server starts immediately while policies load in background)
- Fail-open behavior (errors pass data through unchanged)
- Lock-free policy updates via atomic snapshots
- Graceful shutdown with signal handling
- SIGSEGV handler for crash diagnostics with stack traces
Build: zig build (default) Run: zig build run or
./zig-out/bin/edge [config-file]
Focused distribution for Datadog log and metrics ingestion with:
- Handles
/api/v2/logsand/api/v2/seriesendpoints - Policy-based filtering (DROP/KEEP)
- Separate upstream URLs for logs and metrics (optional)
- Async policy loading (non-blocking startup)
- Fail-open behavior (errors pass data through)
- Lock-free policy updates via atomic snapshots
- Graceful shutdown with signal handling
- SIGSEGV handler for crash diagnostics
Build: zig build datadog Run: zig build run-datadog or
./zig-out/bin/edge-datadog [config-file]
Focused distribution for OpenTelemetry Protocol (OTLP) log ingestion with:
- Handles
/v1/logsendpoint (OTLP JSON format) - Policy-based log filtering (DROP/KEEP) on log body, severity, attributes
- Support for resource attributes, scope attributes, and log attributes
- Async policy loading (non-blocking startup)
- Fail-open behavior (errors pass logs through unchanged)
- Lock-free policy updates via atomic snapshots
- Graceful shutdown with signal handling
- SIGSEGV handler for crash diagnostics
- Compatible with any OTLP-receiving backend (Datadog, Jaeger, etc.)
Build: zig build otlp Run: zig build run-otlp or
./zig-out/bin/edge-otlp [config-file]
Focused distribution for Prometheus metrics scraping with streaming filtering:
- Proxies
/metricsendpoint with policy-based metric filtering - Streaming response processing (bounded memory regardless of response size)
- Configurable per-scrape limits (
max_input_bytes_per_scrape,max_output_bytes_per_scrape) - Filters metrics by name, labels, type, and other fields
- Zero-copy forwarding for metrics that pass policy checks
- Fail-open behavior (errors pass metrics through unchanged)
- Designed for sidecar deployment next to your application
- Lock-free policy updates via atomic snapshots
- Graceful shutdown with signal handling
Build: zig build prometheus Run: zig build run-prometheus or
./zig-out/bin/edge-prometheus [config-file]
AWS Lambda extension distribution for Datadog telemetry processing.
Build: zig build lambda Run: Deployed as a Lambda layer
edge-tail is a file/stream tailer distribution focused on line-oriented log
copying with checkpointed resume semantics.
Build: zig build tail
Run: ./zig-out/bin/edge-tail [options] [PATH ...]
At startup, edge-tail resolves mode from inputs:
- No inputs, or a single
-: stdin mode (runStdinToOutput) - One or more file paths/globs: file mode (
runFilesToOutput)
Watcher backend selection in file mode:
--io-engine inotify-> inotify backend (Linux)--io-engine poll-> polling backend--io-engine auto-> inotify on Linux, otherwise poll
Reads bytes from stdin, frames by newline, writes to output (stdout or file).
No watcher/glob/rotation/checkpoint path is used in this mode.
flowchart LR
A[stdin Reader] --> B[LineFramer pump]
B --> C[Output Writer]
C --> D[flush]
File mode with polling backend and periodic glob refresh.
flowchart TD
A[Tick loop poll_ms] --> B[refreshPaths every glob_interval_ms]
B --> C[expand glob patterns]
C --> D[track new paths / expire removed]
D --> E[collectPollDirtyCandidates]
E --> F[processDirtyIndex per dirty file]
F --> G[LineFramer.readRange start_offset..end_offset]
G --> H[Output Writer buffer]
H --> I[flush by interval/threshold]
F --> J[checkpoint enqueue end_offset]
J --> K[checkpoint worker WAL + in-memory index]
Poll dirty candidate rules:
- unopened file path
- active fd stat failure
- active file size changed
- path inode changed vs active fd inode
- path size changed vs active fd size
- pending rotation file exists
File mode with Linux inotify event triggering. Dirty indices come from watch events, then the same per-file processing pipeline is used.
flowchart TD
A[inotify fd readable] --> B[pollInotify parse events]
B --> C[markDirty idx from wd map]
C --> D[processDirtyIndex]
D --> E[detectPathReplacement]
D --> F[readRange + line framing]
F --> G[Output Writer]
D --> H[checkpoint enqueue]
H --> I[WAL writer thread]
For each tracked path, watcher keeps active and optional pending file handles.
flowchart LR
A[active file] --> B{path inode changed?}
B -- no --> C[continue on active]
B -- yes --> D[open pending file at path]
D --> E[drain active until rotate_wait and no growth]
E --> F[switchToPending reset offset]
Copytruncate/rewrite behavior:
- If file shrinks below current offset: offset resets to
0 - If leading prefix hash changes unexpectedly: treat as rewrite, reset offset
Checkpoint lane runs in a background thread and persists updates to
checkpoint.wal in --state-dir.
flowchart LR
A[file event end_offset] --> B[enqueue Update]
B --> C[worker pop]
C --> D[append WAL record]
C --> E[update in-memory maps]
E --> F[getOffset on startup/collect]
Resume key behavior:
- Primary lookup:
(dev, inode, fingerprint)hash - Fallback lookup:
(dev, inode)hash - TTL enforced from
last_seen_ns(--checkpoint-ttl-ms)
-o -writes to stdout- otherwise opens file in append mode and writes line output
- flushes on
--flush-interval-msor--flush-lines
# Build all targets
zig build
# Run tests
zig build test
# Build specific distribution
zig build edge # Full distribution (Datadog + OTLP + Prometheus)
zig build datadog # Datadog-only distribution
zig build otlp # OTLP-only distribution
zig build prometheus # Prometheus-only distribution
zig build tail # Tail-only distribution
zig build lambda # Lambda extension distribution
# Run specific distribution
zig build run-edge
zig build run-datadog
zig build run-otlp
zig build run-prometheus
zig build run-tailDownload the latest release for your platform from the Releases page:
| Platform | Binary |
|---|---|
| Linux x86_64 | edge-linux-amd64 |
| Linux ARM64 | edge-linux-arm64 |
| macOS ARM64 (Apple Silicon) | edge-darwin-arm64 |
For focused distributions, use edge-datadog-*, edge-otlp-*,
edge-prometheus-*, or edge-tail-* binaries.
# Download and run (example for Linux x86_64)
curl -LO https://github.com/<org>/edge/releases/latest/download/edge-linux-amd64
chmod +x edge-linux-amd64
./edge-linux-amd64 config.jsonMulti-stage Dockerfile for building minimal container images.
# Build the full distribution
docker build --build-arg DISTRIBUTION=edge -t edge .
# Build Datadog-only distribution
docker build --build-arg DISTRIBUTION=datadog -t edge-datadog .
# Build OTLP-only distribution
docker build --build-arg DISTRIBUTION=otlp -t edge-otlp .
# Build Prometheus-only distribution
docker build --build-arg DISTRIBUTION=prometheus -t edge-prometheus .
# Build Tail-only distribution
docker build --build-arg DISTRIBUTION=tail -t edge-tail .
# Run with a config file
docker run -v $(pwd)/config.json:/app/config.json -p 8080:8080 edgePre-built images are available from GitHub Container Registry:
# Pull the full distribution
docker pull ghcr.io/<org>/edge:latest
# Pull Datadog-only distribution
docker pull ghcr.io/<org>/edge-datadog:latest
# Pull OTLP-only distribution
docker pull ghcr.io/<org>/edge-otlp:latest
# Pull Prometheus-only distribution
docker pull ghcr.io/<org>/edge-prometheus:latest
# Pull Tail-only distribution
docker pull ghcr.io/<org>/edge-tail:latestAvailable distributions: edge, datadog, otlp, prometheus, tail
See config.json for the Datadog distribution or config-otlp.json for the
OTLP distribution.
listen_address/listen_port- Server bind addressupstream_url- Default upstream destination (used when specific URLs not set)logs_url- (Optional) Upstream URL for log endpoints (falls back toupstream_url)metrics_url- (Optional) Upstream URL for metrics endpoints (falls back toupstream_url)workspace_id- Workspace identifier for policy synclog_level- Logging level (trace, debug, info, warn, err)policy_providers- List of policy sources (file/http)max_body_size- Request/response body limits
{
"listen_address": "127.0.0.1",
"listen_port": 8080,
"upstream_url": "https://otlp.us5.datadoghq.com",
"workspace_id": "your-workspace-id",
"log_level": "info",
"max_body_size": 1048576,
"policy_providers": [
{
"id": "file",
"type": "file",
"path": "policies.json"
},
{
"id": "http",
"type": "http",
"url": "http://localhost:9090/v1/policy/sync"
}
]
}TERO_LOG_LEVEL- Override log level (trace, debug, info, warn, err)
- Data-Oriented Design - Optimize for cache coherency and memory access patterns
- Lock-Free Reads - Policy evaluation uses atomic snapshot pointers for zero-contention reads
- Fail-Open - Errors in policy evaluation result in data passthrough, not drops
- Modular Composition - Packages can be used independently or composed together
- Explicit Dependencies - Each package declares its dependencies via imports