mirror of
https://github.com/prometheus/prometheus.git
synced 2025-08-05 13:47:10 +02:00
Merge pull request #16695 from sujalshah-bit/block_endpoint
api: Create `/status/tsdb/blocks` endpoint.
This commit is contained in:
commit
2e709c6567
@ -1756,6 +1756,21 @@ func (s *readyStorage) CleanTombstones() error {
|
||||
return tsdb.ErrNotReady
|
||||
}
|
||||
|
||||
// BlockMetas implements the api_v1.TSDBAdminStats and api_v2.TSDBAdmin interfaces.
|
||||
func (s *readyStorage) BlockMetas() ([]tsdb.BlockMeta, error) {
|
||||
if x := s.get(); x != nil {
|
||||
switch db := x.(type) {
|
||||
case *tsdb.DB:
|
||||
return db.BlockMetas(), nil
|
||||
case *agent.DB:
|
||||
return nil, agent.ErrUnsupported
|
||||
default:
|
||||
panic(fmt.Sprintf("unknown storage type %T", db))
|
||||
}
|
||||
}
|
||||
return nil, tsdb.ErrNotReady
|
||||
}
|
||||
|
||||
// Delete implements the api_v1.TSDBAdminStats and api_v2.TSDBAdmin interfaces.
|
||||
func (s *readyStorage) Delete(ctx context.Context, mint, maxt int64, ms ...*labels.Matcher) error {
|
||||
if x := s.get(); x != nil {
|
||||
|
@ -1355,6 +1355,64 @@ curl http://localhost:9090/api/v1/status/tsdb
|
||||
}
|
||||
```
|
||||
|
||||
*New in v3.6.0*
|
||||
|
||||
### TSDB Blocks
|
||||
|
||||
**NOTE**: This endpoint is **experimental** and might change in the future. The endpoint name and the exact format of the returned data may change between Prometheus versions. The **exact metadata returned** by this endpoint is an implementation detail and may change in future Prometheus versions.
|
||||
|
||||
The following endpoint returns the list of currently loaded TSDB blocks and their metadata.
|
||||
|
||||
```
|
||||
GET /api/v1/status/tsdb/blocks
|
||||
```
|
||||
|
||||
This endpoint returns the following information for each block:
|
||||
|
||||
- `ulid`: Unique ID of the block.
|
||||
- `minTime`: Minimum timestamp (in milliseconds) of the block.
|
||||
- `maxTime`: Maximum timestamp (in milliseconds) of the block.
|
||||
- `stats`:
|
||||
- `numSeries`: Number of series in the block.
|
||||
- `numSamples`: Number of samples in the block.
|
||||
- `numChunks`: Number of chunks in the block.
|
||||
- `compaction`:
|
||||
- `level`: The compaction level of the block.
|
||||
- `sources`: List of ULIDs of source blocks used to compact this block.
|
||||
- `version`: The block version.
|
||||
|
||||
|
||||
```bash
|
||||
curl http://localhost:9090/api/v1/status/tsdb/blocks
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"status": "success",
|
||||
"data": {
|
||||
"blocks": [
|
||||
{
|
||||
"ulid": "01JZ8JKZY6XSK3PTDP9ZKRWT60",
|
||||
"minTime": 1750860620060,
|
||||
"maxTime": 1750867200000,
|
||||
"stats": {
|
||||
"numSamples": 13701,
|
||||
"numSeries": 716,
|
||||
"numChunks": 716
|
||||
},
|
||||
"compaction": {
|
||||
"level": 1,
|
||||
"sources": [
|
||||
"01JZ8JKZY6XSK3PTDP9ZKRWT60"
|
||||
]
|
||||
},
|
||||
"version": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
*New in v2.15*
|
||||
|
||||
### WAL Replay Stats
|
||||
|
10
tsdb/db.go
10
tsdb/db.go
@ -1074,6 +1074,16 @@ func (db *DB) Dir() string {
|
||||
return db.dir
|
||||
}
|
||||
|
||||
// BlockMetas returns the list of metadata for all blocks.
|
||||
func (db *DB) BlockMetas() []BlockMeta {
|
||||
blocks := db.Blocks()
|
||||
metas := make([]BlockMeta, 0, len(blocks))
|
||||
for _, b := range blocks {
|
||||
metas = append(metas, b.Meta())
|
||||
}
|
||||
return metas
|
||||
}
|
||||
|
||||
func (db *DB) run(ctx context.Context) {
|
||||
defer close(db.donec)
|
||||
|
||||
|
@ -186,6 +186,7 @@ type TSDBAdminStats interface {
|
||||
Snapshot(dir string, withHead bool) error
|
||||
Stats(statsByLabelName string, limit int) (*tsdb.Stats, error)
|
||||
WALReplayStatus() (tsdb.WALReplayStatus, error)
|
||||
BlockMetas() ([]tsdb.BlockMeta, error)
|
||||
}
|
||||
|
||||
type QueryOpts interface {
|
||||
@ -411,6 +412,7 @@ func (api *API) Register(r *route.Router) {
|
||||
r.Get("/status/buildinfo", wrap(api.serveBuildInfo))
|
||||
r.Get("/status/flags", wrap(api.serveFlags))
|
||||
r.Get("/status/tsdb", wrapAgent(api.serveTSDBStatus))
|
||||
r.Get("/status/tsdb/blocks", wrapAgent(api.serveTSDBBlocks))
|
||||
r.Get("/status/walreplay", api.serveWALReplayStatus)
|
||||
r.Get("/notifications", api.notifications)
|
||||
r.Get("/notifications/live", api.notificationsSSE)
|
||||
@ -1747,6 +1749,19 @@ func TSDBStatsFromIndexStats(stats []index.Stat) []TSDBStat {
|
||||
return result
|
||||
}
|
||||
|
||||
func (api *API) serveTSDBBlocks(_ *http.Request) apiFuncResult {
|
||||
blockMetas, err := api.db.BlockMetas()
|
||||
if err != nil {
|
||||
return apiFuncResult{nil, &apiError{errorInternal, fmt.Errorf("error getting block metadata: %w", err)}, nil, nil}
|
||||
}
|
||||
|
||||
return apiFuncResult{
|
||||
data: map[string][]tsdb.BlockMeta{
|
||||
"blocks": blockMetas,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (api *API) serveTSDBStatus(r *http.Request) apiFuncResult {
|
||||
limit := 10
|
||||
if s := r.FormValue("limit"); s != "" {
|
||||
|
@ -15,6 +15,7 @@ package v1
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
@ -31,6 +32,7 @@ import (
|
||||
"time"
|
||||
|
||||
jsoniter "github.com/json-iterator/go"
|
||||
"github.com/oklog/ulid/v2"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
config_util "github.com/prometheus/common/config"
|
||||
"github.com/prometheus/common/model"
|
||||
@ -3793,10 +3795,15 @@ func assertAPIResponseMetadataLen(t *testing.T, got interface{}, expLen int) {
|
||||
}
|
||||
|
||||
type fakeDB struct {
|
||||
err error
|
||||
err error
|
||||
blockMetas []tsdb.BlockMeta
|
||||
}
|
||||
|
||||
func (f *fakeDB) CleanTombstones() error { return f.err }
|
||||
func (f *fakeDB) CleanTombstones() error { return f.err }
|
||||
|
||||
func (f *fakeDB) BlockMetas() ([]tsdb.BlockMeta, error) {
|
||||
return f.blockMetas, nil
|
||||
}
|
||||
func (f *fakeDB) Delete(context.Context, int64, int64, ...*labels.Matcher) error { return f.err }
|
||||
func (f *fakeDB) Snapshot(string, bool) error { return f.err }
|
||||
func (f *fakeDB) Stats(statsByLabelName string, limit int) (_ *tsdb.Stats, retErr error) {
|
||||
@ -4122,6 +4129,45 @@ func TestRespondSuccess_DefaultCodecCannotEncodeResponse(t *testing.T) {
|
||||
require.JSONEq(t, `{"status":"error","errorType":"not_acceptable","error":"cannot encode response as application/default-format"}`, string(body))
|
||||
}
|
||||
|
||||
func TestServeTSDBBlocks(t *testing.T) {
|
||||
blockMeta := tsdb.BlockMeta{
|
||||
ULID: ulid.MustNew(ulid.Now(), nil),
|
||||
MinTime: 0,
|
||||
MaxTime: 1000,
|
||||
Stats: tsdb.BlockStats{
|
||||
NumSeries: 10,
|
||||
},
|
||||
}
|
||||
|
||||
db := &fakeDB{
|
||||
blockMetas: []tsdb.BlockMeta{blockMeta},
|
||||
}
|
||||
|
||||
api := &API{
|
||||
db: db,
|
||||
}
|
||||
|
||||
req := httptest.NewRequest(http.MethodGet, "/api/v1/status/tsdb/blocks", nil)
|
||||
w := httptest.NewRecorder()
|
||||
|
||||
result := api.serveTSDBBlocks(req)
|
||||
|
||||
json.NewEncoder(w).Encode(result.data)
|
||||
|
||||
resp := w.Result()
|
||||
defer resp.Body.Close()
|
||||
|
||||
require.Equal(t, http.StatusOK, resp.StatusCode)
|
||||
|
||||
var resultData struct {
|
||||
Blocks []tsdb.BlockMeta `json:"blocks"`
|
||||
}
|
||||
err := json.NewDecoder(resp.Body).Decode(&resultData)
|
||||
require.NoError(t, err)
|
||||
require.Len(t, resultData.Blocks, 1)
|
||||
require.Equal(t, blockMeta, resultData.Blocks[0])
|
||||
}
|
||||
|
||||
func TestRespondError(t *testing.T) {
|
||||
s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
|
||||
api := API{}
|
||||
|
@ -52,6 +52,10 @@ type dbAdapter struct {
|
||||
*tsdb.DB
|
||||
}
|
||||
|
||||
func (a *dbAdapter) BlockMetas() ([]tsdb.BlockMeta, error) {
|
||||
return a.DB.BlockMetas(), nil
|
||||
}
|
||||
|
||||
func (a *dbAdapter) Stats(statsByLabelName string, limit int) (*tsdb.Stats, error) {
|
||||
return a.Head().Stats(statsByLabelName, limit), nil
|
||||
}
|
||||
@ -569,6 +573,7 @@ func TestAgentAPIEndPoints(t *testing.T) {
|
||||
"/query_range": {http.MethodGet, http.MethodPost},
|
||||
"/query_exemplars": {http.MethodGet, http.MethodPost},
|
||||
"/status/tsdb": {http.MethodGet},
|
||||
"/status/tsdb/blocks": {http.MethodGet},
|
||||
"/alerts": {http.MethodGet},
|
||||
"/rules": {http.MethodGet},
|
||||
"/admin/tsdb/delete_series": {http.MethodPost, http.MethodPut},
|
||||
|
Loading…
Reference in New Issue
Block a user