yabeda 0.1.3 → 0.6.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a3a3991d4dbb2b060ba55ad682d20eb14012c8fb674cebc335e36ae5c0ab8067
4
- data.tar.gz: 56190b3fae34f414ba1afa58ec0ffc05ca36ee7c5f5209148b64a7a7a9936197
3
+ metadata.gz: 44b181b32e9a07ba7095d67d782e85587fd76280dae1ac5e0feb0a2e5c6ed2c4
4
+ data.tar.gz: 7c21877d04cc6e5284934619e22e47b75047000c9b1ccb6a936f07d4f5db6fb2
5
5
  SHA512:
6
- metadata.gz: def5c6a2dfaf0bff0b17aadb9af664fc5b36427c1b52eff208afc7a43f275691a32d3c2cea2c19c2abd5643339a788f78b7f30f9294a8c882897abd57d060bee
7
- data.tar.gz: 3548e381cf4b1b2fefe93d0211887e040022d02f4fbfc3a23f6404407bdb82e5b5a951a446d461a333978e5892054921593c4ea4a43de956ecefecf121408c0f
6
+ metadata.gz: e4dfbb234b9e84e911ec9c2d5b0477d144eed2c9904d06bed7a1f773646975a1f768277db68732750f2d2d91af509cc5d97b1dbff88f541ab28afb8ee7055c1e
7
+ data.tar.gz: eecd735270b91d2b8e204edbf547be8f77df5094123590a900c574cb54b2a3fe95eb9295940fab6e097abd396b45417f254269f4a84a9a82ed44b6bc296f0f0f
@@ -10,12 +10,9 @@ Metrics/BlockLength:
10
10
  - "Gemfile"
11
11
  - "spec/**/*"
12
12
 
13
- Metrics/LineLength:
13
+ Layout/LineLength:
14
14
  Max: 120
15
15
 
16
- Style/BracesAroundHashParameters:
17
- EnforcedStyle: context_dependent
18
-
19
16
  Style/StringLiterals:
20
17
  EnforcedStyle: double_quotes
21
18
 
@@ -47,3 +44,11 @@ Style/TrailingCommaInHashLiteral:
47
44
  Enabled: true
48
45
  EnforcedStyleForMultiline: consistent_comma
49
46
 
47
+ Style/HashEachMethods:
48
+ Enabled: true
49
+
50
+ Style/HashTransformKeys:
51
+ Enabled: true
52
+
53
+ Style/HashTransformValues:
54
+ Enabled: true
@@ -1,9 +1,9 @@
1
1
  ---
2
- sudo: false
3
2
  language: ruby
4
3
  cache: bundler
5
4
  rvm:
6
- - 2.5.3
7
- - 2.4.5
8
- - 2.3.8
9
- before_install: gem install bundler -v 1.17.0
5
+ - 2.7.0
6
+ - 2.6.5
7
+ - 2.5.7
8
+ - 2.4.9
9
+ before_install: gem install bundler -v "~> 2.0"
@@ -5,6 +5,45 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
6
6
  and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## 0.6.0 - 2020-07-15
