Format with go fmt

This commit is contained in:
Eldwan Brianne 2020-11-02 19:19:37 +01:00
parent f19ad68975
commit 88a0fc5cae
5 changed files with 217 additions and 217 deletions

View File

@ -18,7 +18,7 @@ type Config struct {
AdguardProtocol string `config:"adguard_protocol"` AdguardProtocol string `config:"adguard_protocol"`
AdguardHostname string `config:"adguard_hostname"` AdguardHostname string `config:"adguard_hostname"`
AdguardPort uint16 `config:"adguard_port"` AdguardPort uint16 `config:"adguard_port"`
AdguardUsername string `config:"adguard_username"` AdguardUsername string `config:"adguard_username"`
AdguardPassword string `config:"adguard_password"` AdguardPassword string `config:"adguard_password"`
Port string `config:"port"` Port string `config:"port"`
Interval time.Duration `config:"interval"` Interval time.Duration `config:"interval"`
@ -29,10 +29,10 @@ func getDefaultConfig() *Config {
AdguardProtocol: "http", AdguardProtocol: "http",
AdguardHostname: "127.0.0.1", AdguardHostname: "127.0.0.1",
AdguardPort: 80, AdguardPort: 80,
AdguardUsername: "", AdguardUsername: "",
AdguardPassword: "", AdguardPassword: "",
Port: "9617", Port: "9617",
Interval: 10 * time.Second, Interval: 10 * time.Second,
} }
} }

View File

