mirror of
https://github.com/minio/minio.git
synced 2025-04-15 16:39:16 -04:00
Add detailed parameter tracing + custom prefix (#18518)
* Allow per handler custom prefix. * Add automatic parameter extraction
This commit is contained in:
parent
11dc723324
commit
ca488cce87
@ -732,7 +732,7 @@ func (s *storageRESTServer) DeleteVersionsHandler(w http.ResponseWriter, r *http
|
|||||||
encoder.Encode(dErrsResp)
|
encoder.Encode(dErrsResp)
|
||||||
}
|
}
|
||||||
|
|
||||||
var storageRenameDataHandler = grid.NewSingleHandler[*RenameDataHandlerParams, *RenameDataResp](grid.HandlerRenamedata, func() *RenameDataHandlerParams {
|
var storageRenameDataHandler = grid.NewSingleHandler[*RenameDataHandlerParams, *RenameDataResp](grid.HandlerRenameData, func() *RenameDataHandlerParams {
|
||||||
return &RenameDataHandlerParams{}
|
return &RenameDataHandlerParams{}
|
||||||
}, func() *RenameDataResp {
|
}, func() *RenameDataResp {
|
||||||
return &RenameDataResp{}
|
return &RenameDataResp{}
|
||||||
|
@ -336,7 +336,7 @@ func (c *Connection) Request(ctx context.Context, h HandlerID, req []byte) ([]by
|
|||||||
}
|
}
|
||||||
c.outgoing.Delete(client.MuxID)
|
c.outgoing.Delete(client.MuxID)
|
||||||
}()
|
}()
|
||||||
return client.traceRoundtrip(c.trace, h, req)
|
return client.traceRoundtrip(ctx, c.trace, h, req)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Request allows to do a single remote request.
|
// Request allows to do a single remote request.
|
||||||
@ -364,7 +364,7 @@ func (c *Subroute) Request(ctx context.Context, h HandlerID, req []byte) ([]byte
|
|||||||
}
|
}
|
||||||
c.outgoing.Delete(client.MuxID)
|
c.outgoing.Delete(client.MuxID)
|
||||||
}()
|
}()
|
||||||
return client.traceRoundtrip(c.trace, h, req)
|
return client.traceRoundtrip(ctx, c.trace, h, req)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewStream creates a new stream.
|
// NewStream creates a new stream.
|
||||||
|
@ -55,7 +55,7 @@ const (
|
|||||||
HandlerUpdateMetadata
|
HandlerUpdateMetadata
|
||||||
HandlerWriteMetadata
|
HandlerWriteMetadata
|
||||||
HandlerCheckParts
|
HandlerCheckParts
|
||||||
HandlerRenamedata
|
HandlerRenameData
|
||||||
|
|
||||||
// Add more above here ^^^
|
// Add more above here ^^^
|
||||||
// If all handlers are used, the type of Handler can be changed.
|
// If all handlers are used, the type of Handler can be changed.
|
||||||
@ -65,6 +65,34 @@ const (
|
|||||||
handlerLast
|
handlerLast
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// handlerPrefixes are prefixes for handler IDs used for tracing.
|
||||||
|
// If a handler is not listed here, it will be traced with "grid" prefix.
|
||||||
|
var handlerPrefixes = [handlerLast]string{
|
||||||
|
HandlerLockLock: lockPrefix,
|
||||||
|
HandlerLockRLock: lockPrefix,
|
||||||
|
HandlerLockUnlock: lockPrefix,
|
||||||
|
HandlerLockRUnlock: lockPrefix,
|
||||||
|
HandlerLockRefresh: lockPrefix,
|
||||||
|
HandlerLockForceUnlock: lockPrefix,
|
||||||
|
HandlerWalkDir: storagePrefix,
|
||||||
|
HandlerStatVol: storagePrefix,
|
||||||
|
HandlerDiskInfo: storagePrefix,
|
||||||
|
HandlerNSScanner: storagePrefix,
|
||||||
|
HandlerReadXL: storagePrefix,
|
||||||
|
HandlerReadVersion: storagePrefix,
|
||||||
|
HandlerDeleteFile: storagePrefix,
|
||||||
|
HandlerDeleteVersion: storagePrefix,
|
||||||
|
HandlerUpdateMetadata: storagePrefix,
|
||||||
|
HandlerWriteMetadata: storagePrefix,
|
||||||
|
HandlerCheckParts: storagePrefix,
|
||||||
|
HandlerRenameData: storagePrefix,
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
lockPrefix = "lock"
|
||||||
|
storagePrefix = "storageR"
|
||||||
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
// Static check if we exceed 255 handler ids.
|
// Static check if we exceed 255 handler ids.
|
||||||
// Extend the type to uint16 when hit.
|
// Extend the type to uint16 when hit.
|
||||||
@ -364,6 +392,7 @@ func (h *SingleHandler[Req, Resp]) Call(ctx context.Context, c Requester, req Re
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return resp, err
|
return resp, err
|
||||||
}
|
}
|
||||||
|
ctx = context.WithValue(ctx, TraceParamsKey{}, req)
|
||||||
res, err := c.Request(ctx, h.id, payload)
|
res, err := c.Request(ctx, h.id, payload)
|
||||||
PutByteBuffer(payload)
|
PutByteBuffer(payload)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -26,13 +26,13 @@ func _() {
|
|||||||
_ = x[HandlerUpdateMetadata-15]
|
_ = x[HandlerUpdateMetadata-15]
|
||||||
_ = x[HandlerWriteMetadata-16]
|
_ = x[HandlerWriteMetadata-16]
|
||||||
_ = x[HandlerCheckParts-17]
|
_ = x[HandlerCheckParts-17]
|
||||||
_ = x[HandlerRenamedata-18]
|
_ = x[HandlerRenameData-18]
|
||||||
_ = x[handlerTest-19]
|
_ = x[handlerTest-19]
|
||||||
_ = x[handlerTest2-20]
|
_ = x[handlerTest2-20]
|
||||||
_ = x[handlerLast-21]
|
_ = x[handlerLast-21]
|
||||||
}
|
}
|
||||||
|
|
||||||
const _HandlerID_name = "handlerInvalidLockLockLockRLockLockUnlockLockRUnlockLockRefreshLockForceUnlockWalkDirStatVolDiskInfoNSScannerReadXLReadVersionDeleteFileDeleteVersionUpdateMetadataWriteMetadataCheckPartsRenamedatahandlerTesthandlerTest2handlerLast"
|
const _HandlerID_name = "handlerInvalidLockLockLockRLockLockUnlockLockRUnlockLockRefreshLockForceUnlockWalkDirStatVolDiskInfoNSScannerReadXLReadVersionDeleteFileDeleteVersionUpdateMetadataWriteMetadataCheckPartsRenameDatahandlerTesthandlerTest2handlerLast"
|
||||||
|
|
||||||
var _HandlerID_index = [...]uint8{0, 14, 22, 31, 41, 52, 63, 78, 85, 92, 100, 109, 115, 126, 136, 149, 163, 176, 186, 196, 207, 219, 230}
|
var _HandlerID_index = [...]uint8{0, 14, 22, 31, 41, 52, 63, 78, 85, 92, 100, 109, 115, 126, 136, 149, 163, 176, 186, 196, 207, 219, 230}
|
||||||
|
|
||||||
|
@ -18,19 +18,27 @@
|
|||||||
package grid
|
package grid
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"net/url"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/minio/madmin-go/v3"
|
"github.com/minio/madmin-go/v3"
|
||||||
"github.com/minio/minio/internal/pubsub"
|
"github.com/minio/minio/internal/pubsub"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// TraceParamsKey allows to pass trace parameters to the request via context.
|
||||||
|
// This is only needed when un-typed requests are used.
|
||||||
|
// MSS, map[string]string types are preferred, but any struct with exported fields will work.
|
||||||
|
type TraceParamsKey struct{}
|
||||||
|
|
||||||
// traceRequests adds request tracing to the connection.
|
// traceRequests adds request tracing to the connection.
|
||||||
func (c *Connection) traceRequests(p *pubsub.PubSub[madmin.TraceInfo, madmin.TraceType]) {
|
func (c *Connection) traceRequests(p *pubsub.PubSub[madmin.TraceInfo, madmin.TraceType]) {
|
||||||
c.trace = &tracer{
|
c.trace = &tracer{
|
||||||
Publisher: p,
|
Publisher: p,
|
||||||
TraceType: madmin.TraceInternal,
|
TraceType: madmin.TraceInternal,
|
||||||
Prefix: "grid.",
|
Prefix: "grid",
|
||||||
Local: c.Local,
|
Local: c.Local,
|
||||||
Remote: c.Remote,
|
Remote: c.Remote,
|
||||||
Subroute: "",
|
Subroute: "",
|
||||||
@ -56,7 +64,7 @@ type tracer struct {
|
|||||||
Subroute string
|
Subroute string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *muxClient) traceRoundtrip(t *tracer, h HandlerID, req []byte) ([]byte, error) {
|
func (c *muxClient) traceRoundtrip(ctx context.Context, t *tracer, h HandlerID, req []byte) ([]byte, error) {
|
||||||
if t == nil || t.Publisher.NumSubscribers(t.TraceType) == 0 {
|
if t == nil || t.Publisher.NumSubscribers(t.TraceType) == 0 {
|
||||||
return c.roundtrip(h, req)
|
return c.roundtrip(h, req)
|
||||||
}
|
}
|
||||||
@ -74,9 +82,14 @@ func (c *muxClient) traceRoundtrip(t *tracer, h HandlerID, req []byte) ([]byte,
|
|||||||
status = http.StatusBadRequest
|
status = http.StatusBadRequest
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
prefix := t.Prefix
|
||||||
|
if p := handlerPrefixes[h]; p != "" {
|
||||||
|
prefix = p
|
||||||
|
}
|
||||||
trace := madmin.TraceInfo{
|
trace := madmin.TraceInfo{
|
||||||
TraceType: t.TraceType,
|
TraceType: t.TraceType,
|
||||||
FuncName: t.Prefix + h.String(),
|
FuncName: prefix + "." + h.String(),
|
||||||
NodeName: t.Local,
|
NodeName: t.Local,
|
||||||
Time: start,
|
Time: start,
|
||||||
Duration: end.Sub(start),
|
Duration: end.Sub(start),
|
||||||
@ -105,6 +118,20 @@ func (c *muxClient) traceRoundtrip(t *tracer, h HandlerID, req []byte) ([]byte,
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
// If the context contains a TraceParamsKey, add it to the trace path.
|
||||||
|
v := ctx.Value(TraceParamsKey{})
|
||||||
|
if p, ok := v.(*MSS); ok && p != nil {
|
||||||
|
trace.Path += p.ToQuery()
|
||||||
|
trace.HTTP.ReqInfo.Path = trace.Path
|
||||||
|
} else if p, ok := v.(map[string]string); ok {
|
||||||
|
m := MSS(p)
|
||||||
|
trace.Path += m.ToQuery()
|
||||||
|
trace.HTTP.ReqInfo.Path = trace.Path
|
||||||
|
} else if v != nil {
|
||||||
|
// Print exported fields as single request to path.
|
||||||
|
trace.Path = fmt.Sprintf("%s?req=%s", trace.Path, url.QueryEscape(fmt.Sprintf("%+v", v)))
|
||||||
|
trace.HTTP.ReqInfo.Path = trace.Path
|
||||||
|
}
|
||||||
t.Publisher.Publish(trace)
|
t.Publisher.Publish(trace)
|
||||||
return resp, err
|
return resp, err
|
||||||
}
|
}
|
||||||
|
@ -19,6 +19,9 @@ package grid
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"net/url"
|
||||||
|
"sort"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/tinylib/msgp/msgp"
|
"github.com/tinylib/msgp/msgp"
|
||||||
)
|
)
|
||||||
@ -117,6 +120,31 @@ func NewMSSWith(m map[string]string) *MSS {
|
|||||||
return &m2
|
return &m2
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ToQuery constructs a URL query string from the MSS, including "?" if there are any keys.
|
||||||
|
func (m MSS) ToQuery() string {
|
||||||
|
if len(m) == 0 {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
var buf strings.Builder
|
||||||
|
buf.WriteByte('?')
|
||||||
|
keys := make([]string, 0, len(m))
|
||||||
|
for k := range m {
|
||||||
|
keys = append(keys, k)
|
||||||
|
}
|
||||||
|
sort.Strings(keys)
|
||||||
|
for _, k := range keys {
|
||||||
|
v := m[k]
|
||||||
|
keyEscaped := url.QueryEscape(k)
|
||||||
|
if buf.Len() > 1 {
|
||||||
|
buf.WriteByte('&')
|
||||||
|
}
|
||||||
|
buf.WriteString(keyEscaped)
|
||||||
|
buf.WriteByte('=')
|
||||||
|
buf.WriteString(url.QueryEscape(v))
|
||||||
|
}
|
||||||
|
return buf.String()
|
||||||
|
}
|
||||||
|
|
||||||
// NewBytes returns a new Bytes.
|
// NewBytes returns a new Bytes.
|
||||||
func NewBytes() *Bytes {
|
func NewBytes() *Bytes {
|
||||||
b := Bytes(GetByteBuffer()[:0])
|
b := Bytes(GetByteBuffer()[:0])
|
||||||
|
Loading…
x
Reference in New Issue
Block a user