yabeda 0.1.3 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
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: []