@ -1,123 +1,123 @@
package adguard package adguard
import ( import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"log" "log"
"net/http" "net/http"
"os" "os"
"time" "time"
"github.com/ebrianne/adguard-exporter/internal/metrics" "github.com/ebrianne/adguard-exporter/internal/metrics"
) )
var ( var (
statsURLPattern = "%s://%s:%d/control/stats" statsURLPattern = "%s://%s:%d/control/stats"
) )
// Client struct is a AdGuard client to request an instance of a AdGuard ad blocker. // Client struct is a AdGuard client to request an instance of a AdGuard ad blocker.
type Client struct { type Client struct {
httpClient http.Client httpClient http.Client
interval time.Duration interval time.Duration
protocol string protocol string
hostname string hostname string
port uint16 port uint16
b64password string b64password string
} }
// NewClient method initializes a new AdGuard client. // NewClient method initializes a new AdGuard client.
func NewClient(protocol, hostname string, port uint16, b64password string, interval time.Duration) *Client { func NewClient(protocol, hostname string, port uint16, b64password string, interval time.Duration) *Client {
if protocol != "http" { if protocol != "http" {
log.Printf("protocol %s is invalid. Must be http.", protocol) log.Printf("protocol %s is invalid. Must be http.", protocol)
os.Exit(1) os.Exit(1)
} }
return &Client{ return &Client{
protocol: protocol, protocol: protocol,
hostname: hostname, hostname: hostname,
port: port, port: port,
b64password: b64password, b64password: b64password,
interval: interval, interval: interval,
httpClient: http.Client{}, httpClient: http.Client{},
} }
} }
// Scrape method authenticates and retrieves statistics from AdGuard JSON API // Scrape method authenticates and retrieves statistics from AdGuard JSON API
// and then pass them as Prometheus metrics. // and then pass them as Prometheus metrics.
func (c *Client) Scrape() { func (c *Client) Scrape() {
for range time.Tick(c.interval) { for range time.Tick(c.interval) {
stats := c.getStatistics() stats := c.getStatistics()
c.setMetrics(stats) c.setMetrics(stats)
log.Printf("New tick of statistics: %s", stats.ToString()) log.Printf("New tick of statistics: %s", stats.ToString())
} }
} }
func (c *Client) setMetrics(stats *Stats) { func (c *Client) setMetrics(stats *Stats) {
metrics.AvgProcessingTime.WithLabelValues(c.hostname).Set(float64(stats.AvgProcessingTime)) metrics.AvgProcessingTime.WithLabelValues(c.hostname).Set(float64(stats.AvgProcessingTime))
metrics.DnsQueries.WithLabelValues(c.hostname).Set(float64(stats.DnsQueries)) metrics.DnsQueries.WithLabelValues(c.hostname).Set(float64(stats.DnsQueries))
metrics.BlockedFiltering.WithLabelValues(c.hostname).Set(float64(stats.BlockedFiltering)) metrics.BlockedFiltering.WithLabelValues(c.hostname).Set(float64(stats.BlockedFiltering))
metrics.ParentalFiltering.WithLabelValues(c.hostname).Set(float64(stats.ParentalFiltering)) metrics.ParentalFiltering.WithLabelValues(c.hostname).Set(float64(stats.ParentalFiltering))
metrics.SafeBrowsingFiltering.WithLabelValues(c.hostname).Set(float64(stats.SafeBrowsingFiltering)) metrics.SafeBrowsingFiltering.WithLabelValues(c.hostname).Set(float64(stats.SafeBrowsingFiltering))
metrics.SafeSearchFiltering.WithLabelValues(c.hostname).Set(float64(stats.SafeSearchFiltering)) metrics.SafeSearchFiltering.WithLabelValues(c.hostname).Set(float64(stats.SafeSearchFiltering))
for l := range stats.TopQueries { for l := range stats.TopQueries {
for domain, value := range stats.TopQueries[l] { for domain, value := range stats.TopQueries[l] {
metrics.TopQueries.WithLabelValues(c.hostname, domain).Set(float64(value)) metrics.TopQueries.WithLabelValues(c.hostname, domain).Set(float64(value))
} }
} }
for l := range stats.TopBlocked { for l := range stats.TopBlocked {
for domain, value := range stats.TopBlocked[l] { for domain, value := range stats.TopBlocked[l] {
metrics.TopBlocked.WithLabelValues(c.hostname, domain).Set(float64(value)) metrics.TopBlocked.WithLabelValues(c.hostname, domain).Set(float64(value))
} }
} }
for l := range stats.TopClients { for l := range stats.TopClients {
for source, value := range stats.TopClients[l] { for source, value := range stats.TopClients[l] {
metrics.TopClients.WithLabelValues(c.hostname, source).Set(float64(value)) metrics.TopClients.WithLabelValues(c.hostname, source).Set(float64(value))
} }
} }
} }
func (c *Client) getStatistics() *Stats { func (c *Client) getStatistics() *Stats {
var stats Stats var stats Stats
statsURL := fmt.Sprintf(statsURLPattern, c.protocol, c.hostname, c.port) statsURL := fmt.Sprintf(statsURLPattern, c.protocol, c.hostname, c.port)
req, err := http.NewRequest("GET", statsURL, nil) req, err := http.NewRequest("GET", statsURL, nil)
if err != nil { if err != nil {
log.Fatal("An error has occurred when creating HTTP statistics request ", err) log.Fatal("An error has occurred when creating HTTP statistics request ", err)
} }
if c.isUsingPassword() { if c.isUsingPassword() {
c.authenticateRequest(req) c.authenticateRequest(req)
} }
resp, err := c.httpClient.Do(req) resp, err := c.httpClient.Do(req)
if err != nil { if err != nil {
log.Printf("An error has occurred during login to Adguard: %v", err) log.Printf("An error has occurred during login to Adguard: %v", err)
} }
body, err := ioutil.ReadAll(resp.Body) body, err := ioutil.ReadAll(resp.Body)
if err != nil { if err != nil {
log.Println("Unable to read Adguard statistics HTTP response", err) log.Println("Unable to read Adguard statistics HTTP response", err)
} }
err = json.Unmarshal(body, &stats) err = json.Unmarshal(body, &stats)
if err != nil { if err != nil {
log.Println("Unable to unmarshal Adguard statistics to statistics struct model", err) log.Println("Unable to unmarshal Adguard statistics to statistics struct model", err)
} }
return &stats return &stats
} }
func (c *Client) isUsingPassword() bool { func (c *Client) isUsingPassword() bool {
return len(c.b64password) > 0 return len(c.b64password) > 0
} }
func (c *Client) authenticateRequest(req *http.Request) { func (c *Client) authenticateRequest(req *http.Request) {
req.Header.Add("Authorization", "Basic " + c.b64password) req.Header.Add("Authorization", "Basic "+c.b64password)
} }

