Skip to main content

Grafana Stack Backend

Uses Loki (LogQL) for logs, Prometheus (PromQL) for metrics, and Grafana Tempo for distributed tracing. The best choice for self-hosted environments and local development.

TINKR_BACKEND=grafana

Components

ComponentPurposeDefault port
LokiLog aggregation3100
PrometheusMetrics storage9090
TempoDistributed tracing3200
Grafana UIVisualization3000

All four are included in the Tinkr Docker Compose stack.


Environment variables

VariableRequiredDescription
GRAFANA_LOKI_URLYesLoki base URL (e.g. http://loki:3100)
GRAFANA_PROMETHEUS_URLYesPrometheus base URL (e.g. http://prometheus:9090)
GRAFANA_TEMPO_URLNoTempo base URL (e.g. http://tempo:3200)
GRAFANA_API_KEYNoGrafana API key (for managed Grafana Cloud)

Profile configuration

~/.tinkr/config.toml
[profiles.default]
backend = "grafana"
loki_url = "env:GRAFANA_LOKI_URL"
prometheus_url = "env:GRAFANA_PROMETHEUS_URL"
tempo_url = "env:GRAFANA_TEMPO_URL"

Log query (LogQL)

Tinkr constructs LogQL queries against Loki:

{app="payments-api"} |= "ERROR" | json | line_format "{{.level}} {{.message}}"

The app label must match your Loki label configuration. Tinkr uses the service name as the label value.

Label configuration

Ensure your log shipper (Promtail, Alloy, Fluent Bit) sets an app or service_name label:

promtail-config.yml
scrape_configs:
- job_name: payments-api
static_configs:
- targets: [localhost]
labels:
app: payments-api
__path__: /var/log/payments-api/*.log

Metrics (PromQL)

Tinkr queries Prometheus using PromQL:

rate(http_requests_total{job="payments-api"}[5m])

The service name is matched against the job label. Ensure your scrape config sets the job label to match the Tinkr service name.

Common Prometheus metrics

# Request rate
rate(http_requests_total[5m])

# Error rate
rate(http_requests_total{status=~"5.."}[5m])

# P99 latency
histogram_quantile(0.99, rate(http_request_duration_seconds_bucket[5m]))

# Memory usage
process_resident_memory_bytes

Distributed tracing (Tempo)

Tinkr queries Tempo's HTTP API to search traces:

GET /api/search?service.name=payments-api&start=1712498400&end=1712502000

Traces must be sent to Tempo. Most OpenTelemetry SDKs can export to Tempo via OTLP:

otel-collector-config.yml
exporters:
otlp:
endpoint: http://tempo:4317

Or configure the OTLP SDK directly:

from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter
exporter = OTLPSpanExporter(endpoint="http://tempo:4317", insecure=True)

Local development

Run Tinkr locally with Loki + Prometheus + Grafana using Docker:

# Pull and run Tinkr
docker run -d --name tinker -p 8000:8000 \
-e ANTHROPIC_API_KEY=sk-ant-... \
-e TINKR_BACKEND=grafana \
-e GRAFANA_LOKI_URL=http://loki:3100 \
-e GRAFANA_PROMETHEUS_URL=http://prometheus:9090 \
-v ~/.tinkr:/root/.tinkr \
tinker:local

Build the image first:

git clone https://github.com/gettinker/tinkr && cd tinkr && docker build -t tinker:local .

Or run directly from source:

git clone https://github.com/gettinker/tinkr
cd tinkr
cd tinker
uv sync
TINKR_BACKEND=grafana uv run tinker-server

Grafana Cloud

For Grafana Cloud (managed), set:

GRAFANA_LOKI_URL=https://logs-prod-xxx.grafana.net
GRAFANA_PROMETHEUS_URL=https://prometheus-prod-xxx.grafana.net
GRAFANA_API_KEY=glsa_xxxxxxxxxxxx

Authentication is via the Authorization: Bearer <api-key> header on all Loki and Prometheus requests.