Skip to main content
Send a copy of your usage logs to an observability endpoint or datastore you control, alongside Edgee’s own pipeline.
Available on hosted gateways only. ☁️ Self-hosted deployments configure their own OTLP usage-export target directly. See Kubernetes & Helm.

Supported protocols

Setup

From Org settings → Integrations (Infrastructure group), add one or more destinations. Pick a destination type, then fill in its fields.

OTLP

S3

ClickHouse

The table must already exist before you add the destination: Edgee never creates or migrates schema on your instance. Every row is sent via INSERT ... FORMAT JSONEachRow, so the table needs a column for each field Edgee sends, with matching names and compatible types.
This is the exact schema Edgee’s own internal ClickHouse pipeline uses, so you can copy it as-is. Adapt the ENGINE/PARTITION BY/ORDER BY clauses to your own retention and query patterns as long as every column above stays present. Usage logs are batched in memory per destination and flushed every 60 seconds, or sooner if the buffer grows past 8 MB. Each flush is one write, not one per log record. For S3, that write is one NDJSON object with one usage-log row per line; for ClickHouse, one INSERT ... FORMAT JSONEachRow into your configured table. S3 object keys are laid out as <prefix>/org=<your org id>/date=<yyyy-mm-dd>/hour=<HH>/<timestamp>.jsonl, the partitioning layout most S3-based query engines (Athena, BigQuery external tables, DuckDB) expect out of the box.

BigQuery

Usage rows are buffered in memory per destination and written through BigQuery streaming inserts in batches, every 60 seconds or sooner once 5,000 rows accumulate. Each row carries the same fields Edgee’s own ClickHouse pipeline stores. The destination table is created automatically on first delivery if it does not exist yet, provided the service account has the BigQuery Table Data Editor role; a pre-created table works too.

Snowflake

Before saving, generate a Programmatic Access Token for the user this destination writes as (ALTER USER <user> ADD PROGRAMMATIC ACCESS TOKEN <name>; the secret is shown once, so capture it immediately), and attach a network policy to that user. Snowflake refuses PAT authentication without one. A “Test Connection” that fails with Network policy is required is failing on this check. An allow-all policy satisfies the requirement:
Narrow ALLOWED_IP_LIST once you know which source IPs the traffic should come from. ALLOWED_IP_LIST takes IPv4 addresses only. If your account enforces IPv6, add the IPv6 counterpart with SET ALLOWED_IP6_LIST = ('::/0'). Both statements need a role holding the network-policy privileges, typically ACCOUNTADMIN. Rows are delivered over Snowflake’s SQL REST API rather than a driver connection, so there is no username field: the token resolves its own user. If the target table doesn’t already exist, Edgee creates it automatically the first time it flushes, with this shape: one typed column per usage-log field, the same fields the OTLP and S3 destinations carry.
Four columns (tags, compression_tool_stats, mcp_surface_stats, optimization_stats) are VARIANT rather than a scalar type, since each holds a list or a nested object, the standard Snowflake choice for that shape. Query them with Snowflake’s dot/bracket notation or FLATTEN, e.g. SELECT tags[0]::string FROM EDGEE_USAGE_LOGS_V1. Every other column is a plain scalar you can SELECT directly, e.g. SELECT model, total_cost FROM EDGEE_USAGE_LOGS_V1. The _V1 suffix is a schema version. It applies only to the auto-created default table, not to the name you pass in the Table field. If a future change needs a different column shape, it ships as EDGEE_USAGE_LOGS_V2 rather than altering _V1 in place, so existing rows and any views or pipes built on top of this table keep working unchanged. If you’d rather pre-create the table yourself (e.g. under a role that doesn’t grant CREATE TABLE), run the statement above against your own table name and pass it in the Table field. Usage logs are batched in memory per destination and flushed as one multi-row INSERT every 60 seconds, or sooner once 1,000 rows are buffered, delivered in chunks of 50 rows per statement. Larger chunks would put too many bound parameters in a single statement, since every usage-log field is its own column. You can configure more than one destination. Each active one gets its own copy of the logs.

Test before saving

Run two checks against the form before saving:
  • Test Connection: checks reachability only (a TCP/TLS handshake for OTLP, a bucket HEAD for S3, a ping for ClickHouse, a dataset lookup for BigQuery, a SELECT 1 probe for Snowflake).
  • Send Log: sends one real log record through the full path, in the destination’s protocol, so you can confirm your endpoint or bucket actually receives it.

Security

Secret values (OTLP header values, an S3 destination’s secret access key, a ClickHouse destination’s password, a BigQuery destination’s service account key, a Snowflake destination’s Programmatic Access Token) are encrypted at rest and masked (********) on every read, the same handling Edgee uses for BYOK provider keys. Plaintext values are never returned once saved. Editing a destination requires re-entering its secret, since saving fully replaces the stored config.

Delivery semantics

  • Usage logs keep reaching Edgee’s internal pipeline unchanged, regardless of what you configure here.
  • Forwarding is additive and asynchronous: a slow or failing destination never blocks or delays internal delivery, and never affects your other destinations.
  • The feature is entirely opt-in: no destination configured means no behavior change and no extra calls.