e-volv
Contents

e-volv Observer

e-volv Observer captures logs and traces from every project in a workspace hub, stores them in TimescaleDB with long retention, and turns bursts of errors into incidents with a failure graph. This page covers the standalone surface: the SDKs, OTLP ingest, the query language, the CLI and the public query API. e-volv Observer is a paid tier in early access; see pricing and the public API reference.

Quickstart

In the app, open Logs and create a project. e-volv mints a dedicated ingest key (scope logs:write), shows it exactly once, and gives you copy-paste snippets. Then install the SDK:

shell
npm install @e-volv/logs        # JS / TS, Node 18+
pip install e-volv-logs         # Python 3.10+
go get github.com/e-volv/logs-go   # Go 1.22+

JavaScript / TypeScript:

typescript
import { init } from '@e-volv/logs';

init({
  key: 'evk_...',
  url: 'https://api.e-volv.io/api/public/v1/logs',
  service: 'api',
});

Python:

python
import e_volv_logs

e_volv_logs.init(
    key='evk_...',
    url='https://api.e-volv.io/api/public/v1/logs',
    service='api',
)

Every SDK batches (200 events / 2 s / 512 KB), gzips, backs off on 429 and 413, redacts password|secret|token|authorization| cookie|set-cookie|api[-_]?key attributes, and propagates the traceparent across fetch, httpx, requests and Go's http.RoundTripper so a trace crosses every service it touches. Full references live in the Node.js SDK reference and the Python SDK reference.

The full SDK guides, split by runtime, are at Observer SDKs: Node.js and TypeScript, Python, Go, Java, Ruby, Rust, Android, iOS, Flutter, React Native, browser, front ends and edge and OpenTelemetry presets for every other language.

OTLP endpoint

Any OpenTelemetry collector - or curl - can post OTLP/HTTP JSON to POST https://api.e-volv.io/api/public/v1/logs/otlp with the project key as a bearer token. Logs and traces are auto-detected; the resource’s service.name attribute picks the project:

shell
curl -X POST "https://api.e-volv.io/api/public/v1/logs/otlp" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer evk_..." \
  -d '{"resourceLogs":[{"resource":{"attributes":[{"key":"service.name","value":{"stringValue":"api"}}]},"scopeLogs":[{"logRecords":[{"timeUnixNano":"<unix-ns>","severityNumber":9,"body":{"stringValue":"hello from curl"}}]}]}]}'

Ingest answers 202 after enqueueing - it never waits on storage. Batches are limited to 1 000 events or 5 MB per request.

Collector

The standard OTel paths and the protobuf encoding are served too, so the collector’s default otlphttp exporter works with nothing to customize - it appends /v1/traces and /v1/logs to the endpoint itself:

typescript
exporters:
  otlphttp/evolve:
    endpoint: https://api.e-volv.io/api/public/v1/logs/otlp
    headers:
      Authorization: 'Bearer evk_...' # a project's ingest key
    compression: gzip

service:
  pipelines:
    traces: { receivers: [otlp], exporters: [otlphttp/evolve] }
    logs:   { receivers: [otlp], exporters: [otlphttp/evolve] }

The full walk-through, including the queue-hop pattern that carries a trace across a job queue, lives in the OpenTelemetry guide.

Query language

Search uses a deliberately small filter grammar compiled to SQL, with at most one aggregation suffix:

text
level>=error service:api "connection timeout" attrs.region=ap-southeast-1 -attrs.retry:true
| count by service, 5m
FormMeans
level>=error, level<=warnSeverity comparison using the OTel scale (trace 1 … fatal 21).
service:apiMatch a project. Known keys: level, service, trace, span.
attrs.region=ap-southeast-1Match a dotted path inside the event attributes (JSONB).
"connection timeout"Quoted phrase → full-text match on the message.
timeoutBare word → trigram contains match on the message.
-attrs.retry:trueA leading minus sign negates any of the forms above.
duration>=250Span filters only; meaningful against traces, not log events.

One aggregation is allowed, at the end of the query:

FormMeans
| count by service, 5mEvent count grouped by the given columns, optionally time-bucketed.
| p95 duration by service, 15mp95 span latency grouped the same way.

Bucket suffixes: 1m, 5m, 15m, 1h, 1d.

CLI

The zero-dependency evolve-logs CLI (Node 18+) talks to the public query API with a logs:read key:

text
# Follow live logs (SSE; one JSON event per line)
evolve-logs tail --key evk_... --url https://api.e-volv.io [--project api]

# Search with the query language; prints NDJSON, pages automatically
evolve-logs search --key evk_... --url https://api.e-volv.io \
  --q 'level>=error service:api "connection timeout"' \
  [--from 2026-09-05T00:00:00Z] [--to 2026-09-05T01:00:00Z]

# List incidents
evolve-logs incidents --key evk_... --url https://api.e-volv.io

Without --from/--to, search covers the last 24 hours. The CLI ships with e-volv’s SDK tooling as logs-cli.

Public query API

The same search, dashboards and tail the app serves are keyed by API keys with the logs:read scope. The full route table is on the public API page; a search looks like:

shell
curl "https://api.e-volv.io/api/public/v1/logs/query?q=level%3E%3Derror+service%3Aapi&limit=100" \
  -H "Authorization: Bearer evk_..."

Retention and caps

LimitIncluded
Projects per hub50
Ingest25 GB / month per workspace, pooled across projects
Over the capOldest events are dropped first, never the newest
Raw log retention30 days hot, 90 days tiered
Traces, error groups and incidents180 days

Dashboards read per-minute continuous aggregates, so volume, error rate and p95 latency stay fast at full retention. Error groups and incidents are kept for 180 days.

We use only essential cookies to keep you signed in and the app working. With your consent we may enable optional analytics to help us improve e-volv. See our Privacy Policy and Terms.