00f7e0772a
* debug: remove the CLI check for debug_enabled The API allows collecting profiles even debug_enabled=false as long as ACLs are enabled. Remove this check from the CLI so that users do not need to set debug_enabled=true for no reason. Also: - fix the API client to return errors on non-200 status codes for debug endpoints - improve the failure messages when pprof data can not be collected Co-Authored-By: Dhia Ayachi <dhia@hashicorp.com> * remove parallel test runs parallel runs create a race condition that fail the debug tests * Add changelog Co-authored-by: Daniel Nephin <dnephin@hashicorp.com>
123 lines
3.1 KiB
Go
123 lines
3.1 KiB
Go
package api
|
|
|
|
import (
|
|
"fmt"
|
|
"io/ioutil"
|
|
"strconv"
|
|
)
|
|
|
|
// Debug can be used to query the /debug/pprof endpoints to gather
|
|
// profiling information about the target agent.Debug
|
|
//
|
|
// The agent must have enable_debug set to true for profiling to be enabled
|
|
// and for these endpoints to function.
|
|
type Debug struct {
|
|
c *Client
|
|
}
|
|
|
|
// Debug returns a handle that exposes the internal debug endpoints.
|
|
func (c *Client) Debug() *Debug {
|
|
return &Debug{c}
|
|
}
|
|
|
|
// Heap returns a pprof heap dump
|
|
func (d *Debug) Heap() ([]byte, error) {
|
|
r := d.c.newRequest("GET", "/debug/pprof/heap")
|
|
_, resp, err := d.c.doRequest(r)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("error making request: %s", err)
|
|
}
|
|
defer resp.Body.Close()
|
|
|
|
if resp.StatusCode != 200 {
|
|
return nil, generateUnexpectedResponseCodeError(resp)
|
|
}
|
|
|
|
// We return a raw response because we're just passing through a response
|
|
// from the pprof handlers
|
|
body, err := ioutil.ReadAll(resp.Body)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("error decoding body: %s", err)
|
|
}
|
|
|
|
return body, nil
|
|
}
|
|
|
|
// Profile returns a pprof CPU profile for the specified number of seconds
|
|
func (d *Debug) Profile(seconds int) ([]byte, error) {
|
|
r := d.c.newRequest("GET", "/debug/pprof/profile")
|
|
|
|
// Capture a profile for the specified number of seconds
|
|
r.params.Set("seconds", strconv.Itoa(seconds))
|
|
|
|
_, resp, err := d.c.doRequest(r)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("error making request: %s", err)
|
|
}
|
|
defer resp.Body.Close()
|
|
|
|
if resp.StatusCode != 200 {
|
|
return nil, generateUnexpectedResponseCodeError(resp)
|
|
}
|
|
|
|
// We return a raw response because we're just passing through a response
|
|
// from the pprof handlers
|
|
body, err := ioutil.ReadAll(resp.Body)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("error decoding body: %s", err)
|
|
}
|
|
|
|
return body, nil
|
|
}
|
|
|
|
// Trace returns an execution trace
|
|
func (d *Debug) Trace(seconds int) ([]byte, error) {
|
|
r := d.c.newRequest("GET", "/debug/pprof/trace")
|
|
|
|
// Capture a trace for the specified number of seconds
|
|
r.params.Set("seconds", strconv.Itoa(seconds))
|
|
|
|
_, resp, err := d.c.doRequest(r)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("error making request: %s", err)
|
|
}
|
|
defer resp.Body.Close()
|
|
|
|
if resp.StatusCode != 200 {
|
|
return nil, generateUnexpectedResponseCodeError(resp)
|
|
}
|
|
|
|
// We return a raw response because we're just passing through a response
|
|
// from the pprof handlers
|
|
body, err := ioutil.ReadAll(resp.Body)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("error decoding body: %s", err)
|
|
}
|
|
|
|
return body, nil
|
|
}
|
|
|
|
// Goroutine returns a pprof goroutine profile
|
|
func (d *Debug) Goroutine() ([]byte, error) {
|
|
r := d.c.newRequest("GET", "/debug/pprof/goroutine")
|
|
|
|
_, resp, err := d.c.doRequest(r)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("error making request: %s", err)
|
|
}
|
|
defer resp.Body.Close()
|
|
|
|
if resp.StatusCode != 200 {
|
|
return nil, generateUnexpectedResponseCodeError(resp)
|
|
}
|
|
|
|
// We return a raw response because we're just passing through a response
|
|
// from the pprof handlers
|
|
body, err := ioutil.ReadAll(resp.Body)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("error decoding body: %s", err)
|
|
}
|
|
|
|
return body, nil
|
|
}
|