1// Copyright 2014 The Prometheus Authors 2// Licensed under the Apache License, Version 2.0 (the "License"); 3// you may not use this file except in compliance with the License. 4// You may obtain a copy of the License at 5// 6// http://www.apache.org/licenses/LICENSE-2.0 7// 8// Unless required by applicable law or agreed to in writing, software 9// distributed under the License is distributed on an "AS IS" BASIS, 10// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11// See the License for the specific language governing permissions and 12// limitations under the License. 13 14package storage 15 16import ( 17 "sort" 18 "time" 19 20 //nolint:staticcheck // Ignore SA1019. Dependencies use the deprecated package, so we have to, too. 21 "github.com/golang/protobuf/proto" 22 23 dto "github.com/prometheus/client_model/go" 24) 25 26// MetricStore is the interface to the storage layer for metrics. All its 27// methods must be safe to be called concurrently. 28type MetricStore interface { 29 // SubmitWriteRequest submits a WriteRequest for processing. There is no 30 // guarantee when a request will be processed, but it is guaranteed that 31 // the requests are processed in the order of submission. 32 SubmitWriteRequest(req WriteRequest) 33 // GetMetricFamilies returns all the currently saved MetricFamilies. The 34 // returned MetricFamilies are guaranteed to not be modified by the 35 // MetricStore anymore. However, they may still be read somewhere else, 36 // so the caller is not allowed to modify the returned MetricFamilies. 37 // If different groups have saved MetricFamilies of the same name, they 38 // are all merged into one MetricFamily by concatenating the contained 39 // Metrics. Inconsistent help strings are logged, and one of the 40 // versions will "win". Inconsistent types and inconsistent or duplicate 41 // label sets will go undetected. 42 GetMetricFamilies() []*dto.MetricFamily 43 // GetMetricFamiliesMap returns a map grouping-key -> MetricGroup. The 44 // MetricFamily pointed to by the Metrics map in each MetricGroup is 45 // guaranteed to not be modified by the MetricStore anymore. However, 46 // they may still be read somewhere else, so the caller is not allowed 47 // to modify it. Otherwise, the returned nested map can be seen as a 48 // deep copy of the internal state of the MetricStore and completely 49 // owned by the caller. 50 GetMetricFamiliesMap() GroupingKeyToMetricGroup 51 // Shutdown must only be called after the caller has made sure that 52 // SubmitWriteRequests is not called anymore. (If it is called later, 53 // the request might get submitted, but not processed anymore.) The 54 // Shutdown method waits for the write request queue to empty, then it 55 // persists the content of the MetricStore (if supported by the 56 // implementation). Also, all internal goroutines are stopped. This 57 // method blocks until all of that is complete. If an error is 58 // encountered, it is returned (whereupon the MetricStorage is in an 59 // undefinded state). If nil is returned, the MetricStore cannot be 60 // "restarted" again, but it can still be used for read operations. 61 Shutdown() error 62 // Healthy returns nil if the MetricStore is currently working as 63 // expected. Otherwise, a non-nil error is returned. 64 Healthy() error 65 // Ready returns nil if the MetricStore is ready to be used (all files 66 // are opened and checkpoints have been restored). Otherwise, a non-nil 67 // error is returned. 68 Ready() error 69} 70 71// WriteRequest is a request to change the MetricStore, i.e. to process it, a 72// write lock has to be acquired. 73// 74// If MetricFamilies is nil, this is a request to delete metrics that share the 75// given Labels as a grouping key. Otherwise, this is a request to update the 76// MetricStore with the MetricFamilies. 77// 78// If Replace is true, the MetricFamilies will completely replace the metrics 79// with the same grouping key. Otherwise, only those MetricFamilies with the 80// same name as new MetricFamilies will be replaced. 81// 82// The key in MetricFamilies is the name of the mapped metric family. 83// 84// When the WriteRequest is processed, the metrics in MetricFamilies will be 85// sanitized to have the same job and other labels as those in the Labels 86// fields. Also, if there is no instance label, an instance label with an empty 87// value will be set. This implies that the MetricFamilies in the WriteRequest 88// may be modified be the MetricStore during processing of the WriteRequest! 89// 90// The Timestamp field marks the time the request was received from the 91// network. It is not related to the TimestampMs field in the Metric proto 92// message. In fact, WriteRequests containing any Metrics with a TimestampMs set 93// are invalid and will be rejected. 94// 95// The Done channel may be nil. If it is not nil, it will be closed once the 96// write request is processed. Any errors occurring during processing are sent to 97// the channel before closing it. 98type WriteRequest struct { 99 Labels map[string]string 100 Timestamp time.Time 101 MetricFamilies map[string]*dto.MetricFamily 102 Replace bool 103 Done chan error 104} 105 106// GroupingKeyToMetricGroup is the first level of the metric store, keyed by 107// grouping key. 108type GroupingKeyToMetricGroup map[string]MetricGroup 109 110// MetricGroup adds the grouping labels to a NameToTimestampedMetricFamilyMap. 111type MetricGroup struct { 112 Labels map[string]string 113 Metrics NameToTimestampedMetricFamilyMap 114} 115 116// SortedLabels returns the label names of the grouping labels sorted 117// lexicographically but with the "job" label always first. This method exists 118// for presentation purposes, see template.html. 119func (mg MetricGroup) SortedLabels() []string { 120 lns := make([]string, 1, len(mg.Labels)) 121 lns[0] = "job" 122 for ln := range mg.Labels { 123 if ln != "job" { 124 lns = append(lns, ln) 125 } 126 } 127 sort.Strings(lns[1:]) 128 return lns 129} 130 131// LastPushSuccess returns false if the automatically added metric for the 132// timestamp of the last failed push has a value larger than the value of the 133// automatically added metric for the timestamp of the last successful push. In 134// all other cases, it returns true (including the case that one or both of 135// those metrics are missing for some reason.) 136func (mg MetricGroup) LastPushSuccess() bool { 137 fail := mg.Metrics[pushFailedMetricName].GobbableMetricFamily 138 if fail == nil { 139 return true 140 } 141 success := mg.Metrics[pushMetricName].GobbableMetricFamily 142 if success == nil { 143 return true 144 } 145 return (*dto.MetricFamily)(fail).GetMetric()[0].GetGauge().GetValue() <= (*dto.MetricFamily)(success).GetMetric()[0].GetGauge().GetValue() 146} 147 148// NameToTimestampedMetricFamilyMap is the second level of the metric store, 149// keyed by metric name. 150type NameToTimestampedMetricFamilyMap map[string]TimestampedMetricFamily 151 152// TimestampedMetricFamily adds the push timestamp to a gobbable version of the 153// MetricFamily-DTO. 154type TimestampedMetricFamily struct { 155 Timestamp time.Time 156 GobbableMetricFamily *GobbableMetricFamily 157} 158 159// GetMetricFamily returns the normal GetMetricFamily DTO (without the gob additions). 160func (tmf TimestampedMetricFamily) GetMetricFamily() *dto.MetricFamily { 161 return (*dto.MetricFamily)(tmf.GobbableMetricFamily) 162} 163 164// GobbableMetricFamily is a dto.MetricFamily that implements GobDecoder and 165// GobEncoder. 166type GobbableMetricFamily dto.MetricFamily 167 168// GobDecode implements gob.GobDecoder. 169func (gmf *GobbableMetricFamily) GobDecode(b []byte) error { 170 return proto.Unmarshal(b, (*dto.MetricFamily)(gmf)) 171} 172 173// GobEncode implements gob.GobEncoder. 174func (gmf *GobbableMetricFamily) GobEncode() ([]byte, error) { 175 return proto.Marshal((*dto.MetricFamily)(gmf)) 176} 177