Skip to content

Commit efc5946

Browse files
committed
add dump functions (cpu, block, mutex)
1 parent f1378b2 commit efc5946

File tree

3 files changed

+331
-5
lines changed

3 files changed

+331
-5
lines changed

scouterx/agent_test.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ func TestScouterAgent(T *testing.T) {
2020
go loadTest()
2121
go loadTest()
2222

23+
go mutexLock()
24+
2325
wg.Wait()
2426
}
2527

@@ -29,6 +31,19 @@ func loadTest() {
2931
}
3032
}
3133

34+
func mutexLock() {
35+
//runtime.SetMutexProfileFraction(5)
36+
var mu sync.Mutex
37+
for i := 0; i < 10; i++ {
38+
go func() {
39+
for {
40+
mu.Lock()
41+
time.Sleep(100 * time.Millisecond)
42+
mu.Unlock()
43+
}
44+
}()
45+
}
46+
}
3247

3348
func randomSleeps() {
3449
ctx := context.Background()

scouterx/dump/dump.go

Lines changed: 201 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,10 @@ package dump
22

33
import (
44
"bufio"
5+
"errors"
56
"fmt"
67
"github.com/scouter-contrib/scouter-agent-golang/scouterx/common/constants/tcpflag"
8+
"github.com/scouter-contrib/scouter-agent-golang/scouterx/common/logger"
79
"github.com/scouter-contrib/scouter-agent-golang/scouterx/common/netdata"
810
"github.com/scouter-contrib/scouter-agent-golang/scouterx/common/util"
911
"io"
@@ -16,6 +18,8 @@ import (
1618
"time"
1719
)
1820

21+
const suffix = "pprof"
22+
1923
func StackTrace(count int) string {
2024
// fine, line
2125
pcLen := count
@@ -58,32 +62,147 @@ func HeavyAllStackTrace() netdata.Pack {
5862
}
5963

6064
func heavyAllStackTrace() (string, error) {
61-
path := util.GetScouterPath()
62-
dumpPath := filepath.Join(path, "dump")
63-
util.MakeDir(dumpPath)
64-
65-
fileName := filepath.Join(dumpPath, "go_dump_" + time.Now().Format("20060102_150405") + ".log")
65+
fileName := filepath.Join(getDumpPath(), "go_dump_" + time.Now().Format("20060102_150405") + ".log")
6666

6767
var w io.Writer = os.Stdout
6868
if fileName != "" {
6969
f, err := os.Create(fileName)
7070
if err == nil {
7171
w = bufio.NewWriter(f)
72+
defer f.Close()
7273
} else {
7374
return "", err
7475
}
7576
}
7677
profile := pprof.Lookup("goroutine")
78+
if profile == nil {
79+
logger.Error.Printf("could not find goroutine profile\n")
80+
return "", errors.New("could not find goroutine profile")
81+
}
7782
return fileName, profile.WriteTo(w, 2)
7883
}
7984

85+
func ProfileBinaryCpu(sec int) netdata.Pack {
86+
fileName := filepath.Join(getBinaryDumpPath(), "go_cpu_" + time.Now().Format("20060102_150405") + "." + suffix)
87+
88+
go profileCpu(fileName, sec)
89+
pack := netdata.NewMapPack()
90+
return pack
91+
}
92+
93+
func profileCpu(fileName string, sec int) {
94+
f, err := os.Create(fileName)
95+
if err == nil {
96+
defer f.Close()
97+
} else {
98+
logger.Error.Printf("could not make file to start CPU profile: %s\n", err)
99+
return
100+
}
101+
102+
if err := pprof.StartCPUProfile(f); err != nil {
103+
logger.Error.Printf("could not start CPU profile: %s\n", err)
104+
return
105+
}
106+
defer pprof.StopCPUProfile()
107+
time.Sleep(time.Duration(sec) * time.Second)
108+
}
109+
110+
func ProfileBlock(sec, rate, level int) netdata.Pack {
111+
fileName := filepath.Join(getDumpPath(), "go_block_" + time.Now().Format("20060102_150405") + ".log")
112+
113+
go profileBlock(fileName, sec, rate, level)
114+
pack := netdata.NewMapPack()
115+
return pack
116+
}
117+
118+
func ProfileBlockBinaryDump(sec, rate int) netdata.Pack {
119+
fileName := filepath.Join(getBinaryDumpPath(), "go_block_" + time.Now().Format("20060102_150405") + "." + suffix)
120+
121+
go profileBlock(fileName, sec, rate, 0)
122+
pack := netdata.NewMapPack()
123+
return pack
124+
}
125+
126+
func profileBlock(fileName string, sec, rate, level int) {
127+
runtime.SetBlockProfileRate(rate)
128+
defer runtime.SetBlockProfileRate(-1)
129+
time.Sleep(time.Duration(sec) * time.Second)
130+
131+
var w *bufio.Writer
132+
if fileName != "" {
133+
f, err := os.Create(fileName)
134+
if err == nil {
135+
w = bufio.NewWriter(f)
136+
defer f.Close()
137+
} else {
138+
return
139+
}
140+
}
141+
profile := pprof.Lookup("block")
142+
if profile == nil {
143+
logger.Error.Printf("could not find block profile\n")
144+
}
145+
if err := profile.WriteTo(w, level); err != nil {
146+
logger.Error.Printf("could not run block profile: %s\n", err)
147+
}
148+
w.Flush()
149+
}
150+
151+
152+
func ProfileMutex(sec, rate, level int) {
153+
fileName := filepath.Join(getDumpPath(), "go_mutex_" + time.Now().Format("20060102_150405") + ".log")
154+
155+
go profileMutex(fileName, sec, rate, level)
156+
return
157+
}
158+
159+
func ProfileMutexBinaryDump(sec, rate int) {
160+
fileName := filepath.Join(getBinaryDumpPath(), "go_mutex_" + time.Now().Format("20060102_150405") + "." + suffix)
161+
162+
go profileMutex(fileName, sec, rate, 0)
163+
return
164+
}
165+
166+
167+
func profileMutex(fileName string, sec, rate, level int) {
168+
old := runtime.SetMutexProfileFraction(rate)
169+
defer runtime.SetMutexProfileFraction(old)
170+
time.Sleep(time.Duration(sec) * time.Second)
171+
172+
var w *bufio.Writer
173+
if fileName != "" {
174+
f, err := os.Create(fileName)
175+
if err == nil {
176+
w = bufio.NewWriter(f)
177+
defer f.Close()
178+
} else {
179+
return
180+
}
181+
}
182+
profile := pprof.Lookup("mutex")
183+
if profile == nil {
184+
logger.Error.Printf("could not find mutex profile\n")
185+
}
186+
if err := profile.WriteTo(w, level); err != nil {
187+
logger.Error.Printf("could not run mutex profile: %s\n", err)
188+
}
189+
w.Flush()
190+
}
191+
80192
func getDumpPath() string {
81193
path := util.GetScouterPath()
82194
dumpPath := filepath.Join(path, "dump")
83195
util.MakeDir(dumpPath)
84196
return dumpPath
85197
}
86198

199+
func getBinaryDumpPath() string {
200+
path := util.GetScouterPath()
201+
dumpPath := filepath.Join(path, "binary_dump")
202+
util.MakeDir(dumpPath)
203+
return dumpPath
204+
}
205+
87206
func ListDumpFiles() netdata.Pack {
88207
pack := netdata.NewMapPack()
89208
nameLv := netdata.NewListValue()
@@ -107,6 +226,83 @@ func ListDumpFiles() netdata.Pack {
107226
return pack
108227
}
109228

229+
func ListBinaryDumpFiles() netdata.Pack {
230+
pack := netdata.NewMapPack()
231+
nameLv := netdata.NewListValue()
232+
pack.Put("name", nameLv)
233+
sizeLv := netdata.NewListValue()
234+
pack.Put("size", sizeLv)
235+
236+
dumpPath := getBinaryDumpPath()
237+
238+
filepath.Walk(dumpPath, func(path string, info os.FileInfo, err error) error {
239+
if !info.IsDir() && strings.HasSuffix(info.Name(), suffix) {
240+
nameLv.AddString(info.Name())
241+
sizeLv.AddInt64(info.Size())
242+
}
243+
return nil
244+
})
245+
246+
return pack
247+
}
248+
249+
func DownloadBinaryDumpFiles(out *netdata.DataOutputX, fileName string) {
250+
if fileName == "" || !strings.HasSuffix(fileName, suffix){
251+
return
252+
}
253+
dumpPath := getBinaryDumpPath()
254+
fullName := filepath.Join(dumpPath, fileName)
255+
256+
f, err := os.Open(fullName)
257+
if err != nil {
258+
logger.Error.Printf("could not open file: %s\n", fullName)
259+
return
260+
}
261+
defer f.Close()
262+
263+
//var b = make([]byte, 2 * 1024 * 1024, 2 * 1024 * 1024)
264+
var b = make([]byte, 300, 300)
265+
var offset int64 = 0
266+
267+
for {
268+
len, err := f.ReadAt(b, offset)
269+
if err != nil {
270+
if err != io.EOF {
271+
logger.Error.Printf("file read error: %s\n", err.Error())
272+
} else {
273+
out.WriteUInt8(tcpflag.HasNEXT);
274+
out.WriteBlob(b[0:len]);
275+
}
276+
break
277+
}
278+
out.WriteUInt8(tcpflag.HasNEXT);
279+
out.WriteBlob(b[0:len]);
280+
offset = offset + int64(len)
281+
}
282+
return
283+
}
284+
285+
func DeleteBinaryDumpFiles(fileName string) netdata.Pack {
286+
pack := netdata.NewMapPack()
287+
if fileName == "" || !strings.HasSuffix(fileName, suffix){
288+
pack.Put("success", netdata.NewBooleanValue(false))
289+
pack.Put("msg", "no fileName")
290+
return pack
291+
}
292+
dumpPath := getBinaryDumpPath()
293+
fullName := filepath.Join(dumpPath, fileName)
294+
295+
err := os.Remove(fullName)
296+
if err != nil {
297+
pack.Put("success", netdata.NewBooleanValue(false))
298+
pack.Put("msg", err.Error())
299+
} else {
300+
pack.Put("success", netdata.NewBooleanValue(true))
301+
pack.Put("msg", "success")
302+
}
303+
return pack
304+
}
305+
110306
func StreamDumpFileContents(param netdata.Pack, out *netdata.DataOutputX) {
111307
p, ok := param.(*netdata.MapPack)
112308
if !ok {

0 commit comments

Comments
 (0)