> ## Documentation Index
> Fetch the complete documentation index at: https://docs.rootprint.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Indexes

> Understand how Rootprint uses indexes to organize and query your log data.

Indexes organize your logs into searchable log sources. Each index defines a schema that determines how log fields are stored and queried. When you attach an existing Quickwit instance, its indexes appear automatically as log sources in the UI.

## Built-in OpenTelemetry index

Rootprint ships with `otel-logs-v0_9` as its default OpenTelemetry logs index, the current schema version bundled with Quickwit `v0.9.0-rc`. If you attach an older Quickwit release (0.8.x and earlier), the default index is named `otel-logs-v0_7` instead, so check the index name before assuming. The schema maps directly to the [OpenTelemetry Log Data Model](https://opentelemetry.io/docs/specs/otel/logs/data-model/) and is ready to use without any configuration.

### Rootprint field defaults

Until you save explicit settings for an index, Rootprint uses these OpenTelemetry-friendly defaults to render its rows and detail drawer:

| Rootprint field | Default path                      |
| --------------- | --------------------------------- |
| Level field     | `severity_text`                   |
| Message field   | `body.message`                    |
| Traceback field | `attributes.exception.stacktrace` |

The bundled OTel index uses these paths out of the box. For custom-schema indexes, override any of them in the index's [Configuration tab](/configuration/manage-indexes#field-role-mappings).

### Schema

The index uses `strict` mode: every document must match the schema exactly. Arbitrary fields are not accepted at the top level. Instead, all custom key-value data goes into the `attributes`, `resource_attributes`, or `scope_attributes` JSON fields.

#### Core fields

These fields carry the primary log data.

| Field                      | Type       | Search        | Description                                                                              |
| -------------------------- | ---------- | ------------- | ---------------------------------------------------------------------------------------- |
| `timestamp_nanos`          | `datetime` | fast          | Timestamp in nanoseconds UTC. Primary time field for range filtering.                    |
| `observed_timestamp_nanos` | `datetime` | indexed       | When the collector observed the event.                                                   |
| `severity_text`            | `text`     | indexed, fast | Severity level (`INFO`, `ERROR`). Raw tokenizer — exact match.                           |
| `severity_number`          | `u64`      | indexed, fast | Numeric severity: 1-4 TRACE, 5-8 DEBUG, 9-12 INFO, 13-16 WARN, 17-20 ERROR, 21-24 FATAL. |
| `body`                     | `json`     | indexed       | Log message body. Default tokenizer — full-text searchable.                              |
| `service_name`             | `text`     | indexed, fast | Derived from `resource_attributes["service.name"]`. Raw tokenizer.                       |

#### Attributes

Key-value metadata on the log event and its resource.

| Field                               | Type   | Search        | Description                                                       |
| ----------------------------------- | ------ | ------------- | ----------------------------------------------------------------- |
| `attributes`                        | `json` | indexed, fast | Log-level metadata. Raw tokenizer, `expand_dots` enabled.         |
| `resource_attributes`               | `json` | indexed, fast | Infrastructure metadata (host, k8s, cloud). Same as `attributes`. |
| `dropped_attributes_count`          | `u64`  | —             | Dropped log-level attributes count.                               |
| `resource_dropped_attributes_count` | `u64`  | —             | Dropped resource attributes count.                                |

#### Trace context

Fields for correlating logs with distributed traces.

| Field         | Type    | Search  | Description                           |
| ------------- | ------- | ------- | ------------------------------------- |
| `trace_id`    | `bytes` | indexed | 16-byte trace ID in hex.              |
| `span_id`     | `bytes` | indexed | 8-byte span ID in hex.                |
| `trace_flags` | `u64`   | —       | W3C trace flags bitmask. Stored only. |

#### Instrumentation scope

Metadata about the library that produced the log. Stored but not indexed, available in results but not searchable.

| Field                            | Type   | Description                      |
| -------------------------------- | ------ | -------------------------------- |
| `scope_name`                     | `text` | Instrumentation library name.    |
| `scope_version`                  | `text` | Instrumentation library version. |
| `scope_attributes`               | `json` | Scope-level key-value metadata.  |
| `scope_dropped_attributes_count` | `u64`  | Dropped scope attributes count.  |

### Indexed vs fast fields

Understanding these two properties helps when querying and designing custom indexes:

* **Indexed**: the field is added to an inverted index and is searchable via text queries. When `indexed: false`, you cannot use the field in search predicates.
* **Fast**: the field is stored in column-oriented storage (similar to Lucene DocValues). Enables efficient range queries, aggregations, and sorting. A field can be fast without being indexed, and vice versa.

For example, `timestamp_nanos` is fast but not indexed. It is used for fast time-range filtering, not text search.

### Tokenizers

The index uses two tokenizer strategies:

| Tokenizer | Behavior                                                                     | Used by                                                              |
| --------- | ---------------------------------------------------------------------------- | -------------------------------------------------------------------- |
| `raw`     | No processing. The entire value is one token. Best for exact-match fields.   | `service_name`, `severity_text`, `attributes`, `resource_attributes` |
| `default` | Splits on whitespace and punctuation, lowercases. Best for free-text search. | `body`                                                               |

### Query examples

```bash theme={"theme":"github-light"}
# Full-text search in the log body (default search field)
body.message:timeout

# Exact severity match
severity_text:ERROR

# Numeric severity range (all WARN and above)
severity_number:[13 TO *]

# Filter by service
service_name:api-gateway

# Search structured attributes (exact match)
attributes.http.method:POST

# Correlate by trace ID
trace_id:abc123def456...
```

### Example payload

```json theme={"theme":"github-light"}
{
	"timestamp_nanos": 1776340800000000000,
	"observed_timestamp_nanos": 1776340800000000000,
	"severity_text": "INFO",
	"severity_number": 9,
	"body": { "message": "User logged in" },
	"service_name": "frontend",
	"attributes": { "user_id": "alice" },
	"resource_attributes": { "service.name": "frontend", "host.name": "node-1" },
	"trace_id": "4bf92f3577b34da6a3ce929d0e0e4736",
	"span_id": "00f067aa0ba902b7",
	"trace_flags": 1,
	"dropped_attributes_count": 0,
	"resource_dropped_attributes_count": 0,
	"scope_name": "my-library",
	"scope_version": "1.0.0",
	"scope_attributes": {},
	"scope_dropped_attributes_count": 0
}
```

<Tip>
  Because the schema uses `strict` mode, any fields not defined in the schema are rejected. When
  sending logs manually, ensure your payload only includes fields that match the schema. When using
  an OpenTelemetry collector, Quickwit handles field mapping automatically.
</Tip>

## Custom indexes

For non-OpenTelemetry data (audit trails, custom application events, third-party log formats), create an index with the schema your data needs. See [Create a custom index](/configuration/custom-indexes) for the Create-index form: field types, tokenizers, and retention policy. Once it exists, configure how Rootprint maps its fields from the index's [Configuration tab](/configuration/manage-indexes#configuration-tab).

## Next steps

* [Send logs](/send-logs/overview) to start ingesting data into any index.
* [Search query syntax](/search/query-language) to learn what users can type in the search box.
* [Configure index fields](/configuration/manage-indexes#field-role-mappings) to map log level, message, and traceback for your schema.
