# Architecture Source: https://docs.usetero.com/edge/architecture How Edge is built and why it's fast Edge is a lightweight Zig proxy that applies policies to telemetry at high throughput and low latency. ## Component Overview ### Internal Architecture ```mermaid theme={null} graph TB subgraph Clients C[HTTP Clients] end subgraph Server[HTTP Server] TP[Thread Pool] SC[ServerContext] end subgraph Routing[Request Routing] R[Router] end subgraph Modules[Module Pipeline] direction LR H[HealthModule] DD[DatadogModule] OT[OtlpModule] PT[PassthroughModule] end subgraph Filtering[Policy Engine] REG[PolicyRegistry] PE[PolicyEngine] end subgraph Providers[Policy Providers] PL[PolicyLoader] FP[FileProvider] HP[HttpProvider] end subgraph Upstream UCM[UpstreamClientManager] TLS[TLS Client] end C -->|Request| TP TP --> SC SC --> R R --> H R --> DD R --> OT R --> PT DD --> PE OT --> PE PE -->|Filtered| UCM PT --> UCM UCM --> TLS PL -.->|async| FP PL -.->|async| HP FP -.->|update| REG HP -.->|update| REG REG -.->|snapshot| PE style C fill:#0e2b22,stroke:#0e2b22,color:#fafafa style TP fill:#0e2b22,stroke:#0e2b22,color:#fafafa style SC fill:#0e2b22,stroke:#0e2b22,color:#fafafa style R fill:#0e2b22,stroke:#0e2b22,color:#fafafa style H fill:#0e2b22,stroke:#0e2b22,color:#fafafa style DD fill:#0e2b22,stroke:#0e2b22,color:#fafafa style OT fill:#0e2b22,stroke:#0e2b22,color:#fafafa style PT fill:#0e2b22,stroke:#0e2b22,color:#fafafa style REG fill:#0e2b22,stroke:#0e2b22,color:#fafafa style PE fill:#0e2b22,stroke:#0e2b22,color:#fafafa style PL fill:#0e2b22,stroke:#0e2b22,color:#fafafa style FP fill:#0e2b22,stroke:#0e2b22,color:#fafafa style HP fill:#0e2b22,stroke:#0e2b22,color:#fafafa style UCM fill:#0e2b22,stroke:#0e2b22,color:#fafafa style TLS fill:#0e2b22,stroke:#0e2b22,color:#fafafa ``` ### Protocol Modules Each distribution includes modules for specific protocols: | Module | Endpoints | Description | | --------------- | ---------------- | ---------------------------- | | Datadog Logs | `/api/v2/logs` | Datadog log ingestion API | | Datadog Metrics | `/api/v1/series` | Datadog metrics API | | OTLP Logs | `/v1/logs` | OpenTelemetry log export | | OTLP Metrics | `/v1/metrics` | OpenTelemetry metrics export | Modules are stateless. They parse incoming requests, evaluate policies, and forward results. All state lives in the policy registry. ### Policy Registry The registry holds all loaded policies and provides lock-free read access during request processing. Key properties: * **Atomic snapshots**: Writers create new snapshots; readers use existing ones * **Lock-free reads**: No contention during policy evaluation * **Hot reload**: New policies take effect without restart Policy updates do not block request processing. ### Policy Engine The engine evaluates policies against telemetry using Vectorscan (a Hyperscan fork) for regex matching. Evaluation flow: 1. **Index lookup**: Find policies that might match based on field keys 2. **Regex scan**: Evaluate regex patterns against field values 3. **Action merge**: Combine keep/transform actions from matching policies 4. **Apply**: Execute the merged actions Vectorscan compiles regex patterns into finite automata, enabling simultaneous evaluation of thousands of patterns in a single pass. ### Policy Providers Providers load policies from external sources: | Provider | Source | Reload Mechanism | | -------- | ---------------- | ---------------------------------- | | File | Local filesystem | inotify/kqueue file watching | | HTTP | Remote endpoint | Polling with configurable interval | Multiple sources can be configured. Policies from all sources merge together. The policy ID acts as a unique key. If two providers emit a policy with the same ID, the one from the higher-priority source (HTTP > file) wins. Same-priority sources will have the later update win. This structure allows you to create a set of default policies that can be overridden remotely. ## Design Principles ### Data-Oriented Design Edge optimizes for memory access patterns and cache coherency. It lays out data structures for sequential access to minimize cache misses during high-throughput processing. ### Lock-Free Reads Policy evaluation reads policies on each request, while updates stay rare. Edge uses atomic pointers to policy snapshots, eliminating read-side synchronization. ```mermaid theme={null} sequenceDiagram participant R1 as Request Thread 1 participant R2 as Request Thread 2 participant Reg as Policy Registry participant U as Update Thread Note over Reg: Snapshot v1 active R1->>Reg: read snapshot Reg-->>R1: Snapshot v1 R2->>Reg: read snapshot Reg-->>R2: Snapshot v1 Note over U,Reg: Policy update arrives U->>Reg: create Snapshot v2 U->>Reg: atomic swap pointer Note over Reg: Snapshot v2 now active R1->>Reg: read snapshot Reg-->>R1: Snapshot v2 R2->>Reg: read snapshot Reg-->>R2: Snapshot v2 ``` ### Fail-Open Edge prioritizes availability. If policy evaluation fails, Edge forwards the telemetry unchanged. A filter may not apply, and no data is dropped. ### Stateless Modules Protocol modules are stateless. Each module: 1. Parses the request 2. Reads policies from the registry 3. Applies policies to the data 4. Forwards to upstream Engineers can inspect each module in isolation, and Edge can run modules in parallel. ## Performance Characteristics | Metric | Typical Value | | ------------------- | ----------------- | | Latency overhead | \< 5ms p99 | | Requests per second | 90k+ | | Policy evaluation | O(1) average case | | Memory per policy | \~1KB | | Max policies tested | 8,000+ | Performance depends on: * Number of regex patterns (more patterns = more evaluation time) * Request body size (larger bodies take longer to parse) ## Deployment Patterns ### Gateway Deploy Edge as a shared gateway for multiple services: ```mermaid theme={null} flowchart LR subgraph Applications App1[App 1] App2[App 2] App3[App 3] end subgraph Pipeline[Telemetry Pipeline] Collector[OTel Collector] end subgraph Gateway[Egress Gateway] Edge[Tero Edge] end subgraph Vendors[External Vendors] DD[Datadog] NR[New Relic] Grafana[Grafana Cloud] end App1 --> Collector App2 --> Collector App3 --> Collector Collector -->|All Data| Edge Edge -->|Filtered| DD Edge -->|Filtered| NR Edge -->|Filtered| Grafana style Edge fill:#10b981,stroke:#262626,color:#fff style Collector fill:#f59e0b,stroke:#262626,color:#000 style App1 fill:#262626,stroke:#262626,color:#fafafa style App2 fill:#262626,stroke:#262626,color:#fafafa style App3 fill:#262626,stroke:#262626,color:#fafafa style DD fill:#632ca6,stroke:#262626,color:#fff style NR fill:#0ea5e9,stroke:#262626,color:#fff style Grafana fill:#f97316,stroke:#262626,color:#fff ``` **Use Case**: Tero Edge sits at the egress point after your telemetry pipeline. It acts as a final gateway before data leaves your network and applies cost-focused policies that reduce egress to SaaS vendors. Drop redundant health checks and sample high-cardinality metrics before your provider bills for them. Best for: * Centralized policy management * Environments with many services * When you want a single point of control ### Sidecar Deploy Edge alongside each service: ```mermaid theme={null} flowchart LR subgraph Host[Pod or Host] App[Application] Edge[Tero Edge] end subgraph Pipeline[Telemetry Pipeline] Collector[OTel Collector] end subgraph Backend DD[Datadog] Splunk[Splunk] S3[S3] end App -->|Logs/Metrics| Edge Edge -->|Filtered| Collector Collector --> DD Collector --> Splunk Collector --> S3 style Edge fill:#10b981,stroke:#262626,color:#fff style App fill:#262626,stroke:#262626,color:#fafafa style Collector fill:#f59e0b,stroke:#262626,color:#000 style DD fill:#632ca6,stroke:#262626,color:#fff style Splunk fill:#059669,stroke:#262626,color:#fff style S3 fill:#0ea5e9,stroke:#262626,color:#fff ``` **Use Case**: Tero Edge runs as a lightweight sidecar next to each application. It applies policies at the source by dropping noisy debug logs, redacting PII, or sampling high-volume metrics before data reaches the telemetry pipeline. This reduces load on collectors and network bandwidth within your infrastructure. Best for: * Service-specific policies * Isolation between services * Kubernetes environments with sidecar injection ## Next Steps Get Edge running in 5 minutes Full configuration reference # How Edge works Source: https://docs.usetero.com/edge/concepts The Edge runtime model Edge receives telemetry, evaluates policies, applies the resulting action, and forwards the remaining telemetry to the configured upstream. Each policy evaluates against the original telemetry, not the output of earlier policies. Matching policies contribute actions, and Edge resolves the final keep and transform result. ```mermaid theme={null} flowchart LR Telemetry[Telemetry] --> Match[Match policies] Match --> Keep[Keep decision] Keep --> Transform[Transforms] Transform --> Upstream[Upstream] Match -. uses .-> Matchers[exact, regex, exists, negated matches] Keep -. resolves .-> KeepActions[keep, drop, sample, rate-limit] Transform -. applies .-> TransformActions[remove, redact, rename, add] style Telemetry fill:#262626,stroke:#262626,color:#fafafa style Match fill:#0e2b22,stroke:#0e2b22,color:#fafafa style Keep fill:#00855c,stroke:#006b49,color:#fafafa style Transform fill:#0e2b22,stroke:#0e2b22,color:#fafafa style Upstream fill:#262626,stroke:#262626,color:#fafafa style Matchers fill:#d1fae5,stroke:#10b981,color:#065f46 style KeepActions fill:#d1fae5,stroke:#10b981,color:#065f46 style TransformActions fill:#d1fae5,stroke:#10b981,color:#065f46 ``` ## Policies A policy is an atomic rule: it matches telemetry and declares what should happen when the match succeeds. ```yaml theme={null} id: drop-debug-logs name: Drop debug logs log: match: - log_field: severity_text regex: "^(DEBUG|TRACE)$" keep: none ``` Atomic policies make runtime behavior easier to reason about. A policy should express one intent, such as dropping successful health checks or redacting a payment field. Adding one policy should not require understanding a hidden chain of earlier processors. ## Matching Matchers select telemetry. A policy can match log fields, log attributes, resource attributes, metric fields, datapoint attributes, and other supported telemetry fields depending on the policy type. Policies can use exact matches, regular expressions, field existence checks, and negation. For exact syntax, use the policy reference: * [Log filter](/edge/policy-reference/log-filter) * [Log transform](/edge/policy-reference/log-transform) * [Metric filter](/edge/policy-reference/metric-filter) ## Keep and transform When a policy matches, it can affect two stages. The **keep** stage decides whether matching telemetry continues through Edge. A policy can keep telemetry, drop it, sample it, or rate-limit it. The **transform** stage changes telemetry that survives the keep stage. Supported log transforms include removing fields, redacting values, renaming fields, and adding fields. When multiple policies match the same telemetry, Edge resolves the most restrictive keep action and applies matching transforms in a stable order. ## Policy sources Edge loads policies from configured policy providers. Use a file provider for development and static deployments. Use a remote provider when Tero or another control plane manages policy state. When multiple providers emit policies, policy IDs identify the policy. Provider priority controls which source wins when two sources emit the same ID. ## Failure model Edge fails open. If it cannot evaluate a policy, it forwards the telemetry instead of blocking it. Fail-open behavior protects observability availability. It also means policy errors need monitoring. Use [Operations](/edge/edge-reference/operations) for runtime logging, health checks, and operational guidance. ## Where to go next Use [Quickstart](/edge/quickstart) to run Edge locally. Use [Architecture](/edge/architecture) for the implementation model. Use [Config](/edge/edge-reference/config) for configuration fields. # Edge Full Source: https://docs.usetero.com/edge/distributions/all Full Edge distribution supporting all protocols The Edge distribution includes support for all protocols: Datadog APIs and OTLP. Use this when your environment sends telemetry in multiple formats. ## Supported Endpoints | Endpoint | Method | Protocol | Description | | ---------------- | ------ | -------- | ----------------------------- | | `/api/v2/logs` | POST | Datadog | Log ingestion | | `/api/v1/series` | POST | Datadog | Metrics ingestion | | `/v1/logs` | POST | OTLP | Log export | | `/v1/metrics` | POST | OTLP | Metrics export | | `/_health` | GET | - | Health check | | `/_edge/metrics` | GET | - | Edge's own Prometheus metrics | ## Configuration ```json config.json theme={null} { "listen_address": "0.0.0.0", "listen_port": 8080, "upstream_url": "https://agent-http-intake.logs.datadoghq.com", "logs_url": "https://agent-http-intake.logs.datadoghq.com", "metrics_url": "https://api.datadoghq.com", "log_level": "info", "service": { "name": "edge", "namespace": "production", "resource_attributes": [ { "key": "deployment.environment", "value": "production" } ], "labels": [{ "key": "team", "value": "platform" }] }, "policy_providers": [ { "id": "local", "type": "file", "path": "policies.json" } ] } ``` You can configure separate upstream URLs for logs (`logs_url`) and metrics (`metrics_url`). If not specified, they fall back to `upstream_url`. ## Running ```bash Docker theme={null} docker run -d \ --name edge \ -p 8080:8080 \ -v $(pwd)/config.json:/etc/edge/config.json \ -v $(pwd)/policies.json:/etc/edge/policies.json \ ghcr.io/usetero/edge:latest \ /etc/edge/config.json ``` ```bash Binary theme={null} ./edge config.json ``` ```bash Source theme={null} zig build run -- config.json ``` ## When to Use This Distribution Use the Edge distribution when: * **Mixed telemetry sources**: Some applications use Datadog agents, others use OpenTelemetry * **Migration**: Transitioning from one protocol to another * **Multi-vendor**: Sending data to multiple backends that prefer different protocols * **Flexibility**: Want a single deployment that handles both protocols For single-protocol environments, prefer the focused distributions: * [Edge Datadog](/edge/distributions/datadog) for Datadog-only * [Edge OTLP](/edge/distributions/otlp) for OpenTelemetry-only Focused distributions have a smaller binary size and attack surface. ## Features * Handles Datadog `/api/v2/logs` and `/api/v1/series` endpoints * Handles OTLP `/v1/logs` and `/v1/metrics` endpoints * Policy-based filtering (DROP/KEEP) for logs and metrics * Separate upstream URLs for logs and metrics * Async policy loading (server starts before policy loading completes) * Fail-open behavior (errors pass data through unchanged) * Lock-free policy updates via atomic snapshots * Graceful shutdown with signal handling ## Unified Policies Policies work the same regardless of the incoming protocol. A log filter policy applies to both Datadog logs and OTLP logs. ```json theme={null} { "id": "drop-debug", "name": "Drop debug logs from all sources", "log": { "match": [{ "log_field": "severity_text", "regex": "^(debug|DEBUG)$" }], "keep": "none" } } ``` This policy drops debug logs whether they arrive via `/api/v2/logs` (Datadog) or `/v1/logs` (OTLP). ### Protocol-Specific Filtering To apply policies only to specific protocols, match on protocol-specific attributes: ```json theme={null} { "id": "sample-datadog-agent-logs", "name": "Sample logs from Datadog agents", "log": { "match": [{ "log_attribute": "ddsource", "exists": true }], "keep": "10%" } } ``` The `ddsource` attribute is specific to Datadog, so this policy only affects Datadog-format logs. ## Resource Considerations The Edge distribution: * Has a larger binary size than focused distributions * Loads all protocol modules at startup * Uses more memory For most deployments, this overhead is negligible. Consider focused distributions only if you're running Edge in constrained environments (embedded systems, very small containers). ## Next Steps Datadog-specific configuration OTLP-specific configuration # Edge Datadog Source: https://docs.usetero.com/edge/distributions/datadog Edge distribution for Datadog log and metric ingestion Edge Datadog targets environments that send telemetry to Datadog. It supports the Datadog Logs API and Metrics API. ## Supported Endpoints | Endpoint | Method | Description | | ---------------- | ------ | ----------------------------- | | `/api/v2/logs` | POST | Datadog log ingestion | | `/api/v1/series` | POST | Datadog metrics ingestion | | `/_health` | GET | Health check | | `/_edge/metrics` | GET | Edge's own Prometheus metrics | ## Configuration ```json config.json theme={null} { "listen_address": "0.0.0.0", "listen_port": 8080, "upstream_url": "https://agent-http-intake.logs.datadoghq.com", "metrics_url": "https://api.datadoghq.com", "log_level": "info", "service": { "name": "edge", "namespace": "production", "resource_attributes": [ { "key": "deployment.environment", "value": "production" } ], "labels": [{ "key": "team", "value": "platform" }] }, "policy_providers": [ { "id": "local", "type": "file", "path": "policies.json" } ] } ``` ### Regional Endpoints Set `upstream_url` and `metrics_url` based on your Datadog region: | Region | Logs URL | Metrics URL | | ------ | -------------------------------------------------- | ------------------------------- | | US1 | `https://agent-http-intake.logs.datadoghq.com` | `https://api.datadoghq.com` | | US3 | `https://agent-http-intake.logs.us3.datadoghq.com` | `https://api.us3.datadoghq.com` | | US5 | `https://agent-http-intake.logs.us5.datadoghq.com` | `https://api.us5.datadoghq.com` | | EU1 | `https://agent-http-intake.logs.datadoghq.eu` | `https://api.datadoghq.eu` | | AP1 | `https://agent-http-intake.logs.ap1.datadoghq.com` | `https://api.ap1.datadoghq.com` | ## Running ```bash Docker theme={null} docker run -d \ --name edge-datadog \ -p 8080:8080 \ -v $(pwd)/config.json:/etc/edge/config.json \ -v $(pwd)/policies.json:/etc/edge/policies.json \ ghcr.io/usetero/edge-datadog:latest \ /etc/edge/config.json ``` ```bash Binary theme={null} ./edge-datadog config.json ``` ```bash Source theme={null} zig build run-datadog -- config.json ``` ## Datadog Agent Configuration Point your Datadog Agent at Edge instead of Datadog. ### Logs In `datadog.yaml`: ```yaml theme={null} logs_config: logs_dd_url: "edge-host:8080" use_http: true use_compression: true ``` Or via environment variables: ```bash theme={null} DD_LOGS_CONFIG_LOGS_DD_URL=edge-host:8080 DD_LOGS_CONFIG_USE_HTTP=true ``` ### Metrics In `datadog.yaml`: ```yaml theme={null} dd_url: "http://edge-host:8080" ``` Or via environment variable: ```bash theme={null} DD_DD_URL=http://edge-host:8080 ``` ## Log Format Edge expects Datadog's log format: ```json theme={null} [ { "message": "Log message content", "status": "info", "hostname": "host-1", "service": "my-service", "ddsource": "python", "ddtags": "env:production,version:1.2.3" } ] ``` ### Field Mapping Datadog fields map to policy matchers: | Datadog Field | Policy Matcher | | ------------- | ---------------------------------------------- | | `message` | `log_field: body` | | `status` | `log_field: severity_text` | | `hostname` | `resource_attribute: host.name` | | `service` | `resource_attribute: service.name` | | `ddsource` | `log_attribute: ddsource` | | `ddtags` | Parsed into individual `log_attribute` entries | ## Example Policies ### Drop Debug Logs ```json theme={null} { "id": "drop-debug", "name": "Drop debug logs", "log": { "match": [{ "log_field": "severity_text", "regex": "^(debug|DEBUG)$" }], "keep": "none" } } ``` ### Filter by Service ```json theme={null} { "id": "sample-checkout", "name": "Sample checkout service logs", "log": { "match": [{ "resource_attribute": "service.name", "exact": "checkout" }], "keep": "10%" } } ``` ### Drop Health Checks ```json theme={null} { "id": "drop-health-checks", "name": "Drop health check logs", "log": { "match": [{ "log_field": "body", "regex": "GET /health" }], "keep": "none" } } ``` ### Drop Noisy Metrics ```json theme={null} { "id": "drop-system-load", "name": "Drop system load metrics", "metric": { "match": [{ "metric_field": "name", "regex": "^system\\.load" }], "keep": false } } ``` ## Compression Edge supports gzip and zstd compression for both incoming requests and outgoing requests to Datadog. The Datadog Agent sends compressed payloads by default. Edge accepts those compressed requests and forwards them to Datadog. ## Next Steps All log filtering options Redact and transform logs # Edge OTLP Source: https://docs.usetero.com/edge/distributions/otlp Edge distribution for OpenTelemetry Protocol Edge OTLP targets OpenTelemetry environments. It supports the standard OTLP HTTP endpoints for logs and metrics. ## Supported Endpoints | Endpoint | Method | Description | | ---------------- | ------ | ----------------------------- | | `/v1/logs` | POST | OTLP log export | | `/v1/metrics` | POST | OTLP metrics export | | `/_health` | GET | Health check | | `/_edge/metrics` | GET | Edge's own Prometheus metrics | ## Configuration ```json config.json theme={null} { "listen_address": "0.0.0.0", "listen_port": 8080, "upstream_url": "https://your-otlp-endpoint.com", "log_level": "info", "service": { "name": "edge", "namespace": "production", "resource_attributes": [ { "key": "deployment.environment", "value": "production" } ], "labels": [{ "key": "team", "value": "platform" }] }, "policy_providers": [ { "id": "local", "type": "file", "path": "policies.json" } ] } ``` ### Vendor Endpoints Configure `upstream_url` for your observability vendor: | Vendor | Endpoint | | ------------- | --------------------------------------------------------- | | Datadog | `https://otlp.datadoghq.com` (or regional variant) | | Honeycomb | `https://api.honeycomb.io` | | Grafana Cloud | `https://otlp-gateway-prod-us-central-0.grafana.net/otlp` | | New Relic | `https://otlp.nr-data.net` | | Lightstep | `https://ingest.lightstep.com` | ## Running ```bash Docker theme={null} docker run -d \ --name edge-otlp \ -p 8080:8080 \ -v $(pwd)/config.json:/etc/edge/config.json \ -v $(pwd)/policies.json:/etc/edge/policies.json \ ghcr.io/usetero/edge-otlp:latest \ /etc/edge/config.json ``` ```bash Binary theme={null} ./edge-otlp config.json ``` ```bash Source theme={null} zig build run-otlp -- config.json ``` ## OpenTelemetry Collector Configuration Configure the OpenTelemetry Collector to export through Edge. ### As an Exporter ```yaml otel-collector-config.yaml theme={null} exporters: otlphttp: endpoint: "http://edge-host:8080" compression: gzip service: pipelines: logs: receivers: [otlp] processors: [batch] exporters: [otlphttp] metrics: receivers: [otlp] processors: [batch] exporters: [otlphttp] ``` ### SDK Direct Export For applications using the OpenTelemetry SDK directly: ```bash theme={null} export OTEL_EXPORTER_OTLP_ENDPOINT="http://edge-host:8080" export OTEL_EXPORTER_OTLP_PROTOCOL="http/json" ``` ## OTLP Data Model Edge works with the standard OTLP data model. OTLP fields map to policy matchers as follows. ### Log Records | OTLP Field | Policy Matcher | | --------------------- | ---------------------------- | | `body` | `log_field: body` | | `severityText` | `log_field: severity_text` | | `severityNumber` | `log_field: severity_number` | | `attributes` | `log_attribute: ` | | `resource.attributes` | `resource_attribute: ` | | `scope.name` | `scope_name` | | `scope.version` | `scope_version` | | `scope.attributes` | `scope_attribute: ` | ### Metrics | OTLP Field | Policy Matcher | | ------------------------- | ---------------------------- | | `name` | `metric_field: name` | | `description` | `metric_field: description` | | `unit` | `metric_field: unit` | | `dataPoints[].attributes` | `datapoint_attribute: ` | | `resource.attributes` | `resource_attribute: ` | ## Example Policies ### Filter by Severity ```json theme={null} { "id": "drop-debug-trace", "name": "Drop DEBUG and TRACE logs", "log": { "match": [{ "log_field": "severity_text", "regex": "^(DEBUG|TRACE)$" }], "keep": "none" } } ``` ### Filter by Resource Attribute ```json theme={null} { "id": "sample-api-gateway", "name": "Sample API Gateway logs", "log": { "match": [{ "resource_attribute": "service.name", "exact": "api-gateway" }], "keep": "25%" } } ``` ### Filter by Log Attribute ```json theme={null} { "id": "drop-healthcheck", "name": "Drop health check spans", "log": { "match": [{ "log_attribute": "http.route", "exact": "/health" }], "keep": "none" } } ``` ### Filter by Scope ```json theme={null} { "id": "drop-library-logs", "name": "Drop logs from a noisy instrumentation scope", "log": { "match": [ { "scope_attribute": "library.name", "exact": "noisy-http-client" } ], "keep": "none" } } ``` ### Redact Sensitive Attributes ```json theme={null} { "id": "redact-pii", "name": "Redact PII from logs", "log": { "match": [{ "log_attribute": "user.email", "exists": true }], "transform": { "redact": [{ "log_attribute": "user.email" }] } } } ``` ## Request Format Edge expects OTLP JSON format (`application/json`). Example log export request: ```json theme={null} { "resourceLogs": [ { "resource": { "attributes": [ { "key": "service.name", "value": { "stringValue": "my-service" } } ] }, "scopeLogs": [ { "scope": { "name": "my-library", "version": "1.0.0" }, "logRecords": [ { "timeUnixNano": "1234567890000000000", "severityText": "INFO", "body": { "stringValue": "Hello, world!" }, "attributes": [ { "key": "user.id", "value": { "stringValue": "12345" } } ] } ] } ] } ] } ``` ## Compression Edge supports gzip compression for both incoming requests and outgoing requests. Set the `Content-Encoding: gzip` header for compressed requests. ## Next Steps All log filtering options Filter metrics before export # Config Source: https://docs.usetero.com/edge/edge-reference/config Complete configuration reference for Edge Config lists every Edge configuration option. ## Configuration File Edge uses a JSON configuration file. Pass the path as the first argument: ```bash theme={null} ./edge config.json ``` ### Full Example ```json config.json theme={null} { "listen_address": "0.0.0.0", "listen_port": 8080, "upstream_url": "https://agent-http-intake.logs.datadoghq.com", "logs_url": "https://agent-http-intake.logs.datadoghq.com", "metrics_url": "https://api.datadoghq.com", "log_level": "info", "max_body_size": 1048576, "service": { "name": "edge", "namespace": "production", "resource_attributes": [ { "key": "deployment.environment", "value": "production" } ], "labels": [{ "key": "team", "value": "platform" }] }, "policy_providers": [ { "id": "local", "type": "file", "path": "/etc/edge/policies.json" }, { "id": "remote", "type": "http", "url": "${TERO_CONTROL_PLANE_URL}/v1/policy/sync", "poll_interval": 30, "headers": [ { "name": "Authorization", "value": "Bearer ${TERO_API_TOKEN}" } ] } ] } ``` Any string value can reference an environment variable with `${VAR}` (for example `${TERO_API_TOKEN}`). See [Environment Variables](#environment-variables). ## Configuration Reference Edge supports up to 8,000 policies. Open an [issue on GitHub](https://github.com/usetero/edge/issues/new) if you need more. ### Server Settings | Field | Type | Default | Description | | ---------------- | ------ | ------------- | ------------------------------------------------ | | `listen_address` | string | `"127.0.0.1"` | IP address to bind to | | `listen_port` | number | `8080` | Port to listen on | | `max_body_size` | number | `1048576` | Maximum request body size in bytes (1MB default) | | `log_level` | string | `"info"` | Logging level: `debug`, `info`, `warn`, `err` | ### Upstream Settings | Field | Type | Required | Description | | -------------- | ------ | -------- | ------------------------------------------------------------------------- | | `upstream_url` | string | Yes | Default upstream destination (fallback when specific URLs not set) | | `logs_url` | string | No | Upstream destination for log endpoints (falls back to `upstream_url`) | | `metrics_url` | string | No | Upstream destination for metrics endpoints (falls back to `upstream_url`) | ### Service Settings The `service` object identifies this Edge instance to the control plane and attaches metadata to policy sync requests. Always set `name`, `namespace`, and `version` — the control plane uses them to scope and match policies to this service. `resource_attributes` and `labels` are optional but recommended. ```json theme={null} { "service": { "name": "edge", "namespace": "production", "resource_attributes": [ { "key": "deployment.environment", "value": "production" } ], "labels": [{ "key": "team", "value": "platform" }] } } ``` | Field | Type | Required | Description | | --------------------- | ------ | ----------- | ------------------------------------------------------------- | | `name` | string | Recommended | Service name (default `"tero-edge"`) | | `namespace` | string | Recommended | Service namespace (default `"tero"`) | | `version` | string | Recommended | Service version (default `"latest"`) | | `resource_attributes` | array | No | OTel resource attributes (`{key, value}`) sent on policy sync | | `labels` | array | No | Free-form labels (`{key, value}`) sent on policy sync | `instance_id` is generated at startup and is not configurable. ### Policy Providers The `policy_providers` array configures where Edge loads policies from. #### File Provider Loads policies from a local file and watches for changes. ```json theme={null} { "id": "local", "type": "file", "path": "/etc/edge/policies.json" } ``` | Field | Type | Required | Description | | ------ | ------ | -------- | ----------------------------------- | | `id` | string | Yes | Unique identifier for this provider | | `type` | string | Yes | Must be `"file"` | | `path` | string | Yes | Path to the policy file | Edge watches the file with inotify (Linux) or kqueue (macOS) and applies changes on save. #### HTTP Provider Loads policies from an HTTP endpoint with periodic polling. ```json theme={null} { "id": "remote", "type": "http", "url": "https://api.example.com/policies", "poll_interval": 30, "headers": [ { "name": "Authorization", "value": "Bearer token" } ] } ``` | Field | Type | Required | Description | | --------------- | ------ | -------- | ----------------------------------- | | `id` | string | Yes | Unique identifier for this provider | | `type` | string | Yes | Must be `"http"` | | `url` | string | Yes | URL to fetch policies from | | `poll_interval` | number | No | Seconds between policy fetches | | `headers` | array | No | HTTP headers to include in requests | ### Prometheus Settings The optional `prometheus` object bounds memory use when filtering Prometheus scrapes (relevant to distributions that handle metrics). ```json theme={null} { "prometheus": { "max_input_bytes_per_scrape": 10485760, "max_output_bytes_per_scrape": 10485760 } } ``` | Field | Type | Default | Description | | ----------------------------- | ------ | ---------- | --------------------------------------------------- | | `max_input_bytes_per_scrape` | number | `10485760` | Max bytes read from upstream per scrape (10MB) | | `max_output_bytes_per_scrape` | number | `10485760` | Max bytes forwarded to the client per scrape (10MB) | ## Policy File Format Define policies in a JSON file: ```json policies.json theme={null} { "policies": [ { "id": "policy-1", "name": "Human-readable name", "description": "What this policy does", "enabled": true, "log": { "match": [...], "keep": "...", "transform": {...} } }, { "id": "policy-2", "name": "Another policy", "metric": { "match": [...], "keep": true } } ] } ``` See the [Policies](/edge/policy-reference/log-filter) section for detailed policy configuration. ## Environment Variables Edge reads environment variables two ways. ### Value Substitution Any string value in the config file can reference an environment variable with `${VAR}`. The variable is resolved when the config loads: ```json theme={null} { "upstream_url": "https://agent-http-intake.logs.${TERO_DD_REGION}.datadoghq.com", "policy_providers": [ { "id": "remote", "type": "http", "url": "${TERO_CONTROL_PLANE_URL}/v1/policy/sync", "headers": [ { "name": "Authorization", "value": "Bearer ${TERO_API_TOKEN}" } ] } ] } ``` * Unset variables resolve to an empty string. * Use `$${VAR}` to emit a literal `${VAR}` without substitution. ### Field Overrides A `TERO_`-prefixed environment variable overrides the matching config field. The name is the field path in `SCREAMING_SNAKE_CASE`, with nested fields joined by `_`, so `service.namespace` becomes `TERO_SERVICE_NAMESPACE`. Overrides are applied after the file is parsed, so they always win over it. ```bash theme={null} TERO_LOG_LEVEL=debug TERO_LISTEN_PORT=9090 ./edge config.json ``` Every scalar field is overridable. The full set: | Variable | Overrides | Type | Default | | --------------------------------------------- | ---------------------------------------- | --------------------------- | --------------------- | | `TERO_LISTEN_ADDRESS` | `listen_address` | IPv4 address | `127.0.0.1` | | `TERO_LISTEN_PORT` | `listen_port` | port | `8080` | | `TERO_UPSTREAM_URL` | `upstream_url` | string | `http://127.0.0.1:80` | | `TERO_LOGS_URL` | `logs_url` | string, optional | unset | | `TERO_METRICS_URL` | `metrics_url` | string, optional | unset | | `TERO_SERVICE_NAME` | `service.name` | string | `tero-edge` | | `TERO_SERVICE_NAMESPACE` | `service.namespace` | string | `tero` | | `TERO_SERVICE_VERSION` | `service.version` | string | `latest` | | `TERO_LOG_LEVEL` | `log_level` | `debug`/`info`/`warn`/`err` | `info` | | `TERO_MAX_BODY_SIZE` | `max_body_size` | bytes | `1048576` | | `TERO_MAX_DECODED_BYTES` | `max_decoded_bytes` | bytes, optional | unset | | `TERO_MAX_CONNECTIONS` | `max_connections` | count | `256` | | `TERO_WORKER_COUNT` | `worker_count` | count, optional | unset | | `TERO_THREAD_POOL_COUNT` | `thread_pool_count` | count, optional | unset | | `TERO_TAP_ENABLED` | `tap_enabled` | `true`/`false`/`1`/`0` | `false` | | `TERO_PROMETHEUS_MAX_INPUT_BYTES_PER_SCRAPE` | `prometheus.max_input_bytes_per_scrape` | bytes | `10485760` | | `TERO_PROMETHEUS_MAX_OUTPUT_BYTES_PER_SCRAPE` | `prometheus.max_output_bytes_per_scrape` | bytes | `10485760` | Defaults above are the built-in ones. Each distribution image bakes a `config.json` that already changes some of them — `edge-datadog`, for example, ships `listen_address: 0.0.0.0`, `service.namespace: production`, and a Datadog US1 `upstream_url`. Env vars override whichever value the file set. Rules worth knowing: * **Optional fields accept an empty string to mean "unset".** `TERO_METRICS_URL=` sets `metrics_url` back to null rather than to an empty URL. * **An unparseable value fails startup.** `TERO_LOG_LEVEL=bogus` or a non-numeric `TERO_LISTEN_PORT` exits with `config.load.error err="InvalidValue"` instead of silently falling back to the default. * **Lists are not overridable.** `policy_providers`, `service.resource_attributes`, and `service.labels` are arrays, so they have no env var — supply a config file, or use [value substitution](#value-substitution) for the strings inside it. Setting a `TERO_` variable that matches no field is silently ignored, so a typo fails quietly. * **`service.instance_id` and `service.supported_stages` are ignored.** Both are set by the runtime at startup — the instance ID is generated per process, and the supported stages come from the distribution. ### Other Environment Variables These are read directly rather than as config-field overrides: | Variable | Purpose | | ----------------- | ---------------------------------------------------------------------------------------------------------- | | `TERO_IO_BACKEND` | I/O backend: `inherited` (default) or `single_threaded`. Unknown values warn and fall back to `inherited`. | | `TERO_API_KEY` | Referenced as `${TERO_API_KEY}` by the bundled configs for policy sync. | ## Next Steps Logging, health checks, and resource requirements Configure log filtering policies # Operations Source: https://docs.usetero.com/edge/edge-reference/operations Running Edge in production: logging, health checks, resource requirements Operations covers the production behaviors you need to run Edge: logs, health checks, graceful shutdown, and resource sizing. ## Logging Edge outputs structured logs to stdout: ``` 2026-01-06T17:29:36.322Z [INFO] server.starting 2026-01-06T17:29:36.322Z [INFO] configuration.loaded path="config.json" 2026-01-06T17:29:36.323Z [INFO] listen.address.configured address="127.0.0.1" port=8080 2026-01-06T17:29:36.323Z [INFO] upstream.configured url="https://agent-http-intake.logs.datadoghq.com" 2026-01-06T17:29:36.323Z [INFO] policy.loader.starting provider_count=1 2026-01-06T17:29:36.324Z [INFO] policies.loading path="/etc/edge/policies.json" 2026-01-06T17:29:36.324Z [INFO] server.ready 2026-01-06T17:29:36.324Z [INFO] server.listening address="127.0.0.1" port=8080 ``` ### Log Levels Configure the log level in your config file or via environment variable: ```json theme={null} { "log_level": "info" } ``` Or override with `TERO_LOG_LEVEL`: ```bash theme={null} TERO_LOG_LEVEL=debug ./edge config.json ``` | Level | Description | | ------- | ----------------------------------- | | `debug` | Most verbose, debugging information | | `info` | Normal operation messages | | `warn` | Warning conditions | | `err` | Error conditions only | ## Health Checks Edge exposes a health endpoint for load balancer and orchestrator integration: ```bash theme={null} curl http://localhost:8080/_health ``` Returns `200 OK` when Edge is healthy and ready to process requests. ### Kubernetes Probes Probes can begin as soon as the process starts: ```yaml theme={null} livenessProbe: httpGet: path: /_health port: 8080 periodSeconds: 10 readinessProbe: httpGet: path: /_health port: 8080 periodSeconds: 5 ``` ## Metrics Edge serves its own operational metrics in Prometheus format: ```bash theme={null} curl http://localhost:8080/_edge/metrics ``` Point a Prometheus scrape at this endpoint to monitor Edge itself (request counts, request durations, policy batch stats, build info). This is separate from any `/metrics` traffic Edge filters and forwards to your upstream. ## Graceful Shutdown Edge handles SIGINT and SIGTERM for graceful shutdown: 1. Stops accepting new connections 2. Waits for in-flight requests to complete 3. Exits cleanly This shutdown sequence lets Edge finish accepted requests before the process exits during deployments and scaling events. ### Kubernetes Termination Edge exits as soon as in-flight requests drain. A short grace period is sufficient: ```yaml theme={null} terminationGracePeriodSeconds: 10 ``` ## Resource Requirements Recommended minimums: | Resource | Minimum | Recommended | | -------- | -------- | ---------------- | | CPU | 0.5 core | 1+ cores | | Memory | 10MB | 100MB | | Disk | 10MB | 100MB (for logs) | ### Memory Scaling Memory usage scales with: * **Number of policies**: Each policy consumes memory for its compiled matchers * **Regex complexity**: Hyperscan databases for complex patterns * **Request body sizes**: Buffered during processing ### Kubernetes Resources ```yaml theme={null} resources: requests: cpu: 100m memory: 64Mi limits: cpu: 1000m memory: 256Mi ``` ## Next Steps Full configuration reference Understand Edge internals # Edge Source Source: https://docs.usetero.com/edge/github-edge # Policy Spec Source: https://docs.usetero.com/edge/github-policy # Deploy with Helm Source: https://docs.usetero.com/edge/how-to/helm Install Tero Edge on Kubernetes with the official Helm chart The `tero-edge` Helm chart deploys Edge as a `DaemonSet`, renders `config.json` and `policies.json` into a ConfigMap, and (optionally) wires up HTTP policy sync with API-key auth. The chart is published two ways — an **OCI registry** and a classic **HTTP Helm repository** — pick whichever your tooling prefers. ## Install No `helm repo add` needed — reference the chart by its OCI URL: ```bash theme={null} helm upgrade --install tero-edge oci://ghcr.io/usetero/charts/tero-edge \ --version \ -n tero-system --create-namespace \ -f values.yaml ``` List available versions: ```bash theme={null} helm show chart oci://ghcr.io/usetero/charts/tero-edge --version ``` OCI support is built into Helm 3.8+. Older clients need `export HELM_EXPERIMENTAL_OCI=1`. For HTTP Helm support, please contact [support@usetero.com](mailto:support@usetero.com). Both sources publish identical charts from the same release, so `values.yaml` and every flag below behave the same regardless of which you choose. ## Configure Create a `values.yaml` with the policy-sync connection and the service identity the control plane uses to scope policies: Pick the tab for your Datadog region — the `upstreamUrl` and `metricsUrl` change per region; everything else is identical. ```yaml values.yaml theme={null} tero: url: https://sync.usetero.com apiKey: "" # it is recommended to use an existing secret instead existingSecret: name: "" key: "" config: upstreamUrl: https://agent-http-intake.logs.datadoghq.com metricsUrl: https://api.datadoghq.com # Service identity sent on every policy sync. The control plane scopes and # matches policies to this service, so set name/namespace/version. service: name: edge namespace: production version: 1.0.0 resourceAttributes: - key: deployment.environment value: production labels: - key: team value: platform ``` ```yaml values.yaml theme={null} tero: url: https://sync.usetero.com apiKey: "" # it is recommended to use an existing secret instead existingSecret: name: "" key: "" config: upstreamUrl: https://agent-http-intake.logs.us3.datadoghq.com metricsUrl: https://api.us3.datadoghq.com service: name: edge namespace: production version: 1.0.0 resourceAttributes: - key: deployment.environment value: production labels: - key: team value: platform ``` ```yaml values.yaml theme={null} tero: url: https://sync.usetero.com apiKey: "" # it is recommended to use an existing secret instead existingSecret: name: "" key: "" config: upstreamUrl: https://agent-http-intake.logs.us5.datadoghq.com metricsUrl: https://api.us5.datadoghq.com service: name: edge namespace: production version: 1.0.0 resourceAttributes: - key: deployment.environment value: production labels: - key: team value: platform ``` ```yaml values.yaml theme={null} tero: url: https://sync.usetero.com apiKey: "" # it is recommended to use an existing secret instead existingSecret: name: "" key: "" config: upstreamUrl: https://agent-http-intake.logs.datadoghq.eu metricsUrl: https://api.datadoghq.eu service: name: edge namespace: production version: 1.0.0 resourceAttributes: - key: deployment.environment value: production labels: - key: team value: platform ``` ```yaml values.yaml theme={null} tero: url: https://sync.usetero.com apiKey: "" # it is recommended to use an existing secret instead existingSecret: name: "" key: "" config: upstreamUrl: https://agent-http-intake.logs.ap1.datadoghq.com metricsUrl: https://api.ap1.datadoghq.com service: name: edge namespace: production version: 1.0.0 resourceAttributes: - key: deployment.environment value: production labels: - key: team value: platform ``` ### Authentication Setting `tero.url` automatically configures the HTTP policy provider. Provide the API key one of two ways — never both: | Method | Values | | ----------------------------- | ------------------------------------------------------ | | Inline (chart-managed Secret) | `tero.apiKey: ` | | Existing Secret | `tero.existingSecret.name` + `tero.existingSecret.key` | ```yaml theme={null} # Reference a Secret you manage instead of an inline key: tero: url: https://sync.usetero.com existingSecret: name: tero-edge-api key: api-key ``` Without `tero.url`, Edge loads policies only from the local file provider — no remote policy sync. ### Values The keys you'll touch most. For every chart value (image, scheduling, service account, ingress), see the chart's `README.md`. | Key | Default | Description | | ----------------------------------- | ---------------------------------------------- | ---------------------------------------------------------------------------------- | | `tero.url` | `""` | Control plane base URL; setting it enables HTTP policy sync | | `tero.apiKey` | `""` | Inline API key (chart creates the Secret) | | `tero.existingSecret.name` | `""` | Name of a Secret you manage instead of `tero.apiKey` | | `tero.existingSecret.key` | `api-key` | Key within that Secret holding the API key | | `config.upstreamUrl` | `https://agent-http-intake.logs.datadoghq.com` | Logs intake endpoint (set per Datadog region) | | `config.metricsUrl` | `https://api.datadoghq.com` | Metrics endpoint (set per Datadog region) | | `config.logLevel` | `info` | Edge log level | | `config.maxBodySize` | `1048576` | Max request body in bytes | | `config.maxConnections` | `256` | Max concurrent connections; dominant memory cap (≈ `maxConnections × maxBodySize`) | | `config.maxDecodedBytes` | `null` | Post-decompression body ceiling; defaults to `maxBodySize` | | `config.workerCount` | `null` | httpz event-loop workers (`null` = default 1) | | `config.threadPoolCount` | `null` | httpz handler threads (`null` = default 32; scales per-thread memory) | | `config.service.name` | `""` | Service name sent on policy sync (omitted if empty) | | `config.service.namespace` | `""` | Service namespace sent on policy sync | | `config.service.version` | `""` | Service version sent on policy sync | | `config.service.resourceAttributes` | `[]` | OTel resource attributes (`{key, value}`) sent on policy sync | | `config.service.labels` | `[]` | Free-form labels (`{key, value}`) sent on policy sync | | `policiesJSON` | `[]` | Local policies rendered to the file provider (raw JSON objects) | ## Verify ```bash theme={null} kubectl -n tero-system rollout status ds/tero-edge kubectl -n tero-system port-forward ds/tero-edge 8080:8080 & curl http://localhost:8080/_health ``` A `200 OK` from `/_health` confirms Edge is running. Edge's own Prometheus metrics are available at `/_edge/metrics`. ## Upgrade and uninstall ```bash theme={null} # Upgrade to a new chart version (re-uses your values.yaml) helm upgrade tero-edge --version \ -n tero-system -f values.yaml # Uninstall helm uninstall tero-edge -n tero-system ``` See the [Configuration reference](/edge/edge-reference/config) for every `config.*` field, and [Operations](/edge/edge-reference/operations) for probes, resource sizing, and graceful shutdown. ## Next Steps Full configuration reference Probes, resources, and shutdown # What is Edge? Source: https://docs.usetero.com/edge/overview A telemetry policy runtime for your infrastructure Tero Edge [Edge](https://github.com/usetero/edge) is a telemetry policy runtime. It runs in your infrastructure and applies policies to telemetry before that data reaches an observability provider. Edge sits between telemetry sources and destinations: ```mermaid theme={null} flowchart LR Sources[Applications and agents] --> Edge[Tero Edge] Edge --> Provider[Observability provider] Policies[Policies] -. sync .-> Edge style Sources fill:#262626,stroke:#262626,color:#fafafa style Edge fill:#00855c,stroke:#006b49,color:#fafafa style Provider fill:#0e2b22,stroke:#0e2b22,color:#fafafa style Policies fill:#d1fae5,stroke:#10b981,color:#065f46 ``` Use Edge when a policy should run before telemetry leaves your network. Common policy actions include dropping low-value logs, sampling high-volume events, redacting sensitive values, and transforming fields into a cleaner shape. ## Where Edge fits Tero owns policy review, state, and impact. Edge owns runtime execution for the policies deployed to it. Reviewers can inspect issue evidence and approve policy changes in Tero. Edge receives the policy set, evaluates incoming telemetry, and forwards the telemetry that remains after policy execution. **Edge controls what reaches your observability provider.** ## When to use Edge Edge is useful when the control should happen close to the telemetry source: * Redact sensitive data before it leaves your infrastructure. * Drop repetitive logs before they consume provider ingestion. * Sample or rate-limit high-volume events before they flood the pipeline. * Run the same field transforms across services before storage. Provider-side controls can still be useful. Edge is the runtime surface for policies that need to execute in your environment instead of only inside Datadog, Splunk, or another destination. ## What Edge processes Edge receives telemetry through supported distributions and protocols, evaluates policies, and forwards surviving telemetry upstream. Current distribution docs cover: Datadog log and metric ingestion. OpenTelemetry Protocol ingestion. Multi-protocol Edge distribution. ## Where to go next Use [How Edge works](/edge/concepts) for the runtime model. Use [Quickstart](/edge/quickstart) to run Edge locally and verify one policy. # Log Filter Source: https://docs.usetero.com/edge/policy-reference/log-filter Filter logs by severity, content, attributes, and more Log filter policies control which logs pass through Edge. Use them to drop noise and sample high-volume events. ## Basic Structure ```json theme={null} { "id": "policy-id", "name": "Human-readable name", "log": { "match": [...], "keep": "..." } } ``` Every log policy has: * `match`: One or more matchers that identify target logs * `keep`: What to do with matching logs ## Matchers Matchers identify which logs a policy applies to. When a policy has multiple matchers, all must match (AND logic). ### Log Fields Match on well-known log fields: | Field | Description | | --------------- | ------------------------------------------------------- | | `body` | The log message content | | `severity_text` | Severity level as text (DEBUG, INFO, WARN, ERROR, etc.) | | `trace_id` | Associated trace ID | | `span_id` | Associated span ID | | `event_name` | Event name for event logs | ```json theme={null} { "id": "match-debug-logs", "name": "Match DEBUG severity logs", "log": { "match": [ { "log_field": "severity_text", "exact": "DEBUG" } ], "keep": "none" } } ``` ### Log Attributes Match on log record attributes: ```json theme={null} { "id": "match-200-status", "name": "Match logs with 200 status code", "log": { "match": [ { "log_attribute": "http.status_code", "exact": "200" } ], "keep": "all" } } ``` ### Resource Attributes Match on resource attributes (service name, host, etc.): ```json theme={null} { "id": "match-checkout-service", "name": "Match checkout-api service logs", "log": { "match": [ { "resource_attribute": "service.name", "exact": "checkout-api" } ], "keep": "10%" } } ``` ### Scope Attributes Match on instrumentation scope: ```json theme={null} { "id": "match-otel-python", "name": "Match OpenTelemetry Python logs", "log": { "match": [ { "scope_attribute": "library.name", "exact": "opentelemetry-python" } ], "keep": "all" } } ``` ## Match Types ### Exact Match Match the exact string value: ```json theme={null} { "id": "match-errors", "name": "Match ERROR logs", "log": { "match": [ { "log_field": "severity_text", "exact": "ERROR" } ], "keep": "all" } } ``` ### Regex Match Match using RE2 regular expressions: ```json theme={null} { "id": "match-order-completed", "name": "Match order completed logs", "log": { "match": [ { "log_field": "body", "regex": "order.*completed" } ], "keep": "50%" } } ``` Common patterns: * `^prefix` - Starts with * `suffix$` - Ends with * `word1.*word2` - Contains both words in order * `(option1|option2)` - Either option * `\\d+` - One or more digits ### Exists Match Match on field presence: ```json theme={null} { "id": "match-has-user-id", "name": "Match logs with user.id attribute", "log": { "match": [ { "log_attribute": "user.id", "exists": true } ], "keep": "all" } } ``` Use `exists: false` to match when a field is absent. ### Negation Invert any match with `negate`: ```json theme={null} { "id": "match-non-errors", "name": "Match all logs except ERROR", "log": { "match": [ { "log_field": "severity_text", "exact": "ERROR", "negate": true } ], "keep": "none" } } ``` This matches all logs except ERROR. ## Keep Values The `keep` field determines what happens to matching logs. ### Drop All ```json theme={null} "keep": "none" ``` Drop all matching logs. Use for: * Debug and trace logs in production * Health check logs * Known noisy log patterns ### Keep All ```json theme={null} "keep": "all" ``` Explicitly keep matching logs. ### Percentage Sampling ```json theme={null} "keep": "50%" ``` Keep a random percentage of matching logs. Valid range: 0-100%. Use for: * High-volume events where you don't need every instance * Cost reduction on repetitive logs ### Rate Limiting ```json theme={null} "keep": "100/s" ``` Keep up to N logs per time window: * `100/s` - 100 per second * `1000/m` - 1000 per minute Use for: * Burst protection * Capping runaway log sources ## Policy Precedence When multiple policies match the same log, the most restrictive action wins: 1. `none` (drop) beats everything 2. Lower percentages beat higher percentages 3. Rate limits are evaluated independently Example: If Policy A says `keep: 50%` and Policy B says `keep: none`, the log is dropped. ## Examples ### Drop Debug Logs ```json theme={null} { "id": "drop-debug-logs", "name": "Drop debug and trace logs", "log": { "match": [ { "log_field": "severity_text", "regex": "^(DEBUG|TRACE)$" } ], "keep": "none" } } ``` ### Drop Health Checks ```json theme={null} { "id": "drop-health-checks", "name": "Drop health check request logs", "log": { "match": [ { "log_field": "body", "regex": "(GET|HEAD) /(health|ready|live)" } ], "keep": "none" } } ``` ### Sample by Service ```json theme={null} { "id": "sample-checkout", "name": "Sample checkout service logs to 10%", "log": { "match": [ { "resource_attribute": "service.name", "exact": "checkout-api" } ], "keep": "10%" } } ``` ### Rate Limit Noisy Service ```json theme={null} { "id": "rate-limit-metrics-exporter", "name": "Rate limit metrics exporter logs", "log": { "match": [ { "resource_attribute": "service.name", "exact": "metrics-exporter" }, { "log_field": "severity_text", "exact": "INFO" } ], "keep": "100/s" } } ``` ### Drop by Attribute Presence ```json theme={null} { "id": "drop-internal-logs", "name": "Drop logs with internal flag", "log": { "match": [ { "log_attribute": "internal", "exists": true } ], "keep": "none" } } ``` ### Combine Multiple Conditions ```json theme={null} { "id": "drop-verbose-payment-logs", "name": "Drop verbose logs from payment services", "log": { "match": [ { "resource_attribute": "service.name", "regex": "^payment-" }, { "log_field": "severity_text", "regex": "^(DEBUG|TRACE|INFO)$" } ], "keep": "none" } } ``` ### Keep Everything Except Using `negate` to keep only important logs: ```json theme={null} { "id": "keep-only-errors", "name": "Keep only ERROR and FATAL logs", "log": { "match": [ { "log_field": "severity_text", "regex": "^(ERROR|FATAL)$", "negate": true } ], "keep": "none" } } ``` ## Best Practices 1. **Start broad, then narrow**: Begin with service-level policies, then add event-specific ones 2. **Prefer exact matches**: They are faster than regex 3. **Combine policies**: Multiple simple policies are easier to manage than one complex policy 4. **Document intent**: Use descriptive names and IDs 5. **Test first**: Verify policies in a staging environment before production ## Next Steps Modify logs: redact, remove, rename, add Filter metrics # Log Transform Source: https://docs.usetero.com/edge/policy-reference/log-transform Redact, remove, rename, and add log fields Log transform policies modify logs that pass through Edge. Use them to redact sensitive data, remove verbose fields, normalize attribute names, and add metadata. ## Basic Structure ```json theme={null} { "id": "policy-id", "name": "Human-readable name", "log": { "match": [...], "transform": { "remove": [...], "redact": [...], "rename": [...], "add": [...] } } } ``` Transforms can be combined with `keep` values. Transforms only apply to logs that survive the keep stage. ## Transform Order Transforms execute in a strict order: 1. **Remove** - Delete fields 2. **Redact** - Mask field values 3. **Rename** - Change field names 4. **Add** - Insert new fields This order is fixed, so design your transforms around it. ## Remove Remove fields from logs. Use this to strip verbose or internal data. ```json theme={null} { "id": "remove-verbose-fields", "name": "Remove verbose debug fields", "log": { "match": [ { "log_field": "body", "exists": true } ], "transform": { "remove": [ { "log_attribute": "debug_trace" }, { "log_attribute": "internal_id" }, { "resource_attribute": "k8s.pod.uid" } ] } } } ``` ### Removable Fields | Field Type | Syntax | | ------------------ | ------------------------------- | | Log attribute | `{"log_attribute": "key"}` | | Resource attribute | `{"resource_attribute": "key"}` | | Scope attribute | `{"scope_attribute": "key"}` | ### Example: Remove Verbose Kubernetes Metadata ```json theme={null} { "id": "remove-k8s-verbose", "name": "Remove verbose Kubernetes metadata", "log": { "match": [ { "resource_attribute": "k8s.pod.name", "exists": true } ], "transform": { "remove": [ { "resource_attribute": "k8s.pod.uid" }, { "resource_attribute": "k8s.replicaset.name" }, { "resource_attribute": "k8s.replicaset.uid" }, { "resource_attribute": "k8s.deployment.uid" } ] } } } ``` ## Redact Replace field values with a placeholder. The field remains present, but the value is masked. ```json theme={null} { "id": "redact-sensitive-fields", "name": "Redact email and credit card", "log": { "match": [ { "log_attribute": "user.email", "exists": true } ], "transform": { "redact": [ { "log_attribute": "user.email" }, { "log_attribute": "credit_card", "replacement": "[CARD REDACTED]" } ] } } } ``` ### Options | Option | Default | Description | | ------------- | -------------- | ------------------------- | | `replacement` | `"[REDACTED]"` | The value to replace with | ### Example: Redact PII ```json theme={null} { "id": "redact-pii", "name": "Redact personally identifiable information", "log": { "match": [ { "log_attribute": "user.email", "exists": true } ], "transform": { "redact": [ { "log_attribute": "user.email" }, { "log_attribute": "user.phone" }, { "log_attribute": "user.ssn", "replacement": "[SSN REDACTED]" } ] } } } ``` ### Example: Redact Payment Data ```json theme={null} { "id": "redact-payment", "name": "Redact payment card data", "log": { "match": [ { "resource_attribute": "service.name", "regex": "^payment-" } ], "transform": { "redact": [ { "log_attribute": "card.number", "replacement": "[PAN REDACTED]" }, { "log_attribute": "card.cvv", "replacement": "[CVV REDACTED]" }, { "log_attribute": "card.expiry" } ] } } } ``` ### Example: Redact When Present Only redact fields that exist: ```json theme={null} { "id": "redact-pan-if-exists", "name": "Redact PAN wherever it appears", "log": { "match": [ { "log_attribute": "pan", "exists": true } ], "transform": { "redact": [ { "log_attribute": "pan" } ] } } } ``` ## Rename Change field names. Use this to normalize attribute names across services. ```json theme={null} { "id": "rename-field", "name": "Rename old_name to new_name", "log": { "match": [ { "log_attribute": "old_name", "exists": true } ], "transform": { "rename": [ { "from_log_attribute": "old_name", "to": "new_name" } ] } } } ``` ### Options | Option | Default | Description | | -------- | ------- | ------------------------------------------------------------------------------------------- | | `upsert` | `false` | If `true`, overwrite the target if it exists. If `false`, skip the rename if target exists. | ### Source Field Types | Source | Syntax | | ------------------ | ---------------------------------- | | Log attribute | `"from_log_attribute": "key"` | | Resource attribute | `"from_resource_attribute": "key"` | | Scope attribute | `"from_scope_attribute": "key"` | The `to` field is always the new key name within the same attribute category. ### Example: Normalize Attribute Names ```json theme={null} { "id": "normalize-user-id", "name": "Normalize user ID attribute name", "log": { "match": [ { "log_attribute": "userId", "exists": true } ], "transform": { "rename": [ { "from_log_attribute": "userId", "to": "user.id" } ] } } } ``` ### Example: Rename with Upsert ```json theme={null} { "id": "standardize-service-name", "name": "Standardize service name attribute", "log": { "match": [ { "resource_attribute": "app.name", "exists": true } ], "transform": { "rename": [ { "from_resource_attribute": "app.name", "to": "service.name", "upsert": true } ] } } } ``` ## Add Insert new fields. Use this to add metadata, tags, or computed values. ```json theme={null} { "id": "add-processed-by", "name": "Add processed_by attribute", "log": { "match": [ { "log_field": "body", "exists": true } ], "transform": { "add": [ { "log_attribute": "processed_by", "value": "edge" } ] } } } ``` ### Options | Option | Default | Description | | -------- | ------- | -------------------------------------------------------------------------------------- | | `upsert` | `true` | If `true`, overwrite existing values. If `false`, only add if the field doesn't exist. | ### Field Types | Type | Syntax | | ------------------ | ----------------------------- | | Log attribute | `"log_attribute": "key"` | | Resource attribute | `"resource_attribute": "key"` | | Scope attribute | `"scope_attribute": "key"` | ### Example: Add Processing Metadata ```json theme={null} { "id": "add-edge-metadata", "name": "Add Edge processing metadata", "log": { "match": [ { "log_field": "body", "exists": true } ], "transform": { "add": [ { "log_attribute": "edge.processed", "value": "true" }, { "log_attribute": "edge.version", "value": "1.0.0" } ] } } } ``` ### Example: Add Environment Tag ```json theme={null} { "id": "add-environment", "name": "Add production environment tag", "log": { "match": [ { "resource_attribute": "deployment.environment", "exists": false } ], "transform": { "add": [ { "resource_attribute": "deployment.environment", "value": "production", "upsert": false } ] } } } ``` ## Combined Transforms You can use multiple transform operations in a single policy: ```json theme={null} { "id": "payment-log-cleanup", "name": "Clean up payment service logs", "log": { "match": [ { "resource_attribute": "service.name", "exact": "payment-api" } ], "transform": { "remove": [ { "log_attribute": "debug_context" }, { "log_attribute": "internal_trace_id" } ], "redact": [ { "log_attribute": "card.number" }, { "log_attribute": "card.cvv" } ], "rename": [ { "from_log_attribute": "txn_id", "to": "transaction.id" } ], "add": [ { "log_attribute": "pci.compliant", "value": "true" } ] } } } ``` ## Combining with Keep Transforms only apply to logs that survive the keep stage: ```json theme={null} { "id": "sample-and-redact-checkout", "name": "Sample checkout logs and redact cart data", "log": { "match": [ { "resource_attribute": "service.name", "exact": "checkout-api" } ], "keep": "50%", "transform": { "redact": [ { "log_attribute": "cart.contents" } ] } } } ``` This keeps 50% of checkout logs and redacts cart contents from the survivors. ## Best Practices 1. **Redact PII instead of removing it** so downstream tools still see the field existed 2. **Use descriptive replacements** for redacted fields (`[EMAIL REDACTED]` vs `[REDACTED]`) 3. **Test transforms** in staging before production 4. **Combine related transforms** in one policy for clarity 5. **Document why** fields are being modified ## Next Steps Filter logs by content and attributes Filter metrics # Metric Filter Source: https://docs.usetero.com/edge/policy-reference/metric-filter Filter metrics by name, type, and attributes Metric filter policies control which metrics pass through Edge. Use them to drop noisy metrics and cut cardinality costs. ## Basic Structure ```json theme={null} { "id": "policy-id", "name": "Human-readable name", "metric": { "match": [...], "keep": true } } ``` Every metric policy has: * `match`: One or more matchers that identify target metrics * `keep`: Boolean (`true` to keep, `false` to drop) Unlike log policies, metric policies don't support percentage sampling or rate limiting. The `keep` value is a simple boolean. ## Matchers Matchers identify which metrics a policy applies to. When a policy has multiple matchers, all must match (AND logic). ### Metric Fields Match on well-known metric fields: | Field | Description | | --------------- | -------------------------------------- | | `name` | The metric name | | `description` | Metric description | | `unit` | Metric unit (e.g., `ms`, `bytes`, `1`) | | `scope_name` | Instrumentation scope name | | `scope_version` | Instrumentation scope version | ```json theme={null} { "id": "match-cpu-metrics", "name": "Match system CPU metrics", "metric": { "match": [ { "metric_field": "name", "regex": "^system\\.cpu\\." } ], "keep": false } } ``` ### Metric Type Match on metric type: | Type | Description | | ----------------------------------- | ---------------------------- | | `METRIC_TYPE_GAUGE` | Instantaneous measurement | | `METRIC_TYPE_SUM` | Cumulative or delta sum | | `METRIC_TYPE_HISTOGRAM` | Distribution of values | | `METRIC_TYPE_EXPONENTIAL_HISTOGRAM` | Exponential bucket histogram | | `METRIC_TYPE_SUMMARY` | Pre-calculated quantiles | ```json theme={null} { "id": "match-histograms", "name": "Match histogram metrics", "metric": { "match": [ { "metric_type": "METRIC_TYPE_HISTOGRAM" } ], "keep": false } } ``` ### Aggregation Temporality Match on how metrics report aggregated values: | Temporality | Description | | ------------------------------------ | -------------------------------- | | `AGGREGATION_TEMPORALITY_DELTA` | Reports change since last report | | `AGGREGATION_TEMPORALITY_CUMULATIVE` | Reports total since start | ```json theme={null} { "id": "match-delta-metrics", "name": "Match delta temporality metrics", "metric": { "match": [ { "aggregation_temporality": "AGGREGATION_TEMPORALITY_DELTA" } ], "keep": true } } ``` ### Datapoint Attributes Match on data point attributes (dimensions/labels): ```json theme={null} { "id": "match-prod-web-01", "name": "Match metrics from prod-web-01", "metric": { "match": [ { "datapoint_attribute": "host.name", "exact": "prod-web-01" } ], "keep": true } } ``` ### Resource Attributes Match on resource attributes: ```json theme={null} { "id": "match-api-gateway", "name": "Match api-gateway service metrics", "metric": { "match": [ { "resource_attribute": "service.name", "exact": "api-gateway" } ], "keep": true } } ``` ### Scope Attributes Match on instrumentation scope attributes: ```json theme={null} { "id": "match-otel-go", "name": "Match OpenTelemetry Go metrics", "metric": { "match": [ { "scope_attribute": "library.name", "exact": "opentelemetry-go" } ], "keep": true } } ``` ## Match Types ### Exact Match Match the exact string value: ```json theme={null} { "id": "match-request-duration", "name": "Match HTTP request duration metric", "metric": { "match": [ { "metric_field": "name", "exact": "http.request.duration" } ], "keep": true } } ``` ### Regex Match Match using RE2 regular expressions: ```json theme={null} { "id": "drop-debug-metrics", "name": "Drop debug-prefixed metrics", "metric": { "match": [ { "metric_field": "name", "regex": "^debug\\." } ], "keep": false } } ``` ### Exists Match Match on field presence: ```json theme={null} { "id": "match-internal-flag", "name": "Match metrics with internal attribute", "metric": { "match": [ { "datapoint_attribute": "internal", "exists": true } ], "keep": false } } ``` ### Negation Invert any match with `negate`: ```json theme={null} { "id": "drop-non-system-metrics", "name": "Drop metrics not starting with system", "metric": { "match": [ { "metric_field": "name", "regex": "^system\\.", "negate": true } ], "keep": false } } ``` ## Policy Precedence When multiple policies match the same metric, `keep: false` takes precedence over `keep: true`. ## Examples ### Drop Debug Metrics ```json theme={null} { "id": "drop-debug-metrics", "name": "Drop debug-prefixed metrics", "metric": { "match": [ { "metric_field": "name", "regex": "^debug\\." } ], "keep": false } } ``` ### Drop System Load Metrics ```json theme={null} { "id": "drop-system-load", "name": "Drop system load metrics", "metric": { "match": [ { "metric_field": "name", "regex": "^system\\.load" } ], "keep": false } } ``` ### Drop Histogram Metrics ```json theme={null} { "id": "drop-histograms", "name": "Drop all histogram metrics", "metric": { "match": [ { "metric_type": "METRIC_TYPE_HISTOGRAM" } ], "keep": false } } ``` ### Drop by Datapoint Attribute ```json theme={null} { "id": "drop-internal-metrics", "name": "Drop metrics with internal flag", "metric": { "match": [ { "datapoint_attribute": "internal", "exists": true } ], "keep": false } } ``` ### Drop by Service ```json theme={null} { "id": "drop-test-service-metrics", "name": "Drop metrics from test services", "metric": { "match": [ { "resource_attribute": "service.name", "regex": "^test-" } ], "keep": false } } ``` ### Drop High-Cardinality Metrics ```json theme={null} { "id": "drop-per-request-metrics", "name": "Drop per-request ID metrics", "metric": { "match": [ { "datapoint_attribute": "request.id", "exists": true } ], "keep": false } } ``` ### Keep Only Specific Metrics Using negation to drop everything except what you want: ```json theme={null} { "id": "keep-only-business-metrics", "name": "Drop non-business metrics", "metric": { "match": [ { "metric_field": "name", "regex": "^business\\.", "negate": true } ], "keep": false } } ``` ### Combined Conditions ```json theme={null} { "id": "drop-noisy-api-metrics", "name": "Drop high-frequency API metrics from non-prod", "metric": { "match": [ { "metric_field": "name", "regex": "^http\\." }, { "resource_attribute": "deployment.environment", "exact": "production", "negate": true } ], "keep": false } } ``` ## Common Use Cases ### Cost Reduction Drop metrics you don't query: * Debug and internal metrics * Per-request ID dimensions (high cardinality) * Redundant system metrics * Metrics from test/dev environments ### Cardinality Control High-cardinality metrics (many unique label combinations) are expensive. Drop metrics with: * Unique request IDs as labels * User IDs as labels * Timestamps as labels * Unbounded string values as labels ### Compliance Drop metrics that might contain sensitive information: * Metrics with PII in labels * Metrics from sensitive services * Internal topology information ## Best Practices 1. **Start with observability**: Know what you're dropping before you drop it 2. **Use exact matches when possible**: Faster than regex 3. **Target high-volume metrics**: Focus on metrics that cost the most 4. **Be careful with negation**: It makes it easy to drop metrics you meant to keep 5. **Test in staging**: Verify policies before production deployment ## Next Steps Filter logs Transform log data # Edge Quickstart Source: https://docs.usetero.com/edge/quickstart Run Edge locally and verify one policy Run Edge locally with a file-backed policy, send two test logs, and verify Edge drops the debug log and forwards the error log. Prefer an AI assistant to walk you through this? Run `npx skills add https://docs.usetero.com` to add these docs as a skill in Claude Code, Codex, or Cursor. Then ask questions like "how do I run Edge locally?" and your agent guides you using Tero's documentation. ## Before you begin You need: * Docker * A Datadog intake endpoint and API key for your region * A working directory for the quickstart files This tutorial uses the Datadog distribution because it gives us a concrete log endpoint to test. ## 1. Create the Edge configuration Create `config.json`: ```json config.json theme={null} { "listen_address": "127.0.0.1", "listen_port": 8080, "upstream_url": "https://http-intake.logs.datadoghq.com", "metrics_url": "https://api.datadoghq.com", "log_level": "info", "service": { "name": "edge", "namespace": "production", "resource_attributes": [ { "key": "deployment.environment", "value": "production" } ], "labels": [{ "key": "team", "value": "platform" }] }, "policy_providers": [ { "id": "local", "type": "file", "path": "/etc/edge/policies.json" } ] } ``` If your Datadog account uses another region, replace `upstream_url` and `metrics_url` with the endpoints from [Edge Datadog](/edge/distributions/datadog). You now have a local Edge listener on port `8080` and a file policy provider. ## 2. Create a policy Create `policies.json`: ```json policies.json theme={null} { "policies": [ { "id": "drop-debug-logs", "name": "Drop debug logs", "log": { "match": [ { "log_field": "status", "regex": "^(debug|trace|DEBUG|TRACE)$" } ], "keep": "none" } } ] } ``` This policy matches Datadog log records whose `status` field is `debug` or `trace`. Edge drops matching logs. ## 3. Run Edge Run the Datadog distribution: ```bash theme={null} docker run --name tero-edge-quickstart --rm \ -p 8080:8080 \ -e DD_API_KEY="$DD_API_KEY" \ -v "$(pwd)/config.json:/etc/edge/config.json" \ -v "$(pwd)/policies.json:/etc/edge/policies.json" \ ghcr.io/usetero/edge-datadog:latest \ /etc/edge/config.json ``` Leave this terminal running. You should see Edge start and load the `local` policy provider. ## 4. Send a debug log In another terminal, send a debug log to Edge: ```bash theme={null} curl -X POST http://localhost:8080/api/v2/logs \ -H "Content-Type: application/json" \ --data-binary @- <<'JSON' [ { "message": "quickstart debug log", "status": "debug", "service": "edge-quickstart" } ] JSON ``` Edge should accept the request. Because the policy matches `status: debug`, Edge should drop the log before forwarding. ## 5. Send an error log Send an error log to the same endpoint: ```bash theme={null} curl -X POST http://localhost:8080/api/v2/logs \ -H "Content-Type: application/json" \ --data-binary @- <<'JSON' [ { "message": "quickstart error log", "status": "error", "service": "edge-quickstart" } ] JSON ``` This log should pass through because it does not match the policy. ## 6. Check Edge output Return to the terminal running Edge. You should see activity for the incoming requests. The debug request should show a policy match or dropped-log activity. The error request should show forwarding activity. If Edge forwards both requests, confirm that `policies.json` is mounted at `/etc/edge/policies.json` and that the policy matches the `status` field. ## What you ran You ran Edge locally, loaded one file-backed policy, sent two logs through Edge, and verified the policy decision. That is the basic Edge loop: receive telemetry, match policies, apply the keep decision, and forward the result. ## Next steps * Read [How Edge works](/edge/concepts) for the runtime model. * Use [Config](/edge/edge-reference/config) for configuration fields. * Use [Log filter](/edge/policy-reference/log-filter) for log matching and keep actions. * Use [Edge Datadog](/edge/distributions/datadog) for Datadog-specific configuration. # Datadog Source: https://docs.usetero.com/integrations/datadog Create read-only Datadog credentials for Tero Connect Datadog by creating read-only credentials and sharing them with Tero. This lets Tero review log telemetry, build service and log-event context, and analyze ingestion without changing anything in Datadog. ## What to create Tero needs two Datadog credentials: * An API key named `Tero` * An application key owned by a service account with the [permissions below](#permissions) Use the Datadog UI or `pup` CLI to create both credentials. ## Permissions Every permission Tero asks for is read-only. Tero reads log data out of your indexes and pulls summary statistics for metrics. Log analysis needs four: | Permission | What Tero does with it | | ---------------------- | ------------------------------------------------ | | `logs_read_data` | Reads indexed log data | | `logs_read_config` | Reads index, pipeline, and archive configuration | | `logs_read_index_data` | Reads data in restricted indexes | | `metrics_read` | Reads metric names, tags, and summary statistics | If your account includes metrics analysis, add five more: | Permission | What Tero does with it | | ------------------ | -------------------------------------- | | `timeseries_query` | Queries metric time series | | `dashboards_read` | Finds which dashboards use a metric | | `monitors_read` | Finds which monitors alert on a metric | | `slos_read` | Finds which SLOs depend on a metric | | `events_read` | Reads event data | Datadog's `Read-Only` role covers all nine. Grant it, or build a custom role with only the permissions you need. Nothing here lets Tero change your Datadog configuration. If you later want Tero to [enforce policies in Datadog](/policies/enforcement/provider), that takes write access you grant separately. ## Create credentials In Datadog, go to Organization Settings > API Keys. Create a new key named Tero. Go to Organization Settings > Service Accounts. Create a service account named Tero and assign it the Read-Only role, or a custom role holding the [permissions above](#permissions). Open the Tero service account. Under Application Keys, create an application key and copy it. Datadog shows the application key secret once. Use the same Datadog site your account normally uses. Replace \ with your Datadog site, such as datadoghq.com, us3.datadoghq.com, us5.datadoghq.com, datadoghq.eu, ap1.datadoghq.com, or ddog-gov.com. ```bash theme={null} brew tap datadog-labs/pack brew install datadog-labs/pack/pup pup auth login --site pup users roles --output table ``` ```bash theme={null} pup api-keys create --name Tero --output json ``` Copy the API key value from the output. Create `tero-service-account.json` with the role ID for Datadog's `Read-Only` role, or for a custom role holding the [permissions above](#permissions). The `pup users roles` output lists role IDs. ```json theme={null} { "data": { "type": "users", "attributes": { "name": "Tero", "email": "tero@datadoghq.com", "service_account": true }, "relationships": { "roles": { "data": [ { "id": "", "type": "roles" } ] } } } } ``` ```bash theme={null} pup users service-accounts create --file tero-service-account.json --output json ``` Copy the service account ID from the output. Create `tero-application-key.json`. ```json theme={null} { "data": { "type": "application_keys", "attributes": { "name": "Tero" } } } ``` ```bash theme={null} pup users service-accounts app-keys create --file tero-application-key.json --output json ``` Datadog shows the application key secret once. Copy it before closing the output. ## Share the credentials with Tero Send your Tero contact the Datadog API key, application key, and Datadog site. Tero uses those read-only credentials to start analysis. ## Related pages * [Issues](/issues/overview) * [Policies](/policies) * [Log events](/master-catalog/log-events) # Datadog Agent Source: https://docs.usetero.com/integrations/datadog-agent Deploy Edge alongside the Datadog Agent on Kubernetes Datadog Agent with Tero Edge Deploy Tero Edge alongside your Datadog Agent to apply policies to logs, metrics, and traces before they leave your cluster. ## How it works Edge runs as a DaemonSet on each node. The Datadog Agent sends logs through Edge instead of directly to Datadog. Edge applies policies and forwards to Datadog. ```mermaid theme={null} flowchart LR Pods --> DD[Datadog Agent] DD --> Edge[Tero Edge] Edge --> Datadog style Pods fill:#262626,stroke:#262626,color:#fafafa style DD fill:#632ca6,stroke:#632ca6,color:#fff style Edge fill:#10b981,stroke:#10b981,color:#fff style Datadog fill:#632ca6,stroke:#632ca6,color:#fff ``` Edge only proxies telemetry (logs, metrics, traces). Other agent traffic (security monitoring, remote config, fleet management) bypasses Edge and goes to Datadog. ## Prerequisites * Datadog Agent running on Kubernetes (via [Helm](https://docs.datadoghq.com/containers/kubernetes/installation/?tab=helm) or [Datadog Operator](https://docs.datadoghq.com/containers/kubernetes/installation/?tab=operator)) * `kubectl` access to your cluster * Tero account ## Connect Create the namespace and store your API key as a Kubernetes secret: ```bash theme={null} kubectl create namespace tero-system kubectl create secret generic tero-edge \ --namespace tero-system \ --from-literal=api-key=YOUR_API_KEY ``` Create a ConfigMap with your Edge configuration. Select your Datadog region: ```yaml tero-edge-config.yaml theme={null} apiVersion: v1 kind: ConfigMap metadata: name: tero-edge-config namespace: tero-system data: config.json: | { "listen_address": "0.0.0.0", "listen_port": 8080, "upstream_url": "https://agent-http-intake.logs.datadoghq.com", "metrics_url": "https://api.datadoghq.com", "log_level": "info", "service": { "name": "edge", "namespace": "production", "resource_attributes": [ { "key": "deployment.environment", "value": "production" } ], "labels": [{ "key": "team", "value": "platform" }] }, "max_body_size": 1048576, "policy_providers": [ { "id": "tero", "type": "http", "url": "https://sync.usetero.com/v1/policy/sync", "headers": [ { "name": "Authorization", "value": "Bearer ${TERO_API_KEY}" } ] } ] } ``` ```yaml tero-edge-config.yaml theme={null} apiVersion: v1 kind: ConfigMap metadata: name: tero-edge-config namespace: tero-system data: config.json: | { "listen_address": "0.0.0.0", "listen_port": 8080, "upstream_url": "https://agent-http-intake.logs.us3.datadoghq.com", "metrics_url": "https://api.us3.datadoghq.com", "log_level": "info", "service": { "name": "edge", "namespace": "production", "resource_attributes": [ { "key": "deployment.environment", "value": "production" } ], "labels": [{ "key": "team", "value": "platform" }] }, "max_body_size": 1048576, "policy_providers": [ { "id": "tero", "type": "http", "url": "https://sync.usetero.com/v1/policy/sync", "headers": [ { "name": "Authorization", "value": "Bearer ${TERO_API_KEY}" } ] } ] } ``` ```yaml tero-edge-config.yaml theme={null} apiVersion: v1 kind: ConfigMap metadata: name: tero-edge-config namespace: tero-system data: config.json: | { "listen_address": "0.0.0.0", "listen_port": 8080, "upstream_url": "https://agent-http-intake.logs.us5.datadoghq.com", "metrics_url": "https://api.us5.datadoghq.com", "log_level": "info", "service": { "name": "edge", "namespace": "production", "resource_attributes": [ { "key": "deployment.environment", "value": "production" } ], "labels": [{ "key": "team", "value": "platform" }] }, "max_body_size": 1048576, "policy_providers": [ { "id": "tero", "type": "http", "url": "https://sync.usetero.com/v1/policy/sync", "headers": [ { "name": "Authorization", "value": "Bearer ${TERO_API_KEY}" } ] } ] } ``` ```yaml tero-edge-config.yaml theme={null} apiVersion: v1 kind: ConfigMap metadata: name: tero-edge-config namespace: tero-system data: config.json: | { "listen_address": "0.0.0.0", "listen_port": 8080, "upstream_url": "https://agent-http-intake.logs.datadoghq.eu", "metrics_url": "https://api.datadoghq.eu", "log_level": "info", "service": { "name": "edge", "namespace": "production", "resource_attributes": [ { "key": "deployment.environment", "value": "production" } ], "labels": [{ "key": "team", "value": "platform" }] }, "max_body_size": 1048576, "policy_providers": [ { "id": "tero", "type": "http", "url": "https://sync.usetero.com/v1/policy/sync", "headers": [ { "name": "Authorization", "value": "Bearer ${TERO_API_KEY}" } ] } ] } ``` ```yaml tero-edge-config.yaml theme={null} apiVersion: v1 kind: ConfigMap metadata: name: tero-edge-config namespace: tero-system data: config.json: | { "listen_address": "0.0.0.0", "listen_port": 8080, "upstream_url": "https://agent-http-intake.logs.ap1.datadoghq.com", "metrics_url": "https://api.ap1.datadoghq.com", "log_level": "info", "service": { "name": "edge", "namespace": "production", "resource_attributes": [ { "key": "deployment.environment", "value": "production" } ], "labels": [{ "key": "team", "value": "platform" }] }, "max_body_size": 1048576, "policy_providers": [ { "id": "tero", "type": "http", "url": "https://sync.usetero.com/v1/policy/sync", "headers": [ { "name": "Authorization", "value": "Bearer ${TERO_API_KEY}" } ] } ] } ``` If you prefer to manage policies locally instead of syncing from Tero, use a file provider. Add `policies.json` to your ConfigMap: ```yaml tero-edge-config.yaml theme={null} apiVersion: v1 kind: ConfigMap metadata: name: tero-edge-config namespace: tero-system data: config.json: | { "listen_address": "0.0.0.0", "listen_port": 8080, "upstream_url": "https://agent-http-intake.logs.datadoghq.com", "metrics_url": "https://api.datadoghq.com", "log_level": "info", "service": { "name": "edge", "namespace": "production", "resource_attributes": [ { "key": "deployment.environment", "value": "production" } ], "labels": [{ "key": "team", "value": "platform" }] }, "max_body_size": 1048576, "policy_providers": [ { "id": "file", "type": "file", "path": "/etc/tero/policies.json" } ] } policies.json: | { "policies": [ { "id": "drop-debug-logs", "name": "drop-debug-logs", "enabled": true, "log": { "match": [{ "log_field": "severity_text", "regex": "DEBUG" }], "keep": "none" } } ] } ``` Update `upstream_url` and `metrics_url` for your Datadog region. ```bash theme={null} kubectl apply -f tero-edge-config.yaml ``` Deploy Edge to run on each node: ```yaml tero-edge-daemonset.yaml theme={null} apiVersion: apps/v1 kind: DaemonSet metadata: name: tero-edge namespace: tero-system labels: app: tero-edge spec: selector: matchLabels: app: tero-edge template: metadata: labels: app: tero-edge spec: containers: - name: tero-edge image: ghcr.io/usetero/edge:latest args: - /etc/tero/config.json env: - name: TERO_API_KEY valueFrom: secretKeyRef: name: tero-edge key: api-key ports: - containerPort: 8080 hostPort: 8080 protocol: TCP resources: requests: cpu: 50m memory: 32Mi limits: cpu: 200m memory: 64Mi volumeMounts: - name: tero-edge-config mountPath: /etc/tero readOnly: true livenessProbe: httpGet: path: /_health port: 8080 initialDelaySeconds: 5 periodSeconds: 10 readinessProbe: httpGet: path: /_health port: 8080 initialDelaySeconds: 2 periodSeconds: 5 volumes: - name: tero-edge-config configMap: name: tero-edge-config tolerations: - operator: Exists ``` ```bash theme={null} kubectl apply -f tero-edge-daemonset.yaml ``` Point the Datadog Agent's log output to Edge running on the same node. Add to your `DatadogAgent` CR: ```yaml theme={null} spec: features: logCollection: enabled: true override: nodeAgent: env: - name: HOST_IP valueFrom: fieldRef: fieldPath: status.hostIP - name: DD_LOGS_CONFIG_LOGS_DD_URL value: "http://$(HOST_IP):8080" tolerations: - operator: Exists ``` Add to your `values.yaml`: ```yaml theme={null} datadog: logs: enabled: true agents: containers: agent: env: - name: HOST_IP valueFrom: fieldRef: fieldPath: status.hostIP - name: DD_LOGS_CONFIG_LOGS_DD_URL value: "http://$(HOST_IP):8080" tolerations: - operator: Exists ``` The `HOST_IP` variable points the agent at the Edge instance on the same node via the hostPort. Check that Edge pods are running: ```bash theme={null} kubectl get pods -n tero-system -l app=tero-edge ``` Check Edge logs for incoming traffic: ```bash theme={null} kubectl logs -n tero-system -l app=tero-edge --tail=50 ``` ## Policy providers Edge supports multiple policy sources. Configure them in the `policy_providers` array in your ConfigMap. ### File provider Load policies from a local file. Use this for static policies bundled in the ConfigMap. ```json theme={null} { "id": "file", "type": "file", "path": "/etc/tero/policies.json" } ``` ### HTTP provider Fetch policies from a remote endpoint. This fits dynamic policies managed via the Tero API. ```json theme={null} { "id": "tero", "type": "http", "url": "https://sync.usetero.com/v1/policy/sync", "headers": [{ "name": "Authorization", "value": "Bearer ${TERO_API_KEY}" }] } ``` The DaemonSet injects `${TERO_API_KEY}` from the Kubernetes secret through its environment configuration. ## Example policies Add policies to the `policies.json` section of your ConfigMap: ```json theme={null} { "policies": [ { "id": "drop-debug-logs", "name": "drop-debug-logs", "enabled": true, "log": { "match": [{ "log_field": "severity_text", "regex": "DEBUG" }], "keep": "none" } }, { "id": "drop-nginx-source", "name": "drop-nginx-source", "enabled": true, "log": { "match": [{ "log_attribute": "ddsource", "regex": "nginx" }], "keep": "none" } }, { "id": "keep-errors", "name": "keep-errors", "enabled": true, "log": { "match": [ { "log_field": "severity_text", "regex": "error" }, { "log_field": "severity_text", "regex": "critical" } ], "keep": "all" } } ] } ``` See [Policy Reference](/edge/policy-reference/log-filter) for all filtering options. ## Troubleshooting **Agent can't reach Edge** Verify Edge is listening on the hostPort: ```bash theme={null} kubectl get pods -n tero-system -l app=tero-edge -o wide ``` Ensure both the agent and Edge have matching tolerations so they run on the same nodes. **Policies not applying** Check that Edge loaded policies: ```bash theme={null} kubectl logs -n tero-system -l app=tero-edge | grep -i policy ``` **Traffic not reaching Datadog** Verify `upstream_url` matches your Datadog region. Check Edge logs for upstream connection errors. # Datadog Lambda Extension Source: https://docs.usetero.com/integrations/datadog-lambda-extension Filter Lambda function telemetry with the Tero Datadog Lambda Extension Apply policies to logs, metrics, and traces emitted by your Lambda functions before they reach Datadog. Looking to filter AWS service logs (CloudWatch, S3, etc.)? See the [Lambda Forwarder](/integrations/datadog-lambda-forwarder) instead. ## How it works The Tero Datadog Lambda Extension is a fork of the [Datadog Lambda Extension](https://docs.datadoghq.com/serverless/libraries_integrations/extension/) with policy-based telemetry filtering. It runs as a Lambda layer alongside your function, evaluating each telemetry item against your policies before forwarding to Datadog. ```mermaid theme={null} flowchart LR subgraph ext[Tero Lambda Extension] DD[Datadog Extension] PR[policy-rs] DD --> PR end LF[Lambda Function] --> ext ext --> Datadog style LF fill:#262626,stroke:#262626,color:#fafafa style DD fill:#632ca6,stroke:#632ca6,color:#fff style PR fill:#10b981,stroke:#10b981,color:#fff style Datadog fill:#632ca6,stroke:#632ca6,color:#fff ``` The extension does not support FIPS compliance. Reach out to [Tero Support](mailto:support@usetero.com) if this is required for your environment. ### Versioning Releases track Datadog's upstream releases. Upstream publishes `v` tags, so a Tero release named for upstream v119 contains upstream v119. A new Tero release follows each upstream release. An AWS layer version is a single integer, and AWS only ever appends to it — you cannot ask for version 119. So the upstream version goes in the layer **name**, and the layer **version** integer is the patch number: | Release | Layer name | Layer version | | ------- | ---------------------------- | ------------- | | v119 | `Tero-Datadog-Extension-119` | 1 | | v119.2 | `Tero-Datadog-Extension-119` | 2 | | v120 | `Tero-Datadog-Extension-120` | 1 | This keeps the upstream number exact in every region without publishing filler versions to advance a counter, and it gives patches somewhere to live. A region we add later starts at patch 1, so patch numbers can differ per region. The upstream number never does. The older `Tero-Datadog-Extension` and `Tero-Datadog-Extension-ARM` layers, at versions 1 through 4, still exist and still work. Move to a versioned name when you next update the layer. ## Prerequisites * Lambda function with Datadog monitoring configured (see [Datadog's Lambda setup guide](https://docs.datadoghq.com/serverless/installation/)) * Tero account ## Connect Replace the standard Datadog extension layer with the Tero version. **ARM64:** ``` arn:aws:lambda::242046726909:layer:Tero-Datadog-Extension--ARM: ``` **AMD64:** ``` arn:aws:lambda::242046726909:layer:Tero-Datadog-Extension-: ``` Three parts change. The account ID `242046726909` does not. * `` must match your function's region. We publish to `us-east-1`, `us-east-2`, `us-west-1`, `us-west-2`, `eu-west-1`, `eu-west-2`, `eu-west-3`, `eu-central-1`, and `eu-north-1`. * `` is the Datadog extension version the layer is built from. Pick the name matching the version you want: `Tero-Datadog-Extension-119` contains Datadog v119. * `` is Tero's patch number for that Datadog version. Use the highest one published for it in your region. The [releases](https://github.com/usetero/datadog-lambda-extension/releases) list both numbers. A `v119.2` release is Datadog v119, patch 2. See [Versioning](#versioning) for why the version lives in the name. Add these environment variables to your Lambda function: ```bash theme={null} DD_POLICY_ENABLED=true DD_POLICY_PROVIDERS='[{"id":"tero","type":"http","url":"https://sync.usetero.com/v1/policy/sync","headers":[{"name":"Authorization","value":"Bearer YOUR_TERO_API_KEY"}],"poll_interval_secs":60}]' ``` This assumes `DD_API_KEY` and `DD_EXTENSION_ENABLED=true` are already configured from your existing Datadog setup. Replace `YOUR_TERO_API_KEY` with the API key you created in step 1. The extension will fail to sync policies without a valid bearer token. Invoke your Lambda function and check CloudWatch logs for extension startup: ``` [tero] Extension started, policies loaded: 5 ``` In Datadog, confirm the expected logs, metrics, or traces arrive and that any test telemetry matching your policy is absent or sampled at the expected rate. ## Policy providers The extension fetches policies from configured providers. Set `DD_POLICY_PROVIDERS` to a JSON array of provider configurations. ### HTTP provider Recommended for production. Fetches policies from a remote endpoint and polls for updates. ```bash theme={null} DD_POLICY_PROVIDERS='[{"id":"tero","type":"http","url":"https://sync.usetero.com/v1/policy/sync","headers":[{"name":"Authorization","value":"Bearer YOUR_API_KEY"}],"poll_interval_secs":60}]' ``` ### File provider For local testing. Reads policies from a file bundled with your Lambda deployment. ```bash theme={null} DD_POLICY_PROVIDERS='[{"id":"local","type":"file","path":"/var/task/policies.json"}]' ``` ### Provider options | Field | Type | Required | Description | | -------------------- | ------ | --------- | ----------------------------------------- | | `id` | string | Yes | Unique identifier for this provider | | `type` | string | Yes | `http` or `file` | | `url` | string | http only | URL to fetch policies from | | `path` | string | file only | Path to local policy JSON file | | `headers` | array | No | HTTP headers for authentication | | `poll_interval_secs` | number | No | Polling interval in seconds (default: 60) | ## Deployment examples ```hcl theme={null} resource "aws_lambda_function" "example" { function_name = "my-function" runtime = "python3.12" architectures = ["arm64"] layers = [ "arn:aws:lambda:us-east-1:242046726909:layer:Tero-Datadog-Extension--ARM:" ] environment { variables = { DD_API_KEY = var.datadog_api_key DD_EXTENSION_ENABLED = "true" DD_POLICY_ENABLED = "true" DD_POLICY_PROVIDERS = jsonencode([ { id = "tero" type = "http" url = "https://sync.usetero.com/v1/policy/sync" headers = [ { name = "Authorization", value = "Bearer ${var.tero_api_key}" } ] poll_interval_secs = 60 } ]) } } } ``` ```yaml theme={null} MyFunction: Type: AWS::Serverless::Function Properties: Runtime: python3.12 Architectures: - arm64 Layers: - arn:aws:lambda:us-east-1:242046726909:layer:Tero-Datadog-Extension--ARM: Environment: Variables: DD_API_KEY: !Ref DatadogApiKey DD_EXTENSION_ENABLED: "true" DD_POLICY_ENABLED: "true" DD_POLICY_PROVIDERS: !Sub | [{"id":"tero","type":"http","url":"https://sync.usetero.com/v1/policy/sync","headers":[{"name":"Authorization","value":"Bearer ${TeroApiKey}"}],"poll_interval_secs":60}] ``` ```yaml theme={null} functions: myFunction: runtime: python3.12 architecture: arm64 layers: - arn:aws:lambda:us-east-1:242046726909:layer:Tero-Datadog-Extension--ARM: environment: DD_API_KEY: ${ssm:/datadog/api-key} DD_EXTENSION_ENABLED: "true" DD_POLICY_ENABLED: "true" DD_POLICY_PROVIDERS: '[{"id":"tero","type":"http","url":"https://sync.usetero.com/v1/policy/sync","headers":[{"name":"Authorization","value":"Bearer ${ssm:/tero/api-key}"}],"poll_interval_secs":60}]' ``` ```bash theme={null} aws lambda update-function-configuration \ --function-name my-function \ --layers "arn:aws:lambda:us-east-1:242046726909:layer:Tero-Datadog-Extension--ARM:" \ --environment "Variables={DD_API_KEY=your-api-key,DD_EXTENSION_ENABLED=true,DD_POLICY_ENABLED=true,DD_POLICY_PROVIDERS='[{\"id\":\"tero\",\"type\":\"http\",\"url\":\"https://sync.usetero.com/v1/policy/sync\",\"headers\":[{\"name\":\"Authorization\",\"value\":\"Bearer your-tero-key\"}]}]'}" ``` ## How policy filtering works When `DD_POLICY_ENABLED=true`: 1. The extension fetches policies from configured providers on startup 2. HTTP providers poll for updates at the configured interval 3. The extension evaluates each telemetry item (logs, traces, metrics) against policies 4. Based on policy rules, the extension keeps, drops, samples, or rate-limits each item If no policy matches an item, the extension keeps it (fail open). See [Policy Reference](/edge/policy-reference/log-filter) for filtering options. ## Troubleshooting **Extension not loading** Verify the layer ARN matches your Lambda architecture (ARM64 vs x86\_64) and your function's region. Check CloudWatch logs for extension startup errors. **Layer ARN does not resolve** The layer name carries the Datadog version, so `Tero-Datadog-Extension-118` and `Tero-Datadog-Extension-119` are different layers. Confirm the version in the name is one we publish, and that the patch number exists in that region. Patch numbers can differ per region: a region we added later starts at patch 1, so a patch that resolves in `us-east-1` may not resolve in `eu-north-1` yet. **Policies not applying** * Ensure `DD_POLICY_ENABLED=true` is set * Verify `DD_POLICY_PROVIDERS` is valid JSON * Check that your policy provider URL is accessible from the Lambda VPC **Authentication errors** * Verify the Authorization header value is correct * Ensure your Tero API key is valid and not revoked # Datadog Lambda Forwarder Source: https://docs.usetero.com/integrations/datadog-lambda-forwarder Filter AWS logs with the Tero Edge Lambda Extension Apply policies to AWS service logs (CloudWatch, S3, EventBridge) before they reach Datadog using the Tero Edge Lambda Extension. Looking to filter telemetry from your Lambda functions? See the [Lambda Extension](/integrations/datadog-lambda-extension) instead. ## How it works The Tero Edge Lambda Extension integrates with the [Datadog Forwarder](https://docs.datadoghq.com/logs/guide/forwarder/) to provide policy-based log filtering. The extension runs as an external Lambda extension alongside the forwarder, intercepting logs and applying your policies before forwarding to Datadog. ```mermaid theme={null} flowchart LR CW[CloudWatch Logs] --> LF S3[S3 Buckets] --> LF EB[EventBridge] --> LF subgraph LF[Lambda Function] DD[Datadog Forwarder] TE[Tero Edge Extension] DD --> TE end TE --> Datadog style CW fill:#262626,stroke:#262626,color:#fafafa style S3 fill:#262626,stroke:#262626,color:#fafafa style EB fill:#262626,stroke:#262626,color:#fafafa style DD fill:#632ca6,stroke:#632ca6,color:#fff style TE fill:#10b981,stroke:#10b981,color:#fff style Datadog fill:#632ca6,stroke:#632ca6,color:#fff ``` Use cases: * Filter CloudWatch logs from EC2, RDS, ECS, and other AWS services * Apply policies to S3 access logs, ALB logs, or CloudTrail events * Drop noisy AWS service logs before Datadog indexes them ## Prerequisites * AWS account with logs you want to forward to Datadog * Datadog account with an [API key](https://app.datadoghq.com/organization-settings/api-keys) * Tero account with an API key The Tero Edge Extension layer is available in `us-east-1` only. Need support in another region? [Contact us](mailto:support@usetero.com). ## Setup Deploy the Datadog Forwarder with Tero Edge Extension using CloudFormation. Deploy via AWS CloudFormation ### Required parameters | Parameter | Description | | ------------------ | ------------------------------------------------------------------------------ | | `DdApiKey` | Your Datadog API key | | `DdSite` | Your Datadog site (e.g., `us5.datadoghq.com`, `datadoghq.com`, `datadoghq.eu`) | | `TeroPolicyApiKey` | Your Tero API key for policy sync | ### Tero Edge parameters The extension is enabled by default. Configure these parameters as needed: | Parameter | Default | Description | | ---------------------- | ----------------------------------------- | --------------------------------------------------------------- | | `TeroEdgeLayerVersion` | `4` | Version of the Tero Edge layer. Set to empty string to disable. | | `TeroEdgeLayerArn` | (auto) | Override the full layer ARN. Leave empty to use default. | | `TeroPolicyUrl` | `https://sync.usetero.com/v1/policy/sync` | HTTP policy provider URL | | `TeroPolicyApiKey` | | API key for authenticating with the policy provider | | `TeroPolicyStatic` | | JSON string for static policies (alternative to HTTP provider) | | `TeroListenPort` | `3000` | Port for the extension proxy server | | `TeroLogLevel` | `info` | Log level (`debug`, `info`, `warn`, `err`) | The extension configures the Datadog Forwarder to route logs through `localhost:3000`. The extension derives the upstream URL from your `DdSite` parameter. For existing Datadog Forwarder deployments, add the Tero Edge Extension layer. Add the Tero Edge Extension layer to your Lambda function: ``` arn:aws:lambda:us-east-1:242046726909:layer:Tero-Edge-Extension-ARM:4 ``` Add these environment variables to your Lambda function: | Variable | Value | | --------------------- | -------------------------------------------------- | | `DD_URL` | `localhost` | | `DD_PORT` | `3000` | | `DD_NO_SSL` | `true` | | `TERO_UPSTREAM_URL` | `https://http-intake.logs.YOUR_SITE.datadoghq.com` | | `TERO_LISTEN_PORT` | `3000` | | `TERO_POLICY_URL` | `https://sync.usetero.com/v1/policy/sync` | | `TERO_POLICY_API_KEY` | Your Tero API key | | `TERO_LOG_LEVEL` | `info` | Replace `YOUR_SITE` with your Datadog site (e.g., `us5` for `us5.datadoghq.com`). Invoke your Lambda function and check CloudWatch logs for: ``` [INFO] lambda.extension.starting [INFO] configuration.loaded logs_url="https://http-intake.logs.us5.datadoghq.com" ``` In Datadog Logs, confirm events from the test source arrive and that any logs matching your policy are absent or sampled at the expected rate. ## Triggers After deploying the forwarder, configure triggers to send AWS logs to it. Use the Datadog AWS integration to set up log collection from AWS. In the AWS console, go to **Lambda** → **Functions** and select your Datadog Forwarder. Copy the **Function ARN** from the function overview. In Datadog, go to [**Integrations** → **Amazon Web Services**](https://app.datadoghq.com/integrations/amazon-web-services). Select your AWS account and navigate to the **Log Collection** tab. Paste the forwarder ARN and save. In the same AWS integration page, enable the AWS services you want to collect logs from. Datadog creates the triggers for the selected services. Manually add CloudWatch Log triggers to the forwarder. In the AWS console, go to **Lambda** → **Functions** and select your Datadog Forwarder. Click **Add trigger** and select **CloudWatch Logs**. Select the log group from the dropdown. Enter a name for your filter and optionally specify a filter pattern. Click **Add**. Go to the [Datadog Logs](https://app.datadoghq.com/logs) section to explore log events from your log group. For other log sources (S3, Kinesis, etc.), see [Datadog's trigger configuration guide](https://docs.datadoghq.com/logs/guide/send-aws-services-logs-with-the-datadog-lambda-function/?tab=awsconsole#collecting-logs-from-cloudwatch-log-group). ## Static policies For simple use cases, you can embed policies in the Lambda configuration instead of using the HTTP policy provider. Set `TeroPolicyStatic` (or `TERO_POLICY_STATIC` environment variable) to a JSON string: ```json theme={null} { "policies": [ { "id": "drop-health-checks", "name": "Drop health check logs", "log": { "match": [ { "log_field": "body", "regex": "GET /health" } ], "keep": "none" } } ] } ``` Static policies change only when you redeploy. Use the HTTP policy provider for dynamic policy management. ## Environment variables reference | Variable | Description | | ---------------------- | ---------------------------------------------- | | `TERO_UPSTREAM_URL` | Datadog intake URL for forwarding logs | | `TERO_LISTEN_PORT` | Port for the extension proxy (default: `3000`) | | `TERO_LOG_LEVEL` | Log verbosity: `debug`, `info`, `warn`, `err` | | `TERO_POLICY_URL` | HTTP policy provider URL | | `TERO_POLICY_API_KEY` | API key for the policy provider | | `TERO_POLICY_STATIC` | JSON string with static policies | | `TERO_SERVICE_VERSION` | Version identifier for tracking | ## Troubleshooting **Extension not starting** Check CloudWatch logs for the extension: ``` EXTENSION Name: tero-edge State: Started Events: [] ``` If you see `LaunchError`, verify the layer ARN matches your architecture (ARM64 vs x86\_64). **Policies not applying** * Verify `TERO_POLICY_URL` is set and accessible * Check `TERO_POLICY_API_KEY` is correct * Enable `TERO_LOG_LEVEL=debug` to see policy loading logs **Connection errors to Datadog** * Verify `TERO_UPSTREAM_URL` matches your Datadog site * Check the Lambda has network access to Datadog endpoints * Review extension logs for TLS or connection errors **Forwarder not routing through extension** Ensure these environment variables are set: * `DD_URL=localhost` * `DD_PORT=3000` * `DD_NO_SSL=true` ## Disabling Tero Edge To disable the extension and route logs directly to Datadog: **CloudFormation**: Set `TeroEdgeLayerVersion` to an empty string. **Manual**: Remove the Tero Edge layer and unset the `DD_URL`, `DD_PORT`, `DD_NO_SSL`, and `TERO_*` environment variables. # OpenTelemetry Collector Source: https://docs.usetero.com/integrations/otel-collector Apply policies to logs in the OpenTelemetry Collector Apply Tero policies to logs passing through your OpenTelemetry Collector. Choose the option that fits your environment. | Option | Best for | | -------------------- | ---------------------------------------------------- | | **Tero Distro** | New deployments or replacing your existing collector | | **Edge Proxy** | Adding to an existing collector without rebuilding | | **Policy Processor** | Custom collector distributions you build yourself | Run the Tero Collector, a pre-built OpenTelemetry Collector distribution with the Policy Processor included. ## How it works The Tero Collector is a standard OTel Collector with our Policy Processor baked in. Deploy it like any collector, configure policies, and it filters logs before they reach your backend. ```mermaid theme={null} flowchart LR Apps[Applications] --> Collector[Tero Collector] Collector --> Backend[Backend] style Apps fill:#262626,stroke:#262626,color:#fafafa style Collector fill:#10b981,stroke:#10b981,color:#fff style Backend fill:#262626,stroke:#262626,color:#fafafa ``` The Policy Processor supports three actions: * **Drop**: Remove logs matching patterns * **Keep**: Retain only logs matching patterns * **Sample**: Sample at configurable rates Policies hot-reload without restarting the collector. ## Included components The Tero Collector includes standard OTel components: | Type | Components | | -------------- | ------------------------------------------------------------- | | **Receivers** | OTLP (gRPC, HTTP) | | **Processors** | Policy, Batch, Memory Limiter, Attributes, Filter, Resource | | **Exporters** | Debug, OTLP (gRPC, HTTP) | | **Connectors** | Forward | | **Extensions** | Health Check v2, zPages, PProf, Basic Auth, Bearer Token Auth | ## Prerequisites * Docker or Kubernetes cluster * Tero account ## Deploy Create a collector config: ```yaml config.yaml theme={null} receivers: otlp: protocols: grpc: endpoint: 0.0.0.0:4317 http: endpoint: 0.0.0.0:4318 processors: policy: providers: - type: http id: tero url: https://sync.usetero.com/v1/policy/sync headers: - name: Authorization value: Bearer ${TERO_API_KEY} poll_interval_secs: 60 exporters: otlphttp: endpoint: https://your-backend-endpoint.com service: pipelines: logs: receivers: [otlp] processors: [policy] exporters: [otlphttp] ``` Run the collector: ```bash theme={null} docker run --rm -p 4317:4317 -p 4318:4318 \ -e TERO_API_KEY=YOUR_API_KEY \ -v $(pwd)/config.yaml:/etc/tero-collector/config.yaml:ro \ ghcr.io/usetero/tero-collector-distro:latest ``` Create the namespace and secret: ```bash theme={null} kubectl create namespace observability kubectl create secret generic tero-collector \ --namespace observability \ --from-literal=api-key=YOUR_API_KEY ``` Deploy the collector: ```yaml tero-collector.yaml theme={null} apiVersion: opentelemetry.io/v1beta1 kind: OpenTelemetryCollector metadata: name: tero-collector namespace: observability spec: mode: deployment image: ghcr.io/usetero/tero-collector-distro:latest env: - name: TERO_API_KEY valueFrom: secretKeyRef: name: tero-collector key: api-key config: receivers: otlp: protocols: grpc: endpoint: 0.0.0.0:4317 http: endpoint: 0.0.0.0:4318 processors: policy: providers: - type: http id: tero url: https://sync.usetero.com/v1/policy/sync headers: - name: Authorization value: Bearer ${TERO_API_KEY} poll_interval_secs: 60 exporters: otlphttp: endpoint: https://your-backend-endpoint.com service: pipelines: logs: receivers: [otlp] processors: [policy] exporters: [otlphttp] ``` ```bash theme={null} kubectl apply -f tero-collector.yaml ``` Create the namespace and secret: ```bash theme={null} kubectl create namespace observability kubectl create secret generic tero-collector \ --namespace observability \ --from-literal=api-key=YOUR_API_KEY ``` Add to your `values.yaml`: ```yaml values.yaml theme={null} mode: deployment image: repository: ghcr.io/usetero/tero-collector-distro tag: latest extraEnvs: - name: TERO_API_KEY valueFrom: secretKeyRef: name: tero-collector key: api-key config: receivers: otlp: protocols: grpc: endpoint: 0.0.0.0:4317 http: endpoint: 0.0.0.0:4318 processors: policy: providers: - type: http id: tero url: https://sync.usetero.com/v1/policy/sync headers: - name: Authorization value: Bearer ${TERO_API_KEY} poll_interval_secs: 60 exporters: otlphttp: endpoint: https://your-backend-endpoint.com service: pipelines: logs: receivers: [otlp] processors: [policy] exporters: [otlphttp] ``` Install the chart: ```bash theme={null} helm repo add open-telemetry https://open-telemetry.github.io/opentelemetry-helm-charts helm install tero-collector open-telemetry/opentelemetry-collector \ --namespace observability \ -f values.yaml ``` Check the container is running: ```bash theme={null} docker ps | grep tero-collector ``` Check logs for policy sync: ```bash theme={null} docker logs 2>&1 | grep -i policy ``` ```bash theme={null} kubectl get pods -n observability -l app.kubernetes.io/name=tero-collector-collector kubectl logs -n observability -l app.kubernetes.io/name=tero-collector-collector | grep -i policy ``` ```bash theme={null} kubectl get pods -n observability -l app.kubernetes.io/instance=tero-collector kubectl logs -n observability -l app.kubernetes.io/instance=tero-collector | grep -i policy ``` ## Policy providers Configure where the collector loads policies from. ### File provider Load from a local file. Use this for static policies or GitOps workflows. ```yaml theme={null} processors: policy: providers: - type: file id: local path: /etc/tero-collector/policies.json poll_interval_secs: 30 ``` ### HTTP provider Fetch from a remote endpoint. Choose this for dynamic policies managed via Tero. ```yaml theme={null} processors: policy: providers: - type: http id: tero url: https://sync.usetero.com/v1/policy/sync headers: - name: Authorization value: Bearer ${TERO_API_KEY} poll_interval_secs: 60 ``` Run Edge as a sidecar to your existing OpenTelemetry Collector. Edge proxies telemetry, applies policies, and forwards to your backend. ## How it works Edge runs alongside your OTel Collector. The collector exports telemetry through Edge, which applies policies and forwards to your backend. ```mermaid theme={null} flowchart LR subgraph Deployment OTel[OTel Collector] Edge[Tero Edge] OTel --> Edge end Apps --> OTel Edge --> Backend[Backend] style Apps fill:#262626,stroke:#262626,color:#fafafa style OTel fill:#f59e0b,stroke:#f59e0b,color:#000 style Edge fill:#10b981,stroke:#10b981,color:#fff style Backend fill:#262626,stroke:#262626,color:#fafafa ``` ## Prerequisites * Existing OpenTelemetry Collector * Tero account ## Deploy Create an Edge config: ```json edge-config.json theme={null} { "listen_address": "0.0.0.0", "listen_port": 8080, "upstream_url": "https://your-backend-endpoint.com", "log_level": "info", "service": { "name": "edge", "namespace": "production", "resource_attributes": [ { "key": "deployment.environment", "value": "production" } ], "labels": [{ "key": "team", "value": "platform" }] }, "max_body_size": 1048576, "policy_providers": [ { "id": "tero", "type": "http", "url": "https://sync.usetero.com/v1/policy/sync", "headers": [ { "name": "Authorization", "value": "Bearer ${TERO_API_KEY}" } ], "poll_interval_secs": 60 } ] } ``` Run Edge: ```bash theme={null} docker run --rm -p 8080:8080 \ -e TERO_API_KEY=YOUR_API_KEY \ -v $(pwd)/edge-config.json:/etc/tero/config.json:ro \ ghcr.io/usetero/edge:latest /etc/tero/config.json ``` Configure your collector to export to Edge: ```yaml theme={null} exporters: otlphttp: endpoint: http://localhost:8080 ``` Create the secret and ConfigMap: ```bash theme={null} kubectl create secret generic tero-edge \ --from-literal=api-key=YOUR_API_KEY ``` ```yaml tero-edge-config.yaml theme={null} apiVersion: v1 kind: ConfigMap metadata: name: tero-edge-config data: config.json: | { "listen_address": "127.0.0.1", "listen_port": 8080, "upstream_url": "https://your-backend-endpoint.com", "log_level": "info", "service": { "name": "edge", "namespace": "production", "resource_attributes": [ { "key": "deployment.environment", "value": "production" } ], "labels": [{ "key": "team", "value": "platform" }] }, "max_body_size": 1048576, "policy_providers": [ { "id": "tero", "type": "http", "url": "https://sync.usetero.com/v1/policy/sync", "headers": [ { "name": "Authorization", "value": "Bearer ${TERO_API_KEY}" } ], "poll_interval_secs": 60 } ] } ``` ```bash theme={null} kubectl apply -f tero-edge-config.yaml ``` Add Edge as a sidecar to your `OpenTelemetryCollector` CR: ```yaml theme={null} apiVersion: opentelemetry.io/v1beta1 kind: OpenTelemetryCollector metadata: name: otel-collector spec: mode: deployment config: receivers: otlp: protocols: grpc: endpoint: 0.0.0.0:4317 http: endpoint: 0.0.0.0:4318 exporters: otlphttp: endpoint: http://localhost:8080 service: pipelines: logs: receivers: [otlp] exporters: [otlphttp] metrics: receivers: [otlp] exporters: [otlphttp] traces: receivers: [otlp] exporters: [otlphttp] volumes: - name: tero-edge-config configMap: name: tero-edge-config volumeMounts: - name: tero-edge-config mountPath: /etc/tero readOnly: true additionalContainers: - name: tero-edge image: ghcr.io/usetero/edge:latest args: - /etc/tero/config.json env: - name: TERO_API_KEY valueFrom: secretKeyRef: name: tero-edge key: api-key resources: requests: cpu: 50m memory: 32Mi limits: cpu: 200m memory: 64Mi volumeMounts: - name: tero-edge-config mountPath: /etc/tero readOnly: true livenessProbe: httpGet: path: /_health port: 8080 initialDelaySeconds: 5 periodSeconds: 10 readinessProbe: httpGet: path: /_health port: 8080 initialDelaySeconds: 2 periodSeconds: 5 ``` Create the secret and ConfigMap: ```bash theme={null} kubectl create secret generic tero-edge \ --from-literal=api-key=YOUR_API_KEY ``` ```yaml tero-edge-config.yaml theme={null} apiVersion: v1 kind: ConfigMap metadata: name: tero-edge-config data: config.json: | { "listen_address": "127.0.0.1", "listen_port": 8080, "upstream_url": "https://your-backend-endpoint.com", "log_level": "info", "service": { "name": "edge", "namespace": "production", "resource_attributes": [ { "key": "deployment.environment", "value": "production" } ], "labels": [{ "key": "team", "value": "platform" }] }, "max_body_size": 1048576, "policy_providers": [ { "id": "tero", "type": "http", "url": "https://sync.usetero.com/v1/policy/sync", "headers": [ { "name": "Authorization", "value": "Bearer ${TERO_API_KEY}" } ], "poll_interval_secs": 60 } ] } ``` ```bash theme={null} kubectl apply -f tero-edge-config.yaml ``` Add to your collector `values.yaml`: ```yaml theme={null} extraVolumes: - name: tero-edge-config configMap: name: tero-edge-config extraVolumeMounts: - name: tero-edge-config mountPath: /etc/tero readOnly: true extraContainers: - name: tero-edge image: ghcr.io/usetero/edge:latest args: - /etc/tero/config.json env: - name: TERO_API_KEY valueFrom: secretKeyRef: name: tero-edge key: api-key resources: requests: cpu: 50m memory: 32Mi limits: cpu: 200m memory: 64Mi volumeMounts: - name: tero-edge-config mountPath: /etc/tero readOnly: true livenessProbe: httpGet: path: /_health port: 8080 initialDelaySeconds: 5 periodSeconds: 10 readinessProbe: httpGet: path: /_health port: 8080 initialDelaySeconds: 2 periodSeconds: 5 config: receivers: otlp: protocols: grpc: endpoint: 0.0.0.0:4317 http: endpoint: 0.0.0.0:4318 exporters: otlphttp: endpoint: http://localhost:8080 service: pipelines: logs: receivers: [otlp] exporters: [otlphttp] metrics: receivers: [otlp] exporters: [otlphttp] traces: receivers: [otlp] exporters: [otlphttp] ``` Check Edge is running: ```bash theme={null} docker ps | grep edge curl http://localhost:8080/_health ``` Check that the collector pod has both containers running: ```bash theme={null} kubectl get pods -l app.kubernetes.io/name=otel-collector kubectl logs -c tero-edge --tail=50 ``` Check that the collector pod has both containers running: ```bash theme={null} kubectl get pods -l app.kubernetes.io/instance=otel-collector kubectl logs -c tero-edge --tail=50 ``` ## Policy providers Edge supports multiple policy sources. Configure them in the `policy_providers` array. ### File provider Load policies from a local file. This suits static policies. ```json theme={null} { "id": "file", "type": "file", "path": "/etc/tero/policies.json" } ``` ### HTTP provider Fetch policies from a remote endpoint. This works well for dynamic policies managed via Tero. ```json theme={null} { "id": "tero", "type": "http", "url": "https://sync.usetero.com/v1/policy/sync", "headers": [{ "name": "Authorization", "value": "Bearer ${TERO_API_KEY}" }], "poll_interval_secs": 60 } ``` Add the Policy Processor to your own custom OpenTelemetry Collector distribution using the OpenTelemetry Collector Builder (OCB). ## How it works Build a custom collector with the Policy Processor included. This gives you full control over which components to include while adding Tero's policy filtering. ```mermaid theme={null} flowchart LR Apps[Applications] --> Collector[Your Custom Collector] Collector --> Backend[Backend] style Apps fill:#262626,stroke:#262626,color:#fafafa style Collector fill:#10b981,stroke:#10b981,color:#fff style Backend fill:#262626,stroke:#262626,color:#fafafa ``` The Policy Processor uses [Hyperscan](https://www.hyperscan.io/) for high-performance regex matching. This requires CGO and platform-specific libraries. ## Prerequisites * Go 1.24+ * [OpenTelemetry Collector Builder](https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/main/cmd/builder) (ocb) * CGO-compatible build environment * Hyperscan/Vectorscan libraries * Tero account ### Install Hyperscan ```bash theme={null} brew install vectorscan ``` ```bash theme={null} apt-get install libhyperscan-dev ``` ```bash theme={null} apk add vectorscan-dev ``` ## Build ```yaml manifest.yaml theme={null} dist: name: my-collector description: Custom OTel Collector with Policy Processor output_path: ./build otelcol_version: 0.115.0 # Required for Hyperscan cgo_enabled: true receivers: - gomod: go.opentelemetry.io/collector/receiver/otlpreceiver v0.115.0 processors: - gomod: github.com/usetero/tero-collector-distro/processor/policyprocessor v0.2.0 exporters: - gomod: go.opentelemetry.io/collector/exporter/otlpexporter v0.115.0 - gomod: go.opentelemetry.io/collector/exporter/otlphttpexporter v0.115.0 extensions: - gomod: go.opentelemetry.io/collector/extension/healthcheckextension v0.115.0 ``` `cgo_enabled: true` is required. Without it, the build will fail due to Hyperscan dependencies. ```bash theme={null} ocb --config manifest.yaml ``` The built binary will be in `./build/my-collector`. ```yaml config.yaml theme={null} receivers: otlp: protocols: grpc: endpoint: 0.0.0.0:4317 http: endpoint: 0.0.0.0:4318 processors: policy: providers: - type: http id: tero url: https://sync.usetero.com/v1/policy/sync headers: - name: Authorization value: Bearer ${TERO_API_KEY} poll_interval_secs: 60 exporters: otlphttp: endpoint: https://your-backend-endpoint.com service: pipelines: logs: receivers: [otlp] processors: [policy] exporters: [otlphttp] ``` ```bash theme={null} export TERO_API_KEY=YOUR_API_KEY ./build/my-collector --config config.yaml ``` Create a Dockerfile: ```dockerfile Dockerfile theme={null} FROM golang:1.24-bookworm AS builder # Install Hyperscan RUN apt-get update && apt-get install -y libhyperscan-dev # Install OCB RUN go install go.opentelemetry.io/collector/cmd/builder@latest WORKDIR /build COPY manifest.yaml . # Build with CGO enabled ENV CGO_ENABLED=1 RUN builder --config manifest.yaml FROM debian:bookworm-slim # Install runtime dependencies RUN apt-get update && apt-get install -y libhyperscan5 ca-certificates && rm -rf /var/lib/apt/lists/* COPY --from=builder /build/build/my-collector /collector COPY config.yaml /etc/collector/config.yaml ENTRYPOINT ["/collector"] CMD ["--config", "/etc/collector/config.yaml"] ``` Build and run: ```bash theme={null} docker build -t my-collector . docker run --rm -p 4317:4317 -p 4318:4318 \ -e TERO_API_KEY=YOUR_API_KEY \ my-collector ``` After building and pushing your image, deploy with the OpenTelemetry Operator: ```bash theme={null} kubectl create namespace observability kubectl create secret generic tero-collector \ --namespace observability \ --from-literal=api-key=YOUR_API_KEY ``` ```yaml my-collector.yaml theme={null} apiVersion: opentelemetry.io/v1beta1 kind: OpenTelemetryCollector metadata: name: my-collector namespace: observability spec: mode: deployment image: your-registry/my-collector:latest env: - name: TERO_API_KEY valueFrom: secretKeyRef: name: tero-collector key: api-key config: receivers: otlp: protocols: grpc: endpoint: 0.0.0.0:4317 http: endpoint: 0.0.0.0:4318 processors: policy: providers: - type: http id: tero url: https://sync.usetero.com/v1/policy/sync headers: - name: Authorization value: Bearer ${TERO_API_KEY} poll_interval_secs: 60 exporters: otlphttp: endpoint: https://your-backend-endpoint.com service: pipelines: logs: receivers: [otlp] processors: [policy] exporters: [otlphttp] ``` ```bash theme={null} kubectl apply -f my-collector.yaml ``` After building and pushing your image, deploy with Helm: ```bash theme={null} kubectl create namespace observability kubectl create secret generic tero-collector \ --namespace observability \ --from-literal=api-key=YOUR_API_KEY ``` ```yaml values.yaml theme={null} mode: deployment image: repository: your-registry/my-collector tag: latest extraEnvs: - name: TERO_API_KEY valueFrom: secretKeyRef: name: tero-collector key: api-key config: receivers: otlp: protocols: grpc: endpoint: 0.0.0.0:4317 http: endpoint: 0.0.0.0:4318 processors: policy: providers: - type: http id: tero url: https://sync.usetero.com/v1/policy/sync headers: - name: Authorization value: Bearer ${TERO_API_KEY} poll_interval_secs: 60 exporters: otlphttp: endpoint: https://your-backend-endpoint.com service: pipelines: logs: receivers: [otlp] processors: [policy] exporters: [otlphttp] ``` ```bash theme={null} helm repo add open-telemetry https://open-telemetry.github.io/opentelemetry-helm-charts helm install my-collector open-telemetry/opentelemetry-collector \ --namespace observability \ -f values.yaml ``` ## Policy configuration The processor accepts a `providers` array for policy sources. ### Provider types | Type | Description | | ------ | ------------------------ | | `file` | Load from local file | | `http` | Fetch from HTTP endpoint | | `grpc` | Fetch from gRPC endpoint | ### Provider fields | Field | Type | Description | | -------------------- | ------ | ---------------------------------------- | | `type` | string | Provider type: `file`, `http`, or `grpc` | | `id` | string | Unique identifier for this provider | | `path` | string | File path (file provider only) | | `url` | string | Remote endpoint (http/grpc only) | | `poll_interval_secs` | int | How often to check for updates | | `headers` | array | HTTP headers (http provider only) | ## Telemetry support | Signal | Status | | ------- | ----------------- | | Logs | Alpha | | Metrics | Not yet supported | | Traces | Not yet supported | ## Metrics The processor emits `processor_policy_records` (Counter) with attributes: * `telemetry_type`: `logs`, `metrics`, or `traces` * `result`: `dropped`, `kept`, `sampled`, or `no_match` ## Example policies Policies use JSON format. Here are common patterns: ```json theme={null} { "policies": [ { "id": "drop-debug-logs", "name": "drop-debug-logs", "enabled": true, "log": { "match": [{ "log_field": "severity_text", "regex": "DEBUG" }], "keep": "none" } }, { "id": "sample-noisy-service", "name": "sample-noisy-service", "enabled": true, "log": { "match": [ { "resource_attribute": "service.name", "regex": "noisy-service" } ], "sample_rate": 0.1 } }, { "id": "keep-errors", "name": "keep-errors", "enabled": true, "log": { "match": [ { "log_field": "severity_text", "regex": "ERROR" }, { "log_field": "severity_text", "regex": "CRITICAL" } ], "keep": "all" } } ] } ``` See [Policy Reference](/edge/policy-reference/log-filter) for all filtering options. ## Troubleshooting **Collector won't start** Check the config syntax: ```bash theme={null} ./collector --config config.yaml --dry-run ``` **Policies not loading** Verify the policy file path is correct and the file is valid JSON. Check collector logs for policy-related errors. **CGO build errors (Policy Processor)** Ensure Hyperscan/Vectorscan is installed and `CGO_ENABLED=1` is set. On macOS, you may need to set `PKG_CONFIG_PATH`: ```bash theme={null} export PKG_CONFIG_PATH="/opt/homebrew/lib/pkgconfig:$PKG_CONFIG_PATH" ``` # Prometheus Source: https://docs.usetero.com/integrations/prometheus Deploy Edge as a sidecar proxy for Prometheus metrics scraping on Kubernetes Deploy Tero Edge as a sidecar to your application to filter Prometheus metrics before Prometheus scrapes them. Edge sits between Prometheus and your application, applying policies as each scrape passes through. ## How it works Edge runs as a sidecar container in the same pod as your application. Prometheus scrapes Edge instead of your application. Edge proxies the request to your app's `/metrics` endpoint, applies policies to filter metrics, and returns the filtered response. ```mermaid theme={null} flowchart LR Prometheus --> Edge[Tero Edge] subgraph Pod Edge --> App[Your App] end style Prometheus fill:#e6522c,stroke:#e6522c,color:#fff style Edge fill:#10b981,stroke:#10b981,color:#fff style App fill:#262626,stroke:#262626,color:#fafafa ``` ## Key features * **Streaming processing**: Edge filters metrics line-by-line as they stream through, keeping memory usage bounded regardless of response size * **Dual byte limits**: Configure `max_input_bytes_per_scrape` to bound memory usage and `max_output_bytes_per_scrape` to cap filtered response size * **Zero-copy forwarding**: Edge forwards metrics that pass policy checks without extra allocations * **Fail-open behavior**: If policy evaluation fails, metrics pass through unchanged ## Prerequisites * Application exposing Prometheus metrics on Kubernetes * Prometheus configured to scrape your pods * `kubectl` access to your cluster * Tero account ## Connect Store your API key as a Kubernetes secret: ```bash theme={null} kubectl create secret generic tero-edge \ --from-literal=api-key=YOUR_API_KEY ``` Create a ConfigMap with your Edge configuration: ```yaml tero-edge-config.yaml theme={null} apiVersion: v1 kind: ConfigMap metadata: name: tero-edge-config data: config.json: | { "listen_address": "0.0.0.0", "listen_port": 9090, "upstream_url": "http://localhost:8080", "log_level": "info", "service": { "name": "edge", "namespace": "production", "resource_attributes": [ { "key": "deployment.environment", "value": "production" } ], "labels": [{ "key": "team", "value": "platform" }] }, "prometheus": { "max_input_bytes_per_scrape": 10485760, "max_output_bytes_per_scrape": 10485760 }, "policy_providers": [ { "id": "tero", "type": "http", "url": "https://sync.usetero.com/v1/policy/sync", "headers": [ { "name": "Authorization", "value": "Bearer ${TERO_API_KEY}" } ], "poll_interval_secs": 60 } ] } ``` ```bash theme={null} kubectl apply -f tero-edge-config.yaml ``` Set `upstream_url` to your application's metrics endpoint. If your app exposes metrics on port 8080 at `/metrics`, use `http://localhost:8080`. Add the Edge container to your application deployment: ```yaml theme={null} apiVersion: apps/v1 kind: Deployment metadata: name: my-app spec: template: spec: containers: # Your application container - name: app image: my-app:latest ports: - name: http containerPort: 8080 - name: metrics-internal containerPort: 8080 # Your app's metrics port # Tero Edge sidecar - name: tero-edge image: ghcr.io/usetero/edge-prometheus:latest args: - /etc/tero/config.json ports: - name: metrics containerPort: 9090 # Prometheus scrapes this port env: - name: TERO_API_KEY valueFrom: secretKeyRef: name: tero-edge key: api-key resources: requests: cpu: 50m memory: 32Mi limits: cpu: 200m memory: 128Mi volumeMounts: - name: tero-edge-config mountPath: /etc/tero readOnly: true livenessProbe: httpGet: path: /_health port: 9090 initialDelaySeconds: 5 periodSeconds: 10 readinessProbe: httpGet: path: /_health port: 9090 initialDelaySeconds: 2 periodSeconds: 5 volumes: - name: tero-edge-config configMap: name: tero-edge-config ``` Update your Prometheus configuration to scrape the Edge sidecar port instead of your application's metrics port: ```yaml theme={null} scrape_configs: - job_name: "my-app" kubernetes_sd_configs: - role: pod relabel_configs: # Scrape the tero-edge metrics port (9090) instead of app port - source_labels: [__meta_kubernetes_pod_container_name] action: keep regex: tero-edge - source_labels: [__address__, __meta_kubernetes_pod_container_port_number] action: replace regex: ([^:]+):.* replacement: $1:9090 target_label: __address__ ``` Or if using ServiceMonitor (Prometheus Operator): ```yaml theme={null} apiVersion: monitoring.coreos.com/v1 kind: ServiceMonitor metadata: name: my-app spec: selector: matchLabels: app: my-app endpoints: - port: metrics # Points to Edge's port 9090 interval: 30s ``` Check that both containers are running: ```bash theme={null} kubectl get pods -l app=my-app ``` Test the metrics endpoint through Edge: ```bash theme={null} kubectl exec -it -c tero-edge -- wget -qO- http://localhost:9090/metrics | head -20 ``` Check Edge logs for filtering activity: ```bash theme={null} kubectl logs -c tero-edge --tail=50 ``` ## Configuration ### Prometheus settings Configure Prometheus-specific settings in the `prometheus` section: ```json theme={null} { "prometheus": { "max_input_bytes_per_scrape": 104857600, "max_output_bytes_per_scrape": 10485760 } } ``` | Setting | Default | Description | | ----------------------------- | ------- | ---------------------------------------------------------------------------------------------- | | `max_input_bytes_per_scrape` | 10MB | Maximum bytes to read from upstream per scrape. Limits memory for buffering input. | | `max_output_bytes_per_scrape` | 10MB | Maximum bytes to forward to client per scrape. Set lower than input if filtering reduces data. | **Example: High-cardinality filtering** If your application exposes 1GB of metrics but policies filter it down to 1MB, configure a high input limit with a lower output limit: ```json theme={null} { "prometheus": { "max_input_bytes_per_scrape": 1073741824, "max_output_bytes_per_scrape": 10485760 } } ``` This allows Edge to process the full 1GB response while capping the filtered output at 10MB. ### Policy providers Edge supports multiple policy sources. Configure them in the `policy_providers` array. #### File provider Load policies from a local file. Pick this for static policies bundled in the ConfigMap. ```json theme={null} { "id": "local", "type": "file", "path": "/etc/tero/policies.json" } ``` #### HTTP provider Fetch policies from a remote endpoint. Use this for dynamic policies managed via the Tero API. ```json theme={null} { "id": "tero", "type": "http", "url": "https://sync.usetero.com/v1/policy/sync", "headers": [{ "name": "Authorization", "value": "Bearer ${TERO_API_KEY}" }], "poll_interval_secs": 60 } ``` The `${TERO_API_KEY}` variable is injected from the Kubernetes secret via the container environment configuration. ## Memory tuning Edge's streaming architecture keeps memory usage predictable. Key factors: 1. **Input limit**: `max_input_bytes_per_scrape` caps how much data Edge reads from upstream. This bounds memory for buffering input data. 2. **Output limit**: `max_output_bytes_per_scrape` caps how much data Edge forwards to clients. Set this high if you have aggressive filtering. 3. **Line buffer**: Edge processes each metric line with a 4KB buffer. Edge passes lines over the 4KB limit through unfiltered. 4. **Concurrent scrapes**: Memory scales with concurrent scrapes. Each active scrape can use up to `max_input_bytes_per_scrape`. For high-cardinality workloads with aggressive filtering: ```json theme={null} { "prometheus": { "max_input_bytes_per_scrape": 1073741824, "max_output_bytes_per_scrape": 52428800 } } ``` This allows processing up to 1GB of metrics while capping output at 50MB. ## Troubleshooting **Prometheus can't scrape metrics** Verify Edge is running and healthy: ```bash theme={null} kubectl describe pod kubectl logs -c tero-edge ``` Ensure Prometheus is configured to scrape port 9090 (Edge) not your app's metrics port directly. **Metrics not being filtered** Check that policies loaded successfully: ```bash theme={null} kubectl logs -c tero-edge | grep -i policy ``` Verify your policy targets `metric` telemetry type with `METRIC_FILTER` stage. **Scrapes timing out** If your app has high-cardinality metrics, increase resource limits: ```yaml theme={null} resources: limits: cpu: 500m memory: 256Mi ``` Also check `max_input_bytes_per_scrape` isn't truncating large responses. **Some metrics missing** Check if scrapes are being truncated due to input or output limits: ```bash theme={null} kubectl logs -c tero-edge | grep -i truncat ``` Increase the limit if needed, or add policies to drop unwanted metrics earlier in the stream. # How Tero works Source: https://docs.usetero.com/introduction/how-tero-works From issue evidence to policy runtime impact Tero turns telemetry findings into reviewable policies and tracks what happens after those policies run. Tero presents the control loop. The control plane owns durable evidence, recommendations, policy state, catalog state, runtime state, and impact. Your connected systems remain the source of record for telemetry, provider configuration, repositories, and runtime execution. ## 1. Tero finds issues Tero starts with issues: cost waste, compliance exposure, signal-quality problems, and checks that found policy opportunities. The Issues workspace shows each finding with priority, category, affected service, status, and the next review step. Issues show the work queue for telemetry control.

