- Updated: March 24, 2026
- 6 min read
Step‑by‑Step Observability Tutorial for OpenClaw Full‑Stack Template
OpenClaw observability is achieved by wiring Prometheus‑Grafana for metrics, Winston‑Logstash‑Kibana for logging, and OpenTelemetry‑Jaeger for tracing, creating a full‑stack monitoring stack that works out‑of‑the‑box with the OpenClaw template.
1. Introduction
If you’re deploying the OpenClaw Full‑Stack Template on UBOS, you already have a production‑ready Node.js/React application. The next logical step is to make the system observable so you can detect performance regressions, debug errors, and understand user journeys before they become incidents.
This tutorial walks you through a hands‑on, step‑by‑step setup of:
- Metrics collection with Prometheus and visualization in Grafana
- Structured logging using Winston, shipping logs to Logstash, and exploring them in Kibana
- Distributed tracing via OpenTelemetry SDK and Jaeger UI
By the end you’ll have a unified observability stack that can be extended to any micro‑service you add later.
2. Prerequisites
Before you start, ensure you have the following:
- A running OpenClaw instance on UBOS (Docker or native). Host OpenClaw on UBOS for a quick start.
- Docker Compose installed on your workstation (required for Prometheus, Grafana, Logstash, Kibana, and Jaeger containers).
- Node.js ≥ 18 and npm ≥ 9.
- Basic familiarity with YAML and JavaScript configuration files.
3. Metrics – Prometheus & Grafana
a. Install Prometheus
Create a prometheus directory in the root of your OpenClaw project and add docker-compose.yml for the Prometheus service:
version: '3.8'
services:
prometheus:
image: prom/prometheus:latest
container_name: prometheus
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml
ports:
- "9090:9090"
restart: unless-stopped
Next, create prometheus.yml to scrape the OpenClaw metrics endpoint:
global:
scrape_interval: 15s
evaluation_interval: 15s
scrape_configs:
- job_name: 'openclaw'
static_configs:
- targets: ['host.docker.internal:3001'] # OpenClaw metrics port
Start Prometheus:
docker-compose -f prometheus/docker-compose.yml up -db. Configure OpenClaw metrics endpoint
OpenClaw already ships a /metrics route powered by prom-client. If you disabled it, re‑enable it in src/server/metrics.js:
const client = require('prom-client');
const collectDefaultMetrics = client.collectDefaultMetrics;
collectDefaultMetrics({ timeout: 5000 });
module.exports = (req, res) => {
res.set('Content-Type', client.register.contentType);
res.end(client.register.metrics());
};
Register the route in src/server/index.js:
const metricsHandler = require('./metrics');
app.get('/metrics', metricsHandler);
c. Set up Grafana dashboards
Add a Grafana service to the same docker‑compose.yml (or spin it up separately):
grafana:
image: grafana/grafana:latest
container_name: grafana
ports:
- "3000:3000"
environment:
- GF_SECURITY_ADMIN_PASSWORD=admin
volumes:
- grafana-data:/var/lib/grafana
restart: unless-stopped
volumes:
grafana-data:
After docker-compose up -d, open http://localhost:3000 (admin/admin). Add Prometheus as a data source:
- Configuration → Data Sources → Add data source → Prometheus
- URL:
http://prometheus:9090 - Save & test.
Import a ready‑made dashboard JSON (search “Node.js Exporter”). The dashboard will display CPU, memory, request latency, and custom OpenClaw counters.
4. Logging – Winston & Logstash
a. Add Winston logger to OpenClaw
Install Winston and a JSON formatter:
npm install winston winston-daily-rotate-fileCreate src/logger.js:
const { createLogger, format, transports } = require('winston');
const { combine, timestamp, json } = format;
const DailyRotateFile = require('winston-daily-rotate-file');
const logger = createLogger({
level: 'info',
format: combine(timestamp(), json()),
transports: [
new transports.Console(),
new DailyRotateFile({
filename: 'logs/openclaw-%DATE%.log',
datePattern: 'YYYY-MM-DD',
maxFiles: '14d'
})
]
});
module.exports = logger;
Replace console.log calls throughout the codebase with logger.info(...) or logger.error(...). Example in an Express error handler:
app.use((err, req, res, next) => {
logger.error('Unhandled error', { message: err.message, stack: err.stack });
res.status(500).json({ error: 'Internal Server Error' });
});
b. Ship logs to Logstash
Run a Logstash container that reads the rotating log files and forwards them to Elasticsearch:
version: '3.8'
services:
elasticsearch:
image: docker.elastic.co/elasticsearch/elasticsearch:8.9.0
environment:
- discovery.type=single-node
- xpack.security.enabled=false
ports:
- "9200:9200"
volumes:
- es-data:/usr/share/elasticsearch/data
logstash:
image: docker.elastic.co/logstash/logstash:8.9.0
volumes:
- ./logstash/pipeline:/usr/share/logstash/pipeline
- ./logs:/var/log/openclaw
ports:
- "5044:5044"
depends_on:
- elasticsearch
volumes:
es-data:
Create logstash/pipeline/logstash.conf:
input {
file {
path => "/var/log/openclaw/*.log"
start_position => "beginning"
sincedb_path => "/dev/null"
codec => json
}
}
filter {
# Add any enrichment here (e.g., parse request IDs)
}
output {
elasticsearch {
hosts => ["http://elasticsearch:9200"]
index => "openclaw-logs-%{+YYYY.MM.dd}"
}
stdout { codec => rubydebug }
}
Start the stack:
docker-compose -f logging/docker-compose.yml up -dc. Visualize logs in Kibana
Spin up Kibana alongside Elasticsearch:
kibana:
image: docker.elastic.co/kibana/kibana:8.9.0
ports:
- "5601:5601"
depends_on:
- elasticsearch
Open http://localhost:5601, create an index pattern openclaw-logs-*, and explore logs with filters such as level: "error" or requestId. Kibana’s Discover view makes it trivial to trace a request across multiple services.
5. Tracing – OpenTelemetry & Jaeger
a. Instrument OpenClaw with OpenTelemetry SDK
Install the OpenTelemetry packages for Node.js:
npm install @opentelemetry/api @opentelemetry/sdk-node @opentelemetry/instrumentation-http @opentelemetry/instrumentation-express @opentelemetry/exporter-jaegerCreate src/tracing.js:
const { NodeSDK } = require('@opentelemetry/sdk-node');
const { getNodeAutoInstrumentations } = require('@opentelemetry/auto-instrumentations-node');
const { JaegerExporter } = require('@opentelemetry/exporter-jaeger');
const exporter = new JaegerExporter({
endpoint: 'http://jaeger:14268/api/traces',
});
const sdk = new NodeSDK({
traceExporter: exporter,
instrumentations: [getNodeAutoInstrumentations()],
});
sdk.start()
.then(() => console.log('🛠️ OpenTelemetry initialized'))
.catch(err => console.error('❌ OpenTelemetry failed to start', err));
Import this module at the very top of src/server/index.js so tracing starts before any request handling:
require('./tracing'); // Must be first
const express = require('express');
...
b. Export traces to Jaeger
Add a Jaeger container to your docker‑compose.yml:
jaeger:
image: jaegertracing/all-in-one:1.53
container_name: jaeger
ports:
- "16686:16686" # UI
- "14268:14268" # Collector
restart: unless-stopped
Run the updated compose file:
docker-compose up -d jaegerc. View trace data in Jaeger UI
Navigate to http://localhost:16686. Select the service “openclaw” and you’ll see a list of recent traces. Clicking a trace reveals a flame‑graph of each middleware, database call, and external API request, complete with latency breakdowns.
6. Putting It All Together – Full observability stack
Below is a concise diagram (placeholder) that illustrates how the components interact:
Key takeaways:
- Metrics – Prometheus scrapes
/metricsevery 15 seconds; Grafana visualizes them in real time. - Logs – Winston writes JSON logs; Logstash forwards them to Elasticsearch; Kibana provides searchable dashboards.
- Traces – OpenTelemetry auto‑instrumentation captures request spans; Jaeger stores and displays end‑to‑end latency.
All services run as Docker containers, making the stack portable across development, staging, and production environments. You can scale each component independently (e.g., run multiple Prometheus instances behind a federation layer) without touching the OpenClaw code.
7. Conclusion and next steps
Implementing a complete observability pipeline for the OpenClaw Full‑Stack Template empowers developers and DevOps engineers to:
- Detect performance regressions before users notice them.
- Correlate errors across logs, metrics, and traces for faster root‑cause analysis.
- Maintain a single source of truth for system health, satisfying both SRE and compliance requirements.
Next, consider extending the stack:
- Enable Prometheus Alertmanager to receive Slack or email alerts on SLA breaches.
- Integrate Elastic APM for deeper transaction insights.
- Leverage OpenTelemetry Collector as a unified pipeline for metrics, logs, and traces.
With the observability foundation in place, your OpenClaw deployment is ready for production workloads, continuous improvement, and scaling to enterprise‑grade traffic.
© 2026 UBOS – All rights reserved.