Skip to content
This repository was archived by the owner on Jun 26, 2019. It is now read-only.

Commit 3e4a6e9

Browse files
committed
Initial Commit
0 parents  commit 3e4a6e9

File tree

13 files changed

+517
-0
lines changed

13 files changed

+517
-0
lines changed

CONTRIBUTING.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# How to contribute
2+
3+
Want to get involved? Be our guests, this is a community project, built on other community projects! Always happy to welcome input from our fellow engineers.
4+
5+
## Submitting changes
6+
7+
* Fork and submit a GitHub Pull Request, with clear detail of what you've done. When you send a pull request, please make sure all of your commits are atomic (one feature per commit).
8+
* Always write a clear log message for your commits. One-line messages are fine for small changes.

Dockerfile

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
FROM gliderlabs/alpine:3.4
2+
MAINTAINER infinityworksltd
3+
4+
EXPOSE 9174
5+
6+
RUN addgroup exporter \
7+
&& adduser -S -G exporter exporter
8+
9+
COPY . /go/src/github.com/infinityworksltd/docker-cloud-exporter
10+
11+
RUN apk --update add ca-certificates \
12+
&& apk --update add --virtual build-deps go git \
13+
&& cd /go/src/github.com/infinityworksltd/docker-cloud-exporter \
14+
&& GOPATH=/go go get \
15+
&& GOPATH=/go go build -o /bin/cloud_exporter \
16+
&& apk del --purge build-deps \
17+
&& rm -rf /go/bin /go/pkg /var/cache/apk/*
18+
19+
USER exporter
20+
21+
ENTRYPOINT [ "/bin/cloud_exporter" ]

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
The MIT License (MIT)
2+
3+
Copyright (c) 2016 Infinity Works Ltd
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in
13+
all copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21+
THE SOFTWARE.

METRICS.md

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
# Example Metrics
2+
3+
Example of the metrics you could expect to see, returned for the service,stack, node and node cluster states.
4+
5+
```
6+
# HELP docker_cloud_node_cluster_state State of defined node cluster as reported by the Docker Cloud API
7+
# TYPE docker_cloud_node_cluster_state gauge
8+
docker_cloud_node_cluster_state{node_cluster_name="testing",state="Deployed"} 1
9+
# HELP docker_cloud_node_state State of defined node as reported by the Docker Cloud API
10+
# TYPE docker_cloud_node_state gauge
11+
docker_cloud_node_state{node_uuid="3e00675b-4dc0-4ea9-8329-aa852f34dcc7",state="Deployed"} 1
12+
docker_cloud_node_state{node_uuid="c7f72de9-48ec-4db0-ae70-813c1ce2b7cf",state="Deployed"} 1
13+
# HELP docker_cloud_service_created_date Date & time the service was created in Unix seconds
14+
# TYPE docker_cloud_service_created_date gauge
15+
docker_cloud_service_created_date{service_name="Example1",state="Running"} 1.485188537e+09
16+
docker_cloud_service_created_date{service_name="grafana",state="Running"} 1.485188529e+09
17+
docker_cloud_service_created_date{service_name="node-exporter",state="Running"} 1.485532594e+09
18+
docker_cloud_service_created_date{service_name="prometheus",state="Running"} 1.485188566e+09
19+
# HELP docker_cloud_service_state State of defined service as reported by the Docker Cloud API
20+
# TYPE docker_cloud_service_state gauge
21+
docker_cloud_service_state{service_name="Example1",state="Running"} 1
22+
docker_cloud_service_state{service_name="grafana",state="Running"} 1
23+
docker_cloud_service_state{service_name="node-exporter",state="Running"} 1
24+
docker_cloud_service_state{service_name="prometheus",state="Running"} 1
25+
# HELP docker_cloud_stack_created_date Date & time the stack was created in Unix seconds
26+
# TYPE docker_cloud_stack_created_date gauge
27+
docker_cloud_stack_created_date{stack_name="Example1",state="Running"} 1.485188688e+09
28+
# HELP docker_cloud_stack_state State of defined stack as reported by the Docker Cloud API
29+
# TYPE docker_cloud_stack_state gauge
30+
docker_cloud_stack_state{stack_name="Example1",state="Running"} 1
31+
```
32+
33+
An example of the internal metrics to track the performance of the exporter, and useful as a basic example how to instrument your code.
34+
35+
```
36+
# HELP function_count_totals total count of function calls
37+
# TYPE function_count_totals counter
38+
function_count_totals{fnc="getJSON",pkg="hosts"} 3
39+
function_count_totals{fnc="getJSON",pkg="services"} 3
40+
function_count_totals{fnc="getJSON",pkg="stacks"} 3
41+
# HELP function_durations_seconds Function timings for Rancher Exporter
42+
# TYPE function_durations_seconds summary
43+
function_durations_seconds{fnc="getJSON",pkg="hosts",quantile="0.5"} 33546
44+
function_durations_seconds{fnc="getJSON",pkg="hosts",quantile="0.9"} 59199
45+
function_durations_seconds{fnc="getJSON",pkg="hosts",quantile="0.99"} 59199
46+
function_durations_seconds_sum{fnc="getJSON",pkg="hosts"} 121502
47+
function_durations_seconds_count{fnc="getJSON",pkg="hosts"} 3
48+
function_durations_seconds{fnc="getJSON",pkg="services",quantile="0.5"} 49354
49+
function_durations_seconds{fnc="getJSON",pkg="services",quantile="0.9"} 63310
50+
function_durations_seconds{fnc="getJSON",pkg="services",quantile="0.99"} 63310
51+
function_durations_seconds_sum{fnc="getJSON",pkg="services"} 146519
52+
function_durations_seconds_count{fnc="getJSON",pkg="services"} 3
53+
function_durations_seconds{fnc="getJSON",pkg="stacks",quantile="0.5"} 45075
54+
function_durations_seconds{fnc="getJSON",pkg="stacks",quantile="0.9"} 59805
55+
function_durations_seconds{fnc="getJSON",pkg="stacks",quantile="0.99"} 59805
56+
function_durations_seconds_sum{fnc="getJSON",pkg="stacks"} 134789
57+
function_durations_seconds_count{fnc="getJSON",pkg="stacks"} 3
58+
```

README.md

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
# docker-cloud-exporter
2+
3+
Exposes the health of Stacks, Services, Nodes and Node Clusters from the Docker Cloud API, to a Prometheus compatible endpoint.
4+
5+
6+
## Description
7+
8+
The application can be run in a number of ways, the main consumption is the Docker hub image `infinityworksltd/docker-cloud-exporter`.
9+
10+
**Required**
11+
* `DOCKERCLOUD_USER` // Username of your docker cloud account
12+
* `DOCKERCLOUD_APIKEY` // Generated through the docker cloud admin interface
13+
14+
**Optional**
15+
* `DOCKERCLOUD_NAMESPACE` // Specify this if you wish to show metrics for an organisation your user has access to. Specify the name of the org in this env var.
16+
* `METRICS_PATH` // Path under which to expose metrics.
17+
* `LISTEN_PORT` // Port on which to expose metrics. Defaults to 9174
18+
* `LOG_LEVEL` // Optional - Set the logging level, defaults to Info
19+
20+
## Install and deploy
21+
22+
Run manually from Docker Hub:
23+
```
24+
docker run -d -e DOCKERCLOUD_USER="XXXXXXXX" -e DOCKERCLOUD_APIKEY="XXXXXXX" -p 9174:9174 infinityworks/docker-cloud-exporter
25+
```
26+
27+
Build a docker image:
28+
```
29+
docker build -t <image-name> .
30+
docker run -d -e DOCKERCLOUD_USER="XXXXXXXX" -e DOCKERCLOUD_APIKEY="XXXXXXX" -p 9174:9174 <image-name>
31+
```
32+
33+
## Docker compose
34+
35+
```
36+
docker-cloud-exporter:
37+
tty: true
38+
stdin_open: true
39+
environment:
40+
- DOCKERCLOUD_USER="xxxx"
41+
- DOCKERCLOUD_APIKEY="xxxxxx"
42+
expose:
43+
- 9174:9174
44+
image: infinityworks/docker-cloud-exporter:latest
45+
```
46+
47+
48+
## Metrics
49+
50+
Metrics will be made available on port 9174 by default, or you can pass environment variable ```LISTEN_ADDRESS``` to override this.
51+
An example printout of the metrics you should expect to see can be found in `METRICS.md`.
52+
53+
54+
## Metadata
55+
[![](https://images.microbadger.com/badges/version/infinityworks/docker-cloud-exporter.svg)](http://microbadger.com/images/infinityworks/docker-cloud-exporter "Get your own version badge on microbadger.com") [![](https://images.microbadger.com/badges/image/infinityworks/docker-cloud-exporter.svg)](http://microbadger.com/images/infinityworks/docker-cloud-exporter "Get your own image badge on microbadger.com")
56+
[![Go Report Card](https://goreportcard.com/badge/github.com/infinityworksltd/docker-cloud-exporter)](https://goreportcard.com/report/github.com/infinityworksltd/docker-cloud-exporter)
57+
[![GoDoc](https://godoc.org/github.com/infinityworksltd/docker-cloud-exporter?status.svg)](https://godoc.org/github.com/infinityworksltd/docker-cloud-exporter)

config/config.go

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package config
2+
3+
import (
4+
"os"
5+
"time"
6+
7+
log "github.com/Sirupsen/logrus"
8+
)
9+
10+
func GetEnv(key, fallback string) string {
11+
value := os.Getenv(key)
12+
if len(value) == 0 {
13+
return fallback
14+
}
15+
return value
16+
}
17+
18+
func CheckConfig() {
19+
if os.Getenv("DOCKERCLOUD_USER") == "" {
20+
log.Error("User not set for API Access, required.")
21+
} else if os.Getenv("DOCKERCLOUD_APIKEY") == "" {
22+
log.Error("API Key not set for API Access, required.")
23+
}
24+
}
25+
26+
func ConvertTime(input string) float64 {
27+
t, err := time.Parse(time.RFC1123Z, input)
28+
if err != nil {
29+
log.Println(err)
30+
}
31+
32+
ts := t.Unix()
33+
34+
return float64(ts)
35+
}

exporter.go

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package main
2+
3+
import (
4+
"sync"
5+
6+
"github.com/prometheus/client_golang/prometheus"
7+
)
8+
9+
// Exporter Sets up all the runtime and metrics
10+
type Exporter struct {
11+
mutex sync.RWMutex
12+
gaugeVecs map[string]*prometheus.GaugeVec
13+
}
14+
15+
// NewExporter creates the metrics we wish to monitor
16+
func newExporter() *Exporter {
17+
18+
gaugeVecs := AddMetrics()
19+
20+
return &Exporter{
21+
gaugeVecs: gaugeVecs,
22+
}
23+
}

gather.go

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
package main
2+
3+
import (
4+
"time"
5+
6+
log "github.com/Sirupsen/logrus"
7+
8+
"github.com/docker/go-dockercloud/dockercloud"
9+
c "github.com/infinityworksltd/docker-cloud-exporter/config"
10+
m "github.com/infinityworksltd/docker-cloud-exporter/measure"
11+
"github.com/prometheus/client_golang/prometheus"
12+
)
13+
14+
func (e *Exporter) gatherStackMetrics(ch chan<- prometheus.Metric) (*dockercloud.Stack, error) {
15+
16+
defer m.RecordFunction(time.Now(), "main", "gatherStackMetrics")
17+
18+
var Stack = new(dockercloud.Stack)
19+
20+
stack, err := dockercloud.ListStacks()
21+
if err != nil {
22+
log.Println(err)
23+
}
24+
25+
log.Debugf("Data Captured", Stack)
26+
27+
for _, x := range stack.Objects {
28+
29+
e.gaugeVecs["stacksState"].With(prometheus.Labels{"stack_name": x.Name, "state": x.State}).Set(1)
30+
e.gaugeVecs["stackCreatedDate"].With(prometheus.Labels{"stack_name": x.Name, "state": x.State}).Set(c.ConvertTime(x.Deployed_datetime))
31+
}
32+
33+
return Stack, err
34+
35+
}
36+
37+
func (e *Exporter) gatherServiceMetrics(ch chan<- prometheus.Metric) (*dockercloud.Service, error) {
38+
39+
defer m.RecordFunction(time.Now(), "main", "gatherServiceMetrics")
40+
41+
var Service = new(dockercloud.Service)
42+
43+
service, err := dockercloud.ListServices()
44+
if err != nil {
45+
log.Println(err)
46+
}
47+
48+
log.Debugf("Data Captured", service)
49+
50+
for _, x := range service.Objects {
51+
52+
e.gaugeVecs["serviceState"].With(prometheus.Labels{"service_name": x.Name, "state": x.State}).Set(1)
53+
e.gaugeVecs["serviceCreatedDate"].With(prometheus.Labels{"service_name": x.Name, "state": x.State}).Set(c.ConvertTime(x.Deployed_datetime))
54+
}
55+
56+
return Service, err
57+
58+
}
59+
60+
func (e *Exporter) gatherNodeMetrics(ch chan<- prometheus.Metric) (*dockercloud.Node, error) {
61+
62+
defer m.RecordFunction(time.Now(), "main", "gatherNodeMetrics")
63+
64+
var Node = new(dockercloud.Node)
65+
66+
node, err := dockercloud.ListNodes()
67+
if err != nil {
68+
log.Println(err)
69+
}
70+
71+
log.Debugf("Data Captured", node)
72+
73+
for _, x := range node.Objects {
74+
e.gaugeVecs["nodeState"].With(prometheus.Labels{"node_uuid": x.Uuid, "state": x.State}).Set(1)
75+
}
76+
77+
return Node, err
78+
79+
}
80+
81+
func (e *Exporter) gatherNodeClusterMetrics(ch chan<- prometheus.Metric) (*dockercloud.NodeCluster, error) {
82+
83+
defer m.RecordFunction(time.Now(), "main", "gatherNodeClusterMetrics")
84+
85+
var NodeCluster = new(dockercloud.NodeCluster)
86+
87+
nodeCluster, err := dockercloud.ListNodeClusters()
88+
if err != nil {
89+
log.Println(err)
90+
}
91+
92+
log.Debugf("Data Captured", nodeCluster)
93+
94+
for _, x := range nodeCluster.Objects {
95+
e.gaugeVecs["nodeClusterState"].With(prometheus.Labels{"node_cluster_name": x.Name, "state": x.State}).Set(1)
96+
}
97+
98+
return NodeCluster, err
99+
100+
}

log.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package main
2+
3+
import "github.com/Sirupsen/logrus"
4+
5+
// setLogLevel - Sets the log level based on the passed argument.
6+
func setLogLevel(level string) {
7+
switch level {
8+
case "debug":
9+
logrus.SetLevel(logrus.DebugLevel)
10+
break
11+
case "info":
12+
logrus.SetLevel(logrus.InfoLevel)
13+
break
14+
case "warn":
15+
logrus.SetLevel(logrus.WarnLevel)
16+
break
17+
case "fatal":
18+
logrus.SetLevel(logrus.FatalLevel)
19+
break
20+
case "panic":
21+
logrus.SetLevel(logrus.PanicLevel)
22+
break
23+
}
24+
}

0 commit comments

Comments
 (0)