Issues show the work queue for telemetry control. Open in demo

Cost and Compliance lanes give you another view of the same work. They group affected services and link back to the issues that explain the problem. ## 2. Evidence supports the recommendation Issue detail explains the finding, its cost or compliance stakes, and the supporting evidence. Evidence can include representative log events, field analysis, related checks, affected services, volume, cost, or compliance exposure. Tero also shows provenance. A reviewer can see whether a recommendation came from a check, catalog context, provider inventory, or runtime state. This keeps review grounded in facts from systems you operate. The recommended policy card connects evidence to a concrete action.

The recommended policy card connects evidence to a concrete action. Open in demo

## 3. A policy captures the change Tero presents a recommended policy for issues a policy can address. The policy states what telemetry it matches and what action it takes, such as dropping, sampling, redacting, or transforming matching log events. Approved policies appear in the Policies workspace. Policy detail shows identity, source, related issue, activity, spec, and deployments. The spec is reviewable because the policy is the control-plane artifact that other systems execute. Policy detail shows the reviewed change, its source issue, spec, activity, and deployment state.

Policy detail shows the reviewed change, its source issue, spec, activity, and deployment state. Open in demo

## 4. Runtime surfaces show where policies run Policies can run through provider configuration, repositories, collectors, or [Tero Edge](/edge/overview). The Edge instances screen shows the runtime side of the loop: live instances, deployed policy counts, policy errors, last-seen state, and correlated issues. Edge instances show runtime policy state.

