mirror of https://github.com/minio/minio.git
Combine profiling start/stop APIs into one (#14662)
Take profile duration as a query parameter for profile API
This commit is contained in:
parent
48594617b5
commit
a1b01e6d5f
|
@ -27,6 +27,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"hash/crc32"
|
"hash/crc32"
|
||||||
"io"
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
@ -500,7 +501,7 @@ func (a adminAPIHandlers) TopLocksHandler(w http.ResponseWriter, r *http.Request
|
||||||
}
|
}
|
||||||
|
|
||||||
// StartProfilingResult contains the status of the starting
|
// StartProfilingResult contains the status of the starting
|
||||||
// profiling action in a given server
|
// profiling action in a given server - deprecated API
|
||||||
type StartProfilingResult struct {
|
type StartProfilingResult struct {
|
||||||
NodeName string `json:"nodeName"`
|
NodeName string `json:"nodeName"`
|
||||||
Success bool `json:"success"`
|
Success bool `json:"success"`
|
||||||
|
@ -594,6 +595,85 @@ func (a adminAPIHandlers) StartProfilingHandler(w http.ResponseWriter, r *http.R
|
||||||
writeSuccessResponseJSON(w, startProfilingResultInBytes)
|
writeSuccessResponseJSON(w, startProfilingResultInBytes)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ProfileHandler - POST /minio/admin/v3/profile/?profilerType={profilerType}
|
||||||
|
// ----------
|
||||||
|
// Enable server profiling
|
||||||
|
func (a adminAPIHandlers) ProfileHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
ctx := newContext(r, w, "Profile")
|
||||||
|
|
||||||
|
defer logger.AuditLog(ctx, w, r, mustGetClaimsFromToken(r))
|
||||||
|
|
||||||
|
// Validate request signature.
|
||||||
|
_, adminAPIErr := checkAdminRequestAuth(ctx, r, iampolicy.ProfilingAdminAction, "")
|
||||||
|
if adminAPIErr != ErrNone {
|
||||||
|
writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(adminAPIErr), r.URL)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if globalNotificationSys == nil {
|
||||||
|
writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrServerNotInitialized), r.URL)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
profileStr := r.Form.Get("profilerType")
|
||||||
|
profiles := strings.Split(profileStr, ",")
|
||||||
|
duration := time.Minute
|
||||||
|
if dstr := r.Form.Get("duration"); dstr != "" {
|
||||||
|
var err error
|
||||||
|
duration, err = time.ParseDuration(dstr)
|
||||||
|
if err != nil {
|
||||||
|
writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrServerNotInitialized), r.URL)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// read request body
|
||||||
|
io.CopyN(ioutil.Discard, r.Body, 1)
|
||||||
|
|
||||||
|
globalProfilerMu.Lock()
|
||||||
|
|
||||||
|
if globalProfiler == nil {
|
||||||
|
globalProfiler = make(map[string]minioProfiler, 10)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stop profiler of all types if already running
|
||||||
|
for k, v := range globalProfiler {
|
||||||
|
v.Stop()
|
||||||
|
delete(globalProfiler, k)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start profiling on remote servers.
|
||||||
|
for _, profiler := range profiles {
|
||||||
|
globalNotificationSys.StartProfiling(profiler)
|
||||||
|
|
||||||
|
// Start profiling locally as well.
|
||||||
|
prof, err := startProfiler(profiler)
|
||||||
|
if err == nil {
|
||||||
|
globalProfiler[profiler] = prof
|
||||||
|
}
|
||||||
|
}
|
||||||
|
globalProfilerMu.Unlock()
|
||||||
|
|
||||||
|
timer := time.NewTimer(duration)
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
if !timer.Stop() {
|
||||||
|
<-timer.C
|
||||||
|
}
|
||||||
|
for k, v := range globalProfiler {
|
||||||
|
v.Stop()
|
||||||
|
delete(globalProfiler, k)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
case <-timer.C:
|
||||||
|
if !globalNotificationSys.DownloadProfilingData(ctx, w) {
|
||||||
|
writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrAdminProfilerNotEnabled), r.URL)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// dummyFileInfo represents a dummy representation of a profile data file
|
// dummyFileInfo represents a dummy representation of a profile data file
|
||||||
// present only in memory, it helps to generate the zip stream.
|
// present only in memory, it helps to generate the zip stream.
|
||||||
type dummyFileInfo struct {
|
type dummyFileInfo struct {
|
||||||
|
@ -614,7 +694,7 @@ func (f dummyFileInfo) Sys() interface{} { return f.sys }
|
||||||
|
|
||||||
// DownloadProfilingHandler - POST /minio/admin/v3/profiling/download
|
// DownloadProfilingHandler - POST /minio/admin/v3/profiling/download
|
||||||
// ----------
|
// ----------
|
||||||
// Download profiling information of all nodes in a zip format
|
// Download profiling information of all nodes in a zip format - deprecated API
|
||||||
func (a adminAPIHandlers) DownloadProfilingHandler(w http.ResponseWriter, r *http.Request) {
|
func (a adminAPIHandlers) DownloadProfilingHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
ctx := newContext(r, w, "DownloadProfiling")
|
ctx := newContext(r, w, "DownloadProfiling")
|
||||||
|
|
||||||
|
|
|
@ -84,10 +84,12 @@ func registerAdminRouter(router *mux.Router, enableConfigOps bool) {
|
||||||
adminRouter.Methods(http.MethodPost).Path(adminVersion+"/pools/cancel").HandlerFunc(gz(httpTraceAll(adminAPI.CancelDecommission))).Queries("pool", "{pool:.*}")
|
adminRouter.Methods(http.MethodPost).Path(adminVersion+"/pools/cancel").HandlerFunc(gz(httpTraceAll(adminAPI.CancelDecommission))).Queries("pool", "{pool:.*}")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Profiling operations
|
// Profiling operations - deprecated API
|
||||||
adminRouter.Methods(http.MethodPost).Path(adminVersion+"/profiling/start").HandlerFunc(gz(httpTraceAll(adminAPI.StartProfilingHandler))).
|
adminRouter.Methods(http.MethodPost).Path(adminVersion+"/profiling/start").HandlerFunc(gz(httpTraceAll(adminAPI.StartProfilingHandler))).
|
||||||
Queries("profilerType", "{profilerType:.*}")
|
Queries("profilerType", "{profilerType:.*}")
|
||||||
adminRouter.Methods(http.MethodGet).Path(adminVersion + "/profiling/download").HandlerFunc(gz(httpTraceAll(adminAPI.DownloadProfilingHandler)))
|
adminRouter.Methods(http.MethodGet).Path(adminVersion + "/profiling/download").HandlerFunc(gz(httpTraceAll(adminAPI.DownloadProfilingHandler)))
|
||||||
|
// Profiling operations
|
||||||
|
adminRouter.Methods(http.MethodPost).Path(adminVersion + "/profile").HandlerFunc(gz(httpTraceAll(adminAPI.ProfileHandler)))
|
||||||
|
|
||||||
// Config KV operations.
|
// Config KV operations.
|
||||||
if enableConfigOps {
|
if enableConfigOps {
|
||||||
|
|
Loading…
Reference in New Issue