protor 0.0.3
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 +7 -0
- data/README.md +53 -0
- data/lib/protor.rb +49 -0
- data/lib/protor/accumulator.rb +38 -0
- data/lib/protor/client.rb +30 -0
- data/lib/protor/configuration.rb +17 -0
- data/lib/protor/observer.rb +47 -0
- data/lib/protor/payload.rb +100 -0
- data/lib/protor/registry.rb +63 -0
- data/lib/protor/version.rb +3 -0
- metadata +53 -0
checksums.yaml
ADDED
@@ -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
|
data/README.md
ADDED
@@ -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.
|
data/lib/protor.rb
ADDED
@@ -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,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
|
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: []
|