Metrics
Send application metrics to JuhJuh using gauges, counters, histograms, and sums. Track performance over time with tags, dashboards, and automatic alert evaluation. OpenTelemetry and simple JSON supported.
Metrics are numbers over time. Request latency, error count, memory usage, queue depth. JuhJuh ingests your metrics, stores them as time-series data, and evaluates alert rules on every batch so your team gets notified the moment a threshold is crossed.
Metric types¶
JuhJuh supports four metric types. Choose the one that matches what you are measuring.
| Type | What it measures | Example |
|---|---|---|
| Gauge | A point-in-time value that goes up and down | CPU usage at 73%, memory at 2.1 GB, active connections at 42 |
| Counter | A monotonically increasing count | Total requests served: 1,204,331. Total errors: 847 |
| Sum | A cumulative value that can increase or decrease | Active WebSocket connections, items in a processing queue |
| Histogram | A distribution of values | Request duration distribution, response size percentiles |
If you are unsure, use gauge. It is the most flexible type and works for most measurements.
Sending metrics¶
Send metrics to the ingestion endpoint:
bash
POST /api/ingest/metrics/
Authorization: Bearer jjk_YOUR_API_KEY
Content-Type: application/json
The endpoint auto-detects the format. If the top-level key is resourceMetrics, it parses OTLP. If the key is metrics, it parses simple JSON.
Simple JSON format¶
json
{
"metrics": [
{
"name": "http.request.duration",
"value": 142.5,
"metric_type": "gauge",
"unit": "ms",
"tags": {
"service": "api-gateway",
"endpoint": "/api/users",
"method": "GET",
"status": "200"
},
"timestamp": "2026-04-09T14:30:00Z"
}
]
}
| Field | Required | Default | Description |
|---|---|---|---|
name |
Yes | Metric name. Use dot-separated namespacing: http.request.duration, db.query.count |
|
value |
Yes | Numeric value (integer or float) | |
metric_type |
No | gauge |
One of: gauge, counter, sum, histogram |
unit |
No | None | Unit of measurement: ms, bytes, %, requests, or any custom string |
tags |
No | {} |
Key-value pairs for filtering and grouping. Add service, endpoint, environment, and any dimensions you want to slice by |
timestamp |
No | Server time | ISO 8601 timestamp. If omitted, JuhJuh uses the time the request arrives |
OTLP format¶
OpenTelemetry SDKs send metrics in OTLP format automatically. The structure follows the OpenTelemetry Metrics Data Model:
json
{
"resourceMetrics": [
{
"resource": {
"attributes": [
{ "key": "service.name", "value": { "stringValue": "api-gateway" } }
]
},
"scopeMetrics": [
{
"metrics": [
{
"name": "http.request.duration",
"unit": "ms",
"gauge": {
"dataPoints": [
{
"asDouble": 142.5,
"timeUnixNano": "1712672400000000000",
"attributes": [
{ "key": "endpoint", "value": { "stringValue": "/api/users" } }
]
}
]
}
}
]
}
]
}
]
}
JuhJuh handles three OTLP data types:
| OTLP field | JuhJuh metric type |
|---|---|
gauge |
gauge |
sum (monotonic) |
counter |
sum (non-monotonic) |
sum |
histogram |
Creates two metrics: .sum (total) and .count (sample count) |
The service.name resource attribute is added as a service tag automatically.
Naming conventions¶
Good metric names make dashboards readable and queries predictable.
Use dot-separated namespacing:
text
http.request.duration
http.request.count
db.query.duration
db.connection.pool.size
cache.hit.ratio
queue.depth
queue.processing.duration
Use tags for dimensions, not metric names:
```yaml
Good: one metric, multiple tag values¶
name: "http.request.duration" tags: { "endpoint": "/api/users", "method": "GET" }
Bad: separate metric per endpoint¶
name: "http.request.duration.api.users.get" ```
Tags let you filter, group, and aggregate across dimensions without creating an explosion of metric names.
Common metrics to track¶
These metrics give you a baseline understanding of your application's health:
HTTP layer¶
| Metric | Type | Unit | Tags |
|---|---|---|---|
http.request.duration |
gauge | ms | service, endpoint, method, status |
http.request.count |
counter | requests | service, endpoint, method, status |
http.error.count |
counter | errors | service, endpoint, error_type |
Database¶
| Metric | Type | Unit | Tags |
|---|---|---|---|
db.query.duration |
gauge | ms | service, operation, table |
db.connection.pool.active |
gauge | connections | service |
db.connection.pool.idle |
gauge | connections | service |
Background jobs¶
| Metric | Type | Unit | Tags |
|---|---|---|---|
queue.depth |
gauge | jobs | queue_name |
job.duration |
gauge | ms | queue_name, job_type |
job.failure.count |
counter | failures | queue_name, job_type |
System¶
| Metric | Type | Unit | Tags |
|---|---|---|---|
system.cpu.percent |
gauge | % | host |
system.memory.percent |
gauge | % | host |
system.disk.percent |
gauge | % | host, mount |
Batching¶
Send multiple metrics in a single request:
json
{
"metrics": [
{ "name": "http.request.duration", "value": 142.5, "metric_type": "gauge", "unit": "ms", "tags": { "service": "api" } },
{ "name": "http.request.count", "value": 1, "metric_type": "counter", "tags": { "service": "api" } },
{ "name": "system.cpu.percent", "value": 73.2, "metric_type": "gauge", "unit": "%", "tags": { "host": "web-1" } }
]
}
| Batch size | Behavior |
|---|---|
| 1 to 50 entries | Processed synchronously, returns 200 |
| 51+ entries | Accepted with 202, processed asynchronously |
Alert evaluation¶
Every time a batch of metrics is ingested, JuhJuh evaluates your active alert rules against the new data. If a metric crosses its configured threshold for the specified duration, an alert fires and notifications are sent to your configured channels.
This means alerts are evaluated in near real-time as data arrives, not on a fixed polling interval.
Infrastructure metrics¶
If your application runs on JuhJuh-managed VMs, infrastructure metrics are collected automatically every 60 seconds. These include:
| Category | Metrics collected |
|---|---|
| CPU | Usage percentage, load averages (1m, 5m, 15m) |
| Memory | Total, used, free, available, usage percentage |
| Disk | Total, used, free, usage percentage |
| Network | Bytes received/sent per second, packets received/sent per second |
| Containers | Per-container CPU, memory usage, memory limit, network I/O |
| Database | Connection count, cache hit ratio, transactions per second, slow queries, table bloat |
No configuration needed. Infrastructure metrics appear in your observability dashboard alongside application metrics sent through push-based ingestion.
Data retention¶
Metrics are retained for 30 days. After the retention period, metric data points are permanently deleted in daily cleanup cycles. If you need historical data beyond 30 days, export it before the retention window closes.
Example: periodic metric reporting in Python¶
Send system metrics from a Python application on a 60-second interval:
```python import time import psutil import requests
API_KEY = "jjk_YOUR_API_KEY" ENDPOINT = "https://your-org.juhjuh.com/api/ingest/metrics/" SERVICE = "my-service"
def collect_and_send(): metrics = [ { "name": "system.cpu.percent", "value": psutil.cpu_percent(), "metric_type": "gauge", "unit": "%", "tags": {"service": SERVICE}, }, { "name": "system.memory.percent", "value": psutil.virtual_memory().percent, "metric_type": "gauge", "unit": "%", "tags": {"service": SERVICE}, }, ] requests.post( ENDPOINT, json={"metrics": metrics}, headers={"Authorization": f"Bearer {API_KEY}"}, )
while True: collect_and_send() time.sleep(60) ```
For production use, replace the sleep loop with your application's scheduler or a background task framework. Add error handling around the HTTP request.
Related¶
- Observability for an overview of all observability signals
- Instrumentation for SDK setup and API key management
- Alerts for setting thresholds and notification channels on your metrics
- Tracing for distributed tracing with metric-to-trace correlation
- Logging for structured log ingestion and search
- VMs for automatic infrastructure metric collection on JuhJuh-managed VMs