@@ -16,10 +16,12 @@ package debug
16
16
17
17
import (
18
18
"context"
19
+ "errors"
19
20
"fmt"
20
21
"net/http"
21
22
"net/http/pprof"
22
23
"runtime"
24
+ "sync"
23
25
"time"
24
26
25
27
"github.com/google/gops/agent"
@@ -31,25 +33,75 @@ import (
31
33
// Connect to the debug server with gops:
32
34
//
33
35
// gops stack localhost:PORT
34
- func New (l logrus.FieldLogger , port int ) * Server {
35
- return & Server {
36
+ //
37
+ // Connect to the pprof server with pprof.port when pprof enabled
38
+ func New (l logrus.FieldLogger , config Config ) * Server {
39
+ server := & Server {
36
40
logger : l ,
37
- addr : fmt .Sprintf ("127.0.0.1:%d" , port ),
41
+ addr : fmt .Sprintf ("127.0.0.1:%d" , config . Port ),
38
42
done : make (chan struct {}),
39
43
}
44
+ if config .Enabled {
45
+ server .pprof = NewPProfServer (l , & config .PProf )
46
+ }
47
+ return server
40
48
}
41
49
42
50
// Server wraps a gops server for easy use with oklog/group.
43
51
type Server struct {
44
52
logger logrus.FieldLogger
45
53
addr string
46
54
done chan struct {}
55
+ pprof * PProfServer
47
56
}
48
57
49
58
// Run starts the debug server.
50
59
//
51
- // It implements oklog group's runFn.
60
+ // It implements oklog group's runFn and pprof .
52
61
func (s * Server ) Run () error {
62
+
63
+ var wg sync.WaitGroup
64
+ var gopsErr error
65
+ var pprofErr error
66
+
67
+ wg .Add (1 )
68
+ go func () {
69
+ defer wg .Done ()
70
+ gopsErr = s .RunGOPS ()
71
+ if gopsErr != nil {
72
+ s .logger .WithError (gopsErr ).Error ("gops server failed" )
73
+ }
74
+ }()
75
+
76
+ if s .pprof != nil {
77
+ wg .Add (1 )
78
+ go func () {
79
+ defer wg .Done ()
80
+ pprofErr = s .pprof .Run ()
81
+ if pprofErr != nil {
82
+ s .pprof .logger .WithError (pprofErr ).Error ("pprof server failed" )
83
+ }
84
+ }()
85
+ }
86
+
87
+ wg .Wait ()
88
+
89
+ var err error
90
+ if gopsErr != nil {
91
+ err = fmt .Errorf ("gops error: %w" , gopsErr )
92
+ }
93
+ if pprofErr != nil {
94
+ errPProf := fmt .Errorf ("pprof error: %w" , pprofErr )
95
+ err = errors .Join (err , errPProf )
96
+ }
97
+
98
+ return err
99
+ }
100
+
101
+ // Run starts the debug server.
102
+ //
103
+ // It implements oklog group's runFn.
104
+ func (s * Server ) RunGOPS () error {
53
105
s .logger .WithFields (logrus.Fields {
54
106
"at" : "binding" ,
55
107
"service" : "debug" ,
@@ -70,11 +122,15 @@ func (s *Server) Run() error {
70
122
71
123
// Stop shuts down the debug server.
72
124
//
73
- // It implements oklog group's interruptFn.
125
+ // It implements oklog group's interruptFn and pprof stop .
74
126
func (s * Server ) Stop (_ error ) {
75
127
agent .Close ()
76
128
77
129
close (s .done )
130
+
131
+ if s .pprof != nil {
132
+ s .pprof .Stop (nil )
133
+ }
78
134
}
79
135
80
136
// PProfServer wraps a pprof server.
@@ -85,45 +141,34 @@ type PProfServer struct {
85
141
pprofServer * http.Server
86
142
}
87
143
88
- // ProfileConfig holds the configuration for the pprof server.
89
- type PProfServerConfig struct {
90
- Addr string
91
- MutexProfileFraction int
92
- }
144
+ // NewPProfServer sets up a pprof server with configurable profiling types and returns a PProfServer instance.
145
+ func NewPProfServer (l logrus.FieldLogger , pprofConfig * PProf ) * PProfServer {
93
146
94
- // defaultMutexProfileFraction is the default value for MutexProfileFraction
95
- const defaultMutexProfileFraction = 2
147
+ runtime .MemProfileRate = pprofConfig .MemProfileRate
96
148
97
- // NewPProfServer sets up a pprof server with configurable profiling types and returns a PProfServer instance.
98
- func NewPProfServer (config PProfServerConfig , l logrus.FieldLogger ) * PProfServer {
99
- if config .Addr == "" {
100
- config .Addr = "127.0.0.1:9998" // Default port
149
+ if pprofConfig .EnableMutexProfiling {
150
+ runtime .SetMutexProfileFraction (pprofConfig .MutexProfileFraction )
101
151
}
102
152
103
- // Use a local variable for the mutex profile fraction
104
- mpf := defaultMutexProfileFraction
105
- if config .MutexProfileFraction != 0 {
106
- mpf = config .MutexProfileFraction
153
+ if pprofConfig .EnableBlockProfiling {
154
+ runtime .SetBlockProfileRate (pprofConfig .BlockProfileRate )
107
155
}
108
- runtime .SetMutexProfileFraction (mpf )
109
156
110
157
httpServer := & http.Server {
111
- Addr : config . Addr ,
158
+ Addr : fmt . Sprintf ( "127.0.0.1:%d" , pprofConfig . Port ) ,
112
159
Handler : http .HandlerFunc (pprof .Index ),
113
160
ReadHeaderTimeout : 5 * time .Second ,
114
161
}
115
162
116
163
return & PProfServer {
117
164
logger : l ,
118
- addr : config .Addr ,
165
+ addr : httpServer .Addr ,
119
166
done : make (chan struct {}),
120
167
pprofServer : httpServer ,
121
168
}
122
169
}
123
170
124
171
// Run starts the pprof server.
125
- //
126
- // It implements oklog group's runFn.
127
172
func (s * PProfServer ) Run () error {
128
173
if s .pprofServer == nil {
129
174
return fmt .Errorf ("pprofServer is nil" )
@@ -144,8 +189,6 @@ func (s *PProfServer) Run() error {
144
189
}
145
190
146
191
// Stop shuts down the pprof server.
147
- //
148
- // It implements oklog group's interruptFn.
149
192
func (s * PProfServer ) Stop (_ error ) {
150
193
if s .pprofServer != nil {
151
194
ctx , cancel := context .WithTimeout (context .Background (), 5 * time .Second )
0 commit comments