forked from pneymrl2f/nightingale
parent
1dac755787
commit
679c5892a4
@ -0,0 +1 @@
|
|||||||
|
prometheus/
|
@ -1,13 +0,0 @@
|
|||||||
package github
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/didi/nightingale/src/modules/monapi/plugins"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestCollect(t *testing.T) {
|
|
||||||
plugins.PluginTest(t, &GitHubRule{
|
|
||||||
Repositories: []string{"didi/nightingale"},
|
|
||||||
})
|
|
||||||
}
|
|
@ -1,171 +0,0 @@
|
|||||||
# Prometheus Input Plugin
|
|
||||||
|
|
||||||
The prometheus input plugin gathers metrics from HTTP servers exposing metrics
|
|
||||||
in Prometheus format.
|
|
||||||
|
|
||||||
### Configuration:
|
|
||||||
|
|
||||||
```toml
|
|
||||||
# Read metrics from one or many prometheus clients
|
|
||||||
[[inputs.prometheus]]
|
|
||||||
## An array of urls to scrape metrics from.
|
|
||||||
urls = ["http://localhost:9100/metrics"]
|
|
||||||
|
|
||||||
## Metric version controls the mapping from Prometheus metrics into
|
|
||||||
## Telegraf metrics. When using the prometheus_client output, use the same
|
|
||||||
## value in both plugins to ensure metrics are round-tripped without
|
|
||||||
## modification.
|
|
||||||
##
|
|
||||||
## example: metric_version = 1; deprecated in 1.13
|
|
||||||
## metric_version = 2; recommended version
|
|
||||||
# metric_version = 1
|
|
||||||
|
|
||||||
## An array of Kubernetes services to scrape metrics from.
|
|
||||||
# kubernetes_services = ["http://my-service-dns.my-namespace:9100/metrics"]
|
|
||||||
|
|
||||||
## Kubernetes config file to create client from.
|
|
||||||
# kube_config = "/path/to/kubernetes.config"
|
|
||||||
|
|
||||||
## Scrape Kubernetes pods for the following prometheus annotations:
|
|
||||||
## - prometheus.io/scrape: Enable scraping for this pod
|
|
||||||
## - prometheus.io/scheme: If the metrics endpoint is secured then you will need to
|
|
||||||
## set this to `https` & most likely set the tls config.
|
|
||||||
## - prometheus.io/path: If the metrics path is not /metrics, define it with this annotation.
|
|
||||||
## - prometheus.io/port: If port is not 9102 use this annotation
|
|
||||||
# monitor_kubernetes_pods = true
|
|
||||||
## Restricts Kubernetes monitoring to a single namespace
|
|
||||||
## ex: monitor_kubernetes_pods_namespace = "default"
|
|
||||||
# monitor_kubernetes_pods_namespace = ""
|
|
||||||
# label selector to target pods which have the label
|
|
||||||
# kubernetes_label_selector = "env=dev,app=nginx"
|
|
||||||
# field selector to target pods
|
|
||||||
# eg. To scrape pods on a specific node
|
|
||||||
# kubernetes_field_selector = "spec.nodeName=$HOSTNAME"
|
|
||||||
|
|
||||||
## Use bearer token for authorization. ('bearer_token' takes priority)
|
|
||||||
# bearer_token = "/path/to/bearer/token"
|
|
||||||
## OR
|
|
||||||
# bearer_token_string = "abc_123"
|
|
||||||
|
|
||||||
## HTTP Basic Authentication username and password. ('bearer_token' and
|
|
||||||
## 'bearer_token_string' take priority)
|
|
||||||
# username = ""
|
|
||||||
# password = ""
|
|
||||||
|
|
||||||
## Specify timeout duration for slower prometheus clients (default is 3s)
|
|
||||||
# response_timeout = "3s"
|
|
||||||
|
|
||||||
## Optional TLS Config
|
|
||||||
# tls_ca = /path/to/cafile
|
|
||||||
# tls_cert = /path/to/certfile
|
|
||||||
# tls_key = /path/to/keyfile
|
|
||||||
## Use TLS but skip chain & host verification
|
|
||||||
# insecure_skip_verify = false
|
|
||||||
```
|
|
||||||
|
|
||||||
`urls` can contain a unix socket as well. If a different path is required (default is `/metrics` for both http[s] and unix) for a unix socket, add `path` as a query parameter as follows: `unix:///var/run/prometheus.sock?path=/custom/metrics`
|
|
||||||
|
|
||||||
#### Kubernetes Service Discovery
|
|
||||||
|
|
||||||
URLs listed in the `kubernetes_services` parameter will be expanded
|
|
||||||
by looking up all A records assigned to the hostname as described in
|
|
||||||
[Kubernetes DNS service discovery](https://kubernetes.io/docs/concepts/services-networking/service/#dns).
|
|
||||||
|
|
||||||
This method can be used to locate all
|
|
||||||
[Kubernetes headless services](https://kubernetes.io/docs/concepts/services-networking/service/#headless-services).
|
|
||||||
|
|
||||||
#### Kubernetes scraping
|
|
||||||
|
|
||||||
Enabling this option will allow the plugin to scrape for prometheus annotation on Kubernetes
|
|
||||||
pods. Currently, you can run this plugin in your kubernetes cluster, or we use the kubeconfig
|
|
||||||
file to determine where to monitor.
|
|
||||||
Currently the following annotation are supported:
|
|
||||||
|
|
||||||
* `prometheus.io/scrape` Enable scraping for this pod.
|
|
||||||
* `prometheus.io/scheme` If the metrics endpoint is secured then you will need to set this to `https` & most likely set the tls config. (default 'http')
|
|
||||||
* `prometheus.io/path` Override the path for the metrics endpoint on the service. (default '/metrics')
|
|
||||||
* `prometheus.io/port` Used to override the port. (default 9102)
|
|
||||||
|
|
||||||
Using the `monitor_kubernetes_pods_namespace` option allows you to limit which pods you are scraping.
|
|
||||||
|
|
||||||
#### Bearer Token
|
|
||||||
|
|
||||||
If set, the file specified by the `bearer_token` parameter will be read on
|
|
||||||
each interval and its contents will be appended to the Bearer string in the
|
|
||||||
Authorization header.
|
|
||||||
|
|
||||||
### Usage for Caddy HTTP server
|
|
||||||
|
|
||||||
If you want to monitor Caddy, you need to use Caddy with its Prometheus plugin:
|
|
||||||
|
|
||||||
* Download Caddy+Prometheus plugin [here](https://caddyserver.com/download/linux/amd64?plugins=http.prometheus)
|
|
||||||
* Add the `prometheus` directive in your `CaddyFile`
|
|
||||||
* Restart Caddy
|
|
||||||
* Configure Telegraf to fetch metrics on it:
|
|
||||||
|
|
||||||
```toml
|
|
||||||
[[inputs.prometheus]]
|
|
||||||
# ## An array of urls to scrape metrics from.
|
|
||||||
urls = ["http://localhost:9180/metrics"]
|
|
||||||
```
|
|
||||||
|
|
||||||
> This is the default URL where Caddy Prometheus plugin will send data.
|
|
||||||
> For more details, please read the [Caddy Prometheus documentation](https://github.com/miekg/caddy-prometheus/blob/master/README.md).
|
|
||||||
|
|
||||||
### Metrics:
|
|
||||||
|
|
||||||
Measurement names are based on the Metric Family and tags are created for each
|
|
||||||
label. The value is added to a field named based on the metric type.
|
|
||||||
|
|
||||||
All metrics receive the `url` tag indicating the related URL specified in the
|
|
||||||
Telegraf configuration. If using Kubernetes service discovery the `address`
|
|
||||||
tag is also added indicating the discovered ip address.
|
|
||||||
|
|
||||||
### Example Output:
|
|
||||||
|
|
||||||
**Source**
|
|
||||||
```
|
|
||||||
# HELP go_gc_duration_seconds A summary of the GC invocation durations.
|
|
||||||
# TYPE go_gc_duration_seconds summary
|
|
||||||
go_gc_duration_seconds{quantile="0"} 7.4545e-05
|
|
||||||
go_gc_duration_seconds{quantile="0.25"} 7.6999e-05
|
|
||||||
go_gc_duration_seconds{quantile="0.5"} 0.000277935
|
|
||||||
go_gc_duration_seconds{quantile="0.75"} 0.000706591
|
|
||||||
go_gc_duration_seconds{quantile="1"} 0.000706591
|
|
||||||
go_gc_duration_seconds_sum 0.00113607
|
|
||||||
go_gc_duration_seconds_count 4
|
|
||||||
# HELP go_goroutines Number of goroutines that currently exist.
|
|
||||||
# TYPE go_goroutines gauge
|
|
||||||
go_goroutines 15
|
|
||||||
# HELP cpu_usage_user Telegraf collected metric
|
|
||||||
# TYPE cpu_usage_user gauge
|
|
||||||
cpu_usage_user{cpu="cpu0"} 1.4112903225816156
|
|
||||||
cpu_usage_user{cpu="cpu1"} 0.702106318955865
|
|
||||||
cpu_usage_user{cpu="cpu2"} 2.0161290322588776
|
|
||||||
cpu_usage_user{cpu="cpu3"} 1.5045135406226022
|
|
||||||
```
|
|
||||||
|
|
||||||
**Output**
|
|
||||||
```
|
|
||||||
go_gc_duration_seconds,url=http://example.org:9273/metrics 1=0.001336611,count=14,sum=0.004527551,0=0.000057965,0.25=0.000083812,0.5=0.000286537,0.75=0.000365303 1505776733000000000
|
|
||||||
go_goroutines,url=http://example.org:9273/metrics gauge=21 1505776695000000000
|
|
||||||
cpu_usage_user,cpu=cpu0,url=http://example.org:9273/metrics gauge=1.513622603430151 1505776751000000000
|
|
||||||
cpu_usage_user,cpu=cpu1,url=http://example.org:9273/metrics gauge=5.829145728641773 1505776751000000000
|
|
||||||
cpu_usage_user,cpu=cpu2,url=http://example.org:9273/metrics gauge=2.119071644805144 1505776751000000000
|
|
||||||
cpu_usage_user,cpu=cpu3,url=http://example.org:9273/metrics gauge=1.5228426395944945 1505776751000000000
|
|
||||||
```
|
|
||||||
|
|
||||||
**Output (when metric_version = 2)**
|
|
||||||
```
|
|
||||||
prometheus,quantile=1,url=http://example.org:9273/metrics go_gc_duration_seconds=0.005574303 1556075100000000000
|
|
||||||
prometheus,quantile=0.75,url=http://example.org:9273/metrics go_gc_duration_seconds=0.0001046 1556075100000000000
|
|
||||||
prometheus,quantile=0.5,url=http://example.org:9273/metrics go_gc_duration_seconds=0.0000719 1556075100000000000
|
|
||||||
prometheus,quantile=0.25,url=http://example.org:9273/metrics go_gc_duration_seconds=0.0000579 1556075100000000000
|
|
||||||
prometheus,quantile=0,url=http://example.org:9273/metrics go_gc_duration_seconds=0.0000349 1556075100000000000
|
|
||||||
prometheus,url=http://example.org:9273/metrics go_gc_duration_seconds_count=324,go_gc_duration_seconds_sum=0.091340353 1556075100000000000
|
|
||||||
prometheus,url=http://example.org:9273/metrics go_goroutines=15 1556075100000000000
|
|
||||||
prometheus,cpu=cpu0,url=http://example.org:9273/metrics cpu_usage_user=1.513622603430151 1505776751000000000
|
|
||||||
prometheus,cpu=cpu1,url=http://example.org:9273/metrics cpu_usage_user=5.829145728641773 1505776751000000000
|
|
||||||
prometheus,cpu=cpu2,url=http://example.org:9273/metrics cpu_usage_user=2.119071644805144 1505776751000000000
|
|
||||||
prometheus,cpu=cpu3,url=http://example.org:9273/metrics cpu_usage_user=1.5228426395944945 1505776751000000000
|
|
||||||
```
|
|
@ -1,237 +0,0 @@
|
|||||||
package prometheus
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"log"
|
|
||||||
"net"
|
|
||||||
"net/url"
|
|
||||||
"sync"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/ericchiang/k8s"
|
|
||||||
corev1 "github.com/ericchiang/k8s/apis/core/v1"
|
|
||||||
"github.com/ghodss/yaml"
|
|
||||||
)
|
|
||||||
|
|
||||||
type payload struct {
|
|
||||||
eventype string
|
|
||||||
pod *corev1.Pod
|
|
||||||
}
|
|
||||||
|
|
||||||
// loadClient parses a kubeconfig from a file and returns a Kubernetes
|
|
||||||
// client. It does not support extensions or client auth providers.
|
|
||||||
func loadClient(kubeconfig string) (*k8s.Client, error) {
|
|
||||||
// data, err := ioutil.ReadFile(kubeconfigPath)
|
|
||||||
// if err != nil {
|
|
||||||
// return nil, fmt.Errorf("failed reading '%s': %v", kubeconfigPath, err)
|
|
||||||
// }
|
|
||||||
|
|
||||||
// Unmarshal YAML into a Kubernetes config object.
|
|
||||||
var config k8s.Config
|
|
||||||
if err := yaml.Unmarshal([]byte(kubeconfig), &config); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return k8s.NewClient(&config)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *Prometheus) start(ctx context.Context) error {
|
|
||||||
client, err := k8s.NewInClusterClient()
|
|
||||||
if err != nil {
|
|
||||||
// u, err := user.Current()
|
|
||||||
// if err != nil {
|
|
||||||
// return fmt.Errorf("Failed to get current user - %v", err)
|
|
||||||
// }
|
|
||||||
|
|
||||||
// configLocation := filepath.Join(u.HomeDir, ".kube/config")
|
|
||||||
// if p.KubeConfig != "" {
|
|
||||||
// configLocation = p.KubeConfig
|
|
||||||
// }
|
|
||||||
client, err = loadClient(p.KubeConfigContent)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
p.wg = sync.WaitGroup{}
|
|
||||||
|
|
||||||
p.wg.Add(1)
|
|
||||||
go func() {
|
|
||||||
defer p.wg.Done()
|
|
||||||
for {
|
|
||||||
select {
|
|
||||||
case <-ctx.Done():
|
|
||||||
return
|
|
||||||
case <-time.After(time.Second):
|
|
||||||
err := p.watch(ctx, client)
|
|
||||||
if err != nil {
|
|
||||||
p.Log.Errorf("Unable to watch resources: %s", err.Error())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// An edge case exists if a pod goes offline at the same time a new pod is created
|
|
||||||
// (without the scrape annotations). K8s may re-assign the old pod ip to the non-scrape
|
|
||||||
// pod, causing errors in the logs. This is only true if the pod going offline is not
|
|
||||||
// directed to do so by K8s.
|
|
||||||
func (p *Prometheus) watch(ctx context.Context, client *k8s.Client) error {
|
|
||||||
|
|
||||||
selectors := podSelector(p)
|
|
||||||
|
|
||||||
pod := &corev1.Pod{}
|
|
||||||
watcher, err := client.Watch(ctx, p.PodNamespace, &corev1.Pod{}, selectors...)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer watcher.Close()
|
|
||||||
|
|
||||||
for {
|
|
||||||
select {
|
|
||||||
case <-ctx.Done():
|
|
||||||
return nil
|
|
||||||
default:
|
|
||||||
pod = &corev1.Pod{}
|
|
||||||
// An error here means we need to reconnect the watcher.
|
|
||||||
eventType, err := watcher.Next(pod)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the pod is not "ready", there will be no ip associated with it.
|
|
||||||
if pod.GetMetadata().GetAnnotations()["prometheus.io/scrape"] != "true" ||
|
|
||||||
!podReady(pod.Status.GetContainerStatuses()) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
switch eventType {
|
|
||||||
case k8s.EventAdded:
|
|
||||||
registerPod(pod, p)
|
|
||||||
case k8s.EventModified:
|
|
||||||
// To avoid multiple actions for each event, unregister on the first event
|
|
||||||
// in the delete sequence, when the containers are still "ready".
|
|
||||||
if pod.Metadata.GetDeletionTimestamp() != nil {
|
|
||||||
unregisterPod(pod, p)
|
|
||||||
} else {
|
|
||||||
registerPod(pod, p)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func podReady(statuss []*corev1.ContainerStatus) bool {
|
|
||||||
if len(statuss) == 0 {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
for _, cs := range statuss {
|
|
||||||
if !cs.GetReady() {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func podSelector(p *Prometheus) []k8s.Option {
|
|
||||||
options := []k8s.Option{}
|
|
||||||
|
|
||||||
if len(p.KubernetesLabelSelector) > 0 {
|
|
||||||
options = append(options, k8s.QueryParam("labelSelector", p.KubernetesLabelSelector))
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(p.KubernetesFieldSelector) > 0 {
|
|
||||||
options = append(options, k8s.QueryParam("fieldSelector", p.KubernetesFieldSelector))
|
|
||||||
}
|
|
||||||
|
|
||||||
return options
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func registerPod(pod *corev1.Pod, p *Prometheus) {
|
|
||||||
if p.kubernetesPods == nil {
|
|
||||||
p.kubernetesPods = map[string]URLAndAddress{}
|
|
||||||
}
|
|
||||||
targetURL := getScrapeURL(pod)
|
|
||||||
if targetURL == nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Printf("D! [inputs.prometheus] will scrape metrics from %q", *targetURL)
|
|
||||||
// add annotation as metrics tags
|
|
||||||
tags := pod.GetMetadata().GetAnnotations()
|
|
||||||
if tags == nil {
|
|
||||||
tags = map[string]string{}
|
|
||||||
}
|
|
||||||
tags["pod_name"] = pod.GetMetadata().GetName()
|
|
||||||
tags["namespace"] = pod.GetMetadata().GetNamespace()
|
|
||||||
// add labels as metrics tags
|
|
||||||
for k, v := range pod.GetMetadata().GetLabels() {
|
|
||||||
tags[k] = v
|
|
||||||
}
|
|
||||||
URL, err := url.Parse(*targetURL)
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("E! [inputs.prometheus] could not parse URL %q: %s", *targetURL, err.Error())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
podURL := p.AddressToURL(URL, URL.Hostname())
|
|
||||||
p.lock.Lock()
|
|
||||||
p.kubernetesPods[podURL.String()] = URLAndAddress{
|
|
||||||
URL: podURL,
|
|
||||||
Address: URL.Hostname(),
|
|
||||||
OriginalURL: URL,
|
|
||||||
Tags: tags,
|
|
||||||
}
|
|
||||||
p.lock.Unlock()
|
|
||||||
}
|
|
||||||
|
|
||||||
func getScrapeURL(pod *corev1.Pod) *string {
|
|
||||||
ip := pod.Status.GetPodIP()
|
|
||||||
if ip == "" {
|
|
||||||
// return as if scrape was disabled, we will be notified again once the pod
|
|
||||||
// has an IP
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
scheme := pod.GetMetadata().GetAnnotations()["prometheus.io/scheme"]
|
|
||||||
path := pod.GetMetadata().GetAnnotations()["prometheus.io/path"]
|
|
||||||
port := pod.GetMetadata().GetAnnotations()["prometheus.io/port"]
|
|
||||||
|
|
||||||
if scheme == "" {
|
|
||||||
scheme = "http"
|
|
||||||
}
|
|
||||||
if port == "" {
|
|
||||||
port = "9102"
|
|
||||||
}
|
|
||||||
if path == "" {
|
|
||||||
path = "/metrics"
|
|
||||||
}
|
|
||||||
|
|
||||||
u := &url.URL{
|
|
||||||
Scheme: scheme,
|
|
||||||
Host: net.JoinHostPort(ip, port),
|
|
||||||
Path: path,
|
|
||||||
}
|
|
||||||
|
|
||||||
x := u.String()
|
|
||||||
|
|
||||||
return &x
|
|
||||||
}
|
|
||||||
|
|
||||||
func unregisterPod(pod *corev1.Pod, p *Prometheus) {
|
|
||||||
url := getScrapeURL(pod)
|
|
||||||
if url == nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Printf("D! [inputs.prometheus] registered a delete request for %q in namespace %q",
|
|
||||||
pod.GetMetadata().GetName(), pod.GetMetadata().GetNamespace())
|
|
||||||
|
|
||||||
p.lock.Lock()
|
|
||||||
defer p.lock.Unlock()
|
|
||||||
if _, ok := p.kubernetesPods[*url]; ok {
|
|
||||||
delete(p.kubernetesPods, *url)
|
|
||||||
log.Printf("D! [inputs.prometheus] will stop scraping for %q", *url)
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,155 +0,0 @@
|
|||||||
package prometheus
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/ericchiang/k8s"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/influxdata/telegraf/testutil"
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
|
|
||||||
v1 "github.com/ericchiang/k8s/apis/core/v1"
|
|
||||||
metav1 "github.com/ericchiang/k8s/apis/meta/v1"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestScrapeURLNoAnnotations(t *testing.T) {
|
|
||||||
p := &v1.Pod{Metadata: &metav1.ObjectMeta{}}
|
|
||||||
p.GetMetadata().Annotations = map[string]string{}
|
|
||||||
url := getScrapeURL(p)
|
|
||||||
assert.Nil(t, url)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestScrapeURLAnnotationsNoScrape(t *testing.T) {
|
|
||||||
p := &v1.Pod{Metadata: &metav1.ObjectMeta{}}
|
|
||||||
p.Metadata.Name = str("myPod")
|
|
||||||
p.Metadata.Annotations = map[string]string{"prometheus.io/scrape": "false"}
|
|
||||||
url := getScrapeURL(p)
|
|
||||||
assert.Nil(t, url)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestScrapeURLAnnotations(t *testing.T) {
|
|
||||||
p := pod()
|
|
||||||
p.Metadata.Annotations = map[string]string{"prometheus.io/scrape": "true"}
|
|
||||||
url := getScrapeURL(p)
|
|
||||||
assert.Equal(t, "http://127.0.0.1:9102/metrics", *url)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestScrapeURLAnnotationsCustomPort(t *testing.T) {
|
|
||||||
p := pod()
|
|
||||||
p.Metadata.Annotations = map[string]string{"prometheus.io/scrape": "true", "prometheus.io/port": "9000"}
|
|
||||||
url := getScrapeURL(p)
|
|
||||||
assert.Equal(t, "http://127.0.0.1:9000/metrics", *url)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestScrapeURLAnnotationsCustomPath(t *testing.T) {
|
|
||||||
p := pod()
|
|
||||||
p.Metadata.Annotations = map[string]string{"prometheus.io/scrape": "true", "prometheus.io/path": "mymetrics"}
|
|
||||||
url := getScrapeURL(p)
|
|
||||||
assert.Equal(t, "http://127.0.0.1:9102/mymetrics", *url)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestScrapeURLAnnotationsCustomPathWithSep(t *testing.T) {
|
|
||||||
p := pod()
|
|
||||||
p.Metadata.Annotations = map[string]string{"prometheus.io/scrape": "true", "prometheus.io/path": "/mymetrics"}
|
|
||||||
url := getScrapeURL(p)
|
|
||||||
assert.Equal(t, "http://127.0.0.1:9102/mymetrics", *url)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestAddPod(t *testing.T) {
|
|
||||||
prom := &Prometheus{Log: testutil.Logger{}}
|
|
||||||
|
|
||||||
p := pod()
|
|
||||||
p.Metadata.Annotations = map[string]string{"prometheus.io/scrape": "true"}
|
|
||||||
registerPod(p, prom)
|
|
||||||
assert.Equal(t, 1, len(prom.kubernetesPods))
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestAddMultipleDuplicatePods(t *testing.T) {
|
|
||||||
prom := &Prometheus{Log: testutil.Logger{}}
|
|
||||||
|
|
||||||
p := pod()
|
|
||||||
p.Metadata.Annotations = map[string]string{"prometheus.io/scrape": "true"}
|
|
||||||
registerPod(p, prom)
|
|
||||||
p.Metadata.Name = str("Pod2")
|
|
||||||
registerPod(p, prom)
|
|
||||||
assert.Equal(t, 1, len(prom.kubernetesPods))
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestAddMultiplePods(t *testing.T) {
|
|
||||||
prom := &Prometheus{Log: testutil.Logger{}}
|
|
||||||
|
|
||||||
p := pod()
|
|
||||||
p.Metadata.Annotations = map[string]string{"prometheus.io/scrape": "true"}
|
|
||||||
registerPod(p, prom)
|
|
||||||
p.Metadata.Name = str("Pod2")
|
|
||||||
p.Status.PodIP = str("127.0.0.2")
|
|
||||||
registerPod(p, prom)
|
|
||||||
assert.Equal(t, 2, len(prom.kubernetesPods))
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestDeletePods(t *testing.T) {
|
|
||||||
prom := &Prometheus{Log: testutil.Logger{}}
|
|
||||||
|
|
||||||
p := pod()
|
|
||||||
p.Metadata.Annotations = map[string]string{"prometheus.io/scrape": "true"}
|
|
||||||
registerPod(p, prom)
|
|
||||||
unregisterPod(p, prom)
|
|
||||||
assert.Equal(t, 0, len(prom.kubernetesPods))
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestPodSelector(t *testing.T) {
|
|
||||||
|
|
||||||
cases := []struct {
|
|
||||||
expected []k8s.Option
|
|
||||||
labelselector string
|
|
||||||
fieldselector string
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
expected: []k8s.Option{
|
|
||||||
k8s.QueryParam("labelSelector", "key1=val1,key2=val2,key3"),
|
|
||||||
k8s.QueryParam("fieldSelector", "spec.nodeName=ip-1-2-3-4.acme.com"),
|
|
||||||
},
|
|
||||||
labelselector: "key1=val1,key2=val2,key3",
|
|
||||||
fieldselector: "spec.nodeName=ip-1-2-3-4.acme.com",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
expected: []k8s.Option{
|
|
||||||
k8s.QueryParam("labelSelector", "key1"),
|
|
||||||
k8s.QueryParam("fieldSelector", "spec.nodeName=ip-1-2-3-4.acme.com"),
|
|
||||||
},
|
|
||||||
labelselector: "key1",
|
|
||||||
fieldselector: "spec.nodeName=ip-1-2-3-4.acme.com",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
expected: []k8s.Option{
|
|
||||||
k8s.QueryParam("labelSelector", "key1"),
|
|
||||||
k8s.QueryParam("fieldSelector", "somefield"),
|
|
||||||
},
|
|
||||||
labelselector: "key1",
|
|
||||||
fieldselector: "somefield",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, c := range cases {
|
|
||||||
prom := &Prometheus{
|
|
||||||
Log: testutil.Logger{},
|
|
||||||
KubernetesLabelSelector: c.labelselector,
|
|
||||||
KubernetesFieldSelector: c.fieldselector,
|
|
||||||
}
|
|
||||||
|
|
||||||
output := podSelector(prom)
|
|
||||||
|
|
||||||
assert.Equal(t, len(output), len(c.expected))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func pod() *v1.Pod {
|
|
||||||
p := &v1.Pod{Metadata: &metav1.ObjectMeta{}, Status: &v1.PodStatus{}, Spec: &v1.PodSpec{}}
|
|
||||||
p.Status.PodIP = str("127.0.0.1")
|
|
||||||
p.Metadata.Name = str("myPod")
|
|
||||||
p.Metadata.Namespace = str("default")
|
|
||||||
return p
|
|
||||||
}
|
|
||||||
|
|
||||||
func str(x string) *string {
|
|
||||||
return &x
|
|
||||||
}
|
|
File diff suppressed because it is too large
Load Diff
@ -1,167 +0,0 @@
|
|||||||
package prometheus
|
|
||||||
|
|
||||||
import (
|
|
||||||
"net/http"
|
|
||||||
"testing"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
)
|
|
||||||
|
|
||||||
var exptime = time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC)
|
|
||||||
|
|
||||||
const validUniqueGauge = `# HELP cadvisor_version_info A metric with a constant '1' value labeled by kernel version, OS version, docker version, cadvisor version & cadvisor revision.
|
|
||||||
# TYPE cadvisor_version_info gauge
|
|
||||||
cadvisor_version_info{cadvisorRevision="",cadvisorVersion="",dockerVersion="1.8.2",kernelVersion="3.10.0-229.20.1.el7.x86_64",osVersion="CentOS Linux 7 (Core)"} 1
|
|
||||||
`
|
|
||||||
|
|
||||||
const validUniqueCounter = `# HELP get_token_fail_count Counter of failed Token() requests to the alternate token source
|
|
||||||
# TYPE get_token_fail_count counter
|
|
||||||
get_token_fail_count 0
|
|
||||||
`
|
|
||||||
|
|
||||||
const validUniqueLine = `# HELP get_token_fail_count Counter of failed Token() requests to the alternate token source
|
|
||||||
`
|
|
||||||
|
|
||||||
const validUniqueSummary = `# HELP http_request_duration_microseconds The HTTP request latencies in microseconds.
|
|
||||||
# TYPE http_request_duration_microseconds summary
|
|
||||||
http_request_duration_microseconds{handler="prometheus",quantile="0.5"} 552048.506
|
|
||||||
http_request_duration_microseconds{handler="prometheus",quantile="0.9"} 5.876804288e+06
|
|
||||||
http_request_duration_microseconds{handler="prometheus",quantile="0.99"} 5.876804288e+06
|
|
||||||
http_request_duration_microseconds_sum{handler="prometheus"} 1.8909097205e+07
|
|
||||||
http_request_duration_microseconds_count{handler="prometheus"} 9
|
|
||||||
`
|
|
||||||
|
|
||||||
const validUniqueHistogram = `# HELP apiserver_request_latencies Response latency distribution in microseconds for each verb, resource and client.
|
|
||||||
# TYPE apiserver_request_latencies histogram
|
|
||||||
apiserver_request_latencies_bucket{resource="bindings",verb="POST",le="125000"} 1994
|
|
||||||
apiserver_request_latencies_bucket{resource="bindings",verb="POST",le="250000"} 1997
|
|
||||||
apiserver_request_latencies_bucket{resource="bindings",verb="POST",le="500000"} 2000
|
|
||||||
apiserver_request_latencies_bucket{resource="bindings",verb="POST",le="1e+06"} 2005
|
|
||||||
apiserver_request_latencies_bucket{resource="bindings",verb="POST",le="2e+06"} 2012
|
|
||||||
apiserver_request_latencies_bucket{resource="bindings",verb="POST",le="4e+06"} 2017
|
|
||||||
apiserver_request_latencies_bucket{resource="bindings",verb="POST",le="8e+06"} 2024
|
|
||||||
apiserver_request_latencies_bucket{resource="bindings",verb="POST",le="+Inf"} 2025
|
|
||||||
apiserver_request_latencies_sum{resource="bindings",verb="POST"} 1.02726334e+08
|
|
||||||
apiserver_request_latencies_count{resource="bindings",verb="POST"} 2025
|
|
||||||
`
|
|
||||||
|
|
||||||
const validData = `# HELP cadvisor_version_info A metric with a constant '1' value labeled by kernel version, OS version, docker version, cadvisor version & cadvisor revision.
|
|
||||||
# TYPE cadvisor_version_info gauge
|
|
||||||
cadvisor_version_info{cadvisorRevision="",cadvisorVersion="",dockerVersion="1.8.2",kernelVersion="3.10.0-229.20.1.el7.x86_64",osVersion="CentOS Linux 7 (Core)"} 1
|
|
||||||
# HELP go_gc_duration_seconds A summary of the GC invocation durations.
|
|
||||||
# TYPE go_gc_duration_seconds summary
|
|
||||||
go_gc_duration_seconds{quantile="0"} 0.013534896000000001
|
|
||||||
go_gc_duration_seconds{quantile="0.25"} 0.02469263
|
|
||||||
go_gc_duration_seconds{quantile="0.5"} 0.033727822000000005
|
|
||||||
go_gc_duration_seconds{quantile="0.75"} 0.03840335
|
|
||||||
go_gc_duration_seconds{quantile="1"} 0.049956604
|
|
||||||
go_gc_duration_seconds_sum 1970.341293002
|
|
||||||
go_gc_duration_seconds_count 65952
|
|
||||||
# HELP http_request_duration_microseconds The HTTP request latencies in microseconds.
|
|
||||||
# TYPE http_request_duration_microseconds summary
|
|
||||||
http_request_duration_microseconds{handler="prometheus",quantile="0.5"} 552048.506
|
|
||||||
http_request_duration_microseconds{handler="prometheus",quantile="0.9"} 5.876804288e+06
|
|
||||||
http_request_duration_microseconds{handler="prometheus",quantile="0.99"} 5.876804288e+06
|
|
||||||
http_request_duration_microseconds_sum{handler="prometheus"} 1.8909097205e+07
|
|
||||||
http_request_duration_microseconds_count{handler="prometheus"} 9
|
|
||||||
# HELP get_token_fail_count Counter of failed Token() requests to the alternate token source
|
|
||||||
# TYPE get_token_fail_count counter
|
|
||||||
get_token_fail_count 0
|
|
||||||
# HELP apiserver_request_latencies Response latency distribution in microseconds for each verb, resource and client.
|
|
||||||
# TYPE apiserver_request_latencies histogram
|
|
||||||
apiserver_request_latencies_bucket{resource="bindings",verb="POST",le="125000"} 1994
|
|
||||||
apiserver_request_latencies_bucket{resource="bindings",verb="POST",le="250000"} 1997
|
|
||||||
apiserver_request_latencies_bucket{resource="bindings",verb="POST",le="500000"} 2000
|
|
||||||
apiserver_request_latencies_bucket{resource="bindings",verb="POST",le="1e+06"} 2005
|
|
||||||
apiserver_request_latencies_bucket{resource="bindings",verb="POST",le="2e+06"} 2012
|
|
||||||
apiserver_request_latencies_bucket{resource="bindings",verb="POST",le="4e+06"} 2017
|
|
||||||
apiserver_request_latencies_bucket{resource="bindings",verb="POST",le="8e+06"} 2024
|
|
||||||
apiserver_request_latencies_bucket{resource="bindings",verb="POST",le="+Inf"} 2025
|
|
||||||
apiserver_request_latencies_sum{resource="bindings",verb="POST"} 1.02726334e+08
|
|
||||||
apiserver_request_latencies_count{resource="bindings",verb="POST"} 2025
|
|
||||||
`
|
|
||||||
|
|
||||||
const prometheusMulti = `
|
|
||||||
cpu,host=foo,datacenter=us-east usage_idle=99,usage_busy=1
|
|
||||||
cpu,host=foo,datacenter=us-east usage_idle=99,usage_busy=1
|
|
||||||
cpu,host=foo,datacenter=us-east usage_idle=99,usage_busy=1
|
|
||||||
cpu,host=foo,datacenter=us-east usage_idle=99,usage_busy=1
|
|
||||||
cpu,host=foo,datacenter=us-east usage_idle=99,usage_busy=1
|
|
||||||
cpu,host=foo,datacenter=us-east usage_idle=99,usage_busy=1
|
|
||||||
cpu,host=foo,datacenter=us-east usage_idle=99,usage_busy=1
|
|
||||||
`
|
|
||||||
|
|
||||||
const prometheusMultiSomeInvalid = `
|
|
||||||
cpu,host=foo,datacenter=us-east usage_idle=99,usage_busy=1
|
|
||||||
cpu,host=foo,datacenter=us-east usage_idle=99,usage_busy=1
|
|
||||||
cpu,host=foo,datacenter=us-east usage_idle=99,usage_busy=1
|
|
||||||
cpu,cpu=cpu3, host=foo,datacenter=us-east usage_idle=99,usage_busy=1
|
|
||||||
cpu,cpu=cpu4 , usage_idle=99,usage_busy=1
|
|
||||||
cpu,host=foo,datacenter=us-east usage_idle=99,usage_busy=1
|
|
||||||
`
|
|
||||||
|
|
||||||
func TestParseValidPrometheus(t *testing.T) {
|
|
||||||
// Gauge value
|
|
||||||
metrics, err := Parse([]byte(validUniqueGauge), http.Header{})
|
|
||||||
assert.NoError(t, err)
|
|
||||||
assert.Len(t, metrics, 1)
|
|
||||||
assert.Equal(t, "cadvisor_version_info", metrics[0].Name())
|
|
||||||
assert.Equal(t, map[string]interface{}{
|
|
||||||
"gauge": float64(1),
|
|
||||||
}, metrics[0].Fields())
|
|
||||||
assert.Equal(t, map[string]string{
|
|
||||||
"osVersion": "CentOS Linux 7 (Core)",
|
|
||||||
"cadvisorRevision": "",
|
|
||||||
"cadvisorVersion": "",
|
|
||||||
"dockerVersion": "1.8.2",
|
|
||||||
"kernelVersion": "3.10.0-229.20.1.el7.x86_64",
|
|
||||||
}, metrics[0].Tags())
|
|
||||||
|
|
||||||
// Counter value
|
|
||||||
metrics, err = Parse([]byte(validUniqueCounter), http.Header{})
|
|
||||||
assert.NoError(t, err)
|
|
||||||
assert.Len(t, metrics, 1)
|
|
||||||
assert.Equal(t, "get_token_fail_count", metrics[0].Name())
|
|
||||||
assert.Equal(t, map[string]interface{}{
|
|
||||||
"counter": float64(0),
|
|
||||||
}, metrics[0].Fields())
|
|
||||||
assert.Equal(t, map[string]string{}, metrics[0].Tags())
|
|
||||||
|
|
||||||
// Summary data
|
|
||||||
//SetDefaultTags(map[string]string{})
|
|
||||||
metrics, err = Parse([]byte(validUniqueSummary), http.Header{})
|
|
||||||
assert.NoError(t, err)
|
|
||||||
assert.Len(t, metrics, 1)
|
|
||||||
assert.Equal(t, "http_request_duration_microseconds", metrics[0].Name())
|
|
||||||
assert.Equal(t, map[string]interface{}{
|
|
||||||
"0.5": 552048.506,
|
|
||||||
"0.9": 5.876804288e+06,
|
|
||||||
"0.99": 5.876804288e+06,
|
|
||||||
"count": 9.0,
|
|
||||||
"sum": 1.8909097205e+07,
|
|
||||||
}, metrics[0].Fields())
|
|
||||||
assert.Equal(t, map[string]string{"handler": "prometheus"}, metrics[0].Tags())
|
|
||||||
|
|
||||||
// histogram data
|
|
||||||
metrics, err = Parse([]byte(validUniqueHistogram), http.Header{})
|
|
||||||
assert.NoError(t, err)
|
|
||||||
assert.Len(t, metrics, 1)
|
|
||||||
assert.Equal(t, "apiserver_request_latencies", metrics[0].Name())
|
|
||||||
assert.Equal(t, map[string]interface{}{
|
|
||||||
"500000": 2000.0,
|
|
||||||
"count": 2025.0,
|
|
||||||
"sum": 1.02726334e+08,
|
|
||||||
"250000": 1997.0,
|
|
||||||
"2e+06": 2012.0,
|
|
||||||
"4e+06": 2017.0,
|
|
||||||
"8e+06": 2024.0,
|
|
||||||
"+Inf": 2025.0,
|
|
||||||
"125000": 1994.0,
|
|
||||||
"1e+06": 2005.0,
|
|
||||||
}, metrics[0].Fields())
|
|
||||||
assert.Equal(t,
|
|
||||||
map[string]string{"verb": "POST", "resource": "bindings"},
|
|
||||||
metrics[0].Tags())
|
|
||||||
|
|
||||||
}
|
|
File diff suppressed because it is too large
Load Diff
@ -1,236 +0,0 @@
|
|||||||
package prometheus
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"math"
|
|
||||||
"net/http"
|
|
||||||
"net/http/httptest"
|
|
||||||
"net/url"
|
|
||||||
"testing"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/influxdata/telegraf"
|
|
||||||
"github.com/influxdata/telegraf/testutil"
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
)
|
|
||||||
|
|
||||||
const sampleTextFormat = `# HELP go_gc_duration_seconds A summary of the GC invocation durations.
|
|
||||||
# TYPE go_gc_duration_seconds summary
|
|
||||||
go_gc_duration_seconds{quantile="0"} 0.00010425500000000001
|
|
||||||
go_gc_duration_seconds{quantile="0.25"} 0.000139108
|
|
||||||
go_gc_duration_seconds{quantile="0.5"} 0.00015749400000000002
|
|
||||||
go_gc_duration_seconds{quantile="0.75"} 0.000331463
|
|
||||||
go_gc_duration_seconds{quantile="1"} 0.000667154
|
|
||||||
go_gc_duration_seconds_sum 0.0018183950000000002
|
|
||||||
go_gc_duration_seconds_count 7
|
|
||||||
# HELP go_goroutines Number of goroutines that currently exist.
|
|
||||||
# TYPE go_goroutines gauge
|
|
||||||
go_goroutines 15
|
|
||||||
# HELP test_metric An untyped metric with a timestamp
|
|
||||||
# TYPE test_metric untyped
|
|
||||||
test_metric{label="value"} 1.0 1490802350000
|
|
||||||
`
|
|
||||||
const sampleSummaryTextFormat = `# HELP go_gc_duration_seconds A summary of the GC invocation durations.
|
|
||||||
# TYPE go_gc_duration_seconds summary
|
|
||||||
go_gc_duration_seconds{quantile="0"} 0.00010425500000000001
|
|
||||||
go_gc_duration_seconds{quantile="0.25"} 0.000139108
|
|
||||||
go_gc_duration_seconds{quantile="0.5"} 0.00015749400000000002
|
|
||||||
go_gc_duration_seconds{quantile="0.75"} 0.000331463
|
|
||||||
go_gc_duration_seconds{quantile="1"} 0.000667154
|
|
||||||
go_gc_duration_seconds_sum 0.0018183950000000002
|
|
||||||
go_gc_duration_seconds_count 7
|
|
||||||
`
|
|
||||||
const sampleGaugeTextFormat = `
|
|
||||||
# HELP go_goroutines Number of goroutines that currently exist.
|
|
||||||
# TYPE go_goroutines gauge
|
|
||||||
go_goroutines 15 1490802350000
|
|
||||||
`
|
|
||||||
|
|
||||||
func TestPrometheusGeneratesMetrics(t *testing.T) {
|
|
||||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
fmt.Fprintln(w, sampleTextFormat)
|
|
||||||
}))
|
|
||||||
defer ts.Close()
|
|
||||||
|
|
||||||
p := &Prometheus{
|
|
||||||
Log: testutil.Logger{},
|
|
||||||
URLs: []string{ts.URL},
|
|
||||||
URLTag: "url",
|
|
||||||
}
|
|
||||||
|
|
||||||
var acc testutil.Accumulator
|
|
||||||
|
|
||||||
err := acc.GatherError(p.Gather)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
assert.True(t, acc.HasFloatField("go_gc_duration_seconds", "count"))
|
|
||||||
assert.True(t, acc.HasFloatField("go_goroutines", "gauge"))
|
|
||||||
assert.True(t, acc.HasFloatField("test_metric", "value"))
|
|
||||||
assert.True(t, acc.HasTimestamp("test_metric", time.Unix(1490802350, 0)))
|
|
||||||
assert.False(t, acc.HasTag("test_metric", "address"))
|
|
||||||
assert.True(t, acc.TagValue("test_metric", "url") == ts.URL+"/metrics")
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestPrometheusGeneratesMetricsWithHostNameTag(t *testing.T) {
|
|
||||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
fmt.Fprintln(w, sampleTextFormat)
|
|
||||||
}))
|
|
||||||
defer ts.Close()
|
|
||||||
|
|
||||||
p := &Prometheus{
|
|
||||||
Log: testutil.Logger{},
|
|
||||||
KubernetesServices: []string{ts.URL},
|
|
||||||
URLTag: "url",
|
|
||||||
}
|
|
||||||
u, _ := url.Parse(ts.URL)
|
|
||||||
tsAddress := u.Hostname()
|
|
||||||
|
|
||||||
var acc testutil.Accumulator
|
|
||||||
|
|
||||||
err := acc.GatherError(p.Gather)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
assert.True(t, acc.HasFloatField("go_gc_duration_seconds", "count"))
|
|
||||||
assert.True(t, acc.HasFloatField("go_goroutines", "gauge"))
|
|
||||||
assert.True(t, acc.HasFloatField("test_metric", "value"))
|
|
||||||
assert.True(t, acc.HasTimestamp("test_metric", time.Unix(1490802350, 0)))
|
|
||||||
assert.True(t, acc.TagValue("test_metric", "address") == tsAddress)
|
|
||||||
assert.True(t, acc.TagValue("test_metric", "url") == ts.URL)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestPrometheusGeneratesMetricsAlthoughFirstDNSFails(t *testing.T) {
|
|
||||||
if testing.Short() {
|
|
||||||
t.Skip("Skipping integration test in short mode")
|
|
||||||
}
|
|
||||||
|
|
||||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
fmt.Fprintln(w, sampleTextFormat)
|
|
||||||
}))
|
|
||||||
defer ts.Close()
|
|
||||||
|
|
||||||
p := &Prometheus{
|
|
||||||
Log: testutil.Logger{},
|
|
||||||
URLs: []string{ts.URL},
|
|
||||||
KubernetesServices: []string{"http://random.telegraf.local:88/metrics"},
|
|
||||||
}
|
|
||||||
|
|
||||||
var acc testutil.Accumulator
|
|
||||||
|
|
||||||
err := acc.GatherError(p.Gather)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
assert.True(t, acc.HasFloatField("go_gc_duration_seconds", "count"))
|
|
||||||
assert.True(t, acc.HasFloatField("go_goroutines", "gauge"))
|
|
||||||
assert.True(t, acc.HasFloatField("test_metric", "value"))
|
|
||||||
assert.True(t, acc.HasTimestamp("test_metric", time.Unix(1490802350, 0)))
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestPrometheusGeneratesSummaryMetricsV2(t *testing.T) {
|
|
||||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
fmt.Fprintln(w, sampleSummaryTextFormat)
|
|
||||||
}))
|
|
||||||
defer ts.Close()
|
|
||||||
|
|
||||||
p := &Prometheus{
|
|
||||||
URLs: []string{ts.URL},
|
|
||||||
URLTag: "url",
|
|
||||||
MetricVersion: 2,
|
|
||||||
}
|
|
||||||
|
|
||||||
var acc testutil.Accumulator
|
|
||||||
|
|
||||||
err := acc.GatherError(p.Gather)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
assert.True(t, acc.TagSetValue("prometheus", "quantile") == "0")
|
|
||||||
assert.True(t, acc.HasFloatField("prometheus", "go_gc_duration_seconds_sum"))
|
|
||||||
assert.True(t, acc.HasFloatField("prometheus", "go_gc_duration_seconds_count"))
|
|
||||||
assert.True(t, acc.TagValue("prometheus", "url") == ts.URL+"/metrics")
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestSummaryMayContainNaN(t *testing.T) {
|
|
||||||
const data = `# HELP go_gc_duration_seconds A summary of the GC invocation durations.
|
|
||||||
# TYPE go_gc_duration_seconds summary
|
|
||||||
go_gc_duration_seconds{quantile="0"} NaN
|
|
||||||
go_gc_duration_seconds{quantile="1"} NaN
|
|
||||||
go_gc_duration_seconds_sum 42.0
|
|
||||||
go_gc_duration_seconds_count 42
|
|
||||||
`
|
|
||||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
fmt.Fprintln(w, data)
|
|
||||||
}))
|
|
||||||
defer ts.Close()
|
|
||||||
|
|
||||||
p := &Prometheus{
|
|
||||||
URLs: []string{ts.URL},
|
|
||||||
URLTag: "",
|
|
||||||
MetricVersion: 2,
|
|
||||||
}
|
|
||||||
|
|
||||||
var acc testutil.Accumulator
|
|
||||||
|
|
||||||
err := p.Gather(&acc)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
expected := []telegraf.Metric{
|
|
||||||
testutil.MustMetric(
|
|
||||||
"prometheus",
|
|
||||||
map[string]string{
|
|
||||||
"quantile": "0",
|
|
||||||
},
|
|
||||||
map[string]interface{}{
|
|
||||||
"go_gc_duration_seconds": math.NaN(),
|
|
||||||
},
|
|
||||||
time.Unix(0, 0),
|
|
||||||
telegraf.Summary,
|
|
||||||
),
|
|
||||||
testutil.MustMetric(
|
|
||||||
"prometheus",
|
|
||||||
map[string]string{
|
|
||||||
"quantile": "1",
|
|
||||||
},
|
|
||||||
map[string]interface{}{
|
|
||||||
"go_gc_duration_seconds": math.NaN(),
|
|
||||||
},
|
|
||||||
time.Unix(0, 0),
|
|
||||||
telegraf.Summary,
|
|
||||||
),
|
|
||||||
testutil.MustMetric(
|
|
||||||
"prometheus",
|
|
||||||
map[string]string{},
|
|
||||||
map[string]interface{}{
|
|
||||||
"go_gc_duration_seconds_sum": 42.0,
|
|
||||||
"go_gc_duration_seconds_count": 42.0,
|
|
||||||
},
|
|
||||||
time.Unix(0, 0),
|
|
||||||
telegraf.Summary,
|
|
||||||
),
|
|
||||||
}
|
|
||||||
|
|
||||||
testutil.RequireMetricsEqual(t, expected, acc.GetTelegrafMetrics(),
|
|
||||||
testutil.IgnoreTime(), testutil.SortMetrics())
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestPrometheusGeneratesGaugeMetricsV2(t *testing.T) {
|
|
||||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
fmt.Fprintln(w, sampleGaugeTextFormat)
|
|
||||||
}))
|
|
||||||
defer ts.Close()
|
|
||||||
|
|
||||||
p := &Prometheus{
|
|
||||||
URLs: []string{ts.URL},
|
|
||||||
URLTag: "url",
|
|
||||||
MetricVersion: 2,
|
|
||||||
}
|
|
||||||
|
|
||||||
var acc testutil.Accumulator
|
|
||||||
|
|
||||||
err := acc.GatherError(p.Gather)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
assert.True(t, acc.HasFloatField("prometheus", "go_goroutines"))
|
|
||||||
assert.True(t, acc.TagValue("prometheus", "url") == ts.URL+"/metrics")
|
|
||||||
assert.True(t, acc.HasTimestamp("prometheus", time.Unix(1490802350, 0)))
|
|
||||||
}
|
|
@ -1,56 +0,0 @@
|
|||||||
package prometheus
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"fmt"
|
|
||||||
"net/http"
|
|
||||||
"testing"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/didi/nightingale/src/modules/monapi/plugins"
|
|
||||||
)
|
|
||||||
|
|
||||||
const sampleTextFormat = `# HELP test_metric An untyped metric with a timestamp
|
|
||||||
# TYPE test_metric untyped
|
|
||||||
test_metric{label="value"} 1.0 1490802350000
|
|
||||||
# HELP helo_stats_test_timer helo_stats_test_timer summary
|
|
||||||
# TYPE helo_stats_test_timer summary
|
|
||||||
helo_stats_test_timer{region="bj",zone="test_1",quantile="0.5"} 0.501462767
|
|
||||||
helo_stats_test_timer{region="bj",zone="test_1",quantile="0.75"} 0.751876572
|
|
||||||
helo_stats_test_timer{region="bj",zone="test_1",quantile="0.95"} 0.978413628
|
|
||||||
helo_stats_test_timer{region="bj",zone="test_1",quantile="0.99"} 0.989530661
|
|
||||||
helo_stats_test_timer{region="bj",zone="test_1",quantile="0.999"} 0.989530661
|
|
||||||
helo_stats_test_timer_sum{region="bj",zone="test_1"} 39.169514066999994
|
|
||||||
helo_stats_test_timer_count{region="bj",zone="test_1"} 74
|
|
||||||
# HELP helo_stats_test_histogram helo_stats_test_histogram histogram
|
|
||||||
# TYPE helo_stats_test_histogram histogram
|
|
||||||
helo_stats_test_histogram_bucket{region="bj",zone="test_1",le="0"} 0
|
|
||||||
helo_stats_test_histogram_bucket{region="bj",zone="test_1",le="0.05"} 0
|
|
||||||
helo_stats_test_histogram_bucket{region="bj",zone="test_1",le="0.1"} 2
|
|
||||||
helo_stats_test_histogram_bucket{region="bj",zone="test_1",le="0.25"} 13
|
|
||||||
helo_stats_test_histogram_bucket{region="bj",zone="test_1",le="0.5"} 24
|
|
||||||
helo_stats_test_histogram_bucket{region="bj",zone="test_1",le="1"} 56
|
|
||||||
helo_stats_test_histogram_bucket{region="bj",zone="test_1",le="3"} 56
|
|
||||||
helo_stats_test_histogram_bucket{region="bj",zone="test_1",le="6"} 56
|
|
||||||
helo_stats_test_histogram_bucket{region="bj",zone="test_1",le="+Inf"} 56
|
|
||||||
helo_stats_test_histogram_sum{region="bj",zone="test_1"} 40.45
|
|
||||||
helo_stats_test_histogram_count{region="bj",zone="test_1"} 56
|
|
||||||
# HELP go_goroutines Number of goroutines that currently exist.
|
|
||||||
# TYPE go_goroutines gauge
|
|
||||||
go_goroutines 15 1490802350000
|
|
||||||
`
|
|
||||||
|
|
||||||
func TestCollect(t *testing.T) {
|
|
||||||
http.HandleFunc("/metrics", func(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, sampleTextFormat) })
|
|
||||||
server := &http.Server{Addr: ":18080"}
|
|
||||||
go func() {
|
|
||||||
server.ListenAndServe()
|
|
||||||
}()
|
|
||||||
defer server.Shutdown(context.Background())
|
|
||||||
|
|
||||||
time.Sleep(time.Millisecond * 100)
|
|
||||||
|
|
||||||
plugins.PluginTest(t, &PrometheusRule{
|
|
||||||
URLs: []string{"http://localhost:18080/metrics"},
|
|
||||||
})
|
|
||||||
}
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Loading…
Reference in new issue