Skip to content

Commit 0448cea

Browse files
author
hengyouhai
committed
feat: add pprof endpoint option for profiling
Add --pprof and --pprof-addr flags to enable pprof HTTP endpoint for runtime profiling and debugging. Security improvements: - Use http.Server with ReadHeaderTimeout (10s) and IdleTimeout (120s) - Graceful shutdown tied to options.Ctx with 5s timeout - Explicit pprof handler registration instead of default serve mux Changes: - Add EnablePprof and PprofAddr to AgentOptions - Add --pprof flag to enable pprof server (default: false) - Add --pprof-addr flag to configure listen address (default: localhost:6060) - Implement startPprofServer() with proper timeouts and shutdown handling - Update docs/debug-tips.md and docs/cn/debug-tips.md with usage examples Usage: kyanos watch --pprof kyanos watch --pprof --pprof-addr=:9090 The pprof endpoint provides access to: - /debug/pprof/heap - memory profiling - /debug/pprof/profile - CPU profiling - /debug/pprof/goroutine - goroutine dumps
1 parent 6294a28 commit 0448cea

File tree

5 files changed

+148
-1
lines changed

5 files changed

+148
-1
lines changed

agent/agent.go

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,21 +19,23 @@ import (
1919
"kyanos/version"
2020
"os"
2121
"os/exec"
22+
"net/http"
2223
"os/signal"
2324
"runtime"
2425
"strings"
2526
"sync"
2627
"syscall"
2728
"time"
2829

29-
_ "net/http/pprof"
30+
"net/http/pprof"
3031

3132
"github.com/cilium/ebpf/rlimit"
3233
gops "github.com/google/gops/agent"
3334
)
3435