Edge instances show runtime policy state. Open in demo

Tero shows state and review controls. Providers, Git repositories, collectors, and Edge instances perform the production changes. ## 5. Impact closes the loop After action, Tero tracks impact: issue status, cost movement, compliance exposure, policy activity, and runtime deployment state. If a policy stops matching, fails to deploy, or leaves a related issue open, Tero keeps that visible and keeps the issue, its policy, the runtime state, and the impact connected. Cost shows whether telemetry policy work changed spend and recoverable savings.

Cost shows whether telemetry policy work changed spend and recoverable savings. Open in demo

# How Tero compares Source: https://docs.usetero.com/introduction/tero-versus Where telemetry control fits in your stack Tero is a control plane for telemetry policy. It sits above the systems that collect, store, route, and execute telemetry changes. Tero owns one loop across those systems: find telemetry issues a policy can fix, present evidence for review, and track policy runtime impact. | Work you already do | Existing systems answer | Tero answers | | -------------------------------------------- | ------------------------------------------------ | ---------------------------------------------------------------------------------------------------------- | | Store, search, and visualize telemetry | What happened in production? | Which telemetry creates cost, compliance, or signal-quality issues, and what policy should address it? | | Route, buffer, enrich, and forward telemetry | Where should telemetry go next? | Which policy should run, where should it run, and did the runtime apply it? | | Reduce observability spend | Which account, team, or service spent money? | Which log events caused the spend, what evidence supports action, and which policy can reduce it? | | Control sensitive telemetry | Which controls and risks does the company track? | Which telemetry exposed sensitive data, what policy can remove it, and did exposure decrease after action? | ## Observability platforms Datadog and Splunk store telemetry, run queries, power dashboards, and expose provider-specific controls. Tero connects to them for evidence, catalog context, usage, and provider actions. Your observability provider remains the source of record for its data and configuration. Tero adds a review layer that ties costly or sensitive log events to a policy and confirms the change took effect. Provider actions stay provider-specific. In Datadog, that can mean exclusion filters or pipelines. In Splunk, that can mean ingest actions. Tero keeps the policy review and impact model consistent across providers. ## Pipelines and collectors Collectors and pipelines move telemetry. They route, buffer, enrich, filter, and forward data to the next destination. Tero owns the policy control loop above those runtimes. A policy starts from an issue with evidence attached. Your team reviews it and deploys it through the runtime you choose; the runtime executes the change while Tero tracks policy state and impact. Use the [Edge](/edge/overview) docs when you want policies to run before telemetry leaves your infrastructure. ## Cost tools Cost tools show spend. They help you allocate cost by account, service, product line, or team. Tero shows the telemetry issue behind the spend. The Cost lane links service-level log cost to open issues and policy recommendations. A reviewer does the work: opens the issue, checks the evidence, and approves or rejects the policy. ## Security and compliance tools Security and compliance tools define controls, detect exposure, and support audit work. Tero focuses on telemetry policy issues that create compliance exposure, such as sensitive fields in log events. The Compliance lane groups affected services and links into issues with evidence, recommended policy action, and status. Tero feeds your control process. Your security or compliance system remains the place where your company owns risk acceptance, audit evidence, and security operations. ## Policy repositories Git gives policies review, version history, and auditability. Tero can sync policies to repositories when your workflow needs that control. The policy object still starts from evidence. A repository can store the policy, but Tero keeps the relationship between issue, policy, runtime deployment, and impact visible. # What is Tero? Source: https://docs.usetero.com/introduction/what-is-tero Telemetry control for production teams Tero shows the state of your telemetry estate: the issues that need review, the policies that can fix them, and the impact of those policies at runtime. Datadog, Splunk, collectors, and pipelines remain the systems where telemetry lives. Tero is the control layer above them. Issues are the main entry point for telemetry policy control.

