github.com/minio/madmin-go@v1.7.5/profiling-commands.go (about)

     1  //
     2  // MinIO Object Storage (c) 2021 MinIO, Inc.
     3  //
     4  // Licensed under the Apache License, Version 2.0 (the "License");
     5  // you may not use this file except in compliance with the License.
     6  // You may obtain a copy of the License at
     7  //
     8  //      http://www.apache.org/licenses/LICENSE-2.0
     9  //
    10  // Unless required by applicable law or agreed to in writing, software
    11  // distributed under the License is distributed on an "AS IS" BASIS,
    12  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  // See the License for the specific language governing permissions and
    14  // limitations under the License.
    15  //
    16  
    17  package madmin
    18  
    19  import (
    20  	"context"
    21  	"encoding/json"
    22  	"errors"
    23  	"fmt"
    24  	"io"
    25  	"io/ioutil"
    26  	"net/http"
    27  	"net/url"
    28  	"time"
    29  )
    30  
    31  // ProfilerType represents the profiler type
    32  // passed to the profiler subsystem.
    33  type ProfilerType string
    34  
    35  // Different supported profiler types.
    36  const (
    37  	ProfilerCPU        ProfilerType = "cpu"        // represents CPU profiler type
    38  	ProfilerCPUIO      ProfilerType = "cpuio"      // represents CPU with IO (fgprof) profiler type
    39  	ProfilerMEM        ProfilerType = "mem"        // represents MEM profiler type
    40  	ProfilerBlock      ProfilerType = "block"      // represents Block profiler type
    41  	ProfilerMutex      ProfilerType = "mutex"      // represents Mutex profiler type
    42  	ProfilerTrace      ProfilerType = "trace"      // represents Trace profiler type
    43  	ProfilerThreads    ProfilerType = "threads"    // represents ThreadCreate profiler type
    44  	ProfilerGoroutines ProfilerType = "goroutines" // represents Goroutine dumps.
    45  )
    46  
    47  // StartProfilingResult holds the result of starting
    48  // profiler result in a given node.
    49  type StartProfilingResult struct {
    50  	NodeName string `json:"nodeName"`
    51  	Success  bool   `json:"success"`
    52  	Error    string `json:"error"`
    53  }
    54  
    55  // StartProfiling makes an admin call to remotely start profiling on a standalone
    56  // server or the whole cluster in case of a distributed setup.
    57  // Deprecated: use Profile API instead
    58  func (adm *AdminClient) StartProfiling(ctx context.Context, profiler ProfilerType) ([]StartProfilingResult, error) {
    59  	v := url.Values{}
    60  	v.Set("profilerType", string(profiler))
    61  	resp, err := adm.executeMethod(ctx,
    62  		http.MethodPost, requestData{
    63  			relPath:     adminAPIPrefix + "/profiling/start",
    64  			queryValues: v,
    65  		},
    66  	)
    67  	defer closeResponse(resp)
    68  	if err != nil {
    69  		return nil, err
    70  	}
    71  
    72  	if resp.StatusCode != http.StatusOK {
    73  		return nil, httpRespToErrorResponse(resp)
    74  	}
    75  
    76  	jsonResult, err := ioutil.ReadAll(resp.Body)
    77  	if err != nil {
    78  		return nil, err
    79  	}
    80  
    81  	var startResults []StartProfilingResult
    82  	err = json.Unmarshal(jsonResult, &startResults)
    83  	if err != nil {
    84  		return nil, err
    85  	}
    86  
    87  	return startResults, nil
    88  }
    89  
    90  // DownloadProfilingData makes an admin call to download profiling data of a standalone
    91  // server or of the whole cluster in case of a distributed setup.
    92  // Deprecated: use Profile API instead
    93  func (adm *AdminClient) DownloadProfilingData(ctx context.Context) (io.ReadCloser, error) {
    94  	path := fmt.Sprintf(adminAPIPrefix + "/profiling/download")
    95  	resp, err := adm.executeMethod(ctx,
    96  		http.MethodGet, requestData{
    97  			relPath: path,
    98  		},
    99  	)
   100  	if err != nil {
   101  		closeResponse(resp)
   102  		return nil, err
   103  	}
   104  
   105  	if resp.StatusCode != http.StatusOK {
   106  		return nil, httpRespToErrorResponse(resp)
   107  	}
   108  
   109  	if resp.Body == nil {
   110  		return nil, errors.New("body is nil")
   111  	}
   112  
   113  	return resp.Body, nil
   114  }
   115  
   116  // Profile makes an admin call to remotely start profiling on a standalone
   117  // server or the whole cluster in  case of a distributed setup for a specified duration.
   118  func (adm *AdminClient) Profile(ctx context.Context, profiler ProfilerType, duration time.Duration) (io.ReadCloser, error) {
   119  	v := url.Values{}
   120  	v.Set("profilerType", string(profiler))
   121  	v.Set("duration", duration.String())
   122  	resp, err := adm.executeMethod(ctx,
   123  		http.MethodPost, requestData{
   124  			relPath:     adminAPIPrefix + "/profile",
   125  			queryValues: v,
   126  		},
   127  	)
   128  	if err != nil {
   129  		closeResponse(resp)
   130  		return nil, err
   131  	}
   132  
   133  	if resp.StatusCode != http.StatusOK {
   134  		return nil, httpRespToErrorResponse(resp)
   135  	}
   136  
   137  	if resp.Body == nil {
   138  		return nil, errors.New("body is nil")
   139  	}
   140  	return resp.Body, nil
   141  }