This commit is contained in:
Jake Keeys
2020-01-26 12:35:46 +00:00
commit f5de88e5bb
9 changed files with 764 additions and 0 deletions

10
Dockerfile Normal file
View File

@@ -0,0 +1,10 @@
FROM golang:alpine as build
WORKDIR /build
COPY . .
RUN go get -d -v .
RUN go build -v -o app .
FROM alpine
WORKDIR /service
COPY --from=build /build/app .
ENTRYPOINT ["./app"]

11
go.mod Normal file
View File

@@ -0,0 +1,11 @@
module github.com/jakekeeys/hg612-exporter
go 1.13
require (
github.com/gorilla/handlers v1.4.2
github.com/pkg/errors v0.9.1
github.com/prometheus/client_golang v1.3.0
github.com/sirupsen/logrus v1.4.2
github.com/urfave/cli/v2 v2.1.1
)

93
go.sum Normal file
View File

@@ -0,0 +1,93 @@
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
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/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY=
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d h1:U+s90UTSYgptZMwQh2aRr3LuazLJIa+Pg3Kc1ylSYVY=
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/gorilla/handlers v1.4.2 h1:0QniY0USkHQ1RGCLfKxeNHK9bkDHGRYGNDFBCS+YARg=
github.com/gorilla/handlers v1.4.2/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ=
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/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/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
github.com/prometheus/client_golang v1.3.0 h1:miYCvYqFXtl/J9FIy8eNpBfYthAEFg+Ys0XyUVEcDsc=
github.com/prometheus/client_golang v1.3.0/go.mod h1:hJaj2vgQTGQmVCsAACORcieXFeDPbaTKGT+JTgUa3og=
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.1.0 h1:ElTg5tNp4DqfV7UQjDqv2+RJlNzsDtvNAWccbItceIE=
github.com/prometheus/client_model v0.1.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
github.com/prometheus/common v0.7.0 h1:L+1lyG48J1zAQXA3RBX/nG/B3gjlHq0zTt2tlbJLyCY=
github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA=
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
github.com/prometheus/procfs v0.0.8 h1:+fpWZdT24pJBiqJdAwYBjPSk+5YmQzYNPYzQsdzLkt8=
github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A=
github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q=
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo=
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 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
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/urfave/cli v1.22.2 h1:gsqYFH8bb9ekPA12kRo0hfjngWQjkJPlN9R0N78BoUo=
github.com/urfave/cli/v2 v2.1.1 h1:Qt8FeAtxE/vfdrLmR3rxR6JRE0RoVmbXu8+6kZtYU4k=
github.com/urfave/cli/v2 v2.1.1/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2caLfQ=
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191220142924-d4481acd189f h1:68K/z8GLUxV76xGSqwTWw2gyk/jwn79LUL43rES2g8o=
golang.org/x/sys v0.0.0-20191220142924-d4481acd189f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
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/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=

View File

@@ -0,0 +1,54 @@
package metrics
import (
"context"
"github.com/jakekeeys/hg612-exporter/pkg/hg612"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
"time"
)
type Collector interface {
Collect()
Start()
Stop()
}
type MetricsCollector struct {
ctx context.Context
collectIntervalSeconds int
dslMetricsCollector dslMetricsCollector
}
func New(client hg612.Client, host string, collectIntervalSeconds int) Collector {
return MetricsCollector{
collectIntervalSeconds: collectIntervalSeconds,
ctx: context.Background(),
dslMetricsCollector: newDSLMetricsCollector(client, host),
}
}
func (c MetricsCollector) Collect() {
err := c.dslMetricsCollector.collect()
if err != nil {
logrus.Error(errors.Wrap(err, "error collecting dsl metrics"))
}
}
func (c MetricsCollector) Start() {
go func() {
for {
select {
case <-time.After(time.Second * time.Duration(c.collectIntervalSeconds)):
c.Collect()
case <-c.ctx.Done():
return
}
}
}()
}
func (c MetricsCollector) Stop() {
c.ctx.Done()
}

291
internal/metrics/dsl.go Normal file
View File

