Skip to content

InfluxDB

zero exposes InfluxDB (and other time-series stores) through a unified, type-erased ctx.Timeseries handle.

Write points and run Flux queries with the same calls regardless of backend in src/datasource/specialized/timeseriesInterface.zig.

ctx.Timeseries is optional:

it is null until INFLUXDB_URL (plus INFLUXDB_ORG and INFLUXDB_BUCKET) is configured, so always guard with if (ctx.Timeseries) |ts| { ... } else { notConfigured }.

Configuration

bash
# App configs
APP_ENV=dev
APP_NAME=basic
APP_VERSION=1.0.0
LOG_LEVEL=info
HTTP_PORT=8080

# InfluxDB (time-series)
INFLUXDB_URL=http://localhost:8086
INFLUXDB_ORG=zero
INFLUXDB_BUCKET=metrics
# Optional (required if the bucket is token-protected)
INFLUXDB_TOKEN=my-super-secret-token
EnvRequiredDescription
INFLUXDB_URLyesBase URL of the InfluxDB instance.
INFLUXDB_ORGyesOrganisation.
INFLUXDB_BUCKETyesDefault bucket for writes/queries.
INFLUXDB_TOKENnoAPI token (required for secured buckets).

API

zig
// Write a point. tags/fields use InfluxDB line-protocol syntax.
try ctx.Timeseries.write(ctx, "cpu", "host=server1", "usage=42.1", null);

// Run a Flux query — returns raw CSV from InfluxDB.
const csv = try ctx.Timeseries.query(ctx, "from(bucket:\"metrics\") |> range(start: -1h)");
defer ctx.allocator.free(csv);

write takes measurement, tags, fields (both line-protocol strings), and an optional timestamp (?i64; pass null to use server time).

query runs a Flux string and returns the result as CSV text — free it with defer ctx.allocator.free(...).

Example handler

zig
pub fn writePoint(ctx: *Context) !void {
    if (ctx.Timeseries) |ts| {
        const body = ctx.request.body() orelse "";
        const parsed = try std.json.parseFromSlice(struct {
            measurement: []const u8,
            tags: []const u8 = "",
            fields: []const u8,
            ts: ?i64 = null,
        }, ctx.allocator, body, .{});
        defer parsed.deinit();
        try ts.write(ctx, parsed.value.measurement, parsed.value.tags, parsed.value.fields, parsed.value.ts);
        try ctx.response.json(.{ .status = "written" }, .{});
    } else {
        ctx.response.setStatus(.not_implemented);
        try ctx.response.json(.{ .message = "INFLUXDB_* not configured" }, .{});
    }
}

pub fn queryFlux(ctx: *Context) !void {
    if (ctx.Timeseries) |ts| {
        const q = if (ctx.request.method == .POST)
            (ctx.request.body() orelse "")
        else
            (try ctx.request.query()).get("q") orelse "";
        const csv = try ts.query(ctx, q);
        defer ctx.allocator.free(csv);
        ctx.response.content_type = .TEXT;
        try ctx.response.writer().writeAll(csv);
    }
}

Recommendation

🚩 Use the ctx allocator wherever possible; it is tied to the request lifecycle, so its memory is released automatically and you avoid leaks.

See the runnable zero-timeseries example and the implementation in src/datasource/specialized/influxdb.zig.