Issues are the main entry point for telemetry policy control. Open in demo

Tero helps you control telemetry policy. It finds issues across cost, compliance, and signal quality. Each issue includes evidence, provenance, impact, and a recommended policy or action. You review the evidence before you decide what should change. Policies are control-plane artifacts. Tero presents them with status, source, spec, related issue, deployment state, and measured activity. The control plane owns durable policy state; your providers, repositories, collectors, and Edge instances run the changes. The workflow: 1. [Issues](/issues/overview): Tero shows what it found and the cost or exposure behind it. 2. [Policies](/policies): you review the policy that would address the issue. 3. Runtime: Tero shows where the policy runs, including provider configuration and [Edge instances](/edge/overview). 4. Impact: Tero measures whether the issue, cost, or compliance exposure changed after action. ## Why telemetry needs control Telemetry grows through local decisions. A team adds a debug log during an incident. A health check logs once per second, long after anyone reads it. Two libraries use different names for the same field, so it ships twice. Each change can make sense in isolation, but together they raise your bill and bury the signals you rely on. Pipelines move and transform data, and providers store and query it. Tero adds the missing control loop: find the issue, show the evidence, propose the policy, track runtime state, and measure the result. ## Where to start Start with [Issues](/issues/overview) if you have Tero connected and want to understand the main workspace. Use [How Tero works](/introduction/how-tero-works) for the full control loop. # Evidence Source: https://docs.usetero.com/issues/evidence The evidence Tero shows before it recommends action Tero attaches these evidence surfaces to an issue. ## Evidence types | Evidence | What you learn from it | Where to inspect it | | ------------------- | -------------------------------------------------------------------------------- | ------------------------------------------------------ | | Log events | Which grouped log patterns contributed to the issue | Issue detail, [Log events](/master-catalog/log-events) | | Representative logs | Example records that match the finding | Issue detail | | Fields | Attributes involved in duplication, sensitivity, malformed data, or payload size | Issue detail, log event detail | | Volume | How often the affected telemetry appears | Issue detail, Log events, Log ingestion | | Cost | Estimated spend tied to the affected log volume | Cost lane, issue detail | | Compliance exposure | Sensitive or regulated data detected in telemetry | Compliance lane, issue detail | | Service ownership | Which service or team owns the affected telemetry | Issue detail, [Services](/master-catalog/services) | | Runtime state | Whether a policy is deployed or failing in an execution surface | Policy detail, Edge instances | ## Provenance Provenance identifies where a finding came from. Tero can derive issue context from checks, catalog data, provider inventory, runtime state, or policy activity. ## Checks Checks are detector records behind many issues. The Checks screen shows detector inventory for telemetry waste, quality gaps, and policy opportunities across the log estate. Checks can be filtered by **All**, **Cost**, or **Compliance**. Each check can show related open issues and last-run state. ## Evidence and policy review Use the evidence to answer four review questions: 1. Did Tero identify the right telemetry? 2. Does the issue matter for cost, compliance, or signal quality? 3. Would the recommended policy make the right change? 4. Can Tero show where the policy runs and what changed after it ran? Use [Review an issue](/issues/review-an-issue) for the review workflow. # Issue lifecycle Source: https://docs.usetero.com/issues/lifecycle Statuses, views, and actions for issues Tero uses these issue states, views, and actions. ## Statuses | Status | Meaning | | --------------- | --------------------------------------------------------------- | | **Open** | Tero found the issue and it needs review. | | **In progress** | Someone is deploying the policy or remediating the issue. | | **Resolved** | Tero considers the issue addressed. | | **Ignored** | A reviewer accepted or dismissed the issue without remediation. | ## Domains | Domain | Meaning | | -------------- | ---------------------------------------------------------------- | | **Cost** | The issue affects log volume, spend, or recoverable savings. | | **Compliance** | The issue affects sensitive data exposure or compliance posture. | ## Severities | Severity | Meaning | | ---------- | ----------------------------------------------------------------------------- | | **High** | Review first. The issue has material cost, compliance, or operational impact. | | **Medium** | Review after high-severity issues or when the affected service is in scope. | | **Low** | Review when cleaning up backlog or validating a detector. | ## Queue controls The Issues workspace supports: * Search by issue text * Filter by severity, service, team, domain, check, linked issue, and status * Views for **All**, **Cost**, and **Compliance** * Sort controls in the queue * Loading additional issue rows ## Detail actions Issue detail can show these actions: | Action | Meaning | | ----------------------------------- | -------------------------------------------------------------- | | **Deploy policy** | Create or roll out the recommended policy where it should run. | | **Ignore** | Close the issue without remediation. | | **Retry detail** | Reload issue detail after a failed request. | | **Previous issue** / **Next issue** | Move through the queue without returning to the list. | ## Remediation states Policy-related issues can show remediation states such as **Ready to deploy**, **Creating policy**, **Rolling out policy**, **Policy active**, **Policy revoked**, **Policy rollout failed**, and **Resolution verified**. Use [Review an issue](/issues/review-an-issue) for the review workflow. # Issues Source: https://docs.usetero.com/issues/overview The work queue for telemetry control Issues are the main entry point for telemetry control in Tero. An issue is a finding that needs review: cost waste, compliance exposure, signal-quality risk, or a check result you can turn into a policy action. Tero shows the issue with evidence, provenance, status, severity, affected service, and a recommended next step. The Issues workspace combines filters, a work queue, and issue detail.

