Merge pull request #5 from peschmae/feature/merge-kully
Feature/merge kully
This commit is contained in:
commit
64d17d5c25
11 changed files with 534 additions and 184 deletions
10
.github/workflows/go.yml
vendored
10
.github/workflows/go.yml
vendored
|
@ -12,13 +12,19 @@ jobs:
|
|||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v2
|
||||
uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: 1.17
|
||||
|
||||
- name: install stringer
|
||||
run: go install golang.org/x/tools/cmd/stringer@latest
|
||||
|
||||
- name: Generate
|
||||
run: go generate ./...
|
||||
|
||||
- name: Build
|
||||
run: go build -v ./...
|
||||
|
||||
|
|
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -1,5 +1,6 @@
|
|||
mystrom-exporter
|
||||
output/*
|
||||
*_string.go
|
||||
|
||||
# Created by https://www.toptal.com/developers/gitignore/api/osx,intellij+all,windows
|
||||
# Edit at https://www.toptal.com/developers/gitignore?templates=osx,intellij+all,windows
|
||||
|
|
|
@ -2,7 +2,7 @@ FROM golang:alpine as build
|
|||
|
||||
WORKDIR /root
|
||||
COPY . /root
|
||||
RUN go build .
|
||||
RUN go install golang.org/x/tools/cmd/stringer@latest && go generate ./... && go build .
|
||||
|
||||
FROM alpine:latest
|
||||
|
||||
|
|
63
Makefile
63
Makefile
|
@ -1,13 +1,56 @@
|
|||
.PHONY: clean run
|
||||
##
|
||||
#
|
||||
.DEFAULT_GOAL := help
|
||||
.PHONY: generate go-tools
|
||||
|
||||
linux:
|
||||
GOOS=linux GOARCH=amd64 go build -o output/mystrom-exporter_linux-amd64
|
||||
mac:
|
||||
GOOS=darwin GOARCH=amd64 go build -o output/mystrom-exporter_mac-amd64
|
||||
arm64:
|
||||
GOOS=linux GOARCH=arm64 go build -o output/mystrom-exporter_linux-arm64
|
||||
arm:
|
||||
GOOS=linux GOARCH=arm go build -o output/mystrom-exporter_linux-arm
|
||||
version := $(shell git describe --tags --always)
|
||||
revision := $(shell git rev-parse HEAD)
|
||||
branch := $(shell git rev-parse --abbrev-ref HEAD)
|
||||
builduser := $(shell whoami)
|
||||
builddate := $(shell date '+%FT%T_%Z')
|
||||
|
||||
versionPkgPrefix := mystrom-exporter/pkg/version
|
||||
|
||||
BINDIR := $(CURDIR)/output
|
||||
GO ?= go
|
||||
GOPATH ?= $(shell $(GO) env GOPATH)
|
||||
LDFLAGS := -w -s \
|
||||
-X $(versionPkgPrefix).Version=${version} \
|
||||
-X $(versionPkgPrefix).Revision=${revision} \
|
||||
-X $(versionPkgPrefix).Branch=${branch} \
|
||||
-X $(versionPkgPrefix).BuildUser=${builduser} \
|
||||
-X $(versionPkgPrefix).BuildDate=${builddate}
|
||||
GOFLAGS := -v
|
||||
GOX_FLAGS := -mod=vendor
|
||||
GO_BUILD_FLAGS := -v
|
||||
export GO111MODULE := on
|
||||
|
||||
build: go-tools generate ## builds the all platform binaries of the exporter
|
||||
$(GOPATH)/bin/gox \
|
||||
-os="darwin linux" \
|
||||
-arch="amd64 arm arm64" \
|
||||
-osarch="!darwin/arm" \
|
||||
-output "${BINDIR}/{{.Dir}}-{{.OS}}-{{.Arch}}" \
|
||||
-gcflags "$(GO_BUILD_FLAGS)" \
|
||||
-ldflags '$(LDFLAGS)' \
|
||||
-tags '$(TAGS)' \
|
||||
./...
|
||||
|
||||
run:
|
||||
${BINDIR}/mystrom-exporter-$(shell $(GO) env GOOS)-$(shell $(GO) env GOARCH)
|
||||
|
||||
|
||||
all: linux mac arm64 arm
|
||||
generate: go-tools
|
||||
$(GO) generate ./...
|
||||
|
||||
go-tools: $(GOPATH)/bin/stringer $(GOPATH)/bin/gox
|
||||
|
||||
# -- see more info on https://pkg.go.dev/golang.org/x/tools/cmd/stringer
|
||||
$(GOPATH)/bin/stringer:
|
||||
$(GO) install golang.org/x/tools/cmd/stringer@latest
|
||||
|
||||
$(GOPATH)/bin/gox:
|
||||
$(GO) install github.com/mitchellh/gox@latest
|
||||
# --
|
||||
help:
|
||||
@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'
|
||||
|
|
27
README.md
27
README.md
|
@ -28,9 +28,31 @@ $ ./mystrom-exporter --help
|
|||
```
|
||||
| Flag | Description | Default |
|
||||
| ---- | ----------- | ------- |
|
||||
| switch.ip-address | IP address of the switch you try to monitor | `` |
|
||||
| web.listen-address | Address to listen on | `:9452` |
|
||||
| web.metrics-path | Path under which to expose metrics | `/metrics` |
|
||||
| web.metrics-path | Path under which to expose exporters own metrics | `/metrics` |
|
||||
| web.device-path | Path under which the metrics of the devices are fetched | `/device` |
|
||||
|
||||
## Prometheus configuration
|
||||
A enhancement has been made to have only one exporter which can scrape multiple devices. This is configured in
|
||||
Prometheus as follows assuming we have 4 mystrom devices and the exporter is running locally on the smae machine as
|
||||
the Prometheus.
|
||||
```yaml
|
||||
- job_name: mystrom
|
||||
scrape_interval: 30s
|
||||
metrics_path: /device
|
||||
honor_labels: true
|
||||
static_configs:
|
||||
- targets:
|
||||
- '192.168.105.11'
|
||||
- '192.168.105.12'
|
||||
- '192.168.105.13'
|
||||
- '192.168.105.14'
|
||||
relabel_configs:
|
||||
- source_labels: [__address__]
|
||||
target_label: __param_target
|
||||
- target_label: __address__
|
||||
replacement: 127.0.0.1:9452
|
||||
```
|
||||
|
||||
## Supported architectures
|
||||
Using the make file, you can easily build for the following architectures, those can also be considered the tested ones:
|
||||
|
@ -40,6 +62,7 @@ Using the make file, you can easily build for the following architectures, those
|
|||
| Linux | arm64 |
|
||||
| Linux | arm |
|
||||
| Mac | amd64 |
|
||||
| Mac | arm64 |
|
||||
|
||||
Since go is cross compatible with windows, and mac arm as well, you should be able to build the binary for those as well, but they aren't tested.
|
||||
The docker image is only built & tested for amd64.
|
||||
|
|
8
go.mod
8
go.mod
|
@ -2,4 +2,10 @@ module mystrom-exporter
|
|||
|
||||
go 1.15
|
||||
|
||||
require github.com/prometheus/client_golang v1.10.0
|
||||
require (
|
||||
github.com/gorilla/mux v1.7.3
|
||||
github.com/prometheus/client_golang v1.10.0
|
||||
github.com/prometheus/common v0.18.0
|
||||
golang.org/x/sys v0.0.0-20220825204002-c680a09ffe64 // indirect
|
||||
golang.org/x/tools v0.1.12
|
||||
)
|
||||
|
|
36
go.sum
36
go.sum
|
@ -7,9 +7,11 @@ github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMx
|
|||
github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g=
|
||||
github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c=
|
||||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 h1:JYp7IbQjafoB+tBA3gMyHYHrpOtNuDiK/uB5uXxq5wM=
|
||||
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d h1:UQZhZ2O0vMHr2cI+DC1Mbh0TJxzA3RcLoMsFw+aXw7E=
|
||||
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
|
||||
github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
|
||||
github.com/apache/thrift v0.13.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
|
||||
|
@ -40,6 +42,7 @@ github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfc
|
|||
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
|
||||
github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
|
||||
|
@ -89,6 +92,7 @@ github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5a
|
|||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.4 h1:L8R9j+yAqZuZjsqh/z+F1NCffTKKLShY6zXTItVIZ8M=
|
||||
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||
|
@ -96,6 +100,7 @@ github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+
|
|||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||
github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
|
||||
github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
|
||||
github.com/gorilla/mux v1.7.3 h1:gnP5JzjVOuiZD07fKKToCAOjS0yOpj/qPETTXCCS6hw=
|
||||
github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
|
||||
github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
|
||||
github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
|
||||
|
@ -138,10 +143,13 @@ github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8
|
|||
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.3 h1:CE8S1cTafDpPvMhIxNJKvHsGVBgn1xWYf1NbHQhywc8=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
||||
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM=
|
||||
github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4=
|
||||
|
@ -198,6 +206,7 @@ github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE
|
|||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
|
||||
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
||||
|
@ -237,6 +246,7 @@ github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg
|
|||
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
||||
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||
github.com/sirupsen/logrus v1.6.0 h1:UBcNElsrwanuuMsnGSlYmtmgbb23qDR5dG+6X6Oo89I=
|
||||
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
|
||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
||||
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
|
||||
|
@ -251,11 +261,13 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+
|
|||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
|
||||
github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
|
||||
github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
|
||||
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
|
||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
|
||||
go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg=
|
||||
go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
|
||||
|
@ -275,6 +287,7 @@ golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8U
|
|||
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||
|
@ -283,6 +296,8 @@ golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHl
|
|||
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
|
||||
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 h1:6zppjxzCulZykYSLyVDYbneBfbaBIQPYMevg0bEwv2s=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
|
@ -300,6 +315,8 @@ golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLL
|
|||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
|
@ -309,6 +326,7 @@ golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJ
|
|||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
|
@ -328,11 +346,20 @@ golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210309074719-68d13333faf2 h1:46ULzRKLh1CwgRq2dC5SlBzEqqNCi8rreOZnNrbqcIY=
|
||||
golang.org/x/sys v0.0.0-20210309074719-68d13333faf2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220825204002-c680a09ffe64 h1:UiNENfZ8gDvpiWw7IpOMQ27spWmThO1RwwdQVbJahJM=
|
||||
golang.org/x/sys v0.0.0-20220825204002-c680a09ffe64/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
|
@ -347,9 +374,13 @@ golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBn
|
|||
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.1.12 h1:VveCTK38A2rkS8ZqFY25HIDFscX5X9OoEhJd3quQmXU=
|
||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk=
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
|
@ -376,9 +407,11 @@ google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miE
|
|||
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
|
||||
google.golang.org/protobuf v1.23.0 h1:4MY060fB1DLGMB/7MBTLnwQUY6+F09GEiz6SsrNqyzM=
|
||||
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6 h1:jMFz6MfLP0/4fUyZle81rXUoxOBFi19VUFKVDOQfozc=
|
||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw=
|
||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||
|
@ -392,6 +425,7 @@ gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
|||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
|
||||
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
|
|
292
main.go
292
main.go
|
@ -1,199 +1,155 @@
|
|||
//go:generate stringer -type MystromReqStatus main.go
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/prometheus/client_golang/prometheus/promhttp"
|
||||
"github.com/prometheus/common/log"
|
||||
|
||||
"mystrom-exporter/pkg/mystrom"
|
||||
"mystrom-exporter/pkg/version"
|
||||
)
|
||||
|
||||
type switchReport struct {
|
||||
Power float64 `json:"power"`
|
||||
WattPerSec float64 `json:"Ws"`
|
||||
Relay bool `json:relay`
|
||||
Temperature float64 `json:"temperature`
|
||||
}
|
||||
// -- MystromRequestStatusType represents the request to MyStrom device status
|
||||
type MystromReqStatus uint32
|
||||
|
||||
const namespace = "mystrom"
|
||||
const (
|
||||
OK MystromReqStatus = iota
|
||||
ERROR_SOCKET
|
||||
ERROR_TIMEOUT
|
||||
ERROR_PARSING_VALUE
|
||||
)
|
||||
|
||||
const namespace = "mystrom_exporter"
|
||||
|
||||
var (
|
||||
listenAddress = flag.String("web.listen-address", ":9452",
|
||||
"Address to listen on")
|
||||
metricsPath = flag.String("web.metrics-path", "/metrics",
|
||||
"Path under which to expose metrics")
|
||||
switchIP = flag.String("switch.ip-address", "",
|
||||
"IP address of the switch you try to monitor")
|
||||
|
||||
up = prometheus.NewDesc(
|
||||
prometheus.BuildFQName(namespace, "", "up"),
|
||||
"Was the last myStrom query successful.",
|
||||
nil, nil,
|
||||
"Path under which to expose exporters own metrics")
|
||||
devicePath = flag.String("web.device-path", "/device",
|
||||
"Path under which the metrics of the devices are fetched")
|
||||
showVersion = flag.Bool("version", false,
|
||||
"Show version information.")
|
||||
)
|
||||
myStromPower = prometheus.NewDesc(
|
||||
prometheus.BuildFQName(namespace, "", "report_power"),
|
||||
"The current power consumed by devices attached to the switch",
|
||||
nil, nil,
|
||||
var (
|
||||
mystromDurationCounterVec *prometheus.CounterVec
|
||||
mystromRequestsCounterVec *prometheus.CounterVec
|
||||
)
|
||||
|
||||
myStromRelay = prometheus.NewDesc(
|
||||
prometheus.BuildFQName(namespace, "", "report_relay"),
|
||||
"The current state of the relay (wether or not the relay is currently turned on)",
|
||||
nil, nil,
|
||||
)
|
||||
|
||||
myStromTemperature = prometheus.NewDesc(
|
||||
prometheus.BuildFQName(namespace, "", "report_temperatur"),
|
||||
"The currently measured temperature by the switch. (Might initially be wrong, but will automatically correct itself over the span of a few hours)",
|
||||
nil, nil,
|
||||
)
|
||||
|
||||
myStromWattPerSec = prometheus.NewDesc(
|
||||
prometheus.BuildFQName(namespace, "", "report_watt_per_sec"),
|
||||
"The average of energy consumed per second from last call this request",
|
||||
nil, nil,
|
||||
)
|
||||
)
|
||||
|
||||
type Exporter struct {
|
||||
myStromSwitchIp string
|
||||
}
|
||||
|
||||
func NewExporter(myStromSwitchIp string) *Exporter {
|
||||
return &Exporter{
|
||||
myStromSwitchIp: myStromSwitchIp,
|
||||
}
|
||||
}
|
||||
|
||||
func (e *Exporter) Describe(ch chan<- *prometheus.Desc) {
|
||||
ch <- up
|
||||
ch <- myStromPower
|
||||
ch <- myStromRelay
|
||||
ch <- myStromTemperature
|
||||
ch <- myStromWattPerSec
|
||||
}
|
||||
|
||||
func (e *Exporter) Collect(ch chan<- prometheus.Metric) {
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
up, prometheus.GaugeValue, 1,
|
||||
)
|
||||
|
||||
e.FetchSwitchMetrics(e.myStromSwitchIp, ch)
|
||||
}
|
||||
|
||||
func (e *Exporter) FetchSwitchMetrics(switchIP string, ch chan<- prometheus.Metric) {
|
||||
|
||||
report, err := FetchReport(switchIP)
|
||||
|
||||
if err != nil {
|
||||
log.Printf("Error occured, while fetching metrics: %s", err)
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
up, prometheus.GaugeValue, 0,
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
myStromPower, prometheus.GaugeValue, report.Power,
|
||||
)
|
||||
|
||||
if report.Relay {
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
myStromRelay, prometheus.GaugeValue, 1,
|
||||
)
|
||||
} else {
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
myStromRelay, prometheus.GaugeValue, 0,
|
||||
)
|
||||
}
|
||||
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
myStromWattPerSec, prometheus.GaugeValue, report.WattPerSec,
|
||||
)
|
||||
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
myStromTemperature, prometheus.GaugeValue, report.Temperature,
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
func FetchReport(switchIP string) (*switchReport, error) {
|
||||
log.Printf("Trying to connect to switch at: %s\n", switchIP)
|
||||
url := "http://" + switchIP + "/report"
|
||||
|
||||
switchClient := http.Client{
|
||||
Timeout: time.Second * 5, // 3 second timeout, might need to be increased
|
||||
}
|
||||
|
||||
req, err := http.NewRequest(http.MethodGet, url, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
req.Header.Set("User-Agent", "myStrom-exporter")
|
||||
|
||||
res, getErr := switchClient.Do(req)
|
||||
if getErr != nil {
|
||||
log.Printf("Error while trying to connect to switch: %s\n", getErr)
|
||||
return nil, getErr
|
||||
|
||||
}
|
||||
|
||||
if res.Body != nil {
|
||||
defer res.Body.Close()
|
||||
}
|
||||
|
||||
body, readErr := ioutil.ReadAll(res.Body)
|
||||
if readErr != nil {
|
||||
log.Printf("Error while reading body: %s\n", readErr)
|
||||
return nil, readErr
|
||||
}
|
||||
|
||||
report := switchReport{}
|
||||
err = json.Unmarshal(body, &report)
|
||||
if err != nil {
|
||||
log.Printf("Error while unmarshaling report: %s\n", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &report, nil
|
||||
}
|
||||
|
||||
func main() {
|
||||
|
||||
flag.Parse()
|
||||
|
||||
if *switchIP == "" {
|
||||
flag.Usage()
|
||||
fmt.Println("\nNo switch.ip-address provided")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
exporter := NewExporter(*switchIP)
|
||||
prometheus.MustRegister(exporter)
|
||||
|
||||
http.Handle(*metricsPath, promhttp.Handler())
|
||||
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Write([]byte(`<html>
|
||||
var landingPage = []byte(`<html>
|
||||
<head><title>myStrom switch report Exporter</title></head>
|
||||
<body>
|
||||
<h1>myStrom Exporter</h1>
|
||||
<p><a href='` + *metricsPath + `'>Metrics</a></p>
|
||||
</body>
|
||||
</html>`))
|
||||
})
|
||||
</html>`)
|
||||
|
||||
_, err := FetchReport(*switchIP)
|
||||
func main() {
|
||||
|
||||
flag.Parse()
|
||||
|
||||
// -- show version information
|
||||
if *showVersion {
|
||||
v, err := version.Print("mystrom_exporter")
|
||||
if err != nil {
|
||||
log.Fatalf("Switch at address %s couldn't be reached. Ensure it is reachable before starting the exporter", *switchIP)
|
||||
log.Fatalf("Failed to print version information: %#v", err)
|
||||
}
|
||||
|
||||
log.Printf("Starting listener on %s\n", *listenAddress)
|
||||
log.Fatal(http.ListenAndServe(*listenAddress, nil))
|
||||
fmt.Fprintln(os.Stdout, v)
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
// -- create a new registry for the exporter telemetry
|
||||
telemetryRegistry := setupMetrics()
|
||||
|
||||
router := mux.NewRouter()
|
||||
router.Handle(*metricsPath, promhttp.HandlerFor(telemetryRegistry, promhttp.HandlerOpts{}))
|
||||
router.HandleFunc(*devicePath, scrapeHandler)
|
||||
router.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Write(landingPage)
|
||||
})
|
||||
log.Infoln("Listening on address " + *listenAddress)
|
||||
log.Fatal(http.ListenAndServe(*listenAddress, router))
|
||||
}
|
||||
|
||||
func scrapeHandler(w http.ResponseWriter, r *http.Request) {
|
||||
target := r.URL.Query().Get("target")
|
||||
if target == "" {
|
||||
http.Error(w, "'target' parameter must be specified", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
log.Infof("got scrape request for target '%v'", target)
|
||||
exporter := mystrom.NewExporter(target)
|
||||
|
||||
start := time.Now()
|
||||
gatherer, err := exporter.Scrape()
|
||||
duration := time.Since(start).Seconds()
|
||||
if err != nil {
|
||||
if strings.Contains(fmt.Sprintf("%v", err), "unable to connect with target") {
|
||||
mystromRequestsCounterVec.WithLabelValues(target, ERROR_SOCKET.String()).Inc()
|
||||
} else if strings.Contains(fmt.Sprintf("%v", err), "i/o timeout") {
|
||||
mystromRequestsCounterVec.WithLabelValues(target, ERROR_TIMEOUT.String()).Inc()
|
||||
} else {
|
||||
mystromRequestsCounterVec.WithLabelValues(target, ERROR_PARSING_VALUE.String()).Inc()
|
||||
}
|
||||
http.Error(
|
||||
w,
|
||||
fmt.Sprintf("failed to scrape target '%v': %v", target, err),
|
||||
http.StatusInternalServerError,
|
||||
)
|
||||
log.Error(err)
|
||||
return
|
||||
}
|
||||
mystromDurationCounterVec.WithLabelValues(target).Add(duration)
|
||||
mystromRequestsCounterVec.WithLabelValues(target, OK.String()).Inc()
|
||||
|
||||
promhttp.HandlerFor(gatherer, promhttp.HandlerOpts{}).ServeHTTP(w, r)
|
||||
}
|
||||
|
||||
// -- setupMetrics creates a new registry for the exporter telemetry
|
||||
func setupMetrics() *prometheus.Registry {
|
||||
registry := prometheus.NewRegistry()
|
||||
registry.MustRegister(prometheus.NewGoCollector())
|
||||
registry.MustRegister(prometheus.NewProcessCollector(prometheus.ProcessCollectorOpts{}))
|
||||
|
||||
mystromDurationCounterVec = prometheus.NewCounterVec(
|
||||
prometheus.CounterOpts{
|
||||
Namespace: namespace,
|
||||
Name: "request_duration_seconds_total",
|
||||
Help: "Total duration of mystrom successful requests by target in seconds",
|
||||
},
|
||||
[]string{"target"})
|
||||
registry.MustRegister(mystromDurationCounterVec)
|
||||
|
||||
mystromRequestsCounterVec = prometheus.NewCounterVec(
|
||||
prometheus.CounterOpts{
|
||||
Namespace: namespace,
|
||||
Name: "requests_total",
|
||||
Help: "Number of mystrom request by status and target",
|
||||
},
|
||||
[]string{"target", "status"})
|
||||
registry.MustRegister(mystromRequestsCounterVec)
|
||||
|
||||
// -- make the build information is available through a metric
|
||||
buildInfo := prometheus.NewGaugeVec(
|
||||
prometheus.GaugeOpts{
|
||||
Namespace: namespace,
|
||||
Name: "build_info",
|
||||
Help: "A metric with a constant '1' value labeled by build information.",
|
||||
},
|
||||
[]string{"version", "revision", "branch", "goversion", "builddate", "builduser"},
|
||||
)
|
||||
buildInfo.WithLabelValues(version.Version, version.Revision, version.Branch, version.GoVersion, version.BuildDate, version.BuildUser).Set(1)
|
||||
registry.MustRegister(buildInfo)
|
||||
|
||||
return registry
|
||||
}
|
||||
|
|
214
pkg/mystrom/mystrom.go
Normal file
214
pkg/mystrom/mystrom.go
Normal file
|
@ -0,0 +1,214 @@
|
|||
package mystrom
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/prometheus/common/log"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
)
|
||||
|
||||
const namespace = "mystrom"
|
||||
|
||||
// 5 second timeout, might need to be increased
|
||||
const reqTimeout = time.Second * 5
|
||||
|
||||
type switchReport struct {
|
||||
Power float64 `json:"power"`
|
||||
WattPerSec float64 `json:"Ws"`
|
||||
Relay bool `json:"relay"`
|
||||
Temperature float64 `json:"temperature"`
|
||||
}
|
||||
|
||||
type switchInfo struct {
|
||||
Version string `json:"version"`
|
||||
Mac string `json:"mac"`
|
||||
SwType float64 `json:"type"`
|
||||
SSID string `json:"ssid"`
|
||||
Static bool `json:"static"`
|
||||
Connected bool `json:"connected"`
|
||||
}
|
||||
|
||||
// Exporter --
|
||||
type Exporter struct {
|
||||
myStromSwitchIp string
|
||||
switchType float64
|
||||
}
|
||||
|
||||
// NewExporter --
|
||||
func NewExporter(switchIP string) *Exporter {
|
||||
return &Exporter{
|
||||
myStromSwitchIp: switchIP,
|
||||
}
|
||||
}
|
||||
|
||||
// Scrape --
|
||||
func (e *Exporter) Scrape() (prometheus.Gatherer, error) {
|
||||
reg := prometheus.NewRegistry()
|
||||
|
||||
// --
|
||||
bodyInfo, err := e.fetchData("/api/v1/info")
|
||||
if err != nil {
|
||||
}
|
||||
|
||||
info := switchInfo{}
|
||||
err = json.Unmarshal(bodyInfo, &info)
|
||||
if err != nil {
|
||||
// fmt.Println(err)
|
||||
// ch <- prometheus.MustNewConstMetric(
|
||||
// up, prometheus.GaugeValue, 0,
|
||||
// )
|
||||
return reg, fmt.Errorf("unable to decode switchReport: %v", err.Error())
|
||||
}
|
||||
log.Debugf("info: %#v", info)
|
||||
e.switchType = info.SwType
|
||||
|
||||
if err := registerInfoMetrics(reg, info, e.myStromSwitchIp); err != nil {
|
||||
return nil, fmt.Errorf("failed to register metrics : %v", err.Error())
|
||||
}
|
||||
|
||||
// --
|
||||
bodyData, err := e.fetchData("/report")
|
||||
if err != nil {
|
||||
}
|
||||
|
||||
report := switchReport{}
|
||||
err = json.Unmarshal(bodyData, &report)
|
||||
if err != nil {
|
||||
// fmt.Println(err)
|
||||
// ch <- prometheus.MustNewConstMetric(
|
||||
// up, prometheus.GaugeValue, 0,
|
||||
// )
|
||||
return reg, fmt.Errorf("unable to decode switchReport: %v", err.Error())
|
||||
}
|
||||
log.Debugf("report: %#v", report)
|
||||
|
||||
if err := registerMetrics(reg, report, e.myStromSwitchIp, e.switchType); err != nil {
|
||||
return nil, fmt.Errorf("failed to register metrics : %v", err.Error())
|
||||
}
|
||||
|
||||
return reg, nil
|
||||
}
|
||||
|
||||
// fetchData -- get the data from the switch under the given path
|
||||
func (e *Exporter) fetchData(urlpath string) ([]byte, error) {
|
||||
url := "http://" + e.myStromSwitchIp + urlpath
|
||||
|
||||
switchClient := http.Client{
|
||||
Timeout: reqTimeout,
|
||||
Transport: &http.Transport{
|
||||
DisableCompression: true,
|
||||
},
|
||||
}
|
||||
|
||||
req, err := http.NewRequest(http.MethodGet, url, nil)
|
||||
if err != nil {
|
||||
// ch <- prometheus.MustNewConstMetric(
|
||||
// up, prometheus.GaugeValue, 0,
|
||||
// )
|
||||
}
|
||||
req.Header.Set("User-Agent", "myStrom-exporter")
|
||||
|
||||
res, getErr := switchClient.Do(req)
|
||||
if getErr != nil {
|
||||
// ch <- prometheus.MustNewConstMetric(
|
||||
// up, prometheus.GaugeValue, 0,
|
||||
// )
|
||||
}
|
||||
if res.Body != nil {
|
||||
defer res.Body.Close()
|
||||
}
|
||||
|
||||
body, readErr := ioutil.ReadAll(res.Body)
|
||||
if readErr != nil {
|
||||
// ch <- prometheus.MustNewConstMetric(
|
||||
// up, prometheus.GaugeValue, 0,
|
||||
// )
|
||||
return []byte{}, fmt.Errorf("unable to read body: %v", readErr.Error())
|
||||
}
|
||||
|
||||
return body, nil
|
||||
}
|
||||
|
||||
// registerMetrics --
|
||||
func registerMetrics(reg prometheus.Registerer, data switchReport, target string, st float64) error {
|
||||
|
||||
// --
|
||||
collectorRelay := prometheus.NewGaugeVec(
|
||||
prometheus.GaugeOpts{
|
||||
Namespace: namespace,
|
||||
Name: "relay",
|
||||
Help: "The current state of the relay (wether or not the relay is currently turned on)",
|
||||
},
|
||||
[]string{"instance"})
|
||||
|
||||
if err := reg.Register(collectorRelay); err != nil {
|
||||
return fmt.Errorf("failed to register metric %v: %v", "relay", err.Error())
|
||||
}
|
||||
|
||||
if data.Relay {
|
||||
collectorRelay.WithLabelValues(target).Set(1)
|
||||
} else {
|
||||
collectorRelay.WithLabelValues(target).Set(0)
|
||||
}
|
||||
|
||||
if st != 114 {
|
||||
// --
|
||||
collectorPower := prometheus.NewGaugeVec(
|
||||
prometheus.GaugeOpts{
|
||||
Namespace: namespace,
|
||||
Name: "power",
|
||||
Help: "The current power consumed by devices attached to the switch",
|
||||
},
|
||||
[]string{"instance"})
|
||||
|
||||
if err := reg.Register(collectorPower); err != nil {
|
||||
return fmt.Errorf("failed to register metric %v: %v", "power", err.Error())
|
||||
}
|
||||
|
||||
collectorPower.WithLabelValues(target).Set(data.Power)
|
||||
|
||||
// --
|
||||
collectorTemperature := prometheus.NewGaugeVec(
|
||||
prometheus.GaugeOpts{
|
||||
Namespace: namespace,
|
||||
Name: "temperature",
|
||||
Help: "The currently measured temperature by the switch. (Might initially be wrong, but will automatically correct itself over the span of a few hours)",
|
||||
},
|
||||
[]string{"instance"})
|
||||
|
||||
if err := reg.Register(collectorTemperature); err != nil {
|
||||
return fmt.Errorf("failed to register metric %v: %v", "temperature", err.Error())
|
||||
}
|
||||
|
||||
collectorTemperature.WithLabelValues(target).Set(data.Temperature)
|
||||
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// registerMetrics --
|
||||
func registerInfoMetrics(reg prometheus.Registerer, data switchInfo, target string) error {
|
||||
|
||||
// --
|
||||
collectorInfo := prometheus.NewGaugeVec(
|
||||
prometheus.GaugeOpts{
|
||||
Namespace: namespace,
|
||||
Name: "info",
|
||||
Help: "general information about the device",
|
||||
},
|
||||
[]string{"instance", "version", "mac", "type", "ssid"})
|
||||
|
||||
if err := reg.Register(collectorInfo); err != nil {
|
||||
return fmt.Errorf("failed to register metric %v: %v", "info", err.Error())
|
||||
}
|
||||
|
||||
collectorInfo.WithLabelValues(target, data.Version, data.Mac, fmt.Sprintf("%v", data.SwType), data.SSID).Set(1)
|
||||
|
||||
return nil
|
||||
}
|
60
pkg/version/version.go
Normal file
60
pkg/version/version.go
Normal file
|
@ -0,0 +1,60 @@
|
|||
package version
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"runtime"
|
||||
"strings"
|
||||
"text/template"
|
||||
)
|
||||
|
||||
// Build information. Populated at build-time.
|
||||
var (
|
||||
Version string
|
||||
Revision string
|
||||
Branch string
|
||||
BuildUser string
|
||||
BuildDate string
|
||||
GoVersion = runtime.Version()
|
||||
)
|
||||
|
||||
// versionInfoTmpl contains the template used by Print.
|
||||
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, error) {
|
||||
m := map[string]string{
|
||||
"program": program,
|
||||
"version": Version,
|
||||
"revision": Revision,
|
||||
"branch": Branch,
|
||||
"buildUser": BuildUser,
|
||||
"buildDate": BuildDate,
|
||||
"goVersion": GoVersion,
|
||||
}
|
||||
t, err := template.New("version").Parse(versionInfoTmpl)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
var buf bytes.Buffer
|
||||
if err := t.ExecuteTemplate(&buf, "version", m); err != nil {
|
||||
return "", err
|
||||
}
|
||||
return strings.TrimSpace(buf.String()), nil
|
||||
}
|
||||
|
||||
// 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)
|
||||
}
|
7
tools.go
Normal file
7
tools.go
Normal file
|
@ -0,0 +1,7 @@
|
|||
// +build tools
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
_ "golang.org/x/tools/cmd/stringer"
|
||||
)
|
Loading…
Reference in a new issue