9
+
10
+ ### Added
11
+
12
+ - `Yabeda.with_tags` to redefine default tags for limited amount of time–for all metrics measured during a block execution. [@Envek]
13
+
14
+ ### Fixed
15
+
16
+ - Default tags were not sent to adapters for metrics declared before `default_tag` declaration. [@Envek]
17
+
18
+ ## 0.5.0 - 2020-01-29
19
+
20
+ ### Added
21
+
22
+ - Ability to specify aggregation policy for metrics collected from multiple process and exposed via single endpoint. [@Envek]
23
+
24
+ For now it is only used by yabeda-prometheus when official Prometheus client is configured to use file storage for metrics.
25
+
26
+ ## 0.4.0 - 2020-01-28
27
+
28
+ ### Changed
29
+
30
+ - Configuration of gem was changed from synchronous (at the moment when `configure` block was executed) to postponed (only on `configure!` method call). [@Envek]
31
+
32
+ This should allow to fix problems when metrics from gems are registered too early, before required changes to the monitoring system clients.
33
+
34
+ ## 0.3.0 - 2020-01-15
35
+
36
+ ### Added
37
+
38
+ - Ability to specify default tag which value will be automatically added to all metrics. [#7](https://github.com/yabeda-rb/yabeda/pull/7) by [@asusikov].
39
+
40
+ ## 0.2.0 - 2020-01-14
41
+
42
+ ### Added
43
+
44
+ - Ability to specify an optional list of allowed `tags` as an option to metric declaration. @Envek
45
+
46
+ Some monitoring systems clients (like official prometheus client for Ruby) require to declare all possible metric labels upfront.
8
47
 
9
48
  ## 0.1.3 - 2018-12-18
10
49
 
@@ -27,3 +66,6 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
27
66
  ## 0.1.0 - 2018-10-03
28
67
 
29
68
  - Initial release of evil-metrics gem. @Envek
69
+
70
+ [@Envek]: https://github.com/Envek "Andrey Novikov"
71
+ [@asusikov]: https://github.com/asusikov "Alexander Susikov"
data/Gemfile CHANGED
@@ -11,6 +11,6 @@ group :development, :test do
11
11
  gem "pry"
12
12
  gem "pry-byebug", platform: :mri
13
13
 
14
- gem "rubocop"
14
+ gem "rubocop", "~> 0.80.0"
15
15
  gem "rubocop-rspec"
16
16
  end
data/README.md CHANGED
@@ -33,7 +33,7 @@ And then execute:
33
33
  ```ruby
34
34
  Yabeda.configure do
35
35
  group :your_app do
36
- counter :bells_rang_count, comment: "Total number of bells being rang"
36
+ counter :bells_rang_count, comment: "Total number of bells being rang", tags: %i[bell_size]
37
37
  gauge :whistles_active, comment: "Number of whistles ready to whistle"
38
38
  histogram :whistle_runtime do
39
39
  comment "How long whistles are being active"
@@ -43,7 +43,15 @@ And then execute:
43
43
  end
44
44
  ```
45
45
 
46
- 2. Access metric in your app and use it!
46
+ 2. After your application was initialized and all metrics was declared, you need to apply Yabeda configuration:
47
+
48
+ ```ruby
49
+ Yabeda.configure!
50
+ ```
51
+
52
+ _But [yabeda-rails] will do this for you automatically._
53
+
54
+ 3. Access metric in your app and use it!
47
55
 
48
56
  ```ruby
49
57
  def ring_the_bell(id)
@@ -59,20 +67,40 @@ And then execute:
59
67
  end
60
68
  ```
61
69
 
62
- 3. Setup collecting of metrics that do not tied to specific events in you application. E.g.: reporting your app's current state
70
+ 4. Setup collecting of metrics that do not tied to specific events in you application. E.g.: reporting your app's current state
63
71
  ```ruby
64
72
  Yabeda.configure do
65
73
  # This block will be executed periodically few times in a minute
66
74
  # (by timer or external request depending on adapter you're using)
67
75
  # Keep it fast and simple!
68
76
  collect do
69
- your_app_whistles_active.set({}, Whistle.where(state: :active).count
77
+ your_app.whistles_active.set({}, Whistle.where(state: :active).count)
70
78
  end
71
79
  end
72
80
  ```
73
81
 
74
- 4. See the docs for the adapter you're using
75
- 5. Enjoy!
82
+ 5. _Optionally_ setup default tags that will be added to all metrics
83
+ ```ruby
84
+ Yabeda.configure do
85
+ default_tag :rails_environment, 'production'
86
+ end
87
+
88
+ # You can redefine them for limited amount of time
89
+ Yabeda.with_tags(rails_environment: 'staging') do
90
+ Yabeda.your_app.bells_rang_count.increment({bell_size: bell.size}, by: 1)
91
+ end
92
+ ```
93
+
94
+ 6. See the docs for the adapter you're using
95
+ 7. Enjoy!
96
+
97
+ ## Available monitoring system adapters
98
+
99
+ - [Prometheus](https://github.com/yabeda-rb/yabeda-prometheus)
100
+ - [Datadog](https://github.com/yabeda-rb/yabeda-datadog)
101
+ - [NewRelic](https://github.com/yabeda-rb/yabeda-newrelic)
102
+ - [Statsd](https://github.com/asusikov/yabeda-statsd)
103
+ - _…and more! You can write your own adapter and open a pull request to add it into this list._
76
104
 
77
105
  ## Roadmap (aka TODO or Help wanted)
78
106
 
@@ -109,3 +137,5 @@ Bug reports and pull requests are welcome on GitHub at https://github.com/yabeda
109
137
  ## License
110
138
 
111
139
  The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
140
+
141
+ [yabeda-rails]: https://github.com/yabeda-rb/yabeda-rails/ "Yabeda plugin for collecting and exporting basic metrics for Rails applications"
@@ -4,6 +4,8 @@ require "concurrent"
4
4
 
5
5
  require "yabeda/version"
6
6
  require "yabeda/dsl"
7
+ require "yabeda/tags"
8
+ require "yabeda/errors"
7
9
 
8
10
  # Extendable framework for collecting and exporting metrics from Ruby apps
9
11
  module Yabeda
@@ -30,6 +32,11 @@ module Yabeda
30
32
  @collectors ||= Concurrent::Array.new
31
33
  end
32
34
 
35
+ # @return [Hash<Symbol, Symbol>] All added default tags
36
+ def default_tags
37
+ @default_tags ||= Concurrent::Hash.new
38
+ end
39
+
33
40
  # @param [Symbol] name
34
41
  # @param [BaseAdapter] instance
35
42
  def register_adapter(name, instance)
@@ -39,5 +46,53 @@ module Yabeda
39
46
  instance.register!(metric)
40
47
  end
41
48
  end
49
+
50
+ # @return [Array<Proc>] All configuration blocks for postponed setup
51
+ def configurators
52
+ @configurators ||= Concurrent::Array.new
53
+ end
54
+
55
+ # @return [Boolean] Whether +Yabeda.configure!+ has been already called
56
+ def configured?
57
+ !@configured_by.nil?
58
+ end
59
+ alias already_configured? configured?
60
+
61
+ # Perform configuration: registration of metrics and collector blocks
62
+ # @return [void]
63
+ # rubocop: disable Metrics/MethodLength, Metrics/AbcSize
64
+ def configure!
65
+ raise(AlreadyConfiguredError, @configured_by) if already_configured?
66
+
67
+ configurators.each do |(group, block)|
68
+ group group
69
+ class_eval(&block)
70
+ group nil
71
+ end
72
+
73
+ # Register metrics in adapters after evaluating all configuration blocks
74
+ # to ensure that all global settings (like default tags) will be applied.
75
+ adapters.each_value do |adapter|
76
+ metrics.each_value do |metric|
77
+ adapter.register!(metric)
78
+ end
79
+ end
80
+
81
+ @configured_by = caller_locations(1, 1)[0].to_s
82
+ end
83
+ # rubocop: enable Metrics/MethodLength, Metrics/AbcSize
84
+
85
+ # Forget all the configuration.
86
+ # For testing purposes as it doesn't rollback changes in adapters.
87
+ # @api private
88
+ def reset!
89
+ default_tags.clear
90
+ adapters.clear
91
+ groups.clear
92
+ metrics.clear
93
+ collectors.clear
94
+ configurators.clear
95
+ instance_variable_set(:@configured_by, nil)
96
+ end
42
97
  end
43
98
  end
@@ -4,11 +4,12 @@ module Yabeda
4
4
  # Growing-only counter
5
5
  class Counter < Metric
6
6
  def increment(tags, by: 1)
7
- values[tags] += by
7
+ all_tags = ::Yabeda::Tags.build(tags)
8
+ values[all_tags] += by
8
9
  ::Yabeda.adapters.each do |_, adapter|
9
- adapter.perform_counter_increment!(self, tags, by)
10
+ adapter.perform_counter_increment!(self, all_tags, by)
10
11
  end
11
- values[tags]
12
+ values[all_tags]
12
13
  end
13
14
 
14
15
  def values
@@ -14,7 +14,8 @@ module Yabeda
14
14
  module ClassMethods
15
15
  # Block for grouping and simplifying configuration of related metrics
16
16
  def configure(&block)
17
- class_exec(&block)
17
+ Yabeda.configurators.push([@group, block])
18
+ class_exec(&block) if Yabeda.configured?
18
19
  @group = nil
19
20
  end
20
21
 
@@ -53,13 +54,36 @@ module Yabeda
53
54
  register_metric(metric)
54
55
  end
55
56
 
57
+ # Add default tag for all metric
58
+ #
59
+ # @param name [Symbol] Name of default tag
60
+ # @param value [String] Value of default tag
61
+ def default_tag(name, value)
62
+ ::Yabeda.default_tags[name] = value
63
+ end
64
+
65
+ # Redefine default tags for a limited amount of time
66
+ # @param tags Hash{Symbol=>#to_s}
67
+ def with_tags(**tags)
68
+ Thread.current[:yabeda_temporary_tags] = tags
69
+ yield
70
+ ensure
71
+ Thread.current[:yabeda_temporary_tags] = {}
72
+ end
73
+
74
+ # Get tags set by +with_tags+
75
+ # @api private
76
+ # @return Hash
77
+ def temporary_tags
78
+ Thread.current[:yabeda_temporary_tags] || {}
79
+ end
80
+
56
81
  private
57
82
 
58
83
  def register_metric(metric)
59
84
  name = [metric.group, metric.name].compact.join("_")
60
85
  ::Yabeda.define_singleton_method(name) { metric }
61
86
  ::Yabeda.metrics[name] = metric
62
- ::Yabeda.adapters.each_value { |adapter| adapter.register!(metric) }
63
87
  register_group_for(metric) if metric.group
64
88
  metric
65
89
  end
@@ -3,8 +3,6 @@
3
3
  require "yabeda/dsl/option_builder"
4
4
 
5
5
  module Yabeda
6
- class ConfigurationError < StandardError; end
7
-
8
6
  module DSL
9
7
  # Handles DSL for working with individual metrics
10
8
  class MetricBuilder
@@ -21,8 +19,8 @@ module Yabeda
21
19
 
22
20
  def initialize_metric(params, options, group)
23
21
  metric_klass.new(*params, **options, group: group)
24
- rescue KeyError => error
25
- raise ConfigurationError, "#{error.message} for #{metric_klass.name}"
22
+ rescue KeyError => e
23
+ raise ConfigurationError, "#{e.message} for #{metric_klass.name}"
26
24
  end
27
25
  end
28
26
  end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Yabeda
4
+ class ConfigurationError < StandardError; end
5
+
6
+ # Raises on repeated call to +Yabeda.configure!+
7
+ class AlreadyConfiguredError < StandardError
8
+ def initialize(configuring_location)
9
+ super
10
+ @message = "Yabeda was already configured in #{configuring_location}"
11
+ end
12
+
13
+ attr_reader :message
14
+ end
15
+ end
@@ -4,9 +4,10 @@ module Yabeda
4
4
  # Arbitrary value, can be changed in both sides
5
5
  class Gauge < Metric
6
6
  def set(tags, value)
7
- values[tags] = value
7
+ all_tags = ::Yabeda::Tags.build(tags)
8
+ values[all_tags] = value
8
9
  ::Yabeda.adapters.each do |_, adapter|
9
- adapter.perform_gauge_set!(self, tags, value)
10
+ adapter.perform_gauge_set!(self, all_tags, value)
10
11
  end
11
12
  value
12
13
  end
@@ -7,9 +7,10 @@ module Yabeda
7
7
  option :buckets
8
8
 
9
9
  def measure(tags, value)
10
- values[tags] = value
10
+ all_tags = ::Yabeda::Tags.build(tags)
11
+ values[all_tags] = value
11
12
  ::Yabeda.adapters.each do |_, adapter|
12
- adapter.perform_histogram_measure!(self, tags, value)
13
+ adapter.perform_histogram_measure!(self, all_tags, value)
13
14
  end
14
15
  value
15
16
  end
@@ -9,9 +9,11 @@ module Yabeda
9
9
 
10
10
  param :name, comment: "Metric name. Use snake_case. E.g. job_runtime"
11
11
  option :comment, optional: true, comment: "Documentation string. Required by some adapters."
12
+ option :tags, optional: true, comment: "Allowed labels to be set. Required by some adapters."
12
13
  option :unit, optional: true, comment: "In which units it is measured. E.g. `seconds`"
13
14
  option :per, optional: true, comment: "Per which unit is measured `unit`. E.g. `call` as in seconds per call"
14
15
  option :group, optional: true, comment: "Category name for grouping metrics"
16
+ option :aggregation, optional: true, comment: "How adapters should aggregate values from different processes"
15
17
 
16
18
  # Returns the value for the given label set
17
19
  def get(labels = {})
@@ -21,5 +23,9 @@ module Yabeda
21
23
  def values
22
24
  @values ||= Concurrent::Hash.new
23
25
  end
26
+
27
+ def tags
28
+ (Yabeda.default_tags.keys + Array(super)).uniq
29
+ end
24
30
  end
25
31
  end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Yabeda
4
+ # Class to merge tags
5
+ class Tags
6
+ def self.build(tags)
7
+ ::Yabeda.default_tags.merge(Yabeda.temporary_tags, tags)
8
+ end
9
+ end
10
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Yabeda
4
- VERSION = "0.1.3"
4
+ VERSION = "0.6.0"
5
5
  end
@@ -28,7 +28,7 @@ Gem::Specification.new do |spec|
28
28
  spec.add_dependency "concurrent-ruby"
29
29
  spec.add_dependency "dry-initializer"
30
30
 
31
- spec.add_development_dependency "bundler", "~> 1.16"
31
+ spec.add_development_dependency "bundler", "~> 2.0"
32
32
  spec.add_development_dependency "rake", "~> 12.0"
33
33
  spec.add_development_dependency "rspec", "~> 3.0"
34
34
  spec.add_development_dependency "yard"
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.1.3
4
+ version: 0.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrey Novikov
8
- autorequire:
8
+ autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2018-12-18 00:00:00.000000000 Z
11
+ date: 2020-07-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: concurrent-ruby
@@ -44,14 +44,14 @@ dependencies:
44
44
  requirements:
45
45
  - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: '1.16'
47
+ version: '2.0'
48
48
  type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
- version: '1.16'
54
+ version: '2.0'
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: rake
57
57
  requirement: !ruby/object:Gem::Requirement
@@ -108,10 +108,10 @@ dependencies:
108
108
  - - ">="
109
109
  - !ruby/object:Gem::Version
110
110
  version: '0'
111
- description: 'Collect statistics about how your application is performing with ease. Export
112
- metrics to various monitoring systems.
111
+ description: 'Collect statistics about how your application is performing with ease.
112
+ Export metrics to various monitoring systems.
113
113
 
114
- '
114
+ '
115
115
  email:
116
116
  - envek@envek.name
117
117
  executables: []
@@ -137,17 +137,19 @@ files:
137
137
  - lib/yabeda/dsl/class_methods.rb
138
138
  - lib/yabeda/dsl/metric_builder.rb
139
139
  - lib/yabeda/dsl/option_builder.rb
140
+ - lib/yabeda/errors.rb
140
141
  - lib/yabeda/gauge.rb
141
142
  - lib/yabeda/group.rb
142
143
  - lib/yabeda/histogram.rb
143
144
  - lib/yabeda/metric.rb
145
+ - lib/yabeda/tags.rb
144
146
  - lib/yabeda/version.rb
145
147
  - yabeda.gemspec
146
148
  homepage: https://github.com/yabeda-rb/yabeda
147
149
  licenses:
148
150
  - MIT
149
151
  metadata: {}
150
- post_install_message:
152
+ post_install_message:
151
153
  rdoc_options: []
152
154
  require_paths:
153
155
  - lib
@@ -162,9 +164,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
162
164
  - !ruby/object:Gem::Version
163
165
  version: '0'
164
166
  requirements: []
165
- rubyforge_project:
166
- rubygems_version: 2.7.6
167
- signing_key:
167
+ rubygems_version: 3.1.2
168
+ signing_key:
168
169
  specification_version: 4
169
170
  summary: Extensible framework for collecting metric for your Ruby application
170
171
  test_files: []