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  }