github.com/grafana/pyroscope@v1.18.0/pkg/phlaredb/metrics.go (about) 1 package phlaredb 2 3 import ( 4 "context" 5 6 "github.com/prometheus/client_golang/prometheus" 7 8 "github.com/grafana/pyroscope/pkg/phlaredb/query" 9 phlarecontext "github.com/grafana/pyroscope/pkg/pyroscope/context" 10 "github.com/grafana/pyroscope/pkg/util" 11 ) 12 13 type contextKey uint8 14 15 const ( 16 headMetricsContextKey contextKey = iota 17 blockMetricsContextKey 18 ) 19 20 type headMetrics struct { 21 series prometheus.Gauge 22 seriesCreated *prometheus.CounterVec 23 24 profiles prometheus.Gauge 25 profilesCreated *prometheus.CounterVec 26 27 sizeBytes *prometheus.GaugeVec 28 rowsWritten *prometheus.CounterVec 29 30 sampleValuesIngested *prometheus.CounterVec 31 sampleValuesReceived *prometheus.CounterVec 32 samples prometheus.Gauge 33 34 flushedFileSizeBytes *prometheus.HistogramVec 35 flushedBlockSizeBytes prometheus.Histogram 36 flushedBlockDurationSeconds prometheus.Histogram 37 flushedBlockSeries prometheus.Histogram 38 flushedBlockSamples prometheus.Histogram 39 flusehdBlockProfiles prometheus.Histogram 40 blockDurationSeconds prometheus.Histogram 41 flushedBlocks *prometheus.CounterVec 42 flushedBlocksReasons *prometheus.CounterVec 43 writtenProfileSegments *prometheus.CounterVec 44 writtenProfileSegmentsBytes prometheus.Histogram 45 } 46 47 func newHeadMetrics(reg prometheus.Registerer) *headMetrics { 48 return newHeadMetricsWithPrefix(reg, "pyroscope") 49 } 50 51 func newHeadMetricsWithPrefix(reg prometheus.Registerer, prefix string) *headMetrics { 52 m := &headMetrics{ 53 seriesCreated: prometheus.NewCounterVec(prometheus.CounterOpts{ 54 Name: prefix + "_tsdb_head_series_created_total", 55 Help: "Total number of series created in the head", 56 }, []string{"profile_name"}), 57 rowsWritten: prometheus.NewCounterVec( 58 prometheus.CounterOpts{ 59 Name: prefix + "_rows_written", 60 Help: "Number of rows written to a parquet table.", 61 }, 62 []string{"type"}), 63 profilesCreated: prometheus.NewCounterVec(prometheus.CounterOpts{ 64 Name: prefix + "_head_profiles_created_total", 65 Help: "Total number of profiles created in the head", 66 }, []string{"profile_name"}), 67 sampleValuesIngested: prometheus.NewCounterVec( 68 prometheus.CounterOpts{ 69 Name: prefix + "_head_ingested_sample_values_total", 70 Help: "Number of sample values ingested into the head per profile type.", 71 }, 72 []string{"profile_name"}), 73 sampleValuesReceived: prometheus.NewCounterVec( 74 prometheus.CounterOpts{ 75 Name: prefix + "_head_received_sample_values_total", 76 Help: "Number of sample values received into the head per profile type.", 77 }, 78 []string{"profile_name"}), 79 sizeBytes: prometheus.NewGaugeVec( 80 prometheus.GaugeOpts{ 81 Name: prefix + "_head_size_bytes", 82 Help: "Size of a particular in memory store within the head phlaredb block.", 83 }, 84 []string{"type"}), 85 series: prometheus.NewGauge(prometheus.GaugeOpts{ 86 Name: prefix + "_tsdb_head_series", 87 Help: "Total number of series in the head block.", 88 }), 89 profiles: prometheus.NewGauge(prometheus.GaugeOpts{ 90 Name: prefix + "_head_profiles", 91 Help: "Total number of profiles in the head block.", 92 }), 93 flushedFileSizeBytes: prometheus.NewHistogramVec(prometheus.HistogramOpts{ 94 Name: prefix + "_head_flushed_table_size_bytes", 95 Help: "Size of a flushed table in bytes.", 96 // [2MB, 4MB, 8MB, 16MB, 32MB, 64MB, 128MB, 256MB, 512MB, 1GB, 2GB] 97 Buckets: prometheus.ExponentialBuckets(2*1024*1024, 2, 11), 98 }, []string{"name"}), 99 flushedBlockSizeBytes: prometheus.NewHistogram(prometheus.HistogramOpts{ 100 Name: prefix + "_head_flushed_block_size_bytes", 101 Help: "Size of a flushed block in bytes.", 102 // [50MB, 75MB, 112.5MB, 168.75MB, 253.125MB, 379.688MB, 569.532MB, 854.298MB, 1.281MB, 1.922MB, 2.883MB] 103 Buckets: prometheus.ExponentialBuckets(50*1024*1024, 1.5, 11), 104 }), 105 flushedBlockDurationSeconds: prometheus.NewHistogram(prometheus.HistogramOpts{ 106 Name: prefix + "_head_flushed_block_duration_seconds", 107 Help: "Time to flushed a block in seconds.", 108 // [5s, 7.5s, 11.25s, 16.875s, 25.3125s, 37.96875s, 56.953125s, 85.4296875s, 128.14453125s, 192.216796875s] 109 Buckets: prometheus.ExponentialBuckets(5, 1.5, 10), 110 }), 111 flushedBlockSeries: prometheus.NewHistogram(prometheus.HistogramOpts{ 112 Name: prefix + "_head_flushed_block_series", 113 Help: "Number of series in a flushed block.", 114 // [1k, 3k, 5k, 7k, 9k, 11k, 13k, 15k, 17k, 19k] 115 Buckets: prometheus.LinearBuckets(1000, 2000, 10), 116 }), 117 flushedBlockSamples: prometheus.NewHistogram(prometheus.HistogramOpts{ 118 Name: prefix + "_head_flushed_block_samples", 119 Help: "Number of samples in a flushed block.", 120 // [200k, 400k, 800k, 1.6M, 3.2M, 6.4M, 12.8M, 25.6M, 51.2M, 102.4M, 204.8M, 409.6M, 819.2M, 1.6384G, 3.2768G] 121 Buckets: prometheus.ExponentialBuckets(200_000, 2, 15), 122 }), 123 flusehdBlockProfiles: prometheus.NewHistogram(prometheus.HistogramOpts{ 124 Name: prefix + "_head_flushed_block_profiles", 125 Help: "Number of profiles in a flushed block.", 126 // [20k, 40k, 80k, 160k, 320k, 640k, 1.28M, 2.56M, 5.12M, 10.24M] 127 Buckets: prometheus.ExponentialBuckets(20_000, 2, 10), 128 }), 129 blockDurationSeconds: prometheus.NewHistogram(prometheus.HistogramOpts{ 130 Name: prefix + "_head_block_duration_seconds", 131 Help: "Duration of a block in seconds (the range it covers).", 132 // [20m, 40m, 1h, 1h20, 1h40, 2h, 2h20, 2h40, 3h, 3h20, 3h40, 4h, 4h20, 4h40, 5h, 5h20, 5h40, 6h, 6h20, 6h40, 7h, 7h20, 7h40, 8h] 133 Buckets: prometheus.LinearBuckets(1200, 1200, 24), 134 }), 135 flushedBlocks: prometheus.NewCounterVec(prometheus.CounterOpts{ 136 Name: prefix + "_head_flushed_blocks_total", 137 Help: "Total number of blocks flushed.", 138 }, []string{"status"}), 139 flushedBlocksReasons: prometheus.NewCounterVec(prometheus.CounterOpts{ 140 Name: prefix + "_head_flushed_reason_total", 141 Help: "Total count of reasons why block has been flushed.", 142 }, []string{"reason"}), 143 writtenProfileSegments: prometheus.NewCounterVec(prometheus.CounterOpts{ 144 Name: prefix + "_head_written_profile_segments_total", 145 Help: "Total number and status of profile row groups segments written.", 146 }, []string{"status"}), 147 writtenProfileSegmentsBytes: prometheus.NewHistogram(prometheus.HistogramOpts{ 148 Name: prefix + "_head_written_profile_segments_size_bytes", 149 Help: "Size of a flushed table in bytes.", 150 // [512KB, 1MB, 2MB, 4MB, 8MB, 16MB, 32MB, 64MB, 128MB, 256MB, 512MB] 151 Buckets: prometheus.ExponentialBuckets(512*1024, 2, 11), 152 }), 153 samples: prometheus.NewGauge(prometheus.GaugeOpts{ 154 Name: prefix + "_head_samples", 155 Help: "Number of samples in the head.", 156 }), 157 } 158 159 m.register(reg) 160 return m 161 } 162 163 func (m *headMetrics) register(reg prometheus.Registerer) { 164 if reg == nil { 165 return 166 } 167 m.series = util.RegisterOrGet(reg, m.series) 168 m.seriesCreated = util.RegisterOrGet(reg, m.seriesCreated) 169 m.profiles = util.RegisterOrGet(reg, m.profiles) 170 m.profilesCreated = util.RegisterOrGet(reg, m.profilesCreated) 171 m.sizeBytes = util.RegisterOrGet(reg, m.sizeBytes) 172 m.rowsWritten = util.RegisterOrGet(reg, m.rowsWritten) 173 m.sampleValuesIngested = util.RegisterOrGet(reg, m.sampleValuesIngested) 174 m.sampleValuesReceived = util.RegisterOrGet(reg, m.sampleValuesReceived) 175 m.flushedFileSizeBytes = util.RegisterOrGet(reg, m.flushedFileSizeBytes) 176 m.flushedBlockSizeBytes = util.RegisterOrGet(reg, m.flushedBlockSizeBytes) 177 m.flushedBlockDurationSeconds = util.RegisterOrGet(reg, m.flushedBlockDurationSeconds) 178 m.flushedBlockSeries = util.RegisterOrGet(reg, m.flushedBlockSeries) 179 m.flushedBlockSamples = util.RegisterOrGet(reg, m.flushedBlockSamples) 180 m.flusehdBlockProfiles = util.RegisterOrGet(reg, m.flusehdBlockProfiles) 181 m.blockDurationSeconds = util.RegisterOrGet(reg, m.blockDurationSeconds) 182 m.flushedBlocks = util.RegisterOrGet(reg, m.flushedBlocks) 183 m.flushedBlocksReasons = util.RegisterOrGet(reg, m.flushedBlocksReasons) 184 m.writtenProfileSegments = util.RegisterOrGet(reg, m.writtenProfileSegments) 185 m.writtenProfileSegmentsBytes = util.RegisterOrGet(reg, m.writtenProfileSegmentsBytes) 186 } 187 188 func ContextWithHeadMetrics(ctx context.Context, reg prometheus.Registerer, prefix string) context.Context { 189 return contextWithHeadMetrics(ctx, newHeadMetricsWithPrefix(reg, prefix)) 190 } 191 192 func contextWithHeadMetrics(ctx context.Context, m *headMetrics) context.Context { 193 return context.WithValue(ctx, headMetricsContextKey, m) 194 } 195 196 func contextHeadMetrics(ctx context.Context) *headMetrics { 197 m, ok := ctx.Value(headMetricsContextKey).(*headMetrics) 198 if !ok { 199 return newHeadMetrics(phlarecontext.Registry(ctx)) 200 } 201 return m 202 } 203 204 type BlocksMetrics struct { 205 registerer prometheus.Registerer 206 207 query *query.Metrics 208 209 profileTableAccess *prometheus.CounterVec 210 blockOpeningLatency prometheus.Histogram 211 blockOpened prometheus.Gauge 212 } 213 214 func NewBlocksMetrics(reg prometheus.Registerer) *BlocksMetrics { 215 return &BlocksMetrics{ 216 registerer: reg, 217 query: query.NewMetrics(reg), 218 219 blockOpeningLatency: util.RegisterOrGet(reg, prometheus.NewHistogram(prometheus.HistogramOpts{ 220 Name: "pyroscopedb_block_opening_duration", 221 Help: "Latency of opening a block in seconds", 222 })), 223 224 blockOpened: util.RegisterOrGet(reg, prometheus.NewGauge(prometheus.GaugeOpts{ 225 Name: "pyroscopedb_blocks_currently_open", 226 Help: "Number of blocks opened", 227 })), 228 229 profileTableAccess: util.RegisterOrGet(reg, prometheus.NewCounterVec(prometheus.CounterOpts{ 230 Name: "pyroscopedb_block_profile_table_accesses_total", 231 Help: "Number of times a profile table was accessed", 232 }, []string{"table"})), 233 } 234 } 235 236 func (m *BlocksMetrics) Unregister() { 237 m.query.Unregister() 238 for _, c := range []prometheus.Collector{ 239 m.profileTableAccess, 240 m.blockOpeningLatency, 241 m.blockOpened, 242 } { 243 m.registerer.Unregister(c) 244 } 245 } 246 247 func ContextWithBlockMetrics(ctx context.Context, m *BlocksMetrics) context.Context { 248 return context.WithValue(ctx, blockMetricsContextKey, m) 249 } 250 251 func blockMetricsFromContext(ctx context.Context) *BlocksMetrics { 252 m, ok := ctx.Value(blockMetricsContextKey).(*BlocksMetrics) 253 if !ok { 254 return NewBlocksMetrics(phlarecontext.Registry(ctx)) 255 } 256 return m 257 }