ruby_script_exporter 0.0.1 → 0.0.2
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/.rspec +1 -0
- data/CHANGELOG.md +9 -0
- data/Gemfile +1 -5
- data/Gemfile.lock +20 -3
- data/README.md +52 -19
- data/lib/ruby_script_exporter/executor.rb +56 -2
- data/lib/ruby_script_exporter/formatter.rb +9 -6
- data/lib/ruby_script_exporter/measurement.rb +4 -2
- data/lib/ruby_script_exporter/probe.rb +29 -2
- data/lib/ruby_script_exporter/script_loader.rb +7 -4
- data/lib/ruby_script_exporter/server.rb +1 -1
- data/lib/ruby_script_exporter/type.rb +8 -1
- data/lib/ruby_script_exporter/version.rb +1 -1
- metadata +46 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c519baa82ed0393d7b038669bf035a4bc05018a0ecb8da173ead0ad9d2b58d70
|
4
|
+
data.tar.gz: '0876858a6b675cbc71f0c52f39584dfe3fd5b21850ec54080694416339780a20'
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e97359edfa445da493e7cf9a3fe75716aed59ecef67b387b2b9b733f2696d709e030e9b51fa56433ea1acddbb65abb0e3afeaae167ccb943b64b8f6214c598d8
|
7
|
+
data.tar.gz: ab958039e3494ef2141bb10da35596368fd63957d92e4ce65013ba1ea9c18f9dd94a44106806404d009ac194bb9362ab0a6a19a577e8afc8789aa0a956b054a1
|
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--require spec_helper
|
data/CHANGELOG.md
ADDED
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
ruby_script_exporter (0.0.
|
4
|
+
ruby_script_exporter (0.0.2)
|
5
5
|
rackup (~> 2.1.0)
|
6
6
|
sinatra (~> 4.0.0)
|
7
7
|
|
@@ -9,6 +9,8 @@ GEM
|
|
9
9
|
remote: https://rubygems.org/
|
10
10
|
specs:
|
11
11
|
base64 (0.2.0)
|
12
|
+
diff-lcs (1.5.0)
|
13
|
+
mqtt (0.6.0)
|
12
14
|
mustermann (3.0.0)
|
13
15
|
ruby2_keywords (~> 0.0.1)
|
14
16
|
rack (3.0.8)
|
@@ -21,6 +23,19 @@ GEM
|
|
21
23
|
rack (>= 3)
|
22
24
|
webrick (~> 1.8)
|
23
25
|
rake (13.0.6)
|
26
|
+
rspec (3.12.0)
|
27
|
+
rspec-core (~> 3.12.0)
|
28
|
+
rspec-expectations (~> 3.12.0)
|
29
|
+
rspec-mocks (~> 3.12.0)
|
30
|
+
rspec-core (3.12.2)
|
31
|
+
rspec-support (~> 3.12.0)
|
32
|
+
rspec-expectations (3.12.3)
|
33
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
34
|
+
rspec-support (~> 3.12.0)
|
35
|
+
rspec-mocks (3.12.6)
|
36
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
37
|
+
rspec-support (~> 3.12.0)
|
38
|
+
rspec-support (3.12.1)
|
24
39
|
ruby2_keywords (0.0.5)
|
25
40
|
sinatra (4.0.0)
|
26
41
|
mustermann (~> 3.0)
|
@@ -29,16 +44,18 @@ GEM
|
|
29
44
|
rack-session (>= 2.0.0, < 3)
|
30
45
|
tilt (~> 2.0)
|
31
46
|
tilt (2.3.0)
|
47
|
+
timecop (0.9.8)
|
32
48
|
webrick (1.8.1)
|
33
49
|
|
34
50
|
PLATFORMS
|
35
51
|
x86_64-linux
|
36
52
|
|
37
53
|
DEPENDENCIES
|
38
|
-
|
54
|
+
mqtt
|
39
55
|
rake (~> 13.0)
|
56
|
+
rspec (~> 3.6)
|
40
57
|
ruby_script_exporter!
|
41
|
-
|
58
|
+
timecop (~> 0.9.8)
|
42
59
|
|
43
60
|
BUNDLED WITH
|
44
61
|
2.4.10
|
data/README.md
CHANGED
@@ -1,31 +1,64 @@
|
|
1
|
-
#
|
1
|
+
# ruby_script_exporter
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/ruby_script_exporter`. To experiment with that code, run `bin/console` for an interactive prompt.
|
3
|
+
ruby_script_exporter is a small framework to expose metrics produced by ruby snippets to prometheus.
|
6
4
|
|
7
5
|
## Installation
|
8
6
|
|
9
|
-
|
10
|
-
|
11
|
-
Install the gem and add to the application's Gemfile by executing:
|
12
|
-
|
13
|
-
$ bundle add UPDATE_WITH_YOUR_GEM_NAME_PRIOR_TO_RELEASE_TO_RUBYGEMS_ORG
|
14
|
-
|
15
|
-
If bundler is not being used to manage dependencies, install the gem by executing:
|
16
|
-
|
17
|
-
$ gem install UPDATE_WITH_YOUR_GEM_NAME_PRIOR_TO_RELEASE_TO_RUBYGEMS_ORG
|
7
|
+
`gem install ruby_script_exporter`
|
18
8
|
|
19
9
|
## Usage
|
20
10
|
|
21
|
-
|
11
|
+
```
|
12
|
+
Usage: ruby_script_exporter [options]
|
13
|
+
-s SERVICE_DIR, --script-directory Specify where to look for service definitions
|
14
|
+
-r, --reload-on-request Reload service definitions for every request, useful for developing probes
|
15
|
+
```
|
16
|
+
|
17
|
+
## Example Probe
|
22
18
|
|
23
|
-
|
19
|
+
`services/example_probe.rb`:
|
24
20
|
|
25
|
-
|
21
|
+
```
|
22
|
+
type :some_metric, :gauge, 'Some random metric'
|
26
23
|
|
27
|
-
|
24
|
+
service 'some service' do
|
25
|
+
probe 'some probe' do
|
26
|
+
label :some_label, 'Foo'
|
27
|
+
|
28
|
+
run do
|
29
|
+
observe :some_metric, 123
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
```
|
34
|
+
|
35
|
+
Run the exporter with `ruby_script_exporter` and get `http://localhost:9100` for:
|
28
36
|
|
29
|
-
|
37
|
+
```
|
38
|
+
# HELP cached_probe_count Count of probes which returned a cached result
|
39
|
+
# TYPE cached_probe_count gauge
|
40
|
+
cached_probe_count 0
|
41
|
+
# HELP error_probe_count Count probes witch threw an error while executing
|
42
|
+
# TYPE error_probe_count gauge
|
43
|
+
error_probe_count 0
|
44
|
+
# HELP probe_execution_time Execution time per probe
|
45
|
+
# TYPE probe_execution_time gauge
|
46
|
+
probe_execution_time{service="some service",probe="some probe",some_label="Foo"} 7.915019523352385e-06
|
47
|
+
# HELP some_metric Some random metric
|
48
|
+
# TYPE some_metric gauge
|
49
|
+
some_metric{service="some service",probe="some probe",some_label="Foo"} 123
|
50
|
+
# HELP successful_probe_count Count of probes which ran successfully
|
51
|
+
# TYPE successful_probe_count gauge
|
52
|
+
successful_probe_count 1
|
53
|
+
# HELP timeout_probe_count Count of probes which timed out
|
54
|
+
# TYPE timeout_probe_count gauge
|
55
|
+
timeout_probe_count 0
|
56
|
+
# HELP total_execution_time Total execution time
|
57
|
+
# TYPE total_execution_time gauge
|
58
|
+
total_execution_time 6.38000201433897e-05
|
59
|
+
# HELP total_probe_count Total probe count
|
60
|
+
# TYPE total_probe_count gauge
|
61
|
+
total_probe_count 1
|
62
|
+
```
|
30
63
|
|
31
|
-
|
64
|
+
Next to `some_metric` there are also a number of internal metrics exposed.
|
@@ -1,8 +1,10 @@
|
|
1
1
|
module RubyScriptExporter
|
2
2
|
class Executor
|
3
3
|
|
4
|
-
def initialize(services)
|
4
|
+
def initialize(services, report_execution_time: false, report_counts: false)
|
5
5
|
@services = services
|
6
|
+
@report_execution_time = report_execution_time
|
7
|
+
@report_counts = report_counts
|
6
8
|
end
|
7
9
|
|
8
10
|
def probes
|
@@ -10,7 +12,59 @@ module RubyScriptExporter
|
|
10
12
|
end
|
11
13
|
|
12
14
|
def run
|
13
|
-
|
15
|
+
total_count = 0
|
16
|
+
successful_count = 0
|
17
|
+
cached_count = 0
|
18
|
+
error_count = 0
|
19
|
+
timeout_count = 0
|
20
|
+
measurements = []
|
21
|
+
|
22
|
+
start_time = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
23
|
+
|
24
|
+
probes.each do |probe|
|
25
|
+
total_count += 1
|
26
|
+
|
27
|
+
begin
|
28
|
+
probe_measurements, execution_time = probe.run
|
29
|
+
rescue Probe::ScriptError
|
30
|
+
error_count += 1
|
31
|
+
next
|
32
|
+
rescue Probe::ScriptTimeout
|
33
|
+
timeout_count += 1
|
34
|
+
next
|
35
|
+
end
|
36
|
+
|
37
|
+
measurements.concat(probe_measurements)
|
38
|
+
|
39
|
+
successful_count += 1
|
40
|
+
if execution_time == :cached
|
41
|
+
execution_time = 0
|
42
|
+
cached_count += 1
|
43
|
+
end
|
44
|
+
|
45
|
+
if @report_execution_time
|
46
|
+
measurements << Measurement.new(:probe_execution_time, execution_time,
|
47
|
+
probe: probe,
|
48
|
+
)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
end_time = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
53
|
+
total_execution_time = end_time - start_time
|
54
|
+
|
55
|
+
if @report_execution_time
|
56
|
+
measurements << Measurement.new(:total_execution_time, total_execution_time)
|
57
|
+
end
|
58
|
+
|
59
|
+
if @report_counts
|
60
|
+
measurements << Measurement.new(:total_probe_count, total_count)
|
61
|
+
measurements << Measurement.new(:successful_probe_count, successful_count)
|
62
|
+
measurements << Measurement.new(:cached_probe_count, cached_count)
|
63
|
+
measurements << Measurement.new(:error_probe_count, error_count)
|
64
|
+
measurements << Measurement.new(:timeout_probe_count, timeout_count)
|
65
|
+
end
|
66
|
+
|
67
|
+
measurements
|
14
68
|
end
|
15
69
|
|
16
70
|
end
|
@@ -8,14 +8,17 @@ module RubyScriptExporter
|
|
8
8
|
def format
|
9
9
|
output = []
|
10
10
|
|
11
|
-
@measurements
|
12
|
-
|
13
|
-
|
11
|
+
@measurements
|
12
|
+
.group_by(&:measurement)
|
13
|
+
.sort_by { |key, _| key }
|
14
|
+
.map do |type, measurements|
|
15
|
+
type = Type.from_name(type)
|
16
|
+
output << type.format_for_open_metrics
|
14
17
|
|
15
|
-
|
16
|
-
|
18
|
+
measurements.each do |measurement|
|
19
|
+
output << measurement.format_as_open_metric
|
20
|
+
end
|
17
21
|
end
|
18
|
-
end
|
19
22
|
|
20
23
|
output.join("\n")
|
21
24
|
end
|
@@ -4,7 +4,7 @@ module RubyScriptExporter
|
|
4
4
|
attr_reader :measurement
|
5
5
|
attr_reader :value
|
6
6
|
|
7
|
-
def initialize(measurement, value, timestamp
|
7
|
+
def initialize(measurement, value, timestamp: nil, probe: nil, **labels)
|
8
8
|
@measurement = measurement
|
9
9
|
@value = value
|
10
10
|
@probe = probe
|
@@ -17,6 +17,8 @@ module RubyScriptExporter
|
|
17
17
|
end
|
18
18
|
|
19
19
|
def combined_labels
|
20
|
+
return @labels unless @probe
|
21
|
+
|
20
22
|
@probe.combined_labels.merge(@labels)
|
21
23
|
end
|
22
24
|
|
@@ -34,7 +36,7 @@ module RubyScriptExporter
|
|
34
36
|
line << ' '
|
35
37
|
line << @value.to_s
|
36
38
|
|
37
|
-
if @probe
|
39
|
+
if @probe&.caches_result?
|
38
40
|
line << ' '
|
39
41
|
line << @timestamp.to_s
|
40
42
|
end
|
@@ -3,10 +3,15 @@
|
|
3
3
|
module RubyScriptExporter
|
4
4
|
class Probe
|
5
5
|
|
6
|
+
class ScriptError < StandardError; end
|
7
|
+
class ScriptTimeout < StandardError; end
|
8
|
+
|
6
9
|
attr_reader :name
|
7
10
|
attr_reader :labels
|
8
11
|
attr_accessor :cache_for
|
12
|
+
attr_accessor :timeout
|
9
13
|
attr_writer :runner_proc
|
14
|
+
attr_reader :service
|
10
15
|
|
11
16
|
def initialize(name, service)
|
12
17
|
@name = name
|
@@ -14,6 +19,7 @@ module RubyScriptExporter
|
|
14
19
|
@labels = {}
|
15
20
|
@last_measurements = nil
|
16
21
|
@last_run_at = nil
|
22
|
+
@timeout = 1
|
17
23
|
end
|
18
24
|
|
19
25
|
def combined_labels
|
@@ -28,15 +34,32 @@ module RubyScriptExporter
|
|
28
34
|
|
29
35
|
def run
|
30
36
|
if caches_result? && @last_measurements && @last_run_at > (Time.now.to_f - @cache_for)
|
31
|
-
return @last_measurements
|
37
|
+
return [@last_measurements, :cached]
|
32
38
|
end
|
33
39
|
|
34
40
|
raise ArgumentError, 'No runner given' unless @runner_proc
|
35
41
|
|
36
42
|
runner = Runner.new(self)
|
37
|
-
|
43
|
+
|
44
|
+
start_time = nil
|
45
|
+
end_time = nil
|
46
|
+
begin
|
47
|
+
Timeout::timeout(@timeout) do
|
48
|
+
start_time = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
49
|
+
runner.instance_eval(&@runner_proc)
|
50
|
+
end_time = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
51
|
+
end
|
52
|
+
rescue Timeout::Error
|
53
|
+
raise ScriptTimeout
|
54
|
+
rescue StandardError
|
55
|
+
raise ScriptError
|
56
|
+
end
|
57
|
+
|
58
|
+
execution_time = end_time - start_time
|
59
|
+
|
38
60
|
@last_run_at = Time.now.to_f
|
39
61
|
@last_measurements = runner.measurements
|
62
|
+
[@last_measurements, execution_time]
|
40
63
|
end
|
41
64
|
end
|
42
65
|
|
@@ -51,6 +74,10 @@ module RubyScriptExporter
|
|
51
74
|
@probe.cache_for = time
|
52
75
|
end
|
53
76
|
|
77
|
+
def timeout(timeout)
|
78
|
+
@probe.timeout = timeout
|
79
|
+
end
|
80
|
+
|
54
81
|
def label(key, value)
|
55
82
|
@probe.labels[key] = value
|
56
83
|
end
|
@@ -17,13 +17,17 @@ module RubyScriptExporter
|
|
17
17
|
Type.register_type(name, type, help)
|
18
18
|
end
|
19
19
|
|
20
|
-
def self.
|
20
|
+
def self.load_string(string)
|
21
21
|
loader = ScriptLoader.new
|
22
|
-
|
23
|
-
loader.instance_eval
|
22
|
+
Type.reset_types
|
23
|
+
loader.instance_eval string
|
24
24
|
loader.services
|
25
25
|
end
|
26
26
|
|
27
|
+
def self.load_file(file)
|
28
|
+
load_string File.open(file).read
|
29
|
+
end
|
30
|
+
|
27
31
|
def self.load_directory(directory)
|
28
32
|
unless directory.start_with?('/')
|
29
33
|
directory = File.join(Dir.pwd, directory)
|
@@ -33,7 +37,6 @@ module RubyScriptExporter
|
|
33
37
|
service_files = Dir[directory]
|
34
38
|
|
35
39
|
puts "Loading service definitions ..."
|
36
|
-
Type.clear_types
|
37
40
|
services = service_files.map { load_file(_1) }.flatten
|
38
41
|
probe_count = services.map(&:probes).flatten.count
|
39
42
|
puts "Loaded #{Util.counterize('service', services.count)} with a total of #{Util.counterize('probe', probe_count)}"
|
@@ -20,7 +20,7 @@ module RubyScriptExporter
|
|
20
20
|
set :default_content_type, 'text'
|
21
21
|
|
22
22
|
get '/metrics' do
|
23
|
-
measurements = Executor.new(self.class.services).run
|
23
|
+
measurements = Executor.new(self.class.services, report_execution_time: true, report_counts: true).run
|
24
24
|
Formatter.new(measurements).format
|
25
25
|
end
|
26
26
|
end
|
@@ -26,8 +26,15 @@ module RubyScriptExporter
|
|
26
26
|
type
|
27
27
|
end
|
28
28
|
|
29
|
-
def self.
|
29
|
+
def self.reset_types
|
30
30
|
@types = {}
|
31
|
+
register_type(:cached_probe_count, :gauge, 'Count of probes which returned a cached result')
|
32
|
+
register_type(:error_probe_count, :gauge, 'Count probes witch threw an error while executing')
|
33
|
+
register_type(:successful_probe_count, :gauge, 'Count of probes which ran successfully')
|
34
|
+
register_type(:timeout_probe_count, :gauge, 'Count of probes which timed out')
|
35
|
+
register_type(:total_probe_count, :gauge, 'Total probe count')
|
36
|
+
register_type(:probe_execution_time, :gauge, 'Execution time per probe')
|
37
|
+
register_type(:total_execution_time, :gauge, 'Total execution time')
|
31
38
|
end
|
32
39
|
|
33
40
|
def format_for_open_metrics
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ruby_script_exporter
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Martin Schaflitzl
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-01-
|
11
|
+
date: 2024-01-30 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: sinatra
|
@@ -38,6 +38,48 @@ dependencies:
|
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: 2.1.0
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rspec
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '3.6'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '3.6'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: timecop
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 0.9.8
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: 0.9.8
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rake
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '13.0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '13.0'
|
41
83
|
description:
|
42
84
|
email:
|
43
85
|
- gems@martin-sc.de
|
@@ -46,7 +88,9 @@ executables:
|
|
46
88
|
extensions: []
|
47
89
|
extra_rdoc_files: []
|
48
90
|
files:
|
91
|
+
- ".rspec"
|
49
92
|
- ".tool-versions"
|
93
|
+
- CHANGELOG.md
|
50
94
|
- Gemfile
|
51
95
|
- Gemfile.lock
|
52
96
|
- README.md
|