github.com/yankunsam/loki/v2@v2.6.3-0.20220817130409-389df5235c27/pkg/storage/chunk/client/metrics.go (about) 1 package client 2 3 import ( 4 "context" 5 6 "github.com/prometheus/client_golang/prometheus" 7 "github.com/prometheus/client_golang/prometheus/promauto" 8 9 "github.com/grafana/loki/pkg/storage/chunk" 10 ) 11 12 // takes a chunk client and exposes metrics for its operations. 13 type MetricsChunkClient struct { 14 Client Client 15 16 metrics ChunkClientMetrics 17 } 18 19 func NewMetricsChunkClient(client Client, metrics ChunkClientMetrics) MetricsChunkClient { 20 return MetricsChunkClient{ 21 Client: client, 22 metrics: metrics, 23 } 24 } 25 26 type ChunkClientMetrics struct { 27 chunksPutPerUser *prometheus.CounterVec 28 chunksSizePutPerUser *prometheus.CounterVec 29 chunksFetchedPerUser *prometheus.CounterVec 30 chunksSizeFetchedPerUser *prometheus.CounterVec 31 } 32 33 func NewChunkClientMetrics(reg prometheus.Registerer) ChunkClientMetrics { 34 return ChunkClientMetrics{ 35 chunksPutPerUser: promauto.With(reg).NewCounterVec(prometheus.CounterOpts{ 36 Namespace: "loki", 37 Name: "chunk_store_stored_chunks_total", 38 Help: "Total stored chunks per user.", 39 }, []string{"user"}), 40 chunksSizePutPerUser: promauto.With(reg).NewCounterVec(prometheus.CounterOpts{ 41 Namespace: "loki", 42 Name: "chunk_store_stored_chunk_bytes_total", 43 Help: "Total bytes stored in chunks per user.", 44 }, []string{"user"}), 45 chunksFetchedPerUser: promauto.With(reg).NewCounterVec(prometheus.CounterOpts{ 46 Namespace: "loki", 47 Name: "chunk_store_fetched_chunks_total", 48 Help: "Total fetched chunks per user.", 49 }, []string{"user"}), 50 chunksSizeFetchedPerUser: promauto.With(reg).NewCounterVec(prometheus.CounterOpts{ 51 Namespace: "loki", 52 Name: "chunk_store_fetched_chunk_bytes_total", 53 Help: "Total bytes fetched in chunks per user.", 54 }, []string{"user"}), 55 } 56 } 57 58 func (c MetricsChunkClient) Stop() { 59 c.Client.Stop() 60 } 61 62 func (c MetricsChunkClient) PutChunks(ctx context.Context, chunks []chunk.Chunk) error { 63 if err := c.Client.PutChunks(ctx, chunks); err != nil { 64 return err 65 } 66 67 // For PutChunks, we explicitly encode the userID in the chunk and don't use context. 68 userSizes := map[string]int{} 69 userCounts := map[string]int{} 70 for _, c := range chunks { 71 userSizes[c.UserID] += c.Data.Size() 72 userCounts[c.UserID]++ 73 } 74 for user, size := range userSizes { 75 c.metrics.chunksSizePutPerUser.WithLabelValues(user).Add(float64(size)) 76 } 77 for user, num := range userCounts { 78 c.metrics.chunksPutPerUser.WithLabelValues(user).Add(float64(num)) 79 } 80 81 return nil 82 } 83 84 func (c MetricsChunkClient) GetChunks(ctx context.Context, chunks []chunk.Chunk) ([]chunk.Chunk, error) { 85 chks, err := c.Client.GetChunks(ctx, chunks) 86 if err != nil { 87 return chks, err 88 } 89 90 // For GetChunks, userID is the chunk and we don't need to use context. 91 // For now, we just load one user chunks at once, but the interface lets us do it for multiple users. 92 userSizes := map[string]int{} 93 userCounts := map[string]int{} 94 for _, c := range chks { 95 userSizes[c.UserID] += c.Data.Size() 96 userCounts[c.UserID]++ 97 } 98 for user, size := range userSizes { 99 c.metrics.chunksSizeFetchedPerUser.WithLabelValues(user).Add(float64(size)) 100 } 101 for user, num := range userCounts { 102 c.metrics.chunksFetchedPerUser.WithLabelValues(user).Add(float64(num)) 103 } 104 105 return chks, nil 106 } 107 108 func (c MetricsChunkClient) DeleteChunk(ctx context.Context, userID, chunkID string) error { 109 return c.Client.DeleteChunk(ctx, userID, chunkID) 110 } 111 112 func (c MetricsChunkClient) IsChunkNotFoundErr(err error) bool { 113 return c.Client.IsChunkNotFoundErr(err) 114 }