Query Log: Add source IP from console queries (#6593)
* Query Log: Add source IP from console queries Signed-off-by: Julien Pivotto <roidelapluie@inuits.eu>
This commit is contained in:
parent
1e64d757f7
commit
e7f7b6a06f
|
@ -0,0 +1,50 @@
|
||||||
|
// Copyright 2020 The Prometheus Authors
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package httputil
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"net"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/prometheus/prometheus/promql"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ctxParam int
|
||||||
|
|
||||||
|
var pathParam ctxParam
|
||||||
|
|
||||||
|
// ContextWithPath returns a new context with the given path to be used later
|
||||||
|
// when logging the query.
|
||||||
|
func ContextWithPath(ctx context.Context, path string) context.Context {
|
||||||
|
return context.WithValue(ctx, pathParam, path)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ContextFromRequest returns a new context from a requests with identifiers of
|
||||||
|
// the request to be used later when logging the query.
|
||||||
|
func ContextFromRequest(ctx context.Context, r *http.Request) (context.Context, error) {
|
||||||
|
ip, _, err := net.SplitHostPort(r.RemoteAddr)
|
||||||
|
if err != nil {
|
||||||
|
return ctx, err
|
||||||
|
}
|
||||||
|
var path string
|
||||||
|
if v := ctx.Value(pathParam); v != nil {
|
||||||
|
path = v.(string)
|
||||||
|
}
|
||||||
|
return promql.NewOriginContext(ctx, map[string]string{
|
||||||
|
"clientIP": ip,
|
||||||
|
"method": r.Method,
|
||||||
|
"path": path,
|
||||||
|
}), nil
|
||||||
|
}
|
|
@ -18,7 +18,6 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"math"
|
"math"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"net"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
|
@ -342,7 +341,7 @@ func (api *API) query(r *http.Request) apiFuncResult {
|
||||||
return apiFuncResult{nil, &apiError{errorBadData, err}, nil, nil}
|
return apiFuncResult{nil, &apiError{errorBadData, err}, nil, nil}
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx, err = contextFromRequest(ctx, r)
|
ctx, err = httputil.ContextFromRequest(ctx, r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return apiFuncResult{nil, returnAPIError(err), nil, nil}
|
return apiFuncResult{nil, returnAPIError(err), nil, nil}
|
||||||
}
|
}
|
||||||
|
@ -417,7 +416,7 @@ func (api *API) queryRange(r *http.Request) apiFuncResult {
|
||||||
return apiFuncResult{nil, &apiError{errorBadData, err}, nil, nil}
|
return apiFuncResult{nil, &apiError{errorBadData, err}, nil, nil}
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx, err = contextFromRequest(ctx, r)
|
ctx, err = httputil.ContextFromRequest(ctx, r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return apiFuncResult{nil, returnAPIError(err), nil, nil}
|
return apiFuncResult{nil, returnAPIError(err), nil, nil}
|
||||||
}
|
}
|
||||||
|
@ -1480,11 +1479,3 @@ func marshalPointJSON(ptr unsafe.Pointer, stream *jsoniter.Stream) {
|
||||||
func marshalPointJSONIsEmpty(ptr unsafe.Pointer) bool {
|
func marshalPointJSONIsEmpty(ptr unsafe.Pointer) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func contextFromRequest(ctx context.Context, r *http.Request) (context.Context, error) {
|
|
||||||
ip, _, err := net.SplitHostPort(r.RemoteAddr)
|
|
||||||
if err != nil {
|
|
||||||
return ctx, err
|
|
||||||
}
|
|
||||||
return promql.NewOriginContext(ctx, map[string]string{"clientIP": ip}), nil
|
|
||||||
}
|
|
||||||
|
|
39
web/web.go
39
web/web.go
|
@ -253,7 +253,11 @@ func New(logger log.Logger, o *Options) *Handler {
|
||||||
}
|
}
|
||||||
|
|
||||||
m := newMetrics(o.Registerer)
|
m := newMetrics(o.Registerer)
|
||||||
router := route.New().WithInstrumentation(m.instrumentHandler)
|
router := route.New().
|
||||||
|
WithInstrumentation(combineInstrumentations(
|
||||||
|
m.instrumentHandler,
|
||||||
|
setPathWithPrefix(""),
|
||||||
|
))
|
||||||
|
|
||||||
cwd, err := os.Getwd()
|
cwd, err := os.Getwd()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -542,13 +546,17 @@ func (h *Handler) Run(ctx context.Context) error {
|
||||||
mux := http.NewServeMux()
|
mux := http.NewServeMux()
|
||||||
mux.Handle("/", h.router)
|
mux.Handle("/", h.router)
|
||||||
|
|
||||||
av1 := route.New().WithInstrumentation(h.metrics.instrumentHandlerWithPrefix("/api/v1"))
|
|
||||||
h.apiV1.Register(av1)
|
|
||||||
apiPath := "/api"
|
apiPath := "/api"
|
||||||
if h.options.RoutePrefix != "/" {
|
if h.options.RoutePrefix != "/" {
|
||||||
apiPath = h.options.RoutePrefix + apiPath
|
apiPath = h.options.RoutePrefix + apiPath
|
||||||
level.Info(h.logger).Log("msg", "router prefix", "prefix", h.options.RoutePrefix)
|
level.Info(h.logger).Log("msg", "router prefix", "prefix", h.options.RoutePrefix)
|
||||||
}
|
}
|
||||||
|
av1 := route.New().
|
||||||
|
WithInstrumentation(combineInstrumentations(
|
||||||
|
h.metrics.instrumentHandlerWithPrefix("/api/v1"),
|
||||||
|
setPathWithPrefix(apiPath+"/v1"),
|
||||||
|
))
|
||||||
|
h.apiV1.Register(av1)
|
||||||
|
|
||||||
mux.Handle(apiPath+"/v1/", http.StripPrefix(apiPath+"/v1", av1))
|
mux.Handle(apiPath+"/v1/", http.StripPrefix(apiPath+"/v1", av1))
|
||||||
|
|
||||||
|
@ -643,6 +651,12 @@ func (h *Handler) consoles(w http.ResponseWriter, r *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ctx, err = httputil.ContextFromRequest(ctx, r)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// Provide URL parameters as a map for easy use. Advanced users may have need for
|
// Provide URL parameters as a map for easy use. Advanced users may have need for
|
||||||
// parameters beyond the first, so provide RawParams.
|
// parameters beyond the first, so provide RawParams.
|
||||||
rawParams, err := url.ParseQuery(r.URL.RawQuery)
|
rawParams, err := url.ParseQuery(r.URL.RawQuery)
|
||||||
|
@ -685,7 +699,7 @@ func (h *Handler) consoles(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
|
|
||||||
tmpl := template.NewTemplateExpander(
|
tmpl := template.NewTemplateExpander(
|
||||||
h.context,
|
ctx,
|
||||||
strings.Join(append(defs, string(text)), ""),
|
strings.Join(append(defs, string(text)), ""),
|
||||||
"__console_"+name,
|
"__console_"+name,
|
||||||
data,
|
data,
|
||||||
|
@ -1103,3 +1117,20 @@ type AlertByStateCount struct {
|
||||||
Pending int32
|
Pending int32
|
||||||
Firing int32
|
Firing int32
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func combineInstrumentations(fs ...func(handlerName string, handler http.HandlerFunc) http.HandlerFunc) func(string, http.HandlerFunc) http.HandlerFunc {
|
||||||
|
return func(handlerName string, handler http.HandlerFunc) http.HandlerFunc {
|
||||||
|
for _, f := range fs {
|
||||||
|
handler = f(handlerName, handler)
|
||||||
|
}
|
||||||
|
return handler
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func setPathWithPrefix(prefix string) func(handlerName string, handler http.HandlerFunc) http.HandlerFunc {
|
||||||
|
return func(handlerName string, handler http.HandlerFunc) http.HandlerFunc {
|
||||||
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
handler(w, r.WithContext(httputil.ContextWithPath(r.Context(), prefix+r.URL.Path)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue