Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Better timestamp management #12

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,9 @@ global:
prefix: "huaweicloud"
port: ":8087"
metric_path: "/metrics"
retrieve_offset: "0"
cloudeye_timestamp: false
ignore_empty_datapoints: false

auth:
auth_url: "https://iam.cn-north-1.myhwclouds.com/v3"
Expand All @@ -68,6 +71,11 @@ auth:

```

Notes :
* `global.retrieve_offset` (default "0") is an offset (example "-5m") to ask Cloudeye for some older metrics.
* `global.cloudeye_timestamp` (default false) allows Cloudeye Exporter to send metrics with their Cloudeye timestamp
* `global.ignore_empty_datapoints` (default false), when set, will ignore empty datapoints (no warnings)

## Prometheus Configuration
The huaweicloud exporter needs to be passed the address as a parameter, this can be done with relabelling.

Expand Down
74 changes: 53 additions & 21 deletions collector/collector.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,14 +45,18 @@ var privateResourceFlag = map[string]string{
}

type BaseHuaweiCloudExporter struct {
From string
To string
Debug bool
Namespaces []string
Prefix string
Metrics map[string]*prometheus.Desc
ClientConfig *Config
Region string
From string
To string
Debug bool
Namespaces []string
Prefix string
Metrics map[string]*prometheus.Desc
ClientConfig *Config
Region string
RetrieveOffset bool
RetrieveOffsetDuration time.Duration
CloudeyeTimestamp bool
IgnoreEmptyDatapoints bool
}

func replaceName(name string) string {
Expand All @@ -68,10 +72,22 @@ func GetMonitoringCollector(configpath string, namespaces []string, debug bool)
log.Fatal(err)
}

retrieveOffsetDuration, err := time.ParseDuration(global_config.Global.RetrieveOffset)
if err != nil {
log.Fatal(err)
}

exporter := &BaseHuaweiCloudExporter{
Namespaces: namespaces,
Prefix: global_config.Global.Prefix,
Debug: debug,
Namespaces: namespaces,
Prefix: global_config.Global.Prefix,
RetrieveOffset: global_config.Global.RetrieveOffset != "0",
RetrieveOffsetDuration: retrieveOffsetDuration,
CloudeyeTimestamp: global_config.Global.CloudeyeTimestamp,
IgnoreEmptyDatapoints: global_config.Global.IgnoreEmptyDatapoints,
Debug: debug,
}
if exporter.RetrieveOffset {
log.Infof("Using an offset of %s for Cloudeye metrics", global_config.Global.RetrieveOffset)
}

exporter.ClientConfig = initClient(global_config)
Expand Down Expand Up @@ -123,9 +139,11 @@ func (exporter *BaseHuaweiCloudExporter) collectMetricByNamespace(ch chan<- prom

for _, md := range *mds {
exporter.debugMetricInfo(md)
datapoint, err := getDatapoint(md.Datapoints)
datapoint, t, err := getDatapoint(md.Datapoints)
if err != nil {
fmt.Printf("%s, the metric is:", err, md.MetricName)
if !exporter.IgnoreEmptyDatapoints {
fmt.Printf("%s, the metric is:", err, md.MetricName)
}
continue
}

Expand All @@ -136,9 +154,17 @@ func (exporter *BaseHuaweiCloudExporter) collectMetricByNamespace(ch chan<- prom
}

newMetricName := prometheus.BuildFQName(GetMetricPrefixName(exporter.Prefix, namespace), preResourceName, md.MetricName)
ch <- prometheus.MustNewConstMetric(
prometheus.NewDesc(newMetricName, newMetricName, labels, nil),
prometheus.GaugeValue, datapoint, values...)
if exporter.CloudeyeTimestamp {
ch <- prometheus.NewMetricWithTimestamp(
t,
prometheus.MustNewConstMetric(
prometheus.NewDesc(newMetricName, newMetricName, labels, nil),
prometheus.GaugeValue, datapoint, values...))
} else {
ch <- prometheus.MustNewConstMetric(
prometheus.NewDesc(newMetricName, newMetricName, labels, nil),
prometheus.GaugeValue, datapoint, values...)
}
}

metricTimestamp, _ = getMetricDataTimestamp((*mds)[len(*mds)-1].Datapoints)
Expand All @@ -162,8 +188,12 @@ func (exporter *BaseHuaweiCloudExporter) Collect(ch chan<- prometheus.Metric) {
periodm, _ := time.ParseDuration("-5m")

now := time.Now()
from := strconv.FormatInt(int64(now.Add(periodm).UnixNano()/1e6), 10)
to := strconv.FormatInt(int64(now.UnixNano()/1e6), 10)
now_with_offset := now
if exporter.RetrieveOffset {
now_with_offset = now.Add(exporter.RetrieveOffsetDuration)
}
from := strconv.FormatInt(int64(now_with_offset.Add(periodm).UnixNano()/1e6), 10)
to := strconv.FormatInt(int64(now_with_offset.UnixNano()/1e6), 10)
exporter.From = from
exporter.To = to

Expand Down Expand Up @@ -191,15 +221,17 @@ func isResouceExist(dims *[]metricdata.Dimension, allResouceInfo *map[string][]s
return false
}

func getDatapoint(datapoints []metricdata.Data) (float64, error) {
func getDatapoint(datapoints []metricdata.Data) (float64, time.Time, error) {
var datapoint float64
var t time.Time
if len(datapoints) > 0 {
datapoint = (datapoints)[len(datapoints)-1].Average
t = time.Unix(int64((datapoints)[len(datapoints)-1].Timestamp), 0)
} else {
return 0, fmt.Errorf("The data point of metric are not found")
return 0, time.Unix(0, 0), fmt.Errorf("The data point of metric are not found")
}

return datapoint, nil
return datapoint, t, nil
}

func getMetricDataTimestamp(datapoints []metricdata.Data) (int, error) {
Expand Down
40 changes: 22 additions & 18 deletions collector/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,30 +20,31 @@ import (
)

type CloudAuth struct {
ProjectName string `yaml:"project_name"`
ProjectID string `yaml:"project_id"`
DomainName string `yaml:"domain_name"`
AccessKey string `yaml:"access_key"`
Region string `yaml:"region"`
SecretKey string `yaml:"secret_key"`
AuthURL string `yaml:"auth_url"`
UserName string `yaml:"user_name"`
Password string `yaml:"password"`
ProjectName string `yaml:"project_name"`
ProjectID string `yaml:"project_id"`
DomainName string `yaml:"domain_name"`
AccessKey string `yaml:"access_key"`
Region string `yaml:"region"`
SecretKey string `yaml:"secret_key"`
AuthURL string `yaml:"auth_url"`
UserName string `yaml:"user_name"`
Password string `yaml:"password"`
}

type Global struct {
Port string `yaml:"port"`
Prefix string `yaml:"prefix"`
MetricPath string `yaml:"metric_path"`
Port string `yaml:"port"`
Prefix string `yaml:"prefix"`
MetricPath string `yaml:"metric_path"`
RetrieveOffset string `yaml:"retrieve_offset"`
CloudeyeTimestamp bool `yaml:"cloudeye_timestamp"`
IgnoreEmptyDatapoints bool `yaml:"ignore_empty_datapoints"`
}


type CloudConfig struct {
Auth CloudAuth `yaml:"auth"`
Global Global `yaml:"global"`
Auth CloudAuth `yaml:"auth"`
Global Global `yaml:"global"`
}


func NewCloudConfigFromFile(file string) (*CloudConfig, error) {
var config CloudConfig

Expand All @@ -62,8 +63,7 @@ func NewCloudConfigFromFile(file string) (*CloudConfig, error) {
return &config, err
}


func SetDefaultConfigValues(config *CloudConfig) {
func SetDefaultConfigValues(config *CloudConfig) {
if config.Global.Port == "" {
config.Global.Port = ":8087"
}
Expand All @@ -75,6 +75,10 @@ func SetDefaultConfigValues(config *CloudConfig) {
if config.Global.Prefix == "" {
config.Global.Prefix = "huaweicloud"
}

if config.Global.RetrieveOffset == "" {
config.Global.RetrieveOffset = "0"
}
}

//
Expand Down
5 changes: 2 additions & 3 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,14 @@ import (
"strings"

"github.com/huaweicloud/cloudeye-exporter/collector"
"github.com/prometheus/common/log"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promhttp"
"github.com/prometheus/common/log"
)


var (
clientConfig = flag.String("config", "./clouds.yml", "Path to the cloud configuration file")
debug = flag.Bool("debug", false, "If debug the code.")
debug = flag.Bool("debug", false, "If debug the code.")
)

func handler(w http.ResponseWriter, r *http.Request) {
Expand Down