protor 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 537a3afb0cc18e89d25b042061ca0ddebb5b5db6
4
+ data.tar.gz: 4470654d6e40c9554e88c4b6f652d96ea3fb11ed
5
+ SHA512:
6
+ metadata.gz: 8c745d4dfe654901355e910ef80411451a04029c33383e92a8c066be490f1fa20591ac221504ff18463a7aec663c47c92218a372be5299aece418312dbc9f5c8
7
+ data.tar.gz: ba8dd56a6c69e65af5da3f84352ef3de50baff2b1f51c881d9ffc65e559819b0dbada0384da225e3034a50a600735a7cea65c349e223d25f740b8d538b367795
@@ -0,0 +1,53 @@
1
+ # protor-ruby
2
+ [Prometheus aggregator](https://github.com/rolandhawk/prometheus-aggregator) client for ruby
3
+
4
+ ## Installation
5
+ In Gemfile
6
+ ````ruby
7
+ gem 'protor'
8
+ ````
9
+ Then run
10
+ ````shell
11
+ bundle install
12
+ ````
13
+
14
+ ## Usage
15
+ ### Counter
16
+ It automatically aggregate value
17
+
18
+ ````ruby
19
+ Protor.counter(:counter, 1, {label1: 1}) # value => 1
20
+ Protor.counter(:counter, 1, {label1: 1}) # value => 2
21
+ ````
22
+ ### Gauge
23
+ It automatically replace value
24
+ ````ruby
25
+ Protor.gauge(:gauge, 50) # value 50
26
+ Protor.gauge(:gauge, 20) # value 20
27
+ ````
28
+
29
+ ### Histogram
30
+ It save all observed values
31
+ ````ruby
32
+ Protor.histogram(:histogram, 10, {label1: 1}, [1,2,3,4]) # observed value [10]
33
+ Protor.histogram(:histogram, 2, {label1: 1}, [1,2,3,4]( # observed value [10,2]
34
+ ````
35
+
36
+ ### Publish
37
+ To publish all saved metrics to aggregator
38
+ ````ruby
39
+ Protor.publish
40
+ ````
41
+
42
+ ## Configuration
43
+ To configure protor:
44
+ ````ruby
45
+ Protor.configure do |config|
46
+ config.host = 'localhost' # aggregator host, default to localhost
47
+ config.port = 10601 # aggregator port, default to 10601
48
+ config.max_packet_size = 56607 # max udp packet buffer, default to 56607
49
+ end
50
+ ````
51
+
52
+ ## Contributing
53
+ [Fork the project](https://github.com/rolandhawk/protor-ruby) and send pull requests.
@@ -0,0 +1,49 @@
1
+ require 'monitor'
2
+
3
+ require_relative 'protor/configuration'
4
+ require_relative 'protor/client'
5
+ require_relative 'protor/registry'
6
+ require_relative 'protor/version'
7
+
8
+ module Protor
9
+ extend MonitorMixin
10
+ end
11
+
12
+ class << Protor
13
+ def configuration
14
+ @configuration ||= Protor::Configuration.new
15
+ end
16
+
17
+ def configure
18
+ yield(configuration)
19
+ end
20
+
21
+ def publish
22
+ synchronize do
23
+ unless @registry.empty?
24
+ client.publish(registry)
25
+ reset
26
+ end
27
+ end
28
+ end
29
+
30
+ [:counter, :gauge, :histogram].each do |method|
31
+ define_method method do |*args, &block|
32
+ synchronize{ registry.public_send(method, *args, &block) }
33
+ end
34
+ end
35
+
36
+ private
37
+
38
+ def client
39
+ @client ||= Protor::Client.new(configuration)
40
+ end
41
+
42
+ def registry
43
+ @registry || reset
44
+ end
45
+
46
+ def reset
47
+ @registry = Protor::Registry.new(configuration)
48
+ end
49
+ end
@@ -0,0 +1,38 @@
1
+ module Protor
2
+ class Accumulator
3
+ def initialize(type)
4
+ @data = {}
5
+ @type = type
6
+ end
7
+
8
+ def inc(metric_name, value, labels = {})
9
+ data[metric_name] ||= Hash.new(0)
10
+ data[metric_name][labels] += value
11
+ end
12
+
13
+ def set(metric_name, value, labels = {})
14
+ data[metric_name] ||= Hash.new(0)
15
+ data[metric_name][labels] = value
16
+ end
17
+
18
+ def to_a
19
+ array = []
20
+
21
+ data.each do |metric_name, values|
22
+ values.each do |labels, value|
23
+ array << { metric_name: metric_name, labels: labels, value: value, type: type }
24
+ end
25
+ end
26
+
27
+ return array
28
+ end
29
+
30
+ def empty?
31
+ data.empty?
32
+ end
33
+
34
+ private
35
+
36
+ attr_reader :type, :data
37
+ end
38
+ end
@@ -0,0 +1,30 @@
1
+ require 'socket'
2
+
3
+ module Protor
4
+ class Client
5
+ def initialize(configuration)
6
+ @options = configuration
7
+ end
8
+
9
+ def publish(payload)
10
+ established do |connection|
11
+ payload.each{ |str| connection.send(str, 0) }
12
+ end
13
+ end
14
+
15
+ private
16
+
17
+ attr_reader :options
18
+
19
+ def established
20
+ socket = UDPSocket.new
21
+ socket.connect(options.host, options.port)
22
+ yield socket
23
+ rescue Errno::ECONNREFUSED => exception
24
+ # omit error, it caused by aggregate server being down
25
+ exception
26
+ ensure
27
+ socket.close unless socket.closed?
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,17 @@
1
+ module Protor
2
+ class Configuration
3
+ attr_writer :host, :port, :max_packet_size
4
+
5
+ def host
6
+ @host ||= 'localhost'
7
+ end
8
+
9
+ def port
10
+ @port ||= 10601
11
+ end
12
+
13
+ def max_packet_size
14
+ @max_packet_size ||= 56_607
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,47 @@
1
+ module Protor
2
+ class Observer
3
+ def initialize(type)
4
+ @data = {}
5
+ @type = type
6
+ end
7
+
8
+ def observe(metric_name, value, labels = {}, additional = [])
9
+ data[metric_name] ||= { values: {} }
10
+ data[metric_name][:values][labels] ||= []
11
+
12
+ data[metric_name][:additional] = additional
13
+ data[metric_name][:values][labels] << value
14
+ end
15
+
16
+ def to_a
17
+ array = []
18
+
19
+ data.each do |metric_name, values|
20
+ first = true
21
+ values[:values].each do |labels, value|
22
+ value.each do |val|
23
+ array << {
24
+ metric_name: metric_name,
25
+ labels: labels,
26
+ value: val,
27
+ additional: values[:additional],
28
+ first: first,
29
+ type: type
30
+ }
31
+ first = false
32
+ end
33
+ end
34
+ end
35
+
36
+ return array
37
+ end
38
+
39
+ def empty?
40
+ data.empty?
41
+ end
42
+
43
+ private
44
+
45
+ attr_reader :data, :type
46
+ end
47
+ end
@@ -0,0 +1,100 @@
1
+ module Protor
2
+ class Payload
3
+
4
+ Lf = "\n".freeze
5
+
6
+
7
+ def initialize(max_packet_size)
8
+ @max_packet_size = max_packet_size
9
+ @lines = []
10
+ @total_size = 0
11
+ end
12
+
13
+ def add(data)
14
+ data = data.dup
15
+ data[:first] = true if lines.empty?
16
+
17
+ return false if packet_overflow?(data)
18
+
19
+ self.common_labels = data[:labels]
20
+ @total_size += data_size(data)
21
+ @lines << data
22
+ end
23
+
24
+ def to_s
25
+ str = first_line
26
+ lines.each do |data|
27
+ line = template(data)
28
+ str << "#{line}#{Lf}"
29
+ end
30
+
31
+ return str
32
+ end
33
+
34
+ private
35
+
36
+ attr_reader :common_labels, :lines, :total_size, :max_packet_size
37
+
38
+ def data_size(data)
39
+ size = 3
40
+ [:metric_name, :value].each do |key|
41
+ size += data[key].to_s.size
42
+ end
43
+
44
+ size += labels_string(data[:labels]).size + 1 if data[:labels]
45
+
46
+ size += additional_string(data[:additional]).size + 1 if data[:first] && data[:additional]
47
+
48
+ return size
49
+ end
50
+
51
+ def common_labels=(labels = {})
52
+ @common_labels ||= labels.dup
53
+ intersect(common_labels, labels)
54
+ @common_labels.keep_if{ |k, v| labels.key? k }
55
+ end
56
+
57
+ def first_line
58
+ if !common_labels || common_labels.empty?
59
+ ""
60
+ else
61
+ "#{labels_string(common_labels)}#{Lf}"
62
+ end
63
+ end
64
+
65
+ def template(data)
66
+ labels = exclude_common(data[:labels])
67
+
68
+ "#{ data[:metric_name] }|#{ data[:type][0] }|".tap do |str|
69
+ str << "#{ additional_string(data[:additional]) }|" if data[:first] && data[:additional]
70
+ str << "#{ labels_string(labels) }|" unless labels.empty?
71
+ str << "#{ data[:value] }"
72
+ end
73
+ end
74
+
75
+ def labels_string(labels)
76
+ labels.map{ |k, v| "#{k}=#{v}" }.join(';')
77
+ end
78
+
79
+ def additional_string(additional)
80
+ additional.join(';')
81
+ end
82
+
83
+ def intersect(a, b)
84
+ a.keep_if{ |k, v| b.key? k }
85
+ end
86
+
87
+ def exclude_common(labels)
88
+ labels.keep_if{ |k, v| !common_labels[k] }
89
+ end
90
+
91
+ def packet_overflow?(data)
92
+ backup = common_labels && common_labels.dup || data[:labels]
93
+ intersect(backup, data[:labels])
94
+ size = data_size(data)
95
+
96
+ total_size + size - (labels_string(backup).size * lines.size) > max_packet_size
97
+ end
98
+ end
99
+ end
100
+
@@ -0,0 +1,63 @@
1
+ require_relative 'payload'
2
+ require_relative 'accumulator'
3
+ require_relative 'observer'
4
+
5
+ module Protor
6
+ class Registry
7
+ HistogramDefaultBuckets = [0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1, 2.5, 5, 10].freeze
8
+
9
+ def initialize(options)
10
+ @options = options
11
+ end
12
+
13
+ def counter(metric_name, value, labels = {})
14
+ counter_data.inc(metric_name, value, labels)
15
+ end
16
+
17
+ def gauge(metric_name, value, labels = {})
18
+ gauge_data.set(metric_name, value, labels)
19
+ end
20
+
21
+ def histogram(metric_name, value, labels = {}, buckets = HistogramDefaultBuckets)
22
+ histogram_data.observe(metric_name, value, labels, buckets)
23
+ end
24
+
25
+ def each
26
+ payload = Payload.new options.max_packet_size
27
+ all_data.each do |data|
28
+ unless payload.add(data)
29
+ yield payload.to_s
30
+
31
+ payload = Payload.new options.max_packet_size
32
+ payload.add(data)
33
+ end
34
+ end
35
+
36
+ yield payload.to_s
37
+ end
38
+
39
+ def empty?
40
+ [@counter, @gauge, @histogram].all?{ |metrics| metrics && metrics.empty? }
41
+ end
42
+
43
+ private
44
+
45
+ attr_reader :options
46
+
47
+ def counter_data
48
+ @counter ||= Accumulator.new(:counter)
49
+ end
50
+
51
+ def gauge_data
52
+ @gauge ||= Accumulator.new(:gauge)
53
+ end
54
+
55
+ def histogram_data
56
+ @histogram ||= Observer.new(:histogram)
57
+ end
58
+
59
+ def all_data
60
+ [counter_data.to_a, gauge_data.to_a, histogram_data.to_a].flatten
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,3 @@
1
+ module Protor
2
+ VERSION = '0.0.3'
3
+ end
metadata ADDED
@@ -0,0 +1,53 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: protor
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.3
5
+ platform: ruby
6
+ authors:
7
+ - Roland Rinfandi Utama
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-08-18 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description:
14
+ email:
15
+ - roland_hawk@yahoo.com
16
+ executables: []
17
+ extensions: []
18
+ extra_rdoc_files: []
19
+ files:
20
+ - README.md
21
+ - lib/protor.rb
22
+ - lib/protor/accumulator.rb
23
+ - lib/protor/client.rb
24
+ - lib/protor/configuration.rb
25
+ - lib/protor/observer.rb
26
+ - lib/protor/payload.rb
27
+ - lib/protor/registry.rb
28
+ - lib/protor/version.rb
29
+ homepage: https://github.com/rolandhawk/protor-ruby
30
+ licenses:
31
+ - MIT
32
+ metadata: {}
33
+ post_install_message:
34
+ rdoc_options: []
35
+ require_paths:
36
+ - lib
37
+ required_ruby_version: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - ">="
40
+ - !ruby/object:Gem::Version
41
+ version: '0'
42
+ required_rubygems_version: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ version: '0'
47
+ requirements: []
48
+ rubyforge_project:
49
+ rubygems_version: 2.5.1
50
+ signing_key:
51
+ specification_version: 4
52
+ summary: Prometheus aggregator client for ruby.
53
+ test_files: []