View File

@ -4,18 +4,18 @@ import "fmt"
// Stats struct is the Adguard statistics JSON API corresponding model. // Stats struct is the Adguard statistics JSON API corresponding model.
type Stats struct { type Stats struct {
AvgProcessingTime float64 `json:"avg_processing_time"` AvgProcessingTime float64 `json:"avg_processing_time"`
DnsQueries int `json:"num_dns_queries"` DnsQueries int `json:"num_dns_queries"`
BlockedFiltering int `json:"num_blocked_filtering"` BlockedFiltering int `json:"num_blocked_filtering"`
ParentalFiltering int `json:"num_replaced_parental"` ParentalFiltering int `json:"num_replaced_parental"`
SafeBrowsingFiltering int `json:"num_replaced_safebrowsing"` SafeBrowsingFiltering int `json:"num_replaced_safebrowsing"`
SafeSearchFiltering int `json:"num_replaced_safesearch"` SafeSearchFiltering int `json:"num_replaced_safesearch"`
TopQueries []map[string]int `json:"top_queried_domains"` TopQueries []map[string]int `json:"top_queried_domains"`
TopBlocked []map[string]int `json:"top_blocked_domains"` TopBlocked []map[string]int `json:"top_blocked_domains"`
TopClients []map[string]int `json:"top_clients"` TopClients []map[string]int `json:"top_clients"`
} }
// ToString method returns a string of the current statistics struct. // ToString method returns a string of the current statistics struct.
func (s *Stats) ToString() string { func (s *Stats) ToString() string {
return fmt.Sprintf("%d ads blocked / %d total DNS queries", s.BlockedFiltering, s.DnsQueries) return fmt.Sprintf("%d ads blocked / %d total DNS queries", s.BlockedFiltering, s.DnsQueries)
} }

View File

