Packages
timeless_metrics
6.0.21
6.6.7
6.6.6
6.6.5
retired
6.6.4
retired
6.6.3
retired
6.6.2
retired
6.6.1
retired
6.6.0
retired
6.5.0
retired
6.4.2
retired
6.4.1
retired
6.4.0
retired
6.3.0
retired
6.2.6
retired
6.2.2
6.2.1
6.2.0
6.1.3
6.1.2
6.1.1
6.1.0
6.0.22
6.0.21
6.0.20
6.0.19
6.0.18
6.0.17
6.0.16
6.0.15
6.0.14
6.0.13
6.0.12
6.0.11
6.0.10
6.0.9
6.0.8
6.0.6
6.0.5
6.0.4
6.0.3
Embedded time series database for Elixir with a Rust-native hot path.
Current section
Files
Jump to
Current section
Files
timeless_metrics
README.md
README.md
<p align="center">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="docs/logo-dark.svg">
<source media="(prefers-color-scheme: light)" srcset="docs/logo-light.svg">
<img src="docs/logo-light.svg" width="300" alt="Timeless">
</picture>
</p>
<h3 align="center">Embedded Time Series Database for Elixir</h3>
<p align="center">
<a href="https://hex.pm/packages/timeless_metrics"><img src="https://img.shields.io/hexpm/v/timeless_metrics.svg" alt="Hex.pm"></a>
<a href="https://hexdocs.pm/timeless_metrics"><img src="https://img.shields.io/badge/docs-hexdocs-blue.svg" alt="Docs"></a>
<a href="LICENSE"><img src="https://img.shields.io/hexpm/l/timeless_metrics.svg" alt="License"></a>
</p>
---
> "I found it ironic that the first thing you do to time series data is squash the timestamp. That's how the name Timeless was born." --Mark Cotner
TimelessMetrics is an embedded time-series database for Elixir with a Rust-native hot path, built-in HTTP ingest/query APIs, retention, rollups, alerting, scraping, charts, and Prometheus/VictoriaMetrics compatibility.
It runs:
- as a library inside your Elixir application
- as a local service with the included HTTP API
- in memory-only mode for tests and constrained environments
## Current Architecture
The default engine is the Rust engine.
Hot-path responsibilities live in the Rust NIF:
- labeled writes and batched writes
- raw and aggregate range queries
- series index and label filtering
- chunk persistence and recovery
Elixir still owns the surrounding product surface:
- HTTP API
- background ingest workers
- alerts, annotations, metadata, and scrape target management
- rollups, retention orchestration, charts, dashboard, and PromQL handling
If you need the detailed design, start with [docs/architecture.md](docs/architecture.md).
## Documentation
- [Getting Started](docs/getting_started.md)
- [Configuration Reference](docs/configuration.md)
- [Architecture](docs/architecture.md)
- [API Reference](docs/API.md)
- [Alerting](docs/alerting.md)
- [Scraping](docs/scraping.md)
- [Annotations](docs/annotations.md)
- [Forecasting & Anomaly Detection](docs/forecasting.md)
- [Charts & Embedding](docs/charts.md)
- [Grafana Integration](docs/grafana.md)
- [Operations](docs/operations.md)
- [Capacity Planning](docs/capacity_planning.md)
- [Scaling](docs/scaling_options.md)
- [Benchmarks](bench/README.md)
## Highlights
- Rust-native storage engine enabled by default
- Embedded Elixir API plus optional HTTP API
- Prometheus text ingest, VictoriaMetrics JSON-line ingest, and Influx line protocol ingest
- Prometheus-compatible query endpoints for Grafana
- Fast batched writes and compact on-disk chunks
- Built-in dashboard, SVG charts, annotations, forecasting, anomaly detection, and alerts
- Scraping subsystem for pulling Prometheus targets into the local store
- Memory-only mode for ephemeral deployments and tests
## Quick Start
Add to `mix.exs`:
```elixir
{:timeless_metrics, "~> 6.0"}
```
Add to your supervision tree:
```elixir
children = [
{TimelessMetrics, name: :metrics, data_dir: "/var/lib/metrics"},
{TimelessMetrics.HTTP, store: :metrics, port: 8428}
]
```
Write and query:
```elixir
TimelessMetrics.write(:metrics, "cpu_usage", %{"host" => "web-1"}, 73.2)
{:ok, points} =
TimelessMetrics.query(:metrics, "cpu_usage", %{"host" => "web-1"},
from: System.os_time(:second) - 3600,
to: System.os_time(:second)
)
```
Memory-only mode:
```elixir
children = [
{TimelessMetrics, name: :metrics, mode: :memory},
{TimelessMetrics.HTTP, store: :metrics, port: 8428}
]
```
## Elixir API
Writes:
```elixir
TimelessMetrics.write(:metrics, "cpu_usage", %{"host" => "web-1"}, 73.2)
TimelessMetrics.write_batch(:metrics, [
{"cpu_usage", %{"host" => "web-1"}, 73.2},
{"mem_usage", %{"host" => "web-1"}, 4096.0}
])
```
Queries:
```elixir
{:ok, points} =
TimelessMetrics.query(:metrics, "cpu_usage", %{"host" => "web-1"},
from: System.os_time(:second) - 3600
)
{:ok, series} =
TimelessMetrics.query_multi(:metrics, "cpu_usage", %{"host" => "web-1"},
from: System.os_time(:second) - 3600
)
{:ok, buckets} =
TimelessMetrics.query_aggregate(:metrics, "cpu_usage", %{"host" => "web-1"},
from: System.os_time(:second) - 3600,
bucket: {60, :seconds},
aggregate: :avg
)
```
Discovery and operations:
```elixir
TimelessMetrics.list_metrics(:metrics)
TimelessMetrics.list_series(:metrics, "cpu_usage")
TimelessMetrics.label_values(:metrics, "cpu_usage", "host")
TimelessMetrics.info(:metrics)
TimelessMetrics.flush(:metrics)
TimelessMetrics.backup(:metrics, "/tmp/metrics-backup")
```
## HTTP API
Core endpoints:
| Method | Path | Description |
|--------|------|-------------|
| `POST` | `/api/v1/import` | VictoriaMetrics JSON-line ingest |
| `POST` | `/api/v1/import/prometheus` | Prometheus text ingest |
| `POST` | `/write` | Influx line protocol ingest |
| `GET` | `/api/v1/query` | Latest-value query |
| `GET` | `/api/v1/query_range` | Native range query |
| `GET` | `/api/v1/export` | Multi-series export |
| `GET` | `/prometheus/api/v1/query` | Prometheus instant query |
| `GET` | `/prometheus/api/v1/query_range` | Prometheus range query |
| `GET` | `/prometheus/api/v1/labels` | Prometheus label names |
| `GET` | `/prometheus/api/v1/series` | Prometheus series listing |
| `GET` | `/chart` | SVG chart |
| `GET` | `/health` | Lightweight health/status |
| `GET` | `/health/detailed` | More expensive store diagnostics |
Example ingest:
```bash
curl -X POST http://localhost:8428/api/v1/import/prometheus \
-H "Content-Type: text/plain" \
--data-binary '
cpu_usage{host="web-1"} 73.2
cpu_usage{host="web-2"} 61.8
'
```
Example range query:
```bash
curl 'http://localhost:8428/api/v1/query_range?metric=cpu_usage&host=web-1&from=1700000000&to=1700003600&step=60'
```
Example Prometheus-compatible query:
```bash
curl 'http://localhost:8428/prometheus/api/v1/query_range?query=cpu_usage{host="web-1"}&start=1700000000&end=1700003600&step=60'
```
## Benchmarks
The maintained benchmark set lives under [bench/](bench/README.md):
- embedded API throughput: [bench/write_bench.exs](bench/write_bench.exs)
- HTTP concurrency: [bench/http_concurrency.exs](bench/http_concurrency.exs)
- realistic workload ramp: [bench/realistic_workload.exs](bench/realistic_workload.exs)
- TSBS harness: [bench/tsbs_bench.exs](bench/tsbs_bench.exs)
- VictoriaMetrics comparison: [bench/vs_victoriametrics.exs](bench/vs_victoriametrics.exs)
## Notes
- The legacy Elixir engine still exists behind explicit `engine:` selection for compatibility and migration work, but the default path is Rust.
- The rust build may emit the upstream `rustler::resource!` `non_local_definitions` warning. That warning is currently expected.