Monitoring¶
leBLOB answers two paths that no bucket name can shadow: /-/health for liveness and /-/metrics for Prometheus. Both answer without a signature, so on a store reachable from the internet, block them at the proxy in front of it. Each worker also logs one line per request.
Health¶
answers ok with status 200 once the worker can read the metadata. A load balancer or Docker's HEALTHCHECK can use it. The Dockerfile in the repository does.
Metrics¶
Metrics are served at /-/metrics in the Prometheus text format. A scrape configuration:
scrape_configs:
- job_name: leblob
static_configs:
- targets: ["127.0.0.1:9000"]
metrics_path: /-/metrics
A scrape reaches one worker, chosen by the kernel, so the counters are added up across workers. Each worker writes its counts to a file under data/metrics/ every 5 s and on each scrape. The worker answering adds up the files. Totals can therefore lag by up to 5 s. They never go down until the server restarts, which Prometheus reads as a reset. State, such as free space, is read from the metadata and the disks on each scrape.
The metrics name operations, statuses and volume numbers, never a bucket, a key or a path. They do reveal how busy a store is and how full its disks are.
Requests¶
| Metric | Type | Labels | Meaning |
|---|---|---|---|
leblob_http_requests_total |
counter | operation, status |
Requests answered, by S3 operation and status |
leblob_http_request_seconds |
histogram | operation |
Seconds to answer a request. Buckets at 5, 10, 50, 100 and 500 ms, and 1, 5 and 30 s |
operation is the S3 operation's name in capitals, such as PUT_OBJECT or LIST_OBJECTS_V2, and unknown when a request couldn't be routed.
Background work¶
| Metric | Type | Meaning |
|---|---|---|
leblob_blobs_collected_total |
counter | Blobs deleted after their grace period |
leblob_copies_repaired_total |
counter | Copies of blobs restored by repair |
leblob_copies_scrubbed_total |
counter | Copies checked against their MD5 |
leblob_bad_copies_removed_total |
counter | Bad copies scrub removed for repair to replace |
leblob_only_copies_bad_total |
counter | Times scrub found a blob's only copy bad |
leblob_lifecycle_objects_expired_total |
counter | Objects expired by lifecycle rules |
leblob_lifecycle_versions_erased_total |
counter | Versions erased by lifecycle rules |
leblob_lifecycle_uploads_aborted_total |
counter | Uploads aborted by lifecycle rules |
State¶
| Metric | Type | Labels | Meaning |
|---|---|---|---|
leblob_repairs_queued |
gauge | Blobs waiting for repair | |
leblob_blobs_awaiting_collection |
gauge | Blobs queued for deletion | |
leblob_copies_wanted |
gauge | Copies each blob should have | |
leblob_volume_up |
gauge | volume |
Whether a volume can be used, 1 or 0 |
leblob_volume_draining |
gauge | volume |
Whether a volume is being emptied, 1 or 0 |
leblob_volume_free_bytes |
gauge | volume |
Bytes free on a volume |
Failures¶
| Metric | Type | Labels | Meaning |
|---|---|---|---|
leblob_volume_failures_total |
counter | volume |
I/O errors on a volume |
What to alert on¶
leblob_only_copies_bad_totalrising: a blob with one copy is damaged. Its object can't be repaired from the store.leblob_volume_failures_totalrising, orleblob_volume_upat 0: a disk is failing. On btrfs,leblob_volume_upcan stay at 1 for a dead device that answers from cache, so the counter is the one to rely on.leblob_repairs_queuedstaying high: blobs have fewer copies than wanted. That is normal for a while after a write that lost a copy, a raised number of copies or a forgotten disk.leblob_volume_free_bytesrunning low. On a full disk, new workers may only be able to answer with errors until there is room, because SQLite needs to write to recover its log.- A rising share of
leblob_http_requests_totalwith astatusof 500 or above.
A hung disk stalls the requests that use it, and /-/metrics too, since leBLOB has no timeouts on disk I/O yet.
Access logs¶
Each worker writes one JSON line per request to standard error:
{"request_id": "3f9c0e5b7a1d2c44", "method": "GET", "path": "/my-bucket/hello.txt", "operation": "GET_OBJECT", "status": 200, "seconds": 0.0021}
| Field | Meaning |
|---|---|
request_id |
Also sent to the client in x-amz-request-id, and in an error's XML body |
method, path |
As received, the path still percent-encoded |
operation |
The S3 operation, or unknown |
status |
The status sent, or 499 when the client went away before an answer |
seconds |
Time from receiving the request to the end of the answer |
The path holds bucket and key names, so the logs are as private as the store's listings.
Server errors, status 500 and above, are logged too, with their traceback under the same request ID. A response cut off by the client is logged with how many bytes had gone out.