mirror of
https://git.mirrors.martin98.com/https://github.com/SigNoz/signoz
synced 2025-06-04 11:25:52 +08:00
156 lines
4.4 KiB
Go
156 lines
4.4 KiB
Go
package middleware
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"net"
|
|
"net/http"
|
|
"net/url"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/SigNoz/signoz/pkg/query-service/common"
|
|
"github.com/SigNoz/signoz/pkg/types/authtypes"
|
|
"github.com/gorilla/mux"
|
|
semconv "go.opentelemetry.io/otel/semconv/v1.26.0"
|
|
"go.uber.org/zap"
|
|
)
|
|
|
|
const (
|
|
logMessage string = "::RECEIVED-REQUEST::"
|
|
)
|
|
|
|
type Logging struct {
|
|
logger *zap.Logger
|
|
excludedRoutes map[string]struct{}
|
|
}
|
|
|
|
func NewLogging(logger *zap.Logger, excludedRoutes []string) *Logging {
|
|
if logger == nil {
|
|
panic("cannot build logging, logger is empty")
|
|
}
|
|
|
|
excludedRoutesMap := make(map[string]struct{})
|
|
for _, route := range excludedRoutes {
|
|
excludedRoutesMap[route] = struct{}{}
|
|
}
|
|
|
|
return &Logging{
|
|
logger: logger.Named(pkgname),
|
|
excludedRoutes: excludedRoutesMap,
|
|
}
|
|
}
|
|
|
|
func (middleware *Logging) Wrap(next http.Handler) http.Handler {
|
|
return http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
|
|
start := time.Now()
|
|
host, port, _ := net.SplitHostPort(req.Host)
|
|
path, err := mux.CurrentRoute(req).GetPathTemplate()
|
|
if err != nil {
|
|
path = req.URL.Path
|
|
}
|
|
|
|
fields := []zap.Field{
|
|
zap.String(string(semconv.ClientAddressKey), req.RemoteAddr),
|
|
zap.String(string(semconv.UserAgentOriginalKey), req.UserAgent()),
|
|
zap.String(string(semconv.ServerAddressKey), host),
|
|
zap.String(string(semconv.ServerPortKey), port),
|
|
zap.Int64(string(semconv.HTTPRequestSizeKey), req.ContentLength),
|
|
zap.String(string(semconv.HTTPRouteKey), path),
|
|
}
|
|
|
|
logCommentKVs := middleware.getLogCommentKVs(req)
|
|
req = req.WithContext(context.WithValue(req.Context(), common.LogCommentKey, logCommentKVs))
|
|
|
|
badResponseBuffer := new(bytes.Buffer)
|
|
writer := newBadResponseLoggingWriter(rw, badResponseBuffer)
|
|
next.ServeHTTP(writer, req)
|
|
|
|
// if the path is in the excludedRoutes map, don't log
|
|
if _, ok := middleware.excludedRoutes[path]; ok {
|
|
return
|
|
}
|
|
|
|
statusCode, err := writer.StatusCode(), writer.WriteError()
|
|
fields = append(fields,
|
|
zap.Int(string(semconv.HTTPResponseStatusCodeKey), statusCode),
|
|
zap.Duration(string(semconv.HTTPServerRequestDurationName), time.Since(start)),
|
|
)
|
|
if err != nil {
|
|
fields = append(fields, zap.Error(err))
|
|
middleware.logger.Error(logMessage, fields...)
|
|
} else {
|
|
// when the status code is 400 or >=500, and the response body is not empty.
|
|
if badResponseBuffer.Len() != 0 {
|
|
fields = append(fields, zap.String("response.body", badResponseBuffer.String()))
|
|
}
|
|
|
|
middleware.logger.Info(logMessage, fields...)
|
|
}
|
|
})
|
|
}
|
|
|
|
func (middleware *Logging) getLogCommentKVs(r *http.Request) map[string]string {
|
|
referrer := r.Header.Get("Referer")
|
|
|
|
var path, dashboardID, alertID, page, client, viewName, tab string
|
|
|
|
if referrer != "" {
|
|
referrerURL, _ := url.Parse(referrer)
|
|
client = "browser"
|
|
path = referrerURL.Path
|
|
|
|
if strings.Contains(path, "/dashboard") {
|
|
// Split the path into segments
|
|
pathSegments := strings.Split(referrerURL.Path, "/")
|
|
// The dashboard ID should be the segment after "/dashboard/"
|
|
// Loop through pathSegments to find "dashboard" and then take the next segment as the ID
|
|
for i, segment := range pathSegments {
|
|
if segment == "dashboard" && i < len(pathSegments)-1 {
|
|
// Return the next segment, which should be the dashboard ID
|
|
dashboardID = pathSegments[i+1]
|
|
}
|
|
}
|
|
page = "dashboards"
|
|
} else if strings.Contains(path, "/alerts") {
|
|
urlParams := referrerURL.Query()
|
|
alertID = urlParams.Get("ruleId")
|
|
page = "alerts"
|
|
} else if strings.Contains(path, "logs") && strings.Contains(path, "explorer") {
|
|
page = "logs-explorer"
|
|
viewName = referrerURL.Query().Get("viewName")
|
|
} else if strings.Contains(path, "/trace") || strings.Contains(path, "traces-explorer") {
|
|
page = "traces-explorer"
|
|
viewName = referrerURL.Query().Get("viewName")
|
|
} else if strings.Contains(path, "/services") {
|
|
page = "services"
|
|
tab = referrerURL.Query().Get("tab")
|
|
if tab == "" {
|
|
tab = "OVER_METRICS"
|
|
}
|
|
} else if strings.Contains(path, "/metrics") {
|
|
page = "metrics-explorer"
|
|
}
|
|
} else {
|
|
client = "api"
|
|
}
|
|
|
|
var email string
|
|
claims, err := authtypes.ClaimsFromContext(r.Context())
|
|
if err == nil {
|
|
email = claims.Email
|
|
}
|
|
|
|
kvs := map[string]string{
|
|
"path": path,
|
|
"dashboardID": dashboardID,
|
|
"alertID": alertID,
|
|
"source": page,
|
|
"client": client,
|
|
"viewName": viewName,
|
|
"servicesTab": tab,
|
|
"email": email,
|
|
}
|
|
return kvs
|
|
}
|