Skip to content

Commit

Permalink
Miscellaneous cleanups to collector code
Browse files Browse the repository at this point in the history
Refactor parsing of mod_status proxy balancer lines to use regular
expressions, thus making code more readable.

Signed-off-by: Daniel Swarbrick <[email protected]>
  • Loading branch information
dswarbrick committed Feb 6, 2024
1 parent 92a7bd9 commit aa56e5f
Showing 1 changed file with 41 additions and 52 deletions.
93 changes: 41 additions & 52 deletions collector/collector.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,24 +8,33 @@
package collector

import (
"bufio"
"bytes"
"crypto/tls"
"fmt"
"github.com/prometheus/common/version"
"io"
"net/http"
"regexp"
"strconv"
"strings"
"sync"

"github.com/go-kit/log"
"github.com/go-kit/log/level"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/common/version"
)

const (
namespace = "apache"
)

var (
// Regular expressions for matching proxy balancer status lines.
reProxyBalName = regexp.MustCompile(`ProxyBalancer\[\d+\]Name`)
reProxyBalWorker = regexp.MustCompile(`ProxyBalancer\[\d+\]Worker\[\d+\](\S+)`)
)

type Exporter struct {
URI string
hostOverride string
Expand Down Expand Up @@ -230,7 +239,6 @@ func (e *Exporter) Describe(ch chan<- *prometheus.Desc) {

// Split colon separated string into two fields
func splitkv(s string) (string, string) {

if len(s) == 0 {
return s, s
}
Expand Down Expand Up @@ -275,37 +283,37 @@ func (e *Exporter) updateScoreboard(scoreboard string) {
}

func (e *Exporter) collect(ch chan<- prometheus.Metric) error {
req, err := http.NewRequest("GET", e.URI, nil)
req.Header.Set("User-Agent", e.userAgent)
req, err := http.NewRequest(http.MethodGet, e.URI, nil)
if err != nil {
return fmt.Errorf("error building scraping request: %w", err)
}

if e.hostOverride != "" {
req.Host = e.hostOverride
}
if err != nil {
return fmt.Errorf("error building scraping request: %v", err)
}

for k, v := range e.customHeaders {
req.Header.Add(k, v)
}

req.Header.Set("User-Agent", e.userAgent)
resp, err := e.client.Do(req)
if err != nil {
ch <- prometheus.MustNewConstMetric(e.up, prometheus.GaugeValue, 0)
return fmt.Errorf("error scraping apache: %v", err)
return fmt.Errorf("error scraping Apache: %w", err)
}
ch <- prometheus.MustNewConstMetric(e.up, prometheus.GaugeValue, 1)

data, err := io.ReadAll(resp.Body)
resp.Body.Close()
if resp.StatusCode != 200 {
if resp.StatusCode != http.StatusOK {
if err != nil {
data = []byte(err.Error())
}
return fmt.Errorf("status %s (%d): %s", resp.Status, resp.StatusCode, data)
}

lines := strings.Split(string(data), "\n")

connectionInfo := false
//connectionInfo := false
version := "UNKNOWN"
mpm := "UNKNOWN"
balancerName := "UNKNOWN"
Expand All @@ -316,28 +324,26 @@ func (e *Exporter) collect(ch chan<- prometheus.Metric) error {
e.proxyBalancerStatus.Reset()
e.proxyBalancerBusy.Reset()

for _, l := range lines {
key, v := splitkv(l)
scanner := bufio.NewScanner(bytes.NewReader(data))

for scanner.Scan() {
key, v := splitkv(scanner.Text())
if err != nil {
continue
}

switch {
case key == "ServerVersion":
var tmpstr string
var vparts []string

version = v
tmpstr = strings.Split(v, "/")[1]
tmpstr := strings.Split(v, "/")[1]
tmpstr = strings.Split(tmpstr, " ")[0]
vparts = strings.Split(tmpstr, ".")
tmpstr = vparts[0] + "." + fmt.Sprintf("%02s", vparts[1]) + fmt.Sprintf("%03s", vparts[2])
vparts := strings.Split(tmpstr, ".")
tmpstr = fmt.Sprintf("%s.%02s%03s", vparts[0], vparts[1], vparts[2])

val, err := strconv.ParseFloat(tmpstr, 64)
if err != nil {
return err
}

ch <- prometheus.MustNewConstMetric(e.apacheVersion, prometheus.GaugeValue, val)
case key == "ServerMPM":
mpm = v
Expand All @@ -346,56 +352,48 @@ func (e *Exporter) collect(ch chan<- prometheus.Metric) error {
if err != nil {
return err
}

e.generation.WithLabelValues("config").Set(val)
case key == "ParentServerMPMGeneration":
val, err := strconv.ParseFloat(v, 64)
if err != nil {
return err
}

e.generation.WithLabelValues("mpm").Set(val)
case key == "Load1":
val, err := strconv.ParseFloat(v, 64)
if err != nil {
return err
}

e.load.WithLabelValues("1min").Set(val)
case key == "Load5":
val, err := strconv.ParseFloat(v, 64)
if err != nil {
return err
}

e.load.WithLabelValues("5min").Set(val)
case key == "Load15":
val, err := strconv.ParseFloat(v, 64)
if err != nil {
return err
}

e.load.WithLabelValues("15min").Set(val)
case key == "Total Accesses":
val, err := strconv.ParseFloat(v, 64)
if err != nil {
return err
}

ch <- prometheus.MustNewConstMetric(e.accessesTotal, prometheus.CounterValue, val)
case key == "Total kBytes":
val, err := strconv.ParseFloat(v, 64)
if err != nil {
return err
}

ch <- prometheus.MustNewConstMetric(e.kBytesTotal, prometheus.CounterValue, val)
case key == "Total Duration":
val, err := strconv.ParseFloat(v, 64)
if err != nil {
return err
}

ch <- prometheus.MustNewConstMetric(e.durationTotal, prometheus.CounterValue, val)
case key == "CPUUser":
val, err := strconv.ParseFloat(v, 64)
Expand Down Expand Up @@ -434,57 +432,49 @@ func (e *Exporter) collect(ch chan<- prometheus.Metric) error {
if err != nil {
return err
}

e.cpuload.Set(val)
case key == "Uptime":
val, err := strconv.ParseFloat(v, 64)
if err != nil {
return err
}

ch <- prometheus.MustNewConstMetric(e.uptime, prometheus.CounterValue, val)
case key == "BusyWorkers":
val, err := strconv.ParseFloat(v, 64)
if err != nil {
return err
}

e.workers.WithLabelValues("busy").Set(val)
case key == "IdleWorkers":
val, err := strconv.ParseFloat(v, 64)
if err != nil {
return err
}

e.workers.WithLabelValues("idle").Set(val)
case key == "Processes":
val, err := strconv.ParseFloat(v, 64)
if err != nil {
return err
}

e.processes.WithLabelValues("all").Set(val)
case key == "Stopping":
val, err := strconv.ParseFloat(v, 64)
if err != nil {
return err
}

e.processes.WithLabelValues("stopping").Set(val)
case key == "ConnsTotal":
val, err := strconv.ParseFloat(v, 64)
if err != nil {
return err
}

e.connections.WithLabelValues("total").Set(val)
connectionInfo = true
case key == "ConnsAsyncWriting":
val, err := strconv.ParseFloat(v, 64)
if err != nil {
return err
}

e.connections.WithLabelValues("writing").Set(val)
connectionInfo = true
case key == "ConnsAsyncKeepAlive":
Expand All @@ -504,40 +494,40 @@ func (e *Exporter) collect(ch chan<- prometheus.Metric) error {
case key == "Scoreboard":
e.updateScoreboard(v)
e.scoreboard.Collect(ch)

//ProxyBalancer[0]Name: balancer://sid2021
//ProxyBalancer[0]Worker[0]Name: https://z-app-01:9143
//ProxyBalancer[0]Worker[0]Status: Init Ok
//ProxyBalancer[0]Worker[0]Elected: 5808
//...
case strings.HasPrefix(key, "ProxyBalancer["):
switch {
case strings.HasSuffix(key, "]Name"):
if strings.Contains(key, "]Worker[") {
workerName = v
} else {
balancerName = v
}
case strings.HasSuffix(key, "]Status"):
case reProxyBalName.MatchString(key):
balancerName = v
case reProxyBalWorker.MatchString(key):
key := reProxyBalWorker.FindStringSubmatch(key)[1]
switch key {
case "Name":
workerName = v
case "Status":
e.proxyBalancerStatus.WithLabelValues(balancerName, workerName, v).Set(1)
case strings.HasSuffix(key, "]Elected"):
case "Elected":
val, err := strconv.ParseFloat(v, 64)
if err != nil {
return err
}
ch <- prometheus.MustNewConstMetric(e.proxyBalancerElected, prometheus.CounterValue, val, balancerName, workerName)
case strings.HasSuffix(key, "]Busy"):
case "Busy":
val, err := strconv.ParseFloat(v, 64)
if err != nil {
return err
}
e.proxyBalancerBusy.WithLabelValues(balancerName, workerName).Set(val)
case strings.HasSuffix(key, "]Sent"):
case "Sent":
val, err := strconv.ParseFloat(strings.TrimRight(v, "kK"), 64)
if err != nil {
return err
}
ch <- prometheus.MustNewConstMetric(e.proxyBalancerReqSize, prometheus.CounterValue, val, balancerName, workerName)
case strings.HasSuffix(key, "]Rcvd"):
case "Rcvd":
val, err := strconv.ParseFloat(strings.TrimRight(v, "kK"), 64)
if err != nil {
return err
Expand Down Expand Up @@ -575,9 +565,8 @@ func (e *Exporter) Collect(ch chan<- prometheus.Metric) {
e.mutex.Lock() // To protect metrics from concurrent collects.
defer e.mutex.Unlock()
if err := e.collect(ch); err != nil {
level.Error(e.logger).Log("msg", "Error scraping apache:", "err", err)
level.Error(e.logger).Log("msg", "Error scraping Apache:", "err", err)
e.scrapeFailures.Inc()
e.scrapeFailures.Collect(ch)
}
return
}

0 comments on commit aa56e5f

Please sign in to comment.