├── .github └── workflows │ └── semgrep.yml ├── .gitignore ├── .travis.yml ├── CONTRIBUTING.md ├── LICENSE ├── Makefile ├── README.md ├── VERSION ├── go.mod ├── go.sum ├── main.go ├── main_test.go └── vendor ├── github.com ├── beorn7 │ └── perks │ │ ├── LICENSE │ │ └── quantile │ │ ├── exampledata.txt │ │ └── stream.go ├── golang │ └── protobuf │ │ ├── AUTHORS │ │ ├── CONTRIBUTORS │ │ ├── LICENSE │ │ └── proto │ │ ├── Makefile │ │ ├── clone.go │ │ ├── decode.go │ │ ├── encode.go │ │ ├── equal.go │ │ ├── extensions.go │ │ ├── lib.go │ │ ├── message_set.go │ │ ├── pointer_reflect.go │ │ ├── pointer_unsafe.go │ │ ├── properties.go │ │ ├── text.go │ │ └── text_parser.go ├── matttproud │ └── golang_protobuf_extensions │ │ ├── LICENSE │ │ ├── NOTICE │ │ └── pbutil │ │ ├── .gitignore │ │ ├── Makefile │ │ ├── decode.go │ │ ├── doc.go │ │ └── encode.go └── prometheus │ ├── client_golang │ ├── AUTHORS.md │ ├── LICENSE │ ├── NOTICE │ └── prometheus │ │ ├── .gitignore │ │ ├── README.md │ │ ├── collector.go │ │ ├── counter.go │ │ ├── desc.go │ │ ├── doc.go │ │ ├── expvar_collector.go │ │ ├── fnv.go │ │ ├── gauge.go │ │ ├── go_collector.go │ │ ├── histogram.go │ │ ├── http.go │ │ ├── metric.go │ │ ├── process_collector.go │ │ ├── promhttp │ │ └── http.go │ │ ├── registry.go │ │ ├── summary.go │ │ ├── timer.go │ │ ├── untyped.go │ │ ├── value.go │ │ └── vec.go │ ├── client_model │ ├── AUTHORS.md │ ├── LICENSE │ ├── NOTICE │ └── go │ │ └── metrics.pb.go │ ├── common │ ├── AUTHORS.md │ ├── LICENSE │ ├── NOTICE │ ├── expfmt │ │ ├── decode.go │ │ ├── encode.go │ │ ├── expfmt.go │ │ ├── fuzz.go │ │ ├── text_create.go │ │ └── text_parse.go │ ├── internal │ │ └── bitbucket.org │ │ │ └── ww │ │ │ └── goautoneg │ │ │ ├── README.txt │ │ │ └── autoneg.go │ └── model │ │ ├── alert.go │ │ ├── fingerprinting.go │ │ ├── fnv.go │ │ ├── labels.go │ │ ├── labelset.go │ │ ├── metric.go │ │ ├── model.go │ │ ├── signature.go │ │ ├── silence.go │ │ ├── time.go │ │ └── value.go │ └── procfs │ ├── .travis.yml │ ├── AUTHORS.md │ ├── CONTRIBUTING.md │ ├── LICENSE │ ├── Makefile │ ├── NOTICE │ ├── README.md │ ├── doc.go │ ├── fs.go │ ├── ipvs.go │ ├── mdstat.go │ ├── mountstats.go │ ├── proc.go │ ├── proc_io.go │ ├── proc_limits.go │ ├── proc_stat.go │ └── stat.go └── modules.txt /.github/workflows/semgrep.yml: -------------------------------------------------------------------------------- 1 | 2 | on: 3 | pull_request: {} 4 | workflow_dispatch: {} 5 | push: 6 | branches: 7 | - main 8 | - master 9 | schedule: 10 | - cron: '0 0 * * *' 11 | name: Semgrep config 12 | jobs: 13 | semgrep: 14 | name: semgrep/ci 15 | runs-on: ubuntu-20.04 16 | env: 17 | SEMGREP_APP_TOKEN: ${{ secrets.SEMGREP_APP_TOKEN }} 18 | SEMGREP_URL: https://cloudflare.semgrep.dev 19 | SEMGREP_APP_URL: https://cloudflare.semgrep.dev 20 | SEMGREP_VERSION_CHECK_URL: https://cloudflare.semgrep.dev/api/check-version 21 | container: 22 | image: returntocorp/semgrep 23 | steps: 24 | - uses: actions/checkout@v3 25 | - run: semgrep ci 26 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | alertmanager2es 2 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: go 2 | 3 | go: 4 | - 1.18.x 5 | - master 6 | 7 | matrix: 8 | allow_failures: 9 | - go: master 10 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to alertmanager2es 2 | 3 | Contributions are welcomed. 4 | 5 | ## Getting started 6 | 7 | To download, run: 8 | 9 | go get -u github.com/cloudflare/alertmanager2es 10 | 11 | To run the tests: 12 | 13 | make test 14 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: build test 2 | 3 | build: test 4 | go build -ldflags "-X main.revision=$(shell git describe --tags --always --dirty=-dev)" 5 | 6 | test: 7 | go test $(go list ./... | grep -v /vendor/) 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # alertmanager2es 2 | 3 | alertmanager2es receives [HTTP webhook][] notifications from [AlertManager][] 4 | and inserts them into an [Elasticsearch][] index for searching and analysis. It 5 | runs as a daemon. 6 | 7 | The alerts are stored in Elasticsearch as [alert groups][]. 8 | 9 | [alert groups]: https://prometheus.io/docs/alerting/alertmanager/#grouping 10 | [AlertManager]: https://github.com/prometheus/alertmanager 11 | [Elasticsearch]: https://www.elastic.co/products/elasticsearch 12 | [HTTP webhook]: https://prometheus.io/docs/alerting/configuration/#webhook-receiver- 13 | 14 | ## Rationale 15 | 16 | It can be useful to see which alerts fired over a given time period, and 17 | perform historical analysis of when and where alerts fired. Having this data 18 | can help: 19 | 20 | - tune alerting rules 21 | - understand the impact of an incident 22 | - understand which alerts fired during an incident 23 | 24 | It might have been possible to configure Alertmanager to send the alert groups 25 | to Elasticsearch directly, if not for the fact that [Elasticsearch][] [does not 26 | support unsigned integers][] at the time of writing. Alertmanager uses an 27 | unsigned integer for the `groupKey` field, which alertmanager2es converts to a 28 | string. 29 | 30 | [does not support unsigned integers]: https://github.com/elastic/elasticsearch/issues/13951 31 | 32 | ## Limitations 33 | 34 | - alertmanager2es will not capture [silenced][] or [inhibited][] alerts; the alert 35 | notifications stored in Elasticsearch will closely resemble the notifications 36 | received by a human. 37 | 38 | [silenced]: https://prometheus.io/docs/alerting/alertmanager/#silences 39 | [inhibited]: https://prometheus.io/docs/alerting/alertmanager/#inhibition 40 | 41 | - Kibana does not display arrays of objects well (the alert groupings use an 42 | array), so you may find some irregularities when exploring the alert data in 43 | Kibana. We have not found this to be a significant limitation, and it is 44 | possible to query alert labels stored within the array. 45 | 46 | ## Prerequisites 47 | 48 | To use alertmanager2es, you'll need: 49 | 50 | - an [Elasticsearch][] cluster 51 | - [Alertmanager][] 0.6.0 or above 52 | 53 | To build alertmanager2es, you'll need: 54 | 55 | - [Make][] 56 | - [Go][] 1.7 or above 57 | - a working [GOPATH][] 58 | 59 | [Make]: https://www.gnu.org/software/make/ 60 | [Go]: https://golang.org/dl/ 61 | [GOPATH]: https://golang.org/cmd/go/#hdr-GOPATH_environment_variable 62 | 63 | ## Building 64 | 65 | go get -u github.com/cloudflare/alertmanager2es 66 | cd $GOPATH/src/github.com/cloudflare/alertmanager2es 67 | make 68 | 69 | ## Configuration 70 | 71 | ### alertmanager2es usage 72 | 73 | alertmanager2es is configured using commandline flags. It is assumed that 74 | alertmanager2es has unrestricted access to your Elasticsearch cluster. 75 | 76 | alertmanager2es does not perform any user authentication. 77 | 78 | Run `./alertmanager2es -help` to view the configurable commandline flags. 79 | 80 | ### Example Alertmanager configuration 81 | 82 | #### Receiver configuration 83 | 84 | ```yaml 85 | - name: alertmanager2es 86 | webhook_configs: 87 | - url: https://alertmanager2es.example.com/webhook 88 | ``` 89 | 90 | #### Route configuration 91 | 92 | By omitting a matcher, this route will match all alerts: 93 | 94 | ```yaml 95 | - receiver: alertmanager2es 96 | continue: true 97 | ``` 98 | 99 | ### Example Elasticsearch template 100 | 101 | Apply this Elasticsearch template before you configure alertmanager2es to start 102 | sending data: 103 | 104 | ```json 105 | { 106 | "index_patterns": [ 107 | "alertmanager-2*" 108 | ], 109 | "template": { 110 | "settings": { 111 | "number_of_shards": 1, 112 | "number_of_replicas": 1, 113 | "index.refresh_interval": "10s", 114 | "index.query.default_field": "groupLabels.alertname" 115 | }, 116 | "mappings": { 117 | "properties": { 118 | "@timestamp": { 119 | "type": "date", 120 | "doc_values": true 121 | } 122 | }, 123 | "dynamic_templates": [ 124 | { 125 | "string_fields": { 126 | "match": "*", 127 | "match_mapping_type": "string", 128 | "mapping": { 129 | "type": "text", 130 | "ignore_above": 2048 131 | } 132 | } 133 | } 134 | ] 135 | } 136 | } 137 | } 138 | ``` 139 | 140 | We rotate our index once a month, since there's not enough data to warrant 141 | daily rotation in our case. Therefore our index name looks like: 142 | 143 | alertmanager-200601 144 | 145 | We anchor the template name with `-2` to avoid inadvertently matching other 146 | indices, e.g. `alertmanager-foo-200601`. This of course assumes that you will 147 | no longer care to index your alerts in the year 3000. 148 | 149 | ## Failure modes 150 | 151 | alertmanager2es will return a HTTP 500 (Internal Server Error) if it encounters 152 | a non-2xx response from Elasticsearch. Therefore if Elasticsearch is down, 153 | alertmanager2es will respond to Alertmanager with a HTTP 500. No retries are 154 | made as Alertmanager has its own retry logic. 155 | 156 | Both the HTTP server exposed by alertmanager2es and the HTTP client that 157 | connects to Elasticsearch have read and write timeouts of 10 seconds. 158 | 159 | ## Metrics 160 | 161 | alertmanager2es exposes [Prometheus][] metrics on `/metrics`. 162 | 163 | [Prometheus]: https://prometheus.io/ 164 | 165 | ## Example Elasticsearch queries 166 | 167 | alerts.labels.alertname:"Disk_Likely_To_Fill_Next_4_Days" 168 | 169 | ## Contributions 170 | 171 | Pull requests, comments and suggestions are welcome. 172 | 173 | Please see [CONTRIBUTING.md](CONTRIBUTING.md) for more information. 174 | -------------------------------------------------------------------------------- /VERSION: -------------------------------------------------------------------------------- 1 | 0.1.0 2 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/cloudflare/alertmanager2es 2 | 3 | go 1.18 4 | 5 | require github.com/prometheus/client_golang v0.8.1-0.20161124155732-575f371f7862 6 | 7 | require ( 8 | github.com/beorn7/perks v0.0.0-20160804104726-4c0e84591b9a // indirect 9 | github.com/golang/protobuf v0.0.0-20161117033126-8ee79997227b // indirect 10 | github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect 11 | github.com/prometheus/client_model v0.0.0-20150212101744-fa8ad6fec335 // indirect 12 | github.com/prometheus/common v0.0.0-20161220174553-6d76b79f2398 // indirect 13 | github.com/prometheus/procfs v0.0.0-20161206222141-fcdb11ccb438 // indirect 14 | golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f // indirect 15 | ) 16 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/beorn7/perks v0.0.0-20160804104726-4c0e84591b9a h1:BtpsbiV638WQZwhA98cEZw2BsbnQJrbd0BI7tsy0W1c= 2 | github.com/beorn7/perks v0.0.0-20160804104726-4c0e84591b9a/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= 3 | github.com/golang/protobuf v0.0.0-20161117033126-8ee79997227b h1:fE/yi9pibxGEc0gSJuEShcsBXE2d5FW3OudsjE9tKzQ= 4 | github.com/golang/protobuf v0.0.0-20161117033126-8ee79997227b/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 5 | github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= 6 | github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= 7 | github.com/prometheus/client_golang v0.8.1-0.20161124155732-575f371f7862 h1:VOgRS97yMNL1EmGAjwJVmwMpZ/ErKQUwLDKPmM3hVnE= 8 | github.com/prometheus/client_golang v0.8.1-0.20161124155732-575f371f7862/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= 9 | github.com/prometheus/client_model v0.0.0-20150212101744-fa8ad6fec335 h1:0E/5GnGmzoDCtmzTycjGDWW33H0UBmAhR0h+FC8hWLs= 10 | github.com/prometheus/client_model v0.0.0-20150212101744-fa8ad6fec335/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= 11 | github.com/prometheus/common v0.0.0-20161220174553-6d76b79f2398 h1:GzsEVUW6VeFdoOmBt08Wq8OtIHFJ5xbL2Smw+Xn6dxQ= 12 | github.com/prometheus/common v0.0.0-20161220174553-6d76b79f2398/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= 13 | github.com/prometheus/procfs v0.0.0-20161206222141-fcdb11ccb438 h1:k/s75rGR08iSxh0TE4TCnlrkDzvo8i0MhfyF+g5fy8M= 14 | github.com/prometheus/procfs v0.0.0-20161206222141-fcdb11ccb438/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= 15 | golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f h1:Ax0t5p6N38Ga0dThY21weqDEyz2oklo4IvDkpigvkD8= 16 | golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 17 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bytes" 5 | "crypto/tls" 6 | "encoding/base64" 7 | "encoding/json" 8 | "errors" 9 | "flag" 10 | "fmt" 11 | "io/ioutil" 12 | "log" 13 | "net/http" 14 | "os" 15 | "runtime" 16 | "strings" 17 | "time" 18 | 19 | "github.com/prometheus/client_golang/prometheus" 20 | "github.com/prometheus/client_golang/prometheus/promhttp" 21 | ) 22 | 23 | const supportedWebhookVersion = "4" 24 | 25 | var ( 26 | addr = "localhost:9097" 27 | application = "alertmanager2es" 28 | // See AlertManager docs for info on alert groupings: 29 | // https://prometheus.io/docs/alerting/configuration/#route- 30 | esType = "alert_group" 31 | // Index by month as we don't produce enough data to warrant a daily index 32 | esIndexDateFormat = "2006.01" 33 | esIndexName = "alertmanager" 34 | esURL string 35 | esUser string 36 | esPass string 37 | disableCertCheck = false 38 | revision = "unknown" 39 | versionString = fmt.Sprintf("%s %s (%s)", application, revision, runtime.Version()) 40 | 41 | notificationsErrored = prometheus.NewCounter(prometheus.CounterOpts{ 42 | Namespace: application, 43 | Name: "notifications_errored_total", 44 | Help: "Total number of alert notifications that errored during processing and should be retried", 45 | }) 46 | notificationsInvalid = prometheus.NewCounter(prometheus.CounterOpts{ 47 | Namespace: application, 48 | Name: "notifications_invalid_total", 49 | Help: "Total number of invalid alert notifications received", 50 | }) 51 | notificationsReceived = prometheus.NewCounter(prometheus.CounterOpts{ 52 | Namespace: application, 53 | Name: "notifications_received_total", 54 | Help: "Total number of alert notifications received", 55 | }) 56 | ) 57 | 58 | func empty(s string) bool { 59 | return len(strings.TrimSpace(s)) == 0 60 | } 61 | 62 | func basicAuth(username, password string) string { 63 | auth := username + ":" + password 64 | return base64.StdEncoding.EncodeToString([]byte(auth)) 65 | } 66 | 67 | func init() { 68 | prometheus.MustRegister(notificationsErrored) 69 | prometheus.MustRegister(notificationsInvalid) 70 | prometheus.MustRegister(notificationsReceived) 71 | } 72 | 73 | func main() { 74 | var showVersion bool 75 | flag.StringVar(&addr, "addr", addr, "host:port to listen to") 76 | flag.StringVar(&esIndexDateFormat, "esIndexDateFormat", esIndexDateFormat, "Elasticsearch index date format") 77 | flag.StringVar(&esIndexName, "esIndexName", esIndexName, "Elasticsearch index name") 78 | flag.StringVar(&esType, "esType", esType, "Elasticsearch document type ('_type')") 79 | flag.StringVar(&esURL, "esURL", esURL, "Elasticsearch HTTP URL") 80 | flag.StringVar(&esUser, "esUser", os.Getenv("ES_USER"), "Elasticsearch user (default value is taken from $ES_USER environment variable)") 81 | flag.StringVar(&esPass, "esPass", os.Getenv("ES_PASS"), "Elasticsearch password (default value is taken from $ES_PASS environment variable)") 82 | flag.BoolVar(&disableCertCheck, "disableCertCheck", false, "Disable SSL certificate check") 83 | flag.BoolVar(&showVersion, "version", false, "Print version number and exit") 84 | flag.Parse() 85 | 86 | if showVersion { 87 | fmt.Println(versionString) 88 | os.Exit(0) 89 | } 90 | 91 | if esURL == "" { 92 | fmt.Fprintln(os.Stderr, "Must specify HTTP URL for Elasticsearch") 93 | flag.Usage() 94 | os.Exit(2) 95 | } 96 | 97 | http.DefaultClient.Timeout = 10 * time.Second 98 | s := &http.Server{ 99 | Addr: addr, 100 | ReadTimeout: 10 * time.Second, 101 | WriteTimeout: 10 * time.Second, 102 | } 103 | 104 | http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { 105 | fmt.Fprint(w, versionString) 106 | }) 107 | http.Handle("/metrics", promhttp.Handler()) 108 | http.HandleFunc("/webhook", prometheus.InstrumentHandlerFunc("webhook", http.HandlerFunc(handler))) 109 | 110 | log.Print(versionString) 111 | log.Printf("Listening on %s", addr) 112 | log.Fatal(s.ListenAndServe()) 113 | } 114 | 115 | func handler(w http.ResponseWriter, r *http.Request) { 116 | notificationsReceived.Inc() 117 | 118 | if r.Body == nil { 119 | notificationsInvalid.Inc() 120 | err := errors.New("got empty request body") 121 | http.Error(w, err.Error(), http.StatusBadRequest) 122 | log.Print(err) 123 | return 124 | } 125 | 126 | b, err := ioutil.ReadAll(r.Body) 127 | if err != nil { 128 | notificationsErrored.Inc() 129 | http.Error(w, err.Error(), http.StatusInternalServerError) 130 | log.Print(err) 131 | return 132 | } 133 | defer r.Body.Close() 134 | 135 | var msg notification 136 | err = json.Unmarshal(b, &msg) 137 | if err != nil { 138 | notificationsInvalid.Inc() 139 | http.Error(w, err.Error(), http.StatusBadRequest) 140 | log.Print(err) 141 | return 142 | } 143 | 144 | if msg.Version != supportedWebhookVersion { 145 | notificationsInvalid.Inc() 146 | err := fmt.Errorf("do not understand webhook version %q, only version %q is supported", msg.Version, supportedWebhookVersion) 147 | http.Error(w, err.Error(), http.StatusBadRequest) 148 | log.Print(err) 149 | return 150 | } 151 | 152 | now := time.Now() 153 | // ISO8601: https://github.com/golang/go/issues/2141#issuecomment-66058048 154 | msg.Timestamp = now.Format(time.RFC3339) 155 | 156 | index := fmt.Sprintf("%s-%s/%s", esIndexName, now.Format(esIndexDateFormat), esType) 157 | url := fmt.Sprintf("%s/%s", esURL, index) 158 | 159 | b, err = json.Marshal(&msg) 160 | if err != nil { 161 | notificationsErrored.Inc() 162 | http.Error(w, err.Error(), http.StatusInternalServerError) 163 | log.Print(err) 164 | return 165 | } 166 | 167 | if disableCertCheck { 168 | http.DefaultTransport.(*http.Transport).TLSClientConfig = &tls.Config{InsecureSkipVerify: true} 169 | } 170 | 171 | req, err := http.NewRequest("POST", url, bytes.NewBuffer(b)) 172 | if err != nil { 173 | notificationsErrored.Inc() 174 | http.Error(w, err.Error(), http.StatusInternalServerError) 175 | log.Print(err) 176 | return 177 | } 178 | 179 | req.Header.Set("User-Agent", versionString) 180 | req.Header.Set("Content-Type", "application/json") 181 | 182 | client := new(http.Client) 183 | if !empty(esUser) && !empty(esPass) { 184 | req.Header.Add("Authorization", "Basic "+basicAuth(esUser, esPass)) 185 | client.CheckRedirect = func(req *http.Request, via []*http.Request) error { 186 | req.Header.Add("Authorization", "Basic "+basicAuth(esUser, esPass)) 187 | return nil 188 | } 189 | } 190 | 191 | resp, err := client.Do(req) 192 | if err != nil { 193 | notificationsErrored.Inc() 194 | http.Error(w, err.Error(), http.StatusInternalServerError) 195 | log.Print(err) 196 | return 197 | } 198 | 199 | body, err := ioutil.ReadAll(resp.Body) 200 | defer resp.Body.Close() 201 | if err != nil { 202 | notificationsErrored.Inc() 203 | http.Error(w, err.Error(), http.StatusInternalServerError) 204 | log.Print(err) 205 | return 206 | } 207 | 208 | if resp.StatusCode/100 != 2 { 209 | notificationsErrored.Inc() 210 | err := fmt.Errorf("POST to Elasticsearch on %q returned HTTP %d: %s", url, resp.StatusCode, body) 211 | http.Error(w, err.Error(), http.StatusInternalServerError) 212 | log.Print(err) 213 | return 214 | } 215 | } 216 | 217 | type notification struct { 218 | Alerts []struct { 219 | Annotations map[string]string `json:"annotations"` 220 | EndsAt time.Time `json:"endsAt"` 221 | GeneratorURL string `json:"generatorURL"` 222 | Labels map[string]string `json:"labels"` 223 | StartsAt time.Time `json:"startsAt"` 224 | Status string `json:"status"` 225 | } `json:"alerts"` 226 | CommonAnnotations map[string]string `json:"commonAnnotations"` 227 | CommonLabels map[string]string `json:"commonLabels"` 228 | ExternalURL string `json:"externalURL"` 229 | GroupLabels map[string]string `json:"groupLabels"` 230 | Receiver string `json:"receiver"` 231 | Status string `json:"status"` 232 | Version string `json:"version"` 233 | GroupKey string `json:"groupKey"` 234 | 235 | // Timestamp records when the alert notification was received 236 | Timestamp string `json:"@timestamp"` 237 | } 238 | -------------------------------------------------------------------------------- /main_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "io" 7 | "io/ioutil" 8 | "net/http" 9 | "net/http/httptest" 10 | "net/url" 11 | "regexp" 12 | "testing" 13 | "time" 14 | ) 15 | 16 | func TestHappyPath(t *testing.T) { 17 | var ( 18 | request *http.Request 19 | requestBody []byte 20 | ) 21 | s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 22 | var err error 23 | 24 | if r.Body == nil { 25 | t.Fatal("got empty response body") 26 | return 27 | } 28 | requestBody, err = ioutil.ReadAll(r.Body) 29 | if err != nil { 30 | t.Fatal(err) 31 | } 32 | request = r 33 | 34 | io.WriteString(w, "OK\n") 35 | })) 36 | defer s.Close() 37 | 38 | esURL = s.URL 39 | w, r := recordedRequest(t, s.URL+"/webhook") 40 | handler(w, r) 41 | 42 | expectedCode := http.StatusOK 43 | if w.Code != expectedCode { 44 | t.Fatalf("expected HTTP status %d, got %d", expectedCode, w.Code) 45 | } 46 | 47 | u, _ := url.Parse(s.URL) 48 | expected := u.Host 49 | if request.Host != expected { 50 | t.Fatalf("expected request host %s, got %s", expected, request.Host) 51 | } 52 | 53 | expected = "POST" 54 | if request.Method != expected { 55 | t.Fatalf("expected request method %s, got %s", expected, request.Method) 56 | } 57 | 58 | expected = fmt.Sprintf("/alertmanager-%s/alert_group", time.Now().Format("2006.01")) 59 | if request.RequestURI != expected { 60 | t.Fatalf("expected request path %s, got %s", expected, request.RequestURI) 61 | } 62 | 63 | // the timestamp changes every second, making it hard to test, so strip it off before comparing 64 | lengthOfTimestamp := 42 65 | l := len(esDocument) - lengthOfTimestamp 66 | if !bytes.Equal(esDocument[:l], requestBody[:l]) { 67 | t.Fatalf("expected payload %q, got %q", esDocument[:l], requestBody[:l]) 68 | } 69 | } 70 | 71 | func TestErrorsPassedThrough(t *testing.T) { 72 | // Mock Elasticsearch server returns 404s 73 | s := httptest.NewServer(http.NotFoundHandler()) 74 | defer s.Close() 75 | 76 | esURL = s.URL 77 | w, r := recordedRequest(t, s.URL+"/webhook") 78 | handler(w, r) 79 | 80 | expectedCode := http.StatusInternalServerError 81 | if w.Code != expectedCode { 82 | t.Fatalf("expected HTTP status %d, got %d", expectedCode, w.Code) 83 | } 84 | } 85 | 86 | func TestUserAgentSetWhenPostingToElasticsearch(t *testing.T) { 87 | var userAgent string 88 | s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 89 | userAgent = r.UserAgent() 90 | })) 91 | defer s.Close() 92 | 93 | esURL = s.URL 94 | w, r := recordedRequest(t, s.URL+"/webhook") 95 | handler(w, r) 96 | 97 | expected := regexp.MustCompile(`^alertmanager2es .*? \(go\d.\d+(?:.\d+)?\)$`) 98 | if !expected.MatchString(userAgent) { 99 | t.Fatalf("expected user agent to match %s, got %q", expected.String(), userAgent) 100 | } 101 | 102 | } 103 | 104 | func recordedRequest(t *testing.T, url string) (*httptest.ResponseRecorder, *http.Request) { 105 | w := httptest.NewRecorder() 106 | r, err := http.NewRequest("POST", url, bytes.NewBuffer(amNotification)) 107 | if err != nil { 108 | t.Fatal(err) 109 | } 110 | 111 | return w, r 112 | } 113 | 114 | var amNotification = []byte(`{ 115 | "alerts": [ 116 | { 117 | "annotations": { 118 | "link": "https://example.com/Foo+Bar", 119 | "summary": "Alert summary" 120 | }, 121 | "endsAt": "0001-01-01T00:00:00Z", 122 | "generatorURL": "https://example.com", 123 | "labels": { 124 | "alertname": "Foo_Bar", 125 | "instance": "foo" 126 | }, 127 | "startsAt": "2017-02-02T16:51:13.507955756Z", 128 | "status": "firing" 129 | } 130 | ], 131 | "commonAnnotations": { 132 | "link": "https://example.com/Foo+Bar", 133 | "summary": "Alert summary" 134 | }, 135 | "commonLabels": { 136 | "alertname": "Foo_Bar", 137 | "instance": "foo" 138 | }, 139 | "externalURL": "https://alertmanager.example.com", 140 | "groupLabels": { 141 | "alertname": "Foo_Bar" 142 | }, 143 | "receiver": "alertmanager2es", 144 | "status": "firing", 145 | "version": "4", 146 | "groupKey": "{}/{}/{notify=\"default\":{alertname=\"Foo_Bar\", instance=\"foo\"}" 147 | }`) 148 | 149 | var esDocument = []byte(`{"alerts":[{"annotations":{"link":"https://example.com/Foo+Bar","summary":"Alert summary"},"endsAt":"0001-01-01T00:00:00Z","generatorURL":"https://example.com","labels":{"alertname":"Foo_Bar","instance":"foo"},"startsAt":"2017-02-02T16:51:13.507955756Z","status":"firing"}],"commonAnnotations":{"link":"https://example.com/Foo+Bar","summary":"Alert summary"},"commonLabels":{"alertname":"Foo_Bar","instance":"foo"},"externalURL":"https://alertmanager.example.com","groupLabels":{"alertname":"Foo_Bar"},"receiver":"alertmanager2es","status":"firing","version":"4","groupKey":"{}/{}/{notify=\"default\":{alertname=\"Foo_Bar\", instance=\"foo\"}","@timestamp":"2017-02-02T19:37:22+01:00"}`) 150 | -------------------------------------------------------------------------------- /vendor/github.com/beorn7/perks/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (C) 2013 Blake Mizerany 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /vendor/github.com/beorn7/perks/quantile/stream.go: -------------------------------------------------------------------------------- 1 | // Package quantile computes approximate quantiles over an unbounded data 2 | // stream within low memory and CPU bounds. 3 | // 4 | // A small amount of accuracy is traded to achieve the above properties. 5 | // 6 | // Multiple streams can be merged before calling Query to generate a single set 7 | // of results. This is meaningful when the streams represent the same type of 8 | // data. See Merge and Samples. 9 | // 10 | // For more detailed information about the algorithm used, see: 11 | // 12 | // Effective Computation of Biased Quantiles over Data Streams 13 | // 14 | // http://www.cs.rutgers.edu/~muthu/bquant.pdf 15 | package quantile 16 | 17 | import ( 18 | "math" 19 | "sort" 20 | ) 21 | 22 | // Sample holds an observed value and meta information for compression. JSON 23 | // tags have been added for convenience. 24 | type Sample struct { 25 | Value float64 `json:",string"` 26 | Width float64 `json:",string"` 27 | Delta float64 `json:",string"` 28 | } 29 | 30 | // Samples represents a slice of samples. It implements sort.Interface. 31 | type Samples []Sample 32 | 33 | func (a Samples) Len() int { return len(a) } 34 | func (a Samples) Less(i, j int) bool { return a[i].Value < a[j].Value } 35 | func (a Samples) Swap(i, j int) { a[i], a[j] = a[j], a[i] } 36 | 37 | type invariant func(s *stream, r float64) float64 38 | 39 | // NewLowBiased returns an initialized Stream for low-biased quantiles 40 | // (e.g. 0.01, 0.1, 0.5) where the needed quantiles are not known a priori, but 41 | // error guarantees can still be given even for the lower ranks of the data 42 | // distribution. 43 | // 44 | // The provided epsilon is a relative error, i.e. the true quantile of a value 45 | // returned by a query is guaranteed to be within (1±Epsilon)*Quantile. 46 | // 47 | // See http://www.cs.rutgers.edu/~muthu/bquant.pdf for time, space, and error 48 | // properties. 49 | func NewLowBiased(epsilon float64) *Stream { 50 | ƒ := func(s *stream, r float64) float64 { 51 | return 2 * epsilon * r 52 | } 53 | return newStream(ƒ) 54 | } 55 | 56 | // NewHighBiased returns an initialized Stream for high-biased quantiles 57 | // (e.g. 0.01, 0.1, 0.5) where the needed quantiles are not known a priori, but 58 | // error guarantees can still be given even for the higher ranks of the data 59 | // distribution. 60 | // 61 | // The provided epsilon is a relative error, i.e. the true quantile of a value 62 | // returned by a query is guaranteed to be within 1-(1±Epsilon)*(1-Quantile). 63 | // 64 | // See http://www.cs.rutgers.edu/~muthu/bquant.pdf for time, space, and error 65 | // properties. 66 | func NewHighBiased(epsilon float64) *Stream { 67 | ƒ := func(s *stream, r float64) float64 { 68 | return 2 * epsilon * (s.n - r) 69 | } 70 | return newStream(ƒ) 71 | } 72 | 73 | // NewTargeted returns an initialized Stream concerned with a particular set of 74 | // quantile values that are supplied a priori. Knowing these a priori reduces 75 | // space and computation time. The targets map maps the desired quantiles to 76 | // their absolute errors, i.e. the true quantile of a value returned by a query 77 | // is guaranteed to be within (Quantile±Epsilon). 78 | // 79 | // See http://www.cs.rutgers.edu/~muthu/bquant.pdf for time, space, and error properties. 80 | func NewTargeted(targets map[float64]float64) *Stream { 81 | ƒ := func(s *stream, r float64) float64 { 82 | var m = math.MaxFloat64 83 | var f float64 84 | for quantile, epsilon := range targets { 85 | if quantile*s.n <= r { 86 | f = (2 * epsilon * r) / quantile 87 | } else { 88 | f = (2 * epsilon * (s.n - r)) / (1 - quantile) 89 | } 90 | if f < m { 91 | m = f 92 | } 93 | } 94 | return m 95 | } 96 | return newStream(ƒ) 97 | } 98 | 99 | // Stream computes quantiles for a stream of float64s. It is not thread-safe by 100 | // design. Take care when using across multiple goroutines. 101 | type Stream struct { 102 | *stream 103 | b Samples 104 | sorted bool 105 | } 106 | 107 | func newStream(ƒ invariant) *Stream { 108 | x := &stream{ƒ: ƒ} 109 | return &Stream{x, make(Samples, 0, 500), true} 110 | } 111 | 112 | // Insert inserts v into the stream. 113 | func (s *Stream) Insert(v float64) { 114 | s.insert(Sample{Value: v, Width: 1}) 115 | } 116 | 117 | func (s *Stream) insert(sample Sample) { 118 | s.b = append(s.b, sample) 119 | s.sorted = false 120 | if len(s.b) == cap(s.b) { 121 | s.flush() 122 | } 123 | } 124 | 125 | // Query returns the computed qth percentiles value. If s was created with 126 | // NewTargeted, and q is not in the set of quantiles provided a priori, Query 127 | // will return an unspecified result. 128 | func (s *Stream) Query(q float64) float64 { 129 | if !s.flushed() { 130 | // Fast path when there hasn't been enough data for a flush; 131 | // this also yields better accuracy for small sets of data. 132 | l := len(s.b) 133 | if l == 0 { 134 | return 0 135 | } 136 | i := int(math.Ceil(float64(l) * q)) 137 | if i > 0 { 138 | i -= 1 139 | } 140 | s.maybeSort() 141 | return s.b[i].Value 142 | } 143 | s.flush() 144 | return s.stream.query(q) 145 | } 146 | 147 | // Merge merges samples into the underlying streams samples. This is handy when 148 | // merging multiple streams from separate threads, database shards, etc. 149 | // 150 | // ATTENTION: This method is broken and does not yield correct results. The 151 | // underlying algorithm is not capable of merging streams correctly. 152 | func (s *Stream) Merge(samples Samples) { 153 | sort.Sort(samples) 154 | s.stream.merge(samples) 155 | } 156 | 157 | // Reset reinitializes and clears the list reusing the samples buffer memory. 158 | func (s *Stream) Reset() { 159 | s.stream.reset() 160 | s.b = s.b[:0] 161 | } 162 | 163 | // Samples returns stream samples held by s. 164 | func (s *Stream) Samples() Samples { 165 | if !s.flushed() { 166 | return s.b 167 | } 168 | s.flush() 169 | return s.stream.samples() 170 | } 171 | 172 | // Count returns the total number of samples observed in the stream 173 | // since initialization. 174 | func (s *Stream) Count() int { 175 | return len(s.b) + s.stream.count() 176 | } 177 | 178 | func (s *Stream) flush() { 179 | s.maybeSort() 180 | s.stream.merge(s.b) 181 | s.b = s.b[:0] 182 | } 183 | 184 | func (s *Stream) maybeSort() { 185 | if !s.sorted { 186 | s.sorted = true 187 | sort.Sort(s.b) 188 | } 189 | } 190 | 191 | func (s *Stream) flushed() bool { 192 | return len(s.stream.l) > 0 193 | } 194 | 195 | type stream struct { 196 | n float64 197 | l []Sample 198 | ƒ invariant 199 | } 200 | 201 | func (s *stream) reset() { 202 | s.l = s.l[:0] 203 | s.n = 0 204 | } 205 | 206 | func (s *stream) insert(v float64) { 207 | s.merge(Samples{{v, 1, 0}}) 208 | } 209 | 210 | func (s *stream) merge(samples Samples) { 211 | // TODO(beorn7): This tries to merge not only individual samples, but 212 | // whole summaries. The paper doesn't mention merging summaries at 213 | // all. Unittests show that the merging is inaccurate. Find out how to 214 | // do merges properly. 215 | var r float64 216 | i := 0 217 | for _, sample := range samples { 218 | for ; i < len(s.l); i++ { 219 | c := s.l[i] 220 | if c.Value > sample.Value { 221 | // Insert at position i. 222 | s.l = append(s.l, Sample{}) 223 | copy(s.l[i+1:], s.l[i:]) 224 | s.l[i] = Sample{ 225 | sample.Value, 226 | sample.Width, 227 | math.Max(sample.Delta, math.Floor(s.ƒ(s, r))-1), 228 | // TODO(beorn7): How to calculate delta correctly? 229 | } 230 | i++ 231 | goto inserted 232 | } 233 | r += c.Width 234 | } 235 | s.l = append(s.l, Sample{sample.Value, sample.Width, 0}) 236 | i++ 237 | inserted: 238 | s.n += sample.Width 239 | r += sample.Width 240 | } 241 | s.compress() 242 | } 243 | 244 | func (s *stream) count() int { 245 | return int(s.n) 246 | } 247 | 248 | func (s *stream) query(q float64) float64 { 249 | t := math.Ceil(q * s.n) 250 | t += math.Ceil(s.ƒ(s, t) / 2) 251 | p := s.l[0] 252 | var r float64 253 | for _, c := range s.l[1:] { 254 | r += p.Width 255 | if r+c.Width+c.Delta > t { 256 | return p.Value 257 | } 258 | p = c 259 | } 260 | return p.Value 261 | } 262 | 263 | func (s *stream) compress() { 264 | if len(s.l) < 2 { 265 | return 266 | } 267 | x := s.l[len(s.l)-1] 268 | xi := len(s.l) - 1 269 | r := s.n - 1 - x.Width 270 | 271 | for i := len(s.l) - 2; i >= 0; i-- { 272 | c := s.l[i] 273 | if c.Width+x.Width+x.Delta <= s.ƒ(s, r) { 274 | x.Width += c.Width 275 | s.l[xi] = x 276 | // Remove element at i. 277 | copy(s.l[i:], s.l[i+1:]) 278 | s.l = s.l[:len(s.l)-1] 279 | xi -= 1 280 | } else { 281 | x = c 282 | xi = i 283 | } 284 | r -= c.Width 285 | } 286 | } 287 | 288 | func (s *stream) samples() Samples { 289 | samples := make(Samples, len(s.l)) 290 | copy(samples, s.l) 291 | return samples 292 | } 293 | -------------------------------------------------------------------------------- /vendor/github.com/golang/protobuf/AUTHORS: -------------------------------------------------------------------------------- 1 | # This source code refers to The Go Authors for copyright purposes. 2 | # The master list of authors is in the main Go distribution, 3 | # visible at http://tip.golang.org/AUTHORS. 4 | -------------------------------------------------------------------------------- /vendor/github.com/golang/protobuf/CONTRIBUTORS: -------------------------------------------------------------------------------- 1 | # This source code was written by the Go contributors. 2 | # The master list of contributors is in the main Go distribution, 3 | # visible at http://tip.golang.org/CONTRIBUTORS. 4 | -------------------------------------------------------------------------------- /vendor/github.com/golang/protobuf/LICENSE: -------------------------------------------------------------------------------- 1 | Go support for Protocol Buffers - Google's data interchange format 2 | 3 | Copyright 2010 The Go Authors. All rights reserved. 4 | https://github.com/golang/protobuf 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are 8 | met: 9 | 10 | * Redistributions of source code must retain the above copyright 11 | notice, this list of conditions and the following disclaimer. 12 | * Redistributions in binary form must reproduce the above 13 | copyright notice, this list of conditions and the following disclaimer 14 | in the documentation and/or other materials provided with the 15 | distribution. 16 | * Neither the name of Google Inc. nor the names of its 17 | contributors may be used to endorse or promote products derived from 18 | this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 23 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 24 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 26 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | 32 | -------------------------------------------------------------------------------- /vendor/github.com/golang/protobuf/proto/Makefile: -------------------------------------------------------------------------------- 1 | # Go support for Protocol Buffers - Google's data interchange format 2 | # 3 | # Copyright 2010 The Go Authors. All rights reserved. 4 | # https://github.com/golang/protobuf 5 | # 6 | # Redistribution and use in source and binary forms, with or without 7 | # modification, are permitted provided that the following conditions are 8 | # met: 9 | # 10 | # * Redistributions of source code must retain the above copyright 11 | # notice, this list of conditions and the following disclaimer. 12 | # * Redistributions in binary form must reproduce the above 13 | # copyright notice, this list of conditions and the following disclaimer 14 | # in the documentation and/or other materials provided with the 15 | # distribution. 16 | # * Neither the name of Google Inc. nor the names of its 17 | # contributors may be used to endorse or promote products derived from 18 | # this software without specific prior written permission. 19 | # 20 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 | # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 | # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 23 | # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 24 | # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25 | # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 26 | # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 | # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 | # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 | # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | 32 | install: 33 | go install 34 | 35 | test: install generate-test-pbs 36 | go test 37 | 38 | 39 | generate-test-pbs: 40 | make install 41 | make -C testdata 42 | protoc --go_out=Mtestdata/test.proto=github.com/golang/protobuf/proto/testdata,Mgoogle/protobuf/any.proto=github.com/golang/protobuf/ptypes/any:. proto3_proto/proto3.proto 43 | make 44 | -------------------------------------------------------------------------------- /vendor/github.com/golang/protobuf/proto/clone.go: -------------------------------------------------------------------------------- 1 | // Go support for Protocol Buffers - Google's data interchange format 2 | // 3 | // Copyright 2011 The Go Authors. All rights reserved. 4 | // https://github.com/golang/protobuf 5 | // 6 | // Redistribution and use in source and binary forms, with or without 7 | // modification, are permitted provided that the following conditions are 8 | // met: 9 | // 10 | // * Redistributions of source code must retain the above copyright 11 | // notice, this list of conditions and the following disclaimer. 12 | // * Redistributions in binary form must reproduce the above 13 | // copyright notice, this list of conditions and the following disclaimer 14 | // in the documentation and/or other materials provided with the 15 | // distribution. 16 | // * Neither the name of Google Inc. nor the names of its 17 | // contributors may be used to endorse or promote products derived from 18 | // this software without specific prior written permission. 19 | // 20 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 23 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 24 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 26 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | 32 | // Protocol buffer deep copy and merge. 33 | // TODO: RawMessage. 34 | 35 | package proto 36 | 37 | import ( 38 | "log" 39 | "reflect" 40 | "strings" 41 | ) 42 | 43 | // Clone returns a deep copy of a protocol buffer. 44 | func Clone(pb Message) Message { 45 | in := reflect.ValueOf(pb) 46 | if in.IsNil() { 47 | return pb 48 | } 49 | 50 | out := reflect.New(in.Type().Elem()) 51 | // out is empty so a merge is a deep copy. 52 | mergeStruct(out.Elem(), in.Elem()) 53 | return out.Interface().(Message) 54 | } 55 | 56 | // Merge merges src into dst. 57 | // Required and optional fields that are set in src will be set to that value in dst. 58 | // Elements of repeated fields will be appended. 59 | // Merge panics if src and dst are not the same type, or if dst is nil. 60 | func Merge(dst, src Message) { 61 | in := reflect.ValueOf(src) 62 | out := reflect.ValueOf(dst) 63 | if out.IsNil() { 64 | panic("proto: nil destination") 65 | } 66 | if in.Type() != out.Type() { 67 | // Explicit test prior to mergeStruct so that mistyped nils will fail 68 | panic("proto: type mismatch") 69 | } 70 | if in.IsNil() { 71 | // Merging nil into non-nil is a quiet no-op 72 | return 73 | } 74 | mergeStruct(out.Elem(), in.Elem()) 75 | } 76 | 77 | func mergeStruct(out, in reflect.Value) { 78 | sprop := GetProperties(in.Type()) 79 | for i := 0; i < in.NumField(); i++ { 80 | f := in.Type().Field(i) 81 | if strings.HasPrefix(f.Name, "XXX_") { 82 | continue 83 | } 84 | mergeAny(out.Field(i), in.Field(i), false, sprop.Prop[i]) 85 | } 86 | 87 | if emIn, ok := extendable(in.Addr().Interface()); ok { 88 | emOut, _ := extendable(out.Addr().Interface()) 89 | mIn, muIn := emIn.extensionsRead() 90 | if mIn != nil { 91 | mOut := emOut.extensionsWrite() 92 | muIn.Lock() 93 | mergeExtension(mOut, mIn) 94 | muIn.Unlock() 95 | } 96 | } 97 | 98 | uf := in.FieldByName("XXX_unrecognized") 99 | if !uf.IsValid() { 100 | return 101 | } 102 | uin := uf.Bytes() 103 | if len(uin) > 0 { 104 | out.FieldByName("XXX_unrecognized").SetBytes(append([]byte(nil), uin...)) 105 | } 106 | } 107 | 108 | // mergeAny performs a merge between two values of the same type. 109 | // viaPtr indicates whether the values were indirected through a pointer (implying proto2). 110 | // prop is set if this is a struct field (it may be nil). 111 | func mergeAny(out, in reflect.Value, viaPtr bool, prop *Properties) { 112 | if in.Type() == protoMessageType { 113 | if !in.IsNil() { 114 | if out.IsNil() { 115 | out.Set(reflect.ValueOf(Clone(in.Interface().(Message)))) 116 | } else { 117 | Merge(out.Interface().(Message), in.Interface().(Message)) 118 | } 119 | } 120 | return 121 | } 122 | switch in.Kind() { 123 | case reflect.Bool, reflect.Float32, reflect.Float64, reflect.Int32, reflect.Int64, 124 | reflect.String, reflect.Uint32, reflect.Uint64: 125 | if !viaPtr && isProto3Zero(in) { 126 | return 127 | } 128 | out.Set(in) 129 | case reflect.Interface: 130 | // Probably a oneof field; copy non-nil values. 131 | if in.IsNil() { 132 | return 133 | } 134 | // Allocate destination if it is not set, or set to a different type. 135 | // Otherwise we will merge as normal. 136 | if out.IsNil() || out.Elem().Type() != in.Elem().Type() { 137 | out.Set(reflect.New(in.Elem().Elem().Type())) // interface -> *T -> T -> new(T) 138 | } 139 | mergeAny(out.Elem(), in.Elem(), false, nil) 140 | case reflect.Map: 141 | if in.Len() == 0 { 142 | return 143 | } 144 | if out.IsNil() { 145 | out.Set(reflect.MakeMap(in.Type())) 146 | } 147 | // For maps with value types of *T or []byte we need to deep copy each value. 148 | elemKind := in.Type().Elem().Kind() 149 | for _, key := range in.MapKeys() { 150 | var val reflect.Value 151 | switch elemKind { 152 | case reflect.Ptr: 153 | val = reflect.New(in.Type().Elem().Elem()) 154 | mergeAny(val, in.MapIndex(key), false, nil) 155 | case reflect.Slice: 156 | val = in.MapIndex(key) 157 | val = reflect.ValueOf(append([]byte{}, val.Bytes()...)) 158 | default: 159 | val = in.MapIndex(key) 160 | } 161 | out.SetMapIndex(key, val) 162 | } 163 | case reflect.Ptr: 164 | if in.IsNil() { 165 | return 166 | } 167 | if out.IsNil() { 168 | out.Set(reflect.New(in.Elem().Type())) 169 | } 170 | mergeAny(out.Elem(), in.Elem(), true, nil) 171 | case reflect.Slice: 172 | if in.IsNil() { 173 | return 174 | } 175 | if in.Type().Elem().Kind() == reflect.Uint8 { 176 | // []byte is a scalar bytes field, not a repeated field. 177 | 178 | // Edge case: if this is in a proto3 message, a zero length 179 | // bytes field is considered the zero value, and should not 180 | // be merged. 181 | if prop != nil && prop.proto3 && in.Len() == 0 { 182 | return 183 | } 184 | 185 | // Make a deep copy. 186 | // Append to []byte{} instead of []byte(nil) so that we never end up 187 | // with a nil result. 188 | out.SetBytes(append([]byte{}, in.Bytes()...)) 189 | return 190 | } 191 | n := in.Len() 192 | if out.IsNil() { 193 | out.Set(reflect.MakeSlice(in.Type(), 0, n)) 194 | } 195 | switch in.Type().Elem().Kind() { 196 | case reflect.Bool, reflect.Float32, reflect.Float64, reflect.Int32, reflect.Int64, 197 | reflect.String, reflect.Uint32, reflect.Uint64: 198 | out.Set(reflect.AppendSlice(out, in)) 199 | default: 200 | for i := 0; i < n; i++ { 201 | x := reflect.Indirect(reflect.New(in.Type().Elem())) 202 | mergeAny(x, in.Index(i), false, nil) 203 | out.Set(reflect.Append(out, x)) 204 | } 205 | } 206 | case reflect.Struct: 207 | mergeStruct(out, in) 208 | default: 209 | // unknown type, so not a protocol buffer 210 | log.Printf("proto: don't know how to copy %v", in) 211 | } 212 | } 213 | 214 | func mergeExtension(out, in map[int32]Extension) { 215 | for extNum, eIn := range in { 216 | eOut := Extension{desc: eIn.desc} 217 | if eIn.value != nil { 218 | v := reflect.New(reflect.TypeOf(eIn.value)).Elem() 219 | mergeAny(v, reflect.ValueOf(eIn.value), false, nil) 220 | eOut.value = v.Interface() 221 | } 222 | if eIn.enc != nil { 223 | eOut.enc = make([]byte, len(eIn.enc)) 224 | copy(eOut.enc, eIn.enc) 225 | } 226 | 227 | out[extNum] = eOut 228 | } 229 | } 230 | -------------------------------------------------------------------------------- /vendor/github.com/matttproud/golang_protobuf_extensions/NOTICE: -------------------------------------------------------------------------------- 1 | Copyright 2012 Matt T. Proud (matt.proud@gmail.com) 2 | -------------------------------------------------------------------------------- /vendor/github.com/matttproud/golang_protobuf_extensions/pbutil/.gitignore: -------------------------------------------------------------------------------- 1 | cover.dat 2 | -------------------------------------------------------------------------------- /vendor/github.com/matttproud/golang_protobuf_extensions/pbutil/Makefile: -------------------------------------------------------------------------------- 1 | all: 2 | 3 | cover: 4 | go test -cover -v -coverprofile=cover.dat ./... 5 | go tool cover -func cover.dat 6 | 7 | .PHONY: cover 8 | -------------------------------------------------------------------------------- /vendor/github.com/matttproud/golang_protobuf_extensions/pbutil/decode.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 Matt T. Proud 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package pbutil 16 | 17 | import ( 18 | "encoding/binary" 19 | "errors" 20 | "io" 21 | 22 | "github.com/golang/protobuf/proto" 23 | ) 24 | 25 | var errInvalidVarint = errors.New("invalid varint32 encountered") 26 | 27 | // ReadDelimited decodes a message from the provided length-delimited stream, 28 | // where the length is encoded as 32-bit varint prefix to the message body. 29 | // It returns the total number of bytes read and any applicable error. This is 30 | // roughly equivalent to the companion Java API's 31 | // MessageLite#parseDelimitedFrom. As per the reader contract, this function 32 | // calls r.Read repeatedly as required until exactly one message including its 33 | // prefix is read and decoded (or an error has occurred). The function never 34 | // reads more bytes from the stream than required. The function never returns 35 | // an error if a message has been read and decoded correctly, even if the end 36 | // of the stream has been reached in doing so. In that case, any subsequent 37 | // calls return (0, io.EOF). 38 | func ReadDelimited(r io.Reader, m proto.Message) (n int, err error) { 39 | // Per AbstractParser#parsePartialDelimitedFrom with 40 | // CodedInputStream#readRawVarint32. 41 | var headerBuf [binary.MaxVarintLen32]byte 42 | var bytesRead, varIntBytes int 43 | var messageLength uint64 44 | for varIntBytes == 0 { // i.e. no varint has been decoded yet. 45 | if bytesRead >= len(headerBuf) { 46 | return bytesRead, errInvalidVarint 47 | } 48 | // We have to read byte by byte here to avoid reading more bytes 49 | // than required. Each read byte is appended to what we have 50 | // read before. 51 | newBytesRead, err := r.Read(headerBuf[bytesRead : bytesRead+1]) 52 | if newBytesRead == 0 { 53 | if err != nil { 54 | return bytesRead, err 55 | } 56 | // A Reader should not return (0, nil), but if it does, 57 | // it should be treated as no-op (according to the 58 | // Reader contract). So let's go on... 59 | continue 60 | } 61 | bytesRead += newBytesRead 62 | // Now present everything read so far to the varint decoder and 63 | // see if a varint can be decoded already. 64 | messageLength, varIntBytes = proto.DecodeVarint(headerBuf[:bytesRead]) 65 | } 66 | 67 | messageBuf := make([]byte, messageLength) 68 | newBytesRead, err := io.ReadFull(r, messageBuf) 69 | bytesRead += newBytesRead 70 | if err != nil { 71 | return bytesRead, err 72 | } 73 | 74 | return bytesRead, proto.Unmarshal(messageBuf, m) 75 | } 76 | -------------------------------------------------------------------------------- /vendor/github.com/matttproud/golang_protobuf_extensions/pbutil/doc.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 Matt T. Proud 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | // Package pbutil provides record length-delimited Protocol Buffer streaming. 16 | package pbutil 17 | -------------------------------------------------------------------------------- /vendor/github.com/matttproud/golang_protobuf_extensions/pbutil/encode.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 Matt T. Proud 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package pbutil 16 | 17 | import ( 18 | "encoding/binary" 19 | "io" 20 | 21 | "github.com/golang/protobuf/proto" 22 | ) 23 | 24 | // WriteDelimited encodes and dumps a message to the provided writer prefixed 25 | // with a 32-bit varint indicating the length of the encoded message, producing 26 | // a length-delimited record stream, which can be used to chain together 27 | // encoded messages of the same type together in a file. It returns the total 28 | // number of bytes written and any applicable error. This is roughly 29 | // equivalent to the companion Java API's MessageLite#writeDelimitedTo. 30 | func WriteDelimited(w io.Writer, m proto.Message) (n int, err error) { 31 | buffer, err := proto.Marshal(m) 32 | if err != nil { 33 | return 0, err 34 | } 35 | 36 | var buf [binary.MaxVarintLen32]byte 37 | encodedLength := binary.PutUvarint(buf[:], uint64(len(buffer))) 38 | 39 | sync, err := w.Write(buf[:encodedLength]) 40 | if err != nil { 41 | return sync, err 42 | } 43 | 44 | n, err = w.Write(buffer) 45 | return n + sync, err 46 | } 47 | -------------------------------------------------------------------------------- /vendor/github.com/prometheus/client_golang/AUTHORS.md: -------------------------------------------------------------------------------- 1 | The Prometheus project was started by Matt T. Proud (emeritus) and 2 | Julius Volz in 2012. 3 | 4 | Maintainers of this repository: 5 | 6 | * Björn Rabenstein 7 | 8 | More than [30 individuals][1] have contributed to this repository. Please refer 9 | to the Git commit log for a complete list. 10 | 11 | [1]: https://github.com/prometheus/client_golang/graphs/contributors 12 | -------------------------------------------------------------------------------- /vendor/github.com/prometheus/client_golang/NOTICE: -------------------------------------------------------------------------------- 1 | Prometheus instrumentation library for Go applications 2 | Copyright 2012-2015 The Prometheus Authors 3 | 4 | This product includes software developed at 5 | SoundCloud Ltd. (http://soundcloud.com/). 6 | 7 | 8 | The following components are included in this product: 9 | 10 | perks - a fork of https://github.com/bmizerany/perks 11 | https://github.com/beorn7/perks 12 | Copyright 2013-2015 Blake Mizerany, Björn Rabenstein 13 | See https://github.com/beorn7/perks/blob/master/README.md for license details. 14 | 15 | Go support for Protocol Buffers - Google's data interchange format 16 | http://github.com/golang/protobuf/ 17 | Copyright 2010 The Go Authors 18 | See source code for license details. 19 | 20 | Support for streaming Protocol Buffer messages for the Go language (golang). 21 | https://github.com/matttproud/golang_protobuf_extensions 22 | Copyright 2013 Matt T. Proud 23 | Licensed under the Apache License, Version 2.0 24 | -------------------------------------------------------------------------------- /vendor/github.com/prometheus/client_golang/prometheus/.gitignore: -------------------------------------------------------------------------------- 1 | command-line-arguments.test 2 | -------------------------------------------------------------------------------- /vendor/github.com/prometheus/client_golang/prometheus/README.md: -------------------------------------------------------------------------------- 1 | See [![go-doc](https://godoc.org/github.com/prometheus/client_golang/prometheus?status.svg)](https://godoc.org/github.com/prometheus/client_golang/prometheus). 2 | -------------------------------------------------------------------------------- /vendor/github.com/prometheus/client_golang/prometheus/collector.go: -------------------------------------------------------------------------------- 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 | 14 | package prometheus 15 | 16 | // Collector is the interface implemented by anything that can be used by 17 | // Prometheus to collect metrics. A Collector has to be registered for 18 | // collection. See Registerer.Register. 19 | // 20 | // The stock metrics provided by this package (Gauge, Counter, Summary, 21 | // Histogram, Untyped) are also Collectors (which only ever collect one metric, 22 | // namely itself). An implementer of Collector may, however, collect multiple 23 | // metrics in a coordinated fashion and/or create metrics on the fly. Examples 24 | // for collectors already implemented in this library are the metric vectors 25 | // (i.e. collection of multiple instances of the same Metric but with different 26 | // label values) like GaugeVec or SummaryVec, and the ExpvarCollector. 27 | type Collector interface { 28 | // Describe sends the super-set of all possible descriptors of metrics 29 | // collected by this Collector to the provided channel and returns once 30 | // the last descriptor has been sent. The sent descriptors fulfill the 31 | // consistency and uniqueness requirements described in the Desc 32 | // documentation. (It is valid if one and the same Collector sends 33 | // duplicate descriptors. Those duplicates are simply ignored. However, 34 | // two different Collectors must not send duplicate descriptors.) This 35 | // method idempotently sends the same descriptors throughout the 36 | // lifetime of the Collector. If a Collector encounters an error while 37 | // executing this method, it must send an invalid descriptor (created 38 | // with NewInvalidDesc) to signal the error to the registry. 39 | Describe(chan<- *Desc) 40 | // Collect is called by the Prometheus registry when collecting 41 | // metrics. The implementation sends each collected metric via the 42 | // provided channel and returns once the last metric has been sent. The 43 | // descriptor of each sent metric is one of those returned by 44 | // Describe. Returned metrics that share the same descriptor must differ 45 | // in their variable label values. This method may be called 46 | // concurrently and must therefore be implemented in a concurrency safe 47 | // way. Blocking occurs at the expense of total performance of rendering 48 | // all registered metrics. Ideally, Collector implementations support 49 | // concurrent readers. 50 | Collect(chan<- Metric) 51 | } 52 | 53 | // selfCollector implements Collector for a single Metric so that the Metric 54 | // collects itself. Add it as an anonymous field to a struct that implements 55 | // Metric, and call init with the Metric itself as an argument. 56 | type selfCollector struct { 57 | self Metric 58 | } 59 | 60 | // init provides the selfCollector with a reference to the metric it is supposed 61 | // to collect. It is usually called within the factory function to create a 62 | // metric. See example. 63 | func (c *selfCollector) init(self Metric) { 64 | c.self = self 65 | } 66 | 67 | // Describe implements Collector. 68 | func (c *selfCollector) Describe(ch chan<- *Desc) { 69 | ch <- c.self.Desc() 70 | } 71 | 72 | // Collect implements Collector. 73 | func (c *selfCollector) Collect(ch chan<- Metric) { 74 | ch <- c.self 75 | } 76 | -------------------------------------------------------------------------------- /vendor/github.com/prometheus/client_golang/prometheus/counter.go: -------------------------------------------------------------------------------- 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 | 14 | package prometheus 15 | 16 | import ( 17 | "errors" 18 | ) 19 | 20 | // Counter is a Metric that represents a single numerical value that only ever 21 | // goes up. That implies that it cannot be used to count items whose number can 22 | // also go down, e.g. the number of currently running goroutines. Those 23 | // "counters" are represented by Gauges. 24 | // 25 | // A Counter is typically used to count requests served, tasks completed, errors 26 | // occurred, etc. 27 | // 28 | // To create Counter instances, use NewCounter. 29 | type Counter interface { 30 | Metric 31 | Collector 32 | 33 | // Inc increments the counter by 1. Use Add to increment it by arbitrary 34 | // non-negative values. 35 | Inc() 36 | // Add adds the given value to the counter. It panics if the value is < 37 | // 0. 38 | Add(float64) 39 | } 40 | 41 | // CounterOpts is an alias for Opts. See there for doc comments. 42 | type CounterOpts Opts 43 | 44 | // NewCounter creates a new Counter based on the provided CounterOpts. 45 | func NewCounter(opts CounterOpts) Counter { 46 | desc := NewDesc( 47 | BuildFQName(opts.Namespace, opts.Subsystem, opts.Name), 48 | opts.Help, 49 | nil, 50 | opts.ConstLabels, 51 | ) 52 | result := &counter{value: value{desc: desc, valType: CounterValue, labelPairs: desc.constLabelPairs}} 53 | result.init(result) // Init self-collection. 54 | return result 55 | } 56 | 57 | type counter struct { 58 | value 59 | } 60 | 61 | func (c *counter) Add(v float64) { 62 | if v < 0 { 63 | panic(errors.New("counter cannot decrease in value")) 64 | } 65 | c.value.Add(v) 66 | } 67 | 68 | // CounterVec is a Collector that bundles a set of Counters that all share the 69 | // same Desc, but have different values for their variable labels. This is used 70 | // if you want to count the same thing partitioned by various dimensions 71 | // (e.g. number of HTTP requests, partitioned by response code and 72 | // method). Create instances with NewCounterVec. 73 | // 74 | // CounterVec embeds MetricVec. See there for a full list of methods with 75 | // detailed documentation. 76 | type CounterVec struct { 77 | *MetricVec 78 | } 79 | 80 | // NewCounterVec creates a new CounterVec based on the provided CounterOpts and 81 | // partitioned by the given label names. At least one label name must be 82 | // provided. 83 | func NewCounterVec(opts CounterOpts, labelNames []string) *CounterVec { 84 | desc := NewDesc( 85 | BuildFQName(opts.Namespace, opts.Subsystem, opts.Name), 86 | opts.Help, 87 | labelNames, 88 | opts.ConstLabels, 89 | ) 90 | return &CounterVec{ 91 | MetricVec: newMetricVec(desc, func(lvs ...string) Metric { 92 | result := &counter{value: value{ 93 | desc: desc, 94 | valType: CounterValue, 95 | labelPairs: makeLabelPairs(desc, lvs), 96 | }} 97 | result.init(result) // Init self-collection. 98 | return result 99 | }), 100 | } 101 | } 102 | 103 | // GetMetricWithLabelValues replaces the method of the same name in 104 | // MetricVec. The difference is that this method returns a Counter and not a 105 | // Metric so that no type conversion is required. 106 | func (m *CounterVec) GetMetricWithLabelValues(lvs ...string) (Counter, error) { 107 | metric, err := m.MetricVec.GetMetricWithLabelValues(lvs...) 108 | if metric != nil { 109 | return metric.(Counter), err 110 | } 111 | return nil, err 112 | } 113 | 114 | // GetMetricWith replaces the method of the same name in MetricVec. The 115 | // difference is that this method returns a Counter and not a Metric so that no 116 | // type conversion is required. 117 | func (m *CounterVec) GetMetricWith(labels Labels) (Counter, error) { 118 | metric, err := m.MetricVec.GetMetricWith(labels) 119 | if metric != nil { 120 | return metric.(Counter), err 121 | } 122 | return nil, err 123 | } 124 | 125 | // WithLabelValues works as GetMetricWithLabelValues, but panics where 126 | // GetMetricWithLabelValues would have returned an error. By not returning an 127 | // error, WithLabelValues allows shortcuts like 128 | // myVec.WithLabelValues("404", "GET").Add(42) 129 | func (m *CounterVec) WithLabelValues(lvs ...string) Counter { 130 | return m.MetricVec.WithLabelValues(lvs...).(Counter) 131 | } 132 | 133 | // With works as GetMetricWith, but panics where GetMetricWithLabels would have 134 | // returned an error. By not returning an error, With allows shortcuts like 135 | // myVec.With(Labels{"code": "404", "method": "GET"}).Add(42) 136 | func (m *CounterVec) With(labels Labels) Counter { 137 | return m.MetricVec.With(labels).(Counter) 138 | } 139 | 140 | // CounterFunc is a Counter whose value is determined at collect time by calling a 141 | // provided function. 142 | // 143 | // To create CounterFunc instances, use NewCounterFunc. 144 | type CounterFunc interface { 145 | Metric 146 | Collector 147 | } 148 | 149 | // NewCounterFunc creates a new CounterFunc based on the provided 150 | // CounterOpts. The value reported is determined by calling the given function 151 | // from within the Write method. Take into account that metric collection may 152 | // happen concurrently. If that results in concurrent calls to Write, like in 153 | // the case where a CounterFunc is directly registered with Prometheus, the 154 | // provided function must be concurrency-safe. The function should also honor 155 | // the contract for a Counter (values only go up, not down), but compliance will 156 | // not be checked. 157 | func NewCounterFunc(opts CounterOpts, function func() float64) CounterFunc { 158 | return newValueFunc(NewDesc( 159 | BuildFQName(opts.Namespace, opts.Subsystem, opts.Name), 160 | opts.Help, 161 | nil, 162 | opts.ConstLabels, 163 | ), CounterValue, function) 164 | } 165 | -------------------------------------------------------------------------------- /vendor/github.com/prometheus/client_golang/prometheus/desc.go: -------------------------------------------------------------------------------- 1 | // Copyright 2016 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 | 14 | package prometheus 15 | 16 | import ( 17 | "errors" 18 | "fmt" 19 | "sort" 20 | "strings" 21 | 22 | "github.com/golang/protobuf/proto" 23 | "github.com/prometheus/common/model" 24 | 25 | dto "github.com/prometheus/client_model/go" 26 | ) 27 | 28 | // reservedLabelPrefix is a prefix which is not legal in user-supplied 29 | // label names. 30 | const reservedLabelPrefix = "__" 31 | 32 | // Labels represents a collection of label name -> value mappings. This type is 33 | // commonly used with the With(Labels) and GetMetricWith(Labels) methods of 34 | // metric vector Collectors, e.g.: 35 | // myVec.With(Labels{"code": "404", "method": "GET"}).Add(42) 36 | // 37 | // The other use-case is the specification of constant label pairs in Opts or to 38 | // create a Desc. 39 | type Labels map[string]string 40 | 41 | // Desc is the descriptor used by every Prometheus Metric. It is essentially 42 | // the immutable meta-data of a Metric. The normal Metric implementations 43 | // included in this package manage their Desc under the hood. Users only have to 44 | // deal with Desc if they use advanced features like the ExpvarCollector or 45 | // custom Collectors and Metrics. 46 | // 47 | // Descriptors registered with the same registry have to fulfill certain 48 | // consistency and uniqueness criteria if they share the same fully-qualified 49 | // name: They must have the same help string and the same label names (aka label 50 | // dimensions) in each, constLabels and variableLabels, but they must differ in 51 | // the values of the constLabels. 52 | // 53 | // Descriptors that share the same fully-qualified names and the same label 54 | // values of their constLabels are considered equal. 55 | // 56 | // Use NewDesc to create new Desc instances. 57 | type Desc struct { 58 | // fqName has been built from Namespace, Subsystem, and Name. 59 | fqName string 60 | // help provides some helpful information about this metric. 61 | help string 62 | // constLabelPairs contains precalculated DTO label pairs based on 63 | // the constant labels. 64 | constLabelPairs []*dto.LabelPair 65 | // VariableLabels contains names of labels for which the metric 66 | // maintains variable values. 67 | variableLabels []string 68 | // id is a hash of the values of the ConstLabels and fqName. This 69 | // must be unique among all registered descriptors and can therefore be 70 | // used as an identifier of the descriptor. 71 | id uint64 72 | // dimHash is a hash of the label names (preset and variable) and the 73 | // Help string. Each Desc with the same fqName must have the same 74 | // dimHash. 75 | dimHash uint64 76 | // err is an error that occurred during construction. It is reported on 77 | // registration time. 78 | err error 79 | } 80 | 81 | // NewDesc allocates and initializes a new Desc. Errors are recorded in the Desc 82 | // and will be reported on registration time. variableLabels and constLabels can 83 | // be nil if no such labels should be set. fqName and help must not be empty. 84 | // 85 | // variableLabels only contain the label names. Their label values are variable 86 | // and therefore not part of the Desc. (They are managed within the Metric.) 87 | // 88 | // For constLabels, the label values are constant. Therefore, they are fully 89 | // specified in the Desc. See the Opts documentation for the implications of 90 | // constant labels. 91 | func NewDesc(fqName, help string, variableLabels []string, constLabels Labels) *Desc { 92 | d := &Desc{ 93 | fqName: fqName, 94 | help: help, 95 | variableLabels: variableLabels, 96 | } 97 | if help == "" { 98 | d.err = errors.New("empty help string") 99 | return d 100 | } 101 | if !model.IsValidMetricName(model.LabelValue(fqName)) { 102 | d.err = fmt.Errorf("%q is not a valid metric name", fqName) 103 | return d 104 | } 105 | // labelValues contains the label values of const labels (in order of 106 | // their sorted label names) plus the fqName (at position 0). 107 | labelValues := make([]string, 1, len(constLabels)+1) 108 | labelValues[0] = fqName 109 | labelNames := make([]string, 0, len(constLabels)+len(variableLabels)) 110 | labelNameSet := map[string]struct{}{} 111 | // First add only the const label names and sort them... 112 | for labelName := range constLabels { 113 | if !checkLabelName(labelName) { 114 | d.err = fmt.Errorf("%q is not a valid label name", labelName) 115 | return d 116 | } 117 | labelNames = append(labelNames, labelName) 118 | labelNameSet[labelName] = struct{}{} 119 | } 120 | sort.Strings(labelNames) 121 | // ... so that we can now add const label values in the order of their names. 122 | for _, labelName := range labelNames { 123 | labelValues = append(labelValues, constLabels[labelName]) 124 | } 125 | // Now add the variable label names, but prefix them with something that 126 | // cannot be in a regular label name. That prevents matching the label 127 | // dimension with a different mix between preset and variable labels. 128 | for _, labelName := range variableLabels { 129 | if !checkLabelName(labelName) { 130 | d.err = fmt.Errorf("%q is not a valid label name", labelName) 131 | return d 132 | } 133 | labelNames = append(labelNames, "$"+labelName) 134 | labelNameSet[labelName] = struct{}{} 135 | } 136 | if len(labelNames) != len(labelNameSet) { 137 | d.err = errors.New("duplicate label names") 138 | return d 139 | } 140 | vh := hashNew() 141 | for _, val := range labelValues { 142 | vh = hashAdd(vh, val) 143 | vh = hashAddByte(vh, separatorByte) 144 | } 145 | d.id = vh 146 | // Sort labelNames so that order doesn't matter for the hash. 147 | sort.Strings(labelNames) 148 | // Now hash together (in this order) the help string and the sorted 149 | // label names. 150 | lh := hashNew() 151 | lh = hashAdd(lh, help) 152 | lh = hashAddByte(lh, separatorByte) 153 | for _, labelName := range labelNames { 154 | lh = hashAdd(lh, labelName) 155 | lh = hashAddByte(lh, separatorByte) 156 | } 157 | d.dimHash = lh 158 | 159 | d.constLabelPairs = make([]*dto.LabelPair, 0, len(constLabels)) 160 | for n, v := range constLabels { 161 | d.constLabelPairs = append(d.constLabelPairs, &dto.LabelPair{ 162 | Name: proto.String(n), 163 | Value: proto.String(v), 164 | }) 165 | } 166 | sort.Sort(LabelPairSorter(d.constLabelPairs)) 167 | return d 168 | } 169 | 170 | // NewInvalidDesc returns an invalid descriptor, i.e. a descriptor with the 171 | // provided error set. If a collector returning such a descriptor is registered, 172 | // registration will fail with the provided error. NewInvalidDesc can be used by 173 | // a Collector to signal inability to describe itself. 174 | func NewInvalidDesc(err error) *Desc { 175 | return &Desc{ 176 | err: err, 177 | } 178 | } 179 | 180 | func (d *Desc) String() string { 181 | lpStrings := make([]string, 0, len(d.constLabelPairs)) 182 | for _, lp := range d.constLabelPairs { 183 | lpStrings = append( 184 | lpStrings, 185 | fmt.Sprintf("%s=%q", lp.GetName(), lp.GetValue()), 186 | ) 187 | } 188 | return fmt.Sprintf( 189 | "Desc{fqName: %q, help: %q, constLabels: {%s}, variableLabels: %v}", 190 | d.fqName, 191 | d.help, 192 | strings.Join(lpStrings, ","), 193 | d.variableLabels, 194 | ) 195 | } 196 | 197 | func checkLabelName(l string) bool { 198 | return model.LabelName(l).IsValid() && 199 | !strings.HasPrefix(l, reservedLabelPrefix) 200 | } 201 | -------------------------------------------------------------------------------- /vendor/github.com/prometheus/client_golang/prometheus/expvar_collector.go: -------------------------------------------------------------------------------- 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 | 14 | package prometheus 15 | 16 | import ( 17 | "encoding/json" 18 | "expvar" 19 | ) 20 | 21 | type expvarCollector struct { 22 | exports map[string]*Desc 23 | } 24 | 25 | // NewExpvarCollector returns a newly allocated expvar Collector that still has 26 | // to be registered with a Prometheus registry. 27 | // 28 | // An expvar Collector collects metrics from the expvar interface. It provides a 29 | // quick way to expose numeric values that are already exported via expvar as 30 | // Prometheus metrics. Note that the data models of expvar and Prometheus are 31 | // fundamentally different, and that the expvar Collector is inherently slower 32 | // than native Prometheus metrics. Thus, the expvar Collector is probably great 33 | // for experiments and prototying, but you should seriously consider a more 34 | // direct implementation of Prometheus metrics for monitoring production 35 | // systems. 36 | // 37 | // The exports map has the following meaning: 38 | // 39 | // The keys in the map correspond to expvar keys, i.e. for every expvar key you 40 | // want to export as Prometheus metric, you need an entry in the exports 41 | // map. The descriptor mapped to each key describes how to export the expvar 42 | // value. It defines the name and the help string of the Prometheus metric 43 | // proxying the expvar value. The type will always be Untyped. 44 | // 45 | // For descriptors without variable labels, the expvar value must be a number or 46 | // a bool. The number is then directly exported as the Prometheus sample 47 | // value. (For a bool, 'false' translates to 0 and 'true' to 1). Expvar values 48 | // that are not numbers or bools are silently ignored. 49 | // 50 | // If the descriptor has one variable label, the expvar value must be an expvar 51 | // map. The keys in the expvar map become the various values of the one 52 | // Prometheus label. The values in the expvar map must be numbers or bools again 53 | // as above. 54 | // 55 | // For descriptors with more than one variable label, the expvar must be a 56 | // nested expvar map, i.e. where the values of the topmost map are maps again 57 | // etc. until a depth is reached that corresponds to the number of labels. The 58 | // leaves of that structure must be numbers or bools as above to serve as the 59 | // sample values. 60 | // 61 | // Anything that does not fit into the scheme above is silently ignored. 62 | func NewExpvarCollector(exports map[string]*Desc) Collector { 63 | return &expvarCollector{ 64 | exports: exports, 65 | } 66 | } 67 | 68 | // Describe implements Collector. 69 | func (e *expvarCollector) Describe(ch chan<- *Desc) { 70 | for _, desc := range e.exports { 71 | ch <- desc 72 | } 73 | } 74 | 75 | // Collect implements Collector. 76 | func (e *expvarCollector) Collect(ch chan<- Metric) { 77 | for name, desc := range e.exports { 78 | var m Metric 79 | expVar := expvar.Get(name) 80 | if expVar == nil { 81 | continue 82 | } 83 | var v interface{} 84 | labels := make([]string, len(desc.variableLabels)) 85 | if err := json.Unmarshal([]byte(expVar.String()), &v); err != nil { 86 | ch <- NewInvalidMetric(desc, err) 87 | continue 88 | } 89 | var processValue func(v interface{}, i int) 90 | processValue = func(v interface{}, i int) { 91 | if i >= len(labels) { 92 | copiedLabels := append(make([]string, 0, len(labels)), labels...) 93 | switch v := v.(type) { 94 | case float64: 95 | m = MustNewConstMetric(desc, UntypedValue, v, copiedLabels...) 96 | case bool: 97 | if v { 98 | m = MustNewConstMetric(desc, UntypedValue, 1, copiedLabels...) 99 | } else { 100 | m = MustNewConstMetric(desc, UntypedValue, 0, copiedLabels...) 101 | } 102 | default: 103 | return 104 | } 105 | ch <- m 106 | return 107 | } 108 | vm, ok := v.(map[string]interface{}) 109 | if !ok { 110 | return 111 | } 112 | for lv, val := range vm { 113 | labels[i] = lv 114 | processValue(val, i+1) 115 | } 116 | } 117 | processValue(v, 0) 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /vendor/github.com/prometheus/client_golang/prometheus/fnv.go: -------------------------------------------------------------------------------- 1 | package prometheus 2 | 3 | // Inline and byte-free variant of hash/fnv's fnv64a. 4 | 5 | const ( 6 | offset64 = 14695981039346656037 7 | prime64 = 1099511628211 8 | ) 9 | 10 | // hashNew initializies a new fnv64a hash value. 11 | func hashNew() uint64 { 12 | return offset64 13 | } 14 | 15 | // hashAdd adds a string to a fnv64a hash value, returning the updated hash. 16 | func hashAdd(h uint64, s string) uint64 { 17 | for i := 0; i < len(s); i++ { 18 | h ^= uint64(s[i]) 19 | h *= prime64 20 | } 21 | return h 22 | } 23 | 24 | // hashAddByte adds a byte to a fnv64a hash value, returning the updated hash. 25 | func hashAddByte(h uint64, b byte) uint64 { 26 | h ^= uint64(b) 27 | h *= prime64 28 | return h 29 | } 30 | -------------------------------------------------------------------------------- /vendor/github.com/prometheus/client_golang/prometheus/gauge.go: -------------------------------------------------------------------------------- 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 | 14 | package prometheus 15 | 16 | // Gauge is a Metric that represents a single numerical value that can 17 | // arbitrarily go up and down. 18 | // 19 | // A Gauge is typically used for measured values like temperatures or current 20 | // memory usage, but also "counts" that can go up and down, like the number of 21 | // running goroutines. 22 | // 23 | // To create Gauge instances, use NewGauge. 24 | type Gauge interface { 25 | Metric 26 | Collector 27 | 28 | // Set sets the Gauge to an arbitrary value. 29 | Set(float64) 30 | // Inc increments the Gauge by 1. Use Add to increment it by arbitrary 31 | // values. 32 | Inc() 33 | // Dec decrements the Gauge by 1. Use Sub to decrement it by arbitrary 34 | // values. 35 | Dec() 36 | // Add adds the given value to the Gauge. (The value can be negative, 37 | // resulting in a decrease of the Gauge.) 38 | Add(float64) 39 | // Sub subtracts the given value from the Gauge. (The value can be 40 | // negative, resulting in an increase of the Gauge.) 41 | Sub(float64) 42 | 43 | // SetToCurrentTime sets the Gauge to the current Unix time in seconds. 44 | SetToCurrentTime() 45 | } 46 | 47 | // GaugeOpts is an alias for Opts. See there for doc comments. 48 | type GaugeOpts Opts 49 | 50 | // NewGauge creates a new Gauge based on the provided GaugeOpts. 51 | func NewGauge(opts GaugeOpts) Gauge { 52 | return newValue(NewDesc( 53 | BuildFQName(opts.Namespace, opts.Subsystem, opts.Name), 54 | opts.Help, 55 | nil, 56 | opts.ConstLabels, 57 | ), GaugeValue, 0) 58 | } 59 | 60 | // GaugeVec is a Collector that bundles a set of Gauges that all share the same 61 | // Desc, but have different values for their variable labels. This is used if 62 | // you want to count the same thing partitioned by various dimensions 63 | // (e.g. number of operations queued, partitioned by user and operation 64 | // type). Create instances with NewGaugeVec. 65 | type GaugeVec struct { 66 | *MetricVec 67 | } 68 | 69 | // NewGaugeVec creates a new GaugeVec based on the provided GaugeOpts and 70 | // partitioned by the given label names. At least one label name must be 71 | // provided. 72 | func NewGaugeVec(opts GaugeOpts, labelNames []string) *GaugeVec { 73 | desc := NewDesc( 74 | BuildFQName(opts.Namespace, opts.Subsystem, opts.Name), 75 | opts.Help, 76 | labelNames, 77 | opts.ConstLabels, 78 | ) 79 | return &GaugeVec{ 80 | MetricVec: newMetricVec(desc, func(lvs ...string) Metric { 81 | return newValue(desc, GaugeValue, 0, lvs...) 82 | }), 83 | } 84 | } 85 | 86 | // GetMetricWithLabelValues replaces the method of the same name in 87 | // MetricVec. The difference is that this method returns a Gauge and not a 88 | // Metric so that no type conversion is required. 89 | func (m *GaugeVec) GetMetricWithLabelValues(lvs ...string) (Gauge, error) { 90 | metric, err := m.MetricVec.GetMetricWithLabelValues(lvs...) 91 | if metric != nil { 92 | return metric.(Gauge), err 93 | } 94 | return nil, err 95 | } 96 | 97 | // GetMetricWith replaces the method of the same name in MetricVec. The 98 | // difference is that this method returns a Gauge and not a Metric so that no 99 | // type conversion is required. 100 | func (m *GaugeVec) GetMetricWith(labels Labels) (Gauge, error) { 101 | metric, err := m.MetricVec.GetMetricWith(labels) 102 | if metric != nil { 103 | return metric.(Gauge), err 104 | } 105 | return nil, err 106 | } 107 | 108 | // WithLabelValues works as GetMetricWithLabelValues, but panics where 109 | // GetMetricWithLabelValues would have returned an error. By not returning an 110 | // error, WithLabelValues allows shortcuts like 111 | // myVec.WithLabelValues("404", "GET").Add(42) 112 | func (m *GaugeVec) WithLabelValues(lvs ...string) Gauge { 113 | return m.MetricVec.WithLabelValues(lvs...).(Gauge) 114 | } 115 | 116 | // With works as GetMetricWith, but panics where GetMetricWithLabels would have 117 | // returned an error. By not returning an error, With allows shortcuts like 118 | // myVec.With(Labels{"code": "404", "method": "GET"}).Add(42) 119 | func (m *GaugeVec) With(labels Labels) Gauge { 120 | return m.MetricVec.With(labels).(Gauge) 121 | } 122 | 123 | // GaugeFunc is a Gauge whose value is determined at collect time by calling a 124 | // provided function. 125 | // 126 | // To create GaugeFunc instances, use NewGaugeFunc. 127 | type GaugeFunc interface { 128 | Metric 129 | Collector 130 | } 131 | 132 | // NewGaugeFunc creates a new GaugeFunc based on the provided GaugeOpts. The 133 | // value reported is determined by calling the given function from within the 134 | // Write method. Take into account that metric collection may happen 135 | // concurrently. If that results in concurrent calls to Write, like in the case 136 | // where a GaugeFunc is directly registered with Prometheus, the provided 137 | // function must be concurrency-safe. 138 | func NewGaugeFunc(opts GaugeOpts, function func() float64) GaugeFunc { 139 | return newValueFunc(NewDesc( 140 | BuildFQName(opts.Namespace, opts.Subsystem, opts.Name), 141 | opts.Help, 142 | nil, 143 | opts.ConstLabels, 144 | ), GaugeValue, function) 145 | } 146 | -------------------------------------------------------------------------------- /vendor/github.com/prometheus/client_golang/prometheus/go_collector.go: -------------------------------------------------------------------------------- 1 | package prometheus 2 | 3 | import ( 4 | "fmt" 5 | "runtime" 6 | "runtime/debug" 7 | "time" 8 | ) 9 | 10 | type goCollector struct { 11 | goroutines Gauge 12 | gcDesc *Desc 13 | 14 | // metrics to describe and collect 15 | metrics memStatsMetrics 16 | } 17 | 18 | // NewGoCollector returns a collector which exports metrics about the current 19 | // go process. 20 | func NewGoCollector() Collector { 21 | return &goCollector{ 22 | goroutines: NewGauge(GaugeOpts{ 23 | Namespace: "go", 24 | Name: "goroutines", 25 | Help: "Number of goroutines that currently exist.", 26 | }), 27 | gcDesc: NewDesc( 28 | "go_gc_duration_seconds", 29 | "A summary of the GC invocation durations.", 30 | nil, nil), 31 | metrics: memStatsMetrics{ 32 | { 33 | desc: NewDesc( 34 | memstatNamespace("alloc_bytes"), 35 | "Number of bytes allocated and still in use.", 36 | nil, nil, 37 | ), 38 | eval: func(ms *runtime.MemStats) float64 { return float64(ms.Alloc) }, 39 | valType: GaugeValue, 40 | }, { 41 | desc: NewDesc( 42 | memstatNamespace("alloc_bytes_total"), 43 | "Total number of bytes allocated, even if freed.", 44 | nil, nil, 45 | ), 46 | eval: func(ms *runtime.MemStats) float64 { return float64(ms.TotalAlloc) }, 47 | valType: CounterValue, 48 | }, { 49 | desc: NewDesc( 50 | memstatNamespace("sys_bytes"), 51 | "Number of bytes obtained from system.", 52 | nil, nil, 53 | ), 54 | eval: func(ms *runtime.MemStats) float64 { return float64(ms.Sys) }, 55 | valType: GaugeValue, 56 | }, { 57 | desc: NewDesc( 58 | memstatNamespace("lookups_total"), 59 | "Total number of pointer lookups.", 60 | nil, nil, 61 | ), 62 | eval: func(ms *runtime.MemStats) float64 { return float64(ms.Lookups) }, 63 | valType: CounterValue, 64 | }, { 65 | desc: NewDesc( 66 | memstatNamespace("mallocs_total"), 67 | "Total number of mallocs.", 68 | nil, nil, 69 | ), 70 | eval: func(ms *runtime.MemStats) float64 { return float64(ms.Mallocs) }, 71 | valType: CounterValue, 72 | }, { 73 | desc: NewDesc( 74 | memstatNamespace("frees_total"), 75 | "Total number of frees.", 76 | nil, nil, 77 | ), 78 | eval: func(ms *runtime.MemStats) float64 { return float64(ms.Frees) }, 79 | valType: CounterValue, 80 | }, { 81 | desc: NewDesc( 82 | memstatNamespace("heap_alloc_bytes"), 83 | "Number of heap bytes allocated and still in use.", 84 | nil, nil, 85 | ), 86 | eval: func(ms *runtime.MemStats) float64 { return float64(ms.HeapAlloc) }, 87 | valType: GaugeValue, 88 | }, { 89 | desc: NewDesc( 90 | memstatNamespace("heap_sys_bytes"), 91 | "Number of heap bytes obtained from system.", 92 | nil, nil, 93 | ), 94 | eval: func(ms *runtime.MemStats) float64 { return float64(ms.HeapSys) }, 95 | valType: GaugeValue, 96 | }, { 97 | desc: NewDesc( 98 | memstatNamespace("heap_idle_bytes"), 99 | "Number of heap bytes waiting to be used.", 100 | nil, nil, 101 | ), 102 | eval: func(ms *runtime.MemStats) float64 { return float64(ms.HeapIdle) }, 103 | valType: GaugeValue, 104 | }, { 105 | desc: NewDesc( 106 | memstatNamespace("heap_inuse_bytes"), 107 | "Number of heap bytes that are in use.", 108 | nil, nil, 109 | ), 110 | eval: func(ms *runtime.MemStats) float64 { return float64(ms.HeapInuse) }, 111 | valType: GaugeValue, 112 | }, { 113 | desc: NewDesc( 114 | memstatNamespace("heap_released_bytes"), 115 | "Number of heap bytes released to OS.", 116 | nil, nil, 117 | ), 118 | eval: func(ms *runtime.MemStats) float64 { return float64(ms.HeapReleased) }, 119 | valType: GaugeValue, 120 | }, { 121 | desc: NewDesc( 122 | memstatNamespace("heap_objects"), 123 | "Number of allocated objects.", 124 | nil, nil, 125 | ), 126 | eval: func(ms *runtime.MemStats) float64 { return float64(ms.HeapObjects) }, 127 | valType: GaugeValue, 128 | }, { 129 | desc: NewDesc( 130 | memstatNamespace("stack_inuse_bytes"), 131 | "Number of bytes in use by the stack allocator.", 132 | nil, nil, 133 | ), 134 | eval: func(ms *runtime.MemStats) float64 { return float64(ms.StackInuse) }, 135 | valType: GaugeValue, 136 | }, { 137 | desc: NewDesc( 138 | memstatNamespace("stack_sys_bytes"), 139 | "Number of bytes obtained from system for stack allocator.", 140 | nil, nil, 141 | ), 142 | eval: func(ms *runtime.MemStats) float64 { return float64(ms.StackSys) }, 143 | valType: GaugeValue, 144 | }, { 145 | desc: NewDesc( 146 | memstatNamespace("mspan_inuse_bytes"), 147 | "Number of bytes in use by mspan structures.", 148 | nil, nil, 149 | ), 150 | eval: func(ms *runtime.MemStats) float64 { return float64(ms.MSpanInuse) }, 151 | valType: GaugeValue, 152 | }, { 153 | desc: NewDesc( 154 | memstatNamespace("mspan_sys_bytes"), 155 | "Number of bytes used for mspan structures obtained from system.", 156 | nil, nil, 157 | ), 158 | eval: func(ms *runtime.MemStats) float64 { return float64(ms.MSpanSys) }, 159 | valType: GaugeValue, 160 | }, { 161 | desc: NewDesc( 162 | memstatNamespace("mcache_inuse_bytes"), 163 | "Number of bytes in use by mcache structures.", 164 | nil, nil, 165 | ), 166 | eval: func(ms *runtime.MemStats) float64 { return float64(ms.MCacheInuse) }, 167 | valType: GaugeValue, 168 | }, { 169 | desc: NewDesc( 170 | memstatNamespace("mcache_sys_bytes"), 171 | "Number of bytes used for mcache structures obtained from system.", 172 | nil, nil, 173 | ), 174 | eval: func(ms *runtime.MemStats) float64 { return float64(ms.MCacheSys) }, 175 | valType: GaugeValue, 176 | }, { 177 | desc: NewDesc( 178 | memstatNamespace("buck_hash_sys_bytes"), 179 | "Number of bytes used by the profiling bucket hash table.", 180 | nil, nil, 181 | ), 182 | eval: func(ms *runtime.MemStats) float64 { return float64(ms.BuckHashSys) }, 183 | valType: GaugeValue, 184 | }, { 185 | desc: NewDesc( 186 | memstatNamespace("gc_sys_bytes"), 187 | "Number of bytes used for garbage collection system metadata.", 188 | nil, nil, 189 | ), 190 | eval: func(ms *runtime.MemStats) float64 { return float64(ms.GCSys) }, 191 | valType: GaugeValue, 192 | }, { 193 | desc: NewDesc( 194 | memstatNamespace("other_sys_bytes"), 195 | "Number of bytes used for other system allocations.", 196 | nil, nil, 197 | ), 198 | eval: func(ms *runtime.MemStats) float64 { return float64(ms.OtherSys) }, 199 | valType: GaugeValue, 200 | }, { 201 | desc: NewDesc( 202 | memstatNamespace("next_gc_bytes"), 203 | "Number of heap bytes when next garbage collection will take place.", 204 | nil, nil, 205 | ), 206 | eval: func(ms *runtime.MemStats) float64 { return float64(ms.NextGC) }, 207 | valType: GaugeValue, 208 | }, { 209 | desc: NewDesc( 210 | memstatNamespace("last_gc_time_seconds"), 211 | "Number of seconds since 1970 of last garbage collection.", 212 | nil, nil, 213 | ), 214 | eval: func(ms *runtime.MemStats) float64 { return float64(ms.LastGC) / 1e9 }, 215 | valType: GaugeValue, 216 | }, 217 | }, 218 | } 219 | } 220 | 221 | func memstatNamespace(s string) string { 222 | return fmt.Sprintf("go_memstats_%s", s) 223 | } 224 | 225 | // Describe returns all descriptions of the collector. 226 | func (c *goCollector) Describe(ch chan<- *Desc) { 227 | ch <- c.goroutines.Desc() 228 | ch <- c.gcDesc 229 | 230 | for _, i := range c.metrics { 231 | ch <- i.desc 232 | } 233 | } 234 | 235 | // Collect returns the current state of all metrics of the collector. 236 | func (c *goCollector) Collect(ch chan<- Metric) { 237 | c.goroutines.Set(float64(runtime.NumGoroutine())) 238 | ch <- c.goroutines 239 | 240 | var stats debug.GCStats 241 | stats.PauseQuantiles = make([]time.Duration, 5) 242 | debug.ReadGCStats(&stats) 243 | 244 | quantiles := make(map[float64]float64) 245 | for idx, pq := range stats.PauseQuantiles[1:] { 246 | quantiles[float64(idx+1)/float64(len(stats.PauseQuantiles)-1)] = pq.Seconds() 247 | } 248 | quantiles[0.0] = stats.PauseQuantiles[0].Seconds() 249 | ch <- MustNewConstSummary(c.gcDesc, uint64(stats.NumGC), float64(stats.PauseTotal.Seconds()), quantiles) 250 | 251 | ms := &runtime.MemStats{} 252 | runtime.ReadMemStats(ms) 253 | for _, i := range c.metrics { 254 | ch <- MustNewConstMetric(i.desc, i.valType, i.eval(ms)) 255 | } 256 | } 257 | 258 | // memStatsMetrics provide description, value, and value type for memstat metrics. 259 | type memStatsMetrics []struct { 260 | desc *Desc 261 | eval func(*runtime.MemStats) float64 262 | valType ValueType 263 | } 264 | -------------------------------------------------------------------------------- /vendor/github.com/prometheus/client_golang/prometheus/metric.go: -------------------------------------------------------------------------------- 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 | 14 | package prometheus 15 | 16 | import ( 17 | "strings" 18 | 19 | dto "github.com/prometheus/client_model/go" 20 | ) 21 | 22 | const separatorByte byte = 255 23 | 24 | // A Metric models a single sample value with its meta data being exported to 25 | // Prometheus. Implementations of Metric in this package are Gauge, Counter, 26 | // Histogram, Summary, and Untyped. 27 | type Metric interface { 28 | // Desc returns the descriptor for the Metric. This method idempotently 29 | // returns the same descriptor throughout the lifetime of the 30 | // Metric. The returned descriptor is immutable by contract. A Metric 31 | // unable to describe itself must return an invalid descriptor (created 32 | // with NewInvalidDesc). 33 | Desc() *Desc 34 | // Write encodes the Metric into a "Metric" Protocol Buffer data 35 | // transmission object. 36 | // 37 | // Metric implementations must observe concurrency safety as reads of 38 | // this metric may occur at any time, and any blocking occurs at the 39 | // expense of total performance of rendering all registered 40 | // metrics. Ideally, Metric implementations should support concurrent 41 | // readers. 42 | // 43 | // While populating dto.Metric, it is the responsibility of the 44 | // implementation to ensure validity of the Metric protobuf (like valid 45 | // UTF-8 strings or syntactically valid metric and label names). It is 46 | // recommended to sort labels lexicographically. (Implementers may find 47 | // LabelPairSorter useful for that.) Callers of Write should still make 48 | // sure of sorting if they depend on it. 49 | Write(*dto.Metric) error 50 | // TODO(beorn7): The original rationale of passing in a pre-allocated 51 | // dto.Metric protobuf to save allocations has disappeared. The 52 | // signature of this method should be changed to "Write() (*dto.Metric, 53 | // error)". 54 | } 55 | 56 | // Opts bundles the options for creating most Metric types. Each metric 57 | // implementation XXX has its own XXXOpts type, but in most cases, it is just be 58 | // an alias of this type (which might change when the requirement arises.) 59 | // 60 | // It is mandatory to set Name and Help to a non-empty string. All other fields 61 | // are optional and can safely be left at their zero value. 62 | type Opts struct { 63 | // Namespace, Subsystem, and Name are components of the fully-qualified 64 | // name of the Metric (created by joining these components with 65 | // "_"). Only Name is mandatory, the others merely help structuring the 66 | // name. Note that the fully-qualified name of the metric must be a 67 | // valid Prometheus metric name. 68 | Namespace string 69 | Subsystem string 70 | Name string 71 | 72 | // Help provides information about this metric. Mandatory! 73 | // 74 | // Metrics with the same fully-qualified name must have the same Help 75 | // string. 76 | Help string 77 | 78 | // ConstLabels are used to attach fixed labels to this metric. Metrics 79 | // with the same fully-qualified name must have the same label names in 80 | // their ConstLabels. 81 | // 82 | // Note that in most cases, labels have a value that varies during the 83 | // lifetime of a process. Those labels are usually managed with a metric 84 | // vector collector (like CounterVec, GaugeVec, UntypedVec). ConstLabels 85 | // serve only special purposes. One is for the special case where the 86 | // value of a label does not change during the lifetime of a process, 87 | // e.g. if the revision of the running binary is put into a 88 | // label. Another, more advanced purpose is if more than one Collector 89 | // needs to collect Metrics with the same fully-qualified name. In that 90 | // case, those Metrics must differ in the values of their 91 | // ConstLabels. See the Collector examples. 92 | // 93 | // If the value of a label never changes (not even between binaries), 94 | // that label most likely should not be a label at all (but part of the 95 | // metric name). 96 | ConstLabels Labels 97 | } 98 | 99 | // BuildFQName joins the given three name components by "_". Empty name 100 | // components are ignored. If the name parameter itself is empty, an empty 101 | // string is returned, no matter what. Metric implementations included in this 102 | // library use this function internally to generate the fully-qualified metric 103 | // name from the name component in their Opts. Users of the library will only 104 | // need this function if they implement their own Metric or instantiate a Desc 105 | // (with NewDesc) directly. 106 | func BuildFQName(namespace, subsystem, name string) string { 107 | if name == "" { 108 | return "" 109 | } 110 | switch { 111 | case namespace != "" && subsystem != "": 112 | return strings.Join([]string{namespace, subsystem, name}, "_") 113 | case namespace != "": 114 | return strings.Join([]string{namespace, name}, "_") 115 | case subsystem != "": 116 | return strings.Join([]string{subsystem, name}, "_") 117 | } 118 | return name 119 | } 120 | 121 | // LabelPairSorter implements sort.Interface. It is used to sort a slice of 122 | // dto.LabelPair pointers. This is useful for implementing the Write method of 123 | // custom metrics. 124 | type LabelPairSorter []*dto.LabelPair 125 | 126 | func (s LabelPairSorter) Len() int { 127 | return len(s) 128 | } 129 | 130 | func (s LabelPairSorter) Swap(i, j int) { 131 | s[i], s[j] = s[j], s[i] 132 | } 133 | 134 | func (s LabelPairSorter) Less(i, j int) bool { 135 | return s[i].GetName() < s[j].GetName() 136 | } 137 | 138 | type hashSorter []uint64 139 | 140 | func (s hashSorter) Len() int { 141 | return len(s) 142 | } 143 | 144 | func (s hashSorter) Swap(i, j int) { 145 | s[i], s[j] = s[j], s[i] 146 | } 147 | 148 | func (s hashSorter) Less(i, j int) bool { 149 | return s[i] < s[j] 150 | } 151 | 152 | type invalidMetric struct { 153 | desc *Desc 154 | err error 155 | } 156 | 157 | // NewInvalidMetric returns a metric whose Write method always returns the 158 | // provided error. It is useful if a Collector finds itself unable to collect 159 | // a metric and wishes to report an error to the registry. 160 | func NewInvalidMetric(desc *Desc, err error) Metric { 161 | return &invalidMetric{desc, err} 162 | } 163 | 164 | func (m *invalidMetric) Desc() *Desc { return m.desc } 165 | 166 | func (m *invalidMetric) Write(*dto.Metric) error { return m.err } 167 | -------------------------------------------------------------------------------- /vendor/github.com/prometheus/client_golang/prometheus/process_collector.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 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 | 14 | package prometheus 15 | 16 | import "github.com/prometheus/procfs" 17 | 18 | type processCollector struct { 19 | pid int 20 | collectFn func(chan<- Metric) 21 | pidFn func() (int, error) 22 | cpuTotal *Desc 23 | openFDs, maxFDs *Desc 24 | vsize, rss *Desc 25 | startTime *Desc 26 | } 27 | 28 | // NewProcessCollector returns a collector which exports the current state of 29 | // process metrics including cpu, memory and file descriptor usage as well as 30 | // the process start time for the given process id under the given namespace. 31 | func NewProcessCollector(pid int, namespace string) Collector { 32 | return NewProcessCollectorPIDFn( 33 | func() (int, error) { return pid, nil }, 34 | namespace, 35 | ) 36 | } 37 | 38 | // NewProcessCollectorPIDFn returns a collector which exports the current state 39 | // of process metrics including cpu, memory and file descriptor usage as well 40 | // as the process start time under the given namespace. The given pidFn is 41 | // called on each collect and is used to determine the process to export 42 | // metrics for. 43 | func NewProcessCollectorPIDFn( 44 | pidFn func() (int, error), 45 | namespace string, 46 | ) Collector { 47 | ns := "" 48 | if len(namespace) > 0 { 49 | ns = namespace + "_" 50 | } 51 | 52 | c := processCollector{ 53 | pidFn: pidFn, 54 | collectFn: func(chan<- Metric) {}, 55 | 56 | cpuTotal: NewDesc( 57 | ns+"process_cpu_seconds_total", 58 | "Total user and system CPU time spent in seconds.", 59 | nil, nil, 60 | ), 61 | openFDs: NewDesc( 62 | ns+"process_open_fds", 63 | "Number of open file descriptors.", 64 | nil, nil, 65 | ), 66 | maxFDs: NewDesc( 67 | ns+"process_max_fds", 68 | "Maximum number of open file descriptors.", 69 | nil, nil, 70 | ), 71 | vsize: NewDesc( 72 | ns+"process_virtual_memory_bytes", 73 | "Virtual memory size in bytes.", 74 | nil, nil, 75 | ), 76 | rss: NewDesc( 77 | ns+"process_resident_memory_bytes", 78 | "Resident memory size in bytes.", 79 | nil, nil, 80 | ), 81 | startTime: NewDesc( 82 | ns+"process_start_time_seconds", 83 | "Start time of the process since unix epoch in seconds.", 84 | nil, nil, 85 | ), 86 | } 87 | 88 | // Set up process metric collection if supported by the runtime. 89 | if _, err := procfs.NewStat(); err == nil { 90 | c.collectFn = c.processCollect 91 | } 92 | 93 | return &c 94 | } 95 | 96 | // Describe returns all descriptions of the collector. 97 | func (c *processCollector) Describe(ch chan<- *Desc) { 98 | ch <- c.cpuTotal 99 | ch <- c.openFDs 100 | ch <- c.maxFDs 101 | ch <- c.vsize 102 | ch <- c.rss 103 | ch <- c.startTime 104 | } 105 | 106 | // Collect returns the current state of all metrics of the collector. 107 | func (c *processCollector) Collect(ch chan<- Metric) { 108 | c.collectFn(ch) 109 | } 110 | 111 | // TODO(ts): Bring back error reporting by reverting 7faf9e7 as soon as the 112 | // client allows users to configure the error behavior. 113 | func (c *processCollector) processCollect(ch chan<- Metric) { 114 | pid, err := c.pidFn() 115 | if err != nil { 116 | return 117 | } 118 | 119 | p, err := procfs.NewProc(pid) 120 | if err != nil { 121 | return 122 | } 123 | 124 | if stat, err := p.NewStat(); err == nil { 125 | ch <- MustNewConstMetric(c.cpuTotal, CounterValue, stat.CPUTime()) 126 | ch <- MustNewConstMetric(c.vsize, GaugeValue, float64(stat.VirtualMemory())) 127 | ch <- MustNewConstMetric(c.rss, GaugeValue, float64(stat.ResidentMemory())) 128 | if startTime, err := stat.StartTime(); err == nil { 129 | ch <- MustNewConstMetric(c.startTime, GaugeValue, startTime) 130 | } 131 | } 132 | 133 | if fds, err := p.FileDescriptorsLen(); err == nil { 134 | ch <- MustNewConstMetric(c.openFDs, GaugeValue, float64(fds)) 135 | } 136 | 137 | if limits, err := p.NewLimits(); err == nil { 138 | ch <- MustNewConstMetric(c.maxFDs, GaugeValue, float64(limits.OpenFiles)) 139 | } 140 | } 141 | -------------------------------------------------------------------------------- /vendor/github.com/prometheus/client_golang/prometheus/promhttp/http.go: -------------------------------------------------------------------------------- 1 | // Copyright 2016 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 | 14 | // Copyright (c) 2013, The Prometheus Authors 15 | // All rights reserved. 16 | // 17 | // Use of this source code is governed by a BSD-style license that can be found 18 | // in the LICENSE file. 19 | 20 | // Package promhttp contains functions to create http.Handler instances to 21 | // expose Prometheus metrics via HTTP. In later versions of this package, it 22 | // will also contain tooling to instrument instances of http.Handler and 23 | // http.RoundTripper. 24 | // 25 | // promhttp.Handler acts on the prometheus.DefaultGatherer. With HandlerFor, 26 | // you can create a handler for a custom registry or anything that implements 27 | // the Gatherer interface. It also allows to create handlers that act 28 | // differently on errors or allow to log errors. 29 | package promhttp 30 | 31 | import ( 32 | "bytes" 33 | "compress/gzip" 34 | "fmt" 35 | "io" 36 | "net/http" 37 | "strings" 38 | "sync" 39 | 40 | "github.com/prometheus/common/expfmt" 41 | 42 | "github.com/prometheus/client_golang/prometheus" 43 | ) 44 | 45 | const ( 46 | contentTypeHeader = "Content-Type" 47 | contentLengthHeader = "Content-Length" 48 | contentEncodingHeader = "Content-Encoding" 49 | acceptEncodingHeader = "Accept-Encoding" 50 | ) 51 | 52 | var bufPool sync.Pool 53 | 54 | func getBuf() *bytes.Buffer { 55 | buf := bufPool.Get() 56 | if buf == nil { 57 | return &bytes.Buffer{} 58 | } 59 | return buf.(*bytes.Buffer) 60 | } 61 | 62 | func giveBuf(buf *bytes.Buffer) { 63 | buf.Reset() 64 | bufPool.Put(buf) 65 | } 66 | 67 | // Handler returns an HTTP handler for the prometheus.DefaultGatherer. The 68 | // Handler uses the default HandlerOpts, i.e. report the first error as an HTTP 69 | // error, no error logging, and compression if requested by the client. 70 | // 71 | // If you want to create a Handler for the DefaultGatherer with different 72 | // HandlerOpts, create it with HandlerFor with prometheus.DefaultGatherer and 73 | // your desired HandlerOpts. 74 | func Handler() http.Handler { 75 | return HandlerFor(prometheus.DefaultGatherer, HandlerOpts{}) 76 | } 77 | 78 | // HandlerFor returns an http.Handler for the provided Gatherer. The behavior 79 | // of the Handler is defined by the provided HandlerOpts. 80 | func HandlerFor(reg prometheus.Gatherer, opts HandlerOpts) http.Handler { 81 | return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { 82 | mfs, err := reg.Gather() 83 | if err != nil { 84 | if opts.ErrorLog != nil { 85 | opts.ErrorLog.Println("error gathering metrics:", err) 86 | } 87 | switch opts.ErrorHandling { 88 | case PanicOnError: 89 | panic(err) 90 | case ContinueOnError: 91 | if len(mfs) == 0 { 92 | http.Error(w, "No metrics gathered, last error:\n\n"+err.Error(), http.StatusInternalServerError) 93 | return 94 | } 95 | case HTTPErrorOnError: 96 | http.Error(w, "An error has occurred during metrics gathering:\n\n"+err.Error(), http.StatusInternalServerError) 97 | return 98 | } 99 | } 100 | 101 | contentType := expfmt.Negotiate(req.Header) 102 | buf := getBuf() 103 | defer giveBuf(buf) 104 | writer, encoding := decorateWriter(req, buf, opts.DisableCompression) 105 | enc := expfmt.NewEncoder(writer, contentType) 106 | var lastErr error 107 | for _, mf := range mfs { 108 | if err := enc.Encode(mf); err != nil { 109 | lastErr = err 110 | if opts.ErrorLog != nil { 111 | opts.ErrorLog.Println("error encoding metric family:", err) 112 | } 113 | switch opts.ErrorHandling { 114 | case PanicOnError: 115 | panic(err) 116 | case ContinueOnError: 117 | // Handled later. 118 | case HTTPErrorOnError: 119 | http.Error(w, "An error has occurred during metrics encoding:\n\n"+err.Error(), http.StatusInternalServerError) 120 | return 121 | } 122 | } 123 | } 124 | if closer, ok := writer.(io.Closer); ok { 125 | closer.Close() 126 | } 127 | if lastErr != nil && buf.Len() == 0 { 128 | http.Error(w, "No metrics encoded, last error:\n\n"+err.Error(), http.StatusInternalServerError) 129 | return 130 | } 131 | header := w.Header() 132 | header.Set(contentTypeHeader, string(contentType)) 133 | header.Set(contentLengthHeader, fmt.Sprint(buf.Len())) 134 | if encoding != "" { 135 | header.Set(contentEncodingHeader, encoding) 136 | } 137 | w.Write(buf.Bytes()) 138 | // TODO(beorn7): Consider streaming serving of metrics. 139 | }) 140 | } 141 | 142 | // HandlerErrorHandling defines how a Handler serving metrics will handle 143 | // errors. 144 | type HandlerErrorHandling int 145 | 146 | // These constants cause handlers serving metrics to behave as described if 147 | // errors are encountered. 148 | const ( 149 | // Serve an HTTP status code 500 upon the first error 150 | // encountered. Report the error message in the body. 151 | HTTPErrorOnError HandlerErrorHandling = iota 152 | // Ignore errors and try to serve as many metrics as possible. However, 153 | // if no metrics can be served, serve an HTTP status code 500 and the 154 | // last error message in the body. Only use this in deliberate "best 155 | // effort" metrics collection scenarios. It is recommended to at least 156 | // log errors (by providing an ErrorLog in HandlerOpts) to not mask 157 | // errors completely. 158 | ContinueOnError 159 | // Panic upon the first error encountered (useful for "crash only" apps). 160 | PanicOnError 161 | ) 162 | 163 | // Logger is the minimal interface HandlerOpts needs for logging. Note that 164 | // log.Logger from the standard library implements this interface, and it is 165 | // easy to implement by custom loggers, if they don't do so already anyway. 166 | type Logger interface { 167 | Println(v ...interface{}) 168 | } 169 | 170 | // HandlerOpts specifies options how to serve metrics via an http.Handler. The 171 | // zero value of HandlerOpts is a reasonable default. 172 | type HandlerOpts struct { 173 | // ErrorLog specifies an optional logger for errors collecting and 174 | // serving metrics. If nil, errors are not logged at all. 175 | ErrorLog Logger 176 | // ErrorHandling defines how errors are handled. Note that errors are 177 | // logged regardless of the configured ErrorHandling provided ErrorLog 178 | // is not nil. 179 | ErrorHandling HandlerErrorHandling 180 | // If DisableCompression is true, the handler will never compress the 181 | // response, even if requested by the client. 182 | DisableCompression bool 183 | } 184 | 185 | // decorateWriter wraps a writer to handle gzip compression if requested. It 186 | // returns the decorated writer and the appropriate "Content-Encoding" header 187 | // (which is empty if no compression is enabled). 188 | func decorateWriter(request *http.Request, writer io.Writer, compressionDisabled bool) (io.Writer, string) { 189 | if compressionDisabled { 190 | return writer, "" 191 | } 192 | header := request.Header.Get(acceptEncodingHeader) 193 | parts := strings.Split(header, ",") 194 | for _, part := range parts { 195 | part := strings.TrimSpace(part) 196 | if part == "gzip" || strings.HasPrefix(part, "gzip;") { 197 | return gzip.NewWriter(writer), "gzip" 198 | } 199 | } 200 | return writer, "" 201 | } 202 | -------------------------------------------------------------------------------- /vendor/github.com/prometheus/client_golang/prometheus/timer.go: -------------------------------------------------------------------------------- 1 | // Copyright 2016 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 | 14 | package prometheus 15 | 16 | import "time" 17 | 18 | // Observer is the interface that wraps the Observe method, which is used by 19 | // Histogram and Summary to add observations. 20 | type Observer interface { 21 | Observe(float64) 22 | } 23 | 24 | // The ObserverFunc type is an adapter to allow the use of ordinary 25 | // functions as Observers. If f is a function with the appropriate 26 | // signature, ObserverFunc(f) is an Observer that calls f. 27 | // 28 | // This adapter is usually used in connection with the Timer type, and there are 29 | // two general use cases: 30 | // 31 | // The most common one is to use a Gauge as the Observer for a Timer. 32 | // See the "Gauge" Timer example. 33 | // 34 | // The more advanced use case is to create a function that dynamically decides 35 | // which Observer to use for observing the duration. See the "Complex" Timer 36 | // example. 37 | type ObserverFunc func(float64) 38 | 39 | // Observe calls f(value). It implements Observer. 40 | func (f ObserverFunc) Observe(value float64) { 41 | f(value) 42 | } 43 | 44 | // Timer is a helper type to time functions. Use NewTimer to create new 45 | // instances. 46 | type Timer struct { 47 | begin time.Time 48 | observer Observer 49 | } 50 | 51 | // NewTimer creates a new Timer. The provided Observer is used to observe a 52 | // duration in seconds. Timer is usually used to time a function call in the 53 | // following way: 54 | // func TimeMe() { 55 | // timer := NewTimer(myHistogram) 56 | // defer timer.ObserveDuration() 57 | // // Do actual work. 58 | // } 59 | func NewTimer(o Observer) *Timer { 60 | return &Timer{ 61 | begin: time.Now(), 62 | observer: o, 63 | } 64 | } 65 | 66 | // ObserveDuration records the duration passed since the Timer was created with 67 | // NewTimer. It calls the Observe method of the Observer provided during 68 | // construction with the duration in seconds as an argument. ObserveDuration is 69 | // usually called with a defer statement. 70 | func (t *Timer) ObserveDuration() { 71 | if t.observer != nil { 72 | t.observer.Observe(time.Since(t.begin).Seconds()) 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /vendor/github.com/prometheus/client_golang/prometheus/untyped.go: -------------------------------------------------------------------------------- 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 | 14 | package prometheus 15 | 16 | // Untyped is a Metric that represents a single numerical value that can 17 | // arbitrarily go up and down. 18 | // 19 | // An Untyped metric works the same as a Gauge. The only difference is that to 20 | // no type information is implied. 21 | // 22 | // To create Untyped instances, use NewUntyped. 23 | // 24 | // Deprecated: The Untyped type is deprecated because it doesn't make sense in 25 | // direct instrumentation. If you need to mirror an external metric of unknown 26 | // type (usually while writing exporters), Use MustNewConstMetric to create an 27 | // untyped metric instance on the fly. 28 | type Untyped interface { 29 | Metric 30 | Collector 31 | 32 | // Set sets the Untyped metric to an arbitrary value. 33 | Set(float64) 34 | // Inc increments the Untyped metric by 1. 35 | Inc() 36 | // Dec decrements the Untyped metric by 1. 37 | Dec() 38 | // Add adds the given value to the Untyped metric. (The value can be 39 | // negative, resulting in a decrease.) 40 | Add(float64) 41 | // Sub subtracts the given value from the Untyped metric. (The value can 42 | // be negative, resulting in an increase.) 43 | Sub(float64) 44 | } 45 | 46 | // UntypedOpts is an alias for Opts. See there for doc comments. 47 | type UntypedOpts Opts 48 | 49 | // NewUntyped creates a new Untyped metric from the provided UntypedOpts. 50 | func NewUntyped(opts UntypedOpts) Untyped { 51 | return newValue(NewDesc( 52 | BuildFQName(opts.Namespace, opts.Subsystem, opts.Name), 53 | opts.Help, 54 | nil, 55 | opts.ConstLabels, 56 | ), UntypedValue, 0) 57 | } 58 | 59 | // UntypedVec is a Collector that bundles a set of Untyped metrics that all 60 | // share the same Desc, but have different values for their variable 61 | // labels. This is used if you want to count the same thing partitioned by 62 | // various dimensions. Create instances with NewUntypedVec. 63 | type UntypedVec struct { 64 | *MetricVec 65 | } 66 | 67 | // NewUntypedVec creates a new UntypedVec based on the provided UntypedOpts and 68 | // partitioned by the given label names. At least one label name must be 69 | // provided. 70 | func NewUntypedVec(opts UntypedOpts, labelNames []string) *UntypedVec { 71 | desc := NewDesc( 72 | BuildFQName(opts.Namespace, opts.Subsystem, opts.Name), 73 | opts.Help, 74 | labelNames, 75 | opts.ConstLabels, 76 | ) 77 | return &UntypedVec{ 78 | MetricVec: newMetricVec(desc, func(lvs ...string) Metric { 79 | return newValue(desc, UntypedValue, 0, lvs...) 80 | }), 81 | } 82 | } 83 | 84 | // GetMetricWithLabelValues replaces the method of the same name in 85 | // MetricVec. The difference is that this method returns an Untyped and not a 86 | // Metric so that no type conversion is required. 87 | func (m *UntypedVec) GetMetricWithLabelValues(lvs ...string) (Untyped, error) { 88 | metric, err := m.MetricVec.GetMetricWithLabelValues(lvs...) 89 | if metric != nil { 90 | return metric.(Untyped), err 91 | } 92 | return nil, err 93 | } 94 | 95 | // GetMetricWith replaces the method of the same name in MetricVec. The 96 | // difference is that this method returns an Untyped and not a Metric so that no 97 | // type conversion is required. 98 | func (m *UntypedVec) GetMetricWith(labels Labels) (Untyped, error) { 99 | metric, err := m.MetricVec.GetMetricWith(labels) 100 | if metric != nil { 101 | return metric.(Untyped), err 102 | } 103 | return nil, err 104 | } 105 | 106 | // WithLabelValues works as GetMetricWithLabelValues, but panics where 107 | // GetMetricWithLabelValues would have returned an error. By not returning an 108 | // error, WithLabelValues allows shortcuts like 109 | // myVec.WithLabelValues("404", "GET").Add(42) 110 | func (m *UntypedVec) WithLabelValues(lvs ...string) Untyped { 111 | return m.MetricVec.WithLabelValues(lvs...).(Untyped) 112 | } 113 | 114 | // With works as GetMetricWith, but panics where GetMetricWithLabels would have 115 | // returned an error. By not returning an error, With allows shortcuts like 116 | // myVec.With(Labels{"code": "404", "method": "GET"}).Add(42) 117 | func (m *UntypedVec) With(labels Labels) Untyped { 118 | return m.MetricVec.With(labels).(Untyped) 119 | } 120 | 121 | // UntypedFunc is an Untyped whose value is determined at collect time by 122 | // calling a provided function. 123 | // 124 | // To create UntypedFunc instances, use NewUntypedFunc. 125 | type UntypedFunc interface { 126 | Metric 127 | Collector 128 | } 129 | 130 | // NewUntypedFunc creates a new UntypedFunc based on the provided 131 | // UntypedOpts. The value reported is determined by calling the given function 132 | // from within the Write method. Take into account that metric collection may 133 | // happen concurrently. If that results in concurrent calls to Write, like in 134 | // the case where an UntypedFunc is directly registered with Prometheus, the 135 | // provided function must be concurrency-safe. 136 | func NewUntypedFunc(opts UntypedOpts, function func() float64) UntypedFunc { 137 | return newValueFunc(NewDesc( 138 | BuildFQName(opts.Namespace, opts.Subsystem, opts.Name), 139 | opts.Help, 140 | nil, 141 | opts.ConstLabels, 142 | ), UntypedValue, function) 143 | } 144 | -------------------------------------------------------------------------------- /vendor/github.com/prometheus/client_golang/prometheus/value.go: -------------------------------------------------------------------------------- 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 | 14 | package prometheus 15 | 16 | import ( 17 | "errors" 18 | "fmt" 19 | "math" 20 | "sort" 21 | "sync/atomic" 22 | "time" 23 | 24 | dto "github.com/prometheus/client_model/go" 25 | 26 | "github.com/golang/protobuf/proto" 27 | ) 28 | 29 | // ValueType is an enumeration of metric types that represent a simple value. 30 | type ValueType int 31 | 32 | // Possible values for the ValueType enum. 33 | const ( 34 | _ ValueType = iota 35 | CounterValue 36 | GaugeValue 37 | UntypedValue 38 | ) 39 | 40 | var errInconsistentCardinality = errors.New("inconsistent label cardinality") 41 | 42 | // value is a generic metric for simple values. It implements Metric, Collector, 43 | // Counter, Gauge, and Untyped. Its effective type is determined by 44 | // ValueType. This is a low-level building block used by the library to back the 45 | // implementations of Counter, Gauge, and Untyped. 46 | type value struct { 47 | // valBits containst the bits of the represented float64 value. It has 48 | // to go first in the struct to guarantee alignment for atomic 49 | // operations. http://golang.org/pkg/sync/atomic/#pkg-note-BUG 50 | valBits uint64 51 | 52 | selfCollector 53 | 54 | desc *Desc 55 | valType ValueType 56 | labelPairs []*dto.LabelPair 57 | } 58 | 59 | // newValue returns a newly allocated value with the given Desc, ValueType, 60 | // sample value and label values. It panics if the number of label 61 | // values is different from the number of variable labels in Desc. 62 | func newValue(desc *Desc, valueType ValueType, val float64, labelValues ...string) *value { 63 | if len(labelValues) != len(desc.variableLabels) { 64 | panic(errInconsistentCardinality) 65 | } 66 | result := &value{ 67 | desc: desc, 68 | valType: valueType, 69 | valBits: math.Float64bits(val), 70 | labelPairs: makeLabelPairs(desc, labelValues), 71 | } 72 | result.init(result) 73 | return result 74 | } 75 | 76 | func (v *value) Desc() *Desc { 77 | return v.desc 78 | } 79 | 80 | func (v *value) Set(val float64) { 81 | atomic.StoreUint64(&v.valBits, math.Float64bits(val)) 82 | } 83 | 84 | func (v *value) SetToCurrentTime() { 85 | v.Set(float64(time.Now().UnixNano()) / 1e9) 86 | } 87 | 88 | func (v *value) Inc() { 89 | v.Add(1) 90 | } 91 | 92 | func (v *value) Dec() { 93 | v.Add(-1) 94 | } 95 | 96 | func (v *value) Add(val float64) { 97 | for { 98 | oldBits := atomic.LoadUint64(&v.valBits) 99 | newBits := math.Float64bits(math.Float64frombits(oldBits) + val) 100 | if atomic.CompareAndSwapUint64(&v.valBits, oldBits, newBits) { 101 | return 102 | } 103 | } 104 | } 105 | 106 | func (v *value) Sub(val float64) { 107 | v.Add(val * -1) 108 | } 109 | 110 | func (v *value) Write(out *dto.Metric) error { 111 | val := math.Float64frombits(atomic.LoadUint64(&v.valBits)) 112 | return populateMetric(v.valType, val, v.labelPairs, out) 113 | } 114 | 115 | // valueFunc is a generic metric for simple values retrieved on collect time 116 | // from a function. It implements Metric and Collector. Its effective type is 117 | // determined by ValueType. This is a low-level building block used by the 118 | // library to back the implementations of CounterFunc, GaugeFunc, and 119 | // UntypedFunc. 120 | type valueFunc struct { 121 | selfCollector 122 | 123 | desc *Desc 124 | valType ValueType 125 | function func() float64 126 | labelPairs []*dto.LabelPair 127 | } 128 | 129 | // newValueFunc returns a newly allocated valueFunc with the given Desc and 130 | // ValueType. The value reported is determined by calling the given function 131 | // from within the Write method. Take into account that metric collection may 132 | // happen concurrently. If that results in concurrent calls to Write, like in 133 | // the case where a valueFunc is directly registered with Prometheus, the 134 | // provided function must be concurrency-safe. 135 | func newValueFunc(desc *Desc, valueType ValueType, function func() float64) *valueFunc { 136 | result := &valueFunc{ 137 | desc: desc, 138 | valType: valueType, 139 | function: function, 140 | labelPairs: makeLabelPairs(desc, nil), 141 | } 142 | result.init(result) 143 | return result 144 | } 145 | 146 | func (v *valueFunc) Desc() *Desc { 147 | return v.desc 148 | } 149 | 150 | func (v *valueFunc) Write(out *dto.Metric) error { 151 | return populateMetric(v.valType, v.function(), v.labelPairs, out) 152 | } 153 | 154 | // NewConstMetric returns a metric with one fixed value that cannot be 155 | // changed. Users of this package will not have much use for it in regular 156 | // operations. However, when implementing custom Collectors, it is useful as a 157 | // throw-away metric that is generated on the fly to send it to Prometheus in 158 | // the Collect method. NewConstMetric returns an error if the length of 159 | // labelValues is not consistent with the variable labels in Desc. 160 | func NewConstMetric(desc *Desc, valueType ValueType, value float64, labelValues ...string) (Metric, error) { 161 | if len(desc.variableLabels) != len(labelValues) { 162 | return nil, errInconsistentCardinality 163 | } 164 | return &constMetric{ 165 | desc: desc, 166 | valType: valueType, 167 | val: value, 168 | labelPairs: makeLabelPairs(desc, labelValues), 169 | }, nil 170 | } 171 | 172 | // MustNewConstMetric is a version of NewConstMetric that panics where 173 | // NewConstMetric would have returned an error. 174 | func MustNewConstMetric(desc *Desc, valueType ValueType, value float64, labelValues ...string) Metric { 175 | m, err := NewConstMetric(desc, valueType, value, labelValues...) 176 | if err != nil { 177 | panic(err) 178 | } 179 | return m 180 | } 181 | 182 | type constMetric struct { 183 | desc *Desc 184 | valType ValueType 185 | val float64 186 | labelPairs []*dto.LabelPair 187 | } 188 | 189 | func (m *constMetric) Desc() *Desc { 190 | return m.desc 191 | } 192 | 193 | func (m *constMetric) Write(out *dto.Metric) error { 194 | return populateMetric(m.valType, m.val, m.labelPairs, out) 195 | } 196 | 197 | func populateMetric( 198 | t ValueType, 199 | v float64, 200 | labelPairs []*dto.LabelPair, 201 | m *dto.Metric, 202 | ) error { 203 | m.Label = labelPairs 204 | switch t { 205 | case CounterValue: 206 | m.Counter = &dto.Counter{Value: proto.Float64(v)} 207 | case GaugeValue: 208 | m.Gauge = &dto.Gauge{Value: proto.Float64(v)} 209 | case UntypedValue: 210 | m.Untyped = &dto.Untyped{Value: proto.Float64(v)} 211 | default: 212 | return fmt.Errorf("encountered unknown type %v", t) 213 | } 214 | return nil 215 | } 216 | 217 | func makeLabelPairs(desc *Desc, labelValues []string) []*dto.LabelPair { 218 | totalLen := len(desc.variableLabels) + len(desc.constLabelPairs) 219 | if totalLen == 0 { 220 | // Super fast path. 221 | return nil 222 | } 223 | if len(desc.variableLabels) == 0 { 224 | // Moderately fast path. 225 | return desc.constLabelPairs 226 | } 227 | labelPairs := make([]*dto.LabelPair, 0, totalLen) 228 | for i, n := range desc.variableLabels { 229 | labelPairs = append(labelPairs, &dto.LabelPair{ 230 | Name: proto.String(n), 231 | Value: proto.String(labelValues[i]), 232 | }) 233 | } 234 | for _, lp := range desc.constLabelPairs { 235 | labelPairs = append(labelPairs, lp) 236 | } 237 | sort.Sort(LabelPairSorter(labelPairs)) 238 | return labelPairs 239 | } 240 | -------------------------------------------------------------------------------- /vendor/github.com/prometheus/client_model/AUTHORS.md: -------------------------------------------------------------------------------- 1 | The Prometheus project was started by Matt T. Proud (emeritus) and 2 | Julius Volz in 2012. 3 | 4 | Maintainers of this repository: 5 | 6 | * Björn Rabenstein 7 | 8 | The following individuals have contributed code to this repository 9 | (listed in alphabetical order): 10 | 11 | * Björn Rabenstein 12 | * Matt T. Proud 13 | * Tobias Schmidt 14 | -------------------------------------------------------------------------------- /vendor/github.com/prometheus/client_model/NOTICE: -------------------------------------------------------------------------------- 1 | Data model artifacts for Prometheus. 2 | Copyright 2012-2015 The Prometheus Authors 3 | 4 | This product includes software developed at 5 | SoundCloud Ltd. (http://soundcloud.com/). 6 | -------------------------------------------------------------------------------- /vendor/github.com/prometheus/common/AUTHORS.md: -------------------------------------------------------------------------------- 1 | Maintainers of this repository: 2 | 3 | * Fabian Reinartz 4 | 5 | The following individuals have contributed code to this repository 6 | (listed in alphabetical order): 7 | 8 | * Björn Rabenstein 9 | * Fabian Reinartz 10 | * Julius Volz 11 | * Miguel Molina 12 | -------------------------------------------------------------------------------- /vendor/github.com/prometheus/common/NOTICE: -------------------------------------------------------------------------------- 1 | Common libraries shared by Prometheus Go components. 2 | Copyright 2015 The Prometheus Authors 3 | 4 | This product includes software developed at 5 | SoundCloud Ltd. (http://soundcloud.com/). 6 | -------------------------------------------------------------------------------- /vendor/github.com/prometheus/common/expfmt/encode.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 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 | 14 | package expfmt 15 | 16 | import ( 17 | "fmt" 18 | "io" 19 | "net/http" 20 | 21 | "github.com/golang/protobuf/proto" 22 | "github.com/matttproud/golang_protobuf_extensions/pbutil" 23 | "github.com/prometheus/common/internal/bitbucket.org/ww/goautoneg" 24 | 25 | dto "github.com/prometheus/client_model/go" 26 | ) 27 | 28 | // Encoder types encode metric families into an underlying wire protocol. 29 | type Encoder interface { 30 | Encode(*dto.MetricFamily) error 31 | } 32 | 33 | type encoder func(*dto.MetricFamily) error 34 | 35 | func (e encoder) Encode(v *dto.MetricFamily) error { 36 | return e(v) 37 | } 38 | 39 | // Negotiate returns the Content-Type based on the given Accept header. 40 | // If no appropriate accepted type is found, FmtText is returned. 41 | func Negotiate(h http.Header) Format { 42 | for _, ac := range goautoneg.ParseAccept(h.Get(hdrAccept)) { 43 | // Check for protocol buffer 44 | if ac.Type+"/"+ac.SubType == ProtoType && ac.Params["proto"] == ProtoProtocol { 45 | switch ac.Params["encoding"] { 46 | case "delimited": 47 | return FmtProtoDelim 48 | case "text": 49 | return FmtProtoText 50 | case "compact-text": 51 | return FmtProtoCompact 52 | } 53 | } 54 | // Check for text format. 55 | ver := ac.Params["version"] 56 | if ac.Type == "text" && ac.SubType == "plain" && (ver == TextVersion || ver == "") { 57 | return FmtText 58 | } 59 | } 60 | return FmtText 61 | } 62 | 63 | // NewEncoder returns a new encoder based on content type negotiation. 64 | func NewEncoder(w io.Writer, format Format) Encoder { 65 | switch format { 66 | case FmtProtoDelim: 67 | return encoder(func(v *dto.MetricFamily) error { 68 | _, err := pbutil.WriteDelimited(w, v) 69 | return err 70 | }) 71 | case FmtProtoCompact: 72 | return encoder(func(v *dto.MetricFamily) error { 73 | _, err := fmt.Fprintln(w, v.String()) 74 | return err 75 | }) 76 | case FmtProtoText: 77 | return encoder(func(v *dto.MetricFamily) error { 78 | _, err := fmt.Fprintln(w, proto.MarshalTextString(v)) 79 | return err 80 | }) 81 | case FmtText: 82 | return encoder(func(v *dto.MetricFamily) error { 83 | _, err := MetricFamilyToText(w, v) 84 | return err 85 | }) 86 | } 87 | panic("expfmt.NewEncoder: unknown format") 88 | } 89 | -------------------------------------------------------------------------------- /vendor/github.com/prometheus/common/expfmt/expfmt.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 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 | 14 | // A package for reading and writing Prometheus metrics. 15 | package expfmt 16 | 17 | type Format string 18 | 19 | const ( 20 | TextVersion = "0.0.4" 21 | 22 | ProtoType = `application/vnd.google.protobuf` 23 | ProtoProtocol = `io.prometheus.client.MetricFamily` 24 | ProtoFmt = ProtoType + "; proto=" + ProtoProtocol + ";" 25 | 26 | // The Content-Type values for the different wire protocols. 27 | FmtUnknown Format = `` 28 | FmtText Format = `text/plain; version=` + TextVersion 29 | FmtProtoDelim Format = ProtoFmt + ` encoding=delimited` 30 | FmtProtoText Format = ProtoFmt + ` encoding=text` 31 | FmtProtoCompact Format = ProtoFmt + ` encoding=compact-text` 32 | ) 33 | 34 | const ( 35 | hdrContentType = "Content-Type" 36 | hdrAccept = "Accept" 37 | ) 38 | -------------------------------------------------------------------------------- /vendor/github.com/prometheus/common/expfmt/fuzz.go: -------------------------------------------------------------------------------- 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 | 14 | // Build only when actually fuzzing 15 | // +build gofuzz 16 | 17 | package expfmt 18 | 19 | import "bytes" 20 | 21 | // Fuzz text metric parser with with github.com/dvyukov/go-fuzz: 22 | // 23 | // go-fuzz-build github.com/prometheus/common/expfmt 24 | // go-fuzz -bin expfmt-fuzz.zip -workdir fuzz 25 | // 26 | // Further input samples should go in the folder fuzz/corpus. 27 | func Fuzz(in []byte) int { 28 | parser := TextParser{} 29 | _, err := parser.TextToMetricFamilies(bytes.NewReader(in)) 30 | 31 | if err != nil { 32 | return 0 33 | } 34 | 35 | return 1 36 | } 37 | -------------------------------------------------------------------------------- /vendor/github.com/prometheus/common/internal/bitbucket.org/ww/goautoneg/README.txt: -------------------------------------------------------------------------------- 1 | PACKAGE 2 | 3 | package goautoneg 4 | import "bitbucket.org/ww/goautoneg" 5 | 6 | HTTP Content-Type Autonegotiation. 7 | 8 | The functions in this package implement the behaviour specified in 9 | http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html 10 | 11 | Copyright (c) 2011, Open Knowledge Foundation Ltd. 12 | All rights reserved. 13 | 14 | Redistribution and use in source and binary forms, with or without 15 | modification, are permitted provided that the following conditions are 16 | met: 17 | 18 | Redistributions of source code must retain the above copyright 19 | notice, this list of conditions and the following disclaimer. 20 | 21 | Redistributions in binary form must reproduce the above copyright 22 | notice, this list of conditions and the following disclaimer in 23 | the documentation and/or other materials provided with the 24 | distribution. 25 | 26 | Neither the name of the Open Knowledge Foundation Ltd. nor the 27 | names of its contributors may be used to endorse or promote 28 | products derived from this software without specific prior written 29 | permission. 30 | 31 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 32 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 33 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 34 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 35 | HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 36 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 37 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 38 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 39 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 40 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 41 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 42 | 43 | 44 | FUNCTIONS 45 | 46 | func Negotiate(header string, alternatives []string) (content_type string) 47 | Negotiate the most appropriate content_type given the accept header 48 | and a list of alternatives. 49 | 50 | func ParseAccept(header string) (accept []Accept) 51 | Parse an Accept Header string returning a sorted list 52 | of clauses 53 | 54 | 55 | TYPES 56 | 57 | type Accept struct { 58 | Type, SubType string 59 | Q float32 60 | Params map[string]string 61 | } 62 | Structure to represent a clause in an HTTP Accept Header 63 | 64 | 65 | SUBDIRECTORIES 66 | 67 | .hg 68 | -------------------------------------------------------------------------------- /vendor/github.com/prometheus/common/internal/bitbucket.org/ww/goautoneg/autoneg.go: -------------------------------------------------------------------------------- 1 | /* 2 | HTTP Content-Type Autonegotiation. 3 | 4 | The functions in this package implement the behaviour specified in 5 | http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html 6 | 7 | Copyright (c) 2011, Open Knowledge Foundation Ltd. 8 | All rights reserved. 9 | 10 | Redistribution and use in source and binary forms, with or without 11 | modification, are permitted provided that the following conditions are 12 | met: 13 | 14 | Redistributions of source code must retain the above copyright 15 | notice, this list of conditions and the following disclaimer. 16 | 17 | Redistributions in binary form must reproduce the above copyright 18 | notice, this list of conditions and the following disclaimer in 19 | the documentation and/or other materials provided with the 20 | distribution. 21 | 22 | Neither the name of the Open Knowledge Foundation Ltd. nor the 23 | names of its contributors may be used to endorse or promote 24 | products derived from this software without specific prior written 25 | permission. 26 | 27 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 28 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 29 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 30 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 31 | HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 32 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 33 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 34 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 35 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 36 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 37 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 38 | 39 | 40 | */ 41 | package goautoneg 42 | 43 | import ( 44 | "sort" 45 | "strconv" 46 | "strings" 47 | ) 48 | 49 | // Structure to represent a clause in an HTTP Accept Header 50 | type Accept struct { 51 | Type, SubType string 52 | Q float64 53 | Params map[string]string 54 | } 55 | 56 | // For internal use, so that we can use the sort interface 57 | type accept_slice []Accept 58 | 59 | func (accept accept_slice) Len() int { 60 | slice := []Accept(accept) 61 | return len(slice) 62 | } 63 | 64 | func (accept accept_slice) Less(i, j int) bool { 65 | slice := []Accept(accept) 66 | ai, aj := slice[i], slice[j] 67 | if ai.Q > aj.Q { 68 | return true 69 | } 70 | if ai.Type != "*" && aj.Type == "*" { 71 | return true 72 | } 73 | if ai.SubType != "*" && aj.SubType == "*" { 74 | return true 75 | } 76 | return false 77 | } 78 | 79 | func (accept accept_slice) Swap(i, j int) { 80 | slice := []Accept(accept) 81 | slice[i], slice[j] = slice[j], slice[i] 82 | } 83 | 84 | // Parse an Accept Header string returning a sorted list 85 | // of clauses 86 | func ParseAccept(header string) (accept []Accept) { 87 | parts := strings.Split(header, ",") 88 | accept = make([]Accept, 0, len(parts)) 89 | for _, part := range parts { 90 | part := strings.Trim(part, " ") 91 | 92 | a := Accept{} 93 | a.Params = make(map[string]string) 94 | a.Q = 1.0 95 | 96 | mrp := strings.Split(part, ";") 97 | 98 | media_range := mrp[0] 99 | sp := strings.Split(media_range, "/") 100 | a.Type = strings.Trim(sp[0], " ") 101 | 102 | switch { 103 | case len(sp) == 1 && a.Type == "*": 104 | a.SubType = "*" 105 | case len(sp) == 2: 106 | a.SubType = strings.Trim(sp[1], " ") 107 | default: 108 | continue 109 | } 110 | 111 | if len(mrp) == 1 { 112 | accept = append(accept, a) 113 | continue 114 | } 115 | 116 | for _, param := range mrp[1:] { 117 | sp := strings.SplitN(param, "=", 2) 118 | if len(sp) != 2 { 119 | continue 120 | } 121 | token := strings.Trim(sp[0], " ") 122 | if token == "q" { 123 | a.Q, _ = strconv.ParseFloat(sp[1], 32) 124 | } else { 125 | a.Params[token] = strings.Trim(sp[1], " ") 126 | } 127 | } 128 | 129 | accept = append(accept, a) 130 | } 131 | 132 | slice := accept_slice(accept) 133 | sort.Sort(slice) 134 | 135 | return 136 | } 137 | 138 | // Negotiate the most appropriate content_type given the accept header 139 | // and a list of alternatives. 140 | func Negotiate(header string, alternatives []string) (content_type string) { 141 | asp := make([][]string, 0, len(alternatives)) 142 | for _, ctype := range alternatives { 143 | asp = append(asp, strings.SplitN(ctype, "/", 2)) 144 | } 145 | for _, clause := range ParseAccept(header) { 146 | for i, ctsp := range asp { 147 | if clause.Type == ctsp[0] && clause.SubType == ctsp[1] { 148 | content_type = alternatives[i] 149 | return 150 | } 151 | if clause.Type == ctsp[0] && clause.SubType == "*" { 152 | content_type = alternatives[i] 153 | return 154 | } 155 | if clause.Type == "*" && clause.SubType == "*" { 156 | content_type = alternatives[i] 157 | return 158 | } 159 | } 160 | } 161 | return 162 | } 163 | -------------------------------------------------------------------------------- /vendor/github.com/prometheus/common/model/alert.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 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 | 14 | package model 15 | 16 | import ( 17 | "fmt" 18 | "time" 19 | ) 20 | 21 | type AlertStatus string 22 | 23 | const ( 24 | AlertFiring AlertStatus = "firing" 25 | AlertResolved AlertStatus = "resolved" 26 | ) 27 | 28 | // Alert is a generic representation of an alert in the Prometheus eco-system. 29 | type Alert struct { 30 | // Label value pairs for purpose of aggregation, matching, and disposition 31 | // dispatching. This must minimally include an "alertname" label. 32 | Labels LabelSet `json:"labels"` 33 | 34 | // Extra key/value information which does not define alert identity. 35 | Annotations LabelSet `json:"annotations"` 36 | 37 | // The known time range for this alert. Both ends are optional. 38 | StartsAt time.Time `json:"startsAt,omitempty"` 39 | EndsAt time.Time `json:"endsAt,omitempty"` 40 | GeneratorURL string `json:"generatorURL"` 41 | } 42 | 43 | // Name returns the name of the alert. It is equivalent to the "alertname" label. 44 | func (a *Alert) Name() string { 45 | return string(a.Labels[AlertNameLabel]) 46 | } 47 | 48 | // Fingerprint returns a unique hash for the alert. It is equivalent to 49 | // the fingerprint of the alert's label set. 50 | func (a *Alert) Fingerprint() Fingerprint { 51 | return a.Labels.Fingerprint() 52 | } 53 | 54 | func (a *Alert) String() string { 55 | s := fmt.Sprintf("%s[%s]", a.Name(), a.Fingerprint().String()[:7]) 56 | if a.Resolved() { 57 | return s + "[resolved]" 58 | } 59 | return s + "[active]" 60 | } 61 | 62 | // Resolved returns true iff the activity interval ended in the past. 63 | func (a *Alert) Resolved() bool { 64 | return a.ResolvedAt(time.Now()) 65 | } 66 | 67 | // ResolvedAt returns true off the activity interval ended before 68 | // the given timestamp. 69 | func (a *Alert) ResolvedAt(ts time.Time) bool { 70 | if a.EndsAt.IsZero() { 71 | return false 72 | } 73 | return !a.EndsAt.After(ts) 74 | } 75 | 76 | // Status returns the status of the alert. 77 | func (a *Alert) Status() AlertStatus { 78 | if a.Resolved() { 79 | return AlertResolved 80 | } 81 | return AlertFiring 82 | } 83 | 84 | // Validate checks whether the alert data is inconsistent. 85 | func (a *Alert) Validate() error { 86 | if a.StartsAt.IsZero() { 87 | return fmt.Errorf("start time missing") 88 | } 89 | if !a.EndsAt.IsZero() && a.EndsAt.Before(a.StartsAt) { 90 | return fmt.Errorf("start time must be before end time") 91 | } 92 | if err := a.Labels.Validate(); err != nil { 93 | return fmt.Errorf("invalid label set: %s", err) 94 | } 95 | if len(a.Labels) == 0 { 96 | return fmt.Errorf("at least one label pair required") 97 | } 98 | if err := a.Annotations.Validate(); err != nil { 99 | return fmt.Errorf("invalid annotations: %s", err) 100 | } 101 | return nil 102 | } 103 | 104 | // Alert is a list of alerts that can be sorted in chronological order. 105 | type Alerts []*Alert 106 | 107 | func (as Alerts) Len() int { return len(as) } 108 | func (as Alerts) Swap(i, j int) { as[i], as[j] = as[j], as[i] } 109 | 110 | func (as Alerts) Less(i, j int) bool { 111 | if as[i].StartsAt.Before(as[j].StartsAt) { 112 | return true 113 | } 114 | if as[i].EndsAt.Before(as[j].EndsAt) { 115 | return true 116 | } 117 | return as[i].Fingerprint() < as[j].Fingerprint() 118 | } 119 | 120 | // HasFiring returns true iff one of the alerts is not resolved. 121 | func (as Alerts) HasFiring() bool { 122 | for _, a := range as { 123 | if !a.Resolved() { 124 | return true 125 | } 126 | } 127 | return false 128 | } 129 | 130 | // Status returns StatusFiring iff at least one of the alerts is firing. 131 | func (as Alerts) Status() AlertStatus { 132 | if as.HasFiring() { 133 | return AlertFiring 134 | } 135 | return AlertResolved 136 | } 137 | -------------------------------------------------------------------------------- /vendor/github.com/prometheus/common/model/fingerprinting.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 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 | 14 | package model 15 | 16 | import ( 17 | "fmt" 18 | "strconv" 19 | ) 20 | 21 | // Fingerprint provides a hash-capable representation of a Metric. 22 | // For our purposes, FNV-1A 64-bit is used. 23 | type Fingerprint uint64 24 | 25 | // FingerprintFromString transforms a string representation into a Fingerprint. 26 | func FingerprintFromString(s string) (Fingerprint, error) { 27 | num, err := strconv.ParseUint(s, 16, 64) 28 | return Fingerprint(num), err 29 | } 30 | 31 | // ParseFingerprint parses the input string into a fingerprint. 32 | func ParseFingerprint(s string) (Fingerprint, error) { 33 | num, err := strconv.ParseUint(s, 16, 64) 34 | if err != nil { 35 | return 0, err 36 | } 37 | return Fingerprint(num), nil 38 | } 39 | 40 | func (f Fingerprint) String() string { 41 | return fmt.Sprintf("%016x", uint64(f)) 42 | } 43 | 44 | // Fingerprints represents a collection of Fingerprint subject to a given 45 | // natural sorting scheme. It implements sort.Interface. 46 | type Fingerprints []Fingerprint 47 | 48 | // Len implements sort.Interface. 49 | func (f Fingerprints) Len() int { 50 | return len(f) 51 | } 52 | 53 | // Less implements sort.Interface. 54 | func (f Fingerprints) Less(i, j int) bool { 55 | return f[i] < f[j] 56 | } 57 | 58 | // Swap implements sort.Interface. 59 | func (f Fingerprints) Swap(i, j int) { 60 | f[i], f[j] = f[j], f[i] 61 | } 62 | 63 | // FingerprintSet is a set of Fingerprints. 64 | type FingerprintSet map[Fingerprint]struct{} 65 | 66 | // Equal returns true if both sets contain the same elements (and not more). 67 | func (s FingerprintSet) Equal(o FingerprintSet) bool { 68 | if len(s) != len(o) { 69 | return false 70 | } 71 | 72 | for k := range s { 73 | if _, ok := o[k]; !ok { 74 | return false 75 | } 76 | } 77 | 78 | return true 79 | } 80 | 81 | // Intersection returns the elements contained in both sets. 82 | func (s FingerprintSet) Intersection(o FingerprintSet) FingerprintSet { 83 | myLength, otherLength := len(s), len(o) 84 | if myLength == 0 || otherLength == 0 { 85 | return FingerprintSet{} 86 | } 87 | 88 | subSet := s 89 | superSet := o 90 | 91 | if otherLength < myLength { 92 | subSet = o 93 | superSet = s 94 | } 95 | 96 | out := FingerprintSet{} 97 | 98 | for k := range subSet { 99 | if _, ok := superSet[k]; ok { 100 | out[k] = struct{}{} 101 | } 102 | } 103 | 104 | return out 105 | } 106 | -------------------------------------------------------------------------------- /vendor/github.com/prometheus/common/model/fnv.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 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 | 14 | package model 15 | 16 | // Inline and byte-free variant of hash/fnv's fnv64a. 17 | 18 | const ( 19 | offset64 = 14695981039346656037 20 | prime64 = 1099511628211 21 | ) 22 | 23 | // hashNew initializies a new fnv64a hash value. 24 | func hashNew() uint64 { 25 | return offset64 26 | } 27 | 28 | // hashAdd adds a string to a fnv64a hash value, returning the updated hash. 29 | func hashAdd(h uint64, s string) uint64 { 30 | for i := 0; i < len(s); i++ { 31 | h ^= uint64(s[i]) 32 | h *= prime64 33 | } 34 | return h 35 | } 36 | 37 | // hashAddByte adds a byte to a fnv64a hash value, returning the updated hash. 38 | func hashAddByte(h uint64, b byte) uint64 { 39 | h ^= uint64(b) 40 | h *= prime64 41 | return h 42 | } 43 | -------------------------------------------------------------------------------- /vendor/github.com/prometheus/common/model/labels.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 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 | 14 | package model 15 | 16 | import ( 17 | "encoding/json" 18 | "fmt" 19 | "regexp" 20 | "strings" 21 | "unicode/utf8" 22 | ) 23 | 24 | const ( 25 | // AlertNameLabel is the name of the label containing the an alert's name. 26 | AlertNameLabel = "alertname" 27 | 28 | // ExportedLabelPrefix is the prefix to prepend to the label names present in 29 | // exported metrics if a label of the same name is added by the server. 30 | ExportedLabelPrefix = "exported_" 31 | 32 | // MetricNameLabel is the label name indicating the metric name of a 33 | // timeseries. 34 | MetricNameLabel = "__name__" 35 | 36 | // SchemeLabel is the name of the label that holds the scheme on which to 37 | // scrape a target. 38 | SchemeLabel = "__scheme__" 39 | 40 | // AddressLabel is the name of the label that holds the address of 41 | // a scrape target. 42 | AddressLabel = "__address__" 43 | 44 | // MetricsPathLabel is the name of the label that holds the path on which to 45 | // scrape a target. 46 | MetricsPathLabel = "__metrics_path__" 47 | 48 | // ReservedLabelPrefix is a prefix which is not legal in user-supplied 49 | // label names. 50 | ReservedLabelPrefix = "__" 51 | 52 | // MetaLabelPrefix is a prefix for labels that provide meta information. 53 | // Labels with this prefix are used for intermediate label processing and 54 | // will not be attached to time series. 55 | MetaLabelPrefix = "__meta_" 56 | 57 | // TmpLabelPrefix is a prefix for temporary labels as part of relabelling. 58 | // Labels with this prefix are used for intermediate label processing and 59 | // will not be attached to time series. This is reserved for use in 60 | // Prometheus configuration files by users. 61 | TmpLabelPrefix = "__tmp_" 62 | 63 | // ParamLabelPrefix is a prefix for labels that provide URL parameters 64 | // used to scrape a target. 65 | ParamLabelPrefix = "__param_" 66 | 67 | // JobLabel is the label name indicating the job from which a timeseries 68 | // was scraped. 69 | JobLabel = "job" 70 | 71 | // InstanceLabel is the label name used for the instance label. 72 | InstanceLabel = "instance" 73 | 74 | // BucketLabel is used for the label that defines the upper bound of a 75 | // bucket of a histogram ("le" -> "less or equal"). 76 | BucketLabel = "le" 77 | 78 | // QuantileLabel is used for the label that defines the quantile in a 79 | // summary. 80 | QuantileLabel = "quantile" 81 | ) 82 | 83 | // LabelNameRE is a regular expression matching valid label names. Note that the 84 | // IsValid method of LabelName performs the same check but faster than a match 85 | // with this regular expression. 86 | var LabelNameRE = regexp.MustCompile("^[a-zA-Z_][a-zA-Z0-9_]*$") 87 | 88 | // A LabelName is a key for a LabelSet or Metric. It has a value associated 89 | // therewith. 90 | type LabelName string 91 | 92 | // IsValid is true iff the label name matches the pattern of LabelNameRE. This 93 | // method, however, does not use LabelNameRE for the check but a much faster 94 | // hardcoded implementation. 95 | func (ln LabelName) IsValid() bool { 96 | if len(ln) == 0 { 97 | return false 98 | } 99 | for i, b := range ln { 100 | if !((b >= 'a' && b <= 'z') || (b >= 'A' && b <= 'Z') || b == '_' || (b >= '0' && b <= '9' && i > 0)) { 101 | return false 102 | } 103 | } 104 | return true 105 | } 106 | 107 | // UnmarshalYAML implements the yaml.Unmarshaler interface. 108 | func (ln *LabelName) UnmarshalYAML(unmarshal func(interface{}) error) error { 109 | var s string 110 | if err := unmarshal(&s); err != nil { 111 | return err 112 | } 113 | if !LabelName(s).IsValid() { 114 | return fmt.Errorf("%q is not a valid label name", s) 115 | } 116 | *ln = LabelName(s) 117 | return nil 118 | } 119 | 120 | // UnmarshalJSON implements the json.Unmarshaler interface. 121 | func (ln *LabelName) UnmarshalJSON(b []byte) error { 122 | var s string 123 | if err := json.Unmarshal(b, &s); err != nil { 124 | return err 125 | } 126 | if !LabelName(s).IsValid() { 127 | return fmt.Errorf("%q is not a valid label name", s) 128 | } 129 | *ln = LabelName(s) 130 | return nil 131 | } 132 | 133 | // LabelNames is a sortable LabelName slice. In implements sort.Interface. 134 | type LabelNames []LabelName 135 | 136 | func (l LabelNames) Len() int { 137 | return len(l) 138 | } 139 | 140 | func (l LabelNames) Less(i, j int) bool { 141 | return l[i] < l[j] 142 | } 143 | 144 | func (l LabelNames) Swap(i, j int) { 145 | l[i], l[j] = l[j], l[i] 146 | } 147 | 148 | func (l LabelNames) String() string { 149 | labelStrings := make([]string, 0, len(l)) 150 | for _, label := range l { 151 | labelStrings = append(labelStrings, string(label)) 152 | } 153 | return strings.Join(labelStrings, ", ") 154 | } 155 | 156 | // A LabelValue is an associated value for a LabelName. 157 | type LabelValue string 158 | 159 | // IsValid returns true iff the string is a valid UTF8. 160 | func (lv LabelValue) IsValid() bool { 161 | return utf8.ValidString(string(lv)) 162 | } 163 | 164 | // LabelValues is a sortable LabelValue slice. It implements sort.Interface. 165 | type LabelValues []LabelValue 166 | 167 | func (l LabelValues) Len() int { 168 | return len(l) 169 | } 170 | 171 | func (l LabelValues) Less(i, j int) bool { 172 | return string(l[i]) < string(l[j]) 173 | } 174 | 175 | func (l LabelValues) Swap(i, j int) { 176 | l[i], l[j] = l[j], l[i] 177 | } 178 | 179 | // LabelPair pairs a name with a value. 180 | type LabelPair struct { 181 | Name LabelName 182 | Value LabelValue 183 | } 184 | 185 | // LabelPairs is a sortable slice of LabelPair pointers. It implements 186 | // sort.Interface. 187 | type LabelPairs []*LabelPair 188 | 189 | func (l LabelPairs) Len() int { 190 | return len(l) 191 | } 192 | 193 | func (l LabelPairs) Less(i, j int) bool { 194 | switch { 195 | case l[i].Name > l[j].Name: 196 | return false 197 | case l[i].Name < l[j].Name: 198 | return true 199 | case l[i].Value > l[j].Value: 200 | return false 201 | case l[i].Value < l[j].Value: 202 | return true 203 | default: 204 | return false 205 | } 206 | } 207 | 208 | func (l LabelPairs) Swap(i, j int) { 209 | l[i], l[j] = l[j], l[i] 210 | } 211 | -------------------------------------------------------------------------------- /vendor/github.com/prometheus/common/model/labelset.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 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 | 14 | package model 15 | 16 | import ( 17 | "encoding/json" 18 | "fmt" 19 | "sort" 20 | "strings" 21 | ) 22 | 23 | // A LabelSet is a collection of LabelName and LabelValue pairs. The LabelSet 24 | // may be fully-qualified down to the point where it may resolve to a single 25 | // Metric in the data store or not. All operations that occur within the realm 26 | // of a LabelSet can emit a vector of Metric entities to which the LabelSet may 27 | // match. 28 | type LabelSet map[LabelName]LabelValue 29 | 30 | // Validate checks whether all names and values in the label set 31 | // are valid. 32 | func (ls LabelSet) Validate() error { 33 | for ln, lv := range ls { 34 | if !ln.IsValid() { 35 | return fmt.Errorf("invalid name %q", ln) 36 | } 37 | if !lv.IsValid() { 38 | return fmt.Errorf("invalid value %q", lv) 39 | } 40 | } 41 | return nil 42 | } 43 | 44 | // Equal returns true iff both label sets have exactly the same key/value pairs. 45 | func (ls LabelSet) Equal(o LabelSet) bool { 46 | if len(ls) != len(o) { 47 | return false 48 | } 49 | for ln, lv := range ls { 50 | olv, ok := o[ln] 51 | if !ok { 52 | return false 53 | } 54 | if olv != lv { 55 | return false 56 | } 57 | } 58 | return true 59 | } 60 | 61 | // Before compares the metrics, using the following criteria: 62 | // 63 | // If m has fewer labels than o, it is before o. If it has more, it is not. 64 | // 65 | // If the number of labels is the same, the superset of all label names is 66 | // sorted alphanumerically. The first differing label pair found in that order 67 | // determines the outcome: If the label does not exist at all in m, then m is 68 | // before o, and vice versa. Otherwise the label value is compared 69 | // alphanumerically. 70 | // 71 | // If m and o are equal, the method returns false. 72 | func (ls LabelSet) Before(o LabelSet) bool { 73 | if len(ls) < len(o) { 74 | return true 75 | } 76 | if len(ls) > len(o) { 77 | return false 78 | } 79 | 80 | lns := make(LabelNames, 0, len(ls)+len(o)) 81 | for ln := range ls { 82 | lns = append(lns, ln) 83 | } 84 | for ln := range o { 85 | lns = append(lns, ln) 86 | } 87 | // It's probably not worth it to de-dup lns. 88 | sort.Sort(lns) 89 | for _, ln := range lns { 90 | mlv, ok := ls[ln] 91 | if !ok { 92 | return true 93 | } 94 | olv, ok := o[ln] 95 | if !ok { 96 | return false 97 | } 98 | if mlv < olv { 99 | return true 100 | } 101 | if mlv > olv { 102 | return false 103 | } 104 | } 105 | return false 106 | } 107 | 108 | // Clone returns a copy of the label set. 109 | func (ls LabelSet) Clone() LabelSet { 110 | lsn := make(LabelSet, len(ls)) 111 | for ln, lv := range ls { 112 | lsn[ln] = lv 113 | } 114 | return lsn 115 | } 116 | 117 | // Merge is a helper function to non-destructively merge two label sets. 118 | func (l LabelSet) Merge(other LabelSet) LabelSet { 119 | result := make(LabelSet, len(l)) 120 | 121 | for k, v := range l { 122 | result[k] = v 123 | } 124 | 125 | for k, v := range other { 126 | result[k] = v 127 | } 128 | 129 | return result 130 | } 131 | 132 | func (l LabelSet) String() string { 133 | lstrs := make([]string, 0, len(l)) 134 | for l, v := range l { 135 | lstrs = append(lstrs, fmt.Sprintf("%s=%q", l, v)) 136 | } 137 | 138 | sort.Strings(lstrs) 139 | return fmt.Sprintf("{%s}", strings.Join(lstrs, ", ")) 140 | } 141 | 142 | // Fingerprint returns the LabelSet's fingerprint. 143 | func (ls LabelSet) Fingerprint() Fingerprint { 144 | return labelSetToFingerprint(ls) 145 | } 146 | 147 | // FastFingerprint returns the LabelSet's Fingerprint calculated by a faster hashing 148 | // algorithm, which is, however, more susceptible to hash collisions. 149 | func (ls LabelSet) FastFingerprint() Fingerprint { 150 | return labelSetToFastFingerprint(ls) 151 | } 152 | 153 | // UnmarshalJSON implements the json.Unmarshaler interface. 154 | func (l *LabelSet) UnmarshalJSON(b []byte) error { 155 | var m map[LabelName]LabelValue 156 | if err := json.Unmarshal(b, &m); err != nil { 157 | return err 158 | } 159 | // encoding/json only unmarshals maps of the form map[string]T. It treats 160 | // LabelName as a string and does not call its UnmarshalJSON method. 161 | // Thus, we have to replicate the behavior here. 162 | for ln := range m { 163 | if !ln.IsValid() { 164 | return fmt.Errorf("%q is not a valid label name", ln) 165 | } 166 | } 167 | *l = LabelSet(m) 168 | return nil 169 | } 170 | -------------------------------------------------------------------------------- /vendor/github.com/prometheus/common/model/metric.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 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 | 14 | package model 15 | 16 | import ( 17 | "fmt" 18 | "regexp" 19 | "sort" 20 | "strings" 21 | ) 22 | 23 | var ( 24 | separator = []byte{0} 25 | // MetricNameRE is a regular expression matching valid metric 26 | // names. Note that the IsValidMetricName function performs the same 27 | // check but faster than a match with this regular expression. 28 | MetricNameRE = regexp.MustCompile(`^[a-zA-Z_:][a-zA-Z0-9_:]*$`) 29 | ) 30 | 31 | // A Metric is similar to a LabelSet, but the key difference is that a Metric is 32 | // a singleton and refers to one and only one stream of samples. 33 | type Metric LabelSet 34 | 35 | // Equal compares the metrics. 36 | func (m Metric) Equal(o Metric) bool { 37 | return LabelSet(m).Equal(LabelSet(o)) 38 | } 39 | 40 | // Before compares the metrics' underlying label sets. 41 | func (m Metric) Before(o Metric) bool { 42 | return LabelSet(m).Before(LabelSet(o)) 43 | } 44 | 45 | // Clone returns a copy of the Metric. 46 | func (m Metric) Clone() Metric { 47 | clone := make(Metric, len(m)) 48 | for k, v := range m { 49 | clone[k] = v 50 | } 51 | return clone 52 | } 53 | 54 | func (m Metric) String() string { 55 | metricName, hasName := m[MetricNameLabel] 56 | numLabels := len(m) - 1 57 | if !hasName { 58 | numLabels = len(m) 59 | } 60 | labelStrings := make([]string, 0, numLabels) 61 | for label, value := range m { 62 | if label != MetricNameLabel { 63 | labelStrings = append(labelStrings, fmt.Sprintf("%s=%q", label, value)) 64 | } 65 | } 66 | 67 | switch numLabels { 68 | case 0: 69 | if hasName { 70 | return string(metricName) 71 | } 72 | return "{}" 73 | default: 74 | sort.Strings(labelStrings) 75 | return fmt.Sprintf("%s{%s}", metricName, strings.Join(labelStrings, ", ")) 76 | } 77 | } 78 | 79 | // Fingerprint returns a Metric's Fingerprint. 80 | func (m Metric) Fingerprint() Fingerprint { 81 | return LabelSet(m).Fingerprint() 82 | } 83 | 84 | // FastFingerprint returns a Metric's Fingerprint calculated by a faster hashing 85 | // algorithm, which is, however, more susceptible to hash collisions. 86 | func (m Metric) FastFingerprint() Fingerprint { 87 | return LabelSet(m).FastFingerprint() 88 | } 89 | 90 | // IsValidMetricName returns true iff name matches the pattern of MetricNameRE. 91 | // This function, however, does not use MetricNameRE for the check but a much 92 | // faster hardcoded implementation. 93 | func IsValidMetricName(n LabelValue) bool { 94 | if len(n) == 0 { 95 | return false 96 | } 97 | for i, b := range n { 98 | if !((b >= 'a' && b <= 'z') || (b >= 'A' && b <= 'Z') || b == '_' || b == ':' || (b >= '0' && b <= '9' && i > 0)) { 99 | return false 100 | } 101 | } 102 | return true 103 | } 104 | -------------------------------------------------------------------------------- /vendor/github.com/prometheus/common/model/model.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 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 | 14 | // Package model contains common data structures that are shared across 15 | // Prometheus components and libraries. 16 | package model 17 | -------------------------------------------------------------------------------- /vendor/github.com/prometheus/common/model/signature.go: -------------------------------------------------------------------------------- 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 | 14 | package model 15 | 16 | import ( 17 | "sort" 18 | ) 19 | 20 | // SeparatorByte is a byte that cannot occur in valid UTF-8 sequences and is 21 | // used to separate label names, label values, and other strings from each other 22 | // when calculating their combined hash value (aka signature aka fingerprint). 23 | const SeparatorByte byte = 255 24 | 25 | var ( 26 | // cache the signature of an empty label set. 27 | emptyLabelSignature = hashNew() 28 | ) 29 | 30 | // LabelsToSignature returns a quasi-unique signature (i.e., fingerprint) for a 31 | // given label set. (Collisions are possible but unlikely if the number of label 32 | // sets the function is applied to is small.) 33 | func LabelsToSignature(labels map[string]string) uint64 { 34 | if len(labels) == 0 { 35 | return emptyLabelSignature 36 | } 37 | 38 | labelNames := make([]string, 0, len(labels)) 39 | for labelName := range labels { 40 | labelNames = append(labelNames, labelName) 41 | } 42 | sort.Strings(labelNames) 43 | 44 | sum := hashNew() 45 | for _, labelName := range labelNames { 46 | sum = hashAdd(sum, labelName) 47 | sum = hashAddByte(sum, SeparatorByte) 48 | sum = hashAdd(sum, labels[labelName]) 49 | sum = hashAddByte(sum, SeparatorByte) 50 | } 51 | return sum 52 | } 53 | 54 | // labelSetToFingerprint works exactly as LabelsToSignature but takes a LabelSet as 55 | // parameter (rather than a label map) and returns a Fingerprint. 56 | func labelSetToFingerprint(ls LabelSet) Fingerprint { 57 | if len(ls) == 0 { 58 | return Fingerprint(emptyLabelSignature) 59 | } 60 | 61 | labelNames := make(LabelNames, 0, len(ls)) 62 | for labelName := range ls { 63 | labelNames = append(labelNames, labelName) 64 | } 65 | sort.Sort(labelNames) 66 | 67 | sum := hashNew() 68 | for _, labelName := range labelNames { 69 | sum = hashAdd(sum, string(labelName)) 70 | sum = hashAddByte(sum, SeparatorByte) 71 | sum = hashAdd(sum, string(ls[labelName])) 72 | sum = hashAddByte(sum, SeparatorByte) 73 | } 74 | return Fingerprint(sum) 75 | } 76 | 77 | // labelSetToFastFingerprint works similar to labelSetToFingerprint but uses a 78 | // faster and less allocation-heavy hash function, which is more susceptible to 79 | // create hash collisions. Therefore, collision detection should be applied. 80 | func labelSetToFastFingerprint(ls LabelSet) Fingerprint { 81 | if len(ls) == 0 { 82 | return Fingerprint(emptyLabelSignature) 83 | } 84 | 85 | var result uint64 86 | for labelName, labelValue := range ls { 87 | sum := hashNew() 88 | sum = hashAdd(sum, string(labelName)) 89 | sum = hashAddByte(sum, SeparatorByte) 90 | sum = hashAdd(sum, string(labelValue)) 91 | result ^= sum 92 | } 93 | return Fingerprint(result) 94 | } 95 | 96 | // SignatureForLabels works like LabelsToSignature but takes a Metric as 97 | // parameter (rather than a label map) and only includes the labels with the 98 | // specified LabelNames into the signature calculation. The labels passed in 99 | // will be sorted by this function. 100 | func SignatureForLabels(m Metric, labels ...LabelName) uint64 { 101 | if len(labels) == 0 { 102 | return emptyLabelSignature 103 | } 104 | 105 | sort.Sort(LabelNames(labels)) 106 | 107 | sum := hashNew() 108 | for _, label := range labels { 109 | sum = hashAdd(sum, string(label)) 110 | sum = hashAddByte(sum, SeparatorByte) 111 | sum = hashAdd(sum, string(m[label])) 112 | sum = hashAddByte(sum, SeparatorByte) 113 | } 114 | return sum 115 | } 116 | 117 | // SignatureWithoutLabels works like LabelsToSignature but takes a Metric as 118 | // parameter (rather than a label map) and excludes the labels with any of the 119 | // specified LabelNames from the signature calculation. 120 | func SignatureWithoutLabels(m Metric, labels map[LabelName]struct{}) uint64 { 121 | if len(m) == 0 { 122 | return emptyLabelSignature 123 | } 124 | 125 | labelNames := make(LabelNames, 0, len(m)) 126 | for labelName := range m { 127 | if _, exclude := labels[labelName]; !exclude { 128 | labelNames = append(labelNames, labelName) 129 | } 130 | } 131 | if len(labelNames) == 0 { 132 | return emptyLabelSignature 133 | } 134 | sort.Sort(labelNames) 135 | 136 | sum := hashNew() 137 | for _, labelName := range labelNames { 138 | sum = hashAdd(sum, string(labelName)) 139 | sum = hashAddByte(sum, SeparatorByte) 140 | sum = hashAdd(sum, string(m[labelName])) 141 | sum = hashAddByte(sum, SeparatorByte) 142 | } 143 | return sum 144 | } 145 | -------------------------------------------------------------------------------- /vendor/github.com/prometheus/common/model/silence.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 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 | 14 | package model 15 | 16 | import ( 17 | "encoding/json" 18 | "fmt" 19 | "regexp" 20 | "time" 21 | ) 22 | 23 | // Matcher describes a matches the value of a given label. 24 | type Matcher struct { 25 | Name LabelName `json:"name"` 26 | Value string `json:"value"` 27 | IsRegex bool `json:"isRegex"` 28 | } 29 | 30 | func (m *Matcher) UnmarshalJSON(b []byte) error { 31 | type plain Matcher 32 | if err := json.Unmarshal(b, (*plain)(m)); err != nil { 33 | return err 34 | } 35 | 36 | if len(m.Name) == 0 { 37 | return fmt.Errorf("label name in matcher must not be empty") 38 | } 39 | if m.IsRegex { 40 | if _, err := regexp.Compile(m.Value); err != nil { 41 | return err 42 | } 43 | } 44 | return nil 45 | } 46 | 47 | // Validate returns true iff all fields of the matcher have valid values. 48 | func (m *Matcher) Validate() error { 49 | if !m.Name.IsValid() { 50 | return fmt.Errorf("invalid name %q", m.Name) 51 | } 52 | if m.IsRegex { 53 | if _, err := regexp.Compile(m.Value); err != nil { 54 | return fmt.Errorf("invalid regular expression %q", m.Value) 55 | } 56 | } else if !LabelValue(m.Value).IsValid() || len(m.Value) == 0 { 57 | return fmt.Errorf("invalid value %q", m.Value) 58 | } 59 | return nil 60 | } 61 | 62 | // Silence defines the representation of a silence definiton 63 | // in the Prometheus eco-system. 64 | type Silence struct { 65 | ID uint64 `json:"id,omitempty"` 66 | 67 | Matchers []*Matcher `json:"matchers"` 68 | 69 | StartsAt time.Time `json:"startsAt"` 70 | EndsAt time.Time `json:"endsAt"` 71 | 72 | CreatedAt time.Time `json:"createdAt,omitempty"` 73 | CreatedBy string `json:"createdBy"` 74 | Comment string `json:"comment,omitempty"` 75 | } 76 | 77 | // Validate returns true iff all fields of the silence have valid values. 78 | func (s *Silence) Validate() error { 79 | if len(s.Matchers) == 0 { 80 | return fmt.Errorf("at least one matcher required") 81 | } 82 | for _, m := range s.Matchers { 83 | if err := m.Validate(); err != nil { 84 | return fmt.Errorf("invalid matcher: %s", err) 85 | } 86 | } 87 | if s.StartsAt.IsZero() { 88 | return fmt.Errorf("start time missing") 89 | } 90 | if s.EndsAt.IsZero() { 91 | return fmt.Errorf("end time missing") 92 | } 93 | if s.EndsAt.Before(s.StartsAt) { 94 | return fmt.Errorf("start time must be before end time") 95 | } 96 | if s.CreatedBy == "" { 97 | return fmt.Errorf("creator information missing") 98 | } 99 | if s.Comment == "" { 100 | return fmt.Errorf("comment missing") 101 | } 102 | if s.CreatedAt.IsZero() { 103 | return fmt.Errorf("creation timestamp missing") 104 | } 105 | return nil 106 | } 107 | -------------------------------------------------------------------------------- /vendor/github.com/prometheus/common/model/time.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 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 | 14 | package model 15 | 16 | import ( 17 | "fmt" 18 | "math" 19 | "regexp" 20 | "strconv" 21 | "strings" 22 | "time" 23 | ) 24 | 25 | const ( 26 | // MinimumTick is the minimum supported time resolution. This has to be 27 | // at least time.Second in order for the code below to work. 28 | minimumTick = time.Millisecond 29 | // second is the Time duration equivalent to one second. 30 | second = int64(time.Second / minimumTick) 31 | // The number of nanoseconds per minimum tick. 32 | nanosPerTick = int64(minimumTick / time.Nanosecond) 33 | 34 | // Earliest is the earliest Time representable. Handy for 35 | // initializing a high watermark. 36 | Earliest = Time(math.MinInt64) 37 | // Latest is the latest Time representable. Handy for initializing 38 | // a low watermark. 39 | Latest = Time(math.MaxInt64) 40 | ) 41 | 42 | // Time is the number of milliseconds since the epoch 43 | // (1970-01-01 00:00 UTC) excluding leap seconds. 44 | type Time int64 45 | 46 | // Interval describes and interval between two timestamps. 47 | type Interval struct { 48 | Start, End Time 49 | } 50 | 51 | // Now returns the current time as a Time. 52 | func Now() Time { 53 | return TimeFromUnixNano(time.Now().UnixNano()) 54 | } 55 | 56 | // TimeFromUnix returns the Time equivalent to the Unix Time t 57 | // provided in seconds. 58 | func TimeFromUnix(t int64) Time { 59 | return Time(t * second) 60 | } 61 | 62 | // TimeFromUnixNano returns the Time equivalent to the Unix Time 63 | // t provided in nanoseconds. 64 | func TimeFromUnixNano(t int64) Time { 65 | return Time(t / nanosPerTick) 66 | } 67 | 68 | // Equal reports whether two Times represent the same instant. 69 | func (t Time) Equal(o Time) bool { 70 | return t == o 71 | } 72 | 73 | // Before reports whether the Time t is before o. 74 | func (t Time) Before(o Time) bool { 75 | return t < o 76 | } 77 | 78 | // After reports whether the Time t is after o. 79 | func (t Time) After(o Time) bool { 80 | return t > o 81 | } 82 | 83 | // Add returns the Time t + d. 84 | func (t Time) Add(d time.Duration) Time { 85 | return t + Time(d/minimumTick) 86 | } 87 | 88 | // Sub returns the Duration t - o. 89 | func (t Time) Sub(o Time) time.Duration { 90 | return time.Duration(t-o) * minimumTick 91 | } 92 | 93 | // Time returns the time.Time representation of t. 94 | func (t Time) Time() time.Time { 95 | return time.Unix(int64(t)/second, (int64(t)%second)*nanosPerTick) 96 | } 97 | 98 | // Unix returns t as a Unix time, the number of seconds elapsed 99 | // since January 1, 1970 UTC. 100 | func (t Time) Unix() int64 { 101 | return int64(t) / second 102 | } 103 | 104 | // UnixNano returns t as a Unix time, the number of nanoseconds elapsed 105 | // since January 1, 1970 UTC. 106 | func (t Time) UnixNano() int64 { 107 | return int64(t) * nanosPerTick 108 | } 109 | 110 | // The number of digits after the dot. 111 | var dotPrecision = int(math.Log10(float64(second))) 112 | 113 | // String returns a string representation of the Time. 114 | func (t Time) String() string { 115 | return strconv.FormatFloat(float64(t)/float64(second), 'f', -1, 64) 116 | } 117 | 118 | // MarshalJSON implements the json.Marshaler interface. 119 | func (t Time) MarshalJSON() ([]byte, error) { 120 | return []byte(t.String()), nil 121 | } 122 | 123 | // UnmarshalJSON implements the json.Unmarshaler interface. 124 | func (t *Time) UnmarshalJSON(b []byte) error { 125 | p := strings.Split(string(b), ".") 126 | switch len(p) { 127 | case 1: 128 | v, err := strconv.ParseInt(string(p[0]), 10, 64) 129 | if err != nil { 130 | return err 131 | } 132 | *t = Time(v * second) 133 | 134 | case 2: 135 | v, err := strconv.ParseInt(string(p[0]), 10, 64) 136 | if err != nil { 137 | return err 138 | } 139 | v *= second 140 | 141 | prec := dotPrecision - len(p[1]) 142 | if prec < 0 { 143 | p[1] = p[1][:dotPrecision] 144 | } else if prec > 0 { 145 | p[1] = p[1] + strings.Repeat("0", prec) 146 | } 147 | 148 | va, err := strconv.ParseInt(p[1], 10, 32) 149 | if err != nil { 150 | return err 151 | } 152 | 153 | *t = Time(v + va) 154 | 155 | default: 156 | return fmt.Errorf("invalid time %q", string(b)) 157 | } 158 | return nil 159 | } 160 | 161 | // Duration wraps time.Duration. It is used to parse the custom duration format 162 | // from YAML. 163 | // This type should not propagate beyond the scope of input/output processing. 164 | type Duration time.Duration 165 | 166 | var durationRE = regexp.MustCompile("^([0-9]+)(y|w|d|h|m|s|ms)$") 167 | 168 | // StringToDuration parses a string into a time.Duration, assuming that a year 169 | // always has 365d, a week always has 7d, and a day always has 24h. 170 | func ParseDuration(durationStr string) (Duration, error) { 171 | matches := durationRE.FindStringSubmatch(durationStr) 172 | if len(matches) != 3 { 173 | return 0, fmt.Errorf("not a valid duration string: %q", durationStr) 174 | } 175 | var ( 176 | n, _ = strconv.Atoi(matches[1]) 177 | dur = time.Duration(n) * time.Millisecond 178 | ) 179 | switch unit := matches[2]; unit { 180 | case "y": 181 | dur *= 1000 * 60 * 60 * 24 * 365 182 | case "w": 183 | dur *= 1000 * 60 * 60 * 24 * 7 184 | case "d": 185 | dur *= 1000 * 60 * 60 * 24 186 | case "h": 187 | dur *= 1000 * 60 * 60 188 | case "m": 189 | dur *= 1000 * 60 190 | case "s": 191 | dur *= 1000 192 | case "ms": 193 | // Value already correct 194 | default: 195 | return 0, fmt.Errorf("invalid time unit in duration string: %q", unit) 196 | } 197 | return Duration(dur), nil 198 | } 199 | 200 | func (d Duration) String() string { 201 | var ( 202 | ms = int64(time.Duration(d) / time.Millisecond) 203 | unit = "ms" 204 | ) 205 | factors := map[string]int64{ 206 | "y": 1000 * 60 * 60 * 24 * 365, 207 | "w": 1000 * 60 * 60 * 24 * 7, 208 | "d": 1000 * 60 * 60 * 24, 209 | "h": 1000 * 60 * 60, 210 | "m": 1000 * 60, 211 | "s": 1000, 212 | "ms": 1, 213 | } 214 | 215 | switch int64(0) { 216 | case ms % factors["y"]: 217 | unit = "y" 218 | case ms % factors["w"]: 219 | unit = "w" 220 | case ms % factors["d"]: 221 | unit = "d" 222 | case ms % factors["h"]: 223 | unit = "h" 224 | case ms % factors["m"]: 225 | unit = "m" 226 | case ms % factors["s"]: 227 | unit = "s" 228 | } 229 | return fmt.Sprintf("%v%v", ms/factors[unit], unit) 230 | } 231 | 232 | // MarshalYAML implements the yaml.Marshaler interface. 233 | func (d Duration) MarshalYAML() (interface{}, error) { 234 | return d.String(), nil 235 | } 236 | 237 | // UnmarshalYAML implements the yaml.Unmarshaler interface. 238 | func (d *Duration) UnmarshalYAML(unmarshal func(interface{}) error) error { 239 | var s string 240 | if err := unmarshal(&s); err != nil { 241 | return err 242 | } 243 | dur, err := ParseDuration(s) 244 | if err != nil { 245 | return err 246 | } 247 | *d = dur 248 | return nil 249 | } 250 | -------------------------------------------------------------------------------- /vendor/github.com/prometheus/procfs/.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | language: go 3 | go: 4 | - 1.6.4 5 | - 1.7.4 6 | -------------------------------------------------------------------------------- /vendor/github.com/prometheus/procfs/AUTHORS.md: -------------------------------------------------------------------------------- 1 | The Prometheus project was started by Matt T. Proud (emeritus) and 2 | Julius Volz in 2012. 3 | 4 | Maintainers of this repository: 5 | 6 | * Tobias Schmidt 7 | 8 | The following individuals have contributed code to this repository 9 | (listed in alphabetical order): 10 | 11 | * Armen Baghumian 12 | * Bjoern Rabenstein 13 | * David Cournapeau 14 | * Ji-Hoon, Seol 15 | * Jonas Große Sundrup 16 | * Julius Volz 17 | * Matt Layher 18 | * Matthias Rampke 19 | * Nicky Gerritsen 20 | * Rémi Audebert 21 | * Tobias Schmidt 22 | -------------------------------------------------------------------------------- /vendor/github.com/prometheus/procfs/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | Prometheus uses GitHub to manage reviews of pull requests. 4 | 5 | * If you have a trivial fix or improvement, go ahead and create a pull 6 | request, addressing (with `@...`) one or more of the maintainers 7 | (see [AUTHORS.md](AUTHORS.md)) in the description of the pull request. 8 | 9 | * If you plan to do something more involved, first discuss your ideas 10 | on our [mailing list](https://groups.google.com/forum/?fromgroups#!forum/prometheus-developers). 11 | This will avoid unnecessary work and surely give you and us a good deal 12 | of inspiration. 13 | 14 | * Relevant coding style guidelines are the [Go Code Review 15 | Comments](https://code.google.com/p/go-wiki/wiki/CodeReviewComments) 16 | and the _Formatting and style_ section of Peter Bourgon's [Go: Best 17 | Practices for Production 18 | Environments](http://peter.bourgon.org/go-in-production/#formatting-and-style). 19 | -------------------------------------------------------------------------------- /vendor/github.com/prometheus/procfs/Makefile: -------------------------------------------------------------------------------- 1 | ci: 2 | ! gofmt -l *.go | read nothing 3 | go vet 4 | go test -v ./... 5 | go get github.com/golang/lint/golint 6 | golint *.go 7 | -------------------------------------------------------------------------------- /vendor/github.com/prometheus/procfs/NOTICE: -------------------------------------------------------------------------------- 1 | procfs provides functions to retrieve system, kernel and process 2 | metrics from the pseudo-filesystem proc. 3 | 4 | Copyright 2014-2015 The Prometheus Authors 5 | 6 | This product includes software developed at 7 | SoundCloud Ltd. (http://soundcloud.com/). 8 | -------------------------------------------------------------------------------- /vendor/github.com/prometheus/procfs/README.md: -------------------------------------------------------------------------------- 1 | # procfs 2 | 3 | This procfs package provides functions to retrieve system, kernel and process 4 | metrics from the pseudo-filesystem proc. 5 | 6 | *WARNING*: This package is a work in progress. Its API may still break in 7 | backwards-incompatible ways without warnings. Use it at your own risk. 8 | 9 | [![GoDoc](https://godoc.org/github.com/prometheus/procfs?status.png)](https://godoc.org/github.com/prometheus/procfs) 10 | [![Build Status](https://travis-ci.org/prometheus/procfs.svg?branch=master)](https://travis-ci.org/prometheus/procfs) 11 | -------------------------------------------------------------------------------- /vendor/github.com/prometheus/procfs/doc.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Prometheus Team 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 | 14 | // Package procfs provides functions to retrieve system, kernel and process 15 | // metrics from the pseudo-filesystem proc. 16 | // 17 | // Example: 18 | // 19 | // package main 20 | // 21 | // import ( 22 | // "fmt" 23 | // "log" 24 | // 25 | // "github.com/prometheus/procfs" 26 | // ) 27 | // 28 | // func main() { 29 | // p, err := procfs.Self() 30 | // if err != nil { 31 | // log.Fatalf("could not get process: %s", err) 32 | // } 33 | // 34 | // stat, err := p.NewStat() 35 | // if err != nil { 36 | // log.Fatalf("could not get process stat: %s", err) 37 | // } 38 | // 39 | // fmt.Printf("command: %s\n", stat.Comm) 40 | // fmt.Printf("cpu time: %fs\n", stat.CPUTime()) 41 | // fmt.Printf("vsize: %dB\n", stat.VirtualMemory()) 42 | // fmt.Printf("rss: %dB\n", stat.ResidentMemory()) 43 | // } 44 | // 45 | package procfs 46 | -------------------------------------------------------------------------------- /vendor/github.com/prometheus/procfs/fs.go: -------------------------------------------------------------------------------- 1 | package procfs 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "path" 7 | ) 8 | 9 | // FS represents the pseudo-filesystem proc, which provides an interface to 10 | // kernel data structures. 11 | type FS string 12 | 13 | // DefaultMountPoint is the common mount point of the proc filesystem. 14 | const DefaultMountPoint = "/proc" 15 | 16 | // NewFS returns a new FS mounted under the given mountPoint. It will error 17 | // if the mount point can't be read. 18 | func NewFS(mountPoint string) (FS, error) { 19 | info, err := os.Stat(mountPoint) 20 | if err != nil { 21 | return "", fmt.Errorf("could not read %s: %s", mountPoint, err) 22 | } 23 | if !info.IsDir() { 24 | return "", fmt.Errorf("mount point %s is not a directory", mountPoint) 25 | } 26 | 27 | return FS(mountPoint), nil 28 | } 29 | 30 | // Path returns the path of the given subsystem relative to the procfs root. 31 | func (fs FS) Path(p ...string) string { 32 | return path.Join(append([]string{string(fs)}, p...)...) 33 | } 34 | -------------------------------------------------------------------------------- /vendor/github.com/prometheus/procfs/ipvs.go: -------------------------------------------------------------------------------- 1 | package procfs 2 | 3 | import ( 4 | "bufio" 5 | "encoding/hex" 6 | "errors" 7 | "fmt" 8 | "io" 9 | "io/ioutil" 10 | "net" 11 | "os" 12 | "strconv" 13 | "strings" 14 | ) 15 | 16 | // IPVSStats holds IPVS statistics, as exposed by the kernel in `/proc/net/ip_vs_stats`. 17 | type IPVSStats struct { 18 | // Total count of connections. 19 | Connections uint64 20 | // Total incoming packages processed. 21 | IncomingPackets uint64 22 | // Total outgoing packages processed. 23 | OutgoingPackets uint64 24 | // Total incoming traffic. 25 | IncomingBytes uint64 26 | // Total outgoing traffic. 27 | OutgoingBytes uint64 28 | } 29 | 30 | // IPVSBackendStatus holds current metrics of one virtual / real address pair. 31 | type IPVSBackendStatus struct { 32 | // The local (virtual) IP address. 33 | LocalAddress net.IP 34 | // The local (virtual) port. 35 | LocalPort uint16 36 | // The transport protocol (TCP, UDP). 37 | Proto string 38 | // The remote (real) IP address. 39 | RemoteAddress net.IP 40 | // The remote (real) port. 41 | RemotePort uint16 42 | // The current number of active connections for this virtual/real address pair. 43 | ActiveConn uint64 44 | // The current number of inactive connections for this virtual/real address pair. 45 | InactConn uint64 46 | // The current weight of this virtual/real address pair. 47 | Weight uint64 48 | } 49 | 50 | // NewIPVSStats reads the IPVS statistics. 51 | func NewIPVSStats() (IPVSStats, error) { 52 | fs, err := NewFS(DefaultMountPoint) 53 | if err != nil { 54 | return IPVSStats{}, err 55 | } 56 | 57 | return fs.NewIPVSStats() 58 | } 59 | 60 | // NewIPVSStats reads the IPVS statistics from the specified `proc` filesystem. 61 | func (fs FS) NewIPVSStats() (IPVSStats, error) { 62 | file, err := os.Open(fs.Path("net/ip_vs_stats")) 63 | if err != nil { 64 | return IPVSStats{}, err 65 | } 66 | defer file.Close() 67 | 68 | return parseIPVSStats(file) 69 | } 70 | 71 | // parseIPVSStats performs the actual parsing of `ip_vs_stats`. 72 | func parseIPVSStats(file io.Reader) (IPVSStats, error) { 73 | var ( 74 | statContent []byte 75 | statLines []string 76 | statFields []string 77 | stats IPVSStats 78 | ) 79 | 80 | statContent, err := ioutil.ReadAll(file) 81 | if err != nil { 82 | return IPVSStats{}, err 83 | } 84 | 85 | statLines = strings.SplitN(string(statContent), "\n", 4) 86 | if len(statLines) != 4 { 87 | return IPVSStats{}, errors.New("ip_vs_stats corrupt: too short") 88 | } 89 | 90 | statFields = strings.Fields(statLines[2]) 91 | if len(statFields) != 5 { 92 | return IPVSStats{}, errors.New("ip_vs_stats corrupt: unexpected number of fields") 93 | } 94 | 95 | stats.Connections, err = strconv.ParseUint(statFields[0], 16, 64) 96 | if err != nil { 97 | return IPVSStats{}, err 98 | } 99 | stats.IncomingPackets, err = strconv.ParseUint(statFields[1], 16, 64) 100 | if err != nil { 101 | return IPVSStats{}, err 102 | } 103 | stats.OutgoingPackets, err = strconv.ParseUint(statFields[2], 16, 64) 104 | if err != nil { 105 | return IPVSStats{}, err 106 | } 107 | stats.IncomingBytes, err = strconv.ParseUint(statFields[3], 16, 64) 108 | if err != nil { 109 | return IPVSStats{}, err 110 | } 111 | stats.OutgoingBytes, err = strconv.ParseUint(statFields[4], 16, 64) 112 | if err != nil { 113 | return IPVSStats{}, err 114 | } 115 | 116 | return stats, nil 117 | } 118 | 119 | // NewIPVSBackendStatus reads and returns the status of all (virtual,real) server pairs. 120 | func NewIPVSBackendStatus() ([]IPVSBackendStatus, error) { 121 | fs, err := NewFS(DefaultMountPoint) 122 | if err != nil { 123 | return []IPVSBackendStatus{}, err 124 | } 125 | 126 | return fs.NewIPVSBackendStatus() 127 | } 128 | 129 | // NewIPVSBackendStatus reads and returns the status of all (virtual,real) server pairs from the specified `proc` filesystem. 130 | func (fs FS) NewIPVSBackendStatus() ([]IPVSBackendStatus, error) { 131 | file, err := os.Open(fs.Path("net/ip_vs")) 132 | if err != nil { 133 | return nil, err 134 | } 135 | defer file.Close() 136 | 137 | return parseIPVSBackendStatus(file) 138 | } 139 | 140 | func parseIPVSBackendStatus(file io.Reader) ([]IPVSBackendStatus, error) { 141 | var ( 142 | status []IPVSBackendStatus 143 | scanner = bufio.NewScanner(file) 144 | proto string 145 | localAddress net.IP 146 | localPort uint16 147 | err error 148 | ) 149 | 150 | for scanner.Scan() { 151 | fields := strings.Fields(string(scanner.Text())) 152 | if len(fields) == 0 { 153 | continue 154 | } 155 | switch { 156 | case fields[0] == "IP" || fields[0] == "Prot" || fields[1] == "RemoteAddress:Port": 157 | continue 158 | case fields[0] == "TCP" || fields[0] == "UDP": 159 | if len(fields) < 2 { 160 | continue 161 | } 162 | proto = fields[0] 163 | localAddress, localPort, err = parseIPPort(fields[1]) 164 | if err != nil { 165 | return nil, err 166 | } 167 | case fields[0] == "->": 168 | if len(fields) < 6 { 169 | continue 170 | } 171 | remoteAddress, remotePort, err := parseIPPort(fields[1]) 172 | if err != nil { 173 | return nil, err 174 | } 175 | weight, err := strconv.ParseUint(fields[3], 10, 64) 176 | if err != nil { 177 | return nil, err 178 | } 179 | activeConn, err := strconv.ParseUint(fields[4], 10, 64) 180 | if err != nil { 181 | return nil, err 182 | } 183 | inactConn, err := strconv.ParseUint(fields[5], 10, 64) 184 | if err != nil { 185 | return nil, err 186 | } 187 | status = append(status, IPVSBackendStatus{ 188 | LocalAddress: localAddress, 189 | LocalPort: localPort, 190 | RemoteAddress: remoteAddress, 191 | RemotePort: remotePort, 192 | Proto: proto, 193 | Weight: weight, 194 | ActiveConn: activeConn, 195 | InactConn: inactConn, 196 | }) 197 | } 198 | } 199 | return status, nil 200 | } 201 | 202 | func parseIPPort(s string) (net.IP, uint16, error) { 203 | tmp := strings.SplitN(s, ":", 2) 204 | 205 | if len(tmp) != 2 { 206 | return nil, 0, fmt.Errorf("invalid IP:Port: %s", s) 207 | } 208 | 209 | if len(tmp[0]) != 8 && len(tmp[0]) != 32 { 210 | return nil, 0, fmt.Errorf("invalid IP: %s", tmp[0]) 211 | } 212 | 213 | ip, err := hex.DecodeString(tmp[0]) 214 | if err != nil { 215 | return nil, 0, err 216 | } 217 | 218 | port, err := strconv.ParseUint(tmp[1], 16, 16) 219 | if err != nil { 220 | return nil, 0, err 221 | } 222 | 223 | return ip, uint16(port), nil 224 | } 225 | -------------------------------------------------------------------------------- /vendor/github.com/prometheus/procfs/mdstat.go: -------------------------------------------------------------------------------- 1 | package procfs 2 | 3 | import ( 4 | "fmt" 5 | "io/ioutil" 6 | "regexp" 7 | "strconv" 8 | "strings" 9 | ) 10 | 11 | var ( 12 | statuslineRE = regexp.MustCompile(`(\d+) blocks .*\[(\d+)/(\d+)\] \[[U_]+\]`) 13 | buildlineRE = regexp.MustCompile(`\((\d+)/\d+\)`) 14 | ) 15 | 16 | // MDStat holds info parsed from /proc/mdstat. 17 | type MDStat struct { 18 | // Name of the device. 19 | Name string 20 | // activity-state of the device. 21 | ActivityState string 22 | // Number of active disks. 23 | DisksActive int64 24 | // Total number of disks the device consists of. 25 | DisksTotal int64 26 | // Number of blocks the device holds. 27 | BlocksTotal int64 28 | // Number of blocks on the device that are in sync. 29 | BlocksSynced int64 30 | } 31 | 32 | // ParseMDStat parses an mdstat-file and returns a struct with the relevant infos. 33 | func (fs FS) ParseMDStat() (mdstates []MDStat, err error) { 34 | mdStatusFilePath := fs.Path("mdstat") 35 | content, err := ioutil.ReadFile(mdStatusFilePath) 36 | if err != nil { 37 | return []MDStat{}, fmt.Errorf("error parsing %s: %s", mdStatusFilePath, err) 38 | } 39 | 40 | mdStates := []MDStat{} 41 | lines := strings.Split(string(content), "\n") 42 | for i, l := range lines { 43 | if l == "" { 44 | continue 45 | } 46 | if l[0] == ' ' { 47 | continue 48 | } 49 | if strings.HasPrefix(l, "Personalities") || strings.HasPrefix(l, "unused") { 50 | continue 51 | } 52 | 53 | mainLine := strings.Split(l, " ") 54 | if len(mainLine) < 3 { 55 | return mdStates, fmt.Errorf("error parsing mdline: %s", l) 56 | } 57 | mdName := mainLine[0] 58 | activityState := mainLine[2] 59 | 60 | if len(lines) <= i+3 { 61 | return mdStates, fmt.Errorf( 62 | "error parsing %s: too few lines for md device %s", 63 | mdStatusFilePath, 64 | mdName, 65 | ) 66 | } 67 | 68 | active, total, size, err := evalStatusline(lines[i+1]) 69 | if err != nil { 70 | return mdStates, fmt.Errorf("error parsing %s: %s", mdStatusFilePath, err) 71 | } 72 | 73 | // j is the line number of the syncing-line. 74 | j := i + 2 75 | if strings.Contains(lines[i+2], "bitmap") { // skip bitmap line 76 | j = i + 3 77 | } 78 | 79 | // If device is syncing at the moment, get the number of currently 80 | // synced bytes, otherwise that number equals the size of the device. 81 | syncedBlocks := size 82 | if strings.Contains(lines[j], "recovery") || strings.Contains(lines[j], "resync") { 83 | syncedBlocks, err = evalBuildline(lines[j]) 84 | if err != nil { 85 | return mdStates, fmt.Errorf("error parsing %s: %s", mdStatusFilePath, err) 86 | } 87 | } 88 | 89 | mdStates = append(mdStates, MDStat{ 90 | Name: mdName, 91 | ActivityState: activityState, 92 | DisksActive: active, 93 | DisksTotal: total, 94 | BlocksTotal: size, 95 | BlocksSynced: syncedBlocks, 96 | }) 97 | } 98 | 99 | return mdStates, nil 100 | } 101 | 102 | func evalStatusline(statusline string) (active, total, size int64, err error) { 103 | matches := statuslineRE.FindStringSubmatch(statusline) 104 | if len(matches) != 4 { 105 | return 0, 0, 0, fmt.Errorf("unexpected statusline: %s", statusline) 106 | } 107 | 108 | size, err = strconv.ParseInt(matches[1], 10, 64) 109 | if err != nil { 110 | return 0, 0, 0, fmt.Errorf("unexpected statusline %s: %s", statusline, err) 111 | } 112 | 113 | total, err = strconv.ParseInt(matches[2], 10, 64) 114 | if err != nil { 115 | return 0, 0, 0, fmt.Errorf("unexpected statusline %s: %s", statusline, err) 116 | } 117 | 118 | active, err = strconv.ParseInt(matches[3], 10, 64) 119 | if err != nil { 120 | return 0, 0, 0, fmt.Errorf("unexpected statusline %s: %s", statusline, err) 121 | } 122 | 123 | return active, total, size, nil 124 | } 125 | 126 | func evalBuildline(buildline string) (syncedBlocks int64, err error) { 127 | matches := buildlineRE.FindStringSubmatch(buildline) 128 | if len(matches) != 2 { 129 | return 0, fmt.Errorf("unexpected buildline: %s", buildline) 130 | } 131 | 132 | syncedBlocks, err = strconv.ParseInt(matches[1], 10, 64) 133 | if err != nil { 134 | return 0, fmt.Errorf("%s in buildline: %s", err, buildline) 135 | } 136 | 137 | return syncedBlocks, nil 138 | } 139 | -------------------------------------------------------------------------------- /vendor/github.com/prometheus/procfs/proc.go: -------------------------------------------------------------------------------- 1 | package procfs 2 | 3 | import ( 4 | "fmt" 5 | "io/ioutil" 6 | "os" 7 | "strconv" 8 | "strings" 9 | ) 10 | 11 | // Proc provides information about a running process. 12 | type Proc struct { 13 | // The process ID. 14 | PID int 15 | 16 | fs FS 17 | } 18 | 19 | // Procs represents a list of Proc structs. 20 | type Procs []Proc 21 | 22 | func (p Procs) Len() int { return len(p) } 23 | func (p Procs) Swap(i, j int) { p[i], p[j] = p[j], p[i] } 24 | func (p Procs) Less(i, j int) bool { return p[i].PID < p[j].PID } 25 | 26 | // Self returns a process for the current process read via /proc/self. 27 | func Self() (Proc, error) { 28 | fs, err := NewFS(DefaultMountPoint) 29 | if err != nil { 30 | return Proc{}, err 31 | } 32 | return fs.Self() 33 | } 34 | 35 | // NewProc returns a process for the given pid under /proc. 36 | func NewProc(pid int) (Proc, error) { 37 | fs, err := NewFS(DefaultMountPoint) 38 | if err != nil { 39 | return Proc{}, err 40 | } 41 | return fs.NewProc(pid) 42 | } 43 | 44 | // AllProcs returns a list of all currently available processes under /proc. 45 | func AllProcs() (Procs, error) { 46 | fs, err := NewFS(DefaultMountPoint) 47 | if err != nil { 48 | return Procs{}, err 49 | } 50 | return fs.AllProcs() 51 | } 52 | 53 | // Self returns a process for the current process. 54 | func (fs FS) Self() (Proc, error) { 55 | p, err := os.Readlink(fs.Path("self")) 56 | if err != nil { 57 | return Proc{}, err 58 | } 59 | pid, err := strconv.Atoi(strings.Replace(p, string(fs), "", -1)) 60 | if err != nil { 61 | return Proc{}, err 62 | } 63 | return fs.NewProc(pid) 64 | } 65 | 66 | // NewProc returns a process for the given pid. 67 | func (fs FS) NewProc(pid int) (Proc, error) { 68 | if _, err := os.Stat(fs.Path(strconv.Itoa(pid))); err != nil { 69 | return Proc{}, err 70 | } 71 | return Proc{PID: pid, fs: fs}, nil 72 | } 73 | 74 | // AllProcs returns a list of all currently available processes. 75 | func (fs FS) AllProcs() (Procs, error) { 76 | d, err := os.Open(fs.Path()) 77 | if err != nil { 78 | return Procs{}, err 79 | } 80 | defer d.Close() 81 | 82 | names, err := d.Readdirnames(-1) 83 | if err != nil { 84 | return Procs{}, fmt.Errorf("could not read %s: %s", d.Name(), err) 85 | } 86 | 87 | p := Procs{} 88 | for _, n := range names { 89 | pid, err := strconv.ParseInt(n, 10, 64) 90 | if err != nil { 91 | continue 92 | } 93 | p = append(p, Proc{PID: int(pid), fs: fs}) 94 | } 95 | 96 | return p, nil 97 | } 98 | 99 | // CmdLine returns the command line of a process. 100 | func (p Proc) CmdLine() ([]string, error) { 101 | f, err := os.Open(p.path("cmdline")) 102 | if err != nil { 103 | return nil, err 104 | } 105 | defer f.Close() 106 | 107 | data, err := ioutil.ReadAll(f) 108 | if err != nil { 109 | return nil, err 110 | } 111 | 112 | if len(data) < 1 { 113 | return []string{}, nil 114 | } 115 | 116 | return strings.Split(string(data[:len(data)-1]), string(byte(0))), nil 117 | } 118 | 119 | // Comm returns the command name of a process. 120 | func (p Proc) Comm() (string, error) { 121 | f, err := os.Open(p.path("comm")) 122 | if err != nil { 123 | return "", err 124 | } 125 | defer f.Close() 126 | 127 | data, err := ioutil.ReadAll(f) 128 | if err != nil { 129 | return "", err 130 | } 131 | 132 | return strings.TrimSpace(string(data)), nil 133 | } 134 | 135 | // Executable returns the absolute path of the executable command of a process. 136 | func (p Proc) Executable() (string, error) { 137 | exe, err := os.Readlink(p.path("exe")) 138 | if os.IsNotExist(err) { 139 | return "", nil 140 | } 141 | 142 | return exe, err 143 | } 144 | 145 | // FileDescriptors returns the currently open file descriptors of a process. 146 | func (p Proc) FileDescriptors() ([]uintptr, error) { 147 | names, err := p.fileDescriptors() 148 | if err != nil { 149 | return nil, err 150 | } 151 | 152 | fds := make([]uintptr, len(names)) 153 | for i, n := range names { 154 | fd, err := strconv.ParseInt(n, 10, 32) 155 | if err != nil { 156 | return nil, fmt.Errorf("could not parse fd %s: %s", n, err) 157 | } 158 | fds[i] = uintptr(fd) 159 | } 160 | 161 | return fds, nil 162 | } 163 | 164 | // FileDescriptorTargets returns the targets of all file descriptors of a process. 165 | // If a file descriptor is not a symlink to a file (like a socket), that value will be the empty string. 166 | func (p Proc) FileDescriptorTargets() ([]string, error) { 167 | names, err := p.fileDescriptors() 168 | if err != nil { 169 | return nil, err 170 | } 171 | 172 | targets := make([]string, len(names)) 173 | 174 | for i, name := range names { 175 | target, err := os.Readlink(p.path("fd", name)) 176 | if err == nil { 177 | targets[i] = target 178 | } 179 | } 180 | 181 | return targets, nil 182 | } 183 | 184 | // FileDescriptorsLen returns the number of currently open file descriptors of 185 | // a process. 186 | func (p Proc) FileDescriptorsLen() (int, error) { 187 | fds, err := p.fileDescriptors() 188 | if err != nil { 189 | return 0, err 190 | } 191 | 192 | return len(fds), nil 193 | } 194 | 195 | // MountStats retrieves statistics and configuration for mount points in a 196 | // process's namespace. 197 | func (p Proc) MountStats() ([]*Mount, error) { 198 | f, err := os.Open(p.path("mountstats")) 199 | if err != nil { 200 | return nil, err 201 | } 202 | defer f.Close() 203 | 204 | return parseMountStats(f) 205 | } 206 | 207 | func (p Proc) fileDescriptors() ([]string, error) { 208 | d, err := os.Open(p.path("fd")) 209 | if err != nil { 210 | return nil, err 211 | } 212 | defer d.Close() 213 | 214 | names, err := d.Readdirnames(-1) 215 | if err != nil { 216 | return nil, fmt.Errorf("could not read %s: %s", d.Name(), err) 217 | } 218 | 219 | return names, nil 220 | } 221 | 222 | func (p Proc) path(pa ...string) string { 223 | return p.fs.Path(append([]string{strconv.Itoa(p.PID)}, pa...)...) 224 | } 225 | -------------------------------------------------------------------------------- /vendor/github.com/prometheus/procfs/proc_io.go: -------------------------------------------------------------------------------- 1 | package procfs 2 | 3 | import ( 4 | "fmt" 5 | "io/ioutil" 6 | "os" 7 | ) 8 | 9 | // ProcIO models the content of /proc//io. 10 | type ProcIO struct { 11 | // Chars read. 12 | RChar uint64 13 | // Chars written. 14 | WChar uint64 15 | // Read syscalls. 16 | SyscR uint64 17 | // Write syscalls. 18 | SyscW uint64 19 | // Bytes read. 20 | ReadBytes uint64 21 | // Bytes written. 22 | WriteBytes uint64 23 | // Bytes written, but taking into account truncation. See 24 | // Documentation/filesystems/proc.txt in the kernel sources for 25 | // detailed explanation. 26 | CancelledWriteBytes int64 27 | } 28 | 29 | // NewIO creates a new ProcIO instance from a given Proc instance. 30 | func (p Proc) NewIO() (ProcIO, error) { 31 | pio := ProcIO{} 32 | 33 | f, err := os.Open(p.path("io")) 34 | if err != nil { 35 | return pio, err 36 | } 37 | defer f.Close() 38 | 39 | data, err := ioutil.ReadAll(f) 40 | if err != nil { 41 | return pio, err 42 | } 43 | 44 | ioFormat := "rchar: %d\nwchar: %d\nsyscr: %d\nsyscw: %d\n" + 45 | "read_bytes: %d\nwrite_bytes: %d\n" + 46 | "cancelled_write_bytes: %d\n" 47 | 48 | _, err = fmt.Sscanf(string(data), ioFormat, &pio.RChar, &pio.WChar, &pio.SyscR, 49 | &pio.SyscW, &pio.ReadBytes, &pio.WriteBytes, &pio.CancelledWriteBytes) 50 | if err != nil { 51 | return pio, err 52 | } 53 | 54 | return pio, nil 55 | } 56 | -------------------------------------------------------------------------------- /vendor/github.com/prometheus/procfs/proc_limits.go: -------------------------------------------------------------------------------- 1 | package procfs 2 | 3 | import ( 4 | "bufio" 5 | "fmt" 6 | "os" 7 | "regexp" 8 | "strconv" 9 | ) 10 | 11 | // ProcLimits represents the soft limits for each of the process's resource 12 | // limits. For more information see getrlimit(2): 13 | // http://man7.org/linux/man-pages/man2/getrlimit.2.html. 14 | type ProcLimits struct { 15 | // CPU time limit in seconds. 16 | CPUTime int 17 | // Maximum size of files that the process may create. 18 | FileSize int 19 | // Maximum size of the process's data segment (initialized data, 20 | // uninitialized data, and heap). 21 | DataSize int 22 | // Maximum size of the process stack in bytes. 23 | StackSize int 24 | // Maximum size of a core file. 25 | CoreFileSize int 26 | // Limit of the process's resident set in pages. 27 | ResidentSet int 28 | // Maximum number of processes that can be created for the real user ID of 29 | // the calling process. 30 | Processes int 31 | // Value one greater than the maximum file descriptor number that can be 32 | // opened by this process. 33 | OpenFiles int 34 | // Maximum number of bytes of memory that may be locked into RAM. 35 | LockedMemory int 36 | // Maximum size of the process's virtual memory address space in bytes. 37 | AddressSpace int 38 | // Limit on the combined number of flock(2) locks and fcntl(2) leases that 39 | // this process may establish. 40 | FileLocks int 41 | // Limit of signals that may be queued for the real user ID of the calling 42 | // process. 43 | PendingSignals int 44 | // Limit on the number of bytes that can be allocated for POSIX message 45 | // queues for the real user ID of the calling process. 46 | MsqqueueSize int 47 | // Limit of the nice priority set using setpriority(2) or nice(2). 48 | NicePriority int 49 | // Limit of the real-time priority set using sched_setscheduler(2) or 50 | // sched_setparam(2). 51 | RealtimePriority int 52 | // Limit (in microseconds) on the amount of CPU time that a process 53 | // scheduled under a real-time scheduling policy may consume without making 54 | // a blocking system call. 55 | RealtimeTimeout int 56 | } 57 | 58 | const ( 59 | limitsFields = 3 60 | limitsUnlimited = "unlimited" 61 | ) 62 | 63 | var ( 64 | limitsDelimiter = regexp.MustCompile(" +") 65 | ) 66 | 67 | // NewLimits returns the current soft limits of the process. 68 | func (p Proc) NewLimits() (ProcLimits, error) { 69 | f, err := os.Open(p.path("limits")) 70 | if err != nil { 71 | return ProcLimits{}, err 72 | } 73 | defer f.Close() 74 | 75 | var ( 76 | l = ProcLimits{} 77 | s = bufio.NewScanner(f) 78 | ) 79 | for s.Scan() { 80 | fields := limitsDelimiter.Split(s.Text(), limitsFields) 81 | if len(fields) != limitsFields { 82 | return ProcLimits{}, fmt.Errorf( 83 | "couldn't parse %s line %s", f.Name(), s.Text()) 84 | } 85 | 86 | switch fields[0] { 87 | case "Max cpu time": 88 | l.CPUTime, err = parseInt(fields[1]) 89 | case "Max file size": 90 | l.FileSize, err = parseInt(fields[1]) 91 | case "Max data size": 92 | l.DataSize, err = parseInt(fields[1]) 93 | case "Max stack size": 94 | l.StackSize, err = parseInt(fields[1]) 95 | case "Max core file size": 96 | l.CoreFileSize, err = parseInt(fields[1]) 97 | case "Max resident set": 98 | l.ResidentSet, err = parseInt(fields[1]) 99 | case "Max processes": 100 | l.Processes, err = parseInt(fields[1]) 101 | case "Max open files": 102 | l.OpenFiles, err = parseInt(fields[1]) 103 | case "Max locked memory": 104 | l.LockedMemory, err = parseInt(fields[1]) 105 | case "Max address space": 106 | l.AddressSpace, err = parseInt(fields[1]) 107 | case "Max file locks": 108 | l.FileLocks, err = parseInt(fields[1]) 109 | case "Max pending signals": 110 | l.PendingSignals, err = parseInt(fields[1]) 111 | case "Max msgqueue size": 112 | l.MsqqueueSize, err = parseInt(fields[1]) 113 | case "Max nice priority": 114 | l.NicePriority, err = parseInt(fields[1]) 115 | case "Max realtime priority": 116 | l.RealtimePriority, err = parseInt(fields[1]) 117 | case "Max realtime timeout": 118 | l.RealtimeTimeout, err = parseInt(fields[1]) 119 | } 120 | if err != nil { 121 | return ProcLimits{}, err 122 | } 123 | } 124 | 125 | return l, s.Err() 126 | } 127 | 128 | func parseInt(s string) (int, error) { 129 | if s == limitsUnlimited { 130 | return -1, nil 131 | } 132 | i, err := strconv.ParseInt(s, 10, 32) 133 | if err != nil { 134 | return 0, fmt.Errorf("couldn't parse value %s: %s", s, err) 135 | } 136 | return int(i), nil 137 | } 138 | -------------------------------------------------------------------------------- /vendor/github.com/prometheus/procfs/proc_stat.go: -------------------------------------------------------------------------------- 1 | package procfs 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "io/ioutil" 7 | "os" 8 | ) 9 | 10 | // Originally, this USER_HZ value was dynamically retrieved via a sysconf call 11 | // which required cgo. However, that caused a lot of problems regarding 12 | // cross-compilation. Alternatives such as running a binary to determine the 13 | // value, or trying to derive it in some other way were all problematic. After 14 | // much research it was determined that USER_HZ is actually hardcoded to 100 on 15 | // all Go-supported platforms as of the time of this writing. This is why we 16 | // decided to hardcode it here as well. It is not impossible that there could 17 | // be systems with exceptions, but they should be very exotic edge cases, and 18 | // in that case, the worst outcome will be two misreported metrics. 19 | // 20 | // See also the following discussions: 21 | // 22 | // - https://github.com/prometheus/node_exporter/issues/52 23 | // - https://github.com/prometheus/procfs/pull/2 24 | // - http://stackoverflow.com/questions/17410841/how-does-user-hz-solve-the-jiffy-scaling-issue 25 | const userHZ = 100 26 | 27 | // ProcStat provides status information about the process, 28 | // read from /proc/[pid]/stat. 29 | type ProcStat struct { 30 | // The process ID. 31 | PID int 32 | // The filename of the executable. 33 | Comm string 34 | // The process state. 35 | State string 36 | // The PID of the parent of this process. 37 | PPID int 38 | // The process group ID of the process. 39 | PGRP int 40 | // The session ID of the process. 41 | Session int 42 | // The controlling terminal of the process. 43 | TTY int 44 | // The ID of the foreground process group of the controlling terminal of 45 | // the process. 46 | TPGID int 47 | // The kernel flags word of the process. 48 | Flags uint 49 | // The number of minor faults the process has made which have not required 50 | // loading a memory page from disk. 51 | MinFlt uint 52 | // The number of minor faults that the process's waited-for children have 53 | // made. 54 | CMinFlt uint 55 | // The number of major faults the process has made which have required 56 | // loading a memory page from disk. 57 | MajFlt uint 58 | // The number of major faults that the process's waited-for children have 59 | // made. 60 | CMajFlt uint 61 | // Amount of time that this process has been scheduled in user mode, 62 | // measured in clock ticks. 63 | UTime uint 64 | // Amount of time that this process has been scheduled in kernel mode, 65 | // measured in clock ticks. 66 | STime uint 67 | // Amount of time that this process's waited-for children have been 68 | // scheduled in user mode, measured in clock ticks. 69 | CUTime uint 70 | // Amount of time that this process's waited-for children have been 71 | // scheduled in kernel mode, measured in clock ticks. 72 | CSTime uint 73 | // For processes running a real-time scheduling policy, this is the negated 74 | // scheduling priority, minus one. 75 | Priority int 76 | // The nice value, a value in the range 19 (low priority) to -20 (high 77 | // priority). 78 | Nice int 79 | // Number of threads in this process. 80 | NumThreads int 81 | // The time the process started after system boot, the value is expressed 82 | // in clock ticks. 83 | Starttime uint64 84 | // Virtual memory size in bytes. 85 | VSize int 86 | // Resident set size in pages. 87 | RSS int 88 | 89 | fs FS 90 | } 91 | 92 | // NewStat returns the current status information of the process. 93 | func (p Proc) NewStat() (ProcStat, error) { 94 | f, err := os.Open(p.path("stat")) 95 | if err != nil { 96 | return ProcStat{}, err 97 | } 98 | defer f.Close() 99 | 100 | data, err := ioutil.ReadAll(f) 101 | if err != nil { 102 | return ProcStat{}, err 103 | } 104 | 105 | var ( 106 | ignore int 107 | 108 | s = ProcStat{PID: p.PID, fs: p.fs} 109 | l = bytes.Index(data, []byte("(")) 110 | r = bytes.LastIndex(data, []byte(")")) 111 | ) 112 | 113 | if l < 0 || r < 0 { 114 | return ProcStat{}, fmt.Errorf( 115 | "unexpected format, couldn't extract comm: %s", 116 | data, 117 | ) 118 | } 119 | 120 | s.Comm = string(data[l+1 : r]) 121 | _, err = fmt.Fscan( 122 | bytes.NewBuffer(data[r+2:]), 123 | &s.State, 124 | &s.PPID, 125 | &s.PGRP, 126 | &s.Session, 127 | &s.TTY, 128 | &s.TPGID, 129 | &s.Flags, 130 | &s.MinFlt, 131 | &s.CMinFlt, 132 | &s.MajFlt, 133 | &s.CMajFlt, 134 | &s.UTime, 135 | &s.STime, 136 | &s.CUTime, 137 | &s.CSTime, 138 | &s.Priority, 139 | &s.Nice, 140 | &s.NumThreads, 141 | &ignore, 142 | &s.Starttime, 143 | &s.VSize, 144 | &s.RSS, 145 | ) 146 | if err != nil { 147 | return ProcStat{}, err 148 | } 149 | 150 | return s, nil 151 | } 152 | 153 | // VirtualMemory returns the virtual memory size in bytes. 154 | func (s ProcStat) VirtualMemory() int { 155 | return s.VSize 156 | } 157 | 158 | // ResidentMemory returns the resident memory size in bytes. 159 | func (s ProcStat) ResidentMemory() int { 160 | return s.RSS * os.Getpagesize() 161 | } 162 | 163 | // StartTime returns the unix timestamp of the process in seconds. 164 | func (s ProcStat) StartTime() (float64, error) { 165 | stat, err := s.fs.NewStat() 166 | if err != nil { 167 | return 0, err 168 | } 169 | return float64(stat.BootTime) + (float64(s.Starttime) / userHZ), nil 170 | } 171 | 172 | // CPUTime returns the total CPU user and system time in seconds. 173 | func (s ProcStat) CPUTime() float64 { 174 | return float64(s.UTime+s.STime) / userHZ 175 | } 176 | -------------------------------------------------------------------------------- /vendor/github.com/prometheus/procfs/stat.go: -------------------------------------------------------------------------------- 1 | package procfs 2 | 3 | import ( 4 | "bufio" 5 | "fmt" 6 | "os" 7 | "strconv" 8 | "strings" 9 | ) 10 | 11 | // Stat represents kernel/system statistics. 12 | type Stat struct { 13 | // Boot time in seconds since the Epoch. 14 | BootTime int64 15 | } 16 | 17 | // NewStat returns kernel/system statistics read from /proc/stat. 18 | func NewStat() (Stat, error) { 19 | fs, err := NewFS(DefaultMountPoint) 20 | if err != nil { 21 | return Stat{}, err 22 | } 23 | 24 | return fs.NewStat() 25 | } 26 | 27 | // NewStat returns an information about current kernel/system statistics. 28 | func (fs FS) NewStat() (Stat, error) { 29 | f, err := os.Open(fs.Path("stat")) 30 | if err != nil { 31 | return Stat{}, err 32 | } 33 | defer f.Close() 34 | 35 | s := bufio.NewScanner(f) 36 | for s.Scan() { 37 | line := s.Text() 38 | if !strings.HasPrefix(line, "btime") { 39 | continue 40 | } 41 | fields := strings.Fields(line) 42 | if len(fields) != 2 { 43 | return Stat{}, fmt.Errorf("couldn't parse %s line %s", f.Name(), line) 44 | } 45 | i, err := strconv.ParseInt(fields[1], 10, 32) 46 | if err != nil { 47 | return Stat{}, fmt.Errorf("couldn't parse %s: %s", fields[1], err) 48 | } 49 | return Stat{BootTime: i}, nil 50 | } 51 | if err := s.Err(); err != nil { 52 | return Stat{}, fmt.Errorf("couldn't parse %s: %s", f.Name(), err) 53 | } 54 | 55 | return Stat{}, fmt.Errorf("couldn't parse %s, missing btime", f.Name()) 56 | } 57 | -------------------------------------------------------------------------------- /vendor/modules.txt: -------------------------------------------------------------------------------- 1 | # github.com/beorn7/perks v0.0.0-20160804104726-4c0e84591b9a 2 | ## explicit 3 | github.com/beorn7/perks/quantile 4 | # github.com/golang/protobuf v0.0.0-20161117033126-8ee79997227b 5 | ## explicit 6 | github.com/golang/protobuf/proto 7 | # github.com/matttproud/golang_protobuf_extensions v1.0.1 8 | ## explicit 9 | github.com/matttproud/golang_protobuf_extensions/pbutil 10 | # github.com/prometheus/client_golang v0.8.1-0.20161124155732-575f371f7862 11 | ## explicit 12 | github.com/prometheus/client_golang/prometheus 13 | github.com/prometheus/client_golang/prometheus/promhttp 14 | # github.com/prometheus/client_model v0.0.0-20150212101744-fa8ad6fec335 15 | ## explicit 16 | github.com/prometheus/client_model/go 17 | # github.com/prometheus/common v0.0.0-20161220174553-6d76b79f2398 18 | ## explicit 19 | github.com/prometheus/common/expfmt 20 | github.com/prometheus/common/internal/bitbucket.org/ww/goautoneg 21 | github.com/prometheus/common/model 22 | # github.com/prometheus/procfs v0.0.0-20161206222141-fcdb11ccb438 23 | ## explicit 24 | github.com/prometheus/procfs 25 | # golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f 26 | ## explicit 27 | --------------------------------------------------------------------------------