@@ -59,12 +59,19 @@ implementation.
5959- ` GET /v1/stream/{name}/_routing_keys ` list routing keys alphabetically
6060- ` GET /v1/stream/{name}/_index_status ` get per-stream index status
6161- ` GET /v1/stream/{name}/_details ` get combined stream details
62+ - ` POST /v1/stream/{name}/_otlp/v1/traces ` ingest OTLP traces into an
63+ ` otel-traces ` stream
6264
63- ### 2.5 Streams collection
65+ ### 2.5 Observability resources
66+
67+ - ` POST /v1/traces ` ingest OTLP traces into ` DS_OTLP_TRACES_STREAM `
68+ - ` POST /v1/observe/request ` correlate request events and trace spans
69+
70+ ### 2.6 Streams collection
6471
6572- ` GET /v1/streams ` list streams
6673
67- ### 2.6 Server inspection
74+ ### 2.7 Server inspection
6875
6976- ` GET /v1/server/_details ` get server-scoped configured limits and live runtime state
7077
@@ -211,6 +218,132 @@ Optional fields:
211218- ` group_by `
212219- ` measures `
213220
221+ ### 4.4 OTLP trace ingestion
222+
223+ ` POST /v1/traces ` accepts OTLP trace export requests and writes accepted spans
224+ to the stream named by ` DS_OTLP_TRACES_STREAM ` .
225+
226+ Rules:
227+
228+ - ` DS_OTLP_TRACES_STREAM ` must be configured, otherwise the endpoint returns
229+ ` 400 ` .
230+ - If the target stream does not exist and ` DS_OTLP_AUTO_CREATE=true ` , the
231+ server creates an ` application/json ` stream, installs the ` otel-traces `
232+ profile, uploads the profile-owned schema registry, publishes a manifest, and
233+ then appends accepted spans.
234+ - If the target stream does not exist and auto-create is not enabled, the
235+ endpoint returns ` 404 ` .
236+ - The target stream must have the ` otel-traces ` profile.
237+
238+ ` POST /v1/stream/{name}/_otlp/v1/traces ` accepts the same OTLP payloads for an
239+ explicit stream. The stream must already exist and have the ` otel-traces `
240+ profile.
241+
242+ Supported request content types:
243+
244+ - ` application/x-protobuf `
245+ - ` application/json `
246+
247+ Supported content encodings:
248+
249+ - no encoding / ` identity `
250+ - ` gzip `
251+
252+ Successful full acceptance returns HTTP ` 200 ` with an empty OTLP
253+ ` ExportTraceServiceResponse ` for protobuf or ` {} ` for JSON. Partial acceptance
254+ also returns HTTP ` 200 ` and includes OTLP partial-success information with the
255+ number of rejected spans and an error message. Clients must not retry spans
256+ rejected by a partial-success response.
257+
258+ Malformed payloads and requests that exceed resource-span or scope-span limits
259+ return ` 400 ` . Compressed or decoded OTLP bodies that exceed the configured byte
260+ limits return ` 413 ` . Unsupported content types or content encodings return
261+ ` 415 ` . If a decodable request exceeds the configured span-count limit, the
262+ server accepts the first spans up to the limit and returns HTTP ` 200 ` with OTLP
263+ partial-success information for the rejected overflow. Accepted spans are
264+ appended as canonical JSON span records using ` traceId ` as the routing key.
265+
266+ ### 4.5 Request observability
267+
268+ ` POST /v1/observe/request ` correlates an event stream and a trace stream at
269+ query time. It does not append data and does not create a new stream profile.
270+
271+ Request body:
272+
273+ ``` json
274+ {
275+ "streams" : {
276+ "events" : " app-events" ,
277+ "traces" : " app-traces"
278+ },
279+ "lookup" : {
280+ "requestId" : " req_123"
281+ },
282+ "time" : {
283+ "from" : " 2026-03-27T00:00:00.000Z" ,
284+ "to" : " 2026-03-28T00:00:00.000Z" ,
285+ "paddingMs" : 5000
286+ },
287+ "include" : {
288+ "events" : true ,
289+ "trace" : true ,
290+ "timeline" : true ,
291+ "raw" : false
292+ },
293+ "limits" : {
294+ "events" : 100 ,
295+ "spans" : 5000
296+ }
297+ }
298+ ```
299+
300+ ` lookup ` must contain exactly one of ` requestId ` , ` traceId ` , or ` spanId ` .
301+ ` streams.events ` is required when ` include.events=true ` ; ` streams.traces ` is
302+ required when ` include.trace=true ` .
303+ The supported request-observability pairing is ` streams.events ` with profile
304+ ` evlog ` and ` streams.traces ` with profile ` otel-traces ` .
305+
306+ The endpoint uses the configured ` _search ` registries for the referenced
307+ streams. Event and trace streams must expose the profile correlation capability.
308+ ` include.raw ` defaults to ` false ` . With ` raw=false ` , ` evlog.primary ` ,
309+ ` evlog.matches[].source ` , and ` trace.spans[] ` contain compact normalized records
310+ that keep IDs, timestamps, service/request fields, status/error fields, and
311+ safe request/operation summaries while omitting raw context, attributes,
312+ resources, span events, links, statements, URLs, stack traces, redaction
313+ metadata, and identity internals. Timeline items omit ` data ` . With ` raw=true ` ,
314+ those response fields include the full profile-normalized source records and
315+ timeline source data.
316+ The response contains:
317+
318+ - ` lookup `
319+ - ` summary `
320+ - ` evlog `
321+ - ` trace `
322+ - ` timeline `
323+ - ` coverage `
324+
325+ The trace response deduplicates returned spans by ` traceId:spanId ` for the
326+ tree, service map, errors, and critical path. Duplicate span records remain in
327+ the underlying append-only stream.
328+
329+ ` trace.rootSpanId ` is selected from all returned root candidates by preferring
330+ likely request roots: no parent, server kind, HTTP fields, request ID, and then
331+ duration. Other roots remain in ` trace.tree ` . ` trace.criticalPath ` is a
332+ best-effort interval-aware latency path from the selected root when one exists.
333+
334+ ` coverage.events ` and ` coverage.traces ` de-duplicate ` hits ` , ` unique_hits ` , and
335+ ` total.value ` by stream and offset across overlapping lookup searches.
336+ ` query_count ` and ` batch_count ` report the number of underlying ` _search `
337+ batches used. ` total.relation ` is ` gte ` when limits, timeouts, incomplete
338+ coverage, or underlying lower-bound totals prevent an exact unique total. Each
339+ coverage object also includes ` queries ` , preserving per-query diagnostics such
340+ as ` q ` , returned ` hits ` , backend ` total ` , page count, timeout state, and limit
341+ state.
342+
343+ The endpoint returns ` 400 ` for invalid request bodies, unsupported profile
344+ combinations, or streams without search configuration. Missing streams return
345+ ` 404 ` .
346+
214347---
215348
216349## 5. Offsets
0 commit comments