github.com/thanos-io/thanos@v0.32.5/pkg/api/status/v1.go (about)

     1  // Copyright (c) The Thanos Authors.
     2  // Licensed under the Apache License 2.0.
     3  
     4  // Copyright 2016 The Prometheus Authors
     5  // Licensed under the Apache License, Version 2.0 (the "License");
     6  // you may not use this file except in compliance with the License.
     7  // You may obtain a copy of the License at
     8  //
     9  //     http://www.apache.org/licenses/LICENSE-2.0
    10  //
    11  // Unless required by applicable law or agreed to in writing, software
    12  // distributed under the License is distributed on an "AS IS" BASIS,
    13  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    14  // See the License for the specific language governing permissions and
    15  // limitations under the License.
    16  
    17  package status
    18  
    19  import (
    20  	"net/http"
    21  
    22  	"github.com/prometheus/client_golang/prometheus"
    23  	"github.com/prometheus/prometheus/tsdb"
    24  
    25  	"github.com/go-kit/log"
    26  	"github.com/opentracing/opentracing-go"
    27  	"github.com/prometheus/common/route"
    28  	"github.com/prometheus/prometheus/model/labels"
    29  	v1 "github.com/prometheus/prometheus/web/api/v1"
    30  	"github.com/thanos-io/thanos/pkg/api"
    31  	extpromhttp "github.com/thanos-io/thanos/pkg/extprom/http"
    32  	"github.com/thanos-io/thanos/pkg/logging"
    33  )
    34  
    35  type TenantStats struct {
    36  	Tenant string
    37  	Stats  *tsdb.Stats
    38  }
    39  
    40  // TSDBStatus has information of cardinality statistics from postings.
    41  // TODO(fpetkovski): replace with upstream struct after dependency update.
    42  type TSDBStatus struct {
    43  	Tenant        string `json:"tenant"`
    44  	v1.TSDBStatus `json:","`
    45  }
    46  
    47  type GetStatsFunc func(r *http.Request, statsByLabelName string) ([]TenantStats, *api.ApiError)
    48  
    49  type Options struct {
    50  	GetStats GetStatsFunc
    51  	Registry *prometheus.Registry
    52  }
    53  
    54  type StatusAPI struct {
    55  	getTSDBStats GetStatsFunc
    56  	registry     *prometheus.Registry
    57  }
    58  
    59  func New(opts Options) *StatusAPI {
    60  	return &StatusAPI{
    61  		getTSDBStats: opts.GetStats,
    62  		registry:     opts.Registry,
    63  	}
    64  }
    65  
    66  func (sapi *StatusAPI) Register(r *route.Router, tracer opentracing.Tracer, logger log.Logger, ins extpromhttp.InstrumentationMiddleware, logMiddleware *logging.HTTPServerMiddleware) {
    67  	instr := api.GetInstr(tracer, logger, ins, logMiddleware, false)
    68  	r.Get("/api/v1/status/tsdb", instr("tsdb_status", sapi.httpServeStats))
    69  }
    70  
    71  func (sapi *StatusAPI) httpServeStats(r *http.Request) (interface{}, []error, *api.ApiError, func()) {
    72  	stats, sterr := sapi.getTSDBStats(r, labels.MetricName)
    73  	if sterr != nil {
    74  		return nil, nil, sterr, func() {}
    75  	}
    76  
    77  	result := make([]TSDBStatus, 0, len(stats))
    78  	if len(stats) == 0 {
    79  		return result, nil, nil, func() {}
    80  	}
    81  
    82  	metrics, err := sapi.registry.Gather()
    83  	if err != nil {
    84  		return nil, []error{err}, nil, func() {}
    85  	}
    86  
    87  	tenantChunks := make(map[string]int64)
    88  	for _, mF := range metrics {
    89  		if *mF.Name != "prometheus_tsdb_head_chunks" {
    90  			continue
    91  		}
    92  
    93  		for _, metric := range mF.Metric {
    94  			for _, lbl := range metric.Label {
    95  				if *lbl.Name == "tenant" {
    96  					tenantChunks[*lbl.Value] = int64(metric.Gauge.GetValue())
    97  				}
    98  			}
    99  		}
   100  	}
   101  
   102  	for _, s := range stats {
   103  		var chunkCount int64
   104  		if c, ok := tenantChunks[s.Tenant]; ok {
   105  			chunkCount = c
   106  		}
   107  		result = append(result, TSDBStatus{
   108  			Tenant: s.Tenant,
   109  			TSDBStatus: v1.TSDBStatus{
   110  				HeadStats: v1.HeadStats{
   111  					NumSeries:     s.Stats.NumSeries,
   112  					ChunkCount:    chunkCount,
   113  					MinTime:       s.Stats.MinTime,
   114  					MaxTime:       s.Stats.MaxTime,
   115  					NumLabelPairs: s.Stats.IndexPostingStats.NumLabelPairs,
   116  				},
   117  				SeriesCountByMetricName:     v1.TSDBStatsFromIndexStats(s.Stats.IndexPostingStats.CardinalityMetricsStats),
   118  				LabelValueCountByLabelName:  v1.TSDBStatsFromIndexStats(s.Stats.IndexPostingStats.CardinalityLabelStats),
   119  				MemoryInBytesByLabelName:    v1.TSDBStatsFromIndexStats(s.Stats.IndexPostingStats.LabelValueStats),
   120  				SeriesCountByLabelValuePair: v1.TSDBStatsFromIndexStats(s.Stats.IndexPostingStats.LabelValuePairsStats),
   121  			},
   122  		})
   123  	}
   124  	return result, nil, nil, func() {}
   125  }