3536
func SetupAgent(options ac.AgentOptions) {
3637
startGopsServer(options)
38+
startPprofServer(options)
3739

3840
if err := version.UpgradeDetect(); err != nil {
3941
if errors.Is(err, version.ErrBehindLatest) {
@@ -252,3 +254,49 @@ func startGopsServer(opts ac.AgentOptions) {
252254
}
253255
}
254256
}
257+
258+
func startPprofServer(opts ac.AgentOptions) {
259+
if !opts.EnablePprof {
260+
return
261+
}
262+
263+
addr := opts.GetPprofAddr()
264+
displayAddr := addr
265+
if strings.HasPrefix(addr, ":") {
266+
displayAddr = "localhost" + addr
267+
}
268+
269+
mux := http.NewServeMux()
270+
mux.HandleFunc("/debug/pprof/", pprof.Index)
271+
mux.HandleFunc("/debug/pprof/cmdline", pprof.Cmdline)
272+
mux.HandleFunc("/debug/pprof/profile", pprof.Profile)
273+
mux.HandleFunc("/debug/pprof/symbol", pprof.Symbol)
274+
mux.HandleFunc("/debug/pprof/trace", pprof.Trace)
275+
mux.HandleFunc("/debug/pprof/{name}", pprof.Index)
276+
277+
server := &http.Server{
278+
Addr: addr,
279+
Handler: mux,
280+
ReadHeaderTimeout: 10 * time.Second,
281+
IdleTimeout: 120 * time.Second,
282+
}
283+
284+
go func() {
285+
common.AgentLog.Infof("Starting pprof server on http://%s/debug/pprof/", displayAddr)
286+
common.AgentLog.Info("pprof endpoints: /debug/pprof/heap, /debug/pprof/profile, /debug/pprof/goroutine")
287+
if err := server.ListenAndServe(); err != nil && err != http.ErrServerClosed {
288+
common.AgentLog.Errorf("Failed to start pprof server: %v", err)
289+
}
290+
}()
291+
292+
go func() {
293+
<-opts.Ctx.Done()
294+
shutdownCtx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
295+
defer cancel()
296+
if err := server.Shutdown(shutdownCtx); err != nil {
297+
common.AgentLog.Errorf("Failed to shutdown pprof server: %v", err)
298+
} else {
299+
common.AgentLog.Info("pprof server shutdown gracefully")
300+
}
301+
}()
302+
}

agent/common/options.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,8 @@ type AgentOptions struct {
5050
ConntrackCloseWaitTimeMills int
5151
MaxAllowStuckTimeMills int
5252
StartGopsServer bool
53+
EnablePprof bool
54+
PprofAddr string
5355

5456
FilterComm string
5557
ProcessExecEventChannel chan *bpf.AgentProcessExecEvent
@@ -74,6 +76,13 @@ type AgentOptions struct {
7476
FirstPacketEventMapPageNum int
7577
}
7678

79+
func (o AgentOptions) GetPprofAddr() string {
80+
if o.PprofAddr == "" {
81+
return "localhost:6060"
82+
}
83+
return o.PprofAddr
84+
}
85+
7786
func (o AgentOptions) FilterByContainer() bool {
7887
return o.ContainerId != "" || o.ContainerName != "" || o.PodName != ""
7988
}

cmd/root.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,8 @@ func init() {
105105
rootCmd.PersistentFlags().IntVar(&options.MaxAllowStuckTimeMills, "max-allow-stuck-time-mills", 1000, "--max-allow-stuck-time-mills 100")
106106

107107
rootCmd.PersistentFlags().BoolVar(&options.StartGopsServer, "gops", false, "start gops server")
108+
rootCmd.PersistentFlags().BoolVar(&options.EnablePprof, "pprof", false, "enable pprof HTTP endpoint for profiling (WARNING: exposes sensitive profiling data; do not use on untrusted networks)")
109+
rootCmd.PersistentFlags().StringVar(&options.PprofAddr, "pprof-addr", "127.0.0.1:6060", "pprof HTTP server address (WARNING: binding to non-loopback addresses, e.g. \":6060\" or \"0.0.0.0:6060\", will expose profiling data to the network)")
108110

109111
rootCmd.PersistentFlags().MarkHidden("default-log-level")
110112
rootCmd.PersistentFlags().MarkHidden("agent-log-level")

docs/cn/debug-tips.md

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,50 @@ VSCODE 直接打开项目即可,.vscode/launch.json 添加配置如下:
8585

8686
注意添加 `--debug-output` 参数。
8787

88+
## 性能分析(Profiling)
89+
90+
Kyanos 提供了 pprof 端点用于运行时性能分析和调试。你可以使用 `--pprof` 标志启用 pprof HTTP 服务器:
91+
92+
```bash
93+
./kyanos watch --pprof
94+
```
95+
96+
默认情况下,pprof 服务器监听 `localhost:6060`。你可以使用 `--pprof-addr` 标志自定义监听地址:
97+
98+
```bash
99+
./kyanos watch --pprof --pprof-addr="0.0.0.0:9090"
100+
```
101+
102+
可用的 pprof 端点:
103+
104+
| 端点 | 说明 |
105+
|------|------|
106+
| `/debug/pprof/` | 索引页面,显示所有可用的 profile |
107+
| `/debug/pprof/heap` | 内存堆 profile |
108+
| `/debug/pprof/profile` | CPU profile(默认 30 秒) |
109+
| `/debug/pprof/goroutine` | Goroutine 堆栈信息 |
110+
| `/debug/pprof/allocs` | 内存分配 profile |
111+
| `/debug/pprof/block` | 阻塞 profile |
112+
| `/debug/pprof/mutex` | 锁竞争 profile |
113+
114+
使用示例:
115+
116+
```bash
117+
# 采集 CPU profile
118+
curl -o cpu.pprof http://localhost:6060/debug/pprof/profile?seconds=30
119+
go tool pprof cpu.pprof
120+
121+
# 查看堆内存 profile
122+
go tool pprof http://localhost:6060/debug/pprof/heap
123+
124+
# 查看 goroutine 堆栈
125+
curl http://localhost:6060/debug/pprof/goroutine?debug=1
126+
```
127+
128+
> [!TIP]
129+
>
130+
> pprof 端点对于诊断 Kyanos 自身的性能问题、内存泄漏或 goroutine 泄漏非常有用。
131+
88132
## 源码结构
89133

90134
```

docs/debug-tips.md

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,50 @@ Make sure to add the `--debug-output` parameter.
9494
Protocol inference code can be debugged by printing logs using `bpf_printk`,
9595
refer to: https://nakryiko.com/posts/bpf-tips-printk/.
9696

97+
## Profiling
98+
99+
Kyanos provides pprof endpoints for runtime profiling and debugging. You can enable the pprof HTTP server using the `--pprof` flag:
100+
101+
```bash
102+
./kyanos watch --pprof
103+
```
104+
105+
By default, the pprof server listens on `localhost:6060`. You can customize the address using the `--pprof-addr` flag:
106+
107+
```bash
108+
./kyanos watch --pprof --pprof-addr="0.0.0.0:9090"
109+
```
110+
111+
Available pprof endpoints:
112+
113+
| Endpoint | Description |
114+
|----------|-------------|
115+
| `/debug/pprof/` | Index page with all available profiles |
116+
| `/debug/pprof/heap` | Memory heap profile |
117+
| `/debug/pprof/profile` | CPU profile (30 seconds by default) |
118+
| `/debug/pprof/goroutine` | Goroutine dump |
119+
| `/debug/pprof/allocs` | Allocation profile |
120+
| `/debug/pprof/block` | Block profile |
121+
| `/debug/pprof/mutex` | Mutex contention profile |
122+
123+
Example usage:
124+
125+
```bash
126+
# Capture CPU profile
127+
curl -o cpu.pprof http://localhost:6060/debug/pprof/profile?seconds=30
128+
go tool pprof cpu.pprof
129+
130+
# View heap profile
131+
go tool pprof http://localhost:6060/debug/pprof/heap
132+
133+
# View goroutine dump
134+
curl http://localhost:6060/debug/pprof/goroutine?debug=1
135+
```
136+
137+
> [!TIP]
138+
>
139+
> The pprof endpoint is useful for diagnosing performance issues, memory leaks, or goroutine leaks in Kyanos itself.
140+
97141
## Source Code Structure
98142

99143
```

0 commit comments

Comments
 (0)