yabeda 0.12.0 → 0.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/workflows/lint.yml +8 -3
- data/.github/workflows/{build-release.yml → release.yml} +9 -5
- data/.github/workflows/test.yml +7 -16
- data/.rubocop.yml +3 -0
- data/CHANGELOG.md +44 -1
- data/Gemfile +2 -2
- data/README.md +37 -10
- data/lib/yabeda/counter.rb +2 -2
- data/lib/yabeda/dsl/class_methods.rb +11 -1
- data/lib/yabeda/gauge.rb +3 -3
- data/lib/yabeda/group.rb +7 -0
- data/lib/yabeda/histogram.rb +2 -2
- data/lib/yabeda/metric.rb +30 -1
- data/lib/yabeda/rspec/base_matcher.rb +17 -6
- data/lib/yabeda/rspec/increment_yabeda_counter.rb +14 -3
- data/lib/yabeda/rspec/measure_yabeda_histogram.rb +16 -2
- data/lib/yabeda/rspec/observe_yabeda_summary.rb +16 -2
- data/lib/yabeda/rspec/update_yabeda_gauge.rb +16 -2
- data/lib/yabeda/summary.rb +2 -2
- data/lib/yabeda/version.rb +1 -1
- data/lib/yabeda.rb +10 -6
- metadata +4 -4
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 8d2581bd55cdd41639a1c6f01d456c5e09e1ad7636253e92720d35242fde6fab
|
|
4
|
+
data.tar.gz: 02f88db1ee3d892e387129c8775ab1b31dbafe2ec97ea8a67c34ff6abf67dc1d
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 57c4e7b716b077e37b7191cf4bfcc4f7090943eab1922439d485e02bc925408f21db656e239545bd7836413fc219282e71553b4cbd88e02b80f272dc236bacfb
|
|
7
|
+
data.tar.gz: 63707a843e531b01e685e17f7772dcf718ab730d401396d936ade23a5f8e0a7699ddbf7799caca797afcb4ef0fb5c07cacfd362ff98f46949846f166de636b97
|
data/.github/workflows/lint.yml
CHANGED
|
@@ -3,7 +3,9 @@ name: Lint Ruby
|
|
|
3
3
|
on:
|
|
4
4
|
push:
|
|
5
5
|
branches:
|
|
6
|
-
-
|
|
6
|
+
- '**'
|
|
7
|
+
tags-ignore:
|
|
8
|
+
- 'v*'
|
|
7
9
|
paths:
|
|
8
10
|
- "gemfiles/*"
|
|
9
11
|
- "Gemfile"
|
|
@@ -20,12 +22,15 @@ on:
|
|
|
20
22
|
|
|
21
23
|
jobs:
|
|
22
24
|
rubocop:
|
|
25
|
+
# Skip running tests for local pull requests (use push event instead), run only for foreign ones
|
|
26
|
+
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.owner.login != github.event.pull_request.base.repo.owner.login
|
|
27
|
+
name: RuboCop
|
|
23
28
|
runs-on: ubuntu-latest
|
|
24
29
|
steps:
|
|
25
|
-
- uses: actions/checkout@
|
|
30
|
+
- uses: actions/checkout@v4
|
|
26
31
|
- uses: ruby/setup-ruby@v1
|
|
27
32
|
with:
|
|
28
|
-
ruby-version: 3.
|
|
33
|
+
ruby-version: "3.3"
|
|
29
34
|
bundler-cache: true
|
|
30
35
|
- name: Lint Ruby code with RuboCop
|
|
31
36
|
run: |
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
name: Build and release gem
|
|
1
|
+
name: Build and release gem
|
|
2
2
|
|
|
3
3
|
on:
|
|
4
4
|
push:
|
|
@@ -8,13 +8,17 @@ on:
|
|
|
8
8
|
jobs:
|
|
9
9
|
release:
|
|
10
10
|
runs-on: ubuntu-latest
|
|
11
|
+
permissions:
|
|
12
|
+
contents: write
|
|
13
|
+
id-token: write
|
|
14
|
+
packages: write
|
|
11
15
|
steps:
|
|
12
|
-
- uses: actions/checkout@
|
|
16
|
+
- uses: actions/checkout@v4
|
|
13
17
|
with:
|
|
14
18
|
fetch-depth: 0 # Fetch current tag as annotated. See https://github.com/actions/checkout/issues/290
|
|
15
19
|
- uses: ruby/setup-ruby@v1
|
|
16
20
|
with:
|
|
17
|
-
ruby-version:
|
|
21
|
+
ruby-version: "3.3"
|
|
18
22
|
- name: "Extract data from tag: version, message, body"
|
|
19
23
|
id: tag
|
|
20
24
|
run: |
|
|
@@ -75,8 +79,8 @@ jobs:
|
|
|
75
79
|
GEM_HOST_API_KEY: Bearer ${{ secrets.GITHUB_TOKEN }}
|
|
76
80
|
run: |
|
|
77
81
|
gem push yabeda-${{ steps.tag.outputs.version }}.gem --host https://rubygems.pkg.github.com/${{ github.repository_owner }}
|
|
82
|
+
- name: Configure RubyGems Credentials
|
|
83
|
+
uses: rubygems/configure-rubygems-credentials@main
|
|
78
84
|
- name: Publish to RubyGems
|
|
79
|
-
env:
|
|
80
|
-
GEM_HOST_API_KEY: "${{ secrets.RUBYGEMS_API_KEY }}"
|
|
81
85
|
run: |
|
|
82
86
|
gem push yabeda-${{ steps.tag.outputs.version }}.gem
|
data/.github/workflows/test.yml
CHANGED
|
@@ -11,32 +11,23 @@ on:
|
|
|
11
11
|
jobs:
|
|
12
12
|
test:
|
|
13
13
|
name: "Ruby ${{ matrix.ruby }}"
|
|
14
|
+
# Skip running tests for local pull requests (use push event instead), run only for foreign ones
|
|
15
|
+
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.owner.login != github.event.pull_request.base.repo.owner.login
|
|
14
16
|
runs-on: ubuntu-latest
|
|
15
17
|
strategy:
|
|
16
18
|
fail-fast: false
|
|
17
19
|
matrix:
|
|
18
20
|
include:
|
|
21
|
+
- ruby: "3.3"
|
|
19
22
|
- ruby: "3.2"
|
|
20
23
|
- ruby: "3.1"
|
|
21
24
|
- ruby: "3.0"
|
|
22
25
|
- ruby: "2.7"
|
|
23
|
-
container:
|
|
24
|
-
image: ruby:${{ matrix.ruby }}
|
|
25
|
-
env:
|
|
26
|
-
CI: true
|
|
27
26
|
steps:
|
|
28
|
-
- uses: actions/checkout@
|
|
29
|
-
- uses:
|
|
27
|
+
- uses: actions/checkout@v4
|
|
28
|
+
- uses: ruby/setup-ruby@v1
|
|
30
29
|
with:
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
restore-keys: |
|
|
34
|
-
bundle-${{ matrix.ruby }}-${{ hashFiles('**/*.gemspec') }}-${{ hashFiles('**/Gemfile') }}
|
|
35
|
-
bundle-${{ matrix.ruby }}-
|
|
36
|
-
- name: Bundle install
|
|
37
|
-
run: |
|
|
38
|
-
bundle config path vendor/bundle
|
|
39
|
-
bundle install
|
|
40
|
-
bundle update
|
|
30
|
+
ruby-version: ${{ matrix.ruby }}
|
|
31
|
+
bundler-cache: true
|
|
41
32
|
- name: Run RSpec
|
|
42
33
|
run: bundle exec rspec
|
data/.rubocop.yml
CHANGED
data/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,47 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
|
|
|
7
7
|
|
|
8
8
|
## Unreleased
|
|
9
9
|
|
|
10
|
+
## 0.13.0 - 2024-10-02
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- Ability to limit some metrics to specific adapters. [#37](https://github.com/yabeda-rb/yabeda/pull/37) by [@Keallar] and [@Envek]
|
|
15
|
+
|
|
16
|
+
```ruby
|
|
17
|
+
Yabeda.configure do
|
|
18
|
+
group :cloud do
|
|
19
|
+
adapter :newrelic, :datadog
|
|
20
|
+
|
|
21
|
+
counter :foo
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
counter :bar, adapter: :prometheus
|
|
25
|
+
end
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
- Multiple expectations in RSpec matchers. [@Envek]
|
|
29
|
+
|
|
30
|
+
```ruby
|
|
31
|
+
expect { whatever }.to increment_yabeda_counter(:my_counter).with(
|
|
32
|
+
{ tag: "foo" } => 1,
|
|
33
|
+
{ tag: "bar" } => (be >= 42),
|
|
34
|
+
)
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
### Changed
|
|
38
|
+
|
|
39
|
+
- Don't require to provide tags for counters and histograms, use empty tags (`{}`) by default. See discussion at [#26](https://github.com/yabeda-rb/yabeda/issues/26). [@Envek]
|
|
40
|
+
|
|
41
|
+
```ruby
|
|
42
|
+
Yabeda.foo.increment
|
|
43
|
+
# same as
|
|
44
|
+
Yabeda.foo.increment({}, by: 1)
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### Fixed
|
|
48
|
+
|
|
49
|
+
- Railtie loading to prevent calling methods that have not yet been defined. [#38](https://github.com/yabeda-rb/yabeda/pull/38) by [@bibendi].
|
|
50
|
+
|
|
10
51
|
## 0.12.0 - 2023-07-28
|
|
11
52
|
|
|
12
53
|
### Added
|
|
@@ -37,7 +78,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
|
|
|
37
78
|
|
|
38
79
|
### Changed
|
|
39
80
|
|
|
40
|
-
- Adapters now should use method `Yabeda.collect!` instead of manual calling of every collector block.
|
|
81
|
+
- Adapters now should use method `Yabeda.collect!` instead of manual calling of every collector block.
|
|
41
82
|
|
|
42
83
|
## 0.9.0 - 2021-05-07
|
|
43
84
|
|
|
@@ -140,3 +181,5 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
|
|
|
140
181
|
[@dsalahutdinov]: https://github.com/dsalahutdinov "Dmitry Salahutdinov"
|
|
141
182
|
[@asusikov]: https://github.com/asusikov "Alexander Susikov"
|
|
142
183
|
[@liaden]: https://github.com/liaden "Joel Johnson"
|
|
184
|
+
[@bibendi]: https://github.com/bibendi "Misha Merkushin"
|
|
185
|
+
[@Keallar]: https://github.com/Keallar "Eugene Lysanskiy"
|
data/Gemfile
CHANGED
data/README.md
CHANGED
|
@@ -130,6 +130,7 @@ These are developed and maintained by other awesome folks:
|
|
|
130
130
|
|
|
131
131
|
- [Statsd](https://github.com/asusikov/yabeda-statsd)
|
|
132
132
|
- [AWS CloudWatch](https://github.com/retsef/yabeda-cloudwatch)
|
|
133
|
+
- [Honeybadger Insights](https://github.com/honeybadger-io/yabeda-honeybadger_insights)
|
|
133
134
|
- _…and more! You can write your own adapter and open a pull request to add it into this list._
|
|
134
135
|
|
|
135
136
|
## Available plugins to collect metrics
|
|
@@ -156,6 +157,7 @@ These are developed and maintained by other awesome folks:
|
|
|
156
157
|
- [yabeda-activejob](https://github.com/Fullscript/yabeda-activejob) — backend-agnostic metrics for background jobs.
|
|
157
158
|
- [yabeda-shoryuken](https://github.com/retsef/yabeda-shoryuken) — metrics for [Shoryuken](https://github.com/ruby-shoryuken/shoryuken) jobs execution message queues.
|
|
158
159
|
- [yabeda-rack-ratelimit](https://github.com/basecamp/yabeda-rack-ratelimit) — metrics for [Rack::Ratelimit](https://github.com/jeremy/rack-ratelimit)
|
|
160
|
+
- [yabeda-hanami](https://github.com/mlibrary/yabeda-hanami) — metrics for [Hanami](https://hanamirb.org/) The web, with simplicity.
|
|
159
161
|
- _…and more! You can write your own adapter and open a pull request to add it into this list._
|
|
160
162
|
|
|
161
163
|
## Configuration
|
|
@@ -210,6 +212,41 @@ expect { subject }.to \
|
|
|
210
212
|
with(be_between(0.005, 0.05))
|
|
211
213
|
```
|
|
212
214
|
|
|
215
|
+
You also can specify multiple tags and their expected values in `with`:
|
|
216
|
+
|
|
217
|
+
```ruby
|
|
218
|
+
expect { whatever }.to increment_yabeda_counter(:my_counter).with(
|
|
219
|
+
{ tag: "foo" } => 1,
|
|
220
|
+
{ tag: "bar" } => (be >= 42),
|
|
221
|
+
)
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
## Advanced usage
|
|
225
|
+
|
|
226
|
+
### Limiting metrics and groups to specific adapters
|
|
227
|
+
|
|
228
|
+
You can limit, which metrics and groups should be available for specific adapter:
|
|
229
|
+
|
|
230
|
+
```ruby
|
|
231
|
+
Yabeda.configure do
|
|
232
|
+
group :internal do
|
|
233
|
+
adapter :prometheus
|
|
234
|
+
|
|
235
|
+
counter :foo
|
|
236
|
+
gauge :bar
|
|
237
|
+
end
|
|
238
|
+
|
|
239
|
+
group :cloud do
|
|
240
|
+
adapter :newrelic
|
|
241
|
+
|
|
242
|
+
counter :baz
|
|
243
|
+
end
|
|
244
|
+
|
|
245
|
+
counter :qux, adapter: :prometheus
|
|
246
|
+
end
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
|
|
213
250
|
## Roadmap (aka TODO or Help wanted)
|
|
214
251
|
|
|
215
252
|
- Ability to change metric settings for individual adapters
|
|
@@ -222,16 +259,6 @@ expect { subject }.to \
|
|
|
222
259
|
end
|
|
223
260
|
```
|
|
224
261
|
|
|
225
|
-
- Ability to route some metrics only for given adapter:
|
|
226
|
-
|
|
227
|
-
```rb
|
|
228
|
-
adapter :prometheus do
|
|
229
|
-
include_group :sidekiq
|
|
230
|
-
end
|
|
231
|
-
```
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
262
|
## Development
|
|
236
263
|
|
|
237
264
|
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
data/lib/yabeda/counter.rb
CHANGED
|
@@ -3,10 +3,10 @@
|
|
|
3
3
|
module Yabeda
|
|
4
4
|
# Growing-only counter
|
|
5
5
|
class Counter < Metric
|
|
6
|
-
def increment(tags, by: 1)
|
|
6
|
+
def increment(tags = {}, by: 1)
|
|
7
7
|
all_tags = ::Yabeda::Tags.build(tags, group)
|
|
8
8
|
values[all_tags] += by
|
|
9
|
-
|
|
9
|
+
adapters.each_value do |adapter|
|
|
10
10
|
adapter.perform_counter_increment!(self, all_tags, by)
|
|
11
11
|
end
|
|
12
12
|
values[all_tags]
|
|
@@ -92,6 +92,16 @@ module Yabeda
|
|
|
92
92
|
Thread.current[:yabeda_temporary_tags] ||= {}
|
|
93
93
|
end
|
|
94
94
|
|
|
95
|
+
# Limit all group metrics to specific adapters only
|
|
96
|
+
#
|
|
97
|
+
# @param adapter_names [Array<Symbol>] Names of adapters to use
|
|
98
|
+
def adapter(*adapter_names, group: @group)
|
|
99
|
+
raise ConfigurationError, "Adapter limitation can't be defined outside of group" unless group
|
|
100
|
+
|
|
101
|
+
Yabeda.groups[group] ||= Yabeda::Group.new(group)
|
|
102
|
+
Yabeda.groups[group].adapter(*adapter_names)
|
|
103
|
+
end
|
|
104
|
+
|
|
95
105
|
private
|
|
96
106
|
|
|
97
107
|
def register_metric(metric)
|
|
@@ -99,7 +109,7 @@ module Yabeda
|
|
|
99
109
|
::Yabeda.define_singleton_method(name) { metric }
|
|
100
110
|
::Yabeda.metrics[name] = metric
|
|
101
111
|
register_group_for(metric) if metric.group
|
|
102
|
-
|
|
112
|
+
metric.adapters.each_value { |adapter| adapter.register!(metric) } if ::Yabeda.configured?
|
|
103
113
|
metric
|
|
104
114
|
end
|
|
105
115
|
|
data/lib/yabeda/gauge.rb
CHANGED
|
@@ -6,17 +6,17 @@ module Yabeda
|
|
|
6
6
|
def set(tags, value)
|
|
7
7
|
all_tags = ::Yabeda::Tags.build(tags, group)
|
|
8
8
|
values[all_tags] = value
|
|
9
|
-
|
|
9
|
+
adapters.each_value do |adapter|
|
|
10
10
|
adapter.perform_gauge_set!(self, all_tags, value)
|
|
11
11
|
end
|
|
12
12
|
value
|
|
13
13
|
end
|
|
14
14
|
|
|
15
|
-
def increment(tags, by: 1)
|
|
15
|
+
def increment(tags = {}, by: 1)
|
|
16
16
|
set(tags, get(tags).to_i + by)
|
|
17
17
|
end
|
|
18
18
|
|
|
19
|
-
def decrement(tags, by: 1)
|
|
19
|
+
def decrement(tags = {}, by: 1)
|
|
20
20
|
set(tags, get(tags).to_i - by)
|
|
21
21
|
end
|
|
22
22
|
end
|
data/lib/yabeda/group.rb
CHANGED
|
@@ -19,6 +19,13 @@ module Yabeda
|
|
|
19
19
|
@default_tags[key] = value
|
|
20
20
|
end
|
|
21
21
|
|
|
22
|
+
def adapter(*adapter_names)
|
|
23
|
+
return @adapter if adapter_names.empty?
|
|
24
|
+
|
|
25
|
+
@adapter ||= Concurrent::Array.new
|
|
26
|
+
@adapter.push(*adapter_names)
|
|
27
|
+
end
|
|
28
|
+
|
|
22
29
|
def register_metric(metric)
|
|
23
30
|
define_singleton_method(metric.name) { metric }
|
|
24
31
|
end
|
data/lib/yabeda/histogram.rb
CHANGED
|
@@ -7,7 +7,7 @@ module Yabeda
|
|
|
7
7
|
option :buckets
|
|
8
8
|
|
|
9
9
|
# rubocop: disable Metrics/MethodLength
|
|
10
|
-
def measure(tags, value = nil)
|
|
10
|
+
def measure(tags = {}, value = nil)
|
|
11
11
|
if value.nil? ^ block_given?
|
|
12
12
|
raise ArgumentError, "You must provide either numeric value or block for Yabeda::Histogram#measure!"
|
|
13
13
|
end
|
|
@@ -20,7 +20,7 @@ module Yabeda
|
|
|
20
20
|
|
|
21
21
|
all_tags = ::Yabeda::Tags.build(tags, group)
|
|
22
22
|
values[all_tags] = value
|
|
23
|
-
|
|
23
|
+
adapters.each_value do |adapter|
|
|
24
24
|
adapter.perform_histogram_measure!(self, all_tags, value)
|
|
25
25
|
end
|
|
26
26
|
value
|
data/lib/yabeda/metric.rb
CHANGED
|
@@ -14,6 +14,9 @@ module Yabeda
|
|
|
14
14
|
option :per, optional: true, comment: "Per which unit is measured `unit`. E.g. `call` as in seconds per call"
|
|
15
15
|
option :group, optional: true, comment: "Category name for grouping metrics"
|
|
16
16
|
option :aggregation, optional: true, comment: "How adapters should aggregate values from different processes"
|
|
17
|
+
# rubocop:disable Layout/LineLength
|
|
18
|
+
option :adapter, optional: true, comment: "Monitoring system adapter to register metric in and report metric values to (other adapters won't be used)"
|
|
19
|
+
# rubocop:enable Layout/LineLength
|
|
17
20
|
|
|
18
21
|
# Returns the value for the given label set
|
|
19
22
|
def get(labels = {})
|
|
@@ -25,7 +28,7 @@ module Yabeda
|
|
|
25
28
|
end
|
|
26
29
|
|
|
27
30
|
# Returns allowed tags for metric (with account for global and group-level +default_tags+)
|
|
28
|
-
# @return Array<Symbol>
|
|
31
|
+
# @return [Array<Symbol>]
|
|
29
32
|
def tags
|
|
30
33
|
(Yabeda.groups[group].default_tags.keys + Array(super)).uniq
|
|
31
34
|
end
|
|
@@ -33,5 +36,31 @@ module Yabeda
|
|
|
33
36
|
def inspect
|
|
34
37
|
"#<#{self.class.name}: #{[@group, @name].compact.join('.')}>"
|
|
35
38
|
end
|
|
39
|
+
|
|
40
|
+
# Returns the metric adapters
|
|
41
|
+
# @return [Hash<Symbol, Yabeda::BaseAdapter>]
|
|
42
|
+
def adapters
|
|
43
|
+
return ::Yabeda.adapters unless adapter
|
|
44
|
+
|
|
45
|
+
@adapters ||= begin
|
|
46
|
+
adapter_names = Array(adapter)
|
|
47
|
+
unknown_adapters = adapter_names - ::Yabeda.adapters.keys
|
|
48
|
+
|
|
49
|
+
if unknown_adapters.any?
|
|
50
|
+
raise ConfigurationError,
|
|
51
|
+
"invalid adapter option #{adapter.inspect} in metric #{inspect}"
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
::Yabeda.adapters.slice(*adapter_names)
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
# Redefined option reader to get group-level adapter if not set on metric level
|
|
59
|
+
# @api private
|
|
60
|
+
def adapter
|
|
61
|
+
return ::Yabeda.groups[group]&.adapter if @adapter == Dry::Initializer::UNDEFINED
|
|
62
|
+
|
|
63
|
+
super
|
|
64
|
+
end
|
|
36
65
|
end
|
|
37
66
|
end
|
|
@@ -8,21 +8,30 @@ module Yabeda
|
|
|
8
8
|
# Example:
|
|
9
9
|
# expect { anything }.to do_whatever_with_yabeda_metric(Yabeda.something)
|
|
10
10
|
class BaseMatcher < ::RSpec::Matchers::BuiltIn::BaseMatcher
|
|
11
|
-
attr_reader :tags, :metric
|
|
11
|
+
attr_reader :tags, :metric, :expectations
|
|
12
12
|
|
|
13
13
|
# Specify a scope of labels (tags). Subset of tags can be specified.
|
|
14
14
|
def with_tags(tags)
|
|
15
|
+
raise ArgumentError, "Can't use `with_tags` with expectations hash provided" if !@tags && @expectations&.any?
|
|
16
|
+
|
|
15
17
|
@tags = tags
|
|
18
|
+
@expectations = { tags => nil }
|
|
19
|
+
self
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def with(expectations)
|
|
23
|
+
@expectations = expectations || {}
|
|
16
24
|
self
|
|
17
25
|
end
|
|
18
26
|
|
|
19
|
-
def initialize(
|
|
27
|
+
def initialize(metric)
|
|
20
28
|
super
|
|
21
|
-
@expected = @metric = resolve_metric(
|
|
29
|
+
@expected = @metric = resolve_metric(metric)
|
|
30
|
+
@expectations = {}
|
|
22
31
|
rescue KeyError
|
|
23
32
|
raise ArgumentError, <<~MSG
|
|
24
33
|
Pass metric name or metric instance to matcher (e.g. `increment_yabeda_counter(Yabeda.metric_name)` or \
|
|
25
|
-
increment_yabeda_counter('metric_name')). Got #{
|
|
34
|
+
increment_yabeda_counter('metric_name')). Got #{metric.inspect} instead
|
|
26
35
|
MSG
|
|
27
36
|
end
|
|
28
37
|
|
|
@@ -56,9 +65,11 @@ module Yabeda
|
|
|
56
65
|
# Filter metric changes by tags.
|
|
57
66
|
# If tags specified, treat them as subset of real tags (to avoid bothering with default tags in tests)
|
|
58
67
|
def filter_matching_changes(changes)
|
|
59
|
-
return changes
|
|
68
|
+
return changes.map { |tags, change| [tags, [nil, change]] }.to_h unless expectations&.any?
|
|
60
69
|
|
|
61
|
-
|
|
70
|
+
expectations.map do |tags, expected|
|
|
71
|
+
[tags, [expected, changes.find { |t, _v| t >= tags }&.[](1)]]
|
|
72
|
+
end.to_h
|
|
62
73
|
end
|
|
63
74
|
end
|
|
64
75
|
end
|
|
@@ -15,6 +15,7 @@ module Yabeda
|
|
|
15
15
|
class IncrementYabedaCounter < BaseMatcher
|
|
16
16
|
def by(increment)
|
|
17
17
|
@expected_increment = increment
|
|
18
|
+
@expectations = { tags => increment } if tags
|
|
18
19
|
self
|
|
19
20
|
end
|
|
20
21
|
|
|
@@ -32,8 +33,12 @@ module Yabeda
|
|
|
32
33
|
|
|
33
34
|
increments = filter_matching_changes(Yabeda::TestAdapter.instance.counters.fetch(metric))
|
|
34
35
|
|
|
35
|
-
increments.
|
|
36
|
-
|
|
36
|
+
return false if increments.empty?
|
|
37
|
+
|
|
38
|
+
increments.values.all? do |expected_increment, actual_increment|
|
|
39
|
+
next !actual_increment.nil? if expected_increment.nil?
|
|
40
|
+
|
|
41
|
+
values_match?(expected_increment, actual_increment)
|
|
37
42
|
end
|
|
38
43
|
end
|
|
39
44
|
|
|
@@ -49,13 +54,16 @@ module Yabeda
|
|
|
49
54
|
|
|
50
55
|
increments = filter_matching_changes(Yabeda::TestAdapter.instance.counters.fetch(metric))
|
|
51
56
|
|
|
52
|
-
increments.none?
|
|
57
|
+
increments.none? { |_tags, (_expected, actual)| !actual.nil? }
|
|
53
58
|
end
|
|
54
59
|
|
|
55
60
|
def failure_message
|
|
56
61
|
"expected #{expected_formatted} " \
|
|
57
62
|
"to be incremented #{"by #{description_of(expected_increment)} " unless expected_increment.nil?}" \
|
|
58
63
|
"#{"with tags #{::RSpec::Support::ObjectFormatter.format(tags)} " if tags}" \
|
|
64
|
+
"#{if !tags && expectations
|
|
65
|
+
"with following expectations: #{::RSpec::Support::ObjectFormatter.format(expectations)} "
|
|
66
|
+
end}" \
|
|
59
67
|
"but #{actual_increments_message}"
|
|
60
68
|
end
|
|
61
69
|
|
|
@@ -63,6 +71,9 @@ module Yabeda
|
|
|
63
71
|
"expected #{expected_formatted} " \
|
|
64
72
|
"not to be incremented " \
|
|
65
73
|
"#{"with tags #{::RSpec::Support::ObjectFormatter.format(tags)} " if tags}" \
|
|
74
|
+
"#{if !tags && expectations
|
|
75
|
+
"with following expectations: #{::RSpec::Support::ObjectFormatter.format(expectations)} "
|
|
76
|
+
end}" \
|
|
66
77
|
"but #{actual_increments_message}"
|
|
67
78
|
end
|
|
68
79
|
|
|
@@ -14,6 +14,8 @@ module Yabeda
|
|
|
14
14
|
# Custom matcher class with implementation for +measure_yabeda_histogram+
|
|
15
15
|
class MeasureYabedaHistogram < BaseMatcher
|
|
16
16
|
def with(value)
|
|
17
|
+
return super if value.is_a?(Hash)
|
|
18
|
+
|
|
17
19
|
@expected_value = value
|
|
18
20
|
self
|
|
19
21
|
end
|
|
@@ -32,7 +34,13 @@ module Yabeda
|
|
|
32
34
|
|
|
33
35
|
measures = filter_matching_changes(Yabeda::TestAdapter.instance.histograms.fetch(metric))
|
|
34
36
|
|
|
35
|
-
|
|
37
|
+
return false if measures.empty?
|
|
38
|
+
|
|
39
|
+
measures.values.all? do |expected_measure, actual_measure|
|
|
40
|
+
next !actual_measure.nil? if expected_measure.nil?
|
|
41
|
+
|
|
42
|
+
values_match?(expected_measure, actual_measure)
|
|
43
|
+
end
|
|
36
44
|
end
|
|
37
45
|
|
|
38
46
|
def match_when_negated(metric, block)
|
|
@@ -47,13 +55,16 @@ module Yabeda
|
|
|
47
55
|
|
|
48
56
|
measures = filter_matching_changes(Yabeda::TestAdapter.instance.histograms.fetch(metric))
|
|
49
57
|
|
|
50
|
-
measures.none?
|
|
58
|
+
measures.none? { |_tags, (_expected, actual)| !actual.nil? }
|
|
51
59
|
end
|
|
52
60
|
|
|
53
61
|
def failure_message
|
|
54
62
|
"expected #{expected_formatted} " \
|
|
55
63
|
"to be changed #{"to #{expected} " unless expected_value.nil?}" \
|
|
56
64
|
"#{"with tags #{::RSpec::Support::ObjectFormatter.format(tags)} " if tags}" \
|
|
65
|
+
"#{if !tags && expectations
|
|
66
|
+
"with following expectations: #{::RSpec::Support::ObjectFormatter.format(expectations)} "
|
|
67
|
+
end}" \
|
|
57
68
|
"but #{actual_changes_message}"
|
|
58
69
|
end
|
|
59
70
|
|
|
@@ -61,6 +72,9 @@ module Yabeda
|
|
|
61
72
|
"expected #{expected_formatted} " \
|
|
62
73
|
"not to be incremented " \
|
|
63
74
|
"#{"with tags #{::RSpec::Support::ObjectFormatter.format(tags)} " if tags}" \
|
|
75
|
+
"#{if !tags && expectations
|
|
76
|
+
"with following expectations: #{::RSpec::Support::ObjectFormatter.format(expectations)} "
|
|
77
|
+
end}" \
|
|
64
78
|
"but #{actual_changes_message}"
|
|
65
79
|
end
|
|
66
80
|
|
|
@@ -14,6 +14,8 @@ module Yabeda
|
|
|
14
14
|
# Custom matcher class with implementation for +observe_yabeda_summary+
|
|
15
15
|
class ObserveYabedaSummary < BaseMatcher
|
|
16
16
|
def with(value)
|
|
17
|
+
return super if value.is_a?(Hash)
|
|
18
|
+
|
|
17
19
|
@expected_value = value
|
|
18
20
|
self
|
|
19
21
|
end
|
|
@@ -32,7 +34,13 @@ module Yabeda
|
|
|
32
34
|
|
|
33
35
|
observations = filter_matching_changes(Yabeda::TestAdapter.instance.summaries.fetch(metric))
|
|
34
36
|
|
|
35
|
-
|
|
37
|
+
return false if observations.empty?
|
|
38
|
+
|
|
39
|
+
observations.values.all? do |expected_observation, actual_observation|
|
|
40
|
+
next !actual_observation.nil? if expected_observation.nil?
|
|
41
|
+
|
|
42
|
+
values_match?(expected_observation, actual_observation)
|
|
43
|
+
end
|
|
36
44
|
end
|
|
37
45
|
|
|
38
46
|
def match_when_negated(metric, block)
|
|
@@ -47,13 +55,16 @@ module Yabeda
|
|
|
47
55
|
|
|
48
56
|
observations = filter_matching_changes(Yabeda::TestAdapter.instance.summaries.fetch(metric))
|
|
49
57
|
|
|
50
|
-
observations.none?
|
|
58
|
+
observations.none? { |_tags, (_expected, actual)| !actual.nil? }
|
|
51
59
|
end
|
|
52
60
|
|
|
53
61
|
def failure_message
|
|
54
62
|
"expected #{expected_formatted} " \
|
|
55
63
|
"to be observed #{"with #{expected} " unless expected_value.nil?}" \
|
|
56
64
|
"#{"with tags #{::RSpec::Support::ObjectFormatter.format(tags)} " if tags}" \
|
|
65
|
+
"#{if !tags && expectations
|
|
66
|
+
"with following expectations: #{::RSpec::Support::ObjectFormatter.format(expectations)} "
|
|
67
|
+
end}" \
|
|
57
68
|
"but #{actual_changes_message}"
|
|
58
69
|
end
|
|
59
70
|
|
|
@@ -61,6 +72,9 @@ module Yabeda
|
|
|
61
72
|
"expected #{expected_formatted} " \
|
|
62
73
|
"not to be observed " \
|
|
63
74
|
"#{"with tags #{::RSpec::Support::ObjectFormatter.format(tags)} " if tags}" \
|
|
75
|
+
"#{if !tags && expectations
|
|
76
|
+
"with following expectations: #{::RSpec::Support::ObjectFormatter.format(expectations)} "
|
|
77
|
+
end}" \
|
|
64
78
|
"but #{actual_changes_message}"
|
|
65
79
|
end
|
|
66
80
|
|
|
@@ -14,6 +14,8 @@ module Yabeda
|
|
|
14
14
|
# Custom matcher class with implementation for +update_yabeda_gauge+
|
|
15
15
|
class UpdateYabedaGauge < BaseMatcher
|
|
16
16
|
def with(value)
|
|
17
|
+
return super if value.is_a?(Hash)
|
|
18
|
+
|
|
17
19
|
@expected_value = value
|
|
18
20
|
self
|
|
19
21
|
end
|
|
@@ -32,7 +34,13 @@ module Yabeda
|
|
|
32
34
|
|
|
33
35
|
updates = filter_matching_changes(Yabeda::TestAdapter.instance.gauges.fetch(metric))
|
|
34
36
|
|
|
35
|
-
|
|
37
|
+
return false if updates.empty?
|
|
38
|
+
|
|
39
|
+
updates.values.all? do |expected_update, actual_update|
|
|
40
|
+
next !actual_update.nil? if expected_update.nil?
|
|
41
|
+
|
|
42
|
+
expected_update.nil? || values_match?(expected_update, actual_update)
|
|
43
|
+
end
|
|
36
44
|
end
|
|
37
45
|
|
|
38
46
|
def match_when_negated(metric, block)
|
|
@@ -47,13 +55,16 @@ module Yabeda
|
|
|
47
55
|
|
|
48
56
|
updates = filter_matching_changes(Yabeda::TestAdapter.instance.gauges.fetch(metric))
|
|
49
57
|
|
|
50
|
-
updates.none?
|
|
58
|
+
updates.none? { |_tags, (_expected, actual)| !actual.nil? }
|
|
51
59
|
end
|
|
52
60
|
|
|
53
61
|
def failure_message
|
|
54
62
|
"expected #{expected_formatted} " \
|
|
55
63
|
"to be changed #{"to #{expected_value} " unless expected_value.nil?}" \
|
|
56
64
|
"#{"with tags #{::RSpec::Support::ObjectFormatter.format(tags)} " if tags}" \
|
|
65
|
+
"#{if !tags && expectations
|
|
66
|
+
"with following expectations: #{::RSpec::Support::ObjectFormatter.format(expectations)} "
|
|
67
|
+
end}" \
|
|
57
68
|
"but #{actual_changes_message}"
|
|
58
69
|
end
|
|
59
70
|
|
|
@@ -61,6 +72,9 @@ module Yabeda
|
|
|
61
72
|
"expected #{expected_formatted} " \
|
|
62
73
|
"not to be changed " \
|
|
63
74
|
"#{"with tags #{::RSpec::Support::ObjectFormatter.format(tags)} " if tags}" \
|
|
75
|
+
"#{if !tags && expectations
|
|
76
|
+
"with following expectations: #{::RSpec::Support::ObjectFormatter.format(expectations)} "
|
|
77
|
+
end}" \
|
|
64
78
|
"but #{actual_changes_message}"
|
|
65
79
|
end
|
|
66
80
|
|
data/lib/yabeda/summary.rb
CHANGED
|
@@ -5,7 +5,7 @@ module Yabeda
|
|
|
5
5
|
# calculate averages, percentiles, and so on.
|
|
6
6
|
class Summary < Metric
|
|
7
7
|
# rubocop: disable Metrics/MethodLength
|
|
8
|
-
def observe(tags, value = nil)
|
|
8
|
+
def observe(tags = {}, value = nil)
|
|
9
9
|
if value.nil? ^ block_given?
|
|
10
10
|
raise ArgumentError, "You must provide either numeric value or block for Yabeda::Summary#observe!"
|
|
11
11
|
end
|
|
@@ -18,7 +18,7 @@ module Yabeda
|
|
|
18
18
|
|
|
19
19
|
all_tags = ::Yabeda::Tags.build(tags, group)
|
|
20
20
|
values[all_tags] = value
|
|
21
|
-
|
|
21
|
+
adapters.each_value do |adapter|
|
|
22
22
|
adapter.perform_summary_observe!(self, all_tags, value)
|
|
23
23
|
end
|
|
24
24
|
value
|
data/lib/yabeda/version.rb
CHANGED
data/lib/yabeda.rb
CHANGED
|
@@ -8,7 +8,6 @@ require "yabeda/config"
|
|
|
8
8
|
require "yabeda/dsl"
|
|
9
9
|
require "yabeda/tags"
|
|
10
10
|
require "yabeda/errors"
|
|
11
|
-
require "yabeda/railtie" if defined?(Rails)
|
|
12
11
|
|
|
13
12
|
# Extendable framework for collecting and exporting metrics from Ruby apps
|
|
14
13
|
module Yabeda
|
|
@@ -29,7 +28,7 @@ module Yabeda
|
|
|
29
28
|
end
|
|
30
29
|
end
|
|
31
30
|
|
|
32
|
-
# @return [Hash<
|
|
31
|
+
# @return [Hash<Symbol, Yabeda::BaseAdapter>] All loaded adapters
|
|
33
32
|
def adapters
|
|
34
33
|
@adapters ||= Concurrent::Hash.new
|
|
35
34
|
end
|
|
@@ -68,7 +67,9 @@ module Yabeda
|
|
|
68
67
|
def register_adapter(name, instance)
|
|
69
68
|
adapters[name] = instance
|
|
70
69
|
# NOTE: Pretty sure there is race condition
|
|
71
|
-
metrics.
|
|
70
|
+
metrics.each_value do |metric|
|
|
71
|
+
next unless metric.adapters.key?(name)
|
|
72
|
+
|
|
72
73
|
instance.register!(metric)
|
|
73
74
|
end
|
|
74
75
|
end
|
|
@@ -100,8 +101,8 @@ module Yabeda
|
|
|
100
101
|
|
|
101
102
|
# Register metrics in adapters after evaluating all configuration blocks
|
|
102
103
|
# to ensure that all global settings (like default tags) will be applied.
|
|
103
|
-
|
|
104
|
-
|
|
104
|
+
metrics.each_value do |metric|
|
|
105
|
+
metric.adapters.each_value do |adapter|
|
|
105
106
|
adapter.register!(metric)
|
|
106
107
|
end
|
|
107
108
|
end
|
|
@@ -129,7 +130,6 @@ module Yabeda
|
|
|
129
130
|
|
|
130
131
|
true
|
|
131
132
|
end
|
|
132
|
-
# rubocop: enable Metrics/MethodLength
|
|
133
133
|
|
|
134
134
|
# Forget all the configuration.
|
|
135
135
|
# For testing purposes as it doesn't rollback changes in adapters.
|
|
@@ -143,8 +143,12 @@ module Yabeda
|
|
|
143
143
|
@metrics = nil
|
|
144
144
|
collectors.clear
|
|
145
145
|
configurators.clear
|
|
146
|
+
@config = Config.new
|
|
146
147
|
instance_variable_set(:@configured_by, nil)
|
|
147
148
|
instance_variable_set(:@debug_was_enabled_by, nil)
|
|
148
149
|
end
|
|
150
|
+
# rubocop: enable Metrics/MethodLength
|
|
149
151
|
end
|
|
150
152
|
end
|
|
153
|
+
|
|
154
|
+
require "yabeda/railtie" if defined?(Rails)
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: yabeda
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.13.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Andrey Novikov
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2024-10-02 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: anyway_config
|
|
@@ -68,8 +68,8 @@ executables: []
|
|
|
68
68
|
extensions: []
|
|
69
69
|
extra_rdoc_files: []
|
|
70
70
|
files:
|
|
71
|
-
- ".github/workflows/build-release.yml"
|
|
72
71
|
- ".github/workflows/lint.yml"
|
|
72
|
+
- ".github/workflows/release.yml"
|
|
73
73
|
- ".github/workflows/test.yml"
|
|
74
74
|
- ".gitignore"
|
|
75
75
|
- ".rspec"
|
|
@@ -129,7 +129,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
129
129
|
- !ruby/object:Gem::Version
|
|
130
130
|
version: '0'
|
|
131
131
|
requirements: []
|
|
132
|
-
rubygems_version: 3.
|
|
132
|
+
rubygems_version: 3.5.16
|
|
133
133
|
signing_key:
|
|
134
134
|
specification_version: 4
|
|
135
135
|
summary: Extensible framework for collecting metric for your Ruby application
|