Difference between revisions of "Mtr exporter"

From UVOO Tech Wiki
Jump to navigation Jump to search
 
(One intermediate revision by the same user not shown)
Line 200: Line 200:
 
```
 
```
 
docker run -d -p 9115:9115 -p 9116:9116 mtr-blackbox-exporter
 
docker run -d -p 9115:9115 -p 9116:9116 mtr-blackbox-exporter
 +
 +
```
 +
 +
# more2
 +
 +
```
 +
package main
 +
 +
import (
 +
"encoding/json"
 +
"log"
 +
"net/http"
 +
"os/exec"
 +
"strconv"
 +
"strings"
 +
 +
"github.com/gorilla/mux"
 +
"github.com/prometheus/client_golang/prometheus"
 +
"github.com/prometheus/client_golang/prometheus/promhttp"
 +
)
 +
 +
// Define the MTRResult struct to match MTR JSON output
 +
type MTRResult struct {
 +
Report struct {
 +
Hubs []struct {
 +
Count int    `json:"count"`
 +
Loss  float64 `json:"Loss%"`
 +
Snt  int    `json:"Snt"`
 +
Last  float64 `json:"Last"`
 +
Avg  float64 `json:"Avg"`
 +
Best  float64 `json:"Best"`
 +
Wrst  float64 `json:"Wrst"`
 +
StDev float64 `json:"StDev"`
 +
Host  string  `json:"Host"`
 +
} `json:"hubs"`
 +
} `json:"report"`
 +
}
 +
 +
var (
 +
// Define Prometheus metrics
 +
mtrLoss = prometheus.NewGaugeVec(prometheus.GaugeOpts{
 +
Name: "mtr_loss_percentage",
 +
Help: "Packet loss percentage reported by MTR",
 +
}, []string{"host", "target"})
 +
 +
mtrAvg = prometheus.NewGaugeVec(prometheus.GaugeOpts{
 +
Name: "mtr_avg_latency",
 +
Help: "Average latency reported by MTR",
 +
}, []string{"host", "target"})
 +
 +
mtrBest = prometheus.NewGaugeVec(prometheus.GaugeOpts{
 +
Name: "mtr_best_latency",
 +
Help: "Best latency reported by MTR",
 +
}, []string{"host", "target"})
 +
 +
mtrWrst = prometheus.NewGaugeVec(prometheus.GaugeOpts{
 +
Name: "mtr_wrst_latency",
 +
Help: "Worst latency reported by MTR",
 +
}, []string{"host", "target"})
 +
)
 +
 +
func init() {
 +
// Register Prometheus metrics
 +
prometheus.MustRegister(mtrLoss)
 +
prometheus.MustRegister(mtrAvg)
 +
prometheus.MustRegister(mtrBest)
 +
prometheus.MustRegister(mtrWrst)
 +
}
 +
 +
func runMTR(target string) (MTRResult, error) {
 +
cmd := exec.Command("mtr", "--report", "--json", target)
 +
out, err := cmd.Output()
 +
if err != nil {
 +
return MTRResult{}, err
 +
}
 +
 +
var result MTRResult
 +
err = json.Unmarshal(out, &result)
 +
if err != nil {
 +
return MTRResult{}, err
 +
}
 +
return result, nil
 +
}
 +
 +
func probeHandler(w http.ResponseWriter, r *http.Request) {
 +
target := r.URL.Query().Get("target")
 +
if target == "" {
 +
target = "8.8.8.8"
 +
}
 +
 +
result, err := runMTR(target)
 +
if err != nil {
 +
http.Error(w, err.Error(), http.StatusInternalServerError)
 +
return
 +
}
 +
 +
for _, hub := range result.Report.Hubs {
 +
host := strings.TrimSpace(hub.Host)
 +
mtrLoss.WithLabelValues(host, target).Set(hub.Loss)
 +
mtrAvg.WithLabelValues(host, target).Set(hub.Avg)
 +
mtrBest.WithLabelValues(host, target).Set(hub.Best)
 +
mtrWrst.WithLabelValues(host, target).Set(hub.Wrst)
 +
}
 +
 +
w.Header().Set("Content-Type", "application/json")
 +
json.NewEncoder(w).Encode(result)
 +
}
 +
 +