@ -1,117 +1,117 @@
package metrics package metrics
import ( import (
"log" "log"
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
) )
var ( var (
// AvgProcessingTime - Average processing time for a DNS query // AvgProcessingTime - Average processing time for a DNS query
AvgProcessingTime = prometheus.NewGaugeVec( AvgProcessingTime = prometheus.NewGaugeVec(
prometheus.GaugeOpts{ prometheus.GaugeOpts{
Name: "avg_processing_time", Name: "avg_processing_time",
Namespace: "adguard", Namespace: "adguard",
Help: "This represent the average processing time for a DNS query in s", Help: "This represent the average processing time for a DNS query in s",
}, },
[]string{"hostname"}, []string{"hostname"},
) )
// DnsQueries - Number of DNS queries // DnsQueries - Number of DNS queries
DnsQueries = prometheus.NewGaugeVec( DnsQueries = prometheus.NewGaugeVec(
prometheus.GaugeOpts{ prometheus.GaugeOpts{
Name: "num_dns_queries", Name: "num_dns_queries",
Namespace: "adguard", Namespace: "adguard",
Help: "Number of DNS queries", Help: "Number of DNS queries",
}, },
[]string{"hostname"}, []string{"hostname"},
) )
// BlockedFiltering - Number of DNS queries blocked // BlockedFiltering - Number of DNS queries blocked
BlockedFiltering = prometheus.NewGaugeVec( BlockedFiltering = prometheus.NewGaugeVec(
prometheus.GaugeOpts{ prometheus.GaugeOpts{
Name: "num_blocked_filtering", Name: "num_blocked_filtering",
Namespace: "adguard", Namespace: "adguard",
Help: "This represent the number of domains blocked", Help: "This represent the number of domains blocked",
}, },
[]string{"hostname"}, []string{"hostname"},
) )
// ParentalFiltering - Number of DNS queries replaced by parental control // ParentalFiltering - Number of DNS queries replaced by parental control
ParentalFiltering = prometheus.NewGaugeVec( ParentalFiltering = prometheus.NewGaugeVec(
prometheus.GaugeOpts{ prometheus.GaugeOpts{
Name: "num_replaced_parental", Name: "num_replaced_parental",
Namespace: "adguard", Namespace: "adguard",
Help: "This represent the number of domains blocked (parental)", Help: "This represent the number of domains blocked (parental)",
}, },
[]string{"hostname"}, []string{"hostname"},
) )
// SafeBrowsingFiltering - Number of DNS queries replaced by safe browsing // SafeBrowsingFiltering - Number of DNS queries replaced by safe browsing
SafeBrowsingFiltering = prometheus.NewGaugeVec( SafeBrowsingFiltering = prometheus.NewGaugeVec(
prometheus.GaugeOpts{ prometheus.GaugeOpts{
Name: "num_replaced_safebrowsing", Name: "num_replaced_safebrowsing",
Namespace: "adguard", Namespace: "adguard",
Help: "This represent the number of domains blocked (safe browsing)", Help: "This represent the number of domains blocked (safe browsing)",
}, },
[]string{"hostname"}, []string{"hostname"},
) )
// SafeSearchFiltering - Number of DNS queries replaced by safe search // SafeSearchFiltering - Number of DNS queries replaced by safe search
SafeSearchFiltering = prometheus.NewGaugeVec( SafeSearchFiltering = prometheus.NewGaugeVec(
prometheus.GaugeOpts{ prometheus.GaugeOpts{
Name: "num_replaced_safesearch", Name: "num_replaced_safesearch",
Namespace: "adguard", Namespace: "adguard",
Help: "This represent the number of domains blocked (safe search)", Help: "This represent the number of domains blocked (safe search)",
}, },
[]string{"hostname"}, []string{"hostname"},
) )
// TopQueries - The number of top queries // TopQueries - The number of top queries
TopQueries = prometheus.NewGaugeVec( TopQueries = prometheus.NewGaugeVec(
prometheus.GaugeOpts{ prometheus.GaugeOpts{
Name: "top_queried_domains", Name: "top_queried_domains",
Namespace: "adguard", Namespace: "adguard",
Help: "This represent the top queried domains", Help: "This represent the top queried domains",
}, },
[]string{"hostname", "domain"}, []string{"hostname", "domain"},
) )
// TopBlocked - The number of top domains blocked // TopBlocked - The number of top domains blocked
TopBlocked = prometheus.NewGaugeVec( TopBlocked = prometheus.NewGaugeVec(
prometheus.GaugeOpts{ prometheus.GaugeOpts{
Name: "top_blocked_domains", Name: "top_blocked_domains",
Namespace: "adguard", Namespace: "adguard",
Help: "This represent the top bloacked domains", Help: "This represent the top bloacked domains",
}, },
[]string{"hostname", "domain"}, []string{"hostname", "domain"},
) )
// TopClients - The number of top clients // TopClients - The number of top clients
TopClients = prometheus.NewGaugeVec( TopClients = prometheus.NewGaugeVec(
prometheus.GaugeOpts{ prometheus.GaugeOpts{
Name: "top_clients", Name: "top_clients",
Namespace: "adguard", Namespace: "adguard",
Help: "This represent the top clients", Help: "This represent the top clients",
}, },
[]string{"hostname", "client"}, []string{"hostname", "client"},
) )
) )
// Init initializes all Prometheus metrics made available by AdGuard exporter. // Init initializes all Prometheus metrics made available by AdGuard exporter.
func Init() { func Init() {
initMetric("avg_processing_time", AvgProcessingTime) initMetric("avg_processing_time", AvgProcessingTime)
initMetric("num_dns_queries", DnsQueries) initMetric("num_dns_queries", DnsQueries)
initMetric("num_blocked_filtering", BlockedFiltering) initMetric("num_blocked_filtering", BlockedFiltering)
initMetric("num_replaced_parental", ParentalFiltering) initMetric("num_replaced_parental", ParentalFiltering)
initMetric("num_replaced_safebrowsing", SafeBrowsingFiltering) initMetric("num_replaced_safebrowsing", SafeBrowsingFiltering)
initMetric("num_replaced_safesearch", SafeSearchFiltering) initMetric("num_replaced_safesearch", SafeSearchFiltering)
initMetric("top_queried_domains", TopQueries) initMetric("top_queried_domains", TopQueries)
initMetric("top_blocked_domains", TopBlocked) initMetric("top_blocked_domains", TopBlocked)
initMetric("top_clients", TopClients) initMetric("top_clients", TopClients)
} }
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.Printf("New Prometheus metric registered: %s", name)
} }

