service_skeleton 0.0.0.1.ENOTAG → 0.0.0.2.g46c1e0e
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 +5 -5
- data/.gitignore +0 -2
- data/.rubocop.yml +114 -9
- data/.travis.yml +11 -0
- data/README.md +153 -279
- data/lib/service_skeleton/background_worker.rb +80 -0
- data/lib/service_skeleton/config.rb +18 -78
- data/lib/service_skeleton/config_variable.rb +8 -29
- data/lib/service_skeleton/config_variables.rb +68 -54
- data/lib/service_skeleton/error.rb +3 -5
- data/lib/service_skeleton/filtering_logger.rb +0 -2
- data/lib/service_skeleton/logging_helpers.rb +3 -10
- data/lib/service_skeleton/metrics_methods.rb +13 -28
- data/lib/service_skeleton/signal_handler.rb +183 -0
- data/lib/service_skeleton.rb +145 -22
- data/service_skeleton.gemspec +9 -10
- metadata +19 -102
- data/.editorconfig +0 -7
- data/.git-blame-ignore-revs +0 -2
- data/.github/workflows/ci.yml +0 -50
- data/lib/service_skeleton/config_class.rb +0 -16
- data/lib/service_skeleton/config_variable/boolean.rb +0 -21
- data/lib/service_skeleton/config_variable/enum.rb +0 -27
- data/lib/service_skeleton/config_variable/float.rb +0 -25
- data/lib/service_skeleton/config_variable/integer.rb +0 -25
- data/lib/service_skeleton/config_variable/kv_list.rb +0 -26
- data/lib/service_skeleton/config_variable/path_list.rb +0 -13
- data/lib/service_skeleton/config_variable/string.rb +0 -18
- data/lib/service_skeleton/config_variable/url.rb +0 -36
- data/lib/service_skeleton/config_variable/yaml_file.rb +0 -42
- data/lib/service_skeleton/generator.rb +0 -165
- data/lib/service_skeleton/metric_method_name.rb +0 -9
- data/lib/service_skeleton/runner.rb +0 -46
- data/lib/service_skeleton/service_name.rb +0 -20
- data/lib/service_skeleton/signal_manager.rb +0 -202
- data/lib/service_skeleton/signals_methods.rb +0 -15
- data/lib/service_skeleton/ultravisor_children.rb +0 -20
- data/lib/service_skeleton/ultravisor_loggerstash.rb +0 -11
- data/ultravisor/.yardopts +0 -1
- data/ultravisor/Guardfile +0 -9
- data/ultravisor/README.md +0 -404
- data/ultravisor/lib/ultravisor/child/call.rb +0 -21
- data/ultravisor/lib/ultravisor/child/call_receiver.rb +0 -14
- data/ultravisor/lib/ultravisor/child/cast.rb +0 -16
- data/ultravisor/lib/ultravisor/child/cast_receiver.rb +0 -11
- data/ultravisor/lib/ultravisor/child/process_cast_call.rb +0 -39
- data/ultravisor/lib/ultravisor/child.rb +0 -481
- data/ultravisor/lib/ultravisor/error.rb +0 -25
- data/ultravisor/lib/ultravisor/logging_helpers.rb +0 -32
- data/ultravisor/lib/ultravisor.rb +0 -216
- data/ultravisor/spec/example_group_methods.rb +0 -19
- data/ultravisor/spec/example_methods.rb +0 -8
- data/ultravisor/spec/spec_helper.rb +0 -52
- data/ultravisor/spec/ultravisor/add_child_spec.rb +0 -79
- data/ultravisor/spec/ultravisor/child/call_spec.rb +0 -121
- data/ultravisor/spec/ultravisor/child/cast_spec.rb +0 -111
- data/ultravisor/spec/ultravisor/child/id_spec.rb +0 -21
- data/ultravisor/spec/ultravisor/child/new_spec.rb +0 -152
- data/ultravisor/spec/ultravisor/child/restart_delay_spec.rb +0 -40
- data/ultravisor/spec/ultravisor/child/restart_spec.rb +0 -70
- data/ultravisor/spec/ultravisor/child/run_spec.rb +0 -95
- data/ultravisor/spec/ultravisor/child/shutdown_spec.rb +0 -124
- data/ultravisor/spec/ultravisor/child/spawn_spec.rb +0 -107
- data/ultravisor/spec/ultravisor/child/unsafe_instance_spec.rb +0 -55
- data/ultravisor/spec/ultravisor/child/wait_spec.rb +0 -32
- data/ultravisor/spec/ultravisor/new_spec.rb +0 -71
- data/ultravisor/spec/ultravisor/remove_child_spec.rb +0 -49
- data/ultravisor/spec/ultravisor/run_spec.rb +0 -334
- data/ultravisor/spec/ultravisor/shutdown_spec.rb +0 -106
@@ -0,0 +1,80 @@
|
|
1
|
+
class ServiceSkeleton
|
2
|
+
module BackgroundWorker
|
3
|
+
include ServiceSkeleton::LoggingHelpers
|
4
|
+
|
5
|
+
# async code is a shit to test, and rarely finds bugs anyway, so let's
|
6
|
+
# just
|
7
|
+
#:nocov:
|
8
|
+
# this whole thing.
|
9
|
+
|
10
|
+
# This signal is raised internally if needed to shut down a worker thread.
|
11
|
+
class TerminateBackgroundThread < Exception; end
|
12
|
+
private_constant :TerminateBackgroundThread
|
13
|
+
|
14
|
+
def initialize(*_)
|
15
|
+
@bg_worker_op_mutex = Mutex.new
|
16
|
+
@bg_worker_op_cv = ConditionVariable.new
|
17
|
+
|
18
|
+
begin
|
19
|
+
super
|
20
|
+
rescue ArgumentError => ex
|
21
|
+
if ex.message =~ /wrong number of arguments.*expected 0/
|
22
|
+
super()
|
23
|
+
else
|
24
|
+
raise
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def start!
|
30
|
+
@bg_worker_op_mutex.synchronize do
|
31
|
+
return if @bg_worker_thread
|
32
|
+
|
33
|
+
@bg_worker_thread = Thread.new do
|
34
|
+
Thread.current.name = self.class.to_s
|
35
|
+
|
36
|
+
Thread.handle_interrupt(Exception => :never) do
|
37
|
+
logger.debug("BackgroundWorker(#{self.class})#start!") { "Background worker thread #{Thread.current.object_id} starting" }
|
38
|
+
begin
|
39
|
+
Thread.handle_interrupt(Exception => :immediate) do
|
40
|
+
@bg_worker_op_mutex.synchronize { @bg_worker_op_cv.signal }
|
41
|
+
self.start
|
42
|
+
end
|
43
|
+
rescue TerminateBackgroundThread
|
44
|
+
logger.debug("BackgroundWorker(#{self.class})#start!") { "Background worker thread #{Thread.current.object_id} received magical termination exception" }
|
45
|
+
rescue Exception => ex
|
46
|
+
log_exception(ex) { "Background worker thread #{Thread.current.object_id} received fatal exception" }
|
47
|
+
else
|
48
|
+
logger.debug("BackgroundWorker(#{self.class})#start!") { "Background worker thread #{Thread.current.object_id} terminating" }
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
@bg_worker_op_cv.wait(@bg_worker_op_mutex) until @bg_worker_thread
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def stop!
|
58
|
+
@bg_worker_op_mutex.synchronize do
|
59
|
+
return if @bg_worker_thread.nil?
|
60
|
+
|
61
|
+
logger.debug("BackgroundWorker(#{self.class})#stop!") { "Terminating worker thread #{Thread.current.object_id} as requested" }
|
62
|
+
|
63
|
+
shutdown
|
64
|
+
|
65
|
+
@bg_worker_thread.join
|
66
|
+
@bg_worker_thread = nil
|
67
|
+
|
68
|
+
logger.debug("BackgroundWorker(#{self.class})#stop!") { "Worker thread terminated" }
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
private
|
73
|
+
|
74
|
+
attr_reader :logger
|
75
|
+
|
76
|
+
def shutdown
|
77
|
+
@bg_worker_thread.raise(TerminateBackgroundThread)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
@@ -1,58 +1,38 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
1
|
require "to_regexp"
|
4
2
|
|
5
3
|
require_relative "./filtering_logger"
|
6
4
|
|
7
|
-
|
8
|
-
|
9
|
-
module ServiceSkeleton
|
5
|
+
class ServiceSkeleton
|
10
6
|
class Config
|
11
|
-
attr_reader :logger
|
12
|
-
|
13
|
-
def initialize(env, service_name, variables)
|
14
|
-
@service_name = service_name
|
15
|
-
|
16
|
-
# Parsing variables will redact the environment, so we want to take a
|
17
|
-
# private unredacted copy before that happens for #[] lookup in the
|
18
|
-
# future.
|
19
|
-
@env = env.to_hash.dup.freeze
|
7
|
+
attr_reader :logger
|
20
8
|
|
21
|
-
|
9
|
+
def initialize(env, svc)
|
10
|
+
@env = env.to_hash.freeze
|
11
|
+
@svc = svc
|
22
12
|
|
23
|
-
|
24
|
-
# logger, which requires parsing config variables
|
13
|
+
parse_registered_variables(env)
|
25
14
|
setup_logger
|
26
15
|
end
|
27
16
|
|
28
17
|
def [](k)
|
29
|
-
@env[k]
|
18
|
+
@env[k]
|
30
19
|
end
|
31
20
|
|
32
21
|
private
|
33
22
|
|
34
|
-
def
|
35
|
-
|
36
|
-
var
|
37
|
-
|
38
|
-
val = var.value
|
39
|
-
method_name = var.method_name(@service_name).to_sym
|
40
|
-
|
41
|
-
define_singleton_method(method_name) do
|
23
|
+
def parse_registered_variables(env)
|
24
|
+
@svc.registered_variables.each do |var|
|
25
|
+
val = var.value(env[var.name.to_s])
|
26
|
+
define_singleton_method(var.method_name(@svc.service_name)) do
|
42
27
|
val
|
43
28
|
end
|
44
29
|
|
45
|
-
|
46
|
-
val = new_value
|
47
|
-
end
|
48
|
-
end.each do |var|
|
49
|
-
if var.redact?(env)
|
30
|
+
if var.sensitive?
|
50
31
|
if env.object_id != ENV.object_id
|
51
32
|
raise ServiceSkeleton::Error::CannotSanitizeEnvironmentError,
|
52
|
-
"Attempted to sanitize sensitive variable #{var.name}, but
|
53
|
-
else
|
54
|
-
var.redact!(env)
|
33
|
+
"Attempted to sanitize sensitive variable #{var.name}, but was not passed the ENV object"
|
55
34
|
end
|
35
|
+
env.delete(var.name.to_s)
|
56
36
|
end
|
57
37
|
end
|
58
38
|
end
|
@@ -66,42 +46,14 @@ module ServiceSkeleton
|
|
66
46
|
|
67
47
|
@logger = Logger.new(log_file || $stderr, shift_age, shift_size)
|
68
48
|
|
69
|
-
|
70
|
-
|
71
|
-
# initialised. This should never be updated after it is configured.
|
72
|
-
@pre_run_logger = Logger.new(log_file || $stderr, shift_age, shift_size)
|
73
|
-
|
74
|
-
if Thread.main
|
75
|
-
Thread.main[:thread_map_number] = 0
|
49
|
+
if log_enable_timestamps
|
50
|
+
@logger.formatter = ->(s, t, p, m) { "#{t.utc.strftime("%FT%T.%NZ")} #{s[0]} [#{p}] #{m}\n" }
|
76
51
|
else
|
77
|
-
|
78
|
-
Thread.current[:thread_map_number] = 0
|
79
|
-
#:nocov:
|
80
|
-
end
|
81
|
-
|
82
|
-
thread_map_mutex = Mutex.new
|
83
|
-
|
84
|
-
[@logger, @pre_run_logger].each do |logger|
|
85
|
-
logger.formatter = ->(s, t, p, m) do
|
86
|
-
th_n = if Thread.current.name
|
87
|
-
#:nocov:
|
88
|
-
Thread.current.name
|
89
|
-
#:nocov:
|
90
|
-
else
|
91
|
-
thread_map_mutex.synchronize do
|
92
|
-
Thread.current[:thread_map_number] ||= begin
|
93
|
-
Thread.list.select { |th| th[:thread_map_number] }.length
|
94
|
-
end
|
95
|
-
end
|
96
|
-
end
|
97
|
-
|
98
|
-
ts = log_enable_timestamps ? "#{t.utc.strftime("%FT%T.%NZ")} " : ""
|
99
|
-
"#{ts}#{$$}##{th_n} #{s[0]} [#{p}] #{m}\n"
|
100
|
-
end
|
52
|
+
@logger.formatter = ->(s, t, p, m) { "#{s[0]} [#{p}] #{m}\n" }
|
101
53
|
end
|
102
54
|
|
103
55
|
@logger.filters = []
|
104
|
-
@env.fetch("#{@service_name.upcase}_LOG_LEVEL", "INFO").split(/\s*,\s*/).each do |spec|
|
56
|
+
@env.fetch("#{@svc.service_name.upcase}_LOG_LEVEL", "INFO").split(/\s*,\s*/).each do |spec|
|
105
57
|
if spec.index("=")
|
106
58
|
# "Your developers were so preoccupied with whether or not they
|
107
59
|
# could, they didn't stop to think if they should."
|
@@ -124,17 +76,5 @@ module ServiceSkeleton
|
|
124
76
|
end
|
125
77
|
end
|
126
78
|
end
|
127
|
-
|
128
|
-
def internal_variables
|
129
|
-
[
|
130
|
-
{ name: "#{@service_name.upcase}_LOG_LEVEL", class: ConfigVariable::String, opts: { default: "INFO" } },
|
131
|
-
{ name: "#{@service_name.upcase}_LOG_ENABLE_TIMESTAMPS", class: ConfigVariable::Boolean, opts: { default: false } },
|
132
|
-
{ name: "#{@service_name.upcase}_LOG_FILE", class: ConfigVariable::String, opts: { default: nil } },
|
133
|
-
{ name: "#{@service_name.upcase}_LOG_MAX_FILE_SIZE", class: ConfigVariable::Integer, opts: { default: 1048576, range: 0..Float::INFINITY } },
|
134
|
-
{ name: "#{@service_name.upcase}_LOG_MAX_FILES", class: ConfigVariable::Integer, opts: { default: 3, range: 1..Float::INFINITY } },
|
135
|
-
{ name: "#{@service_name.upcase}_LOGSTASH_SERVER", class: ConfigVariable::String, opts: { default: "" } },
|
136
|
-
{ name: "#{@service_name.upcase}_METRICS_PORT", class: ConfigVariable::Integer, opts: { default: nil, range: 1..65535 } },
|
137
|
-
]
|
138
|
-
end
|
139
79
|
end
|
140
80
|
end
|
@@ -1,44 +1,23 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
module ServiceSkeleton
|
1
|
+
class ServiceSkeleton
|
4
2
|
class ConfigVariable
|
5
|
-
attr_reader :name
|
3
|
+
attr_reader :name
|
6
4
|
|
7
|
-
def initialize(name,
|
5
|
+
def initialize(name, **opts, &blk)
|
8
6
|
@name = name
|
9
7
|
@opts = opts
|
10
8
|
@blk = blk
|
11
|
-
|
12
|
-
@value = pluck_value(env)
|
13
9
|
end
|
14
10
|
|
15
11
|
def method_name(svc_name)
|
16
|
-
|
12
|
+
name.to_s.gsub(/\A#{Regexp.quote(svc_name)}_/i, '').downcase
|
17
13
|
end
|
18
14
|
|
19
|
-
def
|
20
|
-
|
15
|
+
def sensitive?
|
16
|
+
!!@opts[:sensitive]
|
21
17
|
end
|
22
18
|
|
23
|
-
def
|
24
|
-
|
25
|
-
env[@name.to_s] = "*SENSITIVE*" if env.has_key?(@name.to_s)
|
26
|
-
end
|
27
|
-
end
|
28
|
-
|
29
|
-
private
|
30
|
-
|
31
|
-
def maybe_default(env)
|
32
|
-
if env.has_key?(@name.to_s)
|
33
|
-
yield
|
34
|
-
else
|
35
|
-
if @opts.has_key?(:default)
|
36
|
-
@opts[:default]
|
37
|
-
else
|
38
|
-
raise ServiceSkeleton::Error::InvalidEnvironmentError,
|
39
|
-
"Value for required environment variable #{@name} not specified"
|
40
|
-
end
|
41
|
-
end
|
19
|
+
def value(raw_val)
|
20
|
+
@blk.call(raw_val)
|
42
21
|
end
|
43
22
|
end
|
44
23
|
end
|
@@ -1,79 +1,93 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
1
|
require_relative "./error"
|
4
2
|
|
5
3
|
require "service_skeleton/config_variable"
|
6
4
|
|
7
|
-
|
5
|
+
class ServiceSkeleton
|
8
6
|
module ConfigVariables
|
9
|
-
|
7
|
+
attr_reader :registered_variables
|
8
|
+
|
9
|
+
UNDEFINED = Class.new
|
10
10
|
private_constant :UNDEFINED
|
11
11
|
|
12
|
-
def
|
12
|
+
def register_variable(name, **opts, &callback)
|
13
13
|
@registered_variables ||= []
|
14
|
+
|
15
|
+
@registered_variables << ServiceSkeleton::ConfigVariable.new(name, **opts, &callback)
|
14
16
|
end
|
15
17
|
|
16
|
-
def
|
17
|
-
|
18
|
-
|
18
|
+
def string(var_name, default: UNDEFINED, sensitive: false)
|
19
|
+
register_variable(var_name, sensitive: sensitive) do |value|
|
20
|
+
maybe_default(value, default, var_name) do
|
21
|
+
value
|
22
|
+
end
|
19
23
|
end
|
20
|
-
|
21
|
-
registered_variables << {
|
22
|
-
name: name,
|
23
|
-
class: klass,
|
24
|
-
opts: opts,
|
25
|
-
}
|
26
24
|
end
|
27
25
|
|
28
26
|
def boolean(var_name, default: UNDEFINED, sensitive: false)
|
29
|
-
register_variable(var_name,
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
27
|
+
register_variable(var_name, sensitive: sensitive) do |value|
|
28
|
+
maybe_default(value, default, var_name) do
|
29
|
+
case value
|
30
|
+
when /\A(no|n|off|0|false)\z/i
|
31
|
+
false
|
32
|
+
when /\A(yes|y|on|1|true)\z/i
|
33
|
+
true
|
34
|
+
else
|
35
|
+
raise ServiceSkeleton::Error::InvalidEnvironmentError,
|
36
|
+
"Value #{value.inspect} for environment variable #{var_name} is not a valid boolean value"
|
37
|
+
end
|
38
|
+
end
|
36
39
|
end
|
37
|
-
|
38
|
-
register_variable(var_name, ConfigVariable::Enum, default: default, sensitive: sensitive, values: values)
|
39
|
-
end
|
40
|
-
|
41
|
-
def float(var_name, default: UNDEFINED, sensitive: false, range: -Float::INFINITY..Float::INFINITY)
|
42
|
-
register_variable(var_name, ConfigVariable::Float, default: default, sensitive: sensitive, range: range)
|
43
40
|
end
|
44
41
|
|
45
42
|
def integer(var_name, default: UNDEFINED, sensitive: false, range: -Float::INFINITY..Float::INFINITY)
|
46
|
-
register_variable(var_name,
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
43
|
+
register_variable(var_name, sensitive: sensitive) do |value|
|
44
|
+
maybe_default(value, default, var_name) do
|
45
|
+
if value =~ /\A-?\d+\z/
|
46
|
+
value.to_i.tap do |i|
|
47
|
+
unless range.include?(i)
|
48
|
+
raise ServiceSkeleton::Error::InvalidEnvironmentError,
|
49
|
+
"Value #{i} for environment variable #{var_name} is out of the valid range (must be between #{range.first} and #{range.last} inclusive)"
|
50
|
+
end
|
51
|
+
end
|
52
|
+
else
|
53
|
+
raise ServiceSkeleton::Error::InvalidEnvironmentError,
|
54
|
+
"Value #{value.inspect} for environment variable #{var_name} is not a valid integer value"
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
59
58
|
end
|
60
59
|
|
61
|
-
def
|
62
|
-
register_variable(var_name,
|
60
|
+
def float(var_name, default: UNDEFINED, sensitive: false, range: -Float::INFINITY..Float::INFINITY)
|
61
|
+
register_variable(var_name, sensitive: sensitive) do |value|
|
62
|
+
maybe_default(value, default, var_name) do
|
63
|
+
if value =~ /\A-?\d+.?\d*\z/
|
64
|
+
value.to_f.tap do |i|
|
65
|
+
unless range.include?(i)
|
66
|
+
raise ServiceSkeleton::Error::InvalidEnvironmentError,
|
67
|
+
"Value #{i} for environment variable #{var_name} is out of the valid range (must be between #{range.first} and #{range.last} inclusive)"
|
68
|
+
end
|
69
|
+
end
|
70
|
+
else
|
71
|
+
raise ServiceSkeleton::Error::InvalidEnvironmentError,
|
72
|
+
"Value #{value.inspect} for environment variable #{var_name} is not a valid numeric value"
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
63
76
|
end
|
64
77
|
|
65
|
-
|
66
|
-
|
78
|
+
private
|
79
|
+
|
80
|
+
def maybe_default(value, default, var_name)
|
81
|
+
if value.nil?
|
82
|
+
if default == UNDEFINED
|
83
|
+
raise ServiceSkeleton::Error::InvalidEnvironmentError,
|
84
|
+
"Value for required environment variable #{var_name} not specified"
|
85
|
+
else
|
86
|
+
default
|
87
|
+
end
|
88
|
+
else
|
89
|
+
yield
|
90
|
+
end
|
67
91
|
end
|
68
92
|
end
|
69
93
|
end
|
70
|
-
|
71
|
-
require_relative "config_variable/boolean"
|
72
|
-
require_relative "config_variable/enum"
|
73
|
-
require_relative "config_variable/float"
|
74
|
-
require_relative "config_variable/integer"
|
75
|
-
require_relative "config_variable/kv_list"
|
76
|
-
require_relative "config_variable/path_list"
|
77
|
-
require_relative "config_variable/string"
|
78
|
-
require_relative "config_variable/url"
|
79
|
-
require_relative "config_variable/yaml_file"
|
@@ -1,10 +1,8 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
module ServiceSkeleton
|
1
|
+
class ServiceSkeleton
|
4
2
|
class Error < StandardError
|
5
|
-
class CannotSanitizeEnvironmentError < Error; end
|
6
3
|
class InvalidEnvironmentError < Error; end
|
4
|
+
class CannotSanitizeEnvironmentError < Error; end
|
5
|
+
class InheritanceContractError < Error; end
|
7
6
|
class InvalidMetricNameError < Error; end
|
8
|
-
class InvalidServiceClassError < Error; end
|
9
7
|
end
|
10
8
|
end
|
@@ -1,28 +1,21 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
module ServiceSkeleton
|
1
|
+
class ServiceSkeleton
|
4
2
|
module LoggingHelpers
|
5
3
|
private
|
6
4
|
|
7
5
|
def log_exception(ex, progname = nil)
|
8
|
-
#:nocov:
|
9
6
|
progname ||= "#{self.class.to_s}##{caller_locations(2, 1).first.label}"
|
10
7
|
|
11
8
|
logger.error(progname) do
|
9
|
+
#:nocov:
|
12
10
|
explanation = if block_given?
|
13
11
|
yield
|
14
12
|
else
|
15
13
|
nil
|
16
14
|
end
|
15
|
+
#:nocov:
|
17
16
|
|
18
17
|
(["#{explanation}#{explanation ? ": " : ""}#{ex.message} (#{ex.class})"] + ex.backtrace).join("\n ")
|
19
18
|
end
|
20
|
-
#:nocov:
|
21
|
-
end
|
22
|
-
|
23
|
-
def logloc
|
24
|
-
loc = caller_locations.first
|
25
|
-
"#{self.class}##{loc.label}"
|
26
19
|
end
|
27
20
|
end
|
28
21
|
end
|
@@ -1,37 +1,22 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
require "prometheus/client"
|
4
|
-
|
5
|
-
require_relative "metric_method_name"
|
6
|
-
|
7
|
-
Prometheus::Client::Metric.include(ServiceSkeleton::MetricMethodName)
|
8
|
-
|
9
|
-
module ServiceSkeleton
|
1
|
+
class ServiceSkeleton
|
10
2
|
module MetricsMethods
|
11
|
-
def
|
12
|
-
@
|
13
|
-
end
|
14
|
-
|
15
|
-
def metric(metric)
|
16
|
-
@registered_metrics ||= []
|
17
|
-
|
18
|
-
@registered_metrics << metric
|
3
|
+
def service=(svc)
|
4
|
+
@service = svc
|
19
5
|
end
|
20
6
|
|
21
|
-
def
|
22
|
-
metric(
|
23
|
-
end
|
7
|
+
def register(metric)
|
8
|
+
method_name = metric.name.to_s.gsub(/\A#{Regexp.quote(@service.service_name)}_/, '').to_sym
|
24
9
|
|
25
|
-
|
26
|
-
|
27
|
-
|
10
|
+
if self.class.method_defined?(method_name)
|
11
|
+
raise ServiceSkeleton::Error::InvalidMetricNameError,
|
12
|
+
"There is already a method named #{method_name} on ##metrics, so you can't have a metric named #{metric.name}"
|
13
|
+
end
|
28
14
|
|
29
|
-
|
30
|
-
|
31
|
-
|
15
|
+
define_singleton_method(method_name) do
|
16
|
+
metric
|
17
|
+
end
|
32
18
|
|
33
|
-
|
34
|
-
metric(Prometheus::Client::Histogram.new(name, docstring: docstring, labels: labels, preset_labels: preset_labels, buckets: buckets))
|
19
|
+
super
|
35
20
|
end
|
36
21
|
end
|
37
22
|
end
|