func main() {
 +
r := mux.NewRouter()
 +
r.HandleFunc("/probe", probeHandler).Methods("GET")
 +
r.Handle("/metrics", promhttp.Handler())
 +
 +
log.Println("Starting server on :9115")
 +
log.Fatal(http.ListenAndServe(":9115", r))
 +
}
 +
  
 
```
 
```

Latest revision as of 19:50, 14 June 2024

mtr_probe.go

package main

import (
    "encoding/json"
    "log"
    "net/http"
    "os/exec"

    "github.com/gorilla/mux"
)

type MTRResult struct {
    // Define the structure to match MTR JSON output
}

func runMTR(target string) (string, error) {
    cmd := exec.Command("mtr", "--report", "--json", target)
    out, err := cmd.Output()
    if err != nil {
        return "", err
    }
    return string(out), nil
}

func probeHandler(w http.ResponseWriter, r *http.Request) {
    target := r.URL.Query().Get("target")
    if target == "" {
        target = "8.8.8.8"
    }

    result, err := runMTR(target)
    if err != nil {
        http.Error(w, err.Error(), http.StatusInternalServerError)
        return
    }

    w.Header().Set("Content-Type", "application/json")
    w.Write([]byte(result))
}

func main() {
    r := mux.NewRouter()
    r.HandleFunc("/probe", probeHandler).Methods("GET")
    http.Handle("/", r)
    log.Println("Starting server on :9115")
    log.Fatal(http.ListenAndServe(":9115", nil))
}


Dockerfile

# Start from the official Go image
FROM golang:1.18 as builder

# Set the Current Working Directory inside the container
WORKDIR /app

# Copy go.mod and go.sum files
COPY go.mod go.sum ./

# Download all dependencies. Dependencies will be cached if the go.mod and go.sum files are not changed
RUN go mod download

# Copy the source from the current directory to the Working Directory inside the container
COPY . .

# Build the Go app
RUN go build -o mtr_probe .

# Use a minimal image to run the application
FROM debian:bullseye-slim

# Install MTR
RUN apt-get update && apt-get install -y mtr-tiny

# Copy the pre-built binary file from the previous stage
COPY --from=builder /app/mtr_probe /usr/local/bin/mtr_probe

# Expose port 9115 to the outside world
EXPOSE 9115

# Command to run the executable
CMD ["mtr_probe"]

go.mod

module mtr_probe

go 1.18

require github.com/gorilla/mux v1.8.0

sh

# Build the Docker image
docker build -t mtr-probe .

# Run the Docker container
docker run -d -p 9115:9115 mtr-probe


scrape_configs:
  - job_name: 'blackbox'
    metrics_path: /probe
    params:
      module: [mtr]  # Look for an 'mtr' module in blackbox exporter config.
    static_configs:
      - targets:
        - 'example.com'
    relabel_configs:
      - source_labels: [__address__]
        target_label: __param_target
      - source_labels: [__param_target]
        target_label: instance
      - target_label: __address__
        replacement: 127.0.0.1:9115  # MTR prober address

More

# Stage 1: Build the Go application
FROM golang:1.18 as builder

# Set the working directory inside the container
WORKDIR /app

# Copy go.mod and go.sum files
COPY go.mod go.sum ./

# Download all dependencies
RUN go mod download

# Copy the source code
COPY . .

# Build the Go application
RUN go build -o mtr_probe .

# Stage 2: Build the final image
FROM debian:bullseye-slim

# Install MTR and necessary utilities
RUN apt-get update && apt-get install -y mtr-tiny wget ca-certificates

# Install Blackbox Exporter
RUN wget https://github.com/prometheus/blackbox_exporter/releases/download/v0.23.0/blackbox_exporter-0.23.0.linux-amd64.tar.gz \
    && tar -xzf blackbox_exporter-0.23.0.linux-amd64.tar.gz \
    && mv blackbox_exporter-0.23.0.linux-amd64/blackbox_exporter /usr/local/bin/ \
    && rm -rf blackbox_exporter-0.23.0.linux-amd64*

# Copy the Go application binary
COPY --from=builder /app/mtr_probe /usr/local/bin/mtr_probe

