1package api 2 3import ( 4 "fmt" 5 "io/ioutil" 6 "strconv" 7) 8 9// Debug can be used to query the /debug/pprof endpoints to gather 10// profiling information about the target agent.Debug 11// 12// The agent must have enable_debug set to true for profiling to be enabled 13// and for these endpoints to function. 14type Debug struct { 15 c *Client 16} 17 18// Debug returns a handle that exposes the internal debug endpoints. 19func (c *Client) Debug() *Debug { 20 return &Debug{c} 21} 22 23// Heap returns a pprof heap dump 24func (d *Debug) Heap() ([]byte, error) { 25 r := d.c.newRequest("GET", "/debug/pprof/heap") 26 _, resp, err := d.c.doRequest(r) 27 if err != nil { 28 return nil, fmt.Errorf("error making request: %s", err) 29 } 30 defer closeResponseBody(resp) 31 32 if resp.StatusCode != 200 { 33 return nil, generateUnexpectedResponseCodeError(resp) 34 } 35 36 // We return a raw response because we're just passing through a response 37 // from the pprof handlers 38 body, err := ioutil.ReadAll(resp.Body) 39 if err != nil { 40 return nil, fmt.Errorf("error decoding body: %s", err) 41 } 42 43 return body, nil 44} 45 46// Profile returns a pprof CPU profile for the specified number of seconds 47func (d *Debug) Profile(seconds int) ([]byte, error) { 48 r := d.c.newRequest("GET", "/debug/pprof/profile") 49 50 // Capture a profile for the specified number of seconds 51 r.params.Set("seconds", strconv.Itoa(seconds)) 52 53 _, resp, err := d.c.doRequest(r) 54 if err != nil { 55 return nil, fmt.Errorf("error making request: %s", err) 56 } 57 defer closeResponseBody(resp) 58 59 if resp.StatusCode != 200 { 60 return nil, generateUnexpectedResponseCodeError(resp) 61 } 62 63 // We return a raw response because we're just passing through a response 64 // from the pprof handlers 65 body, err := ioutil.ReadAll(resp.Body) 66 if err != nil { 67 return nil, fmt.Errorf("error decoding body: %s", err) 68 } 69 70 return body, nil 71} 72 73// Trace returns an execution trace 74func (d *Debug) Trace(seconds int) ([]byte, error) { 75 r := d.c.newRequest("GET", "/debug/pprof/trace") 76 77 // Capture a trace for the specified number of seconds 78 r.params.Set("seconds", strconv.Itoa(seconds)) 79 80 _, resp, err := d.c.doRequest(r) 81 if err != nil { 82 return nil, fmt.Errorf("error making request: %s", err) 83 } 84 defer closeResponseBody(resp) 85 86 if resp.StatusCode != 200 { 87 return nil, generateUnexpectedResponseCodeError(resp) 88 } 89 90 // We return a raw response because we're just passing through a response 91 // from the pprof handlers 92 body, err := ioutil.ReadAll(resp.Body) 93 if err != nil { 94 return nil, fmt.Errorf("error decoding body: %s", err) 95 } 96 97 return body, nil 98} 99 100// Goroutine returns a pprof goroutine profile 101func (d *Debug) Goroutine() ([]byte, error) { 102 r := d.c.newRequest("GET", "/debug/pprof/goroutine") 103 104 _, resp, err := d.c.doRequest(r) 105 if err != nil { 106 return nil, fmt.Errorf("error making request: %s", err) 107 } 108 defer closeResponseBody(resp) 109 110 if resp.StatusCode != 200 { 111 return nil, generateUnexpectedResponseCodeError(resp) 112 } 113 114 // We return a raw response because we're just passing through a response 115 // from the pprof handlers 116 body, err := ioutil.ReadAll(resp.Body) 117 if err != nil { 118 return nil, fmt.Errorf("error decoding body: %s", err) 119 } 120 121 return body, nil 122} 123