@@ -2,8 +2,10 @@ package dump
22
33import (
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+
1923func StackTrace (count int ) string {
2024 // fine, line
2125 pcLen := count
@@ -58,32 +62,147 @@ func HeavyAllStackTrace() netdata.Pack {
5862}
5963
6064func 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+
80192func 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+
87206func 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+
110306func StreamDumpFileContents (param netdata.Pack , out * netdata.DataOutputX ) {
111307 p , ok := param .(* netdata.MapPack )
112308 if ! ok {
0 commit comments