# Create a blackbox exporter config
COPY blackbox.yml /etc/blackbox_exporter/config.yml

# Expose ports for both services
EXPOSE 9115 9116

# Start both the Go application and Blackbox Exporter
CMD ["sh", "-c", "mtr_probe & blackbox_exporter --config.file=/etc/blackbox_exporter/config.yml"]

blacbox.yaml

modules:
  http_2xx:
    prober: http
    timeout: 5s
    http:
      valid_http_versions: ["HTTP/1.1", "HTTP/2"]
      valid_status_codes: []  # Defaults to 2xx
      method: GET
  mtr:
    prober: mtr
    timeout: 30s
    mtr:
      targets:
        - 8.8.8.8  # Example target

docker run -d -p 9115:9115 -p 9116:9116 mtr-blackbox-exporter

more2

package main

import (
    "encoding/json"
    "log"
    "net/http"
    "os/exec"
    "strconv"
    "strings"

    "github.com/gorilla/mux"
    "github.com/prometheus/client_golang/prometheus"
    "github.com/prometheus/client_golang/prometheus/promhttp"
)

// Define the MTRResult struct to match MTR JSON output
type MTRResult struct {
    Report struct {
        Hubs []struct {
            Count int     `json:"count"`
            Loss  float64 `json:"Loss%"`
            Snt   int     `json:"Snt"`
            Last  float64 `json:"Last"`
            Avg   float64 `json:"Avg"`
            Best  float64 `json:"Best"`
            Wrst  float64 `json:"Wrst"`
            StDev float64 `json:"StDev"`
            Host  string  `json:"Host"`
        } `json:"hubs"`
    } `json:"report"`
}

var (
    // Define Prometheus metrics
    mtrLoss = prometheus.NewGaugeVec(prometheus.GaugeOpts{
        Name: "mtr_loss_percentage",
        Help: "Packet loss percentage reported by MTR",
    }, []string{"host", "target"})

    mtrAvg = prometheus.NewGaugeVec(prometheus.GaugeOpts{
        Name: "mtr_avg_latency",
        Help: "Average latency reported by MTR",
    }, []string{"host", "target"})

    mtrBest = prometheus.NewGaugeVec(prometheus.GaugeOpts{
        Name: "mtr_best_latency",
        Help: "Best latency reported by MTR",
    }, []string{"host", "target"})

    mtrWrst = prometheus.NewGaugeVec(prometheus.GaugeOpts{
        Name: "mtr_wrst_latency",
        Help: "Worst latency reported by MTR",
    }, []string{"host", "target"})
)

func init() {
    // Register Prometheus metrics
    prometheus.MustRegister(mtrLoss)
    prometheus.MustRegister(mtrAvg)
    prometheus.MustRegister(mtrBest)
    prometheus.MustRegister(mtrWrst)
}

func runMTR(target string) (MTRResult, error) {
    cmd := exec.Command("mtr", "--report", "--json", target)
    out, err := cmd.Output()
    if err != nil {
        return MTRResult{}, err
    }

    var result MTRResult
    err = json.Unmarshal(out, &result)
    if err != nil {
        return MTRResult{}, err
    }
    return result, nil
}

func probeHandler(w http.ResponseWriter, r *http.Request) {
    target := r.URL.Query().Get("target")
    if target == "" {
        target = "8.8.8.8"
    }

    result, err := runMTR(target)
    if err != nil {
        http.Error(w, err.Error(), http.StatusInternalServerError)
        return
    }

    for _, hub := range result.Report.Hubs {
        host := strings.TrimSpace(hub.Host)
        mtrLoss.WithLabelValues(host, target).Set(hub.Loss)
        mtrAvg.WithLabelValues(host, target).Set(hub.Avg)
        mtrBest.WithLabelValues(host, target).Set(hub.Best)
        mtrWrst.WithLabelValues(host, target).Set(hub.Wrst)
    }

    w.Header().Set("Content-Type", "application/json")
    json.NewEncoder(w).Encode(result)
}

func main() {
    r := mux.NewRouter()
    r.HandleFunc("/probe", probeHandler).Methods("GET")
    r.Handle("/metrics", promhttp.Handler())

    log.Println("Starting server on :9115")
    log.Fatal(http.ListenAndServe(":9115", r))
}