github.com/minio/madmin-go/v3@v3.0.51/profiling-commands.go (about) 1 // 2 // Copyright (c) 2015-2022 MinIO, Inc. 3 // 4 // This file is part of MinIO Object Storage stack 5 // 6 // This program is free software: you can redistribute it and/or modify 7 // it under the terms of the GNU Affero General Public License as 8 // published by the Free Software Foundation, either version 3 of the 9 // License, or (at your option) any later version. 10 // 11 // This program is distributed in the hope that it will be useful, 12 // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 // GNU Affero General Public License for more details. 15 // 16 // You should have received a copy of the GNU Affero General Public License 17 // along with this program. If not, see <http://www.gnu.org/licenses/>. 18 // 19 20 package madmin 21 22 import ( 23 "context" 24 "encoding/json" 25 "errors" 26 "fmt" 27 "io" 28 "net/http" 29 "net/url" 30 "time" 31 ) 32 33 // ProfilerType represents the profiler type 34 // passed to the profiler subsystem. 35 type ProfilerType string 36 37 // Different supported profiler types. 38 const ( 39 ProfilerCPU ProfilerType = "cpu" // represents CPU profiler type 40 ProfilerCPUIO ProfilerType = "cpuio" // represents CPU with IO (fgprof) profiler type 41 ProfilerMEM ProfilerType = "mem" // represents MEM profiler type 42 ProfilerBlock ProfilerType = "block" // represents Block profiler type 43 ProfilerMutex ProfilerType = "mutex" // represents Mutex profiler type 44 ProfilerTrace ProfilerType = "trace" // represents Trace profiler type 45 ProfilerThreads ProfilerType = "threads" // represents ThreadCreate profiler type 46 ProfilerGoroutines ProfilerType = "goroutines" // represents Goroutine dumps. 47 ) 48 49 // StartProfilingResult holds the result of starting 50 // profiler result in a given node. 51 type StartProfilingResult struct { 52 NodeName string `json:"nodeName"` 53 Success bool `json:"success"` 54 Error string `json:"error"` 55 } 56 57 // StartProfiling makes an admin call to remotely start profiling on a standalone 58 // server or the whole cluster in case of a distributed setup. 59 // Deprecated: use Profile API instead 60 func (adm *AdminClient) StartProfiling(ctx context.Context, profiler ProfilerType) ([]StartProfilingResult, error) { 61 v := url.Values{} 62 v.Set("profilerType", string(profiler)) 63 resp, err := adm.executeMethod(ctx, 64 http.MethodPost, requestData{ 65 relPath: adminAPIPrefix + "/profiling/start", 66 queryValues: v, 67 }, 68 ) 69 defer closeResponse(resp) 70 if err != nil { 71 return nil, err 72 } 73 74 if resp.StatusCode != http.StatusOK { 75 return nil, httpRespToErrorResponse(resp) 76 } 77 78 jsonResult, err := io.ReadAll(resp.Body) 79 if err != nil { 80 return nil, err 81 } 82 83 var startResults []StartProfilingResult 84 err = json.Unmarshal(jsonResult, &startResults) 85 if err != nil { 86 return nil, err 87 } 88 89 return startResults, nil 90 } 91 92 // DownloadProfilingData makes an admin call to download profiling data of a standalone 93 // server or of the whole cluster in case of a distributed setup. 94 // Deprecated: use Profile API instead 95 func (adm *AdminClient) DownloadProfilingData(ctx context.Context) (io.ReadCloser, error) { 96 path := fmt.Sprintf(adminAPIPrefix + "/profiling/download") 97 resp, err := adm.executeMethod(ctx, 98 http.MethodGet, requestData{ 99 relPath: path, 100 }, 101 ) 102 if err != nil { 103 closeResponse(resp) 104 return nil, err 105 } 106 107 if resp.StatusCode != http.StatusOK { 108 return nil, httpRespToErrorResponse(resp) 109 } 110 111 if resp.Body == nil { 112 return nil, errors.New("body is nil") 113 } 114 115 return resp.Body, nil 116 } 117 118 // Profile makes an admin call to remotely start profiling on a standalone 119 // server or the whole cluster in case of a distributed setup for a specified duration. 120 func (adm *AdminClient) Profile(ctx context.Context, profiler ProfilerType, duration time.Duration) (io.ReadCloser, error) { 121 v := url.Values{} 122 v.Set("profilerType", string(profiler)) 123 v.Set("duration", duration.String()) 124 resp, err := adm.executeMethod(ctx, 125 http.MethodPost, requestData{ 126 relPath: adminAPIPrefix + "/profile", 127 queryValues: v, 128 }, 129 ) 130 if err != nil { 131 closeResponse(resp) 132 return nil, err 133 } 134 135 if resp.StatusCode != http.StatusOK { 136 return nil, httpRespToErrorResponse(resp) 137 } 138 139 if resp.Body == nil { 140 return nil, errors.New("body is nil") 141 } 142 return resp.Body, nil 143 }