The Issues workspace combines filters, a work queue, and issue detail. Open in demo

## How issues fit into review Tero starts with issues so each policy traces back to a specific problem you reviewed. You need to know what Tero found and what evidence supports acting on it. A typical review goes like this: 1. Open an issue. 2. Review the evidence and provenance. 3. Inspect the recommended policy or action. 4. Deploy, ignore, or continue investigation. 5. Track policy state, runtime state, and impact. Cost and Compliance lanes group issues by outcome. Checks show the detector inventory behind many issues. Services and Log events show the catalog context that helps you judge whether the recommendation is right. ## What an issue shows Issue rows show status, severity, age, title, affected service or team, check type, and domain. The current domains in Tero are **Cost** and **Compliance**. Issue detail shows the review context: * A summary of what Tero found * A policy card when Tero recommends a policy * Related log events or affected fields * Evidence and timeline entries * Actions such as **Ignore** or **Deploy policy** Tero can also show an active policy link when a policy already addresses the issue. ## Issue views and filters Use the Issues workspace to filter by severity, service, team, domain, check, linked issue, and status. The queue supports issue search, status selection, and loading more results. Use **All** when you want the complete queue. Use **Cost** or **Compliance** when you are reviewing a specific lane. ## Related pages * [Review an issue](/issues/review-an-issue) * [Evidence](/issues/evidence) * [Issue lifecycle](/issues/lifecycle) * [Policies](/policies) * [Checks](/issues/evidence#checks) # Review an issue Source: https://docs.usetero.com/issues/review-an-issue Decide what to do with a telemetry finding Review an open issue and choose the next action. ## Prerequisites * A Tero account with an observability integration connected * An open issue in the Issues workspace * Permission to review issues or deploy policies for the affected service ## Open the issue Go to **Issues** and select an issue from the work queue. Use filters when the queue is large. Filter by status, severity, service, team, domain, check, or linked issue. Cost and Compliance views narrow the queue to those domains. ## Check the summary Read the header summary first. Confirm the affected service, issue category, severity, and current status. If the issue concerns a service you do not own, use the service or team fields to find the right reviewer before taking action. ## Review the evidence Read the evidence sections before acting. Depending on the issue, Tero may show representative log events, affected fields, related checks, volume, cost, compliance exposure, or timeline entries. Open related services or log events when you need more catalog context. The evidence panel shows the facts behind a recommended policy.

The evidence panel shows the facts behind a recommended policy. Open in demo

## Inspect the policy card If Tero recommends a policy, inspect the policy card. Confirm: * What the policy matches * Which action it takes * Which service or log event it affects * Whether the policy already exists or needs deployment If a policy is active, open the policy detail page to review the overview, deployments, and spec. ## Choose the next action Use the issue actions after you review the evidence. Choose **Deploy policy** when the recommendation is correct and your team wants Tero to apply it where the policy should run. Choose **Ignore** when the issue is expected, accepted, or outside the scope Tero should act on. Continue investigation when the evidence is incomplete, the service owner disagrees, or the policy action needs a code or provider change outside the current workflow. ## Verify the result After deployment, return to the issue or open the linked policy. Check that the policy status, deployment state, and activity match the action you took. If deployment fails, use the issue state and policy detail to find where the failure happened. For Edge-related failures, inspect [Edge instances](/edge/overview) and the relevant Edge detail screen. # Log events Source: https://docs.usetero.com/master-catalog/log-events Grouped log patterns used in issue evidence A log event is a grouped pattern of matching log records. Tero uses log events to show service, severity, volume, cost, policies, and related issues for recurring telemetry. Log events group raw logs into patterns you can review.

Log events group raw logs into patterns you can review. Open in demo

## Log event list The Log events list can show these fields: | Field | Description | | ---------- | --------------------------------------------------- | | Log event | The grouped log pattern name or description. | | Service | Service that emits the event. | | Severity | Observed severity for matching logs. | | Event rate | How often matching logs arrive. | | Volume | Total observed log volume over the selected window. | | Cost | Estimated annualized cost for the event. | | Updated | Most recent update time. | Datadog-scoped accounts can inspect 24-hour, 7-day, and 30-day log-volume windows. ## Log event detail Log event detail pages show the event in context. Current detail tabs include overview, policies, and issues. | Detail area | Description | | ----------- | ----------------------------------------- | | Overview | Service, volume, cost, and event summary. | | Policies | Policies attached to the event. | | Issues | Issues related to the event. | ## Relationship to issues Issues use log events as evidence when a finding concerns a recurring log pattern. A cost issue may point to a high-volume event, while a compliance issue may point to an event that carries sensitive fields. A policy recommendation may match a specific log event so the runtime can drop, sample, redact, or transform it. ## Related pages * [Evidence](/issues/evidence) * [Services](/master-catalog/services) * [Policies](/policies) # Master Catalog Source: https://docs.usetero.com/master-catalog/overview The catalog context behind issues and policies The Master Catalog is Tero's maintained context for the telemetry estate. Use catalog data to understand an issue before you approve a policy: it links findings to services, log events, ownership, volume, cost, compliance exposure, and related runtime state. ## Current catalog surfaces Tero exposes catalog context through Services and Log events. Service-level ownership, status, open issues, log volume, cost, and related log events. Grouped log patterns with service, severity, event rate, volume, cost, policies, and issues. Tero also presents catalog-backed lanes: * **Cost** shows service-level log cost and recoverable savings. * **Compliance** shows affected services, exposed fields, and affected log events. * **Checks** shows detector inventory and related issues. * **Log ingestion** shows Datadog ingestion analysis, index breakdown, migration candidates, and projected savings. ## How catalog context helps review Before approving a policy you need the owning service, the affected log event pattern, the volume and cost involved, the issue or check that produced the recommendation, and any policy or runtime state that already exists. The catalog supplies those facts across Tero. Issues use catalog context to explain findings, and policies link back to issues and services. Edge instances and provider surfaces show whether approved policies run. ## Metrics and traces Tero is telemetry control, but these docs cover the log-oriented surfaces: services, log events, checks, issues, policies, log ingestion, cost, compliance, and Edge runtime state. Use the Metrics or Trace Spans pages only when your Tero account exposes those surfaces. ## Related pages * [Services](/master-catalog/services) * [Log events](/master-catalog/log-events) * [Issues](/issues/overview) * [Policies](/policies) # Services Source: https://docs.usetero.com/master-catalog/services Service catalog context for issues and policies The Services catalog shows the owner, open issues, log volume, and cost for each service's telemetry. The Services list shows the owner, open issues, log volume, and cost for each service.

The Services list shows the owner, open issues, log volume, and cost for each service. Open in demo

