Skip to content

Commit 7bd339b

Browse files
committed
add automatic span timing
1 parent 3711054 commit 7bd339b

15 files changed

+211
-239
lines changed

README.md

+7
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,13 @@ span := agent.Profile();
119119
defer span.Stop();
120120
```
121121

122+
```go
123+
// This method is similar to the Profile() method. It additionally
124+
// allows to specify a span name to group span timing measurements.
125+
span := agent.ProfileWithName(name);
126+
defer span.Stop();
127+
```
128+
122129
```go
123130
// A helper function to profile HTTP handler execution by wrapping
124131
// http.Handle method parameters.

agent.go

+11-7
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,13 @@ func (a *Agent) Configure(agentKey string, appName string) {
156156
// overhead constraints. The method returns Span object, on
157157
// which the Stop() method should be called.
158158
func (a *Agent) Profile() *Span {
159-
s := newSpan(a)
159+
return a.ProfileWithName("Default")
160+
}
161+
162+
// This method is similar to the Profile() method. It additionally
163+
// allows to specify a span name to group span timing measurements.
164+
func (a *Agent) ProfileWithName(name string) *Span {
165+
s := newSpan(a, name)
160166
s.start()
161167

162168
return s
@@ -166,13 +172,12 @@ func (a *Agent) Profile() *Span {
166172
// by wrapping http.HandleFunc method parameters.
167173
func (a *Agent) ProfileHandlerFunc(pattern string, handlerFunc func(http.ResponseWriter, *http.Request)) (string, func(http.ResponseWriter, *http.Request)) {
168174
return pattern, func(w http.ResponseWriter, r *http.Request) {
169-
span := newSpan(a)
170-
span.workload = pattern
175+
span := newSpan(a, fmt.Sprintf("Handler %s", pattern))
171176
span.start()
172177
defer span.Stop()
173178

174179
if span.active {
175-
WithPprofLabel("workload", pattern, r, func() {
180+
WithPprofLabel("workload", span.name, r, func() {
176181
handlerFunc(w, r)
177182
})
178183
} else {
@@ -185,13 +190,12 @@ func (a *Agent) ProfileHandlerFunc(pattern string, handlerFunc func(http.Respons
185190
// by wrapping http.Handle method parameters.
186191
func (a *Agent) ProfileHandler(pattern string, handler http.Handler) (string, http.Handler) {
187192
return pattern, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
188-
span := newSpan(a)
189-
span.workload = pattern
193+
span := newSpan(a, fmt.Sprintf("Handler %s", pattern))
190194
span.start()
191195
defer span.Stop()
192196

193197
if span.active {
194-
WithPprofLabel("workload", pattern, r, func() {
198+
WithPprofLabel("workload", span.name, r, func() {
195199
handler.ServeHTTP(w, r)
196200
})
197201
} else {

agent_test.go

+9-3
Original file line numberDiff line numberDiff line change
@@ -123,19 +123,22 @@ func waitForServer(url string) {
123123
}
124124
}
125125

126-
func BenchmarkMeasureSegment(b *testing.B) {
126+
func BenchmarkProfile(b *testing.B) {
127127
agent := NewAgent()
128128
agent.Start(Options{
129129
AgentKey: "key1",
130130
AppName: "app1",
131131
})
132+
agent.internalAgent.Enable()
133+
134+
b.ResetTimer()
132135

133136
for i := 0; i < b.N; i++ {
134-
s := agent.MeasureSegment("seg1")
137+
s := agent.Profile()
135138
s.Stop()
136139
}
137140

138-
// go test -v -run=^$ -bench=BenchmarkMeasureSegment -cpuprofile=cpu.out
141+
// go test -v -run=^$ -bench=BenchmarkProfile -cpuprofile=cpu.out
139142
// go tool pprof internal.test cpu.out
140143
}
141144

@@ -145,9 +148,12 @@ func BenchmarkRecordError(b *testing.B) {
145148
AgentKey: "key1",
146149
AppName: "app1",
147150
})
151+
agent.internalAgent.Enable()
148152

149153
err := errors.New("error1")
150154

155+
b.ResetTimer()
156+
151157
for i := 0; i < b.N; i++ {
152158
agent.RecordError(err)
153159
}

examples/app.go

+2-55
Original file line numberDiff line numberDiff line change
@@ -201,7 +201,7 @@ func simulateProgrammaticProfiling() {
201201
func simulateWorkloadProfiling() {
202202
// start HTTP server
203203
go func() {
204-
http.HandleFunc(agent.ProfileHandlerFunc("/some-handler-workload", func(w http.ResponseWriter, r *http.Request) {
204+
http.HandleFunc(agent.ProfileHandlerFunc("/some-handler", func(w http.ResponseWriter, r *http.Request) {
205205
for i := 0; i < 500000; i++ {
206206
str := "str" + strconv.Itoa(i)
207207
str = str + "a"
@@ -220,58 +220,7 @@ func simulateWorkloadProfiling() {
220220
for {
221221
select {
222222
case <-requestTicker.C:
223-
res, err := http.Get("http://localhost:5003/some-handler-workload")
224-
if err == nil {
225-
res.Body.Close()
226-
}
227-
}
228-
}
229-
}
230-
231-
func simulateSegments() {
232-
for {
233-
done1 := make(chan bool)
234-
235-
go func() {
236-
segment := agent.MeasureSegment("Segment1")
237-
defer segment.Stop()
238-
239-
time.Sleep(time.Duration(100+rand.Intn(20)) * time.Millisecond)
240-
241-
done1 <- true
242-
}()
243-
244-
<-done1
245-
}
246-
}
247-
248-
func simulateHandlerSegments() {
249-
// start HTTP server
250-
go func() {
251-
http.HandleFunc(agent.MeasureHandlerFunc("/some-handler-func", func(w http.ResponseWriter, r *http.Request) {
252-
time.Sleep(time.Duration(200+rand.Intn(50)) * time.Millisecond)
253-
254-
fmt.Fprintf(w, "OK")
255-
}))
256-
257-
http.Handle(agent.MeasureHandler("/some-handler", http.StripPrefix("/some-handler", http.FileServer(http.Dir("/tmp")))))
258-
259-
if err := http.ListenAndServe(":5001", nil); err != nil {
260-
log.Fatal(err)
261-
return
262-
}
263-
}()
264-
265-
requestTicker := time.NewTicker(1000 * time.Millisecond)
266-
for {
267-
select {
268-
case <-requestTicker.C:
269-
res, err := http.Get("http://localhost:5001/some-handler-func")
270-
if err == nil {
271-
res.Body.Close()
272-
}
273-
274-
res, err = http.Get("http://localhost:5001/some-handler")
223+
res, err := http.Get("http://localhost:5003/some-handler")
275224
if err == nil {
276225
res.Body.Close()
277226
}
@@ -346,8 +295,6 @@ func main() {
346295
go simulateLockWait()
347296
go simulateProgrammaticProfiling()
348297
go simulateWorkloadProfiling()
349-
go simulateSegments()
350-
go simulateHandlerSegments()
351298
go simulateErrors()
352299

353300
select {}

internal/agent.go

+8-8
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import (
1616
"time"
1717
)
1818

19-
const AgentVersion = "2.3.5"
19+
const AgentVersion = "2.3.6"
2020
const SAASDashboardAddress = "https://agent-api.stackimpact.com"
2121

2222
var agentPath = filepath.Join("github.com", "stackimpact", "stackimpact-go")
@@ -41,7 +41,7 @@ type Agent struct {
4141
cpuReporter *ProfileReporter
4242
allocationReporter *ProfileReporter
4343
blockReporter *ProfileReporter
44-
segmentReporter *SegmentReporter
44+
spanReporter *SpanReporter
4545
errorReporter *ErrorReporter
4646

4747
profilerActive *Flag
@@ -78,7 +78,7 @@ func NewAgent() *Agent {
7878
cpuReporter: nil,
7979
allocationReporter: nil,
8080
blockReporter: nil,
81-
segmentReporter: nil,
81+
spanReporter: nil,
8282
errorReporter: nil,
8383

8484
profilerActive: &Flag{},
@@ -136,7 +136,7 @@ func NewAgent() *Agent {
136136
}
137137
a.blockReporter = newProfileReporter(a, blockProfiler, blockProfilerConfig)
138138

139-
a.segmentReporter = newSegmentReporter(a)
139+
a.spanReporter = newSpanReporter(a)
140140
a.errorReporter = newErrorReporter(a)
141141

142142
return a
@@ -174,7 +174,7 @@ func (a *Agent) Enable() {
174174
a.cpuReporter.start()
175175
a.allocationReporter.start()
176176
a.blockReporter.start()
177-
a.segmentReporter.start()
177+
a.spanReporter.start()
178178
a.errorReporter.start()
179179
a.processReporter.start()
180180
a.config.setAgentEnabled(true)
@@ -187,7 +187,7 @@ func (a *Agent) Disable() {
187187
a.cpuReporter.stop()
188188
a.allocationReporter.stop()
189189
a.blockReporter.stop()
190-
a.segmentReporter.stop()
190+
a.spanReporter.stop()
191191
a.errorReporter.stop()
192192
a.processReporter.stop()
193193
}
@@ -210,12 +210,12 @@ func (a *Agent) StopProfiling() {
210210
a.blockReporter.stopProfiling()
211211
}
212212

213-
func (a *Agent) RecordSegment(name string, duration float64) {
213+
func (a *Agent) RecordSpan(name string, duration float64) {
214214
if !agentStarted {
215215
return
216216
}
217217

218-
a.segmentReporter.recordSegment(name, duration)
218+
a.spanReporter.recordSpan(name, duration)
219219
}
220220

221221
func (a *Agent) RecordError(group string, msg interface{}, skipFrames int) {

internal/config_loader.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -88,12 +88,12 @@ func (cl *ConfigLoader) load() {
8888
}
8989

9090
if cl.agent.config.isAgentEnabled() {
91-
cl.agent.segmentReporter.start()
91+
cl.agent.spanReporter.start()
9292
cl.agent.errorReporter.start()
9393
cl.agent.processReporter.start()
9494
cl.agent.log("Agent enabled")
9595
} else {
96-
cl.agent.segmentReporter.stop()
96+
cl.agent.spanReporter.stop()
9797
cl.agent.errorReporter.stop()
9898
cl.agent.processReporter.stop()
9999
cl.agent.log("Agent disabled")

internal/error_reporter.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ func (er *ErrorReporter) recordError(group string, err error, skip int) {
112112
er.recordLock.Lock()
113113
errorGraph, exists := er.errorGraphs[group]
114114
if !exists {
115-
// If segment was not created by other recordError call between locks, create it.
115+
// If error was not created by other recordError call between locks, create it.
116116
errorGraph = newBreakdownNode(group)
117117
er.errorGraphs[group] = errorGraph
118118
}

internal/metric.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,13 @@ const CategoryCPU string = "cpu"
1919
const CategoryMemory string = "memory"
2020
const CategoryGC string = "gc"
2121
const CategoryRuntime string = "runtime"
22+
const CategorySpan string = "span"
2223
const CategoryCPUProfile string = "cpu-profile"
2324
const CategoryMemoryProfile string = "memory-profile"
2425
const CategoryBlockProfile string = "block-profile"
2526
const CategoryLockProfile string = "lock-profile"
2627
const CategoryCPUTrace string = "cpu-trace"
2728
const CategoryBlockTrace string = "block-trace"
28-
const CategorySegmentTrace string = "segment-trace"
2929
const CategoryErrorProfile string = "error-profile"
3030

3131
const NameCPUTime string = "CPU time"

0 commit comments

Comments
 (0)