Skip to content

Commit 2084f86

Browse files
committed
new monitoring metric - engine_LastMaxActiveRequests
58de492a9e1d14a374ca14ef471701c1fdbc8cac
1 parent 5b8e11e commit 2084f86

16 files changed

Lines changed: 108 additions & 75 deletions

File tree

.changes/v0.5.30.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
## v0.5.30 - 2024-07-10
2+
### Added
3+
* new monitoring metric - engine_LastMaxActiveRequests

.mapping.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
".changes/v0.5.27.md":"load/projects/pandora/.changes/v0.5.27.md",
2828
".changes/v0.5.28.md":"load/projects/pandora/.changes/v0.5.28.md",
2929
".changes/v0.5.29.md":"load/projects/pandora/.changes/v0.5.29.md",
30+
".changes/v0.5.30.md":"load/projects/pandora/.changes/v0.5.30.md",
3031
".changie.yaml":"load/projects/pandora/.changie.yaml",
3132
".github/actions/setup-yc/action.yml":"load/projects/pandora/.github/actions/setup-yc/action.yml",
3233
".github/workflows/pages.yml":"load/projects/pandora/.github/workflows/pages.yml",
@@ -466,6 +467,7 @@
466467
"lib/math/gcd_lcm.go":"load/projects/pandora/lib/math/gcd_lcm.go",
467468
"lib/math/gcd_lcm_test.go":"load/projects/pandora/lib/math/gcd_lcm_test.go",
468469
"lib/monitoring/counter.go":"load/projects/pandora/lib/monitoring/counter.go",
470+
"lib/monitoring/instance.go":"load/projects/pandora/lib/monitoring/instance.go",
469471
"lib/mp/iterator.go":"load/projects/pandora/lib/mp/iterator.go",
470472
"lib/mp/map.go":"load/projects/pandora/lib/mp/map.go",
471473
"lib/mp/map_test.go":"load/projects/pandora/lib/mp/map_test.go",

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html),
66
and is generated by [Changie](https://github.com/miniscruff/changie).
77

88

9+
## v0.5.30 - 2024-07-10
10+
### Added
11+
* new monitoring metric - engine_LastMaxActiveRequests
12+
913
## v0.5.29 - 2024-06-25
1014
### Added
1115
* HTTP scenario var/header postprocessor use multiple pipes

cli/cli.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ import (
2525
"go.uber.org/zap/zapcore"
2626
)
2727

28-
const Version = "0.5.29"
28+
const Version = "0.5.30"
2929
const defaultConfigFile = "load"
3030
const stdinConfigSelector = "-"
3131

@@ -122,7 +122,7 @@ func ReadConfigAndRunEngine() {
122122

123123
closeMonitoring := startMonitoring(conf.Monitoring)
124124
defer closeMonitoring()
125-
m := newEngineMetrics()
125+
m := engine.NewMetrics("engine")
126126
startReport(m)
127127

128128
pandora := engine.New(log, m, conf.Engine)

cli/expvar.go

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,20 +8,12 @@ import (
88
"go.uber.org/zap"
99
)
1010

11-
func newEngineMetrics() engine.Metrics {
12-
return engine.Metrics{
13-
Request: monitoring.NewCounter("engine_Requests"),
14-
Response: monitoring.NewCounter("engine_Responses"),
15-
InstanceStart: monitoring.NewCounter("engine_UsersStarted"),
16-
InstanceFinish: monitoring.NewCounter("engine_UsersFinished"),
17-
}
18-
}
19-
2011
func startReport(m engine.Metrics) {
2112
evReqPS := monitoring.NewCounter("engine_ReqPS")
2213
evResPS := monitoring.NewCounter("engine_ResPS")
2314
evActiveUsers := monitoring.NewCounter("engine_ActiveUsers")
2415
evActiveRequests := monitoring.NewCounter("engine_ActiveRequests")
16+
evLastMaxActiveRequests := monitoring.NewCounter("engine_LastMaxActiveRequests")
2517
requests := m.Request.Get()
2618
responses := m.Response.Get()
2719
go func() {
@@ -36,15 +28,17 @@ func startReport(m engine.Metrics) {
3628
reqps := requestsNew - requests
3729
activeUsers := m.InstanceStart.Get() - m.InstanceFinish.Get()
3830
activeRequests := requestsNew - responsesNew
31+
lastMaxActiveRequests := int64(m.BusyInstances.Flush())
3932
zap.S().Infof(
4033
"[ENGINE] %d resp/s; %d req/s; %d users; %d active\n",
41-
rps, reqps, activeUsers, activeRequests)
34+
rps, reqps, activeUsers, lastMaxActiveRequests)
4235

4336
requests = requestsNew
4437
responses = responsesNew
4538

4639
evActiveUsers.Set(activeUsers)
4740
evActiveRequests.Set(activeRequests)
41+
evLastMaxActiveRequests.Set(lastMaxActiveRequests)
4842
evReqPS.Set(reqps)
4943
evResPS.Set(rps)
5044
}

components/guns/http/base_test.go

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ import (
1919
"github.com/yandex/pandora/core/aggregator/netsample"
2020
"github.com/yandex/pandora/core/coretest"
2121
"github.com/yandex/pandora/core/engine"
22-
"github.com/yandex/pandora/lib/monitoring"
2322
"github.com/yandex/pandora/lib/testutil"
2423
"go.uber.org/zap"
2524
"go.uber.org/zap/zapcore"
@@ -35,15 +34,6 @@ func newLogger() *zap.Logger {
3534
return log
3635
}
3736

38-
func newEngineMetrics(prefix string) engine.Metrics {
39-
return engine.Metrics{
40-
Request: monitoring.NewCounter(prefix + "_Requests"),
41-
Response: monitoring.NewCounter(prefix + "_Responses"),
42-
InstanceStart: monitoring.NewCounter(prefix + "_UsersStarted"),
43-
InstanceFinish: monitoring.NewCounter(prefix + "_UsersFinished"),
44-
}
45-
}
46-
4737
func TestGunSuite(t *testing.T) {
4838
suite.Run(t, new(BaseGunSuite))
4939
}
@@ -59,7 +49,7 @@ type BaseGunSuite struct {
5949

6050
func (s *BaseGunSuite) SetupSuite() {
6151
s.log = testutil.NewLogger()
62-
s.metrics = newEngineMetrics("http_suite")
52+
s.metrics = engine.NewMetrics("http_suite")
6353
}
6454

6555
func (s *BaseGunSuite) SetupTest() {

core/engine/engine.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,16 @@ type InstancePoolConfig struct {
2929
DiscardOverflow bool `config:"discard_overflow"`
3030
}
3131

32+
func NewMetrics(prefix string) Metrics {
33+
return Metrics{
34+
Request: monitoring.NewCounter(prefix + "_Requests"),
35+
Response: monitoring.NewCounter(prefix + "_Responses"),
36+
InstanceStart: monitoring.NewCounter(prefix + "_UsersStarted"),
37+
InstanceFinish: monitoring.NewCounter(prefix + "_UsersFinished"),
38+
BusyInstances: monitoring.NewInstanceTracker(prefix + "_BusyInstances"),
39+
}
40+
}
41+
3242
// TODO(skipor): use something github.com/rcrowley/go-metrics based.
3343
// Its high level primitives like Meter can be not fast enough, but EWMAs
3444
// and Counters should good for that.
@@ -37,6 +47,7 @@ type Metrics struct {
3747
Response *monitoring.Counter
3848
InstanceStart *monitoring.Counter
3949
InstanceFinish *monitoring.Counter
50+
BusyInstances *monitoring.InstanceTracker
4051
}
4152

4253
func New(log *zap.Logger, m Metrics, conf Config) *Engine {

core/engine/engine_test.go

Lines changed: 18 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ import (
1717
coremock "github.com/yandex/pandora/core/mocks"
1818
"github.com/yandex/pandora/core/provider"
1919
"github.com/yandex/pandora/core/schedule"
20-
"github.com/yandex/pandora/lib/monitoring"
2120
"go.uber.org/atomic"
2221
"go.uber.org/zap"
2322
"go.uber.org/zap/zapcore"
@@ -83,15 +82,15 @@ func Test_InstancePool(t *testing.T) {
8382
waitDoneCalled.Store(false)
8483
ctx, cancel = context.WithCancel(context.Background())
8584
}
86-
var justBeforeEach = func() {
87-
metrics := newTestMetrics()
85+
var justBeforeEach = func(metricPrefix string) {
86+
metrics := NewMetrics(metricPrefix)
8887
p = newPool(newNopLogger(), metrics, onWaitDone, conf)
8988
}
9089
_ = cancel
9190

9291
t.Run("shoot ok", func(t *testing.T) {
9392
beforeEach()
94-
justBeforeEach()
93+
justBeforeEach("shoot-ok")
9594

9695
err := p.Run(ctx)
9796
require.NoError(t, err)
@@ -121,7 +120,7 @@ func Test_InstancePool(t *testing.T) {
121120

122121
beforeEach()
123122
beforeEachContext()
124-
justBeforeEach()
123+
justBeforeEach("context-canceled")
125124

126125
err := p.Run(ctx)
127126
require.Equal(t, context.Canceled, err)
@@ -170,7 +169,7 @@ func Test_InstancePool(t *testing.T) {
170169
})
171170
conf.Aggregator = aggr
172171

173-
justBeforeEach()
172+
justBeforeEach("provider-failed")
174173

175174
err := p.Run(ctx)
176175
require.Error(t, err)
@@ -201,7 +200,7 @@ func Test_InstancePool(t *testing.T) {
201200
aggr := &coremock.Aggregator{}
202201
aggr.On("Run", mock.Anything, mock.Anything).Return(failErr)
203202
conf.Aggregator = aggr
204-
justBeforeEach()
203+
justBeforeEach("aggregator-failed")
205204

206205
err := p.Run(ctx)
207206
require.Error(t, err)
@@ -227,7 +226,7 @@ func Test_InstancePool(t *testing.T) {
227226
conf.NewGun = func() (core.Gun, error) {
228227
return nil, failErr
229228
}
230-
justBeforeEach()
229+
justBeforeEach("start-instances-failed")
231230

232231
err := p.Run(ctx)
233232
require.Error(t, err)
@@ -259,7 +258,7 @@ func Test_MultipleInstance(t *testing.T) {
259258
schedule.NewOnce(2),
260259
schedule.NewConst(1, 5*time.Second),
261260
)
262-
pool := newPool(newNopLogger(), newTestMetrics(), nil, conf)
261+
pool := newPool(newNopLogger(), NewMetrics("test_engine_1"), nil, conf)
263262
ctx := context.Background()
264263

265264
err := pool.Run(ctx)
@@ -274,7 +273,7 @@ func Test_MultipleInstance(t *testing.T) {
274273
return schedule.NewOnce(1), nil
275274
}
276275
conf.StartupSchedule = schedule.NewOnce(3)
277-
pool := newPool(newNopLogger(), newTestMetrics(), nil, conf)
276+
pool := newPool(newNopLogger(), NewMetrics("test_engine_2"), nil, conf)
278277
ctx := context.Background()
279278

280279
err := pool.Run(ctx)
@@ -291,7 +290,7 @@ func Test_MultipleInstance(t *testing.T) {
291290
schedule.NewOnce(2),
292291
schedule.NewConst(1, 2*time.Second),
293292
)
294-
pool := newPool(newNopLogger(), newTestMetrics(), nil, conf)
293+
pool := newPool(newNopLogger(), NewMetrics("test_engine_3"), nil, conf)
295294
ctx := context.Background()
296295

297296
err := pool.Run(ctx)
@@ -319,14 +318,14 @@ func Test_Engine(t *testing.T) {
319318
ctx, cancel = context.WithCancel(context.Background())
320319
}
321320

322-
var justBeforeEach = func() {
323-
metrics := newTestMetrics()
321+
var justBeforeEach = func(metricPrefix string) {
322+
metrics := NewMetrics(metricPrefix)
324323
engine = New(newNopLogger(), metrics, Config{confs})
325324
}
326325

327326
t.Run("shoot ok", func(t *testing.T) {
328327
beforeEach()
329-
justBeforeEach()
328+
justBeforeEach("shoot-ok-2")
330329

331330
err := engine.Run(ctx)
332331
require.NoError(t, err)
@@ -361,7 +360,7 @@ func Test_Engine(t *testing.T) {
361360
}
362361
beforeEach()
363362
beforeEachCtx()
364-
justBeforeEach()
363+
justBeforeEach("context-canceled-2")
365364

366365
err := engine.Run(ctx)
367366
require.Equal(t, err, context.Canceled)
@@ -398,7 +397,7 @@ func Test_Engine(t *testing.T) {
398397
aggr.On("Run", mock.Anything, mock.Anything).Return(failErr)
399398
confs[0].Aggregator = aggr
400399

401-
justBeforeEach()
400+
justBeforeEach("one-pool-failed")
402401

403402
err := engine.Run(ctx)
404403
require.Error(t, err)
@@ -411,7 +410,7 @@ func Test_BuildInstanceSchedule(t *testing.T) {
411410
t.Run("per instance schedule", func(t *testing.T) {
412411
conf, _ := newTestPoolConf()
413412
conf.RPSPerInstance = true
414-
pool := newPool(newNopLogger(), newTestMetrics(), nil, conf)
413+
pool := newPool(newNopLogger(), NewMetrics("per-instance-schedule"), nil, conf)
415414
newInstanceSchedule, err := pool.buildNewInstanceSchedule(context.Background(), func() {
416415
panic("should not be called")
417416
})
@@ -428,7 +427,7 @@ func Test_BuildInstanceSchedule(t *testing.T) {
428427
conf.NewRPSSchedule = func() (core.Schedule, error) {
429428
return nil, scheduleCreateErr
430429
}
431-
pool := newPool(newNopLogger(), newTestMetrics(), nil, conf)
430+
pool := newPool(newNopLogger(), NewMetrics("shared-schedule-create-failed"), nil, conf)
432431
newInstanceSchedule, err := pool.buildNewInstanceSchedule(context.Background(), func() {
433432
panic("should not be called")
434433
})
@@ -446,7 +445,7 @@ func Test_BuildInstanceSchedule(t *testing.T) {
446445
newScheduleCalled = true
447446
return schedule.NewOnce(1), nil
448447
}
449-
pool := newPool(newNopLogger(), newTestMetrics(), nil, conf)
448+
pool := newPool(newNopLogger(), NewMetrics("shared-schedule-work"), nil, conf)
450449
ctx, cancel := context.WithCancel(context.Background())
451450
newInstanceSchedule, err := pool.buildNewInstanceSchedule(context.Background(), cancel)
452451
require.NoError(t, err)
@@ -532,12 +531,3 @@ func newNopLogger() *zap.Logger {
532531
log := zap.New(core)
533532
return log
534533
}
535-
536-
func newTestMetrics() Metrics {
537-
return Metrics{
538-
&monitoring.Counter{},
539-
&monitoring.Counter{},
540-
&monitoring.Counter{},
541-
&monitoring.Counter{},
542-
}
543-
}

core/engine/instance.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,8 @@ func (i *instance) Run(ctx context.Context) (recoverErr error) {
8888
}
8989
if !i.discardOverflow || !waiter.IsSlowDown(ctx) {
9090
i.metrics.Request.Add(1)
91+
i.metrics.BusyInstances.OnStart(i.id)
92+
defer i.metrics.BusyInstances.OnFinish(i.id)
9193
if tag.Debug {
9294
i.log.Debug("Shooting", zap.Any("ammo", ammo))
9395
}

core/engine/instance_test.go

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -32,15 +32,15 @@ func Test_Instance(t *testing.T) {
3232
newGun func() (core.Gun, error)
3333
)
3434

35-
var beforeEach = func() {
35+
var beforeEach = func(metricPrefix string) {
3636
provider = &coremock.Provider{}
3737
aggregator = &coremock.Aggregator{}
3838
gun = &coremock.Gun{}
3939
newGunErr = nil
4040
sched = &coremock.Schedule{}
4141
newScheduleErr = nil
4242
ctx = context.Background()
43-
metrics = newTestMetrics()
43+
metrics = NewMetrics(metricPrefix)
4444
newSchedule = func() (core.Schedule, error) { return sched, newScheduleErr }
4545
newGun = func() (core.Gun, error) { return gun, newGunErr }
4646
}
@@ -85,7 +85,7 @@ func Test_Instance(t *testing.T) {
8585
require.NoError(t, insCreateErr)
8686
}
8787
t.Run("start ok", func(t *testing.T) {
88-
beforeEach()
88+
beforeEach("start-ok")
8989
beforeEachCtx()
9090
justBeforeEachCtx()
9191
justBeforeEach()
@@ -99,7 +99,7 @@ func Test_Instance(t *testing.T) {
9999
})
100100

101101
t.Run("gun implements io.Closer / close called on instance close", func(t *testing.T) {
102-
beforeEach()
102+
beforeEach("gun-implements-io")
103103
beforeEachCtx()
104104
closeGun := mockGunCloser{gun}
105105
closeGun.On("Close").Return(nil)
@@ -122,7 +122,7 @@ func Test_Instance(t *testing.T) {
122122
})
123123

124124
t.Run("context canceled after run / start fail", func(t *testing.T) {
125-
beforeEach()
125+
beforeEach("context-canceled-after-run")
126126

127127
var cancel context.CancelFunc
128128
ctx, cancel = context.WithTimeout(context.Background(), 10*time.Millisecond)
@@ -146,7 +146,7 @@ func Test_Instance(t *testing.T) {
146146
})
147147

148148
t.Run("context canceled before run / nothing acquired and schedule not started", func(t *testing.T) {
149-
beforeEach()
149+
beforeEach("context-canceled-before-run")
150150
var cancel context.CancelFunc
151151
ctx, cancel = context.WithCancel(ctx)
152152
cancel()
@@ -162,7 +162,7 @@ func Test_Instance(t *testing.T) {
162162
})
163163

164164
t.Run("schedule create failed / instance create failed", func(t *testing.T) {
165-
beforeEach()
165+
beforeEach("schedule-create-failed")
166166
sched = nil
167167
newScheduleErr = errors.New("test err")
168168
justBeforeEach()
@@ -173,7 +173,7 @@ func Test_Instance(t *testing.T) {
173173
})
174174

175175
t.Run("gun create failed / instance create failed", func(t *testing.T) {
176-
beforeEach()
176+
beforeEach("gun-create-failed")
177177
gun = nil
178178
newGunErr = errors.New("test err")
179179
justBeforeEach()

0 commit comments

Comments
 (0)