mirror of
https://github.com/eko/pihole-exporter.git
synced 2024-11-21 11:05:22 +01:00
Merge pull request #110 from Galorhallen/async
Connection to Pi-Hole(s) handled in goroutine
This commit is contained in:
commit
5ca28527b1
14
README.md
14
README.md
@ -43,7 +43,6 @@ You can run it using the following example and pass configuration environment va
|
|||||||
$ docker run \
|
$ docker run \
|
||||||
-e 'PIHOLE_HOSTNAME=192.168.1.2' \
|
-e 'PIHOLE_HOSTNAME=192.168.1.2' \
|
||||||
-e 'PIHOLE_PASSWORD=mypassword' \
|
-e 'PIHOLE_PASSWORD=mypassword' \
|
||||||
-e 'INTERVAL=30s' \
|
|
||||||
-e 'PORT=9617' \
|
-e 'PORT=9617' \
|
||||||
-p 9617:9617 \
|
-p 9617:9617 \
|
||||||
ekofr/pihole-exporter:latest
|
ekofr/pihole-exporter:latest
|
||||||
@ -56,7 +55,6 @@ $ API_TOKEN=$(awk -F= -v key="WEBPASSWORD" '$1==key {print $2}' /etc/pihole/setu
|
|||||||
$ docker run \
|
$ docker run \
|
||||||
-e 'PIHOLE_HOSTNAME=192.168.1.2' \
|
-e 'PIHOLE_HOSTNAME=192.168.1.2' \
|
||||||
-e "PIHOLE_API_TOKEN=$API_TOKEN" \
|
-e "PIHOLE_API_TOKEN=$API_TOKEN" \
|
||||||
-e 'INTERVAL=30s' \
|
|
||||||
-e 'PORT=9617' \
|
-e 'PORT=9617' \
|
||||||
ekofr/pihole-exporter:latest
|
ekofr/pihole-exporter:latest
|
||||||
```
|
```
|
||||||
@ -69,7 +67,6 @@ $ docker run \
|
|||||||
-e 'PIHOLE_PROTOCOL=https' \
|
-e 'PIHOLE_PROTOCOL=https' \
|
||||||
-e 'PIHOLE_HOSTNAME=192.168.1.2' \
|
-e 'PIHOLE_HOSTNAME=192.168.1.2' \
|
||||||
-e 'PIHOLE_PASSWORD=mypassword' \
|
-e 'PIHOLE_PASSWORD=mypassword' \
|
||||||
-e 'INTERVAL=30s' \
|
|
||||||
-e 'PORT=9617' \
|
-e 'PORT=9617' \
|
||||||
-v '/etc/ssl/certs:/etc/ssl/certs:ro' \
|
-v '/etc/ssl/certs:/etc/ssl/certs:ro' \
|
||||||
-p 9617:9617 \
|
-p 9617:9617 \
|
||||||
@ -85,7 +82,6 @@ $ docker run \
|
|||||||
-e 'PIHOLE_HOSTNAME="192.168.1.2,192.168.1.3,192.168.1.4"' \
|
-e 'PIHOLE_HOSTNAME="192.168.1.2,192.168.1.3,192.168.1.4"' \
|
||||||
-e "PIHOLE_API_TOKEN="$API_TOKEN1,$API_TOKEN2,$API_TOKEN3" \
|
-e "PIHOLE_API_TOKEN="$API_TOKEN1,$API_TOKEN2,$API_TOKEN3" \
|
||||||
-e "PIHOLE_PORT="8080,8081,8080" \
|
-e "PIHOLE_PORT="8080,8081,8080" \
|
||||||
-e 'INTERVAL=30s' \
|
|
||||||
-e 'PORT=9617' \
|
-e 'PORT=9617' \
|
||||||
ekofr/pihole-exporter:latest
|
ekofr/pihole-exporter:latest
|
||||||
```
|
```
|
||||||
@ -98,7 +94,6 @@ $ docker run \
|
|||||||
-e 'PIHOLE_HOSTNAME="192.168.1.2,192.168.1.3,192.168.1.4"' \
|
-e 'PIHOLE_HOSTNAME="192.168.1.2,192.168.1.3,192.168.1.4"' \
|
||||||
-e "PIHOLE_API_TOKEN="$API_TOKEN" \
|
-e "PIHOLE_API_TOKEN="$API_TOKEN" \
|
||||||
-e "PIHOLE_PORT="8080" \
|
-e "PIHOLE_PORT="8080" \
|
||||||
-e 'INTERVAL=30s' \
|
|
||||||
-e 'PORT=9617' \
|
-e 'PORT=9617' \
|
||||||
ekofr/pihole-exporter:latest
|
ekofr/pihole-exporter:latest
|
||||||
```
|
```
|
||||||
@ -147,7 +142,7 @@ $ ./pihole_exporter -pihole_hostname 192.168.1.10 -pihole_api_token $API_TOKEN
|
|||||||
2019/05/09 20:19:52 PIHoleHostname : 192.168.1.10
|
2019/05/09 20:19:52 PIHoleHostname : 192.168.1.10
|
||||||
2019/05/09 20:19:52 PIHolePassword : azerty
|
2019/05/09 20:19:52 PIHolePassword : azerty
|
||||||
2019/05/09 20:19:52 Port : 9617
|
2019/05/09 20:19:52 Port : 9617
|
||||||
2019/05/09 20:19:52 Interval : 10s
|
2019/05/09 20:19:52 Timeout : 5s
|
||||||
2019/05/09 20:19:52 ------------------------------------
|
2019/05/09 20:19:52 ------------------------------------
|
||||||
2019/05/09 20:19:52 New Prometheus metric registered: domains_blocked
|
2019/05/09 20:19:52 New Prometheus metric registered: domains_blocked
|
||||||
2019/05/09 20:19:52 New Prometheus metric registered: dns_queries_today
|
2019/05/09 20:19:52 New Prometheus metric registered: dns_queries_today
|
||||||
@ -182,15 +177,14 @@ scrape_configs:
|
|||||||
|
|
||||||
## Available CLI options
|
## Available CLI options
|
||||||
```bash
|
```bash
|
||||||
# Interval of time the exporter will fetch data from PI-Hole
|
# Hostname of the host(s) where PI-Hole is installed
|
||||||
-interval duration (optional) (default 10s)
|
|
||||||
|
|
||||||
# Hostname of the Raspberry PI where PI-Hole is installed
|
|
||||||
-pihole_hostname string (optional) (default "127.0.0.1")
|
-pihole_hostname string (optional) (default "127.0.0.1")
|
||||||
|
|
||||||
# Password defined on the PI-Hole interface
|
# Password defined on the PI-Hole interface
|
||||||
-pihole_password string (optional)
|
-pihole_password string (optional)
|
||||||
|
|
||||||
|
# Timeout to connect and retrieve data from a Pi-Hole instance
|
||||||
|
-timeout duration (optional) (default 5s)
|
||||||
|
|
||||||
# WEBPASSWORD / api token defined on the PI-Hole interface at `/etc/pihole/setupVars.conf`
|
# WEBPASSWORD / api token defined on the PI-Hole interface at `/etc/pihole/setupVars.conf`
|
||||||
-pihole_api_token string (optional)
|
-pihole_api_token string (optional)
|
||||||
|
@ -4,11 +4,12 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
|
||||||
"reflect"
|
"reflect"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
|
||||||
"github.com/heetch/confita"
|
"github.com/heetch/confita"
|
||||||
"github.com/heetch/confita/backend"
|
"github.com/heetch/confita/backend"
|
||||||
"github.com/heetch/confita/backend/env"
|
"github.com/heetch/confita/backend/env"
|
||||||
@ -31,7 +32,7 @@ type EnvConfig struct {
|
|||||||
PIHolePassword []string `config:"pihole_password"`
|
PIHolePassword []string `config:"pihole_password"`
|
||||||
PIHoleApiToken []string `config:"pihole_api_token"`
|
PIHoleApiToken []string `config:"pihole_api_token"`
|
||||||
Port uint16 `config:"port"`
|
Port uint16 `config:"port"`
|
||||||
Interval time.Duration `config:"interval"`
|
Timeout time.Duration `config:"timeout"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func getDefaultEnvConfig() *EnvConfig {
|
func getDefaultEnvConfig() *EnvConfig {
|
||||||
@ -42,7 +43,7 @@ func getDefaultEnvConfig() *EnvConfig {
|
|||||||
PIHolePassword: []string{},
|
PIHolePassword: []string{},
|
||||||
PIHoleApiToken: []string{},
|
PIHoleApiToken: []string{},
|
||||||
Port: 9617,
|
Port: 9617,
|
||||||
Interval: 10 * time.Second,
|
Timeout: 5 * time.Second,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -85,6 +86,7 @@ func (c *Config) String() string {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
buffer = removeEmptyString(buffer)
|
||||||
return fmt.Sprintf("<Config@%X %s>", &c, strings.Join(buffer, ", "))
|
return fmt.Sprintf("<Config@%X %s>", &c, strings.Join(buffer, ", "))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -156,6 +158,16 @@ func extractStringConfig(data []string, idx int, hostsCount int) (bool, string,
|
|||||||
return false, "", true
|
return false, "", true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func removeEmptyString(source []string) []string {
|
||||||
|
var result []string
|
||||||
|
for _, s := range source {
|
||||||
|
if s != "" {
|
||||||
|
result = append(result, s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
func (c Config) hostnameURL() string {
|
func (c Config) hostnameURL() string {
|
||||||
s := fmt.Sprintf("%s://%s", c.PIHoleProtocol, c.PIHoleHostname)
|
s := fmt.Sprintf("%s://%s", c.PIHoleProtocol, c.PIHoleHostname)
|
||||||
if c.PIHolePort != 0 {
|
if c.PIHolePort != 0 {
|
||||||
@ -176,25 +188,25 @@ func (c Config) PIHoleLoginURL() string {
|
|||||||
|
|
||||||
func (c EnvConfig) show() {
|
func (c EnvConfig) show() {
|
||||||
val := reflect.ValueOf(&c).Elem()
|
val := reflect.ValueOf(&c).Elem()
|
||||||
log.Println("------------------------------------")
|
log.Info("------------------------------------")
|
||||||
log.Println("- PI-Hole exporter configuration -")
|
log.Info("- PI-Hole exporter configuration -")
|
||||||
log.Println("------------------------------------")
|
log.Info("------------------------------------")
|
||||||
for i := 0; i < val.NumField(); i++ {
|
for i := 0; i < val.NumField(); i++ {
|
||||||
valueField := val.Field(i)
|
valueField := val.Field(i)
|
||||||
typeField := val.Type().Field(i)
|
typeField := val.Type().Field(i)
|
||||||
|
|
||||||
// Do not print password or api token but do print the authentication method
|
// Do not print password or api token but do print the authentication method
|
||||||
if typeField.Name != "PIHolePassword" && typeField.Name != "PIHoleApiToken" {
|
if typeField.Name != "PIHolePassword" && typeField.Name != "PIHoleApiToken" {
|
||||||
log.Println(fmt.Sprintf("%s : %v", typeField.Name, valueField.Interface()))
|
log.Info(fmt.Sprintf("%s : %v", typeField.Name, valueField.Interface()))
|
||||||
} else {
|
} else {
|
||||||
showAuthenticationMethod(typeField.Name, valueField.Len())
|
showAuthenticationMethod(typeField.Name, valueField.Len())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
log.Println("------------------------------------")
|
log.Info("------------------------------------")
|
||||||
}
|
}
|
||||||
|
|
||||||
func showAuthenticationMethod(name string, length int) {
|
func showAuthenticationMethod(name string, length int) {
|
||||||
if length > 0 {
|
if length > 0 {
|
||||||
log.Println(fmt.Sprintf("Pi-Hole Authentication Method : %s", name))
|
log.Info(fmt.Sprintf("Pi-Hole Authentication Method : %s", name))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
2
go.mod
2
go.mod
@ -5,6 +5,7 @@ go 1.17
|
|||||||
require (
|
require (
|
||||||
github.com/heetch/confita v0.10.0
|
github.com/heetch/confita v0.10.0
|
||||||
github.com/prometheus/client_golang v1.12.1
|
github.com/prometheus/client_golang v1.12.1
|
||||||
|
github.com/sirupsen/logrus v1.6.0
|
||||||
github.com/stretchr/testify v1.7.0
|
github.com/stretchr/testify v1.7.0
|
||||||
github.com/xonvanetta/shutdown v0.0.3
|
github.com/xonvanetta/shutdown v0.0.3
|
||||||
golang.org/x/net v0.0.0-20210525063256-abc453219eb5
|
golang.org/x/net v0.0.0-20210525063256-abc453219eb5
|
||||||
@ -15,6 +16,7 @@ require (
|
|||||||
github.com/cespare/xxhash/v2 v2.1.2 // indirect
|
github.com/cespare/xxhash/v2 v2.1.2 // indirect
|
||||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||||
github.com/golang/protobuf v1.5.2 // indirect
|
github.com/golang/protobuf v1.5.2 // indirect
|
||||||
|
github.com/konsorten/go-windows-terminal-sequences v1.0.3 // indirect
|
||||||
github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect
|
github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect
|
||||||
github.com/pkg/errors v0.9.1 // indirect
|
github.com/pkg/errors v0.9.1 // indirect
|
||||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||||
|
2
go.sum
2
go.sum
@ -199,6 +199,7 @@ github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7V
|
|||||||
github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
|
github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
|
||||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
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.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/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/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 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
|
||||||
@ -278,6 +279,7 @@ github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIH
|
|||||||
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
|
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
|
||||||
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
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.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/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
|
||||||
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
|
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
|
@ -1,9 +1,8 @@
|
|||||||
package metrics
|
package metrics
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"log"
|
|
||||||
|
|
||||||
"github.com/prometheus/client_golang/prometheus"
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -201,5 +200,5 @@ func Init() {
|
|||||||
|
|
||||||
func initMetric(name string, metric *prometheus.GaugeVec) {
|
func initMetric(name string, metric *prometheus.GaugeVec) {
|
||||||
prometheus.MustRegister(metric)
|
prometheus.MustRegister(metric)
|
||||||
log.Printf("New Prometheus metric registered: %s", name)
|
log.Info("New Prometheus metric registered: ", name)
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,6 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"log"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
@ -12,22 +11,51 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
|
||||||
"github.com/eko/pihole-exporter/config"
|
"github.com/eko/pihole-exporter/config"
|
||||||
"github.com/eko/pihole-exporter/internal/metrics"
|
"github.com/eko/pihole-exporter/internal/metrics"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type ClientStatus byte
|
||||||
|
|
||||||
|
const (
|
||||||
|
MetricsCollectionInProgress ClientStatus = iota
|
||||||
|
MetricsCollectionSuccess
|
||||||
|
MetricsCollectionError
|
||||||
|
MetricsCollectionTimeout
|
||||||
|
)
|
||||||
|
|
||||||
|
func (status ClientStatus) String() string {
|
||||||
|
return []string{"MetricsCollectionInProgress", "MetricsCollectionSuccess", "MetricsCollectionError", "MetricsCollectionTimeout"}[status]
|
||||||
|
}
|
||||||
|
|
||||||
|
type ClientChannel struct {
|
||||||
|
Status ClientStatus
|
||||||
|
Err error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ClientChannel) String() string {
|
||||||
|
if c.Err != nil {
|
||||||
|
return fmt.Sprintf("ClientChannel<Status: %s, Err: '%s'>", c.Status, c.Err.Error())
|
||||||
|
} else {
|
||||||
|
return fmt.Sprintf("ClientChannel<Status: %s, Err: <nil>>", c.Status)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Client struct is a PI-Hole client to request an instance of a PI-Hole ad blocker.
|
// Client struct is a PI-Hole client to request an instance of a PI-Hole ad blocker.
|
||||||
type Client struct {
|
type Client struct {
|
||||||
httpClient http.Client
|
httpClient http.Client
|
||||||
interval time.Duration
|
interval time.Duration
|
||||||
config *config.Config
|
config *config.Config
|
||||||
|
Status chan *ClientChannel
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewClient method initializes a new PI-Hole client.
|
// NewClient method initializes a new PI-Hole client.
|
||||||
func NewClient(config *config.Config) *Client {
|
func NewClient(config *config.Config, envConfig *config.EnvConfig) *Client {
|
||||||
err := config.Validate()
|
err := config.Validate()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Print(err)
|
log.Error(err)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -39,7 +67,9 @@ func NewClient(config *config.Config) *Client {
|
|||||||
CheckRedirect: func(req *http.Request, via []*http.Request) error {
|
CheckRedirect: func(req *http.Request, via []*http.Request) error {
|
||||||
return http.ErrUseLastResponse
|
return http.ErrUseLastResponse
|
||||||
},
|
},
|
||||||
|
Timeout: envConfig.Timeout,
|
||||||
},
|
},
|
||||||
|
Status: make(chan *ClientChannel, 1),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -47,32 +77,24 @@ func (c *Client) String() string {
|
|||||||
return c.config.PIHoleHostname
|
return c.config.PIHoleHostname
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
func (c *Client) CollectMetricsAsync(writer http.ResponseWriter, request *http.Request) {
|
||||||
// Metrics scrapes pihole and sets them
|
log.Printf("Collecting from %s", c.config.PIHoleHostname)
|
||||||
func (c *Client) Metrics() http.HandlerFunc {
|
if stats, err := c.getStatistics(); err == nil {
|
||||||
return func(writer http.ResponseWriter, request *http.Request) {
|
|
||||||
stats, err := c.getStatistics()
|
|
||||||
if err != nil {
|
|
||||||
writer.WriteHeader(http.StatusBadRequest)
|
|
||||||
_, _ = writer.Write([]byte(err.Error()))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
c.setMetrics(stats)
|
c.setMetrics(stats)
|
||||||
|
c.Status <- &ClientChannel{Status: MetricsCollectionSuccess, Err: nil}
|
||||||
log.Printf("New tick of statistics: %s", stats.ToString())
|
log.Printf("New tick of statistics from %s: %s", c.config.PIHoleHostname, stats)
|
||||||
promhttp.Handler().ServeHTTP(writer, request)
|
} else {
|
||||||
|
c.Status <- &ClientChannel{Status: MetricsCollectionError, Err: err}
|
||||||
}
|
}
|
||||||
}*/
|
}
|
||||||
|
|
||||||
func (c *Client) CollectMetrics(writer http.ResponseWriter, request *http.Request) error {
|
func (c *Client) CollectMetrics(writer http.ResponseWriter, request *http.Request) error {
|
||||||
|
|
||||||
stats, err := c.getStatistics()
|
stats, err := c.getStatistics()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
c.setMetrics(stats)
|
c.setMetrics(stats)
|
||||||
|
log.Printf("New tick of statistics from %s: %s", c.config.PIHoleHostname, stats)
|
||||||
log.Printf("New tick of statistics from %s: %s", c, stats)
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -137,7 +159,7 @@ func (c *Client) getPHPSessionID() (sessionID string) {
|
|||||||
|
|
||||||
resp, err := c.httpClient.Do(req)
|
resp, err := c.httpClient.Do(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("An error has occured during login to PI-Hole: %v", err)
|
log.Errorf("An error has occured during login to PI-Hole: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, cookie := range resp.Cookies() {
|
for _, cookie := range resp.Cookies() {
|
||||||
|
@ -2,7 +2,6 @@ package server
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
@ -10,6 +9,7 @@ import (
|
|||||||
|
|
||||||
"github.com/eko/pihole-exporter/internal/pihole"
|
"github.com/eko/pihole-exporter/internal/pihole"
|
||||||
"github.com/prometheus/client_golang/prometheus/promhttp"
|
"github.com/prometheus/client_golang/prometheus/promhttp"
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
"golang.org/x/net/context"
|
"golang.org/x/net/context"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -22,32 +22,31 @@ type Server struct {
|
|||||||
// the different routes that will be used by Prometheus (metrics) or for monitoring (readiness, liveness).
|
// the different routes that will be used by Prometheus (metrics) or for monitoring (readiness, liveness).
|
||||||
func NewServer(port uint16, clients []*pihole.Client) *Server {
|
func NewServer(port uint16, clients []*pihole.Client) *Server {
|
||||||
mux := http.NewServeMux()
|
mux := http.NewServeMux()
|
||||||
httpServer := &http.Server{Addr: ":" + strconv.Itoa(int(port)), Handler: mux}
|
httpServer := &http.Server{
|
||||||
|
Addr: ":" + strconv.Itoa(int(port)),
|
||||||
|
Handler: mux,
|
||||||
|
}
|
||||||
|
|
||||||
s := &Server{
|
s := &Server{
|
||||||
httpServer: httpServer,
|
httpServer: httpServer,
|
||||||
}
|
}
|
||||||
|
|
||||||
mux.HandleFunc("/metrics",
|
mux.HandleFunc("/metrics", func(writer http.ResponseWriter, request *http.Request) {
|
||||||
func(writer http.ResponseWriter, request *http.Request) {
|
log.Printf("request.Header: %v\n", request.Header)
|
||||||
errors := make([]string, 0)
|
|
||||||
|
|
||||||
for _, client := range clients {
|
for _, client := range clients {
|
||||||
if err := client.CollectMetrics(writer, request); err != nil {
|
go client.CollectMetricsAsync(writer, request)
|
||||||
errors = append(errors, err.Error())
|
}
|
||||||
fmt.Printf("Error %s\n", err)
|
|
||||||
}
|
for _, client := range clients {
|
||||||
|
status := <-client.Status
|
||||||
|
if status.Status == pihole.MetricsCollectionError {
|
||||||
|
log.Printf("An error occured while contacting %s: %s", client.GetHostname(), status.Err.Error())
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if len(errors) == len(clients) {
|
promhttp.Handler().ServeHTTP(writer, request)
|
||||||
writer.WriteHeader(http.StatusBadRequest)
|
})
|
||||||
body := strings.Join(errors, "\n")
|
|
||||||
_, _ = writer.Write([]byte(body))
|
|
||||||
}
|
|
||||||
|
|
||||||
promhttp.Handler().ServeHTTP(writer, request)
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
mux.Handle("/readiness", s.readinessHandler())
|
mux.Handle("/readiness", s.readinessHandler())
|
||||||
mux.Handle("/liveness", s.livenessHandler())
|
mux.Handle("/liveness", s.livenessHandler())
|
||||||
@ -73,6 +72,27 @@ func (s *Server) Stop() {
|
|||||||
s.httpServer.Shutdown(ctx)
|
s.httpServer.Shutdown(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Server) handleMetrics(clients []*pihole.Client) http.HandlerFunc {
|
||||||
|
return func(writer http.ResponseWriter, request *http.Request) {
|
||||||
|
errors := make([]string, 0)
|
||||||
|
|
||||||
|
for _, client := range clients {
|
||||||
|
if err := client.CollectMetrics(writer, request); err != nil {
|
||||||
|
errors = append(errors, err.Error())
|
||||||
|
fmt.Printf("Error %s\n", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(errors) == len(clients) {
|
||||||
|
writer.WriteHeader(http.StatusBadRequest)
|
||||||
|
body := strings.Join(errors, "\n")
|
||||||
|
_, _ = writer.Write([]byte(body))
|
||||||
|
}
|
||||||
|
|
||||||
|
promhttp.Handler().ServeHTTP(writer, request)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (s *Server) readinessHandler() http.HandlerFunc {
|
func (s *Server) readinessHandler() http.HandlerFunc {
|
||||||
return func(w http.ResponseWriter, req *http.Request) {
|
return func(w http.ResponseWriter, req *http.Request) {
|
||||||
if s.isReady() {
|
if s.isReady() {
|
||||||
|
6
main.go
6
main.go
@ -20,7 +20,7 @@ func main() {
|
|||||||
|
|
||||||
serverDead := make(chan struct{})
|
serverDead := make(chan struct{})
|
||||||
|
|
||||||
clients := buildClients(clientConfigs)
|
clients := buildClients(clientConfigs, envConf)
|
||||||
|
|
||||||
s := server.NewServer(envConf.Port, clients)
|
s := server.NewServer(envConf.Port, clients)
|
||||||
go func() {
|
go func() {
|
||||||
@ -43,12 +43,12 @@ func main() {
|
|||||||
log.Println("pihole-exporter HTTP server stopped")
|
log.Println("pihole-exporter HTTP server stopped")
|
||||||
}
|
}
|
||||||
|
|
||||||
func buildClients(clientConfigs []config.Config) []*pihole.Client {
|
func buildClients(clientConfigs []config.Config, envConfig *config.EnvConfig) []*pihole.Client {
|
||||||
clients := make([]*pihole.Client, 0, len(clientConfigs))
|
clients := make([]*pihole.Client, 0, len(clientConfigs))
|
||||||
for i := range clientConfigs {
|
for i := range clientConfigs {
|
||||||
clientConfig := &clientConfigs[i]
|
clientConfig := &clientConfigs[i]
|
||||||
|
|
||||||
client := pihole.NewClient(clientConfig)
|
client := pihole.NewClient(clientConfig, envConfig)
|
||||||
clients = append(clients, client)
|
clients = append(clients, client)
|
||||||
}
|
}
|
||||||
return clients
|
return clients
|
||||||
|
Loading…
Reference in New Issue
Block a user