64
main.go
View File

@ -1,64 +1,64 @@
package main package main
import ( import (
"fmt" "encoding/base64"
"os" "fmt"
"os/signal" "os"
"syscall" "os/signal"
"time" "syscall"
"encoding/base64" "time"
"github.com/ebrianne/adguard-exporter/config" "github.com/ebrianne/adguard-exporter/config"
"github.com/ebrianne/adguard-exporter/internal/metrics" "github.com/ebrianne/adguard-exporter/internal/adguard"
"github.com/ebrianne/adguard-exporter/internal/adguard" "github.com/ebrianne/adguard-exporter/internal/metrics"
"github.com/ebrianne/adguard-exporter/internal/server" "github.com/ebrianne/adguard-exporter/internal/server"
) )
const ( const (
name = "adguard-exporter" name = "adguard-exporter"
) )
var ( var (
s *server.Server s *server.Server
) )
func main() { func main() {
conf := config.Load() conf := config.Load()
metrics.Init() metrics.Init()
initAdguardClient(conf.AdguardProtocol, conf.AdguardHostname, conf.AdguardPort, conf.AdguardUsername, conf.AdguardPassword, conf.Interval) initAdguardClient(conf.AdguardProtocol, conf.AdguardHostname, conf.AdguardPort, conf.AdguardUsername, conf.AdguardPassword, conf.Interval)
initHttpServer(conf.Port) initHttpServer(conf.Port)
handleExitSignal() handleExitSignal()
} }
func basicAuth(username, password string) string { func basicAuth(username, password string) string {
auth := username + ":" + password auth := username + ":" + password
return base64.StdEncoding.EncodeToString([]byte(auth)) return base64.StdEncoding.EncodeToString([]byte(auth))
} }
func initAdguardClient(protocol, hostname string, port uint16, username, password string, interval time.Duration) { func initAdguardClient(protocol, hostname string, port uint16, username, password string, interval time.Duration) {
b64password := "" b64password := ""
if len(username) > 0 && len(password) > 0 { if len(username) > 0 && len(password) > 0 {
b64password = basicAuth(username, password) b64password = basicAuth(username, password)
} }
client := adguard.NewClient(protocol, hostname, port, b64password, interval) client := adguard.NewClient(protocol, hostname, port, b64password, interval)
go client.Scrape() go client.Scrape()
} }
func initHttpServer(port string) { func initHttpServer(port string) {
s = server.NewServer(port) s = server.NewServer(port)
go s.ListenAndServe() go s.ListenAndServe()
} }
func handleExitSignal() { func handleExitSignal() {
stop := make(chan os.Signal, 1) stop := make(chan os.Signal, 1)
signal.Notify(stop, os.Interrupt, syscall.SIGTERM) signal.Notify(stop, os.Interrupt, syscall.SIGTERM)
<-stop <-stop
s.Stop() s.Stop()
fmt.Println(fmt.Sprintf("\n%s HTTP server stopped", name)) fmt.Println(fmt.Sprintf("\n%s HTTP server stopped", name))
} }