mirror of
https://github.com/yusing/godoxy.git
synced 2025-07-24 04:54:03 +02:00
refactor: move metrics logger to middleware package
This commit is contained in:
parent
503671bd1b
commit
1e413ae215
4 changed files with 100 additions and 62 deletions
|
@ -0,0 +1,44 @@
|
||||||
|
package metricslogger
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/yusing/go-proxy/internal/metrics"
|
||||||
|
)
|
||||||
|
|
||||||
|
type MetricsLogger struct {
|
||||||
|
ServiceName string `json:"service_name"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewMetricsLogger(serviceName string) *MetricsLogger {
|
||||||
|
return &MetricsLogger{serviceName}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MetricsLogger) GetHandler(next http.Handler) http.HandlerFunc {
|
||||||
|
return func(rw http.ResponseWriter, req *http.Request) {
|
||||||
|
m.ServeHTTP(rw, req, next.ServeHTTP)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MetricsLogger) ServeHTTP(rw http.ResponseWriter, req *http.Request, next http.HandlerFunc) {
|
||||||
|
visitorIP, _, err := net.SplitHostPort(req.RemoteAddr)
|
||||||
|
if err != nil {
|
||||||
|
visitorIP = req.RemoteAddr
|
||||||
|
}
|
||||||
|
|
||||||
|
// req.RemoteAddr had been modified by middleware (if any)
|
||||||
|
lbls := &metrics.HTTPRouteMetricLabels{
|
||||||
|
Service: m.ServiceName,
|
||||||
|
Method: req.Method,
|
||||||
|
Host: req.Host,
|
||||||
|
Visitor: visitorIP,
|
||||||
|
Path: req.URL.Path,
|
||||||
|
}
|
||||||
|
|
||||||
|
next.ServeHTTP(newHTTPMetricLogger(rw, lbls), req)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MetricsLogger) ResetMetrics() {
|
||||||
|
metrics.GetRouteMetrics().UnregisterService(m.ServiceName)
|
||||||
|
}
|
|
@ -0,0 +1,47 @@
|
||||||
|
package metricslogger
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/yusing/go-proxy/internal/metrics"
|
||||||
|
)
|
||||||
|
|
||||||
|
type httpMetricLogger struct {
|
||||||
|
http.ResponseWriter
|
||||||
|
timestamp time.Time
|
||||||
|
labels *metrics.HTTPRouteMetricLabels
|
||||||
|
}
|
||||||
|
|
||||||
|
// WriteHeader implements http.ResponseWriter.
|
||||||
|
func (l *httpMetricLogger) WriteHeader(status int) {
|
||||||
|
l.ResponseWriter.WriteHeader(status)
|
||||||
|
duration := time.Since(l.timestamp)
|
||||||
|
go func() {
|
||||||
|
m := metrics.GetRouteMetrics()
|
||||||
|
m.HTTPReqTotal.Inc()
|
||||||
|
m.HTTPReqElapsed.With(l.labels).Set(float64(duration.Milliseconds()))
|
||||||
|
|
||||||
|
// ignore 1xx
|
||||||
|
switch {
|
||||||
|
case status >= 500:
|
||||||
|
m.HTTP5xx.With(l.labels).Inc()
|
||||||
|
case status >= 400:
|
||||||
|
m.HTTP4xx.With(l.labels).Inc()
|
||||||
|
case status >= 200:
|
||||||
|
m.HTTP2xx3xx.With(l.labels).Inc()
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *httpMetricLogger) Unwrap() http.ResponseWriter {
|
||||||
|
return l.ResponseWriter
|
||||||
|
}
|
||||||
|
|
||||||
|
func newHTTPMetricLogger(w http.ResponseWriter, labels *metrics.HTTPRouteMetricLabels) *httpMetricLogger {
|
||||||
|
return &httpMetricLogger{
|
||||||
|
ResponseWriter: w,
|
||||||
|
timestamp: time.Now(),
|
||||||
|
labels: labels,
|
||||||
|
}
|
||||||
|
}
|
|
@ -23,12 +23,9 @@ import (
|
||||||
"net/url"
|
"net/url"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/rs/zerolog"
|
"github.com/rs/zerolog"
|
||||||
"github.com/yusing/go-proxy/internal/common"
|
|
||||||
"github.com/yusing/go-proxy/internal/logging"
|
"github.com/yusing/go-proxy/internal/logging"
|
||||||
"github.com/yusing/go-proxy/internal/metrics"
|
|
||||||
gphttp "github.com/yusing/go-proxy/internal/net/http"
|
gphttp "github.com/yusing/go-proxy/internal/net/http"
|
||||||
"github.com/yusing/go-proxy/internal/net/http/accesslog"
|
"github.com/yusing/go-proxy/internal/net/http/accesslog"
|
||||||
"github.com/yusing/go-proxy/internal/net/types"
|
"github.com/yusing/go-proxy/internal/net/types"
|
||||||
|
@ -99,37 +96,6 @@ type ReverseProxy struct {
|
||||||
TargetURL *types.URL
|
TargetURL *types.URL
|
||||||
}
|
}
|
||||||
|
|
||||||
type httpMetricLogger struct {
|
|
||||||
http.ResponseWriter
|
|
||||||
timestamp time.Time
|
|
||||||
labels *metrics.HTTPRouteMetricLabels
|
|
||||||
}
|
|
||||||
|
|
||||||
// WriteHeader implements http.ResponseWriter.
|
|
||||||
func (l *httpMetricLogger) WriteHeader(status int) {
|
|
||||||
l.ResponseWriter.WriteHeader(status)
|
|
||||||
duration := time.Since(l.timestamp)
|
|
||||||
go func() {
|
|
||||||
m := metrics.GetRouteMetrics()
|
|
||||||
m.HTTPReqTotal.Inc()
|
|
||||||
m.HTTPReqElapsed.With(l.labels).Set(float64(duration.Milliseconds()))
|
|
||||||
|
|
||||||
// ignore 1xx
|
|
||||||
switch {
|
|
||||||
case status >= 500:
|
|
||||||
m.HTTP5xx.With(l.labels).Inc()
|
|
||||||
case status >= 400:
|
|
||||||
m.HTTP4xx.With(l.labels).Inc()
|
|
||||||
case status >= 200:
|
|
||||||
m.HTTP2xx3xx.With(l.labels).Inc()
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *httpMetricLogger) Unwrap() http.ResponseWriter {
|
|
||||||
return l.ResponseWriter
|
|
||||||
}
|
|
||||||
|
|
||||||
func singleJoiningSlash(a, b string) string {
|
func singleJoiningSlash(a, b string) string {
|
||||||
aslash := strings.HasSuffix(a, "/")
|
aslash := strings.HasSuffix(a, "/")
|
||||||
bslash := strings.HasPrefix(b, "/")
|
bslash := strings.HasPrefix(b, "/")
|
||||||
|
@ -181,10 +147,6 @@ func NewReverseProxy(name string, target *types.URL, transport http.RoundTripper
|
||||||
return rp
|
return rp
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *ReverseProxy) UnregisterMetrics() {
|
|
||||||
metrics.GetRouteMetrics().UnregisterService(p.TargetName)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *ReverseProxy) rewriteRequestURL(req *http.Request) {
|
func (p *ReverseProxy) rewriteRequestURL(req *http.Request) {
|
||||||
targetQuery := p.TargetURL.RawQuery
|
targetQuery := p.TargetURL.RawQuery
|
||||||
req.URL.Scheme = p.TargetURL.Scheme
|
req.URL.Scheme = p.TargetURL.Scheme
|
||||||
|
@ -255,28 +217,6 @@ func (p *ReverseProxy) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *ReverseProxy) handler(rw http.ResponseWriter, req *http.Request) {
|
func (p *ReverseProxy) handler(rw http.ResponseWriter, req *http.Request) {
|
||||||
visitorIP, _, err := net.SplitHostPort(req.RemoteAddr)
|
|
||||||
if err != nil {
|
|
||||||
visitorIP = req.RemoteAddr
|
|
||||||
}
|
|
||||||
|
|
||||||
if common.PrometheusEnabled {
|
|
||||||
t := time.Now()
|
|
||||||
// req.RemoteAddr had been modified by middleware (if any)
|
|
||||||
lbls := &metrics.HTTPRouteMetricLabels{
|
|
||||||
Service: p.TargetName,
|
|
||||||
Method: req.Method,
|
|
||||||
Host: req.Host,
|
|
||||||
Visitor: visitorIP,
|
|
||||||
Path: req.URL.Path,
|
|
||||||
}
|
|
||||||
rw = &httpMetricLogger{
|
|
||||||
ResponseWriter: rw,
|
|
||||||
timestamp: t,
|
|
||||||
labels: lbls,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
transport := p.Transport
|
transport := p.Transport
|
||||||
|
|
||||||
ctx := req.Context()
|
ctx := req.Context()
|
||||||
|
@ -360,7 +300,11 @@ func (p *ReverseProxy) handler(rw http.ResponseWriter, req *http.Request) {
|
||||||
// separated list and fold multiple headers into one.
|
// separated list and fold multiple headers into one.
|
||||||
prior, ok := outreq.Header[gphttp.HeaderXForwardedFor]
|
prior, ok := outreq.Header[gphttp.HeaderXForwardedFor]
|
||||||
omit := ok && prior == nil // Issue 38079: nil now means don't populate the header
|
omit := ok && prior == nil // Issue 38079: nil now means don't populate the header
|
||||||
xff := visitorIP
|
|
||||||
|
xff, _, err := net.SplitHostPort(req.RemoteAddr)
|
||||||
|
if err != nil {
|
||||||
|
xff = req.RemoteAddr
|
||||||
|
}
|
||||||
if len(prior) > 0 {
|
if len(prior) > 0 {
|
||||||
xff = strings.Join(prior, ", ") + ", " + xff
|
xff = strings.Join(prior, ", ") + ", " + xff
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,6 +15,7 @@ import (
|
||||||
"github.com/yusing/go-proxy/internal/net/http/loadbalancer"
|
"github.com/yusing/go-proxy/internal/net/http/loadbalancer"
|
||||||
loadbalance "github.com/yusing/go-proxy/internal/net/http/loadbalancer/types"
|
loadbalance "github.com/yusing/go-proxy/internal/net/http/loadbalancer/types"
|
||||||
"github.com/yusing/go-proxy/internal/net/http/middleware"
|
"github.com/yusing/go-proxy/internal/net/http/middleware"
|
||||||
|
metricslogger "github.com/yusing/go-proxy/internal/net/http/middleware/metrics_logger"
|
||||||
"github.com/yusing/go-proxy/internal/net/http/reverseproxy"
|
"github.com/yusing/go-proxy/internal/net/http/reverseproxy"
|
||||||
"github.com/yusing/go-proxy/internal/route/routes"
|
"github.com/yusing/go-proxy/internal/route/routes"
|
||||||
"github.com/yusing/go-proxy/internal/task"
|
"github.com/yusing/go-proxy/internal/task"
|
||||||
|
@ -158,7 +159,9 @@ func (r *ReveseProxyRoute) Start(parent task.Parent) E.Error {
|
||||||
}
|
}
|
||||||
|
|
||||||
if common.PrometheusEnabled {
|
if common.PrometheusEnabled {
|
||||||
r.task.OnCancel("metrics_cleanup", r.rp.UnregisterMetrics)
|
metricsLogger := metricslogger.NewMetricsLogger(r.TargetName())
|
||||||
|
r.handler = metricsLogger.GetHandler(r.handler)
|
||||||
|
r.task.OnCancel("reset_metrics", metricsLogger.ResetMetrics)
|
||||||
}
|
}
|
||||||
|
|
||||||
r.task.OnCancel("reset_favicon", func() { favicon.PruneRouteIconCache(r) })
|
r.task.OnCancel("reset_favicon", func() { favicon.PruneRouteIconCache(r) })
|
||||||
|
|
Loading…
Add table
Reference in a new issue