@@ -0,0 +1,291 @@
package metrics
import (
"github.com/jakekeeys/hg612-exporter/pkg/hg612"
"github.com/pkg/errors"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promauto"
)
type dslMetricsCollector struct {
client hg612.Client
host string
status *prometheus.GaugeVec
upCurrRate *prometheus.GaugeVec
downCurrRate *prometheus.GaugeVec
upCurrRate2 *prometheus.GaugeVec
downCurrRate2 *prometheus.GaugeVec
upMaxRate *prometheus.GaugeVec
downMaxRate *prometheus.GaugeVec
upSNR *prometheus.GaugeVec
downSNR *prometheus.GaugeVec
upAttenuation *prometheus.GaugeVec
downAttenuation *prometheus.GaugeVec
upPower *prometheus.GaugeVec
downPower *prometheus.GaugeVec
downHEC *prometheus.GaugeVec
upHEC *prometheus.GaugeVec
downCRC *prometheus.GaugeVec
upCRC *prometheus.GaugeVec
downFEC *prometheus.GaugeVec
upFEC *prometheus.GaugeVec
downHEC2 *prometheus.GaugeVec
upHEC2 *prometheus.GaugeVec
downCRC2 *prometheus.GaugeVec
upCRC2 *prometheus.GaugeVec
downFEC2 *prometheus.GaugeVec
upFEC2 *prometheus.GaugeVec
}
func newDSLMetricsCollector(client hg612.Client, host string) dslMetricsCollector {
status := promauto.NewGaugeVec(
prometheus.GaugeOpts{
Namespace: "dsl",
Name: "status",
},
[]string{"host", "status", "modulation", "dataPath"},
)
upCurrRate := promauto.NewGaugeVec(
prometheus.GaugeOpts{
Namespace: "dsl",
Name: "up_current_rate",
},
[]string{"host"},
)
downCurrRate := promauto.NewGaugeVec(
prometheus.GaugeOpts{
Namespace: "dsl",
Name: "down_current_rate",
},
[]string{"host"},
)
upCurrRate2 := promauto.NewGaugeVec(
prometheus.GaugeOpts{
Namespace: "dsl",
Name: "up_current_rate_2",
},
[]string{"host"},
)
downCurrRate2 := promauto.NewGaugeVec(
prometheus.GaugeOpts{
Namespace: "dsl",
Name: "down_current_rate_2",
},
[]string{"host"},
)
upMaxRate := promauto.NewGaugeVec(
prometheus.GaugeOpts{
Namespace: "dsl",
Name: "up_max_rate",
},
[]string{"host"},
)
downMaxRate := promauto.NewGaugeVec(
prometheus.GaugeOpts{
Namespace: "dsl",
Name: "down_max_rate",
},
[]string{"host"},
)
upSNR := promauto.NewGaugeVec(
prometheus.GaugeOpts{
Namespace: "dsl",
Name: "up_snr",
},
[]string{"host"},
)
downSNR := promauto.NewGaugeVec(
prometheus.GaugeOpts{
Namespace: "dsl",
Name: "down_snr",
},
[]string{"host"},
)
upAttenuation := promauto.NewGaugeVec(
prometheus.GaugeOpts{
Namespace: "dsl",
Name: "up_attenuation",
},
[]string{"host"},
)
downAttenuation := promauto.NewGaugeVec(
prometheus.GaugeOpts{
Namespace: "dsl",
Name: "down_attenuation",
},
[]string{"host"},
)
upPower := promauto.NewGaugeVec(
prometheus.GaugeOpts{
Namespace: "dsl",
Name: "up_power",
},
[]string{"host"},
)
downPower := promauto.NewGaugeVec(
prometheus.GaugeOpts{
Namespace: "dsl",
Name: "down_power",
},
[]string{"host"},
)
downHEC := promauto.NewGaugeVec(
prometheus.GaugeOpts{
Namespace: "dsl",
Name: "down_hec",
},
[]string{"host"},
)
upHEC := promauto.NewGaugeVec(
prometheus.GaugeOpts{
Namespace: "dsl",
Name: "up_hec",
},
[]string{"host"},
)
downCRC := promauto.NewGaugeVec(
prometheus.GaugeOpts{
Namespace: "dsl",
Name: "down_crc",
},
[]string{"host"},
)
upCRC := promauto.NewGaugeVec(
prometheus.GaugeOpts{
Namespace: "dsl",
Name: "up_crc",
},
[]string{"host"},
)
downFEC := promauto.NewGaugeVec(
prometheus.GaugeOpts{
Namespace: "dsl",
Name: "down_fec",
},
[]string{"host"},
)
upFEC := promauto.NewGaugeVec(
prometheus.GaugeOpts{
Namespace: "dsl",
Name: "up_fec",
},
[]string{"host"},
)
downHEC2 := promauto.NewGaugeVec(
prometheus.GaugeOpts{
Namespace: "dsl",
Name: "down_hec_2",
},
[]string{"host"},
)
upHEC2 := promauto.NewGaugeVec(
prometheus.GaugeOpts{
Namespace: "dsl",
Name: "up_hec_2",
},
[]string{"host"},
)
downCRC2 := promauto.NewGaugeVec(
prometheus.GaugeOpts{
Namespace: "dsl",
Name: "down_crc_2",
},
[]string{"host"},
)
upCRC2 := promauto.NewGaugeVec(
prometheus.GaugeOpts{
Namespace: "dsl",
Name: "up_crc_2",
},
[]string{"host"},
)
downFEC2 := promauto.NewGaugeVec(
prometheus.GaugeOpts{
Namespace: "dsl",
Name: "down_fec_2",
},
[]string{"host"},
)
upFEC2 := promauto.NewGaugeVec(
prometheus.GaugeOpts{
Namespace: "dsl",
Name: "up_fec_2",
},
[]string{"host"},
)
return dslMetricsCollector{
client: client,
host: host,
status: status,
upCurrRate: upCurrRate,
downCurrRate: downCurrRate,
upCurrRate2: upCurrRate2,
downCurrRate2: downCurrRate2,
upMaxRate: upMaxRate,
downMaxRate: downMaxRate,
upSNR: upSNR,
downSNR: downSNR,
upAttenuation: upAttenuation,
downAttenuation: downAttenuation,
upPower: upPower,
downPower: downPower,
downHEC: downHEC,
upHEC: upHEC,
downCRC: downCRC,
upCRC: upCRC,
downFEC: downFEC,
upFEC: upFEC,
downHEC2: downHEC2,
upHEC2: upHEC2,
downCRC2: downCRC2,
upCRC2: upCRC2,
downFEC2: downFEC2,
upFEC2: upFEC2,
}
}
func (c dslMetricsCollector) collect() error {
status, err := c.client.DSLStatus()
if err != nil {
return errors.Wrap(err, "error getting dsl status")
}
c.status.WithLabelValues(c.host, status.DSLCfg.Status, status.DSLCfg.Modulation, status.DSLCfg.DataPath).Set(1)
c.upCurrRate.WithLabelValues(c.host).Set(float64(status.DSLCfg.UpCurrRate))
c.downCurrRate.WithLabelValues(c.host).Set(float64(status.DSLCfg.DownCurrRate))
c.upCurrRate2.WithLabelValues(c.host).Set(float64(status.DSLCfg.UpCurrRate2))
c.downCurrRate2.WithLabelValues(c.host).Set(float64(status.DSLCfg.DownCurrRate2))
c.upMaxRate.WithLabelValues(c.host).Set(float64(status.DSLCfg.UpMaxRate))
c.downMaxRate.WithLabelValues(c.host).Set(float64(status.DSLCfg.DownMaxRate))
c.upSNR.WithLabelValues(c.host).Set(float64(status.DSLCfg.UpSNR))
c.downSNR.WithLabelValues(c.host).Set(float64(status.DSLCfg.DownSNR))
c.upAttenuation.WithLabelValues(c.host).Set(float64(status.DSLCfg.UpAttenuation))
c.downAttenuation.WithLabelValues(c.host).Set(float64(status.DSLCfg.DownAttenuation))
c.upPower.WithLabelValues(c.host).Set(float64(status.DSLCfg.UpPower))
c.downPower.WithLabelValues(c.host).Set(float64(status.DSLCfg.DownPower))
c.downHEC.WithLabelValues(c.host).Set(float64(status.DSLStats.DownHEC))
c.upHEC.WithLabelValues(c.host).Set(float64(status.DSLStats.UpHEC))
c.downCRC.WithLabelValues(c.host).Set(float64(status.DSLStats.DownCRC))
c.upCRC.WithLabelValues(c.host).Set(float64(status.DSLStats.UpCRC))
c.downFEC.WithLabelValues(c.host).Set(float64(status.DSLStats.DownFEC))
c.upFEC.WithLabelValues(c.host).Set(float64(status.DSLStats.UpFEC))
c.downHEC2.WithLabelValues(c.host).Set(float64(status.DSLStats.DownHEC2))
c.upHEC2.WithLabelValues(c.host).Set(float64(status.DSLStats.UpHEC2))
c.downCRC2.WithLabelValues(c.host).Set(float64(status.DSLStats.DownCRC2))
c.upCRC2.WithLabelValues(c.host).Set(float64(status.DSLStats.UpCRC2))
c.downFEC2.WithLabelValues(c.host).Set(float64(status.DSLStats.DownFEC2))
c.upFEC2.WithLabelValues(c.host).Set(float64(status.DSLStats.UpFEC2))
return nil
}

