2018-10-17 20:20:35 +00:00
|
|
|
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)
|
|
|
|
}
|
2021-06-15 15:50:29 +00:00
|
|
|
defer closeResponseBody(resp)
|
2018-10-17 20:20:35 +00:00
|
|
|
|
2021-05-27 13:41:53 +00:00
|
|
|
if resp.StatusCode != 200 {
|
|
|
|
return nil, generateUnexpectedResponseCodeError(resp)
|
|
|
|
}
|
|
|
|
|
2018-10-17 20:20:35 +00:00
|
|
|
// 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)
|
|
|
|
}
|
2021-06-15 15:50:29 +00:00
|
|
|
defer closeResponseBody(resp)
|
2018-10-17 20:20:35 +00:00
|
|
|
|
2021-05-27 13:41:53 +00:00
|
|
|
if resp.StatusCode != 200 {
|
|
|
|
return nil, generateUnexpectedResponseCodeError(resp)
|
|
|
|
}
|
|
|
|
|
2018-10-17 20:20:35 +00:00
|
|
|
// 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)
|
|
|
|
}
|
2021-06-15 15:50:29 +00:00
|
|
|
defer closeResponseBody(resp)
|
2018-10-17 20:20:35 +00:00
|
|
|
|
2021-05-27 13:41:53 +00:00
|
|
|
if resp.StatusCode != 200 {
|
|
|
|
return nil, generateUnexpectedResponseCodeError(resp)
|
|
|
|
}
|
|
|
|
|
2018-10-17 20:20:35 +00:00
|
|
|
// 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)
|
|
|
|
}
|
2021-06-15 15:50:29 +00:00
|
|
|
defer closeResponseBody(resp)
|
2018-10-17 20:20:35 +00:00
|
|
|
|
2021-05-27 13:41:53 +00:00
|
|
|
if resp.StatusCode != 200 {
|
|
|
|
return nil, generateUnexpectedResponseCodeError(resp)
|
|
|
|
}
|
|
|
|
|
2018-10-17 20:20:35 +00:00
|
|
|
// 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
|
|
|
|
}
|