first commit

This commit is contained in:
Justin Hawkins 2024-01-04 20:27:46 +10:30
commit dca9f3dd7c
4 changed files with 188 additions and 0 deletions

1
README.md Normal file
View File

@ -0,0 +1 @@
# caddy_prometheus_exporter

21
go.mod Normal file
View File

@ -0,0 +1,21 @@
module github.com/tardisx/caddy_prometheus_exporter
go 1.21.4
require (
github.com/nxadm/tail v1.4.11
github.com/prometheus/client_golang v1.18.0
)
require (
github.com/beorn7/perks v1.0.1 // indirect
github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/fsnotify/fsnotify v1.6.0 // indirect
github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 // indirect
github.com/prometheus/client_model v0.5.0 // indirect
github.com/prometheus/common v0.45.0 // indirect
github.com/prometheus/procfs v0.12.0 // indirect
golang.org/x/sys v0.15.0 // indirect
google.golang.org/protobuf v1.31.0 // indirect
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect
)

33
go.sum Normal file
View File

@ -0,0 +1,33 @@
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.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 h1:jWpvCLoY8Z/e3VKvlsiIGKtc+UG6U5vzxaoagmhXfyg=
github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0/go.mod h1:QUyp042oQthUoa9bqDv0ER0wrtXnBruoNd7aNjkbP+k=
github.com/nxadm/tail v1.4.11 h1:8feyoE3OzPrcshW5/MJ4sGESc5cqmGkGCWlco4l0bqY=
github.com/nxadm/tail v1.4.11/go.mod h1:OTaG3NK980DZzxbRq6lEuzgU+mug70nY11sMd4JXXHc=
github.com/prometheus/client_golang v1.18.0 h1:HzFfmkOzH5Q8L8G+kSJKUx5dtG87sewO+FoDDqP5Tbk=
github.com/prometheus/client_golang v1.18.0/go.mod h1:T+GXkCk5wSJyOqMIzVgvvjFDlkOQntgjkJWKrN5txjA=
github.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw=
github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI=
github.com/prometheus/common v0.45.0 h1:2BGz0eBc2hdMDLnO/8n0jeB3oPrt2D08CekT0lneoxM=
github.com/prometheus/common v0.45.0/go.mod h1:YJmSTw9BoKxJplESWWxlbyttQR4uaEcGyv9MZjVOJsY=
github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo=
github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo=
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc=
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8=
google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=

133
main.go Normal file
View File

@ -0,0 +1,133 @@
package main
import (
"encoding/json"
"fmt"
"io"
"log"
"log/slog"
"net/http"
"os"
"github.com/nxadm/tail"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promhttp"
)
type CaddyLogline struct {
Level string `json:"level"`
Ts float64 `json:"ts"`
Logger string `json:"logger"`
Msg string `json:"msg"`
Request struct {
RemoteIP string `json:"remote_ip"`
RemotePort string `json:"remote_port"`
ClientIP string `json:"client_ip"`
Proto string `json:"proto"`
Method string `json:"method"`
Host string `json:"host"`
URI string `json:"uri"`
Headers struct {
SecFetchSite []string `json:"Sec-Fetch-Site"`
Accept []string `json:"Accept"`
AcceptLanguage []string `json:"Accept-Language"`
Connection []string `json:"Connection"`
UpgradeInsecureRequests []string `json:"Upgrade-Insecure-Requests"`
SecFetchMode []string `json:"Sec-Fetch-Mode"`
UserAgent []string `json:"User-Agent"`
SecFetchDest []string `json:"Sec-Fetch-Dest"`
AcceptEncoding []string `json:"Accept-Encoding"`
} `json:"headers"`
} `json:"request"`
BytesRead int `json:"bytes_read"`
UserID string `json:"user_id"`
Duration float64 `json:"duration"`
Size int `json:"size"`
Status int `json:"status"`
RespHeaders struct {
Server []string `json:"Server"`
Etag []string `json:"Etag"`
ContentType []string `json:"Content-Type"`
LastModified []string `json:"Last-Modified"`
AcceptRanges []string `json:"Accept-Ranges"`
ContentLength []string `json:"Content-Length"`
} `json:"resp_headers"`
}
func main() {
requestsCounter := prometheus.NewCounterVec(prometheus.CounterOpts{
Namespace: "",
Subsystem: "",
Name: "requests",
Help: "",
ConstLabels: map[string]string{},
}, []string{"method", "status_code", "host"})
requestsDuration := prometheus.NewCounterVec(prometheus.CounterOpts{
Namespace: "",
Subsystem: "",
Name: "requests_duration",
Help: "",
ConstLabels: map[string]string{},
}, []string{"method", "status_code", "host"})
requestsSize := prometheus.NewCounterVec(prometheus.CounterOpts{
Namespace: "",
Subsystem: "",
Name: "requests_size",
Help: "",
ConstLabels: map[string]string{},
}, []string{"method", "status_code", "host"})
prometheus.MustRegister(requestsCounter, requestsDuration, requestsSize)
http.Handle("/metrics", promhttp.Handler())
go func() {
log.Fatal(http.ListenAndServe("127.0.0.1:8191", nil))
}()
i := len(os.Args)
if i < 2 {
panic("need names")
}
agg := make(chan *tail.Line)
for _, fn := range os.Args[1:] {
slog.With("file", fn).Info("opening")
t, err := tail.TailFile(fn, tail.Config{
Follow: true,
ReOpen: true,
CompleteLines: true,
Location: &tail.SeekInfo{
Offset: 0,
Whence: io.SeekEnd,
},
})
if err != nil {
panic(err)
}
go func(c chan *tail.Line) {
for msg := range c {
agg <- msg
}
}(t.Lines)
}
for line := range agg {
js := CaddyLogline{}
err := json.Unmarshal([]byte(line.Text), &js)
if err != nil {
slog.With(err).Error("could not unmarshal")
continue
}
if js.Msg != "handled request" {
continue
}
requestsCounter.WithLabelValues(js.Request.Method, fmt.Sprint(js.Status), js.Request.Host).Inc()
requestsDuration.WithLabelValues(js.Request.Method, fmt.Sprint(js.Status), js.Request.Host).Add(js.Duration)
requestsSize.WithLabelValues(js.Request.Method, fmt.Sprint(js.Status), js.Request.Host).Add(float64(js.Size))
}
}