46
internal/rest/server.go Normal file
View File

@@ -0,0 +1,46 @@
package rest
import (
"context"
"github.com/gorilla/handlers"
"github.com/prometheus/client_golang/prometheus/promhttp"
"github.com/sirupsen/logrus"
"net/http"
"os"
)
type Server struct {
httpSrv *http.Server
}
func New(bind string) *Server {
var s Server
r := http.NewServeMux()
r.Handle("/prometheus", promhttp.Handler())
server := http.Server{
Addr: bind,
Handler: handlers.LoggingHandler(os.Stdout, r),
}
s.httpSrv = &server
return &s
}
func (s Server) Start() {
go func() {
err := s.httpSrv.ListenAndServe()
if err != nil {
logrus.Panic(err)
}
}()
}
func (s Server) Stop() {
err := s.httpSrv.Shutdown(context.Background())
if err != nil {
logrus.Warn(err)
}
}

61
main.go Normal file
View File

@@ -0,0 +1,61 @@
package main
import (
"fmt"
"github.com/jakekeeys/hg612-exporter/internal/metrics"
"github.com/jakekeeys/hg612-exporter/internal/rest"
"github.com/jakekeeys/hg612-exporter/pkg/hg612"
"github.com/sirupsen/logrus"
"net/http"
"os"
"os/signal"
"syscall"
"github.com/urfave/cli/v2"
)
func main() {
app := &cli.App{
Name: "hg612 prometheus exporter",
Usage: "a metrics exporter for the hg612",
Flags: []cli.Flag{
&cli.StringFlag{
Name: "host",
Usage: "the fully qualified host for the hg612 modem",
Required: true,
},
&cli.StringFlag{
Name: "bind",
Usage: "the bind string for the http server ie :8080",
Value: ":8080",
},
&cli.IntFlag{
Name: "interval",
Usage: "the interval between collection in seconds",
Value: 10,
},
},
Action: func(c *cli.Context) error {
client := hg612.New(fmt.Sprintf("http://%s", c.String("host")), http.DefaultClient)
collector := metrics.New(client, c.String("host"), c.Int("interval"))
defer collector.Stop()
collector.Start()
server := rest.New(c.String("bind"))
defer server.Stop()
server.Start()
sigChan := make(chan os.Signal, 1)
signal.Notify(sigChan, os.Interrupt, syscall.SIGTERM)
<-sigChan
return nil
},
}
err := app.Run(os.Args)
if err != nil {
logrus.Panic(err)
}
}