## Service list The Services list can show these fields: | Field | Description | | ----------- | --------------------------------------------------------------------------------- | | Service | Service name and enabled state. | | Team | Owning team when Tero has ownership data. | | Open issues | Count of open issues for the service, including high-severity count when present. | | Log volume | Observed log volume for the service. | | Cost | Estimated annualized log cost. | ## Service detail Service detail pages show the service in context. Current detail tabs include overview, issues, log events, and log volume. | Detail area | Description | | ----------- | ------------------------------------------------------ | | Overview | Service state, ownership context, and summary metrics. | | Issues | Open and related issues for the service. | | Log events | Log events emitted by the service. | | Log volume | Observed log volume over time. | ## Relationship to issues and policies Issues often point to an affected service. Policies can also show the service they affect. That connection lets you send reviews to service owners instead of routing all approvals through the platform team. ## Related pages * [Issues](/issues/overview) * [Log events](/master-catalog/log-events) * [Policies](/policies) # Accidental debug statements Source: https://docs.usetero.com/policies/categories/accidental-debug-statements Temporary debugging output that shipped to production Accidental debug statements are developer-authored messages that do not describe application behavior, system state, or user activity. Examples include `console.log("here")`, `print("debug")`, and `logger.info("asdf")`. Tero classifies by message content; these statements appear at `DEBUG`, `INFO`, or any other severity level. ## Signals * Placeholder messages such as `got here`, `hello world`, `testing`, or `asdf`. * Explicit cleanup notes such as `TODO remove`. * Bare variable dumps such as `x = 42`. * Profanity or informal phrases used as temporary debugging markers. * Messages with no stable operational meaning. ## Example ```json theme={null} { "@timestamp": "2024-01-15T10:30:00Z", "service.name": "checkout-api", "severity_text": "DEBUG", "body": "got here" } ``` Dropped. Tero generates a policy to drop this specific log event: ```yaml theme={null} id: drop-debug-got-here-checkout-api name: Drop got-here debug log from checkout-api description: Accidental debug statement that shipped to production. log: match: - resource_attribute: service.name exact: checkout-api - log_field: body exact: "got here" keep: none ``` ## Recommended enforcement Remove accidental debug statements from the codebase. Fix this at the source: the statement should not exist in production code. ## Detection notes * Tero evaluates message content rather than severity. * Tero flags common debug phrases, random character strings, cleanup notes, and bare variable dumps. * Detection is conservative for this category: Tero flags only logs that are clear accidents. * Tero excludes legitimate verbose logging when the message has operational meaning. # Bot traffic Source: https://docs.usetero.com/policies/categories/bot-traffic Log events where bot filtering is possible Bot traffic is non-user request activity generated by automated clients. Common sources include search engine crawlers, SEO tools, social preview fetchers, link unfurlers, uptime monitors, and security scanners. Tero identifies bot traffic when log events contain a user-agent field that can be matched against known or customer-defined bot patterns. ## Signals | Signal | Description | | -------------- | ------------------------------------------------------------------------------------------- | | User agent | `http.user_agent` or an equivalent field contains a known bot identifier. | | Request path | Bot activity often targets public pages, sitemap files, robots.txt, or common scan paths. | | Request rate | Automated clients can generate repeated requests from the same source or user-agent family. | | Correlation ID | A `request_id` or `trace_id` can connect the entry-point request to downstream logs. | ## Example ```json theme={null} { "@timestamp": "2024-01-15T10:30:00Z", "service.name": "marketing-site", "http.method": "GET", "http.target": "/pricing", "http.status_code": 200, "http.user_agent": "Mozilla/5.0 (compatible; Googlebot/2.1)" } ``` Dropped. ```yaml theme={null} id: drop-bot-traffic-marketing-site name: Drop bot traffic from marketing-site description: Drop requests from known crawlers and scrapers. log: match: - resource_attribute: service.name exact: marketing-site - log_attribute: http.user_agent regex: "(Googlebot|bingbot|Slackbot|AhrefsBot|facebookexternalhit)" keep: none ``` ```json theme={null} // Entry point - has user-agent {"service.name": "api-gateway", "request_id": "req_abc123", "http.user_agent": "Googlebot/2.1", "path": "/products"} // Downstream - no user-agent, same request_id {"service.name": "product-service", "request_id": "req_abc123", "event": "fetch_products"} {"service.name": "cache-service", "request_id": "req_abc123", "event": "cache_miss"} {"service.name": "database", "request_id": "req_abc123", "event": "query_executed"} ``` All four logs dropped. Tero identifies the bot at the entry point and drops each log sharing that `request_id`. ```yaml theme={null} id: drop-bot-traffic-correlated name: Drop bot traffic with correlated logs description: Drop entire request trace when entry point is identified as bot traffic. log: match: - log_attribute: http.user_agent regex: "(Googlebot|bingbot|Slackbot|AhrefsBot)" correlation: field: request_id keep: none ``` ## Recommended enforcement Drop bot traffic logs before they reach the destination provider. Use edge enforcement when the pattern describes automated external traffic and you don't need those logs in the provider. ## Detection notes * Tero identifies candidate events that contain a user-agent field. * Bots often self-identify with values such as `Googlebot`, `bingbot`, `Slackbot`, and `AhrefsBot`. * Customers decide which bot identifiers to filter. * When you configure correlation and the field is present, Tero policies can apply the entry-point decision to related downstream logs. # Burst protection Source: https://docs.usetero.com/policies/categories/burst-protection Circuit breakers for logs that surge during failures Burst protection applies to infrastructure symptoms that can repeat for every affected request when a dependency fails. Examples include database timeouts, connection failures, and TLS failures. These policies guard the log pipeline during failures. Tero excludes business events because user activity bounds their volume. ## Signals | Signal | Description | | ------------------------ | --------------------------------------------------------------------------------------------- | | Failure amplification | One dependency failure can cause many requests to emit the same error. | | Infrastructure symptom | The event describes timeout, refused connection, DNS, TLS, or similar infrastructure failure. | | Unbounded repeatability | The event can repeat as fast as traffic reaches the failing path. | | Low per-event uniqueness | Repeated events contain the same failure shape with limited distinguishing context. | ## Example ```json theme={null} { "severity_text": "ERROR", "body": "Connection to postgres failed: timeout", "service.name": "order-service", "database": "products" } ``` ```yaml theme={null} id: burst-protection-postgres-timeout-order-service name: Burst protection for postgres timeout in order-service description: Rate limit infrastructure errors that flood during outages. log: match: - resource_attribute: service.name exact: order-service - log_field: body regex: "^Connection to postgres failed" rate_limit: 100/s ``` ```json theme={null} { "severity_text": "ERROR", "body": "Payment declined", "service.name": "checkout-service", "user_id": "usr_123", "error": "card_expired" } ``` ## Recommended enforcement Rate limit matching infrastructure failures before they leave your infrastructure. Use edge enforcement: the point is protecting the pipeline during failures. ## Detection notes Tero analyzes each log event for burst risk: whether a failure could cause the event to repeat at high volume. For events at risk of bursting, Tero can generate a scoped rate-limit policy. Tero scopes burst protection to each event shape. It applies circuit breakers to infrastructure symptoms and routes unrelated business events through their normal policy path. # Debug mode left on Source: https://docs.usetero.com/policies/categories/debug-mode-left-on Verbose logging enabled for troubleshooting and left on A debug-mode policy category applies when a production service emits DEBUG-level logs for longer than an expected investigation window. This is a service configuration issue: log levels come from environment variables or configuration files, and those changes may not follow the same review path as application code. ## Signals | Signal | Description | | ----------------------- | ------------------------------------------------------------------------------------------------------ | | Persistent DEBUG volume | A service emits DEBUG logs beyond the configured threshold. | | Sudden level change | DEBUG volume jumps from the service's previous baseline. | | Service-scoped pattern | The pattern is evaluated at service level rather than per individual log event. | | Production environment | The logs come from production or another environment where persistent DEBUG logging signals a problem. | ## Example ```json theme={null} {"severity_text": "DEBUG", "body": "Entering getUserById", "service.name": "user-service"} {"severity_text": "DEBUG", "body": "Cache miss for user 12345", "service.name": "user-service"} {"severity_text": "DEBUG", "body": "Querying database", "service.name": "user-service"} {"severity_text": "DEBUG", "body": "Query took 3ms", "service.name": "user-service"} {"severity_text": "DEBUG", "body": "Exiting getUserById", "service.name": "user-service"} ``` Log level set back to INFO. Only meaningful events logged. ## Recommended enforcement Notify the service owner that DEBUG logging is still active. Change the log level when service configuration is managed as code. Apply temporary volume control when you can't change the configuration right away. The preferred remediation is a configuration change at the source. Edge enforcement is a temporary control for persistent high-volume DEBUG output. ## Detection notes Tero detects this category from service-level log patterns: a sudden increase in DEBUG logs that persists beyond a configured threshold. DEBUG logs during an active incident are expected. DEBUG logs that continue for days mean someone forgot to revert the configuration. # Duplicate fields Source: https://docs.usetero.com/policies/categories/duplicate-fields The same field stored in multiple locations Duplicate fields occur when multiple fields in a log record carry the same information. Common sources include: | Duplicate pair | Common source | | --------------------------- | ------------------------------------------------ | | `time` and `@timestamp` | Application timestamp plus collector timestamp | | `level` and `severity_text` | Application severity plus OpenTelemetry severity | | `host` and `hostname` | Service field plus agent field | Duplicate fields require either repeated field names or clear semantic equivalents such as `level` and `severity`. Fields with matching values but different meanings are not duplicates. ## Signals * Repeated values across timestamp, severity, host, service, or environment fields. * Field pairs with equivalent names from different parts of the telemetry pipeline. * Redundant fields added by SDKs, agents, collectors, or exporters. * A canonical field that can preserve the value after the duplicate field is removed. ## Example The following log has three duplicate pairs that carry the same values under different names: `time` and `@timestamp`, `level` and `severity_text`, `host` and `hostname`. ```json theme={null} { "time": "2024-01-15T10:30:00Z", "@timestamp": "2024-01-15T10:30:00Z", "level": "ERROR", "severity_text": "ERROR", "host": "checkout-api-7d8f9", "hostname": "checkout-api-7d8f9", "message": "Connection timeout" } ``` ```json theme={null} { "@timestamp": "2024-01-15T10:30:00Z", "severity_text": "ERROR", "hostname": "checkout-api-7d8f9", "message": "Connection timeout" } ``` Tero generates a scoped policy: ```yaml theme={null} id: remove-duplicate-fields-checkout-api name: Remove duplicate fields from checkout-api description: Drop duplicate fields that contain the same data as their canonical equivalents. log: match: - resource_attribute: service.name exact: checkout-api transform: remove: - log_attribute: time - log_attribute: level - log_attribute: host ``` ## Recommended enforcement Drop duplicate fields before data leaves your network. Use edge enforcement when duplicate fields come from agents, collectors, SDKs, or exporters rather than application code. ## Detection notes * Tero compares field values across logs. * Tero flags exact string matches when the fields represent the same concept. * It flags semantic equivalents when the values share a normalized meaning, such as a numeric severity and a text severity. * Fields with similar values but different meanings are not duplicates. For example, `request_id` and `trace_id` are related identifiers, not duplicate fields. * Fields with different representations are not duplicates unless they normalize to the same value. For example, UTC and local timestamps are different representations. Tero keeps the more standard field, such as `@timestamp` or `severity_text`, and removes the duplicate. # Excessive payloads Source: https://docs.usetero.com/policies/categories/excessive-payloads Response bodies, large objects, and data blobs in logs An excessive payload is a large value embedded in a log event, such as a full HTTP response body, serialized object, data blob, or oversized stack trace. These fields increase event size. In many cases, the log keeps its operational meaning after a policy removes the large field. ## Signals | Signal | Description | | ------------------------------ | ----------------------------------------------------------------------- | | Large field size | A single field contributes most of the event size. | | Serialized object | The field contains a full object that can be retrieved by ID elsewhere. | | Response or request body | The log includes full HTTP payload content. | | Repeated oversized stack trace | Many events contain the same long stack trace or traceback. | ## Example ```json theme={null} { "@timestamp": "2024-01-15T10:30:00Z", "service.name": "order-service", "event": "order.created", "order_id": "ORD-12345", "http.response.body": "{\"id\":\"ORD-12345\",\"items\":[{\"sku\":\"SKU-001\",\"name\":\"Widget Pro\",\"quantity\":2,\"price\":29.99},{\"sku\":\"SKU-002\",\"name\":\"Gadget Plus\",\"quantity\":1,\"price\":49.99}],\"shipping\":{\"method\":\"express\",\"address\":{\"street\":\"123 Main St\",\"city\":\"Seattle\",\"state\":\"WA\",\"zip\":\"98101\",\"country\":\"US\"}},\"billing\":{\"method\":\"card\",\"last4\":\"4242\"},\"totals\":{\"subtotal\":109.97,\"shipping\":12.99,\"tax\":10.45,\"total\":133.41}}" } ``` ```json theme={null} { "@timestamp": "2024-01-15T10:30:00Z", "service.name": "order-service", "event": "order.created", "order_id": "ORD-12345" } ``` ```yaml theme={null} id: remove-response-body-order-service name: Remove response body from order-service description: Drop full HTTP response body. The order_id is sufficient for lookup. log: match: - resource_attribute: service.name exact: order-service - log_attribute: event exact: order.created transform: remove: - log_attribute: http.response.body ``` ```json theme={null} { "@timestamp": "2024-01-15T10:30:00Z", "service.name": "api-service", "severity_text": "ERROR", "error.message": "Connection refused", "error.stack_trace": "Error: Connection refused\n at Socket.connect (net.js:1141:16)\n at DBClient.connect (db.js:89:12)\n ... 200 more lines ..." } ``` ```json theme={null} { "@timestamp": "2024-01-15T10:30:00Z", "service.name": "api-service", "severity_text": "ERROR", "error.message": "Connection refused" } ``` If the full stack trace is available in a tracing backend, the log event can keep the error message without keeping a duplicate stack trace. ## Recommended enforcement Change the source instrumentation when the large field comes from application logging. Use open PR enforcement when application code added the payload and a developer needs to decide which fields stay. ## Detection notes * Tero flags fields that are large relative to routine log events for the same service or pattern. * Common candidates include full HTTP bodies, entire serialized objects, and long stack traces. * Policies can remove a single large field while preserving the rest of the event. * A source change is preferable when the log statement should stop emitting the payload. # Health checks Source: https://docs.usetero.com/policies/categories/health-checks Readiness probes, liveness probes, synthetic monitoring Health check logs come from readiness probes, liveness probes, load balancers, and synthetic monitors. They represent infrastructure availability checks, not user traffic. Successful health checks confirm a known service state. Failed health checks can have diagnostic value and are not part of the default drop pattern. ## Signals * Request paths such as `/health`, `/ready`, `/live`, `/ping`, or `/healthz`. * Probe user agents such as `kube-probe` or `ELB-HealthChecker`. * Successful status codes such as `200`. * Repeated requests at a fixed interval. * Requests generated by infrastructure rather than end users. ## Example ```json theme={null} { "@timestamp": "2024-01-15T10:30:00Z", "service.name": "checkout-api", "http.method": "GET", "http.target": "/health", "http.status_code": 200, "http.user_agent": "kube-probe/1.28" } ``` Dropped. Tero generates a scoped policy for each service where this pattern exists: ```yaml theme={null} id: drop-health-checks-checkout-api name: Drop health check logs from checkout-api description: Drop Kubernetes probe requests to health endpoints. log: match: - resource_attribute: service.name exact: checkout-api - log_attribute: http.target regex: "^/(health|ready|live|ping)" - log_attribute: http.status_code exact: "200" keep: none ``` ## Recommended enforcement Drop successful health check logs before they reach your provider. Use edge enforcement: infrastructure systems like Kubernetes, load balancers, and synthetic monitors generate these logs. ## Detection notes * Tero identifies health check logs by request path, user agent, and status code. * Tero drops successful probes and keeps failed ones; they can show when a service became unhealthy. * Scope path matching to health endpoints so the policy doesn't drop normal user traffic. # High cardinality tags Source: https://docs.usetero.com/policies/categories/high-cardinality-tags Metric tags with unbounded values that create many time series A high-cardinality tag is a metric label or tag whose values can grow without a small fixed set. Common examples include `user_id`, `request_id`, `session_id`, `trace_id`, `ip_address`, full URLs, timestamps, and raw error messages. Each unique tag value creates a separate time series for the metric. A `user_id` tag on a latency metric creates one time series per user for each metric and dimension combination. ## Signals | Signal | Description | | ------------------------------ | ---------------------------------------------------------------------------------------- | | Unbounded value set | The tag can contain thousands or millions of distinct values. | | Per-request or per-user values | The tag contains identifiers such as users, sessions, requests, traces, or IP addresses. | | Sparse series | Many generated time series have little data per series. | | Limited query value | The tag is not used in dashboards, alerts, or common queries. | ## Example ``` http_request_duration_seconds{service="api", endpoint="/users", user_id="usr_abc123"} 0.045 http_request_duration_seconds{service="api", endpoint="/users", user_id="usr_def456"} 0.052 http_request_duration_seconds{service="api", endpoint="/users", user_id="usr_ghi789"} 0.038 ``` ``` http_request_duration_seconds{service="api", endpoint="/users"} 0.045 ``` ```yaml theme={null} id: remove-user-id-tag name: Remove user_id tag from metrics description: Drop high-cardinality user_id tag. Creates millions of sparse time series. metric: match: - tag: user_id exists: true transform: remove_tags: - user_id ``` ## Recommended enforcement Strip the tag before metrics reach your provider. Remove the tag from instrumentation code. The durable remediation is removing the tag from instrumentation. Edge enforcement can remove the tag before metrics reach the provider when you can't change instrumentation right away. ## Detection notes For accounts with metric policy context, Tero analyzes tag cardinality across metrics. It flags tags with thousands or more unique values. Tero can also check whether these tags are used in queries or dashboards. A tag with many unique values and no query usage is a candidate for removal. # Instrumentation bloat Source: https://docs.usetero.com/policies/categories/instrumentation-bloat SDK and collector metadata with low diagnostic value Instrumentation bloat consists of fields added by SDKs, agents, collectors, and exporters. These fields describe the telemetry tooling rather than the observed system. Some instrumentation fields, such as `service.name`, are operational metadata for system identity and routing. Tooling metadata such as `telemetry.sdk.version`, `otel.library.name`, and collector build strings has low value in logs. ## Signals * Fields that describe SDKs, agents, collectors, exporters, or instrumentation libraries. * Version fields for telemetry tooling. * Internal Kubernetes UIDs when human-readable Kubernetes names are also present. * Fields the telemetry pipeline adds on its own rather than fields from application code. * Fields you query only when debugging the telemetry tooling itself. ## Example ```json theme={null} { "@timestamp": "2024-01-15T10:30:00Z", "severity_text": "ERROR", "service.name": "checkout-api", "telemetry.sdk.name": "opentelemetry", "telemetry.sdk.version": "1.24.0", "telemetry.sdk.language": "python", "message": "Connection timeout" } ``` ```json theme={null} { "@timestamp": "2024-01-15T10:30:00Z", "severity_text": "ERROR", "service.name": "checkout-api", "message": "Connection timeout" } ``` ```yaml theme={null} id: remove-otel-sdk-metadata name: Remove OTel SDK metadata description: Drop OpenTelemetry SDK version info. Only useful when debugging the SDK itself. log: match: - resource_attribute: telemetry.sdk.name exists: true transform: remove: - resource_attribute: telemetry.sdk.name - resource_attribute: telemetry.sdk.version - resource_attribute: telemetry.sdk.language - resource_attribute: telemetry.auto.version ``` ```json theme={null} { "@timestamp": "2024-01-15T10:30:00Z", "severity_text": "ERROR", "service.name": "checkout-api", "k8s.pod.name": "checkout-api-7d8f9", "k8s.pod.uid": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "k8s.deployment.name": "checkout-api", "k8s.deployment.uid": "12345678-abcd-efgh-ijkl-mnopqrstuvwx", "message": "Connection timeout" } ``` ```json theme={null} { "@timestamp": "2024-01-15T10:30:00Z", "severity_text": "ERROR", "service.name": "checkout-api", "k8s.pod.name": "checkout-api-7d8f9", "k8s.deployment.name": "checkout-api", "message": "Connection timeout" } ``` Human-readable Kubernetes names remain available after the policy removes internal UIDs. ```yaml theme={null} id: remove-k8s-uids name: Remove Kubernetes UIDs description: Drop internal Kubernetes identifiers. Names are sufficient for debugging. log: match: - resource_attribute: k8s.pod.uid exists: true transform: remove: - resource_attribute: k8s.pod.uid - resource_attribute: k8s.replicaset.uid - resource_attribute: k8s.deployment.uid - resource_attribute: k8s.statefulset.uid - resource_attribute: k8s.daemonset.uid - resource_attribute: k8s.job.uid - resource_attribute: k8s.cronjob.uid ``` ## Recommended enforcement Remove low-value instrumentation metadata before data leaves your network. Use edge enforcement when telemetry tooling, not application code, adds the fields. ## Detection notes * Tero maps dependencies and instrumentation metadata to distinguish tooling fields from application fields. * Tero flags fields such as `telemetry.sdk.version` and `otel.library.name` when they come from telemetry tooling. * It does not classify system identity fields such as `service.name` as instrumentation bloat. * Tero removes Kubernetes UID fields when it keeps the human-readable names. # Logs in hot path Source: https://docs.usetero.com/policies/categories/logs-in-hot-path Log statements in middleware, loops, or high-frequency code Code that runs on most requests or records emits hot-path logs without conditions. Common sources include request middleware, item-processing loops, and polling loops. This category is distinct from [burst protection](/policies/categories/burst-protection). Burst protection applies to logs that flood during failures. Hot-path logs produce high volume even when the service is healthy. ## Signals | Signal | Description | | ----------------------- | -------------------------------------------------------------------------------------------------------------------- | | Disproportionate volume | One event shape represents a large share of a service's logs. | | Generic message text | Messages such as `Incoming request`, `Processing item`, or `Handling request` repeat with little diagnostic context. | | Unconditional emission | The log appears on every request, item, or loop iteration. | | Healthy-state volume | The pattern occurs during normal service operation, not only during incidents. | ## Example ```json theme={null} {"body": "Incoming request", "http.target": "/api/users", "service.name": "api-gateway"} {"body": "Incoming request", "http.target": "/api/orders", "service.name": "api-gateway"} {"body": "Incoming request", "http.target": "/api/products", "service.name": "api-gateway"} {"body": "Incoming request", "http.target": "/api/users", "service.name": "api-gateway"} ``` Log removed from middleware. ```json theme={null} {"body": "Processing item", "item_id": "1", "service.name": "batch-processor"} {"body": "Processing item", "item_id": "2", "service.name": "batch-processor"} {"body": "Processing item", "item_id": "3", "service.name": "batch-processor"} // ... 10,000 more ``` Single log at batch completion with item count. ## Recommended enforcement Remove, relocate, or condition the log statement in code. Ask the owning team to review the high-volume logging pattern. The durable remediation is a code change. Edge filtering can reduce downstream volume, but the service still performs the work required to create the log event. ## Detection notes Tero identifies hot-path logs by relative volume. If one event shape represents a disproportionate share of a service's logs, Tero treats the event as a hot-path candidate. Message content can support detection. Generic messages such as `Processing request` or `Handling item` often indicate unconditional logging, but volume is the primary signal. # Malformed data Source: https://docs.usetero.com/policies/categories/malformed-data Binary blobs, corrupted output, unparseable logs Malformed data includes binary payloads, corrupted output, truncated structured data, and strings that cannot be parsed in the expected format. Typical causes include: * Binary protocols or files routed into a text log pipeline * Application crashes or buffer limits that truncate structured output * Encoding mismatches that produce invalid characters * Partial serialization of JSON or other structured formats ## Signals | Signal | Description | | ---------------- | ---------------------------------------------------------------------------------- | | Binary prefix | A log body starts with a file signature or non-text bytes, such as a PNG header. | | Parser failure | A field expected to contain JSON, XML, or another structured format fails parsing. | | Truncation | A structured value ends before required delimiters, quotes, or braces. | | Invalid encoding | The payload contains characters that cannot be decoded in the expected encoding. | ## Example ```json theme={null} { "@timestamp": "2024-01-15T10:30:00Z", "service.name": "image-processor", "body": "\u0089PNG\r\n\u001a\n\u0000\u0000\u0000\rIHDR..." } ``` Dropped. ```yaml theme={null} id: drop-binary-data-image-processor name: Drop binary data from image-processor description: PNG image data routed to log pipeline. Not parseable, not queryable. log: match: - resource_attribute: service.name exact: image-processor - log_field: body regex: "^\\x89PNG\\r\\n" keep: none ``` ```json theme={null} { "@timestamp": "2024-01-15T10:30:00Z", "service.name": "api-service", "body": "{\"user_id\": \"usr_123\", \"event\": \"login\", \"metadata\": {\"ip\":" } ``` Dropped. ```yaml theme={null} id: drop-truncated-json-api-service name: Drop truncated JSON from api-service description: Incomplete JSON from buffer overflow or crash. Unparseable. log: match: - resource_attribute: service.name exact: api-service - log_field: body malformed: json keep: none ``` ## Recommended enforcement Drop malformed log events before they reach the destination provider. Tero removes malformed events whole because their fields fail parsing. ## Detection notes * Tero can match explicit binary signatures with regular expressions. * Tero can match fields that fail the expected parser, such as malformed JSON. * Scope malformed-data policies to the emitting service or field when the pattern is specific. * Dropping malformed events preserves valid error, warning, and diagnostic logs that are parseable. # Policy categories Source: https://docs.usetero.com/policies/categories/overview Telemetry issue categories that can produce policy recommendations Tero groups telemetry issues into the categories below. Each category can produce policy recommendations. | Category | Signal | Typical action | | ------------------------------------------------------------------------------- | --------------------------------------------------------------------- | --------------------------------------------------------------- | | [Duplicate fields](/policies/categories/duplicate-fields) | The same value appears in multiple fields. | Remove duplicate fields. | | [Accidental debug statements](/policies/categories/accidental-debug-statements) | Temporary debugging messages shipped to production. | Remove the statement in code or drop the matching event. | | [Malformed data](/policies/categories/malformed-data) | Binary, corrupted, or unparseable log payloads. | Drop malformed events. | | [Health checks](/policies/categories/health-checks) | Successful readiness, liveness, or synthetic monitor requests. | Drop successful probe logs. | | [Bot traffic](/policies/categories/bot-traffic) | Requests from known crawlers, scanners, and unfurlers. | Drop or sample matching bot request logs. | | [Instrumentation bloat](/policies/categories/instrumentation-bloat) | SDK, agent, collector, or platform metadata with little review value. | Remove low-value fields. | | [PII leakage](/policies/categories/pii-leakage) | Sensitive values in log fields or free-form messages. | Redact or remove sensitive values. | | [Excessive payloads](/policies/categories/excessive-payloads) | Large bodies, serialized objects, or oversized stack traces. | Trim or remove large fields. | | [Debug mode left on](/policies/categories/debug-mode-left-on) | A service emits prolonged DEBUG-level volume in production. | Create a ticket, open a config PR, or apply a temporary filter. | | [Logs in hot path](/policies/categories/logs-in-hot-path) | One event dominates a service's steady-state log volume. | Remove or relocate the log statement. | | [Burst protection](/policies/categories/burst-protection) | Infrastructure error events can flood during outages. | Rate-limit the matching event. | | [High cardinality tags](/policies/categories/high-cardinality-tags) | Metric tags have unbounded or fast-changing values. | Remove high-cardinality tags. | Use [Policy lifecycle](/policies/lifecycle) for policy states and [Enforcement](/policies/enforcement/overview) for enforcement methods. # PII leakage Source: https://docs.usetero.com/policies/categories/pii-leakage Sensitive data that ended up in logs PII leakage occurs when logs contain personal data, credentials, secrets, payment data, or other sensitive values that don't belong in observability storage. Common sources include request-object logging, error messages that include user input, verbose third-party libraries, and instrumentation that records more fields than intended. ## Signals | Signal | Description | | ------------------------- | ------------------------------------------------------------------------------------------------------------------- | | Sensitive field name | Field names such as `card_number`, `email`, `ssn`, `api_key`, or `token`. | | Sensitive value pattern | Values match known formats for payment cards, secrets, credentials, or identifiers. | | Free-form message content | A text field contains sensitive substrings inside an otherwise routine message. | | High-risk field type | Request bodies, error messages, user input, and metadata fields can contain sensitive data through developer error. | ## Example ```json theme={null} { "@timestamp": "2024-01-15T10:30:00Z", "service.name": "payment-service", "event": "payment.processed", "card_number": "4111111111111111", "amount": 99.99 } ``` ```json theme={null} { "@timestamp": "2024-01-15T10:30:00Z", "service.name": "payment-service", "event": "payment.processed", "amount": 99.99 } ``` ```yaml theme={null} id: redact-credit-card-payment-service name: Redact credit card numbers from payment-service description: Remove card_number field containing credit card data. log: match: - resource_attribute: service.name exact: payment-service - log_attribute: card_number regex: "^[0-9]{13,19}$" transform: remove: - log_attribute: card_number ``` ```json theme={null} { "@timestamp": "2024-01-15T10:30:00Z", "service.name": "user-service", "event": "user.updated", "user_id": "usr_abc123", "email": "alice@example.com" } ``` ```json theme={null} { "@timestamp": "2024-01-15T10:30:00Z", "service.name": "user-service", "event": "user.updated", "user_id": "usr_abc123" } ``` ```yaml theme={null} id: redact-email-user-service name: Redact email addresses from user-service description: Remove email field containing user email addresses. log: match: - resource_attribute: service.name exact: user-service - log_attribute: email exists: true transform: remove: - log_attribute: email ``` ```json theme={null} { "@timestamp": "2024-01-15T10:30:00Z", "service.name": "integration-service", "body": "Request failed with key sk_live_abc123xyz789..." } ``` ```json theme={null} { "@timestamp": "2024-01-15T10:30:00Z", "service.name": "integration-service", "body": "Request failed with key [REDACTED]" } ``` ```yaml theme={null} id: redact-api-key-integration-service name: Redact API keys from integration-service logs description: Redact Stripe API keys found in log messages. log: match: - resource_attribute: service.name exact: integration-service - log_field: body regex: "sk_live_[a-zA-Z0-9]+" transform: redact: - log_field: body pattern: "sk_live_[a-zA-Z0-9]+" replacement: "[REDACTED]" ``` ## Recommended enforcement Redact or remove sensitive values before data leaves your network. Change source instrumentation so sensitive values are not logged. Use edge enforcement to stop matched values from reaching the provider. Open a PR when the source statement should stop emitting the field. Tero creates one policy per PII pattern, and you approve each on its own. ## Detection notes Tero uses the [Master Catalog](/master-catalog) to understand fields, including what each field represents, what values it contains, and why it exists. Tero uses that context to determine which fields are scanned for PII. Tero scans fields that can carry PII through developer error, including `error_message`, `request_body`, `user_input`, and free-form text fields. It skips fields with fixed formats that are structurally incompatible with PII, such as `timestamp`, `severity`, `status_code`, and `pid`. Tero detects PII using patterns from [gitleaks](https://github.com/gitleaks/gitleaks), an open source project for secret detection. * Credit card numbers (Visa, Mastercard, Amex, Discover) * Social Security numbers (US) * National Insurance numbers (UK) * Email addresses * Phone numbers * IP addresses * IBANs * AWS access keys and secret keys * GCP API keys * Azure AD client secrets * Alibaba access keys * DigitalOcean tokens * Heroku API keys * Cloudflare API keys * Databricks API tokens * GitHub tokens (PAT, OAuth, App, Fine-grained) * GitLab tokens (PAT, Deploy, Runner, CI/CD job) * Bitbucket client secrets * Travis CI tokens * CircleCI tokens * Drone CI tokens * Slack tokens (bot, user, webhook) * Discord tokens * Telegram bot tokens * Microsoft Teams webhooks * Mattermost tokens * Twilio API keys * Database connection strings * Planetscale tokens * MongoDB connection strings * Redis connection strings * Elasticsearch credentials * Stripe API keys * Square access tokens * Plaid API tokens * Coinbase access tokens * GoCardless tokens * OpenAI API keys * Anthropic API keys * Hugging Face tokens * Cohere API tokens * Datadog access tokens * New Relic API keys * Grafana API keys * Sentry tokens * Dynatrace API tokens * Notion API tokens * Asana client secrets * Linear API keys * Jira API tokens * Shopify access tokens * SendGrid API tokens * Mailchimp API keys * Private keys (RSA, DSA, EC, PGP) * JWTs * PKCS12 files * Age secret keys # Create tickets Source: https://docs.usetero.com/policies/enforcement/create-tickets Assign work to engineers in Linear or GitHub Issues Variable Create a ticket and assign it to the right team. The engineer investigates, decides on the fix, and resolves it on their schedule. Use this when humans need to make decisions, the fix requires context you don't have, or you want to delegate without prescribing the solution. ## How it works Tero creates a ticket in your issue tracker with the affected service, evidence, cost impact, and suggested next steps. Tero assigns the ticket using service ownership from your [Master Catalog](/master-catalog/services). ## Setup Connect your issue tracker: Connect Linear to create issues in the right team's backlog. Create issues in the repository that owns the service. ## Example Tero identifies that `user-service` has debug mode enabled. It's been emitting DEBUG-level logs for 3 days, generating 10x normal volume. You approve the policy and select "Create tickets." Tero creates a ticket in Linear: ``` Title: Debug mode left on in user-service user-service has been emitting DEBUG logs for 3 days. This is generating 10x normal log volume (~$2,400/day in excess costs). Debug logging was likely enabled for troubleshooting and not disabled afterward. Action needed: - Verify debug mode should be off - Update the log level configuration - Consider adding alerts for prolonged debug mode Identified by Tero: https://app.tero.dev/policies/abc123 ``` Tero assigns the ticket to the user-service team from your Master Catalog. They investigate, change the configuration, and close the ticket. ## When to use Create tickets works best when: * The fix requires human judgment (is this intentional?) * Multiple solutions exist and the team should choose * You want the work tracked in your backlog * The issue can wait for a normal engineering workflow # Enforce at edge Source: https://docs.usetero.com/policies/enforcement/edge Execute policies before data leaves your network Next sync Reversible Drop, sample, or transform telemetry before it leaves your infrastructure, without changing application code or provider configuration. This is the most common enforcement method. Most [policy categories](/policies/categories) recommend it. ## How it works [Tero Edge](/edge) runs in your infrastructure as a proxy. It syncs with the Tero control plane on a fixed interval to fetch policies and applies them to matching telemetry as it passes through. ```mermaid theme={null} flowchart LR Apps["Applications and agents"] -->|"telemetry"| Edge["Tero Edge"] Control["Tero control plane"] -. "policy sync" .-> Edge Edge -->|"kept and transformed telemetry"| Provider["Observability provider"] Edge -. "drop, sample, redact" .-> Filtered["Filtered telemetry"] style Apps fill:#262626,stroke:#262626,color:#fafafa style Edge fill:#00855c,stroke:#006b49,color:#fafafa style Control fill:#0e2b22,stroke:#0e2b22,color:#fafafa style Provider fill:#262626,stroke:#262626,color:#fafafa style Filtered fill:#d1fae5,stroke:#10b981,color:#065f46 ``` ## Setup Deploy the proxy alongside your existing telemetry pipeline: Deploy alongside the Datadog Agent on Kubernetes. Deploy alongside the OTel Collector. ## Example Tero identifies that `checkout-api` is emitting 2.3 million health check logs per day. Kubernetes probes hit `/health` every 10 seconds on every pod. Query history shows no recent searches for those logs, and they don't appear in any dashboard or alert. You approve the policy and select "Enforce at edge." The policy: ```yaml theme={null} id: drop-health-checks-checkout-api name: Drop health check logs from checkout-api log: match: - resource_attribute: service.name exact: checkout-api - log_attribute: http.target regex: "^/(health|ready|live)" - log_attribute: http.status_code exact: "200" keep: none ``` On the next policy sync, Edge begins dropping logs that match: requests to `checkout-api` on health check paths with status code `200`. Failed health checks (non-200) still flow through since those have debugging value. In your data quality dashboard, the `checkout-api` health check volume drops after Edge reports filtered telemetry. If something goes wrong, disable the policy and Edge removes it on the next sync. Logs flow normally again. ## When to use Enforce at edge works best when: * You want impact on the next Edge sync without code changes * The waste is infrastructure noise (health checks, bot traffic, tool metadata) * You need to reduce costs while planning a permanent fix * You want a temporary block you can revert on a later sync # Notify Source: https://docs.usetero.com/policies/enforcement/notify Alert teams in Slack or email Variable Send a notification to the right team. The team learns about the issue without anyone creating tracked work, then decides whether to act. Good for low-priority issues or when you want human confirmation before acting. ## How it works Tero sends a message to Slack or email with context about the issue. The notification includes what Tero found, the impact, and a link to take action in Tero. ## Setup Connect your notification channel: Send notifications to channels or DMs based on service ownership. ## Example Tero identifies that `payment-service` is logging full request payloads including credit card data (masked, but still present). You approve the policy and select "Notify." Tero sends a Slack message to #payments-team: ``` Tero identified an issue in payment-service payment-service is logging full request payloads (~15KB per log). This generates 2.1M logs/day at $3,200/day in costs. The payloads contain masked credit card data. While masked, this may still be a compliance concern. → Review in Tero: https://app.tero.dev/policies/abc123 ``` The team sees the message, investigates, and decides how to respond. They might open a PR, create a ticket, or dismiss if it's intentional. ## When to use Notify works best when: * You want awareness without formal tracking * The issue is low priority * You want human confirmation before automated action * Multiple people should see it but one person will own the response # Open PRs Source: https://docs.usetero.com/policies/enforcement/open-prs Fix instrumentation at the source with pull requests Variable Reversible Fix the problem at the source. Tero opens a pull request to remove or modify the instrumentation that's generating waste. Your team reviews and merges. Use this for code-level issues like accidental debug statements, excessive payloads, or logs in hot paths. The application stops generating the waste, so nothing needs filtering downstream. ## How it works Tero analyzes your codebase to find the instrumentation generating the waste. It creates a branch, makes the change, and opens a pull request. Your team reviews the PR like any other code change. ```mermaid theme={null} flowchart LR Issue["Issue and evidence"] --> Change["Code change"] Change --> Branch["Tero branch"] Branch --> PR["Pull request"] PR --> Review["Team review"] Review --> Deploy["Merge and deploy"] Deploy --> Impact["Waste stops at source"] style Issue fill:#0e2b22,stroke:#0e2b22,color:#fafafa style Change fill:#00855c,stroke:#006b49,color:#fafafa style Branch fill:#262626,stroke:#262626,color:#fafafa style PR fill:#262626,stroke:#262626,color:#fafafa style Review fill:#262626,stroke:#262626,color:#fafafa style Deploy fill:#262626,stroke:#262626,color:#fafafa style Impact fill:#d1fae5,stroke:#10b981,color:#065f46 ``` ## Setup Connect your source control: Install the Tero GitHub App to enable pull requests. ## Example Tero identifies a debug log statement in `checkout-api` that shipped to production. The log says `"got here lol"` and fires 50,000 times per day. You approve the policy and select "Open PRs." Tero locates the log statement in your codebase: ```python theme={null} # src/checkout/service.py, line 142 def process_order(order): logger.debug("got here lol") # <-- Tero removes this line ... ``` Tero opens a pull request: ``` Title: Remove debug log from checkout-api This debug statement shipped to production and generates 50,000 logs/day. It doesn't appear in any dashboard or alert. Identified by Tero: https://app.tero.dev/policies/abc123 ``` Your team reviews the PR. Once they merge and deploy, the application stops generating those logs. ## When to use Open PRs works best when: * The waste is a code mistake (debug logs, forgotten print statements) * The fix is straightforward (remove a line, change a log level) * You want a permanent fix For configuration-based issues (debug mode left on), Tero can also open PRs to change config files if they're in version control. # Enforcement Source: https://docs.usetero.com/policies/enforcement/overview Where and how Tero enforces policies After you approve a policy, choose where Tero enforces it. Some options apply on the next sync or provider API update, while others hand the work to your engineers. Execute policies before data leaves your network. Drop, sample, transform, or redact data. Configure exclusion filters and routing rules through the provider API. Fix instrumentation at the source. Tero opens the PR, your team reviews. Assign work to engineers in Linear or GitHub Issues. Alert teams in Slack or email. Quality targets for teams to meet. Track progress over time. ## Choose an enforcement method | Method | Resolution | Reversible | Best for | | ----------------------------------------------------------------------------- | ---------------------------------------- | -------------------------------------------- | ---------------------- | | [Enforce at edge](/policies/enforcement/edge) | Next sync | Reversible | Most policy categories | | [Enforce in provider](/policies/enforcement/provider) | Provider API | Reversible | No Edge deployed | | [Open PRs](/policies/enforcement/open-prs) | Variable | Reversible | Code-level fixes | | [Create tickets](/policies/enforcement/create-tickets) | Variable | N/A | Human decisions needed | | [Notify](/policies/enforcement/notify) | Variable | N/A | Awareness | | [Set SLOs](/policies/enforcement/set-slos) | Ongoing | Reversible | Long-term tracking | Tero recommends an enforcement method for each policy category. You can override, combine, or change later. # Enforce in provider Source: https://docs.usetero.com/policies/enforcement/provider Configure exclusion filters and routing rules via API Provider API Reversible Configure exclusion filters and routing rules directly in your observability provider. Tero uses the provider's API to apply changes, so this path does not require an Edge deployment. Use this when you don't have [Edge](/edge) deployed or want to configure provider-specific features like index routing. ## How it works Tero connects to your provider's API and configures filters, pipelines, or routing rules. The provider applies these rules as data arrives. You don't deploy anything. Tero manages the configuration through the provider API. ```mermaid theme={null} flowchart LR Tero["Tero"] -->|"provider API"| Controls["Filters, pipelines, routing rules"] Controls --> Provider["Observability provider"] Apps["Applications and agents"] -->|"telemetry"| Provider Provider -->|"apply rules as data arrives"| Indexed["Indexed data"] Provider -. "exclude or reroute" .-> Filtered["Filtered telemetry"] style Tero fill:#00855c,stroke:#006b49,color:#fafafa style Controls fill:#0e2b22,stroke:#0e2b22,color:#fafafa style Apps fill:#262626,stroke:#262626,color:#fafafa style Provider fill:#262626,stroke:#262626,color:#fafafa style Indexed fill:#d1fae5,stroke:#10b981,color:#065f46 style Filtered fill:#d1fae5,stroke:#10b981,color:#065f46 ``` For Datadog, Tero configures [exclusion filters](https://docs.datadoghq.com/logs/log_configuration/indexes/#exclusion-filters) and [pipelines](https://docs.datadoghq.com/logs/log_configuration/pipelines/) via the Datadog API. ## Setup Connect Datadog with write access: Connect with Standard role or a custom role with write permissions. ## Example Tero identifies that `checkout-api` is emitting 2.3 million health check logs per day. Query history shows no recent searches for those logs, and they don't appear in any dashboard or alert. You approve the policy and select "Enforce in provider." Tero configures an exclusion filter in Datadog: ``` Filter name: tero-drop-health-checks-checkout-api Query: service:checkout-api http.target:/health* http.status_code:200 ``` Datadog applies the filter and stops indexing matching logs. You still see them in Live Tail (they reach Datadog), but they don't count against your indexed volume. Your data quality dashboard updates as Datadog reports the change. If something goes wrong, disable the policy and Tero removes the exclusion filter. Logs index again. ## When to use Enforce in provider works best when: * You don't have Edge deployed and want savings now * You need provider-specific features like index routing * Egress costs aren't a concern * You want provider-side controls without deploying infrastructure If you need maximum control, egress savings, or sub-millisecond latency, use [Enforce at edge](/policies/enforcement/edge) instead. # Set SLOs Source: https://docs.usetero.com/policies/enforcement/set-slos Quality targets for teams to meet Ongoing Reversible Define quality targets and track progress over time. Teams see their data quality score and work toward the target at their own pace. Use this for long-term improvement rather than same-day fixes. Good for organizational rollouts where you want to set expectations without mandating specific actions. ## How it works Tero defines SLOs in your observability provider that measure data quality metrics. Teams see dashboards tracking their progress. Alerts fire when teams fall below target. ## Setup Connect your provider with SLO support: Tero creates SLOs using Datadog's SLO product. ## Example You want the platform team to reduce waste from health check logs by 90% over the next quarter. You approve the policy and select "Set SLOs." Tero creates an SLO in Datadog: ``` Name: Health check log reduction - platform services Target: 90% reduction in health check log volume Window: 30 days rolling Current: 2.3M logs/day Target: 230K logs/day ``` The platform team sees this SLO in their Datadog dashboard. They decide how to hit the target: maybe they configure their ingress controller to stop logging health checks, or they deploy Edge policies, or they update their Kubernetes probes. Datadog measures progress regardless of method. If the team falls below target, an alert fires. They investigate and adjust. ## When to use Set SLOs works best when: * You want to measure progress over time instead of requiring a same-day fix * Teams should choose their own approach to hit the target * You're rolling out data quality org-wide and want accountability * The issue isn't urgent but should improve over time # Policy lifecycle Source: https://docs.usetero.com/policies/lifecycle Policy states, sources, deployments, imports, and impact This reference lists the policy state and lifecycle fields shown in Tero. ## Policy states | State | Meaning | | ------------ | ------------------------------------------------------------------- | | **Draft** | The policy exists for review or completion. | | **Active** | The policy is enabled where it should run. | | **Disabled** | The policy remains visible but is not intended to affect telemetry. | ## Policy sources Policy source identifies where a policy originated. | Source | Meaning | | ------------------- | ------------------------------------------------------------------------------------------------- | | Tero recommendation | Tero recommended the policy from issue evidence. | | Provider import | Tero created or previewed the policy from provider inventory, such as a Datadog exclusion filter. | | Repository sync | Tero read or wrote the policy through a configured repository workflow. | | Configured workflow | The policy came from another configured review or deployment workflow. | ## Policy detail tabs | Tab | Contents | | --------------- | ----------------------------------------------------------------------------------- | | **Overview** | Policy identity, source, linked issue, hits over time, and activity. | | **Deployments** | Deployment targets and runtime state, including Edge deployment state when present. | | **Spec** | Structured policy definition used by Tero and runtimes. | ## Deployment targets Policies can run through one or more configured targets. | Target | Description | | --------------------------- | -------------------------------------------------------------------------------------- | | Provider configuration | Provider-side controls such as Datadog exclusion filters. | | Edge instances | Tero Edge instances running in your infrastructure. | | Collector or pipeline paths | Collector or pipeline integrations that apply policy before telemetry reaches storage. | | Repository workflows | Policy or instrumentation changes reviewed through code workflows. | ## Datadog import states Datadog filter conversion can show these states: | State | Meaning | | ----------------------- | --------------------------------------------------------------------- | | **Proposal ready** | Tero can preview a policy from the provider filter. | | **Policy active** | The imported or converted policy is active. | | **Policy verified** | Tero verified the policy after import or deployment. | | **Rejected** | A reviewer rejected the proposed conversion. | | **Unsupported** | The provider filter cannot be represented as a supported Tero policy. | | **Sample key required** | Tero needs an additional sample key before conversion. | | **Blocked** | Conversion or import is blocked by missing context or configuration. | ## Impact checks Use these facts when checking whether a policy changed the expected telemetry path: | Check | Expected result | | ------------- | ------------------------------------------------------------------------------ | | Linked issue | The issue moves from **Open** or **In progress** toward **Resolved**. | | Policy state | The policy remains **Active** in the expected deployment target. | | Runtime state | Edge or provider deployment state reports no policy errors. | | Outcome | Cost, compliance exposure, or matching volume moves in the expected direction. | Use [Policies](/policies) for the policy concept and [Enforcement](/policies/enforcement/overview) for enforcement options. # Policies Source: https://docs.usetero.com/policies/overview Reviewable control-plane artifacts Policies are the control-plane artifacts Tero uses to turn issue evidence into runtime action. A policy states which telemetry it matches and what action the runtime should take. Tero presents policies for review with status, source, action, service, recent activity, linked issue, deployment state, and spec. Track the upstream OpenTelemetry specification proposal for telemetry policy. Policies show status, action, source, service, activity, and linked issue.

