-
Notifications
You must be signed in to change notification settings - Fork 4
/
main.go
113 lines (101 loc) · 2.86 KB
/
main.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
package main
import (
"flag"
"fmt"
"log"
"net/http"
"net/http/httputil"
"strconv"
"strings"
"github.com/lox/httpcache"
"github.com/lox/httpcache/httplog"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promhttp"
)
const (
defaultListen = ":9091"
defaultDir = "/tmp/cachedata"
)
var (
listen string
useDisk bool
dir string
dumpHttp bool
verbose bool
upstream string
duration int
)
func main() {
flag.StringVar(&listen, "listen", defaultListen, "the host and port to bind to")
flag.StringVar(&dir, "dir", defaultDir, "the dir to store cache data in, implies -disk")
flag.BoolVar(&useDisk, "disk", false, "whether to store cache data to disk")
flag.BoolVar(&verbose, "v", false, "show verbose output and debugging")
flag.BoolVar(&dumpHttp, "dumphttp", false, "dumps http requests and responses to stdout")
flag.StringVar(&upstream, "upstream", "127.0.0.1:9090", "upstream host to connect to")
flag.IntVar(&duration, "duration", 60, "forced cache duration")
flag.Parse()
if verbose {
httpcache.DebugLogging = true
}
req := prometheus.NewCounterVec(
prometheus.CounterOpts{
Name: "promcache_http_requests_total",
Help: "Number of HTTP requests to the caching proxy",
},
[]string{"cache"},
)
prometheus.MustRegister(req)
go func() {
mux := http.NewServeMux()
mux.Handle("/metrics", promhttp.Handler())
http.ListenAndServe(":9092", mux)
}()
proxy := &httputil.ReverseProxy{
Director: func(r *http.Request) {
r.URL.Scheme = "http"
r.URL.Host = upstream
r.Host = r.URL.Host
if verbose {
fmt.Printf("UPSTREAM-REQUEST TO: %s\n", r.URL.String())
}
req.WithLabelValues("miss").Inc()
},
ModifyResponse: func(r *http.Response) error {
r.Header.Add("Cache-Control", fmt.Sprintf("max-age=%d, public", duration))
return nil
},
}
handler := httpcache.NewHandler(httpcache.NewMemoryCache(), proxy)
handler.Shared = true
respLogger := httplog.NewResponseLogger(handler)
respLogger.DumpRequests = dumpHttp
respLogger.DumpResponses = dumpHttp
respLogger.DumpErrors = dumpHttp
log.Printf("proxy listening on http://%s", listen)
log.Fatal(http.ListenAndServe(listen, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if !strings.HasPrefix(r.URL.Path, "/api/v1/query") {
respLogger.ServeHTTP(w, r)
return
}
req.WithLabelValues("request").Inc()
r.Header.Del("Pragma")
r.Header.Del("Cache-Control")
val := r.URL.Query()
start, err := strconv.Atoi(val.Get("start"))
if err != nil {
fmt.Println(err)
} else {
nStart := strconv.Itoa(start - (start % duration))
val.Set("start", nStart)
}
end, err := strconv.Atoi(val.Get("end"))
if err != nil {
fmt.Println(err)
} else {
nEnd := strconv.Itoa(end - (end % duration) + duration)
val.Set("end", nEnd)
}
r.URL.RawQuery = val.Encode()
respLogger.ServeHTTP(w, r)
})))
}