37
pkg/hg612/client.go Normal file
View File

@@ -0,0 +1,37 @@
package hg612
import "net/http"
//stats = map[string]stat{
// "deviceInfo": {
// path: "html/status/deviceinfo.asp",
// },
// "ATM": {
// path: "html/status/atmStatus.asp",
// },
// "WAN": {
// path: "html/status/internetstatus.asp",
// },
// "VDSL": {
// path: "html/status/xdslStatus.asp",
// },
// "LAN": {
// path: "html/status/ethenet.asp",
// },
//}
type Client interface {
DSLStatus() (*VDSLStatus, error)
}
type HG612Client struct {
basePath string
client *http.Client
}
func New(basePath string, client *http.Client) Client {
return HG612Client{
basePath: basePath,
client: client,
}
}

161
pkg/hg612/dsl.go Normal file
View File

@@ -0,0 +1,161 @@
package hg612
import (
"fmt"
"github.com/pkg/errors"
"io/ioutil"
"net/http"
"strconv"
"strings"
)
const DSLPath = "html/status/xdslStatus.asp"
type VDSLStatus struct {
DSLCfg DSLCfg
DSLStats DSLStats
DSLUpTime int
Time int
}
type DSLCfg struct {
Domain string
Status string
Modulation string
DataPath string
UpCurrRate int
DownCurrRate int
UpCurrRate2 int
DownCurrRate2 int
UpMaxRate int
DownMaxRate int
UpSNR int
DownSNR int
UpAttenuation int
DownAttenuation int
UpPower int
DownPower int
TrafficType string
}
type DSLStats struct {
Domain string
DownHEC int
UpHEC int
DownCRC int
UpCRC int
DownFEC int
UpFEC int
DownHEC2 int
UpHEC2 int
DownCRC2 int
UpCRC2 int
DownFEC2 int
UpFEC2 int
}
func (c HG612Client) DSLStatus() (*VDSLStatus, error) {
request, err := http.NewRequest(http.MethodGet, fmt.Sprintf("%s/%s", c.basePath, DSLPath), nil)
if err != nil {
return nil, errors.Wrap(err, "error creating dsl status request")
}
resp, err := c.client.Do(request)
if err != nil {
return nil, errors.Wrap(err, "error executing dsl status request")
}
all, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, errors.Wrap(err, "error reading dsl status response")
}
lines := strings.Split(string(all), "\n")
if len(lines) != 4 {
return nil, errors.New("unexpected line length in dsl status response")
}
dslCfgRaw := strings.Split(strings.TrimSuffix(strings.TrimPrefix(lines[0], "var DSLCfg = new Array(new stDsl(\""), "\"),null);"), "\",\"")
if len(dslCfgRaw) != 17 {
return nil, errors.New("unexpected dslcfg length")
}
var dslCfgRawInts []int
for i := 4; i < 16; i++ {
atoi, err := strconv.Atoi(dslCfgRaw[i])
if err != nil {
return nil, errors.Wrap(err, "error converting numeric dslcfg value")
}
dslCfgRawInts = append(dslCfgRawInts, atoi)
}
cfg := DSLCfg{
Domain: dslCfgRaw[0],
Status: dslCfgRaw[1],
Modulation: dslCfgRaw[2],
DataPath: dslCfgRaw[3],
UpCurrRate: dslCfgRawInts[0],
DownCurrRate: dslCfgRawInts[1],
UpCurrRate2: dslCfgRawInts[2],
DownCurrRate2: dslCfgRawInts[3],
UpMaxRate: dslCfgRawInts[4],
DownMaxRate: dslCfgRawInts[5],
UpSNR: dslCfgRawInts[6],
DownSNR: dslCfgRawInts[7],
UpAttenuation: dslCfgRawInts[8],
DownAttenuation: dslCfgRawInts[9],
UpPower: dslCfgRawInts[10],
DownPower: dslCfgRawInts[11],
TrafficType: dslCfgRaw[16],
}
dslStatsRaw := strings.Split(strings.TrimSuffix(strings.TrimPrefix(lines[1], "var DSLStats = new Array(new stStats(\""), "\"),null);"), "\",\"")
if len(dslStatsRaw) != 13 {
return nil, errors.New("unexpected dslstats length")
}
var dslStatsRawInts []int
for i := 1; i < 13; i++ {
atoi, err := strconv.Atoi(dslStatsRaw[i])
if err != nil {
return nil, errors.Wrap(err, "error converting numeric dsl stats value")
}
dslStatsRawInts = append(dslStatsRawInts, atoi)
}
stats := DSLStats{
Domain: dslStatsRaw[0],
DownHEC: dslStatsRawInts[0],
UpHEC: dslStatsRawInts[1],
DownCRC: dslStatsRawInts[2],
UpCRC: dslStatsRawInts[3],
DownFEC: dslStatsRawInts[4],
UpFEC: dslStatsRawInts[5],
DownHEC2: dslStatsRawInts[6],
UpHEC2: dslStatsRawInts[7],
DownCRC2: dslStatsRawInts[8],
UpCRC2: dslStatsRawInts[9],
DownFEC2: dslStatsRawInts[10],
UpFEC2: dslStatsRawInts[11],
}
dslUpTime, err := strconv.Atoi(strings.TrimSuffix(strings.TrimPrefix(lines[2], "var DslUpTime = \""), "\";"))
if err != nil {
return nil, errors.Wrap(err, "error converting dsl uptime")
}
time, err := strconv.Atoi(strings.TrimSuffix(strings.TrimPrefix(lines[3], "var time = "), ";"))
if err != nil {
return nil, errors.Wrap(err, "error converting dsl time")
}
return &VDSLStatus{
DSLCfg: cfg,
DSLStats: stats,
DSLUpTime: dslUpTime,
Time: time,
}, nil
}