Policies show status, action, source, service, activity, and linked issue. Open in demo

## How policies relate to issues Tero starts with a finding. The issue explains what Tero found and shows evidence. If a policy can address the issue, Tero presents the recommended policy in issue detail. After approval or deployment, Tero adds the policy to the Policies workspace. You can open the policy to inspect its identity, source, related issue, activity, deployments, and spec. Tero links each policy to the issue that produced it, so reviewers can check the evidence before approving. ## Policy actions Policy actions describe what the runtime should do to matching telemetry. Common actions include dropping a matching event, sampling a subset, redacting sensitive values, rewriting fields, or trimming large payloads. For lookup details, use [Policy lifecycle](/policies/lifecycle) and [Policy categories](/policies/categories/overview). ## Policy states Policies move through review, deployment, and impact checks. Tero shows policy state, source, linked issue, activity, deployments, and spec so reviewers can connect the policy back to the evidence Tero used to create it. Use [Policy lifecycle](/policies/lifecycle) for the current state reference. ## Policy detail Policy detail pages include: * **Overview**: identity, source, linked issue, hits over time, and activity * **Deployments**: where the policy runs, including Edge deployment state when present * **Spec**: the structured policy definition Tero and runtimes use Policy detail connects spec, activity, linked issue, and deployments.

Policy detail connects spec, activity, linked issue, and deployments. Open in demo

