TUN-813: Clean up cloudflared dependencies

This commit is contained in:
Areg Harutyunyan
2018-07-24 18:04:33 -05:00
parent d06fc520c7
commit 0468866626
3310 changed files with 993 additions and 1223303 deletions

View File

@@ -1,6 +0,0 @@
sudo: false
language: go
go:
- 1.7.5
- tip

View File

@@ -1,18 +0,0 @@
# Contributing
Prometheus uses GitHub to manage reviews of pull requests.
* If you have a trivial fix or improvement, go ahead and create a pull request,
addressing (with `@...`) the maintainer of this repository (see
[MAINTAINERS.md](MAINTAINERS.md)) in the description of the pull request.
* If you plan to do something more involved, first discuss your ideas
on our [mailing list](https://groups.google.com/forum/?fromgroups#!forum/prometheus-developers).
This will avoid unnecessary work and surely give you and us a good deal
of inspiration.
* Relevant coding style guidelines are the [Go Code Review
Comments](https://code.google.com/p/go-wiki/wiki/CodeReviewComments)
and the _Formatting and style_ section of Peter Bourgon's [Go: Best
Practices for Production
Environments](http://peter.bourgon.org/go-in-production/#formatting-and-style).

View File

@@ -1 +0,0 @@
* Fabian Reinartz <fabian.reinartz@coreos.com>

View File

@@ -1,12 +0,0 @@
# Common
[![Build Status](https://travis-ci.org/prometheus/common.svg)](https://travis-ci.org/prometheus/common)
This repository contains Go libraries that are shared across Prometheus
components and libraries.
* **config**: Common configuration structures
* **expfmt**: Decoding and encoding for the exposition format
* **log**: A logging wrapper around [logrus](https://github.com/sirupsen/logrus)
* **model**: Shared data structures
* **route**: A routing wrapper around [httprouter](https://github.com/julienschmidt/httprouter) using `context.Context`
* **version**: Version information and metrics

View File

@@ -1,34 +0,0 @@
// Copyright 2016 The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// This package no longer handles safe yaml parsing. In order to
// ensure correct yaml unmarshalling, use "yaml.UnmarshalStrict()".
package config
// Secret special type for storing secrets.
type Secret string
// MarshalYAML implements the yaml.Marshaler interface for Secrets.
func (s Secret) MarshalYAML() (interface{}, error) {
if s != "" {
return "<secret>", nil
}
return nil, nil
}
//UnmarshalYAML implements the yaml.Unmarshaler interface for Secrets.
func (s *Secret) UnmarshalYAML(unmarshal func(interface{}) error) error {
type plain Secret
return unmarshal((*plain)(s))
}

View File

@@ -1,317 +0,0 @@
// Copyright 2016 The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package config
import (
"crypto/tls"
"crypto/x509"
"fmt"
"io/ioutil"
"net/http"
"net/url"
"strings"
"time"
"github.com/mwitkow/go-conntrack"
"gopkg.in/yaml.v2"
)
// BasicAuth contains basic HTTP authentication credentials.
type BasicAuth struct {
Username string `yaml:"username"`
Password Secret `yaml:"password,omitempty"`
PasswordFile string `yaml:"password_file,omitempty"`
}
// URL is a custom URL type that allows validation at configuration load time.
type URL struct {
*url.URL
}
// UnmarshalYAML implements the yaml.Unmarshaler interface for URLs.
func (u *URL) UnmarshalYAML(unmarshal func(interface{}) error) error {
var s string
if err := unmarshal(&s); err != nil {
return err
}
urlp, err := url.Parse(s)
if err != nil {
return err
}
u.URL = urlp
return nil
}
// MarshalYAML implements the yaml.Marshaler interface for URLs.
func (u URL) MarshalYAML() (interface{}, error) {
if u.URL != nil {
return u.String(), nil
}
return nil, nil
}
// HTTPClientConfig configures an HTTP client.
type HTTPClientConfig struct {
// The HTTP basic authentication credentials for the targets.
BasicAuth *BasicAuth `yaml:"basic_auth,omitempty"`
// The bearer token for the targets.
BearerToken Secret `yaml:"bearer_token,omitempty"`
// The bearer token file for the targets.
BearerTokenFile string `yaml:"bearer_token_file,omitempty"`
// HTTP proxy server to use to connect to the targets.
ProxyURL URL `yaml:"proxy_url,omitempty"`
// TLSConfig to use to connect to the targets.
TLSConfig TLSConfig `yaml:"tls_config,omitempty"`
}
// Validate validates the HTTPClientConfig to check only one of BearerToken,
// BasicAuth and BearerTokenFile is configured.
func (c *HTTPClientConfig) Validate() error {
if len(c.BearerToken) > 0 && len(c.BearerTokenFile) > 0 {
return fmt.Errorf("at most one of bearer_token & bearer_token_file must be configured")
}
if c.BasicAuth != nil && (len(c.BearerToken) > 0 || len(c.BearerTokenFile) > 0) {
return fmt.Errorf("at most one of basic_auth, bearer_token & bearer_token_file must be configured")
}
if c.BasicAuth != nil && (string(c.BasicAuth.Password) != "" && c.BasicAuth.PasswordFile != "") {
return fmt.Errorf("at most one of basic_auth password & password_file must be configured")
}
return nil
}
// UnmarshalYAML implements the yaml.Unmarshaler interface
func (c *HTTPClientConfig) UnmarshalYAML(unmarshal func(interface{}) error) error {
type plain HTTPClientConfig
if err := unmarshal((*plain)(c)); err != nil {
return err
}
return c.Validate()
}
// UnmarshalYAML implements the yaml.Unmarshaler interface.
func (a *BasicAuth) UnmarshalYAML(unmarshal func(interface{}) error) error {
type plain BasicAuth
return unmarshal((*plain)(a))
}
// NewClient returns a http.Client using the specified http.RoundTripper.
func newClient(rt http.RoundTripper) *http.Client {
return &http.Client{Transport: rt}
}
// NewClientFromConfig returns a new HTTP client configured for the
// given config.HTTPClientConfig. The name is used as go-conntrack metric label.
func NewClientFromConfig(cfg HTTPClientConfig, name string) (*http.Client, error) {
rt, err := NewRoundTripperFromConfig(cfg, name)
if err != nil {
return nil, err
}
return newClient(rt), nil
}
// NewRoundTripperFromConfig returns a new HTTP RoundTripper configured for the
// given config.HTTPClientConfig. The name is used as go-conntrack metric label.
func NewRoundTripperFromConfig(cfg HTTPClientConfig, name string) (http.RoundTripper, error) {
tlsConfig, err := NewTLSConfig(&cfg.TLSConfig)
if err != nil {
return nil, err
}
// The only timeout we care about is the configured scrape timeout.
// It is applied on request. So we leave out any timings here.
var rt http.RoundTripper = &http.Transport{
Proxy: http.ProxyURL(cfg.ProxyURL.URL),
MaxIdleConns: 20000,
MaxIdleConnsPerHost: 1000, // see https://github.com/golang/go/issues/13801
DisableKeepAlives: false,
TLSClientConfig: tlsConfig,
DisableCompression: true,
// 5 minutes is typically above the maximum sane scrape interval. So we can
// use keepalive for all configurations.
IdleConnTimeout: 5 * time.Minute,
DialContext: conntrack.NewDialContextFunc(
conntrack.DialWithTracing(),
conntrack.DialWithName(name),
),
}
// If a bearer token is provided, create a round tripper that will set the
// Authorization header correctly on each request.
if len(cfg.BearerToken) > 0 {
rt = NewBearerAuthRoundTripper(cfg.BearerToken, rt)
} else if len(cfg.BearerTokenFile) > 0 {
rt = NewBearerAuthFileRoundTripper(cfg.BearerTokenFile, rt)
}
if cfg.BasicAuth != nil {
rt = NewBasicAuthRoundTripper(cfg.BasicAuth.Username, cfg.BasicAuth.Password, cfg.BasicAuth.PasswordFile, rt)
}
// Return a new configured RoundTripper.
return rt, nil
}
type bearerAuthRoundTripper struct {
bearerToken Secret
rt http.RoundTripper
}
// NewBearerAuthRoundTripper adds the provided bearer token to a request unless the authorization
// header has already been set.
func NewBearerAuthRoundTripper(token Secret, rt http.RoundTripper) http.RoundTripper {
return &bearerAuthRoundTripper{token, rt}
}
func (rt *bearerAuthRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
if len(req.Header.Get("Authorization")) == 0 {
req = cloneRequest(req)
req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", string(rt.bearerToken)))
}
return rt.rt.RoundTrip(req)
}
type bearerAuthFileRoundTripper struct {
bearerFile string
rt http.RoundTripper
}
// NewBearerAuthFileRoundTripper adds the bearer token read from the provided file to a request unless
// the authorization header has already been set. This file is read for every request.
func NewBearerAuthFileRoundTripper(bearerFile string, rt http.RoundTripper) http.RoundTripper {
return &bearerAuthFileRoundTripper{bearerFile, rt}
}
func (rt *bearerAuthFileRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
if len(req.Header.Get("Authorization")) == 0 {
b, err := ioutil.ReadFile(rt.bearerFile)
if err != nil {
return nil, fmt.Errorf("unable to read bearer token file %s: %s", rt.bearerFile, err)
}
bearerToken := strings.TrimSpace(string(b))
req = cloneRequest(req)
req.Header.Set("Authorization", "Bearer "+bearerToken)
}
return rt.rt.RoundTrip(req)
}
type basicAuthRoundTripper struct {
username string
password Secret
passwordFile string
rt http.RoundTripper
}
// NewBasicAuthRoundTripper will apply a BASIC auth authorization header to a request unless it has
// already been set.
func NewBasicAuthRoundTripper(username string, password Secret, passwordFile string, rt http.RoundTripper) http.RoundTripper {
return &basicAuthRoundTripper{username, password, passwordFile, rt}
}
func (rt *basicAuthRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
if len(req.Header.Get("Authorization")) != 0 {
return rt.rt.RoundTrip(req)
}
req = cloneRequest(req)
if rt.passwordFile != "" {
bs, err := ioutil.ReadFile(rt.passwordFile)
if err != nil {
return nil, fmt.Errorf("unable to read basic auth password file %s: %s", rt.passwordFile, err)
}
req.SetBasicAuth(rt.username, strings.TrimSpace(string(bs)))
} else {
req.SetBasicAuth(rt.username, strings.TrimSpace(string(rt.password)))
}
return rt.rt.RoundTrip(req)
}
// cloneRequest returns a clone of the provided *http.Request.
// The clone is a shallow copy of the struct and its Header map.
func cloneRequest(r *http.Request) *http.Request {
// Shallow copy of the struct.
r2 := new(http.Request)
*r2 = *r
// Deep copy of the Header.
r2.Header = make(http.Header)
for k, s := range r.Header {
r2.Header[k] = s
}
return r2
}
// NewTLSConfig creates a new tls.Config from the given TLSConfig.
func NewTLSConfig(cfg *TLSConfig) (*tls.Config, error) {
tlsConfig := &tls.Config{InsecureSkipVerify: cfg.InsecureSkipVerify}
// If a CA cert is provided then let's read it in so we can validate the
// scrape target's certificate properly.
if len(cfg.CAFile) > 0 {
caCertPool := x509.NewCertPool()
// Load CA cert.
caCert, err := ioutil.ReadFile(cfg.CAFile)
if err != nil {
return nil, fmt.Errorf("unable to use specified CA cert %s: %s", cfg.CAFile, err)
}
caCertPool.AppendCertsFromPEM(caCert)
tlsConfig.RootCAs = caCertPool
}
if len(cfg.ServerName) > 0 {
tlsConfig.ServerName = cfg.ServerName
}
// If a client cert & key is provided then configure TLS config accordingly.
if len(cfg.CertFile) > 0 && len(cfg.KeyFile) == 0 {
return nil, fmt.Errorf("client cert file %q specified without client key file", cfg.CertFile)
} else if len(cfg.KeyFile) > 0 && len(cfg.CertFile) == 0 {
return nil, fmt.Errorf("client key file %q specified without client cert file", cfg.KeyFile)
} else if len(cfg.CertFile) > 0 && len(cfg.KeyFile) > 0 {
cert, err := tls.LoadX509KeyPair(cfg.CertFile, cfg.KeyFile)
if err != nil {
return nil, fmt.Errorf("unable to use specified client cert (%s) & key (%s): %s", cfg.CertFile, cfg.KeyFile, err)
}
tlsConfig.Certificates = []tls.Certificate{cert}
}
tlsConfig.BuildNameToCertificate()
return tlsConfig, nil
}
// TLSConfig configures the options for TLS connections.
type TLSConfig struct {
// The CA cert to use for the targets.
CAFile string `yaml:"ca_file,omitempty"`
// The client cert file for the targets.
CertFile string `yaml:"cert_file,omitempty"`
// The client key file for the targets.
KeyFile string `yaml:"key_file,omitempty"`
// Used to verify the hostname for the targets.
ServerName string `yaml:"server_name,omitempty"`
// Disable target certificate validation.
InsecureSkipVerify bool `yaml:"insecure_skip_verify"`
}
// UnmarshalYAML implements the yaml.Unmarshaler interface.
func (c *TLSConfig) UnmarshalYAML(unmarshal func(interface{}) error) error {
type plain TLSConfig
return unmarshal((*plain)(c))
}
func (c HTTPClientConfig) String() string {
b, err := yaml.Marshal(c)
if err != nil {
return fmt.Sprintf("<error creating http client config string: %s>", err)
}
return string(b)
}

View File

@@ -1,618 +0,0 @@
// Copyright 2015 The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package config
import (
"crypto/tls"
"crypto/x509"
"fmt"
"io/ioutil"
"net/http"
"net/http/httptest"
"reflect"
"strings"
"testing"
"gopkg.in/yaml.v2"
)
const (
TLSCAChainPath = "testdata/tls-ca-chain.pem"
ServerCertificatePath = "testdata/server.crt"
ServerKeyPath = "testdata/server.key"
BarneyCertificatePath = "testdata/barney.crt"
BarneyKeyNoPassPath = "testdata/barney-no-pass.key"
MissingCA = "missing/ca.crt"
MissingCert = "missing/cert.crt"
MissingKey = "missing/secret.key"
ExpectedMessage = "I'm here to serve you!!!"
BearerToken = "theanswertothegreatquestionoflifetheuniverseandeverythingisfortytwo"
BearerTokenFile = "testdata/bearer.token"
MissingBearerTokenFile = "missing/bearer.token"
ExpectedBearer = "Bearer " + BearerToken
ExpectedUsername = "arthurdent"
ExpectedPassword = "42"
)
var invalidHTTPClientConfigs = []struct {
httpClientConfigFile string
errMsg string
}{
{
httpClientConfigFile: "testdata/http.conf.bearer-token-and-file-set.bad.yml",
errMsg: "at most one of bearer_token & bearer_token_file must be configured",
},
{
httpClientConfigFile: "testdata/http.conf.empty.bad.yml",
errMsg: "at most one of basic_auth, bearer_token & bearer_token_file must be configured",
},
{
httpClientConfigFile: "testdata/http.conf.basic-auth.too-much.bad.yaml",
errMsg: "at most one of basic_auth password & password_file must be configured",
},
}
func newTestServer(handler func(w http.ResponseWriter, r *http.Request)) (*httptest.Server, error) {
testServer := httptest.NewUnstartedServer(http.HandlerFunc(handler))
tlsCAChain, err := ioutil.ReadFile(TLSCAChainPath)
if err != nil {
return nil, fmt.Errorf("Can't read %s", TLSCAChainPath)
}
serverCertificate, err := tls.LoadX509KeyPair(ServerCertificatePath, ServerKeyPath)
if err != nil {
return nil, fmt.Errorf("Can't load X509 key pair %s - %s", ServerCertificatePath, ServerKeyPath)
}
rootCAs := x509.NewCertPool()
rootCAs.AppendCertsFromPEM(tlsCAChain)
testServer.TLS = &tls.Config{
Certificates: make([]tls.Certificate, 1),
RootCAs: rootCAs,
ClientAuth: tls.RequireAndVerifyClientCert,
ClientCAs: rootCAs}
testServer.TLS.Certificates[0] = serverCertificate
testServer.TLS.BuildNameToCertificate()
testServer.StartTLS()
return testServer, nil
}
func TestNewClientFromConfig(t *testing.T) {
var newClientValidConfig = []struct {
clientConfig HTTPClientConfig
handler func(w http.ResponseWriter, r *http.Request)
}{
{
clientConfig: HTTPClientConfig{
TLSConfig: TLSConfig{
CAFile: "",
CertFile: BarneyCertificatePath,
KeyFile: BarneyKeyNoPassPath,
ServerName: "",
InsecureSkipVerify: true},
},
handler: func(w http.ResponseWriter, r *http.Request) {
fmt.Fprint(w, ExpectedMessage)
},
}, {
clientConfig: HTTPClientConfig{
TLSConfig: TLSConfig{
CAFile: TLSCAChainPath,
CertFile: BarneyCertificatePath,
KeyFile: BarneyKeyNoPassPath,
ServerName: "",
InsecureSkipVerify: false},
},
handler: func(w http.ResponseWriter, r *http.Request) {
fmt.Fprint(w, ExpectedMessage)
},
}, {
clientConfig: HTTPClientConfig{
BearerToken: BearerToken,
TLSConfig: TLSConfig{
CAFile: TLSCAChainPath,
CertFile: BarneyCertificatePath,
KeyFile: BarneyKeyNoPassPath,
ServerName: "",
InsecureSkipVerify: false},
},
handler: func(w http.ResponseWriter, r *http.Request) {
bearer := r.Header.Get("Authorization")
if bearer != ExpectedBearer {
fmt.Fprintf(w, "The expected Bearer Authorization (%s) differs from the obtained Bearer Authorization (%s)",
ExpectedBearer, bearer)
} else {
fmt.Fprint(w, ExpectedMessage)
}
},
}, {
clientConfig: HTTPClientConfig{
BearerTokenFile: BearerTokenFile,
TLSConfig: TLSConfig{
CAFile: TLSCAChainPath,
CertFile: BarneyCertificatePath,
KeyFile: BarneyKeyNoPassPath,
ServerName: "",
InsecureSkipVerify: false},
},
handler: func(w http.ResponseWriter, r *http.Request) {
bearer := r.Header.Get("Authorization")
if bearer != ExpectedBearer {
fmt.Fprintf(w, "The expected Bearer Authorization (%s) differs from the obtained Bearer Authorization (%s)",
ExpectedBearer, bearer)
} else {
fmt.Fprint(w, ExpectedMessage)
}
},
}, {
clientConfig: HTTPClientConfig{
BasicAuth: &BasicAuth{
Username: ExpectedUsername,
Password: ExpectedPassword,
},
TLSConfig: TLSConfig{
CAFile: TLSCAChainPath,
CertFile: BarneyCertificatePath,
KeyFile: BarneyKeyNoPassPath,
ServerName: "",
InsecureSkipVerify: false},
},
handler: func(w http.ResponseWriter, r *http.Request) {
username, password, ok := r.BasicAuth()
if !ok {
fmt.Fprintf(w, "The Authorization header wasn't set")
} else if ExpectedUsername != username {
fmt.Fprintf(w, "The expected username (%s) differs from the obtained username (%s).", ExpectedUsername, username)
} else if ExpectedPassword != password {
fmt.Fprintf(w, "The expected password (%s) differs from the obtained password (%s).", ExpectedPassword, password)
} else {
fmt.Fprint(w, ExpectedMessage)
}
},
},
}
for _, validConfig := range newClientValidConfig {
testServer, err := newTestServer(validConfig.handler)
if err != nil {
t.Fatal(err.Error())
}
defer testServer.Close()
client, err := NewClientFromConfig(validConfig.clientConfig, "test")
if err != nil {
t.Errorf("Can't create a client from this config: %+v", validConfig.clientConfig)
continue
}
response, err := client.Get(testServer.URL)
if err != nil {
t.Errorf("Can't connect to the test server using this config: %+v", validConfig.clientConfig)
continue
}
message, err := ioutil.ReadAll(response.Body)
response.Body.Close()
if err != nil {
t.Errorf("Can't read the server response body using this config: %+v", validConfig.clientConfig)
continue
}
trimMessage := strings.TrimSpace(string(message))
if ExpectedMessage != trimMessage {
t.Errorf("The expected message (%s) differs from the obtained message (%s) using this config: %+v",
ExpectedMessage, trimMessage, validConfig.clientConfig)
}
}
}
func TestNewClientFromInvalidConfig(t *testing.T) {
var newClientInvalidConfig = []struct {
clientConfig HTTPClientConfig
errorMsg string
}{
{
clientConfig: HTTPClientConfig{
TLSConfig: TLSConfig{
CAFile: MissingCA,
CertFile: "",
KeyFile: "",
ServerName: "",
InsecureSkipVerify: true},
},
errorMsg: fmt.Sprintf("unable to use specified CA cert %s:", MissingCA),
},
}
for _, invalidConfig := range newClientInvalidConfig {
client, err := NewClientFromConfig(invalidConfig.clientConfig, "test")
if client != nil {
t.Errorf("A client instance was returned instead of nil using this config: %+v", invalidConfig.clientConfig)
}
if err == nil {
t.Errorf("No error was returned using this config: %+v", invalidConfig.clientConfig)
}
if !strings.Contains(err.Error(), invalidConfig.errorMsg) {
t.Errorf("Expected error %s does not contain %s", err.Error(), invalidConfig.errorMsg)
}
}
}
func TestMissingBearerAuthFile(t *testing.T) {
cfg := HTTPClientConfig{
BearerTokenFile: MissingBearerTokenFile,
TLSConfig: TLSConfig{
CAFile: TLSCAChainPath,
CertFile: BarneyCertificatePath,
KeyFile: BarneyKeyNoPassPath,
ServerName: "",
InsecureSkipVerify: false},
}
handler := func(w http.ResponseWriter, r *http.Request) {
bearer := r.Header.Get("Authorization")
if bearer != ExpectedBearer {
fmt.Fprintf(w, "The expected Bearer Authorization (%s) differs from the obtained Bearer Authorization (%s)",
ExpectedBearer, bearer)
} else {
fmt.Fprint(w, ExpectedMessage)
}
}
testServer, err := newTestServer(handler)
if err != nil {
t.Fatal(err.Error())
}
defer testServer.Close()
client, err := NewClientFromConfig(cfg, "test")
if err != nil {
t.Fatal(err)
}
_, err = client.Get(testServer.URL)
if err == nil {
t.Fatal("No error is returned here")
}
if !strings.Contains(err.Error(), "unable to read bearer token file missing/bearer.token: open missing/bearer.token: no such file or directory") {
t.Fatal("wrong error message being returned")
}
}
func TestBearerAuthRoundTripper(t *testing.T) {
const (
newBearerToken = "goodbyeandthankyouforthefish"
)
fakeRoundTripper := NewRoundTripCheckRequest(func(req *http.Request) {
bearer := req.Header.Get("Authorization")
if bearer != ExpectedBearer {
t.Errorf("The expected Bearer Authorization (%s) differs from the obtained Bearer Authorization (%s)",
ExpectedBearer, bearer)
}
}, nil, nil)
// Normal flow.
bearerAuthRoundTripper := NewBearerAuthRoundTripper(BearerToken, fakeRoundTripper)
request, _ := http.NewRequest("GET", "/hitchhiker", nil)
request.Header.Set("User-Agent", "Douglas Adams mind")
bearerAuthRoundTripper.RoundTrip(request)
// Should honor already Authorization header set.
bearerAuthRoundTripperShouldNotModifyExistingAuthorization := NewBearerAuthRoundTripper(newBearerToken, fakeRoundTripper)
request, _ = http.NewRequest("GET", "/hitchhiker", nil)
request.Header.Set("Authorization", ExpectedBearer)
bearerAuthRoundTripperShouldNotModifyExistingAuthorization.RoundTrip(request)
}
func TestBearerAuthFileRoundTripper(t *testing.T) {
const (
newBearerToken = "goodbyeandthankyouforthefish"
)
fakeRoundTripper := NewRoundTripCheckRequest(func(req *http.Request) {
bearer := req.Header.Get("Authorization")
if bearer != ExpectedBearer {
t.Errorf("The expected Bearer Authorization (%s) differs from the obtained Bearer Authorization (%s)",
ExpectedBearer, bearer)
}
}, nil, nil)
// Normal flow.
bearerAuthRoundTripper := NewBearerAuthFileRoundTripper(BearerTokenFile, fakeRoundTripper)
request, _ := http.NewRequest("GET", "/hitchhiker", nil)
request.Header.Set("User-Agent", "Douglas Adams mind")
bearerAuthRoundTripper.RoundTrip(request)
// Should honor already Authorization header set.
bearerAuthRoundTripperShouldNotModifyExistingAuthorization := NewBearerAuthFileRoundTripper(MissingBearerTokenFile, fakeRoundTripper)
request, _ = http.NewRequest("GET", "/hitchhiker", nil)
request.Header.Set("Authorization", ExpectedBearer)
bearerAuthRoundTripperShouldNotModifyExistingAuthorization.RoundTrip(request)
}
func TestTLSConfig(t *testing.T) {
configTLSConfig := TLSConfig{
CAFile: TLSCAChainPath,
CertFile: BarneyCertificatePath,
KeyFile: BarneyKeyNoPassPath,
ServerName: "localhost",
InsecureSkipVerify: false}
tlsCAChain, err := ioutil.ReadFile(TLSCAChainPath)
if err != nil {
t.Fatalf("Can't read the CA certificate chain (%s)",
TLSCAChainPath)
}
rootCAs := x509.NewCertPool()
rootCAs.AppendCertsFromPEM(tlsCAChain)
barneyCertificate, err := tls.LoadX509KeyPair(BarneyCertificatePath, BarneyKeyNoPassPath)
if err != nil {
t.Fatalf("Can't load the client key pair ('%s' and '%s'). Reason: %s",
BarneyCertificatePath, BarneyKeyNoPassPath, err)
}
expectedTLSConfig := &tls.Config{
RootCAs: rootCAs,
Certificates: []tls.Certificate{barneyCertificate},
ServerName: configTLSConfig.ServerName,
InsecureSkipVerify: configTLSConfig.InsecureSkipVerify}
expectedTLSConfig.BuildNameToCertificate()
tlsConfig, err := NewTLSConfig(&configTLSConfig)
if err != nil {
t.Fatalf("Can't create a new TLS Config from a configuration (%s).", err)
}
if !reflect.DeepEqual(tlsConfig, expectedTLSConfig) {
t.Fatalf("Unexpected TLS Config result: \n\n%+v\n expected\n\n%+v", tlsConfig, expectedTLSConfig)
}
}
func TestTLSConfigEmpty(t *testing.T) {
configTLSConfig := TLSConfig{
CAFile: "",
CertFile: "",
KeyFile: "",
ServerName: "",
InsecureSkipVerify: true}
expectedTLSConfig := &tls.Config{
InsecureSkipVerify: configTLSConfig.InsecureSkipVerify}
expectedTLSConfig.BuildNameToCertificate()
tlsConfig, err := NewTLSConfig(&configTLSConfig)
if err != nil {
t.Fatalf("Can't create a new TLS Config from a configuration (%s).", err)
}
if !reflect.DeepEqual(tlsConfig, expectedTLSConfig) {
t.Fatalf("Unexpected TLS Config result: \n\n%+v\n expected\n\n%+v", tlsConfig, expectedTLSConfig)
}
}
func TestTLSConfigInvalidCA(t *testing.T) {
var invalidTLSConfig = []struct {
configTLSConfig TLSConfig
errorMessage string
}{
{
configTLSConfig: TLSConfig{
CAFile: MissingCA,
CertFile: "",
KeyFile: "",
ServerName: "",
InsecureSkipVerify: false},
errorMessage: fmt.Sprintf("unable to use specified CA cert %s:", MissingCA),
}, {
configTLSConfig: TLSConfig{
CAFile: "",
CertFile: MissingCert,
KeyFile: BarneyKeyNoPassPath,
ServerName: "",
InsecureSkipVerify: false},
errorMessage: fmt.Sprintf("unable to use specified client cert (%s) & key (%s):", MissingCert, BarneyKeyNoPassPath),
}, {
configTLSConfig: TLSConfig{
CAFile: "",
CertFile: BarneyCertificatePath,
KeyFile: MissingKey,
ServerName: "",
InsecureSkipVerify: false},
errorMessage: fmt.Sprintf("unable to use specified client cert (%s) & key (%s):", BarneyCertificatePath, MissingKey),
},
}
for _, anInvalididTLSConfig := range invalidTLSConfig {
tlsConfig, err := NewTLSConfig(&anInvalididTLSConfig.configTLSConfig)
if tlsConfig != nil && err == nil {
t.Errorf("The TLS Config could be created even with this %+v", anInvalididTLSConfig.configTLSConfig)
continue
}
if !strings.Contains(err.Error(), anInvalididTLSConfig.errorMessage) {
t.Errorf("The expected error should contain %s, but got %s", anInvalididTLSConfig.errorMessage, err)
}
}
}
func TestBasicAuthNoPassword(t *testing.T) {
cfg, _, err := LoadHTTPConfigFile("testdata/http.conf.basic-auth.no-password.yaml")
if err != nil {
t.Errorf("Error loading HTTP client config: %v", err)
}
client, err := NewClientFromConfig(*cfg, "test")
if err != nil {
t.Errorf("Error creating HTTP Client: %v", err)
}
rt, ok := client.Transport.(*basicAuthRoundTripper)
if !ok {
t.Fatalf("Error casting to basic auth transport, %v", client.Transport)
}
if rt.username != "user" {
t.Errorf("Bad HTTP client username: %s", rt.username)
}
if string(rt.password) != "" {
t.Errorf("Expected empty HTTP client password: %s", rt.password)
}
if string(rt.passwordFile) != "" {
t.Errorf("Expected empty HTTP client passwordFile: %s", rt.passwordFile)
}
}
func TestBasicAuthNoUsername(t *testing.T) {
cfg, _, err := LoadHTTPConfigFile("testdata/http.conf.basic-auth.no-username.yaml")
if err != nil {
t.Errorf("Error loading HTTP client config: %v", err)
}
client, err := NewClientFromConfig(*cfg, "test")
if err != nil {
t.Errorf("Error creating HTTP Client: %v", err)
}
rt, ok := client.Transport.(*basicAuthRoundTripper)
if !ok {
t.Fatalf("Error casting to basic auth transport, %v", client.Transport)
}
if rt.username != "" {
t.Errorf("Got unexpected username: %s", rt.username)
}
if string(rt.password) != "secret" {
t.Errorf("Unexpected HTTP client password: %s", string(rt.password))
}
if string(rt.passwordFile) != "" {
t.Errorf("Expected empty HTTP client passwordFile: %s", rt.passwordFile)
}
}
func TestBasicAuthPasswordFile(t *testing.T) {
cfg, _, err := LoadHTTPConfigFile("testdata/http.conf.basic-auth.good.yaml")
if err != nil {
t.Errorf("Error loading HTTP client config: %v", err)
}
client, err := NewClientFromConfig(*cfg, "test")
if err != nil {
t.Errorf("Error creating HTTP Client: %v", err)
}
rt, ok := client.Transport.(*basicAuthRoundTripper)
if !ok {
t.Errorf("Error casting to basic auth transport, %v", client.Transport)
}
if rt.username != "user" {
t.Errorf("Bad HTTP client username: %s", rt.username)
}
if string(rt.password) != "" {
t.Errorf("Bad HTTP client password: %s", rt.password)
}
if string(rt.passwordFile) != "testdata/basic-auth-password" {
t.Errorf("Bad HTTP client passwordFile: %s", rt.passwordFile)
}
}
func TestHideHTTPClientConfigSecrets(t *testing.T) {
c, _, err := LoadHTTPConfigFile("testdata/http.conf.good.yml")
if err != nil {
t.Errorf("Error parsing %s: %s", "testdata/http.conf.good.yml", err)
}
// String method must not reveal authentication credentials.
s := c.String()
if strings.Contains(s, "mysecret") {
t.Fatal("http client config's String method reveals authentication credentials.")
}
}
func TestValidateHTTPConfig(t *testing.T) {
cfg, _, err := LoadHTTPConfigFile("testdata/http.conf.good.yml")
if err != nil {
t.Errorf("Error loading HTTP client config: %v", err)
}
err = cfg.Validate()
if err != nil {
t.Fatalf("Error validating %s: %s", "testdata/http.conf.good.yml", err)
}
}
func TestInvalidHTTPConfigs(t *testing.T) {
for _, ee := range invalidHTTPClientConfigs {
_, _, err := LoadHTTPConfigFile(ee.httpClientConfigFile)
if err == nil {
t.Error("Expected error with config but got none")
continue
}
if !strings.Contains(err.Error(), ee.errMsg) {
t.Errorf("Expected error for invalid HTTP client configuration to contain %q but got: %s", ee.errMsg, err)
}
}
}
// LoadHTTPConfig parses the YAML input s into a HTTPClientConfig.
func LoadHTTPConfig(s string) (*HTTPClientConfig, error) {
cfg := &HTTPClientConfig{}
err := yaml.UnmarshalStrict([]byte(s), cfg)
if err != nil {
return nil, err
}
return cfg, nil
}
// LoadHTTPConfigFile parses the given YAML file into a HTTPClientConfig.
func LoadHTTPConfigFile(filename string) (*HTTPClientConfig, []byte, error) {
content, err := ioutil.ReadFile(filename)
if err != nil {
return nil, nil, err
}
cfg, err := LoadHTTPConfig(string(content))
if err != nil {
return nil, nil, err
}
return cfg, content, nil
}
type roundTrip struct {
theResponse *http.Response
theError error
}
func (rt *roundTrip) RoundTrip(r *http.Request) (*http.Response, error) {
return rt.theResponse, rt.theError
}
type roundTripCheckRequest struct {
checkRequest func(*http.Request)
roundTrip
}
func (rt *roundTripCheckRequest) RoundTrip(r *http.Request) (*http.Response, error) {
rt.checkRequest(r)
return rt.theResponse, rt.theError
}
// NewRoundTripCheckRequest creates a new instance of a type that implements http.RoundTripper,
// which before returning theResponse and theError, executes checkRequest against a http.Request.
func NewRoundTripCheckRequest(checkRequest func(*http.Request), theResponse *http.Response, theError error) http.RoundTripper {
return &roundTripCheckRequest{
checkRequest: checkRequest,
roundTrip: roundTrip{
theResponse: theResponse,
theError: theError}}
}

View File

@@ -1,27 +0,0 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEpQIBAAKCAQEAxmYjfBZhZbAup9uSULehoqPCv/U+77ETxUNyS2nviWEHDAb/
pFS8Btx4oCQ1ECVSyxcUmXSlrvDjMY4sisOHvndNRlGi274M5a8Q5yD1BUqvxq3u
XB/+SYNVShBzaswrSjpzMe89AlOPxPjnE14OXh00j2hHunOG4jhlWgJnY0YyvUQQ
YWO6KrmKMiZ4MgmY0SWh/ZhlkDJPtkp3aUVM2sheCru/70E9viLGfdlhc2pIMshy
wNp4/5IkHBZwbqXFFGX4sRtSXI/auZNvcHOBse+3e3BonWvBWS2lIYbzpX3vLB7B
E9BGIxWn1fgNQr14yFPaccSszBvgtmEUONolnwIDAQABAoIBAQC7nBhQHgXKGBl2
Z97rb0pstrjRtsLl/Cg68LWi9LEr0tHMIM4bgnkvb8qtfK+k7fZl0BSNrE2EqYvd
75jVO2MgzEYJieccLpKZm7u7JGIut9qSYSU2fpaCw6uiVv4dbqY9EhqejKG/km8w
j0JMATRK8Qkj1zOE7/wL7dKBlCZaK3u+OT17spuA/21PG/cLiPaSGSA3CU/eqbkU
BD6JeBxp33XNTytwWoOvarsigpL0dGqQ7+qhGq6t69qFfWoe9rimV7Ya+tB9zF/U
HzOIEspOYvzxe+C7VJjlVFr4haMYmsrO9qRUJ2ofp49OLVdfEANsdVISSvS63BEp
gBZN8Ko5AoGBAO1z8y8YCsI+2vBG6nxZ1eMba0KHi3bS8db1TaenJBV22w6WQATh
hEaU6VLMFcMvrOUjXN/7HJfnEMyvFT6gb9obPDVEMZw88s9lVN6njgGLZR/jodyN
7N7utLopN043Ra0WfEILAXPSz8esT1yn05OZV6AFHxJEWMrX3/4+spCLAoGBANXl
RomieVY4u3FF/uzhbzKNNb9ETxrQuexfbangKp5eLniwnr2SQWIbyPzeurwp15J8
HvxB2vpNvs1khSwNx9dQfMdiUVPGLWj7MimAHTHsnQ9LVV9W28ghuSWbjQDGTUt1
WCCu1MkKIOzupbi+zgsNlI33yilRQKAb9SRxdy29AoGBAOKpvyZiPcrkMxwPpb/k
BU7QGpgcSR25CQ+Xg3QZEVHH7h1DgYLnPtwdQ4g8tj1mohTsp7hKvSWndRrdulrY
zUyWmOeD3BN2/pTI9rW/nceNp49EPHsLo2O+2xelRlzMWB98ikqEtPM59gt1SSB6
N3X6d3GR0fIe+d9PKEtK0Cs3AoGAZ9r8ReXSvm+ra5ON9Nx8znHMEAON2TpRnBi1
uY7zgpO+QrGXUfqKrqVJEKbgym4SkribnuYm+fP32eid1McYKk6VV4ZAcMm/0MJv
F8Fx64S0ufFdEX6uFl1xdXYyn5apfyMJ2EyrWrYFSKWTZ8GVb753S/tteGRQWa1Z
eQly0Y0CgYEAnI6G9KFvXI+MLu5y2LPYAwsesDFzaWwyDl96ioQTA9hNSrjR33Vw
xwpiEe0T/WKF8NQ0QWnrQDbTvuCvZUK37TVxscYWuItL6vnBrYqr4Ck0j1BcGwV5
jT581A/Vw8JJiR/vfcxgmrFYqoUmkMKDmCN1oImfz09GtQ4jQ1rlxz8=
-----END RSA PRIVATE KEY-----

View File

@@ -1,96 +0,0 @@
Certificate:
Data:
Version: 3 (0x2)
Serial Number: 2 (0x2)
Signature Algorithm: sha1WithRSAEncryption
Issuer: C=NO, O=Green AS, OU=Green Certificate Authority, CN=Green TLS CA
Validity
Not Before: Jul 13 04:02:47 2017 GMT
Not After : Jul 13 04:02:47 2019 GMT
Subject: C=NO, O=Telenor AS, OU=Support, CN=Barney Rubble
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
Public-Key: (2048 bit)
Modulus:
00:c6:66:23:7c:16:61:65:b0:2e:a7:db:92:50:b7:
a1:a2:a3:c2:bf:f5:3e:ef:b1:13:c5:43:72:4b:69:
ef:89:61:07:0c:06:ff:a4:54:bc:06:dc:78:a0:24:
35:10:25:52:cb:17:14:99:74:a5:ae:f0:e3:31:8e:
2c:8a:c3:87:be:77:4d:46:51:a2:db:be:0c:e5:af:
10:e7:20:f5:05:4a:af:c6:ad:ee:5c:1f:fe:49:83:
55:4a:10:73:6a:cc:2b:4a:3a:73:31:ef:3d:02:53:
8f:c4:f8:e7:13:5e:0e:5e:1d:34:8f:68:47:ba:73:
86:e2:38:65:5a:02:67:63:46:32:bd:44:10:61:63:
ba:2a:b9:8a:32:26:78:32:09:98:d1:25:a1:fd:98:
65:90:32:4f:b6:4a:77:69:45:4c:da:c8:5e:0a:bb:
bf:ef:41:3d:be:22:c6:7d:d9:61:73:6a:48:32:c8:
72:c0:da:78:ff:92:24:1c:16:70:6e:a5:c5:14:65:
f8:b1:1b:52:5c:8f:da:b9:93:6f:70:73:81:b1:ef:
b7:7b:70:68:9d:6b:c1:59:2d:a5:21:86:f3:a5:7d:
ef:2c:1e:c1:13:d0:46:23:15:a7:d5:f8:0d:42:bd:
78:c8:53:da:71:c4:ac:cc:1b:e0:b6:61:14:38:da:
25:9f
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Key Usage: critical
Digital Signature
X509v3 Basic Constraints:
CA:FALSE
X509v3 Extended Key Usage:
TLS Web Client Authentication
X509v3 Subject Key Identifier:
F4:17:02:DD:1B:01:AB:C5:BC:17:A4:5C:4B:75:8E:EC:B1:E0:C8:F1
X509v3 Authority Key Identifier:
keyid:AE:42:88:75:DD:05:A6:8E:48:7F:50:69:F9:B7:34:23:49:B8:B4:71
Authority Information Access:
CA Issuers - URI:http://green.no/ca/tls-ca.cer
X509v3 CRL Distribution Points:
Full Name:
URI:http://green.no/ca/tls-ca.crl
X509v3 Subject Alternative Name:
email:barney@telenor.no
Signature Algorithm: sha1WithRSAEncryption
96:9a:c5:41:8a:2f:4a:c4:80:d9:2b:1a:cf:07:85:e9:b6:18:
01:20:41:b9:c3:d4:ca:d3:2d:66:c3:1d:52:7f:25:d7:92:0c:
e9:a9:ae:e6:2e:fa:9d:0a:cf:84:b9:03:f2:63:e3:d3:c9:70:
6a:ac:04:5e:a9:2d:a2:43:7a:34:60:f7:a9:32:e1:48:ec:c6:
03:ac:b3:06:2e:48:6e:d0:35:11:31:3d:0c:04:66:41:e6:b2:
ec:8c:68:f8:e4:bc:47:85:39:60:69:a9:8a:ee:2f:56:88:8a:
19:45:d0:84:8e:c2:27:2c:82:9c:07:6c:34:ae:41:61:63:f9:
32:cb:8b:33:ea:2c:15:5f:f9:35:b0:3c:51:4d:5f:30:de:0b:
88:28:94:79:f3:bd:69:37:ad:12:20:e1:6b:1d:b6:77:d9:83:
db:81:a4:53:6c:0f:6a:17:5e:2b:c1:94:c6:42:e3:73:cd:9e:
79:1b:8c:89:cd:da:ce:b0:f4:21:c5:32:25:04:6e:68:9f:a7:
ca:f4:c5:86:e5:4e:d9:fd:69:73:e6:15:50:6e:76:0f:73:5e:
7a:a3:f4:dc:15:4a:ab:bb:3c:9a:fa:9f:01:7a:5c:47:a9:a3:
68:1c:49:e0:37:37:77:af:87:07:16:e4:e1:d7:98:39:15:a6:
51:5d:4c:db
-----BEGIN CERTIFICATE-----
MIIEITCCAwmgAwIBAgIBAjANBgkqhkiG9w0BAQUFADBdMQswCQYDVQQGEwJOTzER
MA8GA1UECgwIR3JlZW4gQVMxJDAiBgNVBAsMG0dyZWVuIENlcnRpZmljYXRlIEF1
dGhvcml0eTEVMBMGA1UEAwwMR3JlZW4gVExTIENBMB4XDTE3MDcxMzA0MDI0N1oX
DTE5MDcxMzA0MDI0N1owTDELMAkGA1UEBhMCTk8xEzARBgNVBAoMClRlbGVub3Ig
QVMxEDAOBgNVBAsMB1N1cHBvcnQxFjAUBgNVBAMMDUJhcm5leSBSdWJibGUwggEi
MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDGZiN8FmFlsC6n25JQt6Gio8K/
9T7vsRPFQ3JLae+JYQcMBv+kVLwG3HigJDUQJVLLFxSZdKWu8OMxjiyKw4e+d01G
UaLbvgzlrxDnIPUFSq/Gre5cH/5Jg1VKEHNqzCtKOnMx7z0CU4/E+OcTXg5eHTSP
aEe6c4biOGVaAmdjRjK9RBBhY7oquYoyJngyCZjRJaH9mGWQMk+2SndpRUzayF4K
u7/vQT2+IsZ92WFzakgyyHLA2nj/kiQcFnBupcUUZfixG1Jcj9q5k29wc4Gx77d7
cGida8FZLaUhhvOlfe8sHsET0EYjFafV+A1CvXjIU9pxxKzMG+C2YRQ42iWfAgMB
AAGjgfwwgfkwDgYDVR0PAQH/BAQDAgeAMAkGA1UdEwQCMAAwEwYDVR0lBAwwCgYI
KwYBBQUHAwIwHQYDVR0OBBYEFPQXAt0bAavFvBekXEt1juyx4MjxMB8GA1UdIwQY
MBaAFK5CiHXdBaaOSH9Qafm3NCNJuLRxMDkGCCsGAQUFBwEBBC0wKzApBggrBgEF
BQcwAoYdaHR0cDovL2dyZWVuLm5vL2NhL3Rscy1jYS5jZXIwLgYDVR0fBCcwJTAj
oCGgH4YdaHR0cDovL2dyZWVuLm5vL2NhL3Rscy1jYS5jcmwwHAYDVR0RBBUwE4ER
YmFybmV5QHRlbGVub3Iubm8wDQYJKoZIhvcNAQEFBQADggEBAJaaxUGKL0rEgNkr
Gs8Hhem2GAEgQbnD1MrTLWbDHVJ/JdeSDOmpruYu+p0Kz4S5A/Jj49PJcGqsBF6p
LaJDejRg96ky4UjsxgOsswYuSG7QNRExPQwEZkHmsuyMaPjkvEeFOWBpqYruL1aI
ihlF0ISOwicsgpwHbDSuQWFj+TLLizPqLBVf+TWwPFFNXzDeC4golHnzvWk3rRIg
4WsdtnfZg9uBpFNsD2oXXivBlMZC43PNnnkbjInN2s6w9CHFMiUEbmifp8r0xYbl
Ttn9aXPmFVBudg9zXnqj9NwVSqu7PJr6nwF6XEepo2gcSeA3N3evhwcW5OHXmDkV
plFdTNs=
-----END CERTIFICATE-----

View File

@@ -1 +0,0 @@
foobar

View File

@@ -1 +0,0 @@
theanswertothegreatquestionoflifetheuniverseandeverythingisfortytwo

View File

@@ -1,3 +0,0 @@
basic_auth:
username: user
password_file: testdata/basic-auth-password

View File

@@ -1,2 +0,0 @@
basic_auth:
username: user

View File

@@ -1,2 +0,0 @@
basic_auth:
password: secret

View File

@@ -1,4 +0,0 @@
basic_auth:
username: user
password: foo
password_file: testdata/basic-auth-password

View File

@@ -1,5 +0,0 @@
basic_auth:
username: username
password: "mysecret"
bearer_token: mysecret
bearer_token_file: file

View File

@@ -1,4 +0,0 @@
basic_auth:
username: username
password: mysecret
bearer_token_file: file

View File

@@ -1,4 +0,0 @@
basic_auth:
username: username
password: "mysecret"
proxy_url: "http://remote.host"

View File

@@ -1 +0,0 @@
bearer_token_file: file

View File

@@ -1,96 +0,0 @@
Certificate:
Data:
Version: 3 (0x2)
Serial Number: 4 (0x4)
Signature Algorithm: sha1WithRSAEncryption
Issuer: C=NO, O=Green AS, OU=Green Certificate Authority, CN=Green TLS CA
Validity
Not Before: Jul 26 12:47:08 2017 GMT
Not After : Jul 26 12:47:08 2019 GMT
Subject: C=NO, O=Green AS, OU=Green Certificate Authority, CN=Green TLS CA
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
Public-Key: (2048 bit)
Modulus:
00:97:43:c5:f6:24:b8:ce:30:12:70:ea:17:9c:c0:
ce:f2:ef:58:8b:12:7d:46:5e:01:f1:1a:93:b2:3e:
d8:cf:99:bc:10:32:f1:12:b0:ef:00:6c:d6:c4:45:
85:a8:33:7b:cd:ec:8f:4a:92:d0:5a:4a:41:69:7f:
e3:dd:7e:71:d2:21:9c:df:43:b5:6c:60:bb:2a:12:
a8:08:cf:c5:ee:08:7d:48:ea:4b:54:e4:82:d9:88:
b0:b8:5e:02:12:cb:0e:09:99:b7:5f:42:b6:d7:26:
34:0f:4a:e7:fc:ac:9c:59:cd:a1:50:4c:88:5f:f1:
d2:7e:5b:21:41:f0:37:50:80:48:71:50:26:61:26:
79:64:4b:7e:91:8d:0e:f4:27:fe:19:80:bf:39:55:
b7:f3:d0:cd:61:6c:d8:c1:c7:d3:26:77:92:1a:14:
42:56:cb:bc:fd:1a:4a:eb:17:d8:8d:af:d1:c0:46:
9f:f0:40:5e:0e:34:2f:e7:db:be:66:fd:89:0b:6b:
8c:71:c1:0b:0a:c5:c4:c4:eb:7f:44:c1:75:36:23:
fd:ed:b6:ee:87:d9:88:47:e1:4b:7c:60:53:e7:85:
1c:2f:82:4b:2b:5e:63:1a:49:17:36:2c:fc:39:23:
49:22:4d:43:b5:51:22:12:24:9e:31:44:d8:16:4e:
a8:eb
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Key Usage: critical
Digital Signature, Key Encipherment
X509v3 Basic Constraints:
CA:FALSE
X509v3 Extended Key Usage:
TLS Web Server Authentication, TLS Web Client Authentication
X509v3 Subject Key Identifier:
70:A9:FB:44:66:3C:63:96:E6:05:B2:74:47:C8:18:7E:43:6D:EE:8B
X509v3 Authority Key Identifier:
keyid:AE:42:88:75:DD:05:A6:8E:48:7F:50:69:F9:B7:34:23:49:B8:B4:71
Authority Information Access:
CA Issuers - URI:http://green.no/ca/tls-ca.cer
X509v3 CRL Distribution Points:
Full Name:
URI:http://green.no/ca/tls-ca.crl
X509v3 Subject Alternative Name:
IP Address:127.0.0.1, IP Address:127.0.0.0, DNS:localhost
Signature Algorithm: sha1WithRSAEncryption
56:1e:b8:52:ba:f5:72:42:ad:15:71:c1:5e:00:63:c9:4d:56:
f2:8d:a3:a9:91:db:d0:b5:1b:88:80:93:80:28:48:b2:d0:a9:
d0:ea:de:40:78:cc:57:8c:00:b8:65:99:68:95:98:9b:fb:a2:
43:21:ea:00:37:01:77:c7:3b:1a:ec:58:2d:25:9c:ad:23:41:
5e:ae:fd:ac:2f:26:81:b8:a7:49:9b:5a:10:fe:ad:c3:86:ab:
59:67:b0:c7:81:72:95:60:b5:cb:fc:9f:ad:27:16:50:85:76:
33:16:20:2c:1f:c6:14:09:0c:48:9f:c0:19:16:c9:fa:b0:d8:
bf:b7:8d:a7:aa:eb:fe:f8:6f:dd:2b:83:ee:c7:8a:df:c8:59:
e6:2e:13:1f:57:cc:6f:31:db:f7:b7:5c:3f:78:ad:22:2c:48:
bb:6d:c4:ab:dc:c1:76:34:29:d9:1e:67:e0:ac:37:2b:90:f9:
71:bd:cf:a1:01:b9:eb:0b:0b:79:2e:8b:52:3d:8e:13:97:c8:
05:a3:ef:68:82:49:12:2a:25:1a:48:49:b8:7c:3c:66:0d:74:
f9:00:8c:5b:57:d7:76:b1:26:95:86:b2:2e:a3:b2:9c:e0:eb:
2d:fc:77:03:8f:cd:56:46:3a:c9:6a:fa:72:e3:19:d8:ef:de:
4b:36:95:79
-----BEGIN CERTIFICATE-----
MIIEQjCCAyqgAwIBAgIBBDANBgkqhkiG9w0BAQUFADBdMQswCQYDVQQGEwJOTzER
MA8GA1UECgwIR3JlZW4gQVMxJDAiBgNVBAsMG0dyZWVuIENlcnRpZmljYXRlIEF1
dGhvcml0eTEVMBMGA1UEAwwMR3JlZW4gVExTIENBMB4XDTE3MDcyNjEyNDcwOFoX
DTE5MDcyNjEyNDcwOFowXTELMAkGA1UEBhMCTk8xETAPBgNVBAoMCEdyZWVuIEFT
MSQwIgYDVQQLDBtHcmVlbiBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkxFTATBgNVBAMM
DEdyZWVuIFRMUyBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJdD
xfYkuM4wEnDqF5zAzvLvWIsSfUZeAfEak7I+2M+ZvBAy8RKw7wBs1sRFhagze83s
j0qS0FpKQWl/491+cdIhnN9DtWxguyoSqAjPxe4IfUjqS1TkgtmIsLheAhLLDgmZ
t19CttcmNA9K5/ysnFnNoVBMiF/x0n5bIUHwN1CASHFQJmEmeWRLfpGNDvQn/hmA
vzlVt/PQzWFs2MHH0yZ3khoUQlbLvP0aSusX2I2v0cBGn/BAXg40L+fbvmb9iQtr
jHHBCwrFxMTrf0TBdTYj/e227ofZiEfhS3xgU+eFHC+CSyteYxpJFzYs/DkjSSJN
Q7VRIhIknjFE2BZOqOsCAwEAAaOCAQswggEHMA4GA1UdDwEB/wQEAwIFoDAJBgNV
HRMEAjAAMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAdBgNVHQ4EFgQU
cKn7RGY8Y5bmBbJ0R8gYfkNt7oswHwYDVR0jBBgwFoAUrkKIdd0Fpo5If1Bp+bc0
I0m4tHEwOQYIKwYBBQUHAQEELTArMCkGCCsGAQUFBzAChh1odHRwOi8vZ3JlZW4u
bm8vY2EvdGxzLWNhLmNlcjAuBgNVHR8EJzAlMCOgIaAfhh1odHRwOi8vZ3JlZW4u
bm8vY2EvdGxzLWNhLmNybDAgBgNVHREEGTAXhwR/AAABhwR/AAAAgglsb2NhbGhv
c3QwDQYJKoZIhvcNAQEFBQADggEBAFYeuFK69XJCrRVxwV4AY8lNVvKNo6mR29C1
G4iAk4AoSLLQqdDq3kB4zFeMALhlmWiVmJv7okMh6gA3AXfHOxrsWC0lnK0jQV6u
/awvJoG4p0mbWhD+rcOGq1lnsMeBcpVgtcv8n60nFlCFdjMWICwfxhQJDEifwBkW
yfqw2L+3jaeq6/74b90rg+7Hit/IWeYuEx9XzG8x2/e3XD94rSIsSLttxKvcwXY0
KdkeZ+CsNyuQ+XG9z6EBuesLC3kui1I9jhOXyAWj72iCSRIqJRpISbh8PGYNdPkA
jFtX13axJpWGsi6jspzg6y38dwOPzVZGOslq+nLjGdjv3ks2lXk=
-----END CERTIFICATE-----

View File

@@ -1,28 +0,0 @@
-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCXQ8X2JLjOMBJw
6hecwM7y71iLEn1GXgHxGpOyPtjPmbwQMvESsO8AbNbERYWoM3vN7I9KktBaSkFp
f+PdfnHSIZzfQ7VsYLsqEqgIz8XuCH1I6ktU5ILZiLC4XgISyw4JmbdfQrbXJjQP
Suf8rJxZzaFQTIhf8dJ+WyFB8DdQgEhxUCZhJnlkS36RjQ70J/4ZgL85Vbfz0M1h
bNjBx9Mmd5IaFEJWy7z9GkrrF9iNr9HARp/wQF4ONC/n275m/YkLa4xxwQsKxcTE
639EwXU2I/3ttu6H2YhH4Ut8YFPnhRwvgksrXmMaSRc2LPw5I0kiTUO1USISJJ4x
RNgWTqjrAgMBAAECggEAVurwo4FyV7gzwIIi00XPJLT3ceJL7dUy1HHrEG8gchnq
gHxlHdJhYyMnPVydcosyxp75r2YxJtCoSZDdRHbVvGLoGzpy0zW6FnDl8TpCh4aF
RxKp+rvbnFf5A9ew5U+cX1PelHRnT7V6EJeAOiaNKOUJnnR7oHX59/UxZQw9HJnX
3H4xUdRDmSS3BGKXEswbd7beQjqJtEIkbConfaw32yEod0w2MC0LI4miZ87/6Hsk
pyvfpeYxXp4z3BTvFBbf/GEBFuozu63VWHayB9PDmEN/TlphoQpJQihdR2r1lz/H
I5QwVlFTDvUSFitNLu+FoaHOfgLprQndbojBXb+tcQKBgQDHCPyM4V7k97RvJgmB
ELgZiDYufDrjRLXvFzrrZ7ySU3N+nx3Gz/EhtgbHicDjnRVagHBIwi/QAfBJksCd
xcioY5k2OW+8PSTsfFZTAA6XwJp/LGfJik/JjvAVv5CnxBu9lYG4WiSBJFp59ojC
zTmfEuB4GPwrjQvzjlqaSpij9QKBgQDCjriwAB2UJIdlgK+DkryLqgim5I4cteB3
+juVKz+S8ufFmVvmIXkyDcpyy/26VLC6esy8dV0JoWc4EeitoJvQD1JVZ5+CBTY+
r9umx18oe2A/ZgcEf/A3Zd94jM1MwriF6YC+eIOhwhpi7T1xTLf3hc9B0OJ5B1mA
vob9rGDtXwKBgD4rkW+UCictNIAvenKFPWxEPuBgT6ij0sx/DhlwCtgOFxprK0rp
syFbkVyMq+KtM3lUez5O4c5wfJUOsPnXSOlISxhD8qHy23C/GdvNPcGrGNc2kKjE
ek20R0wTzWSJ/jxG0gE6rwJjz5sfJfLrVd9ZbyI0c7hK03vdcHGXcXxtAoGAeGHl
BwnbQ3niyTx53VijD2wTVGjhQgSLstEDowYSnTNtk8eTpG6b1gvQc32jLnMOsyQe
oJGiEr5q5re2GBDjuDZyxGOMv9/Hs7wOlkCQsbS9Vh0kRHWBRlXjk2zT7yYhFMLp
pXFeSW2X9BRFS2CkCCUkm93K9AZHLDE3x6ishNMCgYEAsDsUCzGhI49Aqe+CMP2l
WPZl7SEMYS5AtdC5sLtbLYBl8+rMXVGL2opKXqVFYBYkqMJiHGdX3Ub6XSVKLYkN
vm4PWmlQS24ZT+jlUl4jk6JU6SAlM/o6ixZl5KNR7yQm6zN2O/RHDeYm0urUQ9tF
9dux7LbIFeOoJmoDTWG2+fI=
-----END PRIVATE KEY-----

View File

@@ -1,172 +0,0 @@
Certificate:
Data:
Version: 3 (0x2)
Serial Number: 2 (0x2)
Signature Algorithm: sha1WithRSAEncryption
Issuer: C=NO, O=Green AS, OU=Green Certificate Authority, CN=Green Root CA
Validity
Not Before: Jul 13 03:47:20 2017 GMT
Not After : Jul 13 03:47:20 2027 GMT
Subject: C=NO, O=Green AS, OU=Green Certificate Authority, CN=Green TLS CA
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
Public-Key: (2048 bit)
Modulus:
00:b5:5a:b3:7a:7f:6a:5b:e9:ee:62:ee:4f:61:42:
79:93:06:bf:81:fc:9a:1f:b5:80:83:7c:b3:a6:94:
54:58:8a:b1:74:cb:c3:b8:3c:23:a8:69:1f:ca:2b:
af:be:97:ba:31:73:b5:b8:ce:d9:bf:bf:9a:7a:cf:
3a:64:51:83:c9:36:d2:f7:3b:3a:0e:4c:c7:66:2e:
bf:1a:df:ce:10:aa:3d:0f:19:74:03:7e:b5:10:bb:
e8:37:bd:62:f0:42:2d:df:3d:ca:70:50:10:17:ce:
a9:ec:55:8e:87:6f:ce:9a:04:36:14:96:cb:d1:a5:
48:d5:d2:87:02:62:93:4e:21:4a:ff:be:44:f1:d2:
7e:ed:74:da:c2:51:26:8e:03:a0:c2:bd:bd:5f:b0:
50:11:78:fd:ab:1d:04:86:6c:c1:8d:20:bd:05:5f:
51:67:c6:d3:07:95:92:2d:92:90:00:c6:9f:2d:dd:
36:5c:dc:78:10:7c:f6:68:39:1d:2c:e0:e1:26:64:
4f:36:34:66:a7:84:6a:90:15:3a:94:b7:79:b1:47:
f5:d2:51:95:54:bf:92:76:9a:b9:88:ee:63:f9:6c:
0d:38:c6:b6:1c:06:43:ed:24:1d:bb:6c:72:48:cc:
8c:f4:35:bc:43:fe:a6:96:4c:31:5f:82:0d:0d:20:
2a:3d
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Key Usage: critical
Certificate Sign, CRL Sign
X509v3 Basic Constraints: critical
CA:TRUE, pathlen:0
X509v3 Subject Key Identifier:
AE:42:88:75:DD:05:A6:8E:48:7F:50:69:F9:B7:34:23:49:B8:B4:71
X509v3 Authority Key Identifier:
keyid:60:93:53:2F:C7:CF:2A:D7:F3:09:28:F6:3C:AE:9C:50:EC:93:63:E5
Authority Information Access:
CA Issuers - URI:http://green.no/ca/root-ca.cer
X509v3 CRL Distribution Points:
Full Name:
URI:http://green.no/ca/root-ca.crl
Signature Algorithm: sha1WithRSAEncryption
15:a7:ac:d7:25:9e:2a:d4:d1:14:b4:99:38:3d:2f:73:61:2a:
d9:b6:8b:13:ea:fe:db:78:d9:0a:6c:df:26:6e:c1:d5:4a:97:
42:19:dd:97:05:03:e4:2b:fc:1e:1f:38:3c:4e:b0:3b:8c:38:
ad:2b:65:fa:35:2d:81:8e:e0:f6:0a:89:4c:38:97:01:4b:9c:
ac:4e:e1:55:17:ef:0a:ad:a7:eb:1e:4b:86:23:12:f1:52:69:
cb:a3:8a:ce:fb:14:8b:86:d7:bb:81:5e:bd:2a:c7:a7:79:58:
00:10:c0:db:ff:d4:a5:b9:19:74:b3:23:19:4a:1f:78:4b:a8:
b6:f6:20:26:c1:69:f9:89:7f:b8:1c:3b:a2:f9:37:31:80:2c:
b0:b6:2b:d2:84:44:d7:42:e4:e6:44:51:04:35:d9:1c:a4:48:
c6:b7:35:de:f2:ae:da:4b:ba:c8:09:42:8d:ed:7a:81:dc:ed:
9d:f0:de:6e:21:b9:01:1c:ad:64:3d:25:4c:91:94:f1:13:18:
bb:89:e9:48:ac:05:73:07:c8:db:bd:69:8e:6f:02:9d:b0:18:
c0:b9:e1:a8:b1:17:50:3d:ac:05:6e:6f:63:4f:b1:73:33:60:
9a:77:d2:81:8a:01:38:43:e9:4c:3c:90:63:a4:99:4b:d2:1b:
f9:1b:ec:ee
-----BEGIN CERTIFICATE-----
MIIECzCCAvOgAwIBAgIBAjANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJOTzER
MA8GA1UECgwIR3JlZW4gQVMxJDAiBgNVBAsMG0dyZWVuIENlcnRpZmljYXRlIEF1
dGhvcml0eTEWMBQGA1UEAwwNR3JlZW4gUm9vdCBDQTAeFw0xNzA3MTMwMzQ3MjBa
Fw0yNzA3MTMwMzQ3MjBaMF0xCzAJBgNVBAYTAk5PMREwDwYDVQQKDAhHcmVlbiBB
UzEkMCIGA1UECwwbR3JlZW4gQ2VydGlmaWNhdGUgQXV0aG9yaXR5MRUwEwYDVQQD
DAxHcmVlbiBUTFMgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC1
WrN6f2pb6e5i7k9hQnmTBr+B/JoftYCDfLOmlFRYirF0y8O4PCOoaR/KK6++l7ox
c7W4ztm/v5p6zzpkUYPJNtL3OzoOTMdmLr8a384Qqj0PGXQDfrUQu+g3vWLwQi3f
PcpwUBAXzqnsVY6Hb86aBDYUlsvRpUjV0ocCYpNOIUr/vkTx0n7tdNrCUSaOA6DC
vb1fsFAReP2rHQSGbMGNIL0FX1FnxtMHlZItkpAAxp8t3TZc3HgQfPZoOR0s4OEm
ZE82NGanhGqQFTqUt3mxR/XSUZVUv5J2mrmI7mP5bA04xrYcBkPtJB27bHJIzIz0
NbxD/qaWTDFfgg0NICo9AgMBAAGjgdQwgdEwDgYDVR0PAQH/BAQDAgEGMBIGA1Ud
EwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYEFK5CiHXdBaaOSH9Qafm3NCNJuLRxMB8G
A1UdIwQYMBaAFGCTUy/HzyrX8wko9jyunFDsk2PlMDoGCCsGAQUFBwEBBC4wLDAq
BggrBgEFBQcwAoYeaHR0cDovL2dyZWVuLm5vL2NhL3Jvb3QtY2EuY2VyMC8GA1Ud
HwQoMCYwJKAioCCGHmh0dHA6Ly9ncmVlbi5uby9jYS9yb290LWNhLmNybDANBgkq
hkiG9w0BAQUFAAOCAQEAFaes1yWeKtTRFLSZOD0vc2Eq2baLE+r+23jZCmzfJm7B
1UqXQhndlwUD5Cv8Hh84PE6wO4w4rStl+jUtgY7g9gqJTDiXAUucrE7hVRfvCq2n
6x5LhiMS8VJpy6OKzvsUi4bXu4FevSrHp3lYABDA2//UpbkZdLMjGUofeEuotvYg
JsFp+Yl/uBw7ovk3MYAssLYr0oRE10Lk5kRRBDXZHKRIxrc13vKu2ku6yAlCje16
gdztnfDebiG5ARytZD0lTJGU8RMYu4npSKwFcwfI271pjm8CnbAYwLnhqLEXUD2s
BW5vY0+xczNgmnfSgYoBOEPpTDyQY6SZS9Ib+Rvs7g==
-----END CERTIFICATE-----
Certificate:
Data:
Version: 3 (0x2)
Serial Number: 1 (0x1)
Signature Algorithm: sha1WithRSAEncryption
Issuer: C=NO, O=Green AS, OU=Green Certificate Authority, CN=Green Root CA
Validity
Not Before: Jul 13 03:44:39 2017 GMT
Not After : Dec 31 23:59:59 2030 GMT
Subject: C=NO, O=Green AS, OU=Green Certificate Authority, CN=Green Root CA
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
Public-Key: (2048 bit)
Modulus:
00:a7:e8:ed:de:d4:54:08:41:07:40:d5:c0:43:d6:
ab:d3:9e:21:87:c6:13:bf:a7:cf:3d:08:4f:c1:fe:
8f:e5:6c:c5:89:97:e5:27:75:26:c3:2a:73:2d:34:
7c:6f:35:8d:40:66:61:05:c0:eb:e9:b3:38:47:f8:
8b:26:35:2c:df:dc:24:31:fe:72:e3:87:10:d1:f7:
a0:57:b7:f3:b1:1a:fe:c7:4b:f8:7b:14:6d:73:08:
54:eb:63:3c:0c:ce:22:95:5f:3f:f2:6f:89:ae:63:
da:80:74:36:21:13:e8:91:01:58:77:cc:c2:f2:42:
bf:eb:b3:60:a7:21:ed:88:24:7f:eb:ff:07:41:9b:
93:c8:5f:6a:8e:a6:1a:15:3c:bc:e7:0d:fd:05:fd:
3c:c1:1c:1d:1f:57:2b:40:27:62:a1:7c:48:63:c1:
45:e7:2f:20:ed:92:1c:42:94:e4:58:70:7a:b6:d2:
85:c5:61:d8:cd:c6:37:6b:72:3b:7f:af:55:81:d6:
9d:dc:10:c9:d8:0e:81:e4:5e:40:13:2f:20:e8:6b:
46:81:ce:88:47:dd:38:71:3d:ef:21:cc:c0:67:cf:
0a:f4:e9:3f:a8:9d:26:25:2e:23:1e:a3:11:18:cb:
d1:70:1c:9e:7d:09:b1:a4:20:dc:95:15:1d:49:cf:
1b:ad
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Key Usage: critical
Certificate Sign, CRL Sign
X509v3 Basic Constraints: critical
CA:TRUE
X509v3 Subject Key Identifier:
60:93:53:2F:C7:CF:2A:D7:F3:09:28:F6:3C:AE:9C:50:EC:93:63:E5
X509v3 Authority Key Identifier:
keyid:60:93:53:2F:C7:CF:2A:D7:F3:09:28:F6:3C:AE:9C:50:EC:93:63:E5
Signature Algorithm: sha1WithRSAEncryption
a7:77:71:8b:1a:e5:5a:5b:87:54:08:bf:07:3e:cb:99:2f:dc:
0e:8d:63:94:95:83:19:c9:92:82:d5:cb:5b:8f:1f:86:55:bc:
70:01:1d:33:46:ec:99:de:6b:1f:c3:c2:7a:dd:ef:69:ab:96:
58:ec:6c:6f:6c:70:82:71:8a:7f:f0:3b:80:90:d5:64:fa:80:
27:b8:7b:50:69:98:4b:37:99:ad:bf:a2:5b:93:22:5e:96:44:
3c:5a:cf:0c:f4:62:63:4a:6f:72:a7:f6:89:1d:09:26:3d:8f:
a8:86:d4:b4:bc:dd:b3:38:ca:c0:59:16:8c:20:1f:89:35:12:
b4:2d:c0:e9:de:93:e0:39:76:32:fc:80:db:da:44:26:fd:01:
32:74:97:f8:44:ae:fe:05:b1:34:96:13:34:56:73:b4:93:a5:
55:56:d1:01:51:9d:9c:55:e7:38:53:28:12:4e:38:72:0c:8f:
bd:91:4c:45:48:3b:e1:0d:03:5f:58:40:c9:d3:a0:ac:b3:89:
ce:af:27:8a:0f:ab:ec:72:4d:40:77:30:6b:36:fd:32:46:9f:
ee:f9:c4:f5:17:06:0f:4b:d3:88:f5:a4:2f:3d:87:9e:f5:26:
74:f0:c9:dc:cb:ad:d9:a7:8a:d3:71:15:00:d3:5d:9f:4c:59:
3e:24:63:f5
-----BEGIN CERTIFICATE-----
MIIDnDCCAoSgAwIBAgIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJOTzER
MA8GA1UECgwIR3JlZW4gQVMxJDAiBgNVBAsMG0dyZWVuIENlcnRpZmljYXRlIEF1
dGhvcml0eTEWMBQGA1UEAwwNR3JlZW4gUm9vdCBDQTAgFw0xNzA3MTMwMzQ0Mzla
GA8yMDMwMTIzMTIzNTk1OVowXjELMAkGA1UEBhMCTk8xETAPBgNVBAoMCEdyZWVu
IEFTMSQwIgYDVQQLDBtHcmVlbiBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkxFjAUBgNV
BAMMDUdyZWVuIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB
AQCn6O3e1FQIQQdA1cBD1qvTniGHxhO/p889CE/B/o/lbMWJl+UndSbDKnMtNHxv
NY1AZmEFwOvpszhH+IsmNSzf3CQx/nLjhxDR96BXt/OxGv7HS/h7FG1zCFTrYzwM
ziKVXz/yb4muY9qAdDYhE+iRAVh3zMLyQr/rs2CnIe2IJH/r/wdBm5PIX2qOphoV
PLznDf0F/TzBHB0fVytAJ2KhfEhjwUXnLyDtkhxClORYcHq20oXFYdjNxjdrcjt/
r1WB1p3cEMnYDoHkXkATLyDoa0aBzohH3ThxPe8hzMBnzwr06T+onSYlLiMeoxEY
y9FwHJ59CbGkINyVFR1JzxutAgMBAAGjYzBhMA4GA1UdDwEB/wQEAwIBBjAPBgNV
HRMBAf8EBTADAQH/MB0GA1UdDgQWBBRgk1Mvx88q1/MJKPY8rpxQ7JNj5TAfBgNV
HSMEGDAWgBRgk1Mvx88q1/MJKPY8rpxQ7JNj5TANBgkqhkiG9w0BAQUFAAOCAQEA
p3dxixrlWluHVAi/Bz7LmS/cDo1jlJWDGcmSgtXLW48fhlW8cAEdM0bsmd5rH8PC
et3vaauWWOxsb2xwgnGKf/A7gJDVZPqAJ7h7UGmYSzeZrb+iW5MiXpZEPFrPDPRi
Y0pvcqf2iR0JJj2PqIbUtLzdszjKwFkWjCAfiTUStC3A6d6T4Dl2MvyA29pEJv0B
MnSX+ESu/gWxNJYTNFZztJOlVVbRAVGdnFXnOFMoEk44cgyPvZFMRUg74Q0DX1hA
ydOgrLOJzq8nig+r7HJNQHcwazb9Mkaf7vnE9RcGD0vTiPWkLz2HnvUmdPDJ3Mut
2aeK03EVANNdn0xZPiRj9Q==
-----END CERTIFICATE-----

View File

@@ -1 +0,0 @@
cert_file: somefile

View File

@@ -1 +0,0 @@
insecure_skip_verify: true

View File

@@ -1 +0,0 @@
something_invalid: true

View File

@@ -1 +0,0 @@
key_file: somefile

View File

@@ -1,62 +0,0 @@
// Copyright 2016 The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package config
import (
"crypto/tls"
"io/ioutil"
"reflect"
"testing"
"gopkg.in/yaml.v2"
)
// LoadTLSConfig parses the given YAML file into a tls.Config.
func LoadTLSConfig(filename string) (*tls.Config, error) {
content, err := ioutil.ReadFile(filename)
if err != nil {
return nil, err
}
cfg := TLSConfig{}
if err = yaml.UnmarshalStrict(content, &cfg); err != nil {
return nil, err
}
return NewTLSConfig(&cfg)
}
var expectedTLSConfigs = []struct {
filename string
config *tls.Config
}{
{
filename: "tls_config.empty.good.yml",
config: &tls.Config{},
}, {
filename: "tls_config.insecure.good.yml",
config: &tls.Config{InsecureSkipVerify: true},
},
}
func TestValidTLSConfig(t *testing.T) {
for _, cfg := range expectedTLSConfigs {
cfg.config.BuildNameToCertificate()
got, err := LoadTLSConfig("testdata/" + cfg.filename)
if err != nil {
t.Errorf("Error parsing %s: %s", cfg.filename, err)
}
if !reflect.DeepEqual(*got, *cfg.config) {
t.Fatalf("%v: unexpected config result: \n\n%v\n expected\n\n%v", cfg.filename, got, cfg.config)
}
}
}

View File

@@ -1,167 +0,0 @@
// Copyright 2015 The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package expfmt
import (
"bytes"
"compress/gzip"
"io"
"io/ioutil"
"testing"
"github.com/matttproud/golang_protobuf_extensions/pbutil"
dto "github.com/prometheus/client_model/go"
)
var parser TextParser
// Benchmarks to show how much penalty text format parsing actually inflicts.
//
// Example results on Linux 3.13.0, Intel(R) Core(TM) i7-4700MQ CPU @ 2.40GHz, go1.4.
//
// BenchmarkParseText 1000 1188535 ns/op 205085 B/op 6135 allocs/op
// BenchmarkParseTextGzip 1000 1376567 ns/op 246224 B/op 6151 allocs/op
// BenchmarkParseProto 10000 172790 ns/op 52258 B/op 1160 allocs/op
// BenchmarkParseProtoGzip 5000 324021 ns/op 94931 B/op 1211 allocs/op
// BenchmarkParseProtoMap 10000 187946 ns/op 58714 B/op 1203 allocs/op
//
// CONCLUSION: The overhead for the map is negligible. Text format needs ~5x more allocations.
// Without compression, it needs ~7x longer, but with compression (the more relevant scenario),
// the difference becomes less relevant, only ~4x.
//
// The test data contains 248 samples.
// BenchmarkParseText benchmarks the parsing of a text-format scrape into metric
// family DTOs.
func BenchmarkParseText(b *testing.B) {
b.StopTimer()
data, err := ioutil.ReadFile("testdata/text")
if err != nil {
b.Fatal(err)
}
b.StartTimer()
for i := 0; i < b.N; i++ {
if _, err := parser.TextToMetricFamilies(bytes.NewReader(data)); err != nil {
b.Fatal(err)
}
}
}
// BenchmarkParseTextGzip benchmarks the parsing of a gzipped text-format scrape
// into metric family DTOs.
func BenchmarkParseTextGzip(b *testing.B) {
b.StopTimer()
data, err := ioutil.ReadFile("testdata/text.gz")
if err != nil {
b.Fatal(err)
}
b.StartTimer()
for i := 0; i < b.N; i++ {
in, err := gzip.NewReader(bytes.NewReader(data))
if err != nil {
b.Fatal(err)
}
if _, err := parser.TextToMetricFamilies(in); err != nil {
b.Fatal(err)
}
}
}
// BenchmarkParseProto benchmarks the parsing of a protobuf-format scrape into
// metric family DTOs. Note that this does not build a map of metric families
// (as the text version does), because it is not required for Prometheus
// ingestion either. (However, it is required for the text-format parsing, as
// the metric family might be sprinkled all over the text, while the
// protobuf-format guarantees bundling at one place.)
func BenchmarkParseProto(b *testing.B) {
b.StopTimer()
data, err := ioutil.ReadFile("testdata/protobuf")
if err != nil {
b.Fatal(err)
}
b.StartTimer()
for i := 0; i < b.N; i++ {
family := &dto.MetricFamily{}
in := bytes.NewReader(data)
for {
family.Reset()
if _, err := pbutil.ReadDelimited(in, family); err != nil {
if err == io.EOF {
break
}
b.Fatal(err)
}
}
}
}
// BenchmarkParseProtoGzip is like BenchmarkParseProto above, but parses gzipped
// protobuf format.
func BenchmarkParseProtoGzip(b *testing.B) {
b.StopTimer()
data, err := ioutil.ReadFile("testdata/protobuf.gz")
if err != nil {
b.Fatal(err)
}
b.StartTimer()
for i := 0; i < b.N; i++ {
family := &dto.MetricFamily{}
in, err := gzip.NewReader(bytes.NewReader(data))
if err != nil {
b.Fatal(err)
}
for {
family.Reset()
if _, err := pbutil.ReadDelimited(in, family); err != nil {
if err == io.EOF {
break
}
b.Fatal(err)
}
}
}
}
// BenchmarkParseProtoMap is like BenchmarkParseProto but DOES put the parsed
// metric family DTOs into a map. This is not happening during Prometheus
// ingestion. It is just here to measure the overhead of that map creation and
// separate it from the overhead of the text format parsing.
func BenchmarkParseProtoMap(b *testing.B) {
b.StopTimer()
data, err := ioutil.ReadFile("testdata/protobuf")
if err != nil {
b.Fatal(err)
}
b.StartTimer()
for i := 0; i < b.N; i++ {
families := map[string]*dto.MetricFamily{}
in := bytes.NewReader(data)
for {
family := &dto.MetricFamily{}
if _, err := pbutil.ReadDelimited(in, family); err != nil {
if err == io.EOF {
break
}
b.Fatal(err)
}
families[family.GetName()] = family
}
}
}

View File

@@ -1,435 +0,0 @@
// Copyright 2015 The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package expfmt
import (
"io"
"net/http"
"reflect"
"sort"
"strings"
"testing"
"github.com/golang/protobuf/proto"
dto "github.com/prometheus/client_model/go"
"github.com/prometheus/common/model"
)
func TestTextDecoder(t *testing.T) {
var (
ts = model.Now()
in = `
# Only a quite simple scenario with two metric families.
# More complicated tests of the parser itself can be found in the text package.
# TYPE mf2 counter
mf2 3
mf1{label="value1"} -3.14 123456
mf1{label="value2"} 42
mf2 4
`
out = model.Vector{
&model.Sample{
Metric: model.Metric{
model.MetricNameLabel: "mf1",
"label": "value1",
},
Value: -3.14,
Timestamp: 123456,
},
&model.Sample{
Metric: model.Metric{
model.MetricNameLabel: "mf1",
"label": "value2",
},
Value: 42,
Timestamp: ts,
},
&model.Sample{
Metric: model.Metric{
model.MetricNameLabel: "mf2",
},
Value: 3,
Timestamp: ts,
},
&model.Sample{
Metric: model.Metric{
model.MetricNameLabel: "mf2",
},
Value: 4,
Timestamp: ts,
},
}
)
dec := &SampleDecoder{
Dec: &textDecoder{r: strings.NewReader(in)},
Opts: &DecodeOptions{
Timestamp: ts,
},
}
var all model.Vector
for {
var smpls model.Vector
err := dec.Decode(&smpls)
if err == io.EOF {
break
}
if err != nil {
t.Fatal(err)
}
all = append(all, smpls...)
}
sort.Sort(all)
sort.Sort(out)
if !reflect.DeepEqual(all, out) {
t.Fatalf("output does not match")
}
}
func TestProtoDecoder(t *testing.T) {
var testTime = model.Now()
scenarios := []struct {
in string
expected model.Vector
fail bool
}{
{
in: "",
},
{
in: "\x8f\x01\n\rrequest_count\x12\x12Number of requests\x18\x00\"0\n#\n\x0fsome_!abel_name\x12\x10some_label_value\x1a\t\t\x00\x00\x00\x00\x00\x00E\xc0\"6\n)\n\x12another_label_name\x12\x13another_label_value\x1a\t\t\x00\x00\x00\x00\x00\x00U@",
fail: true,
},
{
in: "\x8f\x01\n\rrequest_count\x12\x12Number of requests\x18\x00\"0\n#\n\x0fsome_label_name\x12\x10some_label_value\x1a\t\t\x00\x00\x00\x00\x00\x00E\xc0\"6\n)\n\x12another_label_name\x12\x13another_label_value\x1a\t\t\x00\x00\x00\x00\x00\x00U@",
expected: model.Vector{
&model.Sample{
Metric: model.Metric{
model.MetricNameLabel: "request_count",
"some_label_name": "some_label_value",
},
Value: -42,
Timestamp: testTime,
},
&model.Sample{
Metric: model.Metric{
model.MetricNameLabel: "request_count",
"another_label_name": "another_label_value",
},
Value: 84,
Timestamp: testTime,
},
},
},
{
in: "\xb9\x01\n\rrequest_count\x12\x12Number of requests\x18\x02\"O\n#\n\x0fsome_label_name\x12\x10some_label_value\"(\x1a\x12\t\xaeG\xe1z\x14\xae\xef?\x11\x00\x00\x00\x00\x00\x00E\xc0\x1a\x12\t+\x87\x16\xd9\xce\xf7\xef?\x11\x00\x00\x00\x00\x00\x00U\xc0\"A\n)\n\x12another_label_name\x12\x13another_label_value\"\x14\x1a\x12\t\x00\x00\x00\x00\x00\x00\xe0?\x11\x00\x00\x00\x00\x00\x00$@",
expected: model.Vector{
&model.Sample{
Metric: model.Metric{
model.MetricNameLabel: "request_count_count",
"some_label_name": "some_label_value",
},
Value: 0,
Timestamp: testTime,
},
&model.Sample{
Metric: model.Metric{
model.MetricNameLabel: "request_count_sum",
"some_label_name": "some_label_value",
},
Value: 0,
Timestamp: testTime,
},
&model.Sample{
Metric: model.Metric{
model.MetricNameLabel: "request_count",
"some_label_name": "some_label_value",
"quantile": "0.99",
},
Value: -42,
Timestamp: testTime,
},
&model.Sample{
Metric: model.Metric{
model.MetricNameLabel: "request_count",
"some_label_name": "some_label_value",
"quantile": "0.999",
},
Value: -84,
Timestamp: testTime,
},
&model.Sample{
Metric: model.Metric{
model.MetricNameLabel: "request_count_count",
"another_label_name": "another_label_value",
},
Value: 0,
Timestamp: testTime,
},
&model.Sample{
Metric: model.Metric{
model.MetricNameLabel: "request_count_sum",
"another_label_name": "another_label_value",
},
Value: 0,
Timestamp: testTime,
},
&model.Sample{
Metric: model.Metric{
model.MetricNameLabel: "request_count",
"another_label_name": "another_label_value",
"quantile": "0.5",
},
Value: 10,
Timestamp: testTime,
},
},
},
{
in: "\x8d\x01\n\x1drequest_duration_microseconds\x12\x15The response latency.\x18\x04\"S:Q\b\x85\x15\x11\xcd\xcc\xccL\x8f\xcb:A\x1a\v\b{\x11\x00\x00\x00\x00\x00\x00Y@\x1a\f\b\x9c\x03\x11\x00\x00\x00\x00\x00\x00^@\x1a\f\b\xd0\x04\x11\x00\x00\x00\x00\x00\x00b@\x1a\f\b\xf4\v\x11\x9a\x99\x99\x99\x99\x99e@\x1a\f\b\x85\x15\x11\x00\x00\x00\x00\x00\x00\xf0\u007f",
expected: model.Vector{
&model.Sample{
Metric: model.Metric{
model.MetricNameLabel: "request_duration_microseconds_bucket",
"le": "100",
},
Value: 123,
Timestamp: testTime,
},
&model.Sample{
Metric: model.Metric{
model.MetricNameLabel: "request_duration_microseconds_bucket",
"le": "120",
},
Value: 412,
Timestamp: testTime,
},
&model.Sample{
Metric: model.Metric{
model.MetricNameLabel: "request_duration_microseconds_bucket",
"le": "144",
},
Value: 592,
Timestamp: testTime,
},
&model.Sample{
Metric: model.Metric{
model.MetricNameLabel: "request_duration_microseconds_bucket",
"le": "172.8",
},
Value: 1524,
Timestamp: testTime,
},
&model.Sample{
Metric: model.Metric{
model.MetricNameLabel: "request_duration_microseconds_bucket",
"le": "+Inf",
},
Value: 2693,
Timestamp: testTime,
},
&model.Sample{
Metric: model.Metric{
model.MetricNameLabel: "request_duration_microseconds_sum",
},
Value: 1756047.3,
Timestamp: testTime,
},
&model.Sample{
Metric: model.Metric{
model.MetricNameLabel: "request_duration_microseconds_count",
},
Value: 2693,
Timestamp: testTime,
},
},
},
{
// The metric type is unset in this protobuf, which needs to be handled
// correctly by the decoder.
in: "\x1c\n\rrequest_count\"\v\x1a\t\t\x00\x00\x00\x00\x00\x00\xf0?",
expected: model.Vector{
&model.Sample{
Metric: model.Metric{
model.MetricNameLabel: "request_count",
},
Value: 1,
Timestamp: testTime,
},
},
},
}
for i, scenario := range scenarios {
dec := &SampleDecoder{
Dec: &protoDecoder{r: strings.NewReader(scenario.in)},
Opts: &DecodeOptions{
Timestamp: testTime,
},
}
var all model.Vector
for {
var smpls model.Vector
err := dec.Decode(&smpls)
if err == io.EOF {
break
}
if scenario.fail {
if err == nil {
t.Fatal("Expected error but got none")
}
break
}
if err != nil {
t.Fatal(err)
}
all = append(all, smpls...)
}
sort.Sort(all)
sort.Sort(scenario.expected)
if !reflect.DeepEqual(all, scenario.expected) {
t.Fatalf("%d. output does not match, want: %#v, got %#v", i, scenario.expected, all)
}
}
}
func testDiscriminatorHTTPHeader(t testing.TB) {
var scenarios = []struct {
input map[string]string
output Format
err error
}{
{
input: map[string]string{"Content-Type": `application/vnd.google.protobuf; proto="io.prometheus.client.MetricFamily"; encoding="delimited"`},
output: FmtProtoDelim,
},
{
input: map[string]string{"Content-Type": `application/vnd.google.protobuf; proto="illegal"; encoding="delimited"`},
output: FmtUnknown,
},
{
input: map[string]string{"Content-Type": `application/vnd.google.protobuf; proto="io.prometheus.client.MetricFamily"; encoding="illegal"`},
output: FmtUnknown,
},
{
input: map[string]string{"Content-Type": `text/plain; version=0.0.4`},
output: FmtText,
},
{
input: map[string]string{"Content-Type": `text/plain`},
output: FmtText,
},
{
input: map[string]string{"Content-Type": `text/plain; version=0.0.3`},
output: FmtUnknown,
},
}
for i, scenario := range scenarios {
var header http.Header
if len(scenario.input) > 0 {
header = http.Header{}
}
for key, value := range scenario.input {
header.Add(key, value)
}
actual := ResponseFormat(header)
if scenario.output != actual {
t.Errorf("%d. expected %s, got %s", i, scenario.output, actual)
}
}
}
func TestDiscriminatorHTTPHeader(t *testing.T) {
testDiscriminatorHTTPHeader(t)
}
func BenchmarkDiscriminatorHTTPHeader(b *testing.B) {
for i := 0; i < b.N; i++ {
testDiscriminatorHTTPHeader(b)
}
}
func TestExtractSamples(t *testing.T) {
var (
goodMetricFamily1 = &dto.MetricFamily{
Name: proto.String("foo"),
Help: proto.String("Help for foo."),
Type: dto.MetricType_COUNTER.Enum(),
Metric: []*dto.Metric{
&dto.Metric{
Counter: &dto.Counter{
Value: proto.Float64(4711),
},
},
},
}
goodMetricFamily2 = &dto.MetricFamily{
Name: proto.String("bar"),
Help: proto.String("Help for bar."),
Type: dto.MetricType_GAUGE.Enum(),
Metric: []*dto.Metric{
&dto.Metric{
Gauge: &dto.Gauge{
Value: proto.Float64(3.14),
},
},
},
}
badMetricFamily = &dto.MetricFamily{
Name: proto.String("bad"),
Help: proto.String("Help for bad."),
Type: dto.MetricType(42).Enum(),
Metric: []*dto.Metric{
&dto.Metric{
Gauge: &dto.Gauge{
Value: proto.Float64(2.7),
},
},
},
}
opts = &DecodeOptions{
Timestamp: 42,
}
)
got, err := ExtractSamples(opts, goodMetricFamily1, goodMetricFamily2)
if err != nil {
t.Error("Unexpected error from ExtractSamples:", err)
}
want := model.Vector{
&model.Sample{Metric: model.Metric{model.MetricNameLabel: "foo"}, Value: 4711, Timestamp: 42},
&model.Sample{Metric: model.Metric{model.MetricNameLabel: "bar"}, Value: 3.14, Timestamp: 42},
}
if !reflect.DeepEqual(got, want) {
t.Errorf("unexpected samples extracted, got: %v, want: %v", got, want)
}
got, err = ExtractSamples(opts, goodMetricFamily1, badMetricFamily, goodMetricFamily2)
if err == nil {
t.Error("Expected error from ExtractSamples")
}
if !reflect.DeepEqual(got, want) {
t.Errorf("unexpected samples extracted, got: %v, want: %v", got, want)
}
}

View File

@@ -1,2 +0,0 @@

View File

@@ -1,6 +0,0 @@
minimal_metric 1.234
another_metric -3e3 103948
# Even that:
no_labels{} 3
# HELP line for non-existing metric will be ignored.

View File

@@ -1,12 +0,0 @@
# A normal comment.
#
# TYPE name counter
name{labelname="val1",basename="basevalue"} NaN
name {labelname="val2",basename="base\"v\\al\nue"} 0.23 1234567890
# HELP name two-line\n doc str\\ing
# HELP name2 doc str"ing 2
# TYPE name2 gauge
name2{labelname="val2" ,basename = "basevalue2" } +Inf 54321
name2{ labelname = "val1" , }-Inf

View File

@@ -1,22 +0,0 @@
# TYPE my_summary summary
my_summary{n1="val1",quantile="0.5"} 110
decoy -1 -2
my_summary{n1="val1",quantile="0.9"} 140 1
my_summary_count{n1="val1"} 42
# Latest timestamp wins in case of a summary.
my_summary_sum{n1="val1"} 4711 2
fake_sum{n1="val1"} 2001
# TYPE another_summary summary
another_summary_count{n2="val2",n1="val1"} 20
my_summary_count{n2="val2",n1="val1"} 5 5
another_summary{n1="val1",n2="val2",quantile=".3"} -1.2
my_summary_sum{n1="val2"} 08 15
my_summary{n1="val3", quantile="0.2"} 4711
my_summary{n1="val1",n2="val2",quantile="-12.34",} NaN
# some
# funny comments
# HELP
# HELP
# HELP my_summary
# HELP my_summary

View File

@@ -1,10 +0,0 @@
# HELP request_duration_microseconds The response latency.
# TYPE request_duration_microseconds histogram
request_duration_microseconds_bucket{le="100"} 123
request_duration_microseconds_bucket{le="120"} 412
request_duration_microseconds_bucket{le="144"} 592
request_duration_microseconds_bucket{le="172.8"} 1524
request_duration_microseconds_bucket{le="+Inf"} 2693
request_duration_microseconds_sum 1.7560473e+06
request_duration_microseconds_count 2693

View File

@@ -1 +0,0 @@
bla 3.14

View File

@@ -1 +0,0 @@
metric{label="\t"} 3.14

View File

@@ -1 +0,0 @@
metric{label="bla"} 3.14 2 3

View File

@@ -1 +0,0 @@
metric{label="bla"} blubb

View File

@@ -1,3 +0,0 @@
# HELP metric one
# HELP metric two

View File

@@ -1,3 +0,0 @@
# TYPE metric counter
# TYPE metric untyped

View File

@@ -1,3 +0,0 @@
metric 4.12
# TYPE metric counter

View File

@@ -1,2 +0,0 @@
# TYPE metric bla

View File

@@ -1,2 +0,0 @@
# TYPE met-ric

View File

@@ -1 +0,0 @@
@invalidmetric{label="bla"} 3.14 2

View File

@@ -1 +0,0 @@
{label="bla"} 3.14 2

View File

@@ -1,3 +0,0 @@
# TYPE metric histogram
metric_bucket{le="bla"} 3.14

View File

@@ -1,3 +0,0 @@
metric{label="new
line"} 3.14

View File

@@ -1 +0,0 @@
metric{@="bla"} 3.14

View File

@@ -1 +0,0 @@
metric{__name__="bla"} 3.14

View File

@@ -1 +0,0 @@
metric{label+="bla"} 3.14

View File

@@ -1 +0,0 @@
metric{label=bla} 3.14

View File

@@ -1,3 +0,0 @@
# TYPE metric summary
metric{quantile="bla"} 3.14

View File

@@ -1 +0,0 @@
metric{label="bla"+} 3.14

View File

@@ -1 +0,0 @@
metric{label="bla"} 3.14 2.72

View File

@@ -1 +0,0 @@
m{} 0

View File

@@ -1,46 +0,0 @@
[
{
"baseLabels": {
"__name__": "rpc_calls_total",
"job": "batch_job"
},
"docstring": "RPC calls.",
"metric": {
"type": "counter",
"value": [
{
"labels": {
"service": "zed"
},
"value": 25
},
{
"labels": {
"service": "bar"
},
"value": 24
}
]
}
},
{
"baseLabels": {
"__name__": "rpc_latency_microseconds"
},
"docstring": "RPC latency.",
"metric": {
"type": "histogram",
"value": [
{
"labels": {
"service": "foo"
},
"value": {
"0.010000": 15,
"0.990000": 17
}
}
]
}
}
]

View File

@@ -1,46 +0,0 @@
[
{
"baseLabels": {
"__name__": "rpc_calls_total",
"job": "batch_job"
},
"docstring": "RPC calls.",
"metric": {
"type": "counter",
"value": [
{
"labels": {
"servic|e": "zed"
},
"value": 25
},
{
"labels": {
"service": "bar"
},
"value": 24
}
]
}
},
{
"baseLabels": {
"__name__": "rpc_latency_microseconds"
},
"docstring": "RPC latency.",
"metric": {
"type": "histogram",
"value": [
{
"labels": {
"service": "foo"
},
"value": {
"0.010000": 15,
"0.990000": 17
}
}
]
}
}
]

Binary file not shown.

Binary file not shown.

View File

@@ -1,322 +0,0 @@
# HELP http_request_duration_microseconds The HTTP request latencies in microseconds.
# TYPE http_request_duration_microseconds summary
http_request_duration_microseconds{handler="/",quantile="0.5"} 0
http_request_duration_microseconds{handler="/",quantile="0.9"} 0
http_request_duration_microseconds{handler="/",quantile="0.99"} 0
http_request_duration_microseconds_sum{handler="/"} 0
http_request_duration_microseconds_count{handler="/"} 0
http_request_duration_microseconds{handler="/alerts",quantile="0.5"} 0
http_request_duration_microseconds{handler="/alerts",quantile="0.9"} 0
http_request_duration_microseconds{handler="/alerts",quantile="0.99"} 0
http_request_duration_microseconds_sum{handler="/alerts"} 0
http_request_duration_microseconds_count{handler="/alerts"} 0
http_request_duration_microseconds{handler="/api/metrics",quantile="0.5"} 0
http_request_duration_microseconds{handler="/api/metrics",quantile="0.9"} 0
http_request_duration_microseconds{handler="/api/metrics",quantile="0.99"} 0
http_request_duration_microseconds_sum{handler="/api/metrics"} 0
http_request_duration_microseconds_count{handler="/api/metrics"} 0
http_request_duration_microseconds{handler="/api/query",quantile="0.5"} 0
http_request_duration_microseconds{handler="/api/query",quantile="0.9"} 0
http_request_duration_microseconds{handler="/api/query",quantile="0.99"} 0
http_request_duration_microseconds_sum{handler="/api/query"} 0
http_request_duration_microseconds_count{handler="/api/query"} 0
http_request_duration_microseconds{handler="/api/query_range",quantile="0.5"} 0
http_request_duration_microseconds{handler="/api/query_range",quantile="0.9"} 0
http_request_duration_microseconds{handler="/api/query_range",quantile="0.99"} 0
http_request_duration_microseconds_sum{handler="/api/query_range"} 0
http_request_duration_microseconds_count{handler="/api/query_range"} 0
http_request_duration_microseconds{handler="/api/targets",quantile="0.5"} 0
http_request_duration_microseconds{handler="/api/targets",quantile="0.9"} 0
http_request_duration_microseconds{handler="/api/targets",quantile="0.99"} 0
http_request_duration_microseconds_sum{handler="/api/targets"} 0
http_request_duration_microseconds_count{handler="/api/targets"} 0
http_request_duration_microseconds{handler="/consoles/",quantile="0.5"} 0
http_request_duration_microseconds{handler="/consoles/",quantile="0.9"} 0
http_request_duration_microseconds{handler="/consoles/",quantile="0.99"} 0
http_request_duration_microseconds_sum{handler="/consoles/"} 0
http_request_duration_microseconds_count{handler="/consoles/"} 0
http_request_duration_microseconds{handler="/graph",quantile="0.5"} 0
http_request_duration_microseconds{handler="/graph",quantile="0.9"} 0
http_request_duration_microseconds{handler="/graph",quantile="0.99"} 0
http_request_duration_microseconds_sum{handler="/graph"} 0
http_request_duration_microseconds_count{handler="/graph"} 0
http_request_duration_microseconds{handler="/heap",quantile="0.5"} 0
http_request_duration_microseconds{handler="/heap",quantile="0.9"} 0
http_request_duration_microseconds{handler="/heap",quantile="0.99"} 0
http_request_duration_microseconds_sum{handler="/heap"} 0
http_request_duration_microseconds_count{handler="/heap"} 0
http_request_duration_microseconds{handler="/static/",quantile="0.5"} 0
http_request_duration_microseconds{handler="/static/",quantile="0.9"} 0
http_request_duration_microseconds{handler="/static/",quantile="0.99"} 0
http_request_duration_microseconds_sum{handler="/static/"} 0
http_request_duration_microseconds_count{handler="/static/"} 0
http_request_duration_microseconds{handler="prometheus",quantile="0.5"} 1307.275
http_request_duration_microseconds{handler="prometheus",quantile="0.9"} 1858.632
http_request_duration_microseconds{handler="prometheus",quantile="0.99"} 3087.384
http_request_duration_microseconds_sum{handler="prometheus"} 179886.5000000001
http_request_duration_microseconds_count{handler="prometheus"} 119
# HELP http_request_size_bytes The HTTP request sizes in bytes.
# TYPE http_request_size_bytes summary
http_request_size_bytes{handler="/",quantile="0.5"} 0
http_request_size_bytes{handler="/",quantile="0.9"} 0
http_request_size_bytes{handler="/",quantile="0.99"} 0
http_request_size_bytes_sum{handler="/"} 0
http_request_size_bytes_count{handler="/"} 0
http_request_size_bytes{handler="/alerts",quantile="0.5"} 0
http_request_size_bytes{handler="/alerts",quantile="0.9"} 0
http_request_size_bytes{handler="/alerts",quantile="0.99"} 0
http_request_size_bytes_sum{handler="/alerts"} 0
http_request_size_bytes_count{handler="/alerts"} 0
http_request_size_bytes{handler="/api/metrics",quantile="0.5"} 0
http_request_size_bytes{handler="/api/metrics",quantile="0.9"} 0
http_request_size_bytes{handler="/api/metrics",quantile="0.99"} 0
http_request_size_bytes_sum{handler="/api/metrics"} 0
http_request_size_bytes_count{handler="/api/metrics"} 0
http_request_size_bytes{handler="/api/query",quantile="0.5"} 0
http_request_size_bytes{handler="/api/query",quantile="0.9"} 0
http_request_size_bytes{handler="/api/query",quantile="0.99"} 0
http_request_size_bytes_sum{handler="/api/query"} 0
http_request_size_bytes_count{handler="/api/query"} 0
http_request_size_bytes{handler="/api/query_range",quantile="0.5"} 0
http_request_size_bytes{handler="/api/query_range",quantile="0.9"} 0
http_request_size_bytes{handler="/api/query_range",quantile="0.99"} 0
http_request_size_bytes_sum{handler="/api/query_range"} 0
http_request_size_bytes_count{handler="/api/query_range"} 0
http_request_size_bytes{handler="/api/targets",quantile="0.5"} 0
http_request_size_bytes{handler="/api/targets",quantile="0.9"} 0
http_request_size_bytes{handler="/api/targets",quantile="0.99"} 0
http_request_size_bytes_sum{handler="/api/targets"} 0
http_request_size_bytes_count{handler="/api/targets"} 0
http_request_size_bytes{handler="/consoles/",quantile="0.5"} 0
http_request_size_bytes{handler="/consoles/",quantile="0.9"} 0
http_request_size_bytes{handler="/consoles/",quantile="0.99"} 0
http_request_size_bytes_sum{handler="/consoles/"} 0
http_request_size_bytes_count{handler="/consoles/"} 0
http_request_size_bytes{handler="/graph",quantile="0.5"} 0
http_request_size_bytes{handler="/graph",quantile="0.9"} 0
http_request_size_bytes{handler="/graph",quantile="0.99"} 0
http_request_size_bytes_sum{handler="/graph"} 0
http_request_size_bytes_count{handler="/graph"} 0
http_request_size_bytes{handler="/heap",quantile="0.5"} 0
http_request_size_bytes{handler="/heap",quantile="0.9"} 0
http_request_size_bytes{handler="/heap",quantile="0.99"} 0
http_request_size_bytes_sum{handler="/heap"} 0
http_request_size_bytes_count{handler="/heap"} 0
http_request_size_bytes{handler="/static/",quantile="0.5"} 0
http_request_size_bytes{handler="/static/",quantile="0.9"} 0
http_request_size_bytes{handler="/static/",quantile="0.99"} 0
http_request_size_bytes_sum{handler="/static/"} 0
http_request_size_bytes_count{handler="/static/"} 0
http_request_size_bytes{handler="prometheus",quantile="0.5"} 291
http_request_size_bytes{handler="prometheus",quantile="0.9"} 291
http_request_size_bytes{handler="prometheus",quantile="0.99"} 291
http_request_size_bytes_sum{handler="prometheus"} 34488
http_request_size_bytes_count{handler="prometheus"} 119
# HELP http_requests_total Total number of HTTP requests made.
# TYPE http_requests_total counter
http_requests_total{code="200",handler="prometheus",method="get"} 119
# HELP http_response_size_bytes The HTTP response sizes in bytes.
# TYPE http_response_size_bytes summary
http_response_size_bytes{handler="/",quantile="0.5"} 0
http_response_size_bytes{handler="/",quantile="0.9"} 0
http_response_size_bytes{handler="/",quantile="0.99"} 0
http_response_size_bytes_sum{handler="/"} 0
http_response_size_bytes_count{handler="/"} 0
http_response_size_bytes{handler="/alerts",quantile="0.5"} 0
http_response_size_bytes{handler="/alerts",quantile="0.9"} 0
http_response_size_bytes{handler="/alerts",quantile="0.99"} 0
http_response_size_bytes_sum{handler="/alerts"} 0
http_response_size_bytes_count{handler="/alerts"} 0
http_response_size_bytes{handler="/api/metrics",quantile="0.5"} 0
http_response_size_bytes{handler="/api/metrics",quantile="0.9"} 0
http_response_size_bytes{handler="/api/metrics",quantile="0.99"} 0
http_response_size_bytes_sum{handler="/api/metrics"} 0
http_response_size_bytes_count{handler="/api/metrics"} 0
http_response_size_bytes{handler="/api/query",quantile="0.5"} 0
http_response_size_bytes{handler="/api/query",quantile="0.9"} 0
http_response_size_bytes{handler="/api/query",quantile="0.99"} 0
http_response_size_bytes_sum{handler="/api/query"} 0
http_response_size_bytes_count{handler="/api/query"} 0
http_response_size_bytes{handler="/api/query_range",quantile="0.5"} 0
http_response_size_bytes{handler="/api/query_range",quantile="0.9"} 0
http_response_size_bytes{handler="/api/query_range",quantile="0.99"} 0
http_response_size_bytes_sum{handler="/api/query_range"} 0
http_response_size_bytes_count{handler="/api/query_range"} 0
http_response_size_bytes{handler="/api/targets",quantile="0.5"} 0
http_response_size_bytes{handler="/api/targets",quantile="0.9"} 0
http_response_size_bytes{handler="/api/targets",quantile="0.99"} 0
http_response_size_bytes_sum{handler="/api/targets"} 0
http_response_size_bytes_count{handler="/api/targets"} 0
http_response_size_bytes{handler="/consoles/",quantile="0.5"} 0
http_response_size_bytes{handler="/consoles/",quantile="0.9"} 0
http_response_size_bytes{handler="/consoles/",quantile="0.99"} 0
http_response_size_bytes_sum{handler="/consoles/"} 0
http_response_size_bytes_count{handler="/consoles/"} 0
http_response_size_bytes{handler="/graph",quantile="0.5"} 0
http_response_size_bytes{handler="/graph",quantile="0.9"} 0
http_response_size_bytes{handler="/graph",quantile="0.99"} 0
http_response_size_bytes_sum{handler="/graph"} 0
http_response_size_bytes_count{handler="/graph"} 0
http_response_size_bytes{handler="/heap",quantile="0.5"} 0
http_response_size_bytes{handler="/heap",quantile="0.9"} 0
http_response_size_bytes{handler="/heap",quantile="0.99"} 0
http_response_size_bytes_sum{handler="/heap"} 0
http_response_size_bytes_count{handler="/heap"} 0
http_response_size_bytes{handler="/static/",quantile="0.5"} 0
http_response_size_bytes{handler="/static/",quantile="0.9"} 0
http_response_size_bytes{handler="/static/",quantile="0.99"} 0
http_response_size_bytes_sum{handler="/static/"} 0
http_response_size_bytes_count{handler="/static/"} 0
http_response_size_bytes{handler="prometheus",quantile="0.5"} 2049
http_response_size_bytes{handler="prometheus",quantile="0.9"} 2058
http_response_size_bytes{handler="prometheus",quantile="0.99"} 2064
http_response_size_bytes_sum{handler="prometheus"} 247001
http_response_size_bytes_count{handler="prometheus"} 119
# HELP process_cpu_seconds_total Total user and system CPU time spent in seconds.
# TYPE process_cpu_seconds_total counter
process_cpu_seconds_total 0.55
# HELP go_goroutines Number of goroutines that currently exist.
# TYPE go_goroutines gauge
go_goroutines 70
# HELP process_max_fds Maximum number of open file descriptors.
# TYPE process_max_fds gauge
process_max_fds 8192
# HELP process_open_fds Number of open file descriptors.
# TYPE process_open_fds gauge
process_open_fds 29
# HELP process_resident_memory_bytes Resident memory size in bytes.
# TYPE process_resident_memory_bytes gauge
process_resident_memory_bytes 5.3870592e+07
# HELP process_start_time_seconds Start time of the process since unix epoch in seconds.
# TYPE process_start_time_seconds gauge
process_start_time_seconds 1.42236894836e+09
# HELP process_virtual_memory_bytes Virtual memory size in bytes.
# TYPE process_virtual_memory_bytes gauge
process_virtual_memory_bytes 5.41478912e+08
# HELP prometheus_dns_sd_lookup_failures_total The number of DNS-SD lookup failures.
# TYPE prometheus_dns_sd_lookup_failures_total counter
prometheus_dns_sd_lookup_failures_total 0
# HELP prometheus_dns_sd_lookups_total The number of DNS-SD lookups.
# TYPE prometheus_dns_sd_lookups_total counter
prometheus_dns_sd_lookups_total 7
# HELP prometheus_evaluator_duration_milliseconds The duration for all evaluations to execute.
# TYPE prometheus_evaluator_duration_milliseconds summary
prometheus_evaluator_duration_milliseconds{quantile="0.01"} 0
prometheus_evaluator_duration_milliseconds{quantile="0.05"} 0
prometheus_evaluator_duration_milliseconds{quantile="0.5"} 0
prometheus_evaluator_duration_milliseconds{quantile="0.9"} 1
prometheus_evaluator_duration_milliseconds{quantile="0.99"} 1
prometheus_evaluator_duration_milliseconds_sum 12
prometheus_evaluator_duration_milliseconds_count 23
# HELP prometheus_local_storage_checkpoint_duration_milliseconds The duration (in milliseconds) it took to checkpoint in-memory metrics and head chunks.
# TYPE prometheus_local_storage_checkpoint_duration_milliseconds gauge
prometheus_local_storage_checkpoint_duration_milliseconds 0
# HELP prometheus_local_storage_chunk_ops_total The total number of chunk operations by their type.
# TYPE prometheus_local_storage_chunk_ops_total counter
prometheus_local_storage_chunk_ops_total{type="create"} 598
prometheus_local_storage_chunk_ops_total{type="persist"} 174
prometheus_local_storage_chunk_ops_total{type="pin"} 920
prometheus_local_storage_chunk_ops_total{type="transcode"} 415
prometheus_local_storage_chunk_ops_total{type="unpin"} 920
# HELP prometheus_local_storage_indexing_batch_latency_milliseconds Quantiles for batch indexing latencies in milliseconds.
# TYPE prometheus_local_storage_indexing_batch_latency_milliseconds summary
prometheus_local_storage_indexing_batch_latency_milliseconds{quantile="0.5"} 0
prometheus_local_storage_indexing_batch_latency_milliseconds{quantile="0.9"} 0
prometheus_local_storage_indexing_batch_latency_milliseconds{quantile="0.99"} 0
prometheus_local_storage_indexing_batch_latency_milliseconds_sum 0
prometheus_local_storage_indexing_batch_latency_milliseconds_count 1
# HELP prometheus_local_storage_indexing_batch_sizes Quantiles for indexing batch sizes (number of metrics per batch).
# TYPE prometheus_local_storage_indexing_batch_sizes summary
prometheus_local_storage_indexing_batch_sizes{quantile="0.5"} 2
prometheus_local_storage_indexing_batch_sizes{quantile="0.9"} 2
prometheus_local_storage_indexing_batch_sizes{quantile="0.99"} 2
prometheus_local_storage_indexing_batch_sizes_sum 2
prometheus_local_storage_indexing_batch_sizes_count 1
# HELP prometheus_local_storage_indexing_queue_capacity The capacity of the indexing queue.
# TYPE prometheus_local_storage_indexing_queue_capacity gauge
prometheus_local_storage_indexing_queue_capacity 16384
# HELP prometheus_local_storage_indexing_queue_length The number of metrics waiting to be indexed.
# TYPE prometheus_local_storage_indexing_queue_length gauge
prometheus_local_storage_indexing_queue_length 0
# HELP prometheus_local_storage_ingested_samples_total The total number of samples ingested.
# TYPE prometheus_local_storage_ingested_samples_total counter
prometheus_local_storage_ingested_samples_total 30473
# HELP prometheus_local_storage_invalid_preload_requests_total The total number of preload requests referring to a non-existent series. This is an indication of outdated label indexes.
# TYPE prometheus_local_storage_invalid_preload_requests_total counter
prometheus_local_storage_invalid_preload_requests_total 0
# HELP prometheus_local_storage_memory_chunkdescs The current number of chunk descriptors in memory.
# TYPE prometheus_local_storage_memory_chunkdescs gauge
prometheus_local_storage_memory_chunkdescs 1059
# HELP prometheus_local_storage_memory_chunks The current number of chunks in memory, excluding cloned chunks (i.e. chunks without a descriptor).
# TYPE prometheus_local_storage_memory_chunks gauge
prometheus_local_storage_memory_chunks 1020
# HELP prometheus_local_storage_memory_series The current number of series in memory.
# TYPE prometheus_local_storage_memory_series gauge
prometheus_local_storage_memory_series 424
# HELP prometheus_local_storage_persist_latency_microseconds A summary of latencies for persisting each chunk.
# TYPE prometheus_local_storage_persist_latency_microseconds summary
prometheus_local_storage_persist_latency_microseconds{quantile="0.5"} 30.377
prometheus_local_storage_persist_latency_microseconds{quantile="0.9"} 203.539
prometheus_local_storage_persist_latency_microseconds{quantile="0.99"} 2626.463
prometheus_local_storage_persist_latency_microseconds_sum 20424.415
prometheus_local_storage_persist_latency_microseconds_count 174
# HELP prometheus_local_storage_persist_queue_capacity The total capacity of the persist queue.
# TYPE prometheus_local_storage_persist_queue_capacity gauge
prometheus_local_storage_persist_queue_capacity 1024
# HELP prometheus_local_storage_persist_queue_length The current number of chunks waiting in the persist queue.
# TYPE prometheus_local_storage_persist_queue_length gauge
prometheus_local_storage_persist_queue_length 0
# HELP prometheus_local_storage_series_ops_total The total number of series operations by their type.
# TYPE prometheus_local_storage_series_ops_total counter
prometheus_local_storage_series_ops_total{type="create"} 2
prometheus_local_storage_series_ops_total{type="maintenance_in_memory"} 11
# HELP prometheus_notifications_latency_milliseconds Latency quantiles for sending alert notifications (not including dropped notifications).
# TYPE prometheus_notifications_latency_milliseconds summary
prometheus_notifications_latency_milliseconds{quantile="0.5"} 0
prometheus_notifications_latency_milliseconds{quantile="0.9"} 0
prometheus_notifications_latency_milliseconds{quantile="0.99"} 0
prometheus_notifications_latency_milliseconds_sum 0
prometheus_notifications_latency_milliseconds_count 0
# HELP prometheus_notifications_queue_capacity The capacity of the alert notifications queue.
# TYPE prometheus_notifications_queue_capacity gauge
prometheus_notifications_queue_capacity 100
# HELP prometheus_notifications_queue_length The number of alert notifications in the queue.
# TYPE prometheus_notifications_queue_length gauge
prometheus_notifications_queue_length 0
# HELP prometheus_rule_evaluation_duration_milliseconds The duration for a rule to execute.
# TYPE prometheus_rule_evaluation_duration_milliseconds summary
prometheus_rule_evaluation_duration_milliseconds{rule_type="alerting",quantile="0.5"} 0
prometheus_rule_evaluation_duration_milliseconds{rule_type="alerting",quantile="0.9"} 0
prometheus_rule_evaluation_duration_milliseconds{rule_type="alerting",quantile="0.99"} 2
prometheus_rule_evaluation_duration_milliseconds_sum{rule_type="alerting"} 12
prometheus_rule_evaluation_duration_milliseconds_count{rule_type="alerting"} 115
prometheus_rule_evaluation_duration_milliseconds{rule_type="recording",quantile="0.5"} 0
prometheus_rule_evaluation_duration_milliseconds{rule_type="recording",quantile="0.9"} 0
prometheus_rule_evaluation_duration_milliseconds{rule_type="recording",quantile="0.99"} 3
prometheus_rule_evaluation_duration_milliseconds_sum{rule_type="recording"} 15
prometheus_rule_evaluation_duration_milliseconds_count{rule_type="recording"} 115
# HELP prometheus_rule_evaluation_failures_total The total number of rule evaluation failures.
# TYPE prometheus_rule_evaluation_failures_total counter
prometheus_rule_evaluation_failures_total 0
# HELP prometheus_samples_queue_capacity Capacity of the queue for unwritten samples.
# TYPE prometheus_samples_queue_capacity gauge
prometheus_samples_queue_capacity 4096
# HELP prometheus_samples_queue_length Current number of items in the queue for unwritten samples. Each item comprises all samples exposed by one target as one metric family (i.e. metrics of the same name).
# TYPE prometheus_samples_queue_length gauge
prometheus_samples_queue_length 0
# HELP prometheus_target_interval_length_seconds Actual intervals between scrapes.
# TYPE prometheus_target_interval_length_seconds summary
prometheus_target_interval_length_seconds{interval="15s",quantile="0.01"} 14
prometheus_target_interval_length_seconds{interval="15s",quantile="0.05"} 14
prometheus_target_interval_length_seconds{interval="15s",quantile="0.5"} 15
prometheus_target_interval_length_seconds{interval="15s",quantile="0.9"} 15
prometheus_target_interval_length_seconds{interval="15s",quantile="0.99"} 15
prometheus_target_interval_length_seconds_sum{interval="15s"} 175
prometheus_target_interval_length_seconds_count{interval="15s"} 12
prometheus_target_interval_length_seconds{interval="1s",quantile="0.01"} 0
prometheus_target_interval_length_seconds{interval="1s",quantile="0.05"} 0
prometheus_target_interval_length_seconds{interval="1s",quantile="0.5"} 0
prometheus_target_interval_length_seconds{interval="1s",quantile="0.9"} 1
prometheus_target_interval_length_seconds{interval="1s",quantile="0.99"} 1
prometheus_target_interval_length_seconds_sum{interval="1s"} 55
prometheus_target_interval_length_seconds_count{interval="1s"} 117

Binary file not shown.

View File

@@ -1,443 +0,0 @@
// Copyright 2014 The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package expfmt
import (
"bytes"
"math"
"strings"
"testing"
"github.com/golang/protobuf/proto"
dto "github.com/prometheus/client_model/go"
)
func testCreate(t testing.TB) {
var scenarios = []struct {
in *dto.MetricFamily
out string
}{
// 0: Counter, NaN as value, timestamp given.
{
in: &dto.MetricFamily{
Name: proto.String("name"),
Help: proto.String("two-line\n doc str\\ing"),
Type: dto.MetricType_COUNTER.Enum(),
Metric: []*dto.Metric{
&dto.Metric{
Label: []*dto.LabelPair{
&dto.LabelPair{
Name: proto.String("labelname"),
Value: proto.String("val1"),
},
&dto.LabelPair{
Name: proto.String("basename"),
Value: proto.String("basevalue"),
},
},
Counter: &dto.Counter{
Value: proto.Float64(math.NaN()),
},
},
&dto.Metric{
Label: []*dto.LabelPair{
&dto.LabelPair{
Name: proto.String("labelname"),
Value: proto.String("val2"),
},
&dto.LabelPair{
Name: proto.String("basename"),
Value: proto.String("basevalue"),
},
},
Counter: &dto.Counter{
Value: proto.Float64(.23),
},
TimestampMs: proto.Int64(1234567890),
},
},
},
out: `# HELP name two-line\n doc str\\ing
# TYPE name counter
name{labelname="val1",basename="basevalue"} NaN
name{labelname="val2",basename="basevalue"} 0.23 1234567890
`,
},
// 1: Gauge, some escaping required, +Inf as value, multi-byte characters in label values.
{
in: &dto.MetricFamily{
Name: proto.String("gauge_name"),
Help: proto.String("gauge\ndoc\nstr\"ing"),
Type: dto.MetricType_GAUGE.Enum(),
Metric: []*dto.Metric{
&dto.Metric{
Label: []*dto.LabelPair{
&dto.LabelPair{
Name: proto.String("name_1"),
Value: proto.String("val with\nnew line"),
},
&dto.LabelPair{
Name: proto.String("name_2"),
Value: proto.String("val with \\backslash and \"quotes\""),
},
},
Gauge: &dto.Gauge{
Value: proto.Float64(math.Inf(+1)),
},
},
&dto.Metric{
Label: []*dto.LabelPair{
&dto.LabelPair{
Name: proto.String("name_1"),
Value: proto.String("Björn"),
},
&dto.LabelPair{
Name: proto.String("name_2"),
Value: proto.String("佖佥"),
},
},
Gauge: &dto.Gauge{
Value: proto.Float64(3.14E42),
},
},
},
},
out: `# HELP gauge_name gauge\ndoc\nstr"ing
# TYPE gauge_name gauge
gauge_name{name_1="val with\nnew line",name_2="val with \\backslash and \"quotes\""} +Inf
gauge_name{name_1="Björn",name_2="佖佥"} 3.14e+42
`,
},
// 2: Untyped, no help, one sample with no labels and -Inf as value, another sample with one label.
{
in: &dto.MetricFamily{
Name: proto.String("untyped_name"),
Type: dto.MetricType_UNTYPED.Enum(),
Metric: []*dto.Metric{
&dto.Metric{
Untyped: &dto.Untyped{
Value: proto.Float64(math.Inf(-1)),
},
},
&dto.Metric{
Label: []*dto.LabelPair{
&dto.LabelPair{
Name: proto.String("name_1"),
Value: proto.String("value 1"),
},
},
Untyped: &dto.Untyped{
Value: proto.Float64(-1.23e-45),
},
},
},
},
out: `# TYPE untyped_name untyped
untyped_name -Inf
untyped_name{name_1="value 1"} -1.23e-45
`,
},
// 3: Summary.
{
in: &dto.MetricFamily{
Name: proto.String("summary_name"),
Help: proto.String("summary docstring"),
Type: dto.MetricType_SUMMARY.Enum(),
Metric: []*dto.Metric{
&dto.Metric{
Summary: &dto.Summary{
SampleCount: proto.Uint64(42),
SampleSum: proto.Float64(-3.4567),
Quantile: []*dto.Quantile{
&dto.Quantile{
Quantile: proto.Float64(0.5),
Value: proto.Float64(-1.23),
},
&dto.Quantile{
Quantile: proto.Float64(0.9),
Value: proto.Float64(.2342354),
},
&dto.Quantile{
Quantile: proto.Float64(0.99),
Value: proto.Float64(0),
},
},
},
},
&dto.Metric{
Label: []*dto.LabelPair{
&dto.LabelPair{
Name: proto.String("name_1"),
Value: proto.String("value 1"),
},
&dto.LabelPair{
Name: proto.String("name_2"),
Value: proto.String("value 2"),
},
},
Summary: &dto.Summary{
SampleCount: proto.Uint64(4711),
SampleSum: proto.Float64(2010.1971),
Quantile: []*dto.Quantile{
&dto.Quantile{
Quantile: proto.Float64(0.5),
Value: proto.Float64(1),
},
&dto.Quantile{
Quantile: proto.Float64(0.9),
Value: proto.Float64(2),
},
&dto.Quantile{
Quantile: proto.Float64(0.99),
Value: proto.Float64(3),
},
},
},
},
},
},
out: `# HELP summary_name summary docstring
# TYPE summary_name summary
summary_name{quantile="0.5"} -1.23
summary_name{quantile="0.9"} 0.2342354
summary_name{quantile="0.99"} 0
summary_name_sum -3.4567
summary_name_count 42
summary_name{name_1="value 1",name_2="value 2",quantile="0.5"} 1
summary_name{name_1="value 1",name_2="value 2",quantile="0.9"} 2
summary_name{name_1="value 1",name_2="value 2",quantile="0.99"} 3
summary_name_sum{name_1="value 1",name_2="value 2"} 2010.1971
summary_name_count{name_1="value 1",name_2="value 2"} 4711
`,
},
// 4: Histogram
{
in: &dto.MetricFamily{
Name: proto.String("request_duration_microseconds"),
Help: proto.String("The response latency."),
Type: dto.MetricType_HISTOGRAM.Enum(),
Metric: []*dto.Metric{
&dto.Metric{
Histogram: &dto.Histogram{
SampleCount: proto.Uint64(2693),
SampleSum: proto.Float64(1756047.3),
Bucket: []*dto.Bucket{
&dto.Bucket{
UpperBound: proto.Float64(100),
CumulativeCount: proto.Uint64(123),
},
&dto.Bucket{
UpperBound: proto.Float64(120),
CumulativeCount: proto.Uint64(412),
},
&dto.Bucket{
UpperBound: proto.Float64(144),
CumulativeCount: proto.Uint64(592),
},
&dto.Bucket{
UpperBound: proto.Float64(172.8),
CumulativeCount: proto.Uint64(1524),
},
&dto.Bucket{
UpperBound: proto.Float64(math.Inf(+1)),
CumulativeCount: proto.Uint64(2693),
},
},
},
},
},
},
out: `# HELP request_duration_microseconds The response latency.
# TYPE request_duration_microseconds histogram
request_duration_microseconds_bucket{le="100"} 123
request_duration_microseconds_bucket{le="120"} 412
request_duration_microseconds_bucket{le="144"} 592
request_duration_microseconds_bucket{le="172.8"} 1524
request_duration_microseconds_bucket{le="+Inf"} 2693
request_duration_microseconds_sum 1.7560473e+06
request_duration_microseconds_count 2693
`,
},
// 5: Histogram with missing +Inf bucket.
{
in: &dto.MetricFamily{
Name: proto.String("request_duration_microseconds"),
Help: proto.String("The response latency."),
Type: dto.MetricType_HISTOGRAM.Enum(),
Metric: []*dto.Metric{
&dto.Metric{
Histogram: &dto.Histogram{
SampleCount: proto.Uint64(2693),
SampleSum: proto.Float64(1756047.3),
Bucket: []*dto.Bucket{
&dto.Bucket{
UpperBound: proto.Float64(100),
CumulativeCount: proto.Uint64(123),
},
&dto.Bucket{
UpperBound: proto.Float64(120),
CumulativeCount: proto.Uint64(412),
},
&dto.Bucket{
UpperBound: proto.Float64(144),
CumulativeCount: proto.Uint64(592),
},
&dto.Bucket{
UpperBound: proto.Float64(172.8),
CumulativeCount: proto.Uint64(1524),
},
},
},
},
},
},
out: `# HELP request_duration_microseconds The response latency.
# TYPE request_duration_microseconds histogram
request_duration_microseconds_bucket{le="100"} 123
request_duration_microseconds_bucket{le="120"} 412
request_duration_microseconds_bucket{le="144"} 592
request_duration_microseconds_bucket{le="172.8"} 1524
request_duration_microseconds_bucket{le="+Inf"} 2693
request_duration_microseconds_sum 1.7560473e+06
request_duration_microseconds_count 2693
`,
},
// 6: No metric type, should result in default type Counter.
{
in: &dto.MetricFamily{
Name: proto.String("name"),
Help: proto.String("doc string"),
Metric: []*dto.Metric{
&dto.Metric{
Counter: &dto.Counter{
Value: proto.Float64(math.Inf(-1)),
},
},
},
},
out: `# HELP name doc string
# TYPE name counter
name -Inf
`,
},
}
for i, scenario := range scenarios {
out := bytes.NewBuffer(make([]byte, 0, len(scenario.out)))
n, err := MetricFamilyToText(out, scenario.in)
if err != nil {
t.Errorf("%d. error: %s", i, err)
continue
}
if expected, got := len(scenario.out), n; expected != got {
t.Errorf(
"%d. expected %d bytes written, got %d",
i, expected, got,
)
}
if expected, got := scenario.out, out.String(); expected != got {
t.Errorf(
"%d. expected out=%q, got %q",
i, expected, got,
)
}
}
}
func TestCreate(t *testing.T) {
testCreate(t)
}
func BenchmarkCreate(b *testing.B) {
for i := 0; i < b.N; i++ {
testCreate(b)
}
}
func testCreateError(t testing.TB) {
var scenarios = []struct {
in *dto.MetricFamily
err string
}{
// 0: No metric.
{
in: &dto.MetricFamily{
Name: proto.String("name"),
Help: proto.String("doc string"),
Type: dto.MetricType_COUNTER.Enum(),
Metric: []*dto.Metric{},
},
err: "MetricFamily has no metrics",
},
// 1: No metric name.
{
in: &dto.MetricFamily{
Help: proto.String("doc string"),
Type: dto.MetricType_UNTYPED.Enum(),
Metric: []*dto.Metric{
&dto.Metric{
Untyped: &dto.Untyped{
Value: proto.Float64(math.Inf(-1)),
},
},
},
},
err: "MetricFamily has no name",
},
// 2: Wrong type.
{
in: &dto.MetricFamily{
Name: proto.String("name"),
Help: proto.String("doc string"),
Type: dto.MetricType_COUNTER.Enum(),
Metric: []*dto.Metric{
&dto.Metric{
Untyped: &dto.Untyped{
Value: proto.Float64(math.Inf(-1)),
},
},
},
},
err: "expected counter in metric",
},
}
for i, scenario := range scenarios {
var out bytes.Buffer
_, err := MetricFamilyToText(&out, scenario.in)
if err == nil {
t.Errorf("%d. expected error, got nil", i)
continue
}
if expected, got := scenario.err, err.Error(); strings.Index(got, expected) != 0 {
t.Errorf(
"%d. expected error starting with %q, got %q",
i, expected, got,
)
}
}
}
func TestCreateError(t *testing.T) {
testCreateError(t)
}
func BenchmarkCreateError(b *testing.B) {
for i := 0; i < b.N; i++ {
testCreateError(b)
}
}

View File

@@ -1,593 +0,0 @@
// Copyright 2014 The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package expfmt
import (
"math"
"strings"
"testing"
"github.com/golang/protobuf/proto"
dto "github.com/prometheus/client_model/go"
)
func testTextParse(t testing.TB) {
var scenarios = []struct {
in string
out []*dto.MetricFamily
}{
// 0: Empty lines as input.
{
in: `
`,
out: []*dto.MetricFamily{},
},
// 1: Minimal case.
{
in: `
minimal_metric 1.234
another_metric -3e3 103948
# Even that:
no_labels{} 3
# HELP line for non-existing metric will be ignored.
`,
out: []*dto.MetricFamily{
&dto.MetricFamily{
Name: proto.String("minimal_metric"),
Type: dto.MetricType_UNTYPED.Enum(),
Metric: []*dto.Metric{
&dto.Metric{
Untyped: &dto.Untyped{
Value: proto.Float64(1.234),
},
},
},
},
&dto.MetricFamily{
Name: proto.String("another_metric"),
Type: dto.MetricType_UNTYPED.Enum(),
Metric: []*dto.Metric{
&dto.Metric{
Untyped: &dto.Untyped{
Value: proto.Float64(-3e3),
},
TimestampMs: proto.Int64(103948),
},
},
},
&dto.MetricFamily{
Name: proto.String("no_labels"),
Type: dto.MetricType_UNTYPED.Enum(),
Metric: []*dto.Metric{
&dto.Metric{
Untyped: &dto.Untyped{
Value: proto.Float64(3),
},
},
},
},
},
},
// 2: Counters & gauges, docstrings, various whitespace, escape sequences.
{
in: `
# A normal comment.
#
# TYPE name counter
name{labelname="val1",basename="basevalue"} NaN
name {labelname="val2",basename="base\"v\\al\nue"} 0.23 1234567890
# HELP name two-line\n doc str\\ing
# HELP name2 doc str"ing 2
# TYPE name2 gauge
name2{labelname="val2" ,basename = "basevalue2" } +Inf 54321
name2{ labelname = "val1" , }-Inf
`,
out: []*dto.MetricFamily{
&dto.MetricFamily{
Name: proto.String("name"),
Help: proto.String("two-line\n doc str\\ing"),
Type: dto.MetricType_COUNTER.Enum(),
Metric: []*dto.Metric{
&dto.Metric{
Label: []*dto.LabelPair{
&dto.LabelPair{
Name: proto.String("labelname"),
Value: proto.String("val1"),
},
&dto.LabelPair{
Name: proto.String("basename"),
Value: proto.String("basevalue"),
},
},
Counter: &dto.Counter{
Value: proto.Float64(math.NaN()),
},
},
&dto.Metric{
Label: []*dto.LabelPair{
&dto.LabelPair{
Name: proto.String("labelname"),
Value: proto.String("val2"),
},
&dto.LabelPair{
Name: proto.String("basename"),
Value: proto.String("base\"v\\al\nue"),
},
},
Counter: &dto.Counter{
Value: proto.Float64(.23),
},
TimestampMs: proto.Int64(1234567890),
},
},
},
&dto.MetricFamily{
Name: proto.String("name2"),
Help: proto.String("doc str\"ing 2"),
Type: dto.MetricType_GAUGE.Enum(),
Metric: []*dto.Metric{
&dto.Metric{
Label: []*dto.LabelPair{
&dto.LabelPair{
Name: proto.String("labelname"),
Value: proto.String("val2"),
},
&dto.LabelPair{
Name: proto.String("basename"),
Value: proto.String("basevalue2"),
},
},
Gauge: &dto.Gauge{
Value: proto.Float64(math.Inf(+1)),
},
TimestampMs: proto.Int64(54321),
},
&dto.Metric{
Label: []*dto.LabelPair{
&dto.LabelPair{
Name: proto.String("labelname"),
Value: proto.String("val1"),
},
},
Gauge: &dto.Gauge{
Value: proto.Float64(math.Inf(-1)),
},
},
},
},
},
},
// 3: The evil summary, mixed with other types and funny comments.
{
in: `
# TYPE my_summary summary
my_summary{n1="val1",quantile="0.5"} 110
decoy -1 -2
my_summary{n1="val1",quantile="0.9"} 140 1
my_summary_count{n1="val1"} 42
# Latest timestamp wins in case of a summary.
my_summary_sum{n1="val1"} 4711 2
fake_sum{n1="val1"} 2001
# TYPE another_summary summary
another_summary_count{n2="val2",n1="val1"} 20
my_summary_count{n2="val2",n1="val1"} 5 5
another_summary{n1="val1",n2="val2",quantile=".3"} -1.2
my_summary_sum{n1="val2"} 08 15
my_summary{n1="val3", quantile="0.2"} 4711
my_summary{n1="val1",n2="val2",quantile="-12.34",} NaN
# some
# funny comments
# HELP
# HELP
# HELP my_summary
# HELP my_summary
`,
out: []*dto.MetricFamily{
&dto.MetricFamily{
Name: proto.String("fake_sum"),
Type: dto.MetricType_UNTYPED.Enum(),
Metric: []*dto.Metric{
&dto.Metric{
Label: []*dto.LabelPair{
&dto.LabelPair{
Name: proto.String("n1"),
Value: proto.String("val1"),
},
},
Untyped: &dto.Untyped{
Value: proto.Float64(2001),
},
},
},
},
&dto.MetricFamily{
Name: proto.String("decoy"),
Type: dto.MetricType_UNTYPED.Enum(),
Metric: []*dto.Metric{
&dto.Metric{
Untyped: &dto.Untyped{
Value: proto.Float64(-1),
},
TimestampMs: proto.Int64(-2),
},
},
},
&dto.MetricFamily{
Name: proto.String("my_summary"),
Type: dto.MetricType_SUMMARY.Enum(),
Metric: []*dto.Metric{
&dto.Metric{
Label: []*dto.LabelPair{
&dto.LabelPair{
Name: proto.String("n1"),
Value: proto.String("val1"),
},
},
Summary: &dto.Summary{
SampleCount: proto.Uint64(42),
SampleSum: proto.Float64(4711),
Quantile: []*dto.Quantile{
&dto.Quantile{
Quantile: proto.Float64(0.5),
Value: proto.Float64(110),
},
&dto.Quantile{
Quantile: proto.Float64(0.9),
Value: proto.Float64(140),
},
},
},
TimestampMs: proto.Int64(2),
},
&dto.Metric{
Label: []*dto.LabelPair{
&dto.LabelPair{
Name: proto.String("n2"),
Value: proto.String("val2"),
},
&dto.LabelPair{
Name: proto.String("n1"),
Value: proto.String("val1"),
},
},
Summary: &dto.Summary{
SampleCount: proto.Uint64(5),
Quantile: []*dto.Quantile{
&dto.Quantile{
Quantile: proto.Float64(-12.34),
Value: proto.Float64(math.NaN()),
},
},
},
TimestampMs: proto.Int64(5),
},
&dto.Metric{
Label: []*dto.LabelPair{
&dto.LabelPair{
Name: proto.String("n1"),
Value: proto.String("val2"),
},
},
Summary: &dto.Summary{
SampleSum: proto.Float64(8),
},
TimestampMs: proto.Int64(15),
},
&dto.Metric{
Label: []*dto.LabelPair{
&dto.LabelPair{
Name: proto.String("n1"),
Value: proto.String("val3"),
},
},
Summary: &dto.Summary{
Quantile: []*dto.Quantile{
&dto.Quantile{
Quantile: proto.Float64(0.2),
Value: proto.Float64(4711),
},
},
},
},
},
},
&dto.MetricFamily{
Name: proto.String("another_summary"),
Type: dto.MetricType_SUMMARY.Enum(),
Metric: []*dto.Metric{
&dto.Metric{
Label: []*dto.LabelPair{
&dto.LabelPair{
Name: proto.String("n2"),
Value: proto.String("val2"),
},
&dto.LabelPair{
Name: proto.String("n1"),
Value: proto.String("val1"),
},
},
Summary: &dto.Summary{
SampleCount: proto.Uint64(20),
Quantile: []*dto.Quantile{
&dto.Quantile{
Quantile: proto.Float64(0.3),
Value: proto.Float64(-1.2),
},
},
},
},
},
},
},
},
// 4: The histogram.
{
in: `
# HELP request_duration_microseconds The response latency.
# TYPE request_duration_microseconds histogram
request_duration_microseconds_bucket{le="100"} 123
request_duration_microseconds_bucket{le="120"} 412
request_duration_microseconds_bucket{le="144"} 592
request_duration_microseconds_bucket{le="172.8"} 1524
request_duration_microseconds_bucket{le="+Inf"} 2693
request_duration_microseconds_sum 1.7560473e+06
request_duration_microseconds_count 2693
`,
out: []*dto.MetricFamily{
{
Name: proto.String("request_duration_microseconds"),
Help: proto.String("The response latency."),
Type: dto.MetricType_HISTOGRAM.Enum(),
Metric: []*dto.Metric{
&dto.Metric{
Histogram: &dto.Histogram{
SampleCount: proto.Uint64(2693),
SampleSum: proto.Float64(1756047.3),
Bucket: []*dto.Bucket{
&dto.Bucket{
UpperBound: proto.Float64(100),
CumulativeCount: proto.Uint64(123),
},
&dto.Bucket{
UpperBound: proto.Float64(120),
CumulativeCount: proto.Uint64(412),
},
&dto.Bucket{
UpperBound: proto.Float64(144),
CumulativeCount: proto.Uint64(592),
},
&dto.Bucket{
UpperBound: proto.Float64(172.8),
CumulativeCount: proto.Uint64(1524),
},
&dto.Bucket{
UpperBound: proto.Float64(math.Inf(+1)),
CumulativeCount: proto.Uint64(2693),
},
},
},
},
},
},
},
},
}
for i, scenario := range scenarios {
out, err := parser.TextToMetricFamilies(strings.NewReader(scenario.in))
if err != nil {
t.Errorf("%d. error: %s", i, err)
continue
}
if expected, got := len(scenario.out), len(out); expected != got {
t.Errorf(
"%d. expected %d MetricFamilies, got %d",
i, expected, got,
)
}
for _, expected := range scenario.out {
got, ok := out[expected.GetName()]
if !ok {
t.Errorf(
"%d. expected MetricFamily %q, found none",
i, expected.GetName(),
)
continue
}
if expected.String() != got.String() {
t.Errorf(
"%d. expected MetricFamily %s, got %s",
i, expected, got,
)
}
}
}
}
func TestTextParse(t *testing.T) {
testTextParse(t)
}
func BenchmarkTextParse(b *testing.B) {
for i := 0; i < b.N; i++ {
testTextParse(b)
}
}
func testTextParseError(t testing.TB) {
var scenarios = []struct {
in string
err string
}{
// 0: No new-line at end of input.
{
in: `
bla 3.14
blubber 42`,
err: "text format parsing error in line 3: unexpected end of input stream",
},
// 1: Invalid escape sequence in label value.
{
in: `metric{label="\t"} 3.14`,
err: "text format parsing error in line 1: invalid escape sequence",
},
// 2: Newline in label value.
{
in: `
metric{label="new
line"} 3.14
`,
err: `text format parsing error in line 2: label value "new" contains unescaped new-line`,
},
// 3:
{
in: `metric{@="bla"} 3.14`,
err: "text format parsing error in line 1: invalid label name for metric",
},
// 4:
{
in: `metric{__name__="bla"} 3.14`,
err: `text format parsing error in line 1: label name "__name__" is reserved`,
},
// 5:
{
in: `metric{label+="bla"} 3.14`,
err: "text format parsing error in line 1: expected '=' after label name",
},
// 6:
{
in: `metric{label=bla} 3.14`,
err: "text format parsing error in line 1: expected '\"' at start of label value",
},
// 7:
{
in: `
# TYPE metric summary
metric{quantile="bla"} 3.14
`,
err: "text format parsing error in line 3: expected float as value for 'quantile' label",
},
// 8:
{
in: `metric{label="bla"+} 3.14`,
err: "text format parsing error in line 1: unexpected end of label value",
},
// 9:
{
in: `metric{label="bla"} 3.14 2.72
`,
err: "text format parsing error in line 1: expected integer as timestamp",
},
// 10:
{
in: `metric{label="bla"} 3.14 2 3
`,
err: "text format parsing error in line 1: spurious string after timestamp",
},
// 11:
{
in: `metric{label="bla"} blubb
`,
err: "text format parsing error in line 1: expected float as value",
},
// 12:
{
in: `
# HELP metric one
# HELP metric two
`,
err: "text format parsing error in line 3: second HELP line for metric name",
},
// 13:
{
in: `
# TYPE metric counter
# TYPE metric untyped
`,
err: `text format parsing error in line 3: second TYPE line for metric name "metric", or TYPE reported after samples`,
},
// 14:
{
in: `
metric 4.12
# TYPE metric counter
`,
err: `text format parsing error in line 3: second TYPE line for metric name "metric", or TYPE reported after samples`,
},
// 14:
{
in: `
# TYPE metric bla
`,
err: "text format parsing error in line 2: unknown metric type",
},
// 15:
{
in: `
# TYPE met-ric
`,
err: "text format parsing error in line 2: invalid metric name in comment",
},
// 16:
{
in: `@invalidmetric{label="bla"} 3.14 2`,
err: "text format parsing error in line 1: invalid metric name",
},
// 17:
{
in: `{label="bla"} 3.14 2`,
err: "text format parsing error in line 1: invalid metric name",
},
// 18:
{
in: `
# TYPE metric histogram
metric_bucket{le="bla"} 3.14
`,
err: "text format parsing error in line 3: expected float as value for 'le' label",
},
// 19: Invalid UTF-8 in label value.
{
in: "metric{l=\"\xbd\"} 3.14\n",
err: "text format parsing error in line 1: invalid label value \"\\xbd\"",
},
}
for i, scenario := range scenarios {
_, err := parser.TextToMetricFamilies(strings.NewReader(scenario.in))
if err == nil {
t.Errorf("%d. expected error, got nil", i)
continue
}
if expected, got := scenario.err, err.Error(); strings.Index(got, expected) != 0 {
t.Errorf(
"%d. expected error starting with %q, got %q",
i, expected, got,
)
}
}
}
func TestTextParseError(t *testing.T) {
testTextParseError(t)
}
func BenchmarkParseError(b *testing.B) {
for i := 0; i < b.N; i++ {
testTextParseError(b)
}
}

View File

@@ -1,33 +0,0 @@
package goautoneg
import (
"testing"
)
var chrome = "application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5"
func TestParseAccept(t *testing.T) {
alternatives := []string{"text/html", "image/png"}
content_type := Negotiate(chrome, alternatives)
if content_type != "image/png" {
t.Errorf("got %s expected image/png", content_type)
}
alternatives = []string{"text/html", "text/plain", "text/n3"}
content_type = Negotiate(chrome, alternatives)
if content_type != "text/html" {
t.Errorf("got %s expected text/html", content_type)
}
alternatives = []string{"text/n3", "text/plain"}
content_type = Negotiate(chrome, alternatives)
if content_type != "text/plain" {
t.Errorf("got %s expected text/plain", content_type)
}
alternatives = []string{"text/n3", "application/rdf+xml"}
content_type = Negotiate(chrome, alternatives)
if content_type != "text/n3" {
t.Errorf("got %s expected text/n3", content_type)
}
}

View File

@@ -1,89 +0,0 @@
// Copyright 2015 The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// +build windows
package log
import (
"fmt"
"os"
"golang.org/x/sys/windows/svc/eventlog"
"github.com/sirupsen/logrus"
)
func init() {
setEventlogFormatter = func(l logger, name string, debugAsInfo bool) error {
if name == "" {
return fmt.Errorf("missing name parameter")
}
fmter, err := newEventlogger(name, debugAsInfo, l.entry.Logger.Formatter)
if err != nil {
fmt.Fprintf(os.Stderr, "error creating eventlog formatter: %v\n", err)
l.Errorf("can't connect logger to eventlog: %v", err)
return err
}
l.entry.Logger.Formatter = fmter
return nil
}
}
type eventlogger struct {
log *eventlog.Log
debugAsInfo bool
wrap logrus.Formatter
}
func newEventlogger(name string, debugAsInfo bool, fmter logrus.Formatter) (*eventlogger, error) {
logHandle, err := eventlog.Open(name)
if err != nil {
return nil, err
}
return &eventlogger{log: logHandle, debugAsInfo: debugAsInfo, wrap: fmter}, nil
}
func (s *eventlogger) Format(e *logrus.Entry) ([]byte, error) {
data, err := s.wrap.Format(e)
if err != nil {
fmt.Fprintf(os.Stderr, "eventlogger: can't format entry: %v\n", err)
return data, err
}
switch e.Level {
case logrus.PanicLevel:
fallthrough
case logrus.FatalLevel:
fallthrough
case logrus.ErrorLevel:
err = s.log.Error(102, e.Message)
case logrus.WarnLevel:
err = s.log.Warning(101, e.Message)
case logrus.InfoLevel:
err = s.log.Info(100, e.Message)
case logrus.DebugLevel:
if s.debugAsInfo {
err = s.log.Info(100, e.Message)
}
default:
err = s.log.Info(100, e.Message)
}
if err != nil {
fmt.Fprintf(os.Stderr, "eventlogger: can't send log to eventlog: %v\n", err)
}
return data, err
}

View File

@@ -1,364 +0,0 @@
// Copyright 2015 The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package log
import (
"fmt"
"io"
"io/ioutil"
"log"
"net/url"
"os"
"runtime"
"strconv"
"strings"
"github.com/sirupsen/logrus"
"gopkg.in/alecthomas/kingpin.v2"
)
// setSyslogFormatter is nil if the target architecture does not support syslog.
var setSyslogFormatter func(logger, string, string) error
// setEventlogFormatter is nil if the target OS does not support Eventlog (i.e., is not Windows).
var setEventlogFormatter func(logger, string, bool) error
func setJSONFormatter() {
origLogger.Formatter = &logrus.JSONFormatter{}
}
type loggerSettings struct {
level string
format string
}
func (s *loggerSettings) apply(ctx *kingpin.ParseContext) error {
err := baseLogger.SetLevel(s.level)
if err != nil {
return err
}
err = baseLogger.SetFormat(s.format)
return err
}
// AddFlags adds the flags used by this package to the Kingpin application.
// To use the default Kingpin application, call AddFlags(kingpin.CommandLine)
func AddFlags(a *kingpin.Application) {
s := loggerSettings{}
a.Flag("log.level", "Only log messages with the given severity or above. Valid levels: [debug, info, warn, error, fatal]").
Default(origLogger.Level.String()).
StringVar(&s.level)
defaultFormat := url.URL{Scheme: "logger", Opaque: "stderr"}
a.Flag("log.format", `Set the log target and format. Example: "logger:syslog?appname=bob&local=7" or "logger:stdout?json=true"`).
Default(defaultFormat.String()).
StringVar(&s.format)
a.Action(s.apply)
}
// Logger is the interface for loggers used in the Prometheus components.
type Logger interface {
Debug(...interface{})
Debugln(...interface{})
Debugf(string, ...interface{})
Info(...interface{})
Infoln(...interface{})
Infof(string, ...interface{})
Warn(...interface{})
Warnln(...interface{})
Warnf(string, ...interface{})
Error(...interface{})
Errorln(...interface{})
Errorf(string, ...interface{})
Fatal(...interface{})
Fatalln(...interface{})
Fatalf(string, ...interface{})
With(key string, value interface{}) Logger
SetFormat(string) error
SetLevel(string) error
}
type logger struct {
entry *logrus.Entry
}
func (l logger) With(key string, value interface{}) Logger {
return logger{l.entry.WithField(key, value)}
}
// Debug logs a message at level Debug on the standard logger.
func (l logger) Debug(args ...interface{}) {
l.sourced().Debug(args...)
}
// Debug logs a message at level Debug on the standard logger.
func (l logger) Debugln(args ...interface{}) {
l.sourced().Debugln(args...)
}
// Debugf logs a message at level Debug on the standard logger.
func (l logger) Debugf(format string, args ...interface{}) {
l.sourced().Debugf(format, args...)
}
// Info logs a message at level Info on the standard logger.
func (l logger) Info(args ...interface{}) {
l.sourced().Info(args...)
}
// Info logs a message at level Info on the standard logger.
func (l logger) Infoln(args ...interface{}) {
l.sourced().Infoln(args...)
}
// Infof logs a message at level Info on the standard logger.
func (l logger) Infof(format string, args ...interface{}) {
l.sourced().Infof(format, args...)
}
// Warn logs a message at level Warn on the standard logger.
func (l logger) Warn(args ...interface{}) {
l.sourced().Warn(args...)
}
// Warn logs a message at level Warn on the standard logger.
func (l logger) Warnln(args ...interface{}) {
l.sourced().Warnln(args...)
}
// Warnf logs a message at level Warn on the standard logger.
func (l logger) Warnf(format string, args ...interface{}) {
l.sourced().Warnf(format, args...)
}
// Error logs a message at level Error on the standard logger.
func (l logger) Error(args ...interface{}) {
l.sourced().Error(args...)
}
// Error logs a message at level Error on the standard logger.
func (l logger) Errorln(args ...interface{}) {
l.sourced().Errorln(args...)
}
// Errorf logs a message at level Error on the standard logger.
func (l logger) Errorf(format string, args ...interface{}) {
l.sourced().Errorf(format, args...)
}
// Fatal logs a message at level Fatal on the standard logger.
func (l logger) Fatal(args ...interface{}) {
l.sourced().Fatal(args...)
}
// Fatal logs a message at level Fatal on the standard logger.
func (l logger) Fatalln(args ...interface{}) {
l.sourced().Fatalln(args...)
}
// Fatalf logs a message at level Fatal on the standard logger.
func (l logger) Fatalf(format string, args ...interface{}) {
l.sourced().Fatalf(format, args...)
}
func (l logger) SetLevel(level string) error {
lvl, err := logrus.ParseLevel(level)
if err != nil {
return err
}
l.entry.Logger.Level = lvl
return nil
}
func (l logger) SetFormat(format string) error {
u, err := url.Parse(format)
if err != nil {
return err
}
if u.Scheme != "logger" {
return fmt.Errorf("invalid scheme %s", u.Scheme)
}
jsonq := u.Query().Get("json")
if jsonq == "true" {
setJSONFormatter()
}
switch u.Opaque {
case "syslog":
if setSyslogFormatter == nil {
return fmt.Errorf("system does not support syslog")
}
appname := u.Query().Get("appname")
facility := u.Query().Get("local")
return setSyslogFormatter(l, appname, facility)
case "eventlog":
if setEventlogFormatter == nil {
return fmt.Errorf("system does not support eventlog")
}
name := u.Query().Get("name")
debugAsInfo := false
debugAsInfoRaw := u.Query().Get("debugAsInfo")
if parsedDebugAsInfo, err := strconv.ParseBool(debugAsInfoRaw); err == nil {
debugAsInfo = parsedDebugAsInfo
}
return setEventlogFormatter(l, name, debugAsInfo)
case "stdout":
l.entry.Logger.Out = os.Stdout
case "stderr":
l.entry.Logger.Out = os.Stderr
default:
return fmt.Errorf("unsupported logger %q", u.Opaque)
}
return nil
}
// sourced adds a source field to the logger that contains
// the file name and line where the logging happened.
func (l logger) sourced() *logrus.Entry {
_, file, line, ok := runtime.Caller(2)
if !ok {
file = "<???>"
line = 1
} else {
slash := strings.LastIndex(file, "/")
file = file[slash+1:]
}
return l.entry.WithField("source", fmt.Sprintf("%s:%d", file, line))
}
var origLogger = logrus.New()
var baseLogger = logger{entry: logrus.NewEntry(origLogger)}
// Base returns the default Logger logging to
func Base() Logger {
return baseLogger
}
// NewLogger returns a new Logger logging to out.
func NewLogger(w io.Writer) Logger {
l := logrus.New()
l.Out = w
return logger{entry: logrus.NewEntry(l)}
}
// NewNopLogger returns a logger that discards all log messages.
func NewNopLogger() Logger {
l := logrus.New()
l.Out = ioutil.Discard
return logger{entry: logrus.NewEntry(l)}
}
// With adds a field to the logger.
func With(key string, value interface{}) Logger {
return baseLogger.With(key, value)
}
// Debug logs a message at level Debug on the standard logger.
func Debug(args ...interface{}) {
baseLogger.sourced().Debug(args...)
}
// Debugln logs a message at level Debug on the standard logger.
func Debugln(args ...interface{}) {
baseLogger.sourced().Debugln(args...)
}
// Debugf logs a message at level Debug on the standard logger.
func Debugf(format string, args ...interface{}) {
baseLogger.sourced().Debugf(format, args...)
}
// Info logs a message at level Info on the standard logger.
func Info(args ...interface{}) {
baseLogger.sourced().Info(args...)
}
// Infoln logs a message at level Info on the standard logger.
func Infoln(args ...interface{}) {
baseLogger.sourced().Infoln(args...)
}
// Infof logs a message at level Info on the standard logger.
func Infof(format string, args ...interface{}) {
baseLogger.sourced().Infof(format, args...)
}
// Warn logs a message at level Warn on the standard logger.
func Warn(args ...interface{}) {
baseLogger.sourced().Warn(args...)
}
// Warnln logs a message at level Warn on the standard logger.
func Warnln(args ...interface{}) {
baseLogger.sourced().Warnln(args...)
}
// Warnf logs a message at level Warn on the standard logger.
func Warnf(format string, args ...interface{}) {
baseLogger.sourced().Warnf(format, args...)
}
// Error logs a message at level Error on the standard logger.
func Error(args ...interface{}) {
baseLogger.sourced().Error(args...)
}
// Errorln logs a message at level Error on the standard logger.
func Errorln(args ...interface{}) {
baseLogger.sourced().Errorln(args...)
}
// Errorf logs a message at level Error on the standard logger.
func Errorf(format string, args ...interface{}) {
baseLogger.sourced().Errorf(format, args...)
}
// Fatal logs a message at level Fatal on the standard logger.
func Fatal(args ...interface{}) {
baseLogger.sourced().Fatal(args...)
}
// Fatalln logs a message at level Fatal on the standard logger.
func Fatalln(args ...interface{}) {
baseLogger.sourced().Fatalln(args...)
}
// Fatalf logs a message at level Fatal on the standard logger.
func Fatalf(format string, args ...interface{}) {
baseLogger.sourced().Fatalf(format, args...)
}
// AddHook adds hook to Prometheus' original logger.
func AddHook(hook logrus.Hook) {
origLogger.Hooks.Add(hook)
}
type errorLogWriter struct{}
func (errorLogWriter) Write(b []byte) (int, error) {
baseLogger.sourced().Error(string(b))
return len(b), nil
}
// NewErrorLogger returns a log.Logger that is meant to be used
// in the ErrorLog field of an http.Server to log HTTP server errors.
func NewErrorLogger() *log.Logger {
return log.New(&errorLogWriter{}, "", 0)
}

View File

@@ -1,39 +0,0 @@
// Copyright 2015 The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package log
import (
"bytes"
"regexp"
"testing"
"github.com/sirupsen/logrus"
)
func TestFileLineLogging(t *testing.T) {
var buf bytes.Buffer
origLogger.Out = &buf
origLogger.Formatter = &logrus.TextFormatter{
DisableColors: true,
}
// The default logging level should be "info".
Debug("This debug-level line should not show up in the output.")
Infof("This %s-level line should show up in the output.", "info")
re := `^time=".*" level=info msg="This info-level line should show up in the output." source="log_test.go:33"\n$`
if !regexp.MustCompile(re).Match(buf.Bytes()) {
t.Fatalf("%q did not match expected regex %q", buf.String(), re)
}
}

View File

@@ -1,126 +0,0 @@
// Copyright 2015 The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// +build !windows,!nacl,!plan9
package log
import (
"fmt"
"log/syslog"
"os"
"github.com/sirupsen/logrus"
)
var _ logrus.Formatter = (*syslogger)(nil)
func init() {
setSyslogFormatter = func(l logger, appname, local string) error {
if appname == "" {
return fmt.Errorf("missing appname parameter")
}
if local == "" {
return fmt.Errorf("missing local parameter")
}
fmter, err := newSyslogger(appname, local, l.entry.Logger.Formatter)
if err != nil {
fmt.Fprintf(os.Stderr, "error creating syslog formatter: %v\n", err)
l.entry.Errorf("can't connect logger to syslog: %v", err)
return err
}
l.entry.Logger.Formatter = fmter
return nil
}
}
var prefixTag []byte
type syslogger struct {
wrap logrus.Formatter
out *syslog.Writer
}
func newSyslogger(appname string, facility string, fmter logrus.Formatter) (*syslogger, error) {
priority, err := getFacility(facility)
if err != nil {
return nil, err
}
out, err := syslog.New(priority, appname)
_, isJSON := fmter.(*logrus.JSONFormatter)
if isJSON {
// add cee tag to json formatted syslogs
prefixTag = []byte("@cee:")
}
return &syslogger{
out: out,
wrap: fmter,
}, err
}
func getFacility(facility string) (syslog.Priority, error) {
switch facility {
case "0":
return syslog.LOG_LOCAL0, nil
case "1":
return syslog.LOG_LOCAL1, nil
case "2":
return syslog.LOG_LOCAL2, nil
case "3":
return syslog.LOG_LOCAL3, nil
case "4":
return syslog.LOG_LOCAL4, nil
case "5":
return syslog.LOG_LOCAL5, nil
case "6":
return syslog.LOG_LOCAL6, nil
case "7":
return syslog.LOG_LOCAL7, nil
}
return syslog.LOG_LOCAL0, fmt.Errorf("invalid local(%s) for syslog", facility)
}
func (s *syslogger) Format(e *logrus.Entry) ([]byte, error) {
data, err := s.wrap.Format(e)
if err != nil {
fmt.Fprintf(os.Stderr, "syslogger: can't format entry: %v\n", err)
return data, err
}
// only append tag to data sent to syslog (line), not to what
// is returned
line := string(append(prefixTag, data...))
switch e.Level {
case logrus.PanicLevel:
err = s.out.Crit(line)
case logrus.FatalLevel:
err = s.out.Crit(line)
case logrus.ErrorLevel:
err = s.out.Err(line)
case logrus.WarnLevel:
err = s.out.Warning(line)
case logrus.InfoLevel:
err = s.out.Info(line)
case logrus.DebugLevel:
err = s.out.Debug(line)
default:
err = s.out.Notice(line)
}
if err != nil {
fmt.Fprintf(os.Stderr, "syslogger: can't send log to syslog: %v\n", err)
}
return data, err
}

View File

@@ -1,52 +0,0 @@
// Copyright 2015 The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// +build !windows,!nacl,!plan9
package log
import (
"errors"
"log/syslog"
"testing"
)
func TestGetFacility(t *testing.T) {
testCases := []struct {
facility string
expectedPriority syslog.Priority
expectedErr error
}{
{"0", syslog.LOG_LOCAL0, nil},
{"1", syslog.LOG_LOCAL1, nil},
{"2", syslog.LOG_LOCAL2, nil},
{"3", syslog.LOG_LOCAL3, nil},
{"4", syslog.LOG_LOCAL4, nil},
{"5", syslog.LOG_LOCAL5, nil},
{"6", syslog.LOG_LOCAL6, nil},
{"7", syslog.LOG_LOCAL7, nil},
{"8", syslog.LOG_LOCAL0, errors.New("invalid local(8) for syslog")},
}
for _, tc := range testCases {
priority, err := getFacility(tc.facility)
if err != tc.expectedErr {
if err.Error() != tc.expectedErr.Error() {
t.Errorf("want %s, got %s", tc.expectedErr.Error(), err.Error())
}
}
if priority != tc.expectedPriority {
t.Errorf("want %q, got %q", tc.expectedPriority, priority)
}
}
}

View File

@@ -1,118 +0,0 @@
// Copyright 2013 The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package model
import (
"strings"
"testing"
"time"
)
func TestAlertValidate(t *testing.T) {
ts := time.Now()
var cases = []struct {
alert *Alert
err string
}{
{
alert: &Alert{
Labels: LabelSet{"a": "b"},
StartsAt: ts,
},
},
{
alert: &Alert{
Labels: LabelSet{"a": "b"},
},
err: "start time missing",
},
{
alert: &Alert{
Labels: LabelSet{"a": "b"},
StartsAt: ts,
EndsAt: ts,
},
},
{
alert: &Alert{
Labels: LabelSet{"a": "b"},
StartsAt: ts,
EndsAt: ts.Add(1 * time.Minute),
},
},
{
alert: &Alert{
Labels: LabelSet{"a": "b"},
StartsAt: ts,
EndsAt: ts.Add(-1 * time.Minute),
},
err: "start time must be before end time",
},
{
alert: &Alert{
StartsAt: ts,
},
err: "at least one label pair required",
},
{
alert: &Alert{
Labels: LabelSet{"a": "b", "!bad": "label"},
StartsAt: ts,
},
err: "invalid label set: invalid name",
},
{
alert: &Alert{
Labels: LabelSet{"a": "b", "bad": "\xfflabel"},
StartsAt: ts,
},
err: "invalid label set: invalid value",
},
{
alert: &Alert{
Labels: LabelSet{"a": "b"},
Annotations: LabelSet{"!bad": "label"},
StartsAt: ts,
},
err: "invalid annotations: invalid name",
},
{
alert: &Alert{
Labels: LabelSet{"a": "b"},
Annotations: LabelSet{"bad": "\xfflabel"},
StartsAt: ts,
},
err: "invalid annotations: invalid value",
},
}
for i, c := range cases {
err := c.alert.Validate()
if err == nil {
if c.err == "" {
continue
}
t.Errorf("%d. Expected error %q but got none", i, c.err)
continue
}
if c.err == "" && err != nil {
t.Errorf("%d. Expected no error but got %q", i, err)
continue
}
if !strings.Contains(err.Error(), c.err) {
t.Errorf("%d. Expected error to contain %q but got %q", i, c.err, err)
}
}
}

View File

@@ -1,140 +0,0 @@
// Copyright 2013 The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package model
import (
"sort"
"testing"
)
func testLabelNames(t testing.TB) {
var scenarios = []struct {
in LabelNames
out LabelNames
}{
{
in: LabelNames{"ZZZ", "zzz"},
out: LabelNames{"ZZZ", "zzz"},
},
{
in: LabelNames{"aaa", "AAA"},
out: LabelNames{"AAA", "aaa"},
},
}
for i, scenario := range scenarios {
sort.Sort(scenario.in)
for j, expected := range scenario.out {
if expected != scenario.in[j] {
t.Errorf("%d.%d expected %s, got %s", i, j, expected, scenario.in[j])
}
}
}
}
func TestLabelNames(t *testing.T) {
testLabelNames(t)
}
func BenchmarkLabelNames(b *testing.B) {
for i := 0; i < b.N; i++ {
testLabelNames(b)
}
}
func testLabelValues(t testing.TB) {
var scenarios = []struct {
in LabelValues
out LabelValues
}{
{
in: LabelValues{"ZZZ", "zzz"},
out: LabelValues{"ZZZ", "zzz"},
},
{
in: LabelValues{"aaa", "AAA"},
out: LabelValues{"AAA", "aaa"},
},
}
for i, scenario := range scenarios {
sort.Sort(scenario.in)
for j, expected := range scenario.out {
if expected != scenario.in[j] {
t.Errorf("%d.%d expected %s, got %s", i, j, expected, scenario.in[j])
}
}
}
}
func TestLabelValues(t *testing.T) {
testLabelValues(t)
}
func BenchmarkLabelValues(b *testing.B) {
for i := 0; i < b.N; i++ {
testLabelValues(b)
}
}
func TestLabelNameIsValid(t *testing.T) {
var scenarios = []struct {
ln LabelName
valid bool
}{
{
ln: "Avalid_23name",
valid: true,
},
{
ln: "_Avalid_23name",
valid: true,
},
{
ln: "1valid_23name",
valid: false,
},
{
ln: "avalid_23name",
valid: true,
},
{
ln: "Ava:lid_23name",
valid: false,
},
{
ln: "a lid_23name",
valid: false,
},
{
ln: ":leading_colon",
valid: false,
},
{
ln: "colon:in:the:middle",
valid: false,
},
}
for _, s := range scenarios {
if s.ln.IsValid() != s.valid {
t.Errorf("Expected %v for %q using IsValid method", s.valid, s.ln)
}
if LabelNameRE.MatchString(string(s.ln)) != s.valid {
t.Errorf("Expected %v for %q using regexp match", s.valid, s.ln)
}
}
}

View File

@@ -1,132 +0,0 @@
// Copyright 2013 The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package model
import "testing"
func testMetric(t testing.TB) {
var scenarios = []struct {
input LabelSet
fingerprint Fingerprint
fastFingerprint Fingerprint
}{
{
input: LabelSet{},
fingerprint: 14695981039346656037,
fastFingerprint: 14695981039346656037,
},
{
input: LabelSet{
"first_name": "electro",
"occupation": "robot",
"manufacturer": "westinghouse",
},
fingerprint: 5911716720268894962,
fastFingerprint: 11310079640881077873,
},
{
input: LabelSet{
"x": "y",
},
fingerprint: 8241431561484471700,
fastFingerprint: 13948396922932177635,
},
{
input: LabelSet{
"a": "bb",
"b": "c",
},
fingerprint: 3016285359649981711,
fastFingerprint: 3198632812309449502,
},
{
input: LabelSet{
"a": "b",
"bb": "c",
},
fingerprint: 7122421792099404749,
fastFingerprint: 5774953389407657638,
},
}
for i, scenario := range scenarios {
input := Metric(scenario.input)
if scenario.fingerprint != input.Fingerprint() {
t.Errorf("%d. expected %d, got %d", i, scenario.fingerprint, input.Fingerprint())
}
if scenario.fastFingerprint != input.FastFingerprint() {
t.Errorf("%d. expected %d, got %d", i, scenario.fastFingerprint, input.FastFingerprint())
}
}
}
func TestMetric(t *testing.T) {
testMetric(t)
}
func BenchmarkMetric(b *testing.B) {
for i := 0; i < b.N; i++ {
testMetric(b)
}
}
func TestMetricNameIsValid(t *testing.T) {
var scenarios = []struct {
mn LabelValue
valid bool
}{
{
mn: "Avalid_23name",
valid: true,
},
{
mn: "_Avalid_23name",
valid: true,
},
{
mn: "1valid_23name",
valid: false,
},
{
mn: "avalid_23name",
valid: true,
},
{
mn: "Ava:lid_23name",
valid: true,
},
{
mn: "a lid_23name",
valid: false,
},
{
mn: ":leading_colon",
valid: true,
},
{
mn: "colon:in:the:middle",
valid: true,
},
}
for _, s := range scenarios {
if IsValidMetricName(s.mn) != s.valid {
t.Errorf("Expected %v for %q using IsValidMetricName function", s.valid, s.mn)
}
if MetricNameRE.MatchString(string(s.mn)) != s.valid {
t.Errorf("Expected %v for %q using regexp matching", s.valid, s.mn)
}
}
}

View File

@@ -1,314 +0,0 @@
// Copyright 2014 The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package model
import (
"runtime"
"sync"
"testing"
)
func TestLabelsToSignature(t *testing.T) {
var scenarios = []struct {
in map[string]string
out uint64
}{
{
in: map[string]string{},
out: 14695981039346656037,
},
{
in: map[string]string{"name": "garland, briggs", "fear": "love is not enough"},
out: 5799056148416392346,
},
}
for i, scenario := range scenarios {
actual := LabelsToSignature(scenario.in)
if actual != scenario.out {
t.Errorf("%d. expected %d, got %d", i, scenario.out, actual)
}
}
}
func TestMetricToFingerprint(t *testing.T) {
var scenarios = []struct {
in LabelSet
out Fingerprint
}{
{
in: LabelSet{},
out: 14695981039346656037,
},
{
in: LabelSet{"name": "garland, briggs", "fear": "love is not enough"},
out: 5799056148416392346,
},
}
for i, scenario := range scenarios {
actual := labelSetToFingerprint(scenario.in)
if actual != scenario.out {
t.Errorf("%d. expected %d, got %d", i, scenario.out, actual)
}
}
}
func TestMetricToFastFingerprint(t *testing.T) {
var scenarios = []struct {
in LabelSet
out Fingerprint
}{
{
in: LabelSet{},
out: 14695981039346656037,
},
{
in: LabelSet{"name": "garland, briggs", "fear": "love is not enough"},
out: 12952432476264840823,
},
}
for i, scenario := range scenarios {
actual := labelSetToFastFingerprint(scenario.in)
if actual != scenario.out {
t.Errorf("%d. expected %d, got %d", i, scenario.out, actual)
}
}
}
func TestSignatureForLabels(t *testing.T) {
var scenarios = []struct {
in Metric
labels LabelNames
out uint64
}{
{
in: Metric{},
labels: nil,
out: 14695981039346656037,
},
{
in: Metric{},
labels: LabelNames{"empty"},
out: 7187873163539638612,
},
{
in: Metric{"name": "garland, briggs", "fear": "love is not enough"},
labels: LabelNames{"empty"},
out: 7187873163539638612,
},
{
in: Metric{"name": "garland, briggs", "fear": "love is not enough"},
labels: LabelNames{"fear", "name"},
out: 5799056148416392346,
},
{
in: Metric{"name": "garland, briggs", "fear": "love is not enough", "foo": "bar"},
labels: LabelNames{"fear", "name"},
out: 5799056148416392346,
},
{
in: Metric{"name": "garland, briggs", "fear": "love is not enough"},
labels: LabelNames{},
out: 14695981039346656037,
},
{
in: Metric{"name": "garland, briggs", "fear": "love is not enough"},
labels: nil,
out: 14695981039346656037,
},
}
for i, scenario := range scenarios {
actual := SignatureForLabels(scenario.in, scenario.labels...)
if actual != scenario.out {
t.Errorf("%d. expected %d, got %d", i, scenario.out, actual)
}
}
}
func TestSignatureWithoutLabels(t *testing.T) {
var scenarios = []struct {
in Metric
labels map[LabelName]struct{}
out uint64
}{
{
in: Metric{},
labels: nil,
out: 14695981039346656037,
},
{
in: Metric{"name": "garland, briggs", "fear": "love is not enough"},
labels: map[LabelName]struct{}{"fear": struct{}{}, "name": struct{}{}},
out: 14695981039346656037,
},
{
in: Metric{"name": "garland, briggs", "fear": "love is not enough", "foo": "bar"},
labels: map[LabelName]struct{}{"foo": struct{}{}},
out: 5799056148416392346,
},
{
in: Metric{"name": "garland, briggs", "fear": "love is not enough"},
labels: map[LabelName]struct{}{},
out: 5799056148416392346,
},
{
in: Metric{"name": "garland, briggs", "fear": "love is not enough"},
labels: nil,
out: 5799056148416392346,
},
}
for i, scenario := range scenarios {
actual := SignatureWithoutLabels(scenario.in, scenario.labels)
if actual != scenario.out {
t.Errorf("%d. expected %d, got %d", i, scenario.out, actual)
}
}
}
func benchmarkLabelToSignature(b *testing.B, l map[string]string, e uint64) {
for i := 0; i < b.N; i++ {
if a := LabelsToSignature(l); a != e {
b.Fatalf("expected signature of %d for %s, got %d", e, l, a)
}
}
}
func BenchmarkLabelToSignatureScalar(b *testing.B) {
benchmarkLabelToSignature(b, nil, 14695981039346656037)
}
func BenchmarkLabelToSignatureSingle(b *testing.B) {
benchmarkLabelToSignature(b, map[string]string{"first-label": "first-label-value"}, 5146282821936882169)
}
func BenchmarkLabelToSignatureDouble(b *testing.B) {
benchmarkLabelToSignature(b, map[string]string{"first-label": "first-label-value", "second-label": "second-label-value"}, 3195800080984914717)
}
func BenchmarkLabelToSignatureTriple(b *testing.B) {
benchmarkLabelToSignature(b, map[string]string{"first-label": "first-label-value", "second-label": "second-label-value", "third-label": "third-label-value"}, 13843036195897128121)
}
func benchmarkMetricToFingerprint(b *testing.B, ls LabelSet, e Fingerprint) {
for i := 0; i < b.N; i++ {
if a := labelSetToFingerprint(ls); a != e {
b.Fatalf("expected signature of %d for %s, got %d", e, ls, a)
}
}
}
func BenchmarkMetricToFingerprintScalar(b *testing.B) {
benchmarkMetricToFingerprint(b, nil, 14695981039346656037)
}
func BenchmarkMetricToFingerprintSingle(b *testing.B) {
benchmarkMetricToFingerprint(b, LabelSet{"first-label": "first-label-value"}, 5146282821936882169)
}
func BenchmarkMetricToFingerprintDouble(b *testing.B) {
benchmarkMetricToFingerprint(b, LabelSet{"first-label": "first-label-value", "second-label": "second-label-value"}, 3195800080984914717)
}
func BenchmarkMetricToFingerprintTriple(b *testing.B) {
benchmarkMetricToFingerprint(b, LabelSet{"first-label": "first-label-value", "second-label": "second-label-value", "third-label": "third-label-value"}, 13843036195897128121)
}
func benchmarkMetricToFastFingerprint(b *testing.B, ls LabelSet, e Fingerprint) {
for i := 0; i < b.N; i++ {
if a := labelSetToFastFingerprint(ls); a != e {
b.Fatalf("expected signature of %d for %s, got %d", e, ls, a)
}
}
}
func BenchmarkMetricToFastFingerprintScalar(b *testing.B) {
benchmarkMetricToFastFingerprint(b, nil, 14695981039346656037)
}
func BenchmarkMetricToFastFingerprintSingle(b *testing.B) {
benchmarkMetricToFastFingerprint(b, LabelSet{"first-label": "first-label-value"}, 5147259542624943964)
}
func BenchmarkMetricToFastFingerprintDouble(b *testing.B) {
benchmarkMetricToFastFingerprint(b, LabelSet{"first-label": "first-label-value", "second-label": "second-label-value"}, 18269973311206963528)
}
func BenchmarkMetricToFastFingerprintTriple(b *testing.B) {
benchmarkMetricToFastFingerprint(b, LabelSet{"first-label": "first-label-value", "second-label": "second-label-value", "third-label": "third-label-value"}, 15738406913934009676)
}
func BenchmarkEmptyLabelSignature(b *testing.B) {
input := []map[string]string{nil, {}}
var ms runtime.MemStats
runtime.ReadMemStats(&ms)
alloc := ms.Alloc
for _, labels := range input {
LabelsToSignature(labels)
}
runtime.ReadMemStats(&ms)
if got := ms.Alloc; alloc != got {
b.Fatal("expected LabelsToSignature with empty labels not to perform allocations")
}
}
func benchmarkMetricToFastFingerprintConc(b *testing.B, ls LabelSet, e Fingerprint, concLevel int) {
var start, end sync.WaitGroup
start.Add(1)
end.Add(concLevel)
for i := 0; i < concLevel; i++ {
go func() {
start.Wait()
for j := b.N / concLevel; j >= 0; j-- {
if a := labelSetToFastFingerprint(ls); a != e {
b.Fatalf("expected signature of %d for %s, got %d", e, ls, a)
}
}
end.Done()
}()
}
b.ResetTimer()
start.Done()
end.Wait()
}
func BenchmarkMetricToFastFingerprintTripleConc1(b *testing.B) {
benchmarkMetricToFastFingerprintConc(b, LabelSet{"first-label": "first-label-value", "second-label": "second-label-value", "third-label": "third-label-value"}, 15738406913934009676, 1)
}
func BenchmarkMetricToFastFingerprintTripleConc2(b *testing.B) {
benchmarkMetricToFastFingerprintConc(b, LabelSet{"first-label": "first-label-value", "second-label": "second-label-value", "third-label": "third-label-value"}, 15738406913934009676, 2)
}
func BenchmarkMetricToFastFingerprintTripleConc4(b *testing.B) {
benchmarkMetricToFastFingerprintConc(b, LabelSet{"first-label": "first-label-value", "second-label": "second-label-value", "third-label": "third-label-value"}, 15738406913934009676, 4)
}
func BenchmarkMetricToFastFingerprintTripleConc8(b *testing.B) {
benchmarkMetricToFastFingerprintConc(b, LabelSet{"first-label": "first-label-value", "second-label": "second-label-value", "third-label": "third-label-value"}, 15738406913934009676, 8)
}

View File

@@ -1,228 +0,0 @@
// Copyright 2015 The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package model
import (
"strings"
"testing"
"time"
)
func TestMatcherValidate(t *testing.T) {
var cases = []struct {
matcher *Matcher
err string
}{
{
matcher: &Matcher{
Name: "name",
Value: "value",
},
},
{
matcher: &Matcher{
Name: "name",
Value: "value",
IsRegex: true,
},
},
{
matcher: &Matcher{
Name: "name!",
Value: "value",
},
err: "invalid name",
},
{
matcher: &Matcher{
Name: "",
Value: "value",
},
err: "invalid name",
},
{
matcher: &Matcher{
Name: "name",
Value: "value\xff",
},
err: "invalid value",
},
{
matcher: &Matcher{
Name: "name",
Value: "",
},
err: "invalid value",
},
}
for i, c := range cases {
err := c.matcher.Validate()
if err == nil {
if c.err == "" {
continue
}
t.Errorf("%d. Expected error %q but got none", i, c.err)
continue
}
if c.err == "" && err != nil {
t.Errorf("%d. Expected no error but got %q", i, err)
continue
}
if !strings.Contains(err.Error(), c.err) {
t.Errorf("%d. Expected error to contain %q but got %q", i, c.err, err)
}
}
}
func TestSilenceValidate(t *testing.T) {
ts := time.Now()
var cases = []struct {
sil *Silence
err string
}{
{
sil: &Silence{
Matchers: []*Matcher{
{Name: "name", Value: "value"},
},
StartsAt: ts,
EndsAt: ts,
CreatedAt: ts,
CreatedBy: "name",
Comment: "comment",
},
},
{
sil: &Silence{
Matchers: []*Matcher{
{Name: "name", Value: "value"},
{Name: "name", Value: "value"},
{Name: "name", Value: "value"},
{Name: "name", Value: "value", IsRegex: true},
},
StartsAt: ts,
EndsAt: ts,
CreatedAt: ts,
CreatedBy: "name",
Comment: "comment",
},
},
{
sil: &Silence{
Matchers: []*Matcher{
{Name: "name", Value: "value"},
},
StartsAt: ts,
EndsAt: ts.Add(-1 * time.Minute),
CreatedAt: ts,
CreatedBy: "name",
Comment: "comment",
},
err: "start time must be before end time",
},
{
sil: &Silence{
Matchers: []*Matcher{
{Name: "name", Value: "value"},
},
StartsAt: ts,
CreatedAt: ts,
CreatedBy: "name",
Comment: "comment",
},
err: "end time missing",
},
{
sil: &Silence{
Matchers: []*Matcher{
{Name: "name", Value: "value"},
},
EndsAt: ts,
CreatedAt: ts,
CreatedBy: "name",
Comment: "comment",
},
err: "start time missing",
},
{
sil: &Silence{
Matchers: []*Matcher{
{Name: "!name", Value: "value"},
},
StartsAt: ts,
EndsAt: ts,
CreatedAt: ts,
CreatedBy: "name",
Comment: "comment",
},
err: "invalid matcher",
},
{
sil: &Silence{
Matchers: []*Matcher{
{Name: "name", Value: "value"},
},
StartsAt: ts,
EndsAt: ts,
CreatedAt: ts,
CreatedBy: "name",
},
err: "comment missing",
},
{
sil: &Silence{
Matchers: []*Matcher{
{Name: "name", Value: "value"},
},
StartsAt: ts,
EndsAt: ts,
CreatedBy: "name",
Comment: "comment",
},
err: "creation timestamp missing",
},
{
sil: &Silence{
Matchers: []*Matcher{
{Name: "name", Value: "value"},
},
StartsAt: ts,
EndsAt: ts,
CreatedAt: ts,
Comment: "comment",
},
err: "creator information missing",
},
}
for i, c := range cases {
err := c.sil.Validate()
if err == nil {
if c.err == "" {
continue
}
t.Errorf("%d. Expected error %q but got none", i, c.err)
continue
}
if c.err == "" && err != nil {
t.Errorf("%d. Expected no error but got %q", i, err)
continue
}
if !strings.Contains(err.Error(), c.err) {
t.Errorf("%d. Expected error to contain %q but got %q", i, c.err, err)
}
}
}

View File

@@ -1,132 +0,0 @@
// Copyright 2013 The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package model
import (
"testing"
"time"
)
func TestComparators(t *testing.T) {
t1a := TimeFromUnix(0)
t1b := TimeFromUnix(0)
t2 := TimeFromUnix(2*second - 1)
if !t1a.Equal(t1b) {
t.Fatalf("Expected %s to be equal to %s", t1a, t1b)
}
if t1a.Equal(t2) {
t.Fatalf("Expected %s to not be equal to %s", t1a, t2)
}
if !t1a.Before(t2) {
t.Fatalf("Expected %s to be before %s", t1a, t2)
}
if t1a.Before(t1b) {
t.Fatalf("Expected %s to not be before %s", t1a, t1b)
}
if !t2.After(t1a) {
t.Fatalf("Expected %s to be after %s", t2, t1a)
}
if t1b.After(t1a) {
t.Fatalf("Expected %s to not be after %s", t1b, t1a)
}
}
func TestTimeConversions(t *testing.T) {
unixSecs := int64(1136239445)
unixNsecs := int64(123456789)
unixNano := unixSecs*1e9 + unixNsecs
t1 := time.Unix(unixSecs, unixNsecs-unixNsecs%nanosPerTick)
t2 := time.Unix(unixSecs, unixNsecs)
ts := TimeFromUnixNano(unixNano)
if !ts.Time().Equal(t1) {
t.Fatalf("Expected %s, got %s", t1, ts.Time())
}
// Test available precision.
ts = TimeFromUnixNano(t2.UnixNano())
if !ts.Time().Equal(t1) {
t.Fatalf("Expected %s, got %s", t1, ts.Time())
}
if ts.UnixNano() != unixNano-unixNano%nanosPerTick {
t.Fatalf("Expected %d, got %d", unixNano, ts.UnixNano())
}
}
func TestDuration(t *testing.T) {
duration := time.Second + time.Minute + time.Hour
goTime := time.Unix(1136239445, 0)
ts := TimeFromUnix(goTime.Unix())
if !goTime.Add(duration).Equal(ts.Add(duration).Time()) {
t.Fatalf("Expected %s to be equal to %s", goTime.Add(duration), ts.Add(duration))
}
earlier := ts.Add(-duration)
delta := ts.Sub(earlier)
if delta != duration {
t.Fatalf("Expected %s to be equal to %s", delta, duration)
}
}
func TestParseDuration(t *testing.T) {
var cases = []struct {
in string
out time.Duration
}{
{
in: "0s",
out: 0,
}, {
in: "324ms",
out: 324 * time.Millisecond,
}, {
in: "3s",
out: 3 * time.Second,
}, {
in: "5m",
out: 5 * time.Minute,
}, {
in: "1h",
out: time.Hour,
}, {
in: "4d",
out: 4 * 24 * time.Hour,
}, {
in: "3w",
out: 3 * 7 * 24 * time.Hour,
}, {
in: "10y",
out: 10 * 365 * 24 * time.Hour,
},
}
for _, c := range cases {
d, err := ParseDuration(c.in)
if err != nil {
t.Errorf("Unexpected error on input %q", c.in)
}
if time.Duration(d) != c.out {
t.Errorf("Expected %v but got %v", c.out, d)
}
if d.String() != c.in {
t.Errorf("Expected duration string %q but got %q", c.in, d.String())
}
}
}

View File

@@ -1,468 +0,0 @@
// Copyright 2013 The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package model
import (
"encoding/json"
"math"
"reflect"
"sort"
"testing"
)
func TestEqualValues(t *testing.T) {
tests := map[string]struct {
in1, in2 SampleValue
want bool
}{
"equal floats": {
in1: 3.14,
in2: 3.14,
want: true,
},
"unequal floats": {
in1: 3.14,
in2: 3.1415,
want: false,
},
"positive inifinities": {
in1: SampleValue(math.Inf(+1)),
in2: SampleValue(math.Inf(+1)),
want: true,
},
"negative inifinities": {
in1: SampleValue(math.Inf(-1)),
in2: SampleValue(math.Inf(-1)),
want: true,
},
"different inifinities": {
in1: SampleValue(math.Inf(+1)),
in2: SampleValue(math.Inf(-1)),
want: false,
},
"number and infinity": {
in1: 42,
in2: SampleValue(math.Inf(+1)),
want: false,
},
"number and NaN": {
in1: 42,
in2: SampleValue(math.NaN()),
want: false,
},
"NaNs": {
in1: SampleValue(math.NaN()),
in2: SampleValue(math.NaN()),
want: true, // !!!
},
}
for name, test := range tests {
got := test.in1.Equal(test.in2)
if got != test.want {
t.Errorf("Comparing %s, %f and %f: got %t, want %t", name, test.in1, test.in2, got, test.want)
}
}
}
func TestEqualSamples(t *testing.T) {
testSample := &Sample{}
tests := map[string]struct {
in1, in2 *Sample
want bool
}{
"equal pointers": {
in1: testSample,
in2: testSample,
want: true,
},
"different metrics": {
in1: &Sample{Metric: Metric{"foo": "bar"}},
in2: &Sample{Metric: Metric{"foo": "biz"}},
want: false,
},
"different timestamp": {
in1: &Sample{Timestamp: 0},
in2: &Sample{Timestamp: 1},
want: false,
},
"different value": {
in1: &Sample{Value: 0},
in2: &Sample{Value: 1},
want: false,
},
"equal samples": {
in1: &Sample{
Metric: Metric{"foo": "bar"},
Timestamp: 0,
Value: 1,
},
in2: &Sample{
Metric: Metric{"foo": "bar"},
Timestamp: 0,
Value: 1,
},
want: true,
},
}
for name, test := range tests {
got := test.in1.Equal(test.in2)
if got != test.want {
t.Errorf("Comparing %s, %v and %v: got %t, want %t", name, test.in1, test.in2, got, test.want)
}
}
}
func TestSamplePairJSON(t *testing.T) {
input := []struct {
plain string
value SamplePair
}{
{
plain: `[1234.567,"123.1"]`,
value: SamplePair{
Value: 123.1,
Timestamp: 1234567,
},
},
}
for _, test := range input {
b, err := json.Marshal(test.value)
if err != nil {
t.Error(err)
continue
}
if string(b) != test.plain {
t.Errorf("encoding error: expected %q, got %q", test.plain, b)
continue
}
var sp SamplePair
err = json.Unmarshal(b, &sp)
if err != nil {
t.Error(err)
continue
}
if sp != test.value {
t.Errorf("decoding error: expected %v, got %v", test.value, sp)
}
}
}
func TestSampleJSON(t *testing.T) {
input := []struct {
plain string
value Sample
}{
{
plain: `{"metric":{"__name__":"test_metric"},"value":[1234.567,"123.1"]}`,
value: Sample{
Metric: Metric{
MetricNameLabel: "test_metric",
},
Value: 123.1,
Timestamp: 1234567,
},
},
}
for _, test := range input {
b, err := json.Marshal(test.value)
if err != nil {
t.Error(err)
continue
}
if string(b) != test.plain {
t.Errorf("encoding error: expected %q, got %q", test.plain, b)
continue
}
var sv Sample
err = json.Unmarshal(b, &sv)
if err != nil {
t.Error(err)
continue
}
if !reflect.DeepEqual(sv, test.value) {
t.Errorf("decoding error: expected %v, got %v", test.value, sv)
}
}
}
func TestVectorJSON(t *testing.T) {
input := []struct {
plain string
value Vector
}{
{
plain: `[]`,
value: Vector{},
},
{
plain: `[{"metric":{"__name__":"test_metric"},"value":[1234.567,"123.1"]}]`,
value: Vector{&Sample{
Metric: Metric{
MetricNameLabel: "test_metric",
},
Value: 123.1,
Timestamp: 1234567,
}},
},
{
plain: `[{"metric":{"__name__":"test_metric"},"value":[1234.567,"123.1"]},{"metric":{"foo":"bar"},"value":[1.234,"+Inf"]}]`,
value: Vector{
&Sample{
Metric: Metric{
MetricNameLabel: "test_metric",
},
Value: 123.1,
Timestamp: 1234567,
},
&Sample{
Metric: Metric{
"foo": "bar",
},
Value: SampleValue(math.Inf(1)),
Timestamp: 1234,
},
},
},
}
for _, test := range input {
b, err := json.Marshal(test.value)
if err != nil {
t.Error(err)
continue
}
if string(b) != test.plain {
t.Errorf("encoding error: expected %q, got %q", test.plain, b)
continue
}
var vec Vector
err = json.Unmarshal(b, &vec)
if err != nil {
t.Error(err)
continue
}
if !reflect.DeepEqual(vec, test.value) {
t.Errorf("decoding error: expected %v, got %v", test.value, vec)
}
}
}
func TestScalarJSON(t *testing.T) {
input := []struct {
plain string
value Scalar
}{
{
plain: `[123.456,"456"]`,
value: Scalar{
Timestamp: 123456,
Value: 456,
},
},
{
plain: `[123123.456,"+Inf"]`,
value: Scalar{
Timestamp: 123123456,
Value: SampleValue(math.Inf(1)),
},
},
{
plain: `[123123.456,"-Inf"]`,
value: Scalar{
Timestamp: 123123456,
Value: SampleValue(math.Inf(-1)),
},
},
}
for _, test := range input {
b, err := json.Marshal(test.value)
if err != nil {
t.Error(err)
continue
}
if string(b) != test.plain {
t.Errorf("encoding error: expected %q, got %q", test.plain, b)
continue
}
var sv Scalar
err = json.Unmarshal(b, &sv)
if err != nil {
t.Error(err)
continue
}
if sv != test.value {
t.Errorf("decoding error: expected %v, got %v", test.value, sv)
}
}
}
func TestStringJSON(t *testing.T) {
input := []struct {
plain string
value String
}{
{
plain: `[123.456,"test"]`,
value: String{
Timestamp: 123456,
Value: "test",
},
},
{
plain: `[123123.456,"台北"]`,
value: String{
Timestamp: 123123456,
Value: "台北",
},
},
}
for _, test := range input {
b, err := json.Marshal(test.value)
if err != nil {
t.Error(err)
continue
}
if string(b) != test.plain {
t.Errorf("encoding error: expected %q, got %q", test.plain, b)
continue
}
var sv String
err = json.Unmarshal(b, &sv)
if err != nil {
t.Error(err)
continue
}
if sv != test.value {
t.Errorf("decoding error: expected %v, got %v", test.value, sv)
}
}
}
func TestVectorSort(t *testing.T) {
input := Vector{
&Sample{
Metric: Metric{
MetricNameLabel: "A",
},
Timestamp: 1,
},
&Sample{
Metric: Metric{
MetricNameLabel: "A",
},
Timestamp: 2,
},
&Sample{
Metric: Metric{
MetricNameLabel: "C",
},
Timestamp: 1,
},
&Sample{
Metric: Metric{
MetricNameLabel: "C",
},
Timestamp: 2,
},
&Sample{
Metric: Metric{
MetricNameLabel: "B",
},
Timestamp: 1,
},
&Sample{
Metric: Metric{
MetricNameLabel: "B",
},
Timestamp: 2,
},
}
expected := Vector{
&Sample{
Metric: Metric{
MetricNameLabel: "A",
},
Timestamp: 1,
},
&Sample{
Metric: Metric{
MetricNameLabel: "A",
},
Timestamp: 2,
},
&Sample{
Metric: Metric{
MetricNameLabel: "B",
},
Timestamp: 1,
},
&Sample{
Metric: Metric{
MetricNameLabel: "B",
},
Timestamp: 2,
},
&Sample{
Metric: Metric{
MetricNameLabel: "C",
},
Timestamp: 1,
},
&Sample{
Metric: Metric{
MetricNameLabel: "C",
},
Timestamp: 2,
},
}
sort.Sort(input)
for i, actual := range input {
actualFp := actual.Metric.Fingerprint()
expectedFp := expected[i].Metric.Fingerprint()
if actualFp != expectedFp {
t.Fatalf("%d. Incorrect fingerprint. Got %s; want %s", i, actualFp.String(), expectedFp.String())
}
if actual.Timestamp != expected[i].Timestamp {
t.Fatalf("%d. Incorrect timestamp. Got %s; want %s", i, actual.Timestamp, expected[i].Timestamp)
}
}
}

View File

@@ -1,33 +0,0 @@
// Copyright 2017 The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package flag
import (
"github.com/prometheus/common/promlog"
kingpin "gopkg.in/alecthomas/kingpin.v2"
)
// LevelFlagName is the canonical flag name to configure the allowed log level
// within Prometheus projects.
const LevelFlagName = "log.level"
// LevelFlagHelp is the help description for the log.level flag.
const LevelFlagHelp = "Only log messages with the given severity or above. One of: [debug, info, warn, error]"
// AddFlags adds the flags used by this package to the Kingpin application.
// To use the default Kingpin application, call AddFlags(kingpin.CommandLine)
func AddFlags(a *kingpin.Application, logLevel *promlog.AllowedLevel) {
a.Flag(LevelFlagName, LevelFlagHelp).
Default("info").SetValue(logLevel)
}

View File

@@ -1,63 +0,0 @@
// Copyright 2017 The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Package promlog defines standardised ways to initialize Go kit loggers
// across Prometheus components.
// It should typically only ever be imported by main packages.
package promlog
import (
"os"
"github.com/go-kit/kit/log"
"github.com/go-kit/kit/log/level"
"github.com/pkg/errors"
)
// AllowedLevel is a settable identifier for the minimum level a log entry
// must be have.
type AllowedLevel struct {
s string
o level.Option
}
func (l *AllowedLevel) String() string {
return l.s
}
// Set updates the value of the allowed level.
func (l *AllowedLevel) Set(s string) error {
switch s {
case "debug":
l.o = level.AllowDebug()
case "info":
l.o = level.AllowInfo()
case "warn":
l.o = level.AllowWarn()
case "error":
l.o = level.AllowError()
default:
return errors.Errorf("unrecognized log level %q", s)
}
l.s = s
return nil
}
// New returns a new leveled oklog logger in the logfmt format. Each logged line will be annotated
// with a timestamp. The output always goes to stderr.
func New(al AllowedLevel) log.Logger {
l := log.NewLogfmtLogger(log.NewSyncWriter(os.Stderr))
l = level.NewFilter(l, al.o)
l = log.With(l, "ts", log.DefaultTimestampUTC, "caller", log.DefaultCaller)
return l
}

View File

@@ -1,110 +0,0 @@
package route
import (
"net/http"
"github.com/julienschmidt/httprouter"
"golang.org/x/net/context"
)
type param string
// Param returns param p for the context.
func Param(ctx context.Context, p string) string {
return ctx.Value(param(p)).(string)
}
// WithParam returns a new context with param p set to v.
func WithParam(ctx context.Context, p, v string) context.Context {
return context.WithValue(ctx, param(p), v)
}
// Router wraps httprouter.Router and adds support for prefixed sub-routers,
// per-request context injections and instrumentation.
type Router struct {
rtr *httprouter.Router
prefix string
instrh func(handlerName string, handler http.HandlerFunc) http.HandlerFunc
}
// New returns a new Router.
func New() *Router {
return &Router{
rtr: httprouter.New(),
}
}
// WithInstrumentation returns a router with instrumentation support.
func (r *Router) WithInstrumentation(instrh func(handlerName string, handler http.HandlerFunc) http.HandlerFunc) *Router {
return &Router{rtr: r.rtr, prefix: r.prefix, instrh: instrh}
}
// WithPrefix returns a router that prefixes all registered routes with prefix.
func (r *Router) WithPrefix(prefix string) *Router {
return &Router{rtr: r.rtr, prefix: r.prefix + prefix, instrh: r.instrh}
}
// handle turns a HandlerFunc into an httprouter.Handle.
func (r *Router) handle(handlerName string, h http.HandlerFunc) httprouter.Handle {
if r.instrh != nil {
// This needs to be outside the closure to avoid data race when reading and writing to 'h'.
h = r.instrh(handlerName, h)
}
return func(w http.ResponseWriter, req *http.Request, params httprouter.Params) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
for _, p := range params {
ctx = context.WithValue(ctx, param(p.Key), p.Value)
}
h(w, req.WithContext(ctx))
}
}
// Get registers a new GET route.
func (r *Router) Get(path string, h http.HandlerFunc) {
r.rtr.GET(r.prefix+path, r.handle(path, h))
}
// Options registers a new OPTIONS route.
func (r *Router) Options(path string, h http.HandlerFunc) {
r.rtr.OPTIONS(r.prefix+path, r.handle(path, h))
}
// Del registers a new DELETE route.
func (r *Router) Del(path string, h http.HandlerFunc) {
r.rtr.DELETE(r.prefix+path, r.handle(path, h))
}
// Put registers a new PUT route.
func (r *Router) Put(path string, h http.HandlerFunc) {
r.rtr.PUT(r.prefix+path, r.handle(path, h))
}
// Post registers a new POST route.
func (r *Router) Post(path string, h http.HandlerFunc) {
r.rtr.POST(r.prefix+path, r.handle(path, h))
}
// Redirect takes an absolute path and sends an internal HTTP redirect for it,
// prefixed by the router's path prefix. Note that this method does not include
// functionality for handling relative paths or full URL redirects.
func (r *Router) Redirect(w http.ResponseWriter, req *http.Request, path string, code int) {
http.Redirect(w, req, r.prefix+path, code)
}
// ServeHTTP implements http.Handler.
func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) {
r.rtr.ServeHTTP(w, req)
}
// FileServe returns a new http.HandlerFunc that serves files from dir.
// Using routes must provide the *filepath parameter.
func FileServe(dir string) http.HandlerFunc {
fs := http.FileServer(http.Dir(dir))
return func(w http.ResponseWriter, r *http.Request) {
r.URL.Path = Param(r.Context(), "filepath")
fs.ServeHTTP(w, r)
}
}

View File

@@ -1,76 +0,0 @@
package route
import (
"net/http"
"net/http/httptest"
"testing"
)
func TestRedirect(t *testing.T) {
router := New().WithPrefix("/test/prefix")
w := httptest.NewRecorder()
r, err := http.NewRequest("GET", "http://localhost:9090/foo", nil)
if err != nil {
t.Fatalf("Error building test request: %s", err)
}
router.Redirect(w, r, "/some/endpoint", http.StatusFound)
if w.Code != http.StatusFound {
t.Fatalf("Unexpected redirect status code: got %d, want %d", w.Code, http.StatusFound)
}
want := "/test/prefix/some/endpoint"
got := w.Header()["Location"][0]
if want != got {
t.Fatalf("Unexpected redirect location: got %s, want %s", got, want)
}
}
func TestContext(t *testing.T) {
router := New()
router.Get("/test/:foo/", func(w http.ResponseWriter, r *http.Request) {
want := "bar"
got := Param(r.Context(), "foo")
if want != got {
t.Fatalf("Unexpected context value: want %q, got %q", want, got)
}
})
r, err := http.NewRequest("GET", "http://localhost:9090/test/bar/", nil)
if err != nil {
t.Fatalf("Error building test request: %s", err)
}
router.ServeHTTP(nil, r)
}
func TestInstrumentation(t *testing.T) {
var got string
cases := []struct {
router *Router
want string
}{
{
router: New(),
want: "",
}, {
router: New().WithInstrumentation(func(handlerName string, handler http.HandlerFunc) http.HandlerFunc {
got = handlerName
return handler
}),
want: "/foo",
},
}
for _, c := range cases {
c.router.Get("/foo", func(w http.ResponseWriter, r *http.Request) {})
r, err := http.NewRequest("GET", "http://localhost:9090/foo", nil)
if err != nil {
t.Fatalf("Error building test request: %s", err)
}
c.router.ServeHTTP(nil, r)
if c.want != got {
t.Fatalf("Unexpected value: want %q, got %q", c.want, got)
}
}
}

View File

@@ -1,89 +0,0 @@
// Copyright 2016 The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package version
import (
"bytes"
"fmt"
"runtime"
"strings"
"text/template"
"github.com/prometheus/client_golang/prometheus"
)
// Build information. Populated at build-time.
var (
Version string
Revision string
Branch string
BuildUser string
BuildDate string
GoVersion = runtime.Version()
)
// NewCollector returns a collector which exports metrics about current version information.
func NewCollector(program string) *prometheus.GaugeVec {
buildInfo := prometheus.NewGaugeVec(
prometheus.GaugeOpts{
Namespace: program,
Name: "build_info",
Help: fmt.Sprintf(
"A metric with a constant '1' value labeled by version, revision, branch, and goversion from which %s was built.",
program,
),
},
[]string{"version", "revision", "branch", "goversion"},
)
buildInfo.WithLabelValues(Version, Revision, Branch, GoVersion).Set(1)
return buildInfo
}
// versionInfoTmpl contains the template used by Info.
var versionInfoTmpl = `
{{.program}}, version {{.version}} (branch: {{.branch}}, revision: {{.revision}})
build user: {{.buildUser}}
build date: {{.buildDate}}
go version: {{.goVersion}}
`
// Print returns version information.
func Print(program string) string {
m := map[string]string{
"program": program,
"version": Version,
"revision": Revision,
"branch": Branch,
"buildUser": BuildUser,
"buildDate": BuildDate,
"goVersion": GoVersion,
}
t := template.Must(template.New("version").Parse(versionInfoTmpl))
var buf bytes.Buffer
if err := t.ExecuteTemplate(&buf, "version", m); err != nil {
panic(err)
}
return strings.TrimSpace(buf.String())
}
// Info returns version, branch and revision information.
func Info() string {
return fmt.Sprintf("(version=%s, branch=%s, revision=%s)", Version, Branch, Revision)
}
// BuildContext returns goVersion, buildUser and buildDate information.
func BuildContext() string {
return fmt.Sprintf("(go=%s, user=%s, date=%s)", GoVersion, BuildUser, BuildDate)
}