# Capture and explore events

Define a dataset, connect your application and investigate typed event data.

Events turns application activity into a source you can search, chart and investigate. A dataset defines retention, optional masking and the typed fields available for analysis. Its managed source appears alongside your other query sources.

## Set up a dataset

Open **Events**, choose or create a dataset, and select its event destination. Destinations can use a separately configured event service; managed cloud capacity has its own provisioning and billing flow. Dataset configuration is available before storage is ready, but ingestion and real searches need a working destination.

Choose retention when creating the dataset. Retention cannot be edited afterward. Add typed dimensions for values you intend to filter or aggregate: text, number, boolean or date/time. Field names and types are immutable; add a new field when meaning changes.

Use stable namespaces and groups such as `production` and `orders`. They organize events; they are not tenant isolation boundaries. The dataset credential determines ingestion authority.

## Connect an application

Choose **Connect application** to obtain the dataset's endpoint and create an ingestion key. Copy the key when it is shown and store it in the producer's secret configuration. These keys append events to their dataset; they do not grant dashboard or account access.

The batch envelope includes a stable batch ID and events with an immutable ID, namespace, group, type, timestamp and schema version. Typed `dimensions` are queryable. Optional `data` holds inspection details.

```json
{
  "version": 1,
  "batchId": "ab84bb9c-93fa-4ce8-bb75-dcb787bc2a07",
  "events": [
    {
      "id": "order-123-created",
      "namespace": "production",
      "group": "orders",
      "type": "order.created",
      "timestamp": "2026-10-23T12:00:00.000Z",
      "schemaVersion": 1,
      "dimensions": { "orderId": "123" },
      "data": { "origin": "checkout" }
    }
  ]
}
```

Declare `orderId` as a text dimension before sending this example, and use a current timestamp within the dataset's retention window. Do not reuse an event identity for different contents. If a delivery times out, retry the same batch ID and payload. A `202` means durable queue acceptance; the event may not be queryable immediately.

Masking applies only to the field names and paths you configure. There is no automatic secret detection. Keep sensitive payloads out of event data unless their collection and access are intended.

## Search and investigate

Select a time range and add conditions on core fields or declared dimensions. Text search covers event IDs, types, namespaces, groups and declared text dimensions. Raw `data` is inspection-only and is not searched or scanned for chart calculations.

Submit the search, page through the bounded results, and open an event to fetch its details. Group matching events by up to four fields. Preserve the returned `total`, `hasMore` and `truncated` distinctions when using these operations through an agent or SDK; one page is not the complete dataset.

## Inspect a trace

In the dataset editor, choose **Add trace fields**. This adds missing fields without changing existing names or types. A conflicting field type must be resolved by choosing a compatible dataset; existing field types are immutable.

| Dimension        | Type   | Meaning                                 |
| ---------------- | ------ | --------------------------------------- |
| `trace_id`       | Text   | Shared trace identifier                 |
| `span_id`        | Text   | Span identifier within the trace        |
| `duration_ms`    | Number | Completed span duration in milliseconds |
| `parent_span_id` | Text   | Parent span, or omitted/null for a root |
| `span_name`      | Text   | Operation name                          |
| `service_name`   | Text   | Producing service                       |
| `span_status`    | Text   | `unset`, `ok` or `error`                |

The event's `timestamp` is the span start. The first three dimensions enable trace inspection; the other fields add hierarchy and context. The SDK exports `EVENT_TRACE_DIMENSIONS` for programmatic dataset creation and `spanEvent` for completed spans:

```ts
import { createEventClient, spanEvent } from 'bytesmap/events'

const events = createEventClient({
  endpoint: process.env.BYTESMAP_EVENTS_URL!,
  dataset: process.env.BYTESMAP_EVENT_DATASET!,
  token: process.env.BYTESMAP_EVENT_TOKEN!,
  namespace: 'production',
  group: 'orders',
})

await events.emit(
  spanEvent({
    traceId: '4bf92f3577b34da6a3ce929d0e0e4736',
    spanId: '00f067aa0ba902b7',
    name: 'GET /orders',
    service: 'api',
    start: requestStartedAt.toISOString(),
    durationMs: elapsedMs,
    status: 'ok',
    data: { route: '/orders' },
  }),
)
```

Configure the endpoint, dataset and ingestion key from **Connect application**, and supply your actual request timing and trace context. The helper validates nonzero 32-character hexadecimal trace IDs and 16-character span IDs, generates a stable event identity, and does not instrument your application or create parent context automatically. Fractional millisecond durations are supported; stored start timestamps have millisecond precision. Map completed spans from your instrumentation into these fields. BytesMap does not currently expose an OTLP collector endpoint.

Open an event and select **View trace**. **Waterfall** shows span start offsets and durations; **Tree** shows the same parent hierarchy. Expand or collapse branches, select a span, then open its original event. Elapsed time covers the earliest retained start through the latest retained end; overlapping durations are not added together. Colors identify services, and failures have an explicit error label.

The trace query reads only the selected dataset using its current read permission. An ingestion key cannot read traces. Results include at most 1,000 retained spans, or fewer when the source's row limit is lower. A limited result is marked incomplete. Missing parents, duplicate IDs, cyclic links and timing outside a parent are shown explicitly; a partial result is not a complete distributed trace. Refresh keeps existing spans visible while loading, but revoked access clears them.

Agents and SDK consumers can use `events.trace({ id: datasetId, traceId })`. It returns `events` and `truncated`; the query does not include inspection-only payloads. Fetch a selected original event with `events.inspect` using its ID, namespace and group. Trace reads retain the source's timeout and query limits; a row limit alone is not a bound on scanning work.

## Use events in a dashboard or workflow

Choose the dataset's managed source in a query. Its analytical view exposes typed nullable columns from the declared dimensions. Use the shared query and chart builder to count, filter, group or compare them over time.

Workflows can append events using an explicit event target and dataset ingestion permission. Saving a mapping does not send it. Use a test dataset when exercising effects.

Agents use the same [Events operations](https://bytesmap.com/docs/reference/events.md) and [destination operations](https://bytesmap.com/docs/reference/eventDestinations.md). Creating a reusable ingestion key remains an account action in the application.

For the complete wire limits, durable-delivery contract and service deployment settings, see the [event service reference](https://github.com/oblien/bytesmap/blob/main/apps/events/README.md).