The issue link returns you to the evidence. Open Deployments for runtime state, or Spec for the exact match and action. ## Provider inventory The Policies workspace can also show Datadog exclusion filters. This inventory helps teams compare existing provider configuration with Tero policies and convert supported filters into policies. Datadog filter detail can show overview, policy preview, imported policies, and import readiness. ## Related pages * [Review an issue](/issues/review-an-issue) * [Policy lifecycle](/policies/lifecycle) * [Policy categories](/policies/categories/overview) * [Policy enforcement](/policies/enforcement/overview) * [Datadog integration](/integrations/datadog) # Security Architecture Source: https://docs.usetero.com/trust/architecture End-to-end security architecture, trust boundaries, and enforcement model. Last reviewed: March 5, 2026 Owner: Security + Engineering Review cadence: Quarterly Status: Implemented This page maps request flow through Tero, the trust boundaries along the way, and the controls that enforce them. ## Reviewer focus * Where authentication, authorization, encryption, and logging controls are enforced * Where Tero terminates traffic and whether it requires inbound connectivity * Which architecture layers are Tero-owned vs customer-owned in self-hosted deployments ## Implementation status (March 5, 2026) Tero operates as a control plane. Customer users and systems call Tero APIs over HTTPS. Tero executes operations within tenant and workspace scope and logs security-relevant activity for audit and response. ## System flow diagram (hosted default) ```mermaid theme={null} flowchart LR U[Customer Users] --> E[Cloudflare Edge] I[Customer Integrations] --> E E --> A[Auth + Session Validation] A --> Z[Tenant/Workspace Authorization] Z --> C[Tero Control Plane] C --> D[(Encrypted Control-Plane Data Stores)] C --> L[(Security + Audit Logs)] C -. Optional provider path .-> P[AI Provider Integration] ``` ## End-to-end request flow (hosted default) 1. A user or integration authenticates to approved endpoints. 2. Traffic reaches Tero over TLS-protected connections. 3. Tero authorizes requests to tenant and workspace scope. 4. Services execute control-plane workflows and metadata processing. 5. Tero stores required data in encrypted managed services. 6. Tero records security and operational events for detection and audit. ## Trust boundaries and enforcement points | Boundary | What it separates | Key controls | | ----------- | ---------------------------------------------------------------- | ------------------------------------------------------------------------ | | Identity | Authenticated users and integrations vs unauthenticated requests | Auth provider integration, token and session validation, scoped access | | Network | Internet edge vs application ingress | TLS-required connections, edge protections, controlled endpoint exposure | | Application | Tenant and workspace operations | Tenant-scoped authorization and role-based access patterns | | Data | Control-plane metadata vs customer source telemetry systems | Data minimization model and bounded storage scope | | Secrets | Runtime services vs credential material | Managed secret stores with least-privilege access | ## Tenant isolation model (hosted) | Layer | Isolation approach | | ----------- | ----------------------------------------------------------------------------------------------------------------------------------- | | Application | Tero authorizes requests in tenant and workspace scope; role and operation checks run before execution | | Data | Tero applies tenant and workspace context in control-plane data access paths; bounded data model reduces cross-tenant exposure risk | | Network | Managed ingress and service boundaries isolate Internet edge, application ingress, and internal service communication paths | ## Isolation boundary diagram ```mermaid theme={null} flowchart TB subgraph Identity_Boundary[Identity Boundary] AUTH[Authenticated User/Session or Integration Token] end subgraph Network_Boundary[Network Boundary] EDGE[Internet Edge + Ingress Controls] end subgraph Application_Boundary[Application Boundary] APP[Tenant/Workspace Authorization Layer] end subgraph Data_Boundary[Data Boundary] META[(Control-Plane Metadata Stores)] SRC[(Customer Source Telemetry Systems)] end subgraph Secrets_Boundary[Secrets Boundary] SEC[Managed Secret Store with Scoped Access] end AUTH --> EDGE --> APP --> META APP -. no baseline vendor-initiated inbound connectivity .-> SRC APP --> SEC ``` ## Architecture diagrams and review artifacts Tero maintains architecture documentation that describes trust boundaries, tenant isolation, and data-flow separation. This Trust Center includes public overview material; Tero shares deeper architecture walkthrough material for security review under NDA. ## Traffic and termination model | Path | Tero-hosted | Self-hosted | | ---------------------------------------------- | ----------------------------------------- | ---------------------------------- | | External API traffic | HTTPS to Tero-managed endpoints | Customer-defined ingress path | | TLS termination | Hosted edge reverse-proxy layer | Customer-defined termination model | | Service-to-service traffic | Managed cloud networking controls | Customer networking controls | | Inbound connectivity into customer environment | Not required for baseline API integration | Customer-controlled | ## Hosted vs self-hosted ownership | Area | Tero-hosted | Self-hosted | | -------------------------------------------- | --------------------------- | ------------------------------- | | Infrastructure runtime ownership | Tero | Customer | | Environment hardening | Tero platform controls | Customer environment controls | | Secrets backend operations | Tero-managed implementation | Customer-managed implementation | | Private connectivity model | Tero-managed hosted model | Customer-defined | | Incident ownership for infrastructure events | Tero | Customer | ## Evidence you can request | Control domain | Implementation summary | Primary evidence | | ----------------------------------- | ---------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------- | | Authentication and session controls | Enterprise auth provider integration and scoped session handling | [Identity and Access](/trust/controls/identity-access) | | Authorization | Tenant and workspace scoped access and role enforcement | [Identity and Access](/trust/controls/identity-access) | | Encryption in transit and at rest | TLS-required communication and encrypted managed storage | [Encryption and Key Management](/trust/controls/encryption-key-management), [Encryption Standard](/trust/policies/encryption-standard) | | Secrets management | Centralized secret stores with least-privilege access | [Identity and Access](/trust/controls/identity-access), [Encryption and Key Management](/trust/controls/encryption-key-management) | | Monitoring and response | Centralized logging and security event monitoring | [Incident Response and Resilience](/trust/controls/incident-response) | | Change control | Peer review, CI checks, controlled deployment paths | [Secure Development](/trust/controls/secure-development) | ## Exceptions and governance Any architecture-control exception requires documented risk, explicit Security and Engineering approval, compensating controls, and a time-bound remediation date. Evidence requests: # Compliance and Assurance Source: https://docs.usetero.com/trust/assurance/compliance-and-assurance Current compliance status and available assurance artifacts. Last reviewed: March 5, 2026 Owner: Security + Engineering Review cadence: Quarterly Status: In progress This page lists available assurance artifacts, work in progress, and how Tero reports control maturity during procurement. ## Reviewer focus * Which assurance milestones are complete versus in progress * What evidence is available now for review * How in-progress items are represented in questionnaire responses ## Implementation status (March 5, 2026) | Framework or artifact | Status | | -------------------------------------- | ------------------------------- | | SOC 2 Type II | In progress (target: July 2026) | | Security questionnaire support | Available | | Architecture and control documentation | Available | | DPA and contractual privacy terms | Available | ## Assurance package availability | Item | Availability | | --------------------------------- | -------------------- | | Public Trust Center documentation | Available now | | Security questionnaire responses | Available on request | | Additional assurance artifacts | Available under NDA | ## How we represent in-progress controls When a control or audit milestone is still in progress, we provide: * current implementation state, * compensating controls in operation, * target completion timing, * and the evidence path once complete. ## Evidence you can request | Topic | Primary evidence | | --------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Architecture and trust boundaries | [Security Architecture](/trust/architecture) | | Data handling and subprocessors | [Data Handling](/trust/controls/data-handling), [Subprocessors and Third Parties](/trust/assurance/subprocessors-third-parties) | | Operational controls | [Identity and Access](/trust/controls/identity-access), [Network Security](/trust/controls/network-security), [Secure Development](/trust/controls/secure-development) | | Policy baseline | [Policies](/trust/policies/index) | ## Questions and escalation path For assurance-package requests, email with your checklist and timeline. # Documents and Requests Source: https://docs.usetero.com/trust/assurance/documents-and-requests How to request security documentation and assurance artifacts. Last reviewed: March 5, 2026 Owner: Security + Engineering Review cadence: Quarterly Status: Reference Use this page as the intake path for procurement and security review requests. ## Reviewer focus * Which artifacts are public versus request-based * What to include so we can answer fast * How we handle NDA-gated evidence ## Available materials | Category | Availability | | --------------------------------- | -------------------- | | Public Trust Center documentation | Available now | | Security questionnaire responses | Available on request | | Detailed assurance artifacts | Available under NDA | ## Request process 1. Send your checklist and timeline to . 2. Include deployment model (`Tero-hosted` or `self-hosted`) and any mandatory controls. 3. We return the relevant package and identify any follow-up items. ## Typical request topics * Architecture and trust boundaries * Identity, authentication, and token controls * Encryption and key management * Data handling, retention, and subprocessors * Compliance milestones and assurance status ## Escalations If your review has a hard procurement deadline, include that date in the request so we can respond before it. # Subprocessors and Third Parties Source: https://docs.usetero.com/trust/assurance/subprocessors-third-parties Third-party services used in hosted deployments and their processing roles. Last reviewed: March 5, 2026 Owner: Security + Engineering Review cadence: Quarterly Status: Implemented This page lists the core third-party services Tero uses in hosted deployments and the role each one plays. ## Reviewer focus * Which third parties are involved in hosted delivery * What data category each subprocessor handles * How subprocessor scope changes in self-hosted deployments ## Current subprocessors (hosted) | Service | Purpose | Data category | Location | | ------------------------------------------ | ---------------------------------------- | ------------------------------------ | -------- | | Google Cloud Platform | Infrastructure runtime, storage, backups | Control-plane operational data | US | | WorkOS | Authentication and identity workflows | Identity and authentication metadata | US | | Anthropic or OpenAI (deployment-dependent) | AI-assisted classification workflows | AI workflow input scope | US | | Stripe (self-service only) | Billing operations | Billing metadata | US | ## Self-hosted model boundary In self-hosted deployments, you choose and operate your own infrastructure and provider stack. You define subprocessor scope for the components you host. ## Change management baseline * Subprocessor changes follow internal review before customer use. * Tero communicates material changes that could affect security, availability, or data handling in advance where required by contract or plan terms. * Tero communicates emergency changes, with impact context, as soon as it understands the impact. ## Evidence you can request | Topic | Primary evidence | | --------------------------------- | ------------------------------------------------------------------------------------------------ | | Ownership split | [Shared Responsibility](/trust/shared-responsibility) | | Data scope and retention baseline | [Data Handling](/trust/controls/data-handling), [Data Retention](/trust/policies/data-retention) | | Compliance context | [Compliance and Assurance](/trust/assurance/compliance-and-assurance) | ## Questions For subprocessor detail requests, email . # AI Data Controls Source: https://docs.usetero.com/trust/controls/ai-data-controls How AI provider paths are configured, what data is sent, and deployment-dependent control options. Last reviewed: March 5, 2026 Owner: Security + Engineering Review cadence: Quarterly Status: Implemented This page covers how Tero configures AI provider integrations and which controls apply to AI-related data paths. ## Reviewer focus * What data is sent to AI providers for classification and analysis workflows * Which provider and key-ownership modes are supported * How retention and training controls differ by provider and configuration ## Implementation status (March 5, 2026) Tero supports three AI deployment modes: hosted default provider path, bring-your-own provider credentials, and customer-controlled self-hosted provider routing. ## AI workflow data scope Tero sends AI providers only the data each classification or analysis task needs. By default, that means control-plane-relevant context and the telemetry samples the task requires. Tero does not ingest your full telemetry stream. | Topic | Baseline approach | | --------------------- | ------------------------------------------------------------------------------ | | Prompt scope | Task-scoped inputs for classification and analysis workflows | | Data minimization | Inputs are bounded to workflow requirements | | Model output handling | Outputs are used for product classification and recommendation workflows | | Governance | Provider path and key ownership can be customer-controlled by deployment model | ## Provider and key ownership modes | Mode | Description | Typical use case | | ----------------------------------- | --------------------------------------------------------------- | ----------------------------------------------------------------- | | Tero-managed provider path | Tero-hosted default provider configuration | Fastest onboarding | | Bring-your-own provider credentials | Customer API credentials used for provider calls | Customer-controlled commercial relationship with OpenAI/Anthropic | | Self-hosted provider path | Runtime and provider routing controlled in customer environment | Maximum infrastructure and network control | ## Provider data controls (external policy alignment) | Provider path | Training usage baseline | Retention baseline | Zero-retention option | | ------------- | ----------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------- | | OpenAI API | API data is not used for model training by default (unless customer opts in) | Abuse-monitoring and application-state retention depends on endpoint/configuration (default policies apply) | Available for approved organizations on eligible configurations/endpoints | | Anthropic API | Commercial/API data is not used for model training by default | Standard API retention baseline applies (commercial policy default) | Available by agreement for eligible enterprise API use cases | | AWS Bedrock | Prompts/outputs are not used to train base models and are not shared with model providers | Bedrock service data-protection model applies | Private connectivity and customer-managed encryption controls available | ## Deployment boundary | Control area | Tero-hosted | Self-hosted | | ----------------------------- | --------------------------------------------- | ------------------------------------------------- | | Provider account boundary | Tero-managed or customer-provided credentials | Customer-controlled | | Runtime/network boundary | Tero-hosted boundary | Customer infrastructure boundary | | Provider policy configuration | Configured per provider path | Customer-configured | | Compliance posture | Tero controls + selected provider controls | Customer environment + selected provider controls | ## Model and provider coverage * Recommended frontier providers for production quality are Anthropic and OpenAI. * Bedrock and additional provider paths are supported as deployment-dependent integration options. * Additional open-source/local model paths (for example, Ollama-compatible) are possible, with quality validated case-by-case. ## Recommended strict-control profile | Control | Recommended setting | | ------------------------- | ----------------------------------------------------------------------------------------------------- | | Provider account boundary | Use customer-provided credentials or self-hosted provider routing for strict boundary control | | Data retention mode | Use provider zero-retention mode where eligible and contractually enabled | | Training controls | Keep provider training opt-in disabled for API data | | Prompt scope control | Limit prompts to minimum task-relevant context and avoid unrestricted raw payload submission | | Secret management | Store provider credentials in managed secret stores with scoped runtime access | | Key lifecycle | Rotate provider credentials on a defined cadence and on any incident trigger | | Network controls | Restrict outbound destinations to approved AI provider endpoints | | Auditability | Log AI request metadata and outcome events without exposing sensitive prompt text in operational logs | ## External references * [OpenAI data controls](https://platform.openai.com/docs/guides/your-data) * [Anthropic retention and zero data retention FAQs](https://privacy.anthropic.com/en/articles/7996866-how-long-do-you-store-my-organization-s-data) * [Anthropic zero data retention scope](https://privacy.anthropic.com/en/articles/8956058-i-have-a-zero-data-retention-agreement-with-anthropic-what-products-does-it-apply-to) * [Amazon Bedrock data protection](https://docs.aws.amazon.com/bedrock/latest/userguide/data-protection.html) * [Amazon Bedrock security/privacy overview](https://aws.amazon.com/bedrock/security-privacy-responsible-ai/) ## Evidence you can request | Topic | Primary evidence | | -------------------------------- | --------------------------------------------------------------------------- | | High-level data scope | [Overview](/trust/overview), [Data Handling](/trust/controls/data-handling) | | Ownership split | [Shared Responsibility](/trust/shared-responsibility) | | Identity and credential controls | [Identity and Access](/trust/controls/identity-access) | | Encryption and key controls | [Encryption and Key Management](/trust/controls/encryption-key-management) | ## Exceptions and governance Any AI data-path exception requires documented approval, compensating controls, and a time-bound remediation plan. Evidence requests: # Data Handling Source: https://docs.usetero.com/trust/controls/data-handling What data Tero handles, what is stored, and how retention and deletion work. Last reviewed: March 5, 2026 Owner: Security + Engineering Review cadence: Quarterly Status: Implemented This page defines the hosted default data scope, retention behavior, and what changes when you self-host. ## Reviewer focus * Which data classes are stored in the hosted model * What the default retention and deletion behavior is * How ownership changes between hosted and self-hosted environments ## Implementation status (March 5, 2026) Tero limits retained data by default. The control plane stores only the metadata required to operate the product. Full raw telemetry stays in your observability platform. ## Data lifecycle diagram (hosted default) ```mermaid theme={null} flowchart LR IN[Ingested Product Data] --> CL[Classify and Scope] CL --> MD[Metadata Processing and Storage] MD --> RT[Retention Window Applied] RT --> DEL[Deletion from Active Systems] RT --> BK[Encrypted Backups] BK --> EXP[Backup Expiry] ``` ## Data classes and handling model (hosted default) | Data class | Stored in Tero-hosted | Typical purpose | | --------------------------------------------------------- | --------------------- | -------------------------------------------------------- | | Account and workspace configuration | Yes | Service setup and access control | | Telemetry metadata (schema, field types, volume patterns) | Yes | Catalog, analysis, and policy generation | | Full raw telemetry content | No (default model) | Source of record remains customer observability platform | | Authentication and session metadata | Yes | Authentication and authorization workflows | | Billing metadata (self-service) | Limited scope only | Billing operations | ## Retention and deletion baseline | Data type | Default retention | | --------------------------------------- | ------------------------------------ | | Account and workspace data | While account or workspace is active | | Metadata required for service operation | While workspace is active | | Backups | 30 days | When a customer account or workspace is deleted, Tero removes data from active systems within 30 days. Backup copies age out under backup-retention windows. ## Hosted vs self-hosted boundary | Area | Tero-hosted | Self-hosted | | ----------------------- | -------------------------- | ------------------------------------------- | | Data locality control | Tero-hosted region model | Customer-selected region and infrastructure | | Infrastructure boundary | Tero-operated | Customer-operated | | Subprocessor scope | Tero-managed service stack | Customer-selected stack | | Data deletion execution | Tero-operated | Customer-operated runtime | ## Evidence you can request | Topic | Primary evidence | | ----------------------------------- | ------------------------------------------------------------------------------- | | High-level storage model | [Overview](/trust/overview) | | Ownership split by deployment | [Shared Responsibility](/trust/shared-responsibility) | | Retention and deletion expectations | [Data Retention](/trust/policies/data-retention) | | Subprocessor scope | [Subprocessors and Third Parties](/trust/assurance/subprocessors-third-parties) | ## Exceptions and governance Any exception to standard handling or retention behavior requires documented risk, Security and Engineering approval, compensating controls, and a time-bound remediation plan. Evidence requests: # Encryption and Key Management Source: https://docs.usetero.com/trust/controls/encryption-key-management Encryption in transit and at rest, key ownership model, rotation, and key event visibility. Last reviewed: March 5, 2026 Owner: Security + Engineering Review cadence: Quarterly Status: Implemented This page summarizes Tero's encryption controls for cloud data and how key ownership and operations differ between hosted and self-hosted deployments. ## Reviewer focus * How data is encrypted in transit and at rest * Who owns and administers encryption keys by deployment model * How Tero handles key visibility, rotation, and revocation ## Implementation status (March 5, 2026) Tero encrypts sensitive and confidential data paths in transit and at rest in hosted environments. ## Encryption controls | Area | Implementation | | --------------- | ------------------------------------------------------------- | | Data in transit | TLS-protected external API and service communication | | Data at rest | Cloud-provider encryption for databases, storage, and backups | | Secrets storage | Managed secret systems with restricted access | ## Key ownership and access model | Topic | Tero-hosted | Self-hosted | | ----------------------------- | ----------------------------------------------- | --------------------------- | | Key ownership model | Cloud-provider managed keys in hosted stack | Customer-selected key model | | Key and secret administration | Restricted by IAM and RBAC with least privilege | Customer-defined | | Key usage visibility | Cloud logging and monitoring paths | Customer-defined | ## Rotation and revocation baseline * Key lifecycle follows cloud-provider rotation and lifecycle controls. * Tero supports rotation and revocation for integration credentials and secrets. * Tero supports emergency revocation for compromised credentials. ## Evidence you can request | Topic | Primary evidence | | ------------------------ | ------------------------------------------------------------------------------------------------ | | Detailed policy language | [Encryption Standard](/trust/policies/encryption-standard) | | Architecture controls | [Security Architecture](/trust/architecture) | | Data scope and retention | [Data Handling](/trust/controls/data-handling), [Data Retention](/trust/policies/data-retention) | ## Exceptions and governance Any exception requires documented approval, compensating controls, and a time-bound remediation plan. Evidence requests: # Identity and Access Source: https://docs.usetero.com/trust/controls/identity-access Authentication, authorization, credential scope, and access lifecycle controls. Last reviewed: March 5, 2026 Owner: Security + Engineering Review cadence: Quarterly Status: Implemented This page explains how users and integrations authenticate, how Tero scopes access, and how Tero protects, rotates, and revokes credentials. ## Reviewer focus * Which identity types are used for users and integrations * How least-privilege authorization is enforced * How credentials are stored, rotated, and revoked ## Implementation status (March 5, 2026) Tero supports SSO and OIDC-capable authentication with tenant and workspace scoped authorization. Tero scopes integration credentials to required operations and supports rotation and revocation. ## Authentication and token flow ```mermaid theme={null} flowchart LR U[User or Integration] --> A[Authentication] A --> S[Session or Token Validation] S --> Z[Tenant/Workspace Authorization] Z --> X[Scoped Action Execution] K[Credential Rotation / Revocation] --> S R[Role or Lifecycle Change] --> Z ``` ## Authentication model | Access path | Model | | ---------------------- | --------------------------------------------------------- | | User access | SSO and OIDC-capable authentication with session controls | | API integrations | Scoped token-based authentication | | Administrative actions | Restricted administrative access model | ## Authorization and least privilege | Control | Implementation | | ----------------- | ----------------------------------------------------------------------------- | | Tenant isolation | Tero evaluates requests in tenant and workspace context | | Role-based access | Tero constrains access by role and permitted operations | | Scope constraints | Tero limits integration credentials to required functions | | Access lifecycle | Admins provision access for approved need and remove it when no longer needed | ## Credential lifecycle controls | Area | Practice | | ---------------------- | --------------------------------------------------------- | | Creation | Issued through controlled integration and admin workflows | | Storage | Tero stores credentials in managed secret systems | | Rotation | Supported on demand and through operational workflows | | Revocation | Immediate disable and revocation supported | | Source control hygiene | Secrets are not committed to source code | ## Hosted vs self-hosted boundary | Area | Tero-hosted | Self-hosted | | ------------------------------ | --------------------- | ------------------------- | | Runtime identity controls | Tero-operated | Customer-operated runtime | | IdP policy and lifecycle rules | Customer-controlled | Customer-controlled | | Secret backend ownership | Tero-managed services | Customer-managed services | ## Evidence you can request | Topic | Primary evidence | | ------------------------------------ | ---------------------------------------------------------------------------------------- | | Authentication and password baseline | [Authentication and Password Standard](/trust/policies/authentication-password-standard) | | Ownership split | [Shared Responsibility](/trust/shared-responsibility) | | Secret handling and key model | [Encryption and Key Management](/trust/controls/encryption-key-management) | | Architecture boundaries | [Security Architecture](/trust/architecture) | ## Exceptions and governance Any identity or access exception requires documented approval, scoped compensating controls, and a target remediation date. Evidence requests: # Incident Response and Resilience Source: https://docs.usetero.com/trust/controls/incident-response Detection, triage, communication, and recovery expectations for security incidents. Last reviewed: March 5, 2026 Owner: Security + Engineering Review cadence: Quarterly Status: Implemented Tero detects, triages, communicates, and follows through on incidents. This page describes what you can expect at each phase. ## Reviewer focus * How Tero responds to security-relevant incidents * What customers can expect for communication during material incidents * How resilience controls support recovery and continuity ## Implementation status (March 5, 2026) Tero monitors security and operational events, including cloud security alerts, and triages them through incident-response workflows. ## Incident-response lifecycle | Phase | Expected behavior | | ---------------------------- | --------------------------------------------------------- | | Detection | Tero monitors and investigates security-relevant signals | | Triage | Tero assesses severity and impact | | Containment and recovery | Tero executes containment and service-restoration actions | | Communication | Tero notifies affected customers for material incidents | | Post-incident follow-through | Tero tracks corrective actions and improvements | ## Customer communication baseline * Tero notifies affected customers when it confirms a material incident. * Communication includes impact scope, current status, and next steps. * Tero keeps sending updates until it resolves the customer-impacting risk. ## Resilience controls | Area | Approach | | ----------------------- | ----------------------------------------------------------------------------------------------- | | Cloud security alerting | Tero monitors provider and platform security alerts and triages them through incident workflows | | Backups | Encrypted backups with retention controls | | Recovery | Operational recovery procedures and runbooks | | Deployment resilience | Managed cloud service patterns and operational controls | ## Hosted vs self-hosted boundary | Area | Tero-hosted | Self-hosted | | --------------------------------- | ----------- | ----------- | | Product incident support | Tero | Tero | | Infrastructure incident ownership | Tero | Customer | | Runtime recovery execution | Tero | Customer | ## Evidence you can request | Topic | Primary evidence | | -------------------------------------- | ------------------------------------------------------------------------------------------------ | | Architecture and monitoring controls | [Security Architecture](/trust/architecture) | | Data durability and retention behavior | [Data Handling](/trust/controls/data-handling), [Data Retention](/trust/policies/data-retention) | | Assurance posture | [Compliance and Assurance](/trust/assurance/compliance-and-assurance) | ## Exceptions and governance Any incident-handling exception requires explicit risk acceptance and time-bound remediation. Evidence requests: # Network Security Source: https://docs.usetero.com/trust/controls/network-security External exposure model, transport security, edge protections, and connectivity options. Last reviewed: March 5, 2026 Owner: Security + Engineering Review cadence: Quarterly Status: Implemented Tero requires TLS for integration traffic and protects hosted endpoints at the Cloudflare edge. This page covers that baseline and the connectivity options by deployment model. ## Reviewer focus * How traffic reaches Tero and where TLS is terminated * Which WAF and DDoS controls protect hosted endpoints * What network restriction options are supported for stricter deployment requirements ## Implementation status (March 5, 2026) Tero exposes hosted APIs through controlled public endpoints behind Cloudflare edge protections. Self-hosted deployments are customer-controlled for perimeter and routing policy. ## Network path diagram ```mermaid theme={null} flowchart LR C[Customer System] --> P[Public Internet / Allowlisted Path] P --> E[Cloudflare Edge] E --> I[Tero API Ingress] I --> S[Internal Service Boundary] C -. Enterprise option .-> X[Private Connectivity Path] X -. customer configured .-> I ``` ## Connectivity baseline | Topic | Tero-hosted | Self-hosted | | --------------------------------- | ---------------------------------------------- | ---------------- | | Integration directionality | Customer-initiated outbound API calls | Customer-defined | | Inbound into customer environment | Not required for baseline integration | Customer-defined | | Private connectivity model | Available based on customer requirements | Customer-managed | | Destination restrictions | Allowlisting support for customer integrations | Customer-managed | ## Edge protection model (hosted) | Control area | Implementation | | -------------------------- | ---------------------------------------------------------------------------------------- | | WAF and L7 protections | Cloudflare-managed WAF rules and request controls | | DDoS protection | Cloudflare network and application-layer DDoS protections | | Monitoring | Edge and application telemetry monitored for anomalous traffic patterns | | Rule and change management | Rule changes follow controlled change workflows and validation before production rollout | ## Traffic and termination model | Path | Tero-hosted | Self-hosted | | -------------------------- | --------------------------------------------------------- | ---------------------------------- | | External API traffic | HTTPS to Tero-managed endpoints | Customer-defined ingress path | | TLS termination | Hosted edge reverse-proxy layer | Customer-defined termination model | | Service-to-service traffic | Managed cloud network segmentation and service boundaries | Customer networking controls | ## Evidence you can request | Topic | Primary evidence | | --------------------- | -------------------------------------------------------------------------- | | Architecture boundary | [Security Architecture](/trust/architecture) | | Ownership split | [Shared Responsibility](/trust/shared-responsibility) | | Encryption details | [Encryption and Key Management](/trust/controls/encryption-key-management) | ## Exceptions and governance Any network-control exception requires documented risk, compensating controls, and a target remediation date. Evidence requests: # Secure Development Source: https://docs.usetero.com/trust/controls/secure-development How code, dependencies, secrets, and deployments are controlled in the SDLC. Last reviewed: March 5, 2026 Owner: Security + Engineering Review cadence: Quarterly Status: Implemented This page covers the engineering controls Tero applies before changes reach production. ## Reviewer focus * How code changes are reviewed and validated * How dependency and secret risks are managed in CI and deployment workflows * How production changes are controlled and rolled back when needed ## Implementation status (March 5, 2026) Tero uses reviewed change workflows, automated checks, and controlled deployment paths. ## SDLC control baseline | Control | Implementation | | ------------------ | ------------------------------------------------------------ | | Code review | Tero requires peer review before merge | | CI checks | Tero requires automated checks before merge and deploy | | Testing | Automated tests run in CI workflows | | Dependency risk | Vulnerability scanning in development and security workflows | | Secrets hygiene | Tero manages secrets in dedicated secret systems | | Deployment control | Controlled CI/CD paths and environment controls | ## Change management expectations * Tero reviews changes before merge. * Production-impacting changes follow controlled rollout behavior. * Tero rolls back failed deploys and tracks post-incident fixes to completion. ## Hosted vs self-hosted boundary | Area | Tero-hosted | Self-hosted | | -------------------------------- | ------------- | ------------------------- | | Product SDLC controls | Tero | Tero | | Runtime deployment controls | Tero-operated | Customer-operated runtime | | Infrastructure patching controls | Tero-operated | Customer-operated | ## Evidence you can request | Topic | Primary evidence | | ----------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------- | | Runtime and architecture boundaries | [Security Architecture](/trust/architecture) | | Access and secret handling | [Identity and Access](/trust/controls/identity-access), [Encryption and Key Management](/trust/controls/encryption-key-management) | | Assurance posture | [Compliance and Assurance](/trust/assurance/compliance-and-assurance) | ## Exceptions and governance Any SDLC control exception requires documented approval, compensating controls, and remediation timing. Evidence requests: # Overview Source: https://docs.usetero.com/trust/overview Security, privacy, and compliance posture for Tero-hosted and self-hosted deployments. Last reviewed: March 5, 2026 Owner: Security + Engineering Review cadence: Quarterly Status: In progress You need fast, concrete answers: what Tero operates, what data it handles, where responsibility splits, and what evidence you can get. ## Reviewer focus * What is live today versus still in progress * What changes between Tero-hosted and self-hosted deployments * Where to go next for architecture, ownership, and evidence details ## Implementation status (March 5, 2026) | Topic | Status | | ------------------- | ------------------------------------------------------------ | | SOC 2 Type II | In progress (target: July 2026) | | Encryption | Enabled in transit and at rest | | Deployment models | Tero-hosted and self-hosted | | AI provider options | Hosted default provider plus bring-your-own provider options | If a control is in progress, we mark it as in progress. ## Start your review End-to-end request flow, trust boundaries, and control points. Ownership split by deployment model. Questionnaire topic to page lookup. ## Deployment boundary at a glance | Area | Tero-hosted | Self-hosted | | -------------------------------------- | ------------------------------------- | ------------------------------------- | | Control plane runtime | Operated by Tero | Operated by customer | | Network perimeter | Managed by Tero baseline controls | Managed by customer | | Data locality control | Tero-hosted region model | Customer-chosen region/infrastructure | | AI provider path | Hosted default and configured options | Customer-controlled provider path | | Infrastructure patching and operations | Tero | Customer | ## Default hosted data scope | Data class | Stored | Why | | ---------------------------------------------------------- | ------------------ | ---------------------------------------------------- | | Account and workspace configuration | Yes | Service configuration and access control | | Telemetry metadata (schemas, field types, volume patterns) | Yes | Catalog, analysis, and policy generation | | Full raw telemetry content | No (default model) | Source of record remains your observability platform | | Authentication metadata | Yes | Session and access control | | Billing records (self-service) | Limited scope only | Billing operations | ## In practice * Baseline integration does not require vendor-initiated inbound connectivity into your environment. * Full raw telemetry is not the default hosted system-of-record data model. * In self-hosted mode, you own the infrastructure and network control layers. ## Evidence path | Topic | Public evidence | Additional evidence (on request) | | --------------------------------- | ------------------------------------------------------------------------------- | ----------------------------------------------------------- | | Architecture and trust boundaries | [Security Architecture](/trust/architecture) | Architecture walkthrough and control notes | | Responsibility split | [Shared Responsibility](/trust/shared-responsibility) | Deployment-specific control allocation review | | Encryption controls | [Encryption Standard](/trust/policies/encryption-standard) | Platform control evidence and security review package | | Subprocessors and data handling | [Subprocessors and Third Parties](/trust/assurance/subprocessors-third-parties) | Subprocessor and data-flow detail under NDA | | AI data handling options | [AI Data Controls](/trust/controls/ai-data-controls) | Deployment-specific model and provider configuration review | ## In progress * SOC 2 Type II is in progress. * Target issuance window: July 2026. Email with your checklist, deployment model, and review timeline. # Authentication and Password Standard Source: https://docs.usetero.com/trust/policies/authentication-password-standard Authentication, password, MFA, and session-control baseline for user access. Last reviewed: March 5, 2026 Owner: Security + Engineering Review cadence: Quarterly Status: Implemented This standard defines how Tero enforces user authentication controls, including password policy ownership, MFA, and session protections. ## What this standard answers * Who owns password policy controls in hosted and self-hosted deployments * How authentication is enforced for users and admins * What controls are applied when password-based authentication is used ## Implementation status (March 5, 2026) Tero supports SSO and OIDC-capable authentication and enforces authentication and session controls in application access paths. ## Authentication and password baseline | Area | Requirement | | ------------------------------------- | --------------------------------------------------------------------------------------------------- | | Primary user authentication model | SSO-capable authentication with SAML 2.0 and OpenID Connect support | | Password policy source of truth (SSO) | Customer IdP policy controls (complexity, lockout, rotation, MFA policies) | | Password handling | Tero never stores passwords in source code; managed identity systems handle password authentication | | MFA support | Enforced through customer IdP policy where configured | | Administrative access | Restricted administrative access model with scoped authorization | | Session controls | Tero enforces session validation and scoped authorization in runtime access paths | ## Supported login and SSO protocols | Method or protocol | Support | Notes | | --------------------------------- | ------------------------------------ | ----------------------------------------------------------------------------------- | | Username and password | Supported | Can be disabled when SSO-only access is required | | SSO via SAML 2.0 | Supported | Works with major SAML-compatible IdPs | | SSO via OpenID Connect | Supported | Works with major OIDC-compatible IdPs | | Multi-factor authentication (MFA) | Supported | Enforced through customer IdP policy for SSO; configurable for password-based login | | OAuth 2.0 delegated access | Supported | Used for scoped API/integration authorization paths | | LDAP | Not a direct authentication protocol | LDAP-backed directories integrate through IdP/SSO providers | ## Automated provisioning and deprovisioning | Capability | Support model | Notes | | -------------------------- | -------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- | | User provisioning | Supported | Customer IdP directory-sync integrations create users | | User deprovisioning | Supported | Removing or disabling a user in the customer IdP removes the user or revokes their access | | Inactive-account handling | Supported | Customer IdP lifecycle policy, platform account-lifecycle controls, or both disable inactive user access, depending on deployment configuration | | Group-based access mapping | Supported | IdP groups can be mapped to product roles/teams for least-privilege access assignment | | SCIM transport | Supported where configured | SCIM-capable directory-sync paths are supported through identity integrations; provider-native sync paths are also supported | ## Session timeout and reauthentication settings | Access mode | Default session/reauth behavior | Customer configurability | | ----------------- | ---------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------- | | SSO (SAML/OIDC) | Session timeout and reauthentication follow customer IdP policy defaults | Customer-configurable in IdP policy (for example idle timeout, max session age, reauth/MFA frequency) | | Username/password | Tero enforces platform-managed secure session controls in application access paths | Customers can require SSO-only mode; Tero reviews customer-specific session policy requirements during security onboarding | ## Session binding and network attribute controls | Control | Baseline behavior | Customer configurability | | ------------------------------------- | ------------------------------------------------------------------------ | --------------------------------------------------------- | | Device-aware session policy | Enforced through customer IdP/conditional-access policy where configured | Configurable by customer in IdP/device-trust policy | | Network/IP-based session restrictions | Supported through customer IdP policy and network allowlisting controls | Configurable by customer requirement and deployment model | ## Enforcement model * Tero requires authentication before access to protected application paths. * Tero evaluates authorization in tenant and workspace context. * Tero removes or adjusts access when role and lifecycle state changes. ## Hosted vs self-hosted scope | Area | Tero-hosted | Self-hosted | | ------------------------------------ | ------------------- | -------------------------------------------- | | Application authentication controls | Tero-operated | Tero software with customer runtime controls | | IdP password and MFA policy settings | Customer-controlled | Customer-controlled | | Runtime identity stack operations | Tero-operated | Customer-operated runtime | ## Exceptions and governance Any authentication or password-control exception requires documented risk acceptance, approval, compensating controls, and a time-bound remediation plan. Questions: # Cloud Services Security Standard Source: https://docs.usetero.com/trust/policies/cloud-services-security-standard Approval and operating security baseline for cloud services used to deliver Tero. Last reviewed: March 5, 2026 Owner: Security + Engineering Review cadence: Quarterly Status: Implemented This standard defines how Tero approves, configures, and operates cloud services to a consistent security baseline. ## What this standard answers * How Tero approves new cloud services before production use * What minimum security requirements apply to cloud configuration and operations * How Tero handles cloud security alerts and material service changes ## Implementation status (March 5, 2026) Tero uses a defined cloud-service approval and operations baseline for hosted delivery. ## Approval requirements before production use | Requirement | Baseline | | ----------------------------------- | --------------------------------------------------------------- | | Business and data-scope review | Required before production onboarding | | Security capability review | Required for identity, logging, encryption, and access controls | | Subprocessor and contractual review | Required where third-party processing applies | | Owner assignment | Security and engineering ownership assigned for each service | ## Minimum cloud security baseline | Area | Requirement | | ------------------------ | ------------------------------------------------------------------------------- | | Access control | Least-privilege IAM with role-scoped access and periodic review | | Identity security | SSO-backed administrative access and MFA for privileged paths | | Encryption | Encryption in transit and at rest using managed cloud security controls | | Logging and auditability | Administrative and security-relevant events are logged and retained per policy | | Network controls | Internet edge and service boundary controls with monitored ingress paths | | Change management | Production-impacting changes follow controlled rollout and validation practices | | Backup and recovery | Encrypted backup and recovery procedures for hosted control-plane operations | ## Monitoring and response baseline | Area | Baseline | | --------------------------- | --------------------------------------------------------------------------------------- | | Cloud security alert intake | Tero monitors and triages security alerts from cloud and provider controls | | Incident handling | Tero routes security-relevant events through documented incident workflows | | Escalation | Tero escalates and communicates material incidents through customer communication paths | ## Material change communication * Tero communicates material security, availability, or data-handling changes in advance where required by contract or plan terms. * Tero communicates incident-driven or emergency changes as soon as it understands the impact, including remediation context. ## Hosted vs self-hosted boundary | Area | Tero-hosted | Self-hosted | | ------------------------------------------ | ------------- | ---------------------------------------------------- | | Cloud service approval and operation | Tero-operated | Customer-operated for customer runtime | | Infrastructure monitoring and alert triage | Tero-operated | Customer-operated for customer runtime | | Product-level security controls | Tero-operated | Tero product controls plus customer runtime controls | ## Evidence map | Topic | Primary evidence | | -------------------------------------------- | ------------------------------------------------------------------------------- | | Architecture and trust boundaries | [Security Architecture](/trust/architecture) | | Network and perimeter controls | [Network Security](/trust/controls/network-security) | | Incident workflow and customer communication | [Incident Response](/trust/controls/incident-response) | | Third-party service scope | [Subprocessors and Third Parties](/trust/assurance/subprocessors-third-parties) | ## Exceptions and governance Any baseline exception requires documented risk acceptance, compensating controls, owner approval, and a time-bound remediation plan. Questions: # Data Classification Source: https://docs.usetero.com/trust/policies/data-classification Classification levels and required handling controls. Last reviewed: March 5, 2026 Owner: Security + Engineering Review cadence: Quarterly Status: In progress This policy defines data classification levels and handling requirements used across product and operations. ## What this policy answers * Which classification levels are used * What baseline handling controls apply to each level * What is already operating versus still being formalized ## Implementation status (March 5, 2026) Classification controls are active. We are finalizing policy language and evidence mapping as part of the SOC 2 workstream. ## Classification levels | Level | Examples | Handling baseline | | ------------ | -------------------------------------------------------------------- | ----------------------------------------------------------------- | | Public | Public documentation and published materials | No confidentiality restrictions | | Internal | Operational runbooks and internal non-sensitive records | Internal access controls | | Confidential | Customer configuration and operational metadata | Least privilege and encrypted storage and transport | | Sensitive | Credentials, security artifacts, regulated identifiers where present | Restricted access, strict storage controls, heightened monitoring | ## Handling controls enforced today * Access by least privilege and role scope * Encryption in transit and at rest * Secrets in managed secret systems * Retention and deletion per policy expectations ## In progress * Final policy language and control-to-evidence mapping completion target: July 2026. ## Exceptions and governance Classification exceptions require documented risk, approval, and a time-bound remediation plan. Questions: # Data Retention Source: https://docs.usetero.com/trust/policies/data-retention Retention periods and deletion behavior for core hosted data classes. Last reviewed: March 5, 2026 Owner: Security + Engineering Review cadence: Quarterly Status: Implemented This policy defines baseline retention windows and deletion behavior for core hosted data classes. ## What this policy answers * Which hosted data classes are retained and for how long * How deletion is enforced in active systems and backups * How retention ownership differs in self-hosted deployments ## Implementation status (March 5, 2026) Retention and deletion controls described on this page are active in the hosted deployment model. ## Retention schedule (hosted default) | Data type | Retention | | ----------------------------------------- | ------------------------- | | Account and workspace records | While active | | Telemetry metadata required for operation | While workspace is active | | Backups | 30 days | ## Deletion behavior * On account or workspace deletion, Tero removes data from active systems within 30 days. * Backup copies expire with their retention windows. ## Hosted vs self-hosted scope | Area | Tero-hosted | Self-hosted | | -------------------------------------------- | --------------------- | ----------------- | | Retention enforcement | Tero-operated | Customer-operated | | Backup lifecycle controls | Tero-operated | Customer-operated | | Infrastructure-level retention configuration | Tero-defined baseline | Customer-defined | ## Exceptions and governance Retention exceptions require documented risk acceptance, approval, and time-bound remediation. Questions: # DLP Standard Source: https://docs.usetero.com/trust/policies/dlp-standard Current and planned controls for preventing and detecting sensitive data exfiltration risk. Last reviewed: March 5, 2026 Owner: Security + Engineering Review cadence: Quarterly Status: In progress This standard defines baseline prevention and detection controls for sensitive-data handling and exfiltration risk. ## What this standard answers * Which DLP-relevant controls are active today * Which policy artifacts are still being formalized * How this standard should be interpreted during review ## Implementation status (March 5, 2026) Tero implements core preventive controls through product design and access controls. Formal policy mapping is in progress. ## Current control baseline | Area | Current control | | --------------------- | ---------------------------------------------- | | Data minimization | Product design limits persistent storage scope | | Access control | Tenant and role-scoped authorization model | | Secrets protection | Managed secret systems and restricted access | | Transport and storage | Encryption in transit and at rest | | Monitoring | Security and operational event monitoring | ## In progress * Formalized DLP policy mapping and control-to-evidence matrix completion. * Target completion: July 2026. ## Scope note This standard describes Tero's control baseline and policy maturity status. It is not a standalone endpoint DLP product claim. ## Exceptions and governance Any DLP-control exception requires documented risk, compensating controls, and remediation timing. Questions: # Encryption Standard Source: https://docs.usetero.com/trust/policies/encryption-standard Encryption and key-management requirements for hosted deployments. Last reviewed: March 5, 2026 Owner: Security + Engineering Review cadence: Quarterly Status: Implemented This standard defines encryption and key-management requirements for hosted deployments. ## What this standard answers * Where encryption is required in transit and at rest * Which key-management controls are required * How exceptions are reviewed and approved ## Implementation status (March 5, 2026) The encryption and key-management requirements on this page are active in hosted production systems. ## Scope Applies to production systems, data stores, backups, service-to-service paths, and secrets handling. ## Encryption requirements | Area | Requirement | | --------------- | ----------------------------------------------------------------------------------- | | Data in transit | TLS is required for external API and service traffic | | Data at rest | Cloud-provider encryption controls are required for databases, storage, and backups | | Secrets | Managed secret systems are required; secrets are not stored in source code | ## Key-management requirements | Area | Requirement | | -------------------- | ---------------------------------------------------------------------------- | | Key services | Cloud key-management services | | Access control | Least-privilege IAM and RBAC for key and secret administration | | Rotation | Key lifecycle follows cloud-provider rotation and lifecycle controls | | Credential lifecycle | Integration credentials are rotatable and revocable | | Visibility | Key and encryption events are available through logging and monitoring paths | ## Exceptions and governance Exceptions require documented risk acceptance, Security and Engineering approval, compensating controls, and a time-bound remediation plan. Questions: # Security Policies Source: https://docs.usetero.com/trust/policies/index Policy library for trust controls and handling standards. Last reviewed: March 5, 2026 Owner: Security + Engineering Review cadence: Quarterly Status: Reference This library backs Trust Center control statements with policy-level requirements and status. ## Policy status snapshot | Policy | Status | | ------------------------------------ | ----------- | | Authentication and Password Standard | Implemented | | Cloud Services Security Standard | Implemented | | Data Classification | In progress | | Data Retention | Implemented | | DLP Standard | In progress | | Encryption Standard | Implemented | ## Policy set Authentication model, password policy ownership, MFA, and session-control baseline. Classification levels and handling requirements. Cloud approval, baseline security requirements, and operating controls. Retention periods and deletion behavior. Prevention and detection expectations for sensitive-data exfiltration risk. Encryption and key-management requirements. ## Need policy evidence? For policy evidence mapping or control-language questions, email . # Reviewer Map Source: https://docs.usetero.com/trust/reviewer-map Fast lookup for common security questionnaire topics. Last reviewed: March 5, 2026 Owner: Security + Engineering Review cadence: Quarterly Status: Reference Use this page as the index for questionnaire completion. It maps common prompts to the right trust pages without requiring deep navigation. ## How to use this map 1. Find the closest questionnaire topic. 2. Start with the listed primary page. 3. Use the secondary page only if the reviewer asks for more depth. ## Architecture and boundaries | Questionnaire topic | Primary page | Secondary page | | --------------------------------------- | -------------------------------------------------------------------------- | -------------------------------------------------------------------------- | | Architecture and trust boundaries | [Security Architecture](/trust/architecture) | [Shared Responsibility](/trust/shared-responsibility) | | Hosted vs self-hosted ownership | [Shared Responsibility](/trust/shared-responsibility) | [Overview](/trust/overview) | | Tenant isolation and logical separation | [Security Architecture](/trust/architecture) | [Identity and Access](/trust/controls/identity-access) | | Encryption in transit and at rest | [Encryption Standard](/trust/policies/encryption-standard) | [Encryption and Key Management](/trust/controls/encryption-key-management) | | Key management and key rotation | [Encryption and Key Management](/trust/controls/encryption-key-management) | [Encryption Standard](/trust/policies/encryption-standard) | ## Identity and access | Questionnaire topic | Primary page | Secondary page | | ---------------------------------------------- | ---------------------------------------------------------------------------------------- | ------------------------------------------------------ | | API identity and token controls | [Identity and Access](/trust/controls/identity-access) | [Shared Responsibility](/trust/shared-responsibility) | | Login and SSO protocol support | [Authentication and Password Standard](/trust/policies/authentication-password-standard) | [Identity and Access](/trust/controls/identity-access) | | Automated user provisioning and deprovisioning | [Authentication and Password Standard](/trust/policies/authentication-password-standard) | [Identity and Access](/trust/controls/identity-access) | | Inactive account disablement after inactivity | [Authentication and Password Standard](/trust/policies/authentication-password-standard) | [Identity and Access](/trust/controls/identity-access) | | Session timeout and reauthentication controls | [Authentication and Password Standard](/trust/policies/authentication-password-standard) | [Identity and Access](/trust/controls/identity-access) | | Device or IP-based session restrictions | [Authentication and Password Standard](/trust/policies/authentication-password-standard) | [Network Security](/trust/controls/network-security) | ## Data governance | Questionnaire topic | Primary page | Secondary page | | ----------------------------------------------------------------- | ------------------------------------------------------------------------------- | --------------------------------------------------------------------- | | Data handling scope and stored data | [Data Handling](/trust/controls/data-handling) | [Overview](/trust/overview) | | Subprocessors and third-party services | [Subprocessors and Third Parties](/trust/assurance/subprocessors-third-parties) | [Shared Responsibility](/trust/shared-responsibility) | | Integration directionality and connectivity model | [Network Security](/trust/controls/network-security) | [Security Architecture](/trust/architecture) | | Material change notice (security, availability, or data handling) | [Subprocessors and Third Parties](/trust/assurance/subprocessors-third-parties) | [Compliance and Assurance](/trust/assurance/compliance-and-assurance) | ## Cloud operations | Questionnaire topic | Primary page | Secondary page | | ----------------------------------------------- | ------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------ | | Cloud services policy and baseline requirements | [Cloud Services Security Standard](/trust/policies/cloud-services-security-standard) | [Network Security](/trust/controls/network-security) | | Cloud security alert monitoring | [Incident Response](/trust/controls/incident-response) | [Cloud Services Security Standard](/trust/policies/cloud-services-security-standard) | ## AI and model governance | Questionnaire topic | Primary page | Secondary page | | ------------------------------------------- | ---------------------------------------------------- | --------------------------- | | AI provider handling and deployment options | [AI Data Controls](/trust/controls/ai-data-controls) | [Overview](/trust/overview) | ## Assurance and legal | Questionnaire topic | Primary page | Secondary page | | ---------------------------------------- | --------------------------------------------------------------------- | ----------------------------------------------------------------- | | Compliance status and current assurances | [Compliance and Assurance](/trust/assurance/compliance-and-assurance) | [Documents and Requests](/trust/assurance/documents-and-requests) | ## How we answer in-progress controls When a control is incomplete, we answer with: * current implementation status, * compensating controls in place, * target completion timing, * and where evidence will be provided when complete. ## Need a full review packet? Email with your checklist and timeline. We can provide additional evidence under NDA. # Shared Responsibility Source: https://docs.usetero.com/trust/shared-responsibility Control ownership between Tero and customers in hosted and self-hosted deployments. Last reviewed: March 5, 2026 Owner: Security + Engineering Review cadence: Quarterly Status: Implemented This page defines who owns each control in each deployment model. ## Reviewer focus * Which controls are Tero-owned vs customer-owned * How baseline integration traffic flows between customer systems and Tero * Where customers commonly add stricter controls ## Implementation status (March 5, 2026) Tero supports two deployment models: * Tero-hosted control plane * Self-hosted control plane in customer-managed infrastructure Control ownership changes by model at the infrastructure and network layers. ## Scope and integration boundary * Baseline integration model is customer-initiated outbound API traffic over HTTPS. * Baseline operation does not require vendor-initiated inbound connectivity into customer environments. * Identity policy inside the customer IdP remains customer-owned in both models. ## Ownership model diagram ```mermaid theme={null} flowchart LR subgraph Hosted[Tero-hosted] H_INFRA[Infrastructure + Network: Tero] H_APP[Application Controls: Tero] H_IDP[IdP Policy: Customer] H_DATA[Retention + Deletion Ops: Tero] end subgraph SelfHosted[Self-hosted] S_INFRA[Infrastructure + Network: Customer] S_APP[Application Controls: Tero Software + Customer Runtime] S_IDP[IdP Policy: Customer] S_DATA[Retention + Deletion Ops: Customer Runtime] end ``` ## Responsibility matrix | Control area | Tero-hosted | Self-hosted | | ------------------------------------------ | --------------------- | ------------------------------------------------------- | | Infrastructure security and patching | Tero | Customer | | Network perimeter and private connectivity | Tero-managed baseline | Customer | | Identity provider policy (IdP side) | Customer | Customer | | Application authn and authz implementation | Tero | Tero software with customer runtime controls | | Secrets and key administration | Tero-managed services | Customer-managed services | | Data retention and deletion operations | Tero | Customer-operated runtime with product-defined behavior | | Incident response for platform operations | Tero | Customer for environment ops, Tero for product support | | Subprocessor management | Tero | Customer (for customer-chosen stack) | ## Where customers tighten controls * Self-hosted deployment for full environment ownership * Customer IdP policy enforcement for authentication lifecycle controls * Destination allowlisting and private routing in customer networks * Customer-selected AI provider path where required ## Go-live checklist (recommended) 1. Confirm identity and role mapping model. 2. Confirm network allowlisting and routing requirements. 3. Confirm data handling and retention expectations. 4. Confirm incident communication paths and named contacts. ## Evidence you can request | Topic | Primary evidence | | ------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------- | | Ownership split by deployment model | Current page | | Architecture and trust boundary | [Security Architecture](/trust/architecture) | | Data handling scope and storage model | [Overview](/trust/overview), [Data Handling](/trust/controls/data-handling) | | Encryption and key management | [Encryption and Key Management](/trust/controls/encryption-key-management), [Encryption Standard](/trust/policies/encryption-standard) | ## Exceptions and governance If a control allocation does not match customer policy requirements, Tero and the customer document the gap, agree on compensating controls, and define a time-bound resolution plan before production use. Evidence requests: