prometheus-splash 0.3.0 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/ruby.yml +25 -0
- data/CHANGELOG +26 -0
- data/README.md +37 -1
- data/assets/images/splash_design.png +0 -0
- data/bin/splash +9 -1
- data/config/splash.yml +13 -3
- data/lib/splash/backends/file.rb +16 -0
- data/lib/splash/cli/commands.rb +117 -41
- data/lib/splash/cli/config.rb +7 -5
- data/lib/splash/cli/daemon.rb +8 -4
- data/lib/splash/cli/logs.rb +32 -18
- data/lib/splash/commands.rb +17 -16
- data/lib/splash/config.rb +4 -0
- data/lib/splash/config/sanitycheck.rb +23 -19
- data/lib/splash/config/setup.rb +15 -11
- data/lib/splash/constants.rb +9 -5
- data/lib/splash/controller.rb +20 -10
- data/lib/splash/dependencies.rb +3 -0
- data/lib/splash/exiter.rb +4 -2
- data/lib/splash/helpers.rb +30 -4
- data/lib/splash/loggers.rb +89 -0
- data/lib/splash/loggers/cli.rb +83 -0
- data/lib/splash/loggers/daemon.rb +32 -0
- data/lib/splash/loggers/dual.rb +22 -0
- data/lib/splash/logs.rb +4 -3
- data/lib/splash/orchestrator.rb +17 -8
- data/lib/splash/orchestrator/grammar.rb +13 -6
- data/lib/splash/transports.rb +2 -2
- data/lib/splash/transports/rabbitmq.rb +16 -2
- data/prometheus-splash.gemspec +2 -1
- metadata +23 -2
data/lib/splash/controller.rb
CHANGED
@@ -6,25 +6,34 @@ module Splash
|
|
6
6
|
include Splash::Helpers
|
7
7
|
include Splash::Config
|
8
8
|
include Splash::Orchestrator
|
9
|
+
include Splash::Exiter
|
10
|
+
include Splash::Loggers
|
9
11
|
|
10
12
|
def startdaemon(options = {})
|
11
13
|
config = get_config
|
14
|
+
log = get_logger
|
12
15
|
unless verify_service host: config.prometheus_pushgateway_host ,port: config.prometheus_pushgateway_port then
|
13
16
|
return {:case => :service_dependence_missing, :more => 'Prometheus Gateway'}
|
14
17
|
end
|
15
18
|
unless File::exist? config.full_pid_path then
|
16
|
-
|
19
|
+
daemon_config = {:description => config.daemon_process_name,
|
17
20
|
:pid_file => config.full_pid_path,
|
18
21
|
:stdout_trace => config.full_stdout_trace_path,
|
19
|
-
:stderr_trace => config.full_stderr_trace_path,
|
22
|
+
:stderr_trace => config.full_stderr_trace_path,
|
23
|
+
:foreground => options[:foreground]
|
24
|
+
}
|
25
|
+
|
26
|
+
["int","term","hup"].each do |type| daemon_config["sig#{type}_handler".to_sym] = Proc::new { ObjectSpace.each_object(Splash::Orchestrator::Scheduler).first.shutdown } end
|
27
|
+
res = daemonize daemon_config do
|
20
28
|
Scheduler::new options
|
21
29
|
end
|
30
|
+
sleep 1
|
22
31
|
if res == 0 then
|
23
32
|
pid = `cat #{config.full_pid_path}`.to_i
|
24
|
-
|
25
|
-
return {:case => :quiet_exit}
|
33
|
+
log.ok "Splash Daemon Started, with PID : #{pid}"
|
34
|
+
return {:case => :quiet_exit, :more => "Splash Daemon successfully loaded."}
|
26
35
|
else
|
27
|
-
return {:case => :unknown_error, :more => "Splash Daemon loading error, see logs for more details"}
|
36
|
+
return {:case => :unknown_error, :more => "Splash Daemon loading error, see logs for more details."}
|
28
37
|
end
|
29
38
|
|
30
39
|
else
|
@@ -49,7 +58,8 @@ module Splash
|
|
49
58
|
return acase
|
50
59
|
end
|
51
60
|
|
52
|
-
def statusdaemon
|
61
|
+
def statusdaemon(options = {})
|
62
|
+
log = get_logger
|
53
63
|
config = get_config
|
54
64
|
pid = realpid = ''
|
55
65
|
pid = `cat #{config.full_pid_path}`.to_s if File.exist?(config.full_pid_path)
|
@@ -57,14 +67,14 @@ module Splash
|
|
57
67
|
pid.chomp!
|
58
68
|
realpid.chomp!
|
59
69
|
unless realpid.empty? then
|
60
|
-
|
70
|
+
log.item "Splash Process is running with PID #{realpid} "
|
61
71
|
else
|
62
|
-
|
72
|
+
log.item 'Splash Process not found '
|
63
73
|
end
|
64
74
|
unless pid.empty? then
|
65
|
-
|
75
|
+
log.item "and PID file exist with PID #{pid}"
|
66
76
|
else
|
67
|
-
|
77
|
+
log.item "and PID file don't exist"
|
68
78
|
end
|
69
79
|
if pid == realpid then
|
70
80
|
return {:case => :status_ok }
|
data/lib/splash/dependencies.rb
CHANGED
@@ -24,6 +24,7 @@ module Splash
|
|
24
24
|
require 'rufus-scheduler'
|
25
25
|
require 'tty-markdown'
|
26
26
|
require 'tty-pager'
|
27
|
+
require 'colorize'
|
27
28
|
require "redis"
|
28
29
|
|
29
30
|
rescue Gem::GemNotFoundException
|
@@ -37,11 +38,13 @@ module Splash
|
|
37
38
|
require 'splash/constants'
|
38
39
|
require 'splash/helpers'
|
39
40
|
require 'splash/config'
|
41
|
+
require 'splash/loggers'
|
40
42
|
require 'splash/exiter'
|
41
43
|
require 'splash/templates'
|
42
44
|
require 'splash/backends'
|
43
45
|
require 'splash/transports'
|
44
46
|
|
47
|
+
|
45
48
|
require 'splash/commands'
|
46
49
|
require 'splash/logs'
|
47
50
|
require 'splash/orchestrator'
|
data/lib/splash/exiter.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
# coding: utf-8
|
2
2
|
module Splash
|
3
3
|
module Exiter
|
4
|
+
include Splash::Loggers
|
4
5
|
EXIT_MAP= {
|
5
6
|
|
6
7
|
# context execution
|
@@ -34,15 +35,16 @@ module Splash
|
|
34
35
|
}
|
35
36
|
|
36
37
|
def splash_exit(options = {})
|
38
|
+
log = get_logger
|
37
39
|
mess = ""
|
38
40
|
mess = EXIT_MAP[options[:case]][:message] if EXIT_MAP[options[:case]].include? :message
|
39
41
|
mess << " : " unless mess.empty? or not options[:more]
|
40
42
|
mess << "#{options[:more]}" if options[:more]
|
41
43
|
if EXIT_MAP[options[:case]][:code] == 0 then
|
42
|
-
|
44
|
+
log.success mess unless mess.empty?
|
43
45
|
exit 0
|
44
46
|
else
|
45
|
-
|
47
|
+
log.fatal mess unless mess.empty?
|
46
48
|
exit EXIT_MAP[options[:case]][:code]
|
47
49
|
end
|
48
50
|
end
|
data/lib/splash/helpers.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
# @option options [String] :stdout_trace the path of the file where to redirect STDOUT
|
1
2
|
# coding: utf-8
|
2
3
|
module Splash
|
3
4
|
module Helpers
|
@@ -89,6 +90,9 @@ module Splash
|
|
89
90
|
# @option options [String] :daemon_group the group to change privileges
|
90
91
|
# @option options [String] :stderr_trace the path of the file where to redirect STDERR
|
91
92
|
# @option options [String] :stdout_trace the path of the file where to redirect STDOUT
|
93
|
+
# @option options [Proc] :sigint_handler handler Proc for SIGINT signal
|
94
|
+
# @option options [Proc] :sigterm_handler handler Proc for SIGTERM signal
|
95
|
+
# @option options [Proc] :sighup_handler handler Proc for SIGHuP signal
|
92
96
|
# @option options [Bool] :foreground option to run foreground
|
93
97
|
# @yield a process definion or block given
|
94
98
|
# @example usage inline
|
@@ -129,11 +133,33 @@ module Splash
|
|
129
133
|
#Process.euid = 0
|
130
134
|
#Process.egid = 0
|
131
135
|
|
132
|
-
trap("SIGINT"){
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
+
trap("SIGINT"){
|
137
|
+
if options[:sigint_handler] then
|
138
|
+
options[:sigint_handler].call
|
139
|
+
else
|
140
|
+
exit! 0
|
141
|
+
end
|
142
|
+
}
|
143
|
+
trap("SIGTERM"){
|
144
|
+
if options[:sigterm_handler] then
|
145
|
+
options[:sigterm_handler].call
|
146
|
+
else
|
147
|
+
exit! 0
|
148
|
+
end
|
149
|
+
}
|
150
|
+
trap("SIGHUP"){
|
151
|
+
if options[:sighup_handler] then
|
152
|
+
options[:sighup_handler].call
|
153
|
+
else
|
154
|
+
exit! 0
|
155
|
+
end
|
156
|
+
}
|
157
|
+
if options[:foreground]
|
158
|
+
change_logger logger: :dual
|
159
|
+
return yield
|
160
|
+
end
|
136
161
|
fork do
|
162
|
+
change_logger logger: :daemon
|
137
163
|
#Process.daemon
|
138
164
|
File.open(options[:pid_file],"w"){|f| f.puts Process.pid } if options[:pid_file]
|
139
165
|
if options[:daemon_user] and options[:daemon_group] then
|
@@ -0,0 +1,89 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
|
4
|
+
module Splash
|
5
|
+
module Loggers
|
6
|
+
include Splash::Config
|
7
|
+
|
8
|
+
@@logger=nil
|
9
|
+
|
10
|
+
def get_logger(options = {})
|
11
|
+
logger = (get_config.loggers[:list].include? options[:logger])? options[:logger].to_s : get_config.loggers[:default].to_s
|
12
|
+
aclass = "Splash::Loggers::#{logger.capitalize}"
|
13
|
+
# begin
|
14
|
+
return @@logger = Kernel.const_get(aclass)::new if options[:force]
|
15
|
+
return @@logger ||= Kernel.const_get(aclass)::new
|
16
|
+
# rescue
|
17
|
+
# splash_exit case: :configuration_error, more: "Logger specified inexistant : #{logger}"
|
18
|
+
# end
|
19
|
+
end
|
20
|
+
|
21
|
+
|
22
|
+
def change_logger(options = {})
|
23
|
+
options[:force] = true
|
24
|
+
get_logger(options)
|
25
|
+
end
|
26
|
+
|
27
|
+
|
28
|
+
|
29
|
+
class LoggerTemplate
|
30
|
+
include Splash::Config
|
31
|
+
|
32
|
+
LEVELS = [:debug, :warn, :info, :result, :fatal, :unknown]
|
33
|
+
ALIAS = {:flat => :info, :item => :info, :ok => :info, :ko => :info, :trigger => :info,
|
34
|
+
:schedule => :info, :arrow => :info, :send => :info,
|
35
|
+
:receive => :info, :error => :result, :success => :result }
|
36
|
+
LEVELS.each do |method|
|
37
|
+
define_method(method) do |message|
|
38
|
+
self.log({ :level => method, :message => message})
|
39
|
+
end
|
40
|
+
end
|
41
|
+
ALIAS.keys.each do |method|
|
42
|
+
define_method(method) do |message|
|
43
|
+
self.log({ :level => method, :message => message})
|
44
|
+
end
|
45
|
+
end
|
46
|
+
def initialize
|
47
|
+
self.level = get_config.loggers[:level]
|
48
|
+
|
49
|
+
|
50
|
+
end
|
51
|
+
|
52
|
+
|
53
|
+
def log(options)
|
54
|
+
level = (ALIAS.keys.include? options[:level])? ALIAS[options[:level]] : options[:level]
|
55
|
+
if @active_levels.include? level then
|
56
|
+
puts options[:message]
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
|
61
|
+
def level
|
62
|
+
return @active_levels.first
|
63
|
+
end
|
64
|
+
|
65
|
+
def level=(level)
|
66
|
+
if LEVELS.include? level then
|
67
|
+
@active_levels = LEVELS.dup
|
68
|
+
@active_levels.shift(LEVELS.index(level))
|
69
|
+
else
|
70
|
+
raise BadLevel
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
|
75
|
+
private
|
76
|
+
def alt(symbol)
|
77
|
+
return "=>" if symbol == :arrow
|
78
|
+
return '' if symbol == :flat
|
79
|
+
return symbol.to_s.upcase
|
80
|
+
end
|
81
|
+
|
82
|
+
end
|
83
|
+
|
84
|
+
class BadLevel < Exception; end
|
85
|
+
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
Dir[File.dirname(__FILE__) + '/loggers/*.rb'].each {|file| require file }
|
@@ -0,0 +1,83 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
module Splash
|
3
|
+
module Loggers
|
4
|
+
|
5
|
+
class Cli < Splash::Loggers::LoggerTemplate
|
6
|
+
|
7
|
+
include Splash::Config
|
8
|
+
|
9
|
+
EMOJI = { :unknown => "\u{1F4A5}",
|
10
|
+
:fatal => "\u{26D4}",
|
11
|
+
:error => "\u{1F6AB}",
|
12
|
+
:ko => "\u{1F44E}",
|
13
|
+
:warn => "\u{26A0}",
|
14
|
+
:info => "\u{2139}",
|
15
|
+
:item => " \u{1F539}",
|
16
|
+
:arrow => " \u{27A1}",
|
17
|
+
:schedule => "\u{23F1}",
|
18
|
+
:trigger => "\u{23F0}",
|
19
|
+
:send => "\u{1F4E4}",
|
20
|
+
:receive => "\u{1F4E5}",
|
21
|
+
:ok => "\u{1F44D}",
|
22
|
+
:success => "\u{1F4AA}",
|
23
|
+
:debug => "\u{1F41B}"}
|
24
|
+
|
25
|
+
COLORS = { :unknown => :red,
|
26
|
+
:fatal => :red,
|
27
|
+
:error => :red,
|
28
|
+
:ko => :yellow,
|
29
|
+
:warn => :yellow,
|
30
|
+
:item => :white,
|
31
|
+
:arrow => :white,
|
32
|
+
:send => :white,
|
33
|
+
:schedule => :white,
|
34
|
+
:trigger => :white,
|
35
|
+
:receive => :white,
|
36
|
+
:info => :cyan,
|
37
|
+
:ok => :green,
|
38
|
+
:success => :green,
|
39
|
+
:debug => :magenta}
|
40
|
+
|
41
|
+
|
42
|
+
|
43
|
+
def log(options)
|
44
|
+
level = (ALIAS.keys.include? options[:level])? ALIAS[options[:level]] : options[:level]
|
45
|
+
if @active_levels.include? level then
|
46
|
+
if options[:level] == :flat then
|
47
|
+
puts options[:message]
|
48
|
+
else
|
49
|
+
String.disable_colorization = !get_config.loggers[:cli][:color]
|
50
|
+
emoji = get_config.loggers[:cli][:emoji]
|
51
|
+
emoji = check_unicode_term if emoji
|
52
|
+
if emoji then
|
53
|
+
display = "#{EMOJI[options[:level]]} #{options[:message]}"
|
54
|
+
else
|
55
|
+
display = "#{alt(options[:level])} #{options[:message]}"
|
56
|
+
end
|
57
|
+
puts display.colorize(COLORS[options[:level]])
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def emoji=(status)
|
63
|
+
get_config.loggers[:cli][:emoji] = status
|
64
|
+
end
|
65
|
+
|
66
|
+
def color=(status)
|
67
|
+
get_config.loggers[:cli][:color] = status
|
68
|
+
end
|
69
|
+
|
70
|
+
def check_unicode_term
|
71
|
+
if ENV.values_at("LC_ALL","LC_CTYPE","LANG").compact.first.include?("UTF-8") and ENV.values_at('TERM').first.include? "xterm" then
|
72
|
+
return true
|
73
|
+
else
|
74
|
+
return false
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
end
|
79
|
+
|
80
|
+
class BadLevel < Exception; end
|
81
|
+
|
82
|
+
end
|
83
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
module Splash
|
3
|
+
module Loggers
|
4
|
+
|
5
|
+
|
6
|
+
class Daemon < Splash::Loggers::LoggerTemplate
|
7
|
+
|
8
|
+
|
9
|
+
|
10
|
+
def initialize
|
11
|
+
self.level = get_config.loggers[:level]
|
12
|
+
@log_file = get_config.loggers[:daemon][:file]
|
13
|
+
@stream = File::open(@log_file, 'a')
|
14
|
+
@stream.sync = true
|
15
|
+
end
|
16
|
+
|
17
|
+
|
18
|
+
def log(options)
|
19
|
+
level = (ALIAS.keys.include? options[:level])? ALIAS[options[:level]] : options[:level]
|
20
|
+
if @active_levels.include? level then
|
21
|
+
@stream.puts "#{alt(options[:level])} #{options[:message]}"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def close
|
26
|
+
@stream.close
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Splash
|
2
|
+
module Loggers
|
3
|
+
|
4
|
+
class Dual < Splash::Loggers::LoggerTemplate
|
5
|
+
include Splash::Config
|
6
|
+
|
7
|
+
|
8
|
+
|
9
|
+
def initialize
|
10
|
+
super
|
11
|
+
@log1 = Splash::Loggers::Cli::new
|
12
|
+
@log2 = Splash::Loggers::Daemon::new
|
13
|
+
end
|
14
|
+
|
15
|
+
def log(options)
|
16
|
+
@log1.log options
|
17
|
+
@log2.log options
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
data/lib/splash/logs.rb
CHANGED
@@ -43,13 +43,14 @@ module Splash
|
|
43
43
|
|
44
44
|
# start notification on prometheus for metric logerrors, logmissing; loglines
|
45
45
|
def notify
|
46
|
+
log = get_logger
|
46
47
|
unless verify_service host: @config.prometheus_pushgateway_host ,port: @config.prometheus_pushgateway_port then
|
47
48
|
return { :case => :service_dependence_missing, :more => "Prometheus Notification not send." }
|
48
49
|
end
|
49
|
-
|
50
|
+
log.info "Sending metrics to Prometheus Pushgateway"
|
50
51
|
@logs_target.each do |item|
|
51
52
|
missing = (item[:status] == :missing)? 1 : 0
|
52
|
-
|
53
|
+
log.item "Sending metrics for #{item[:log]}"
|
53
54
|
@metric_count.set(item[:count], labels: { log: item[:log] })
|
54
55
|
@metric_missing.set(missing, labels: { log: item[:log] })
|
55
56
|
lines = (item[:lines])? item[:lines] : 0
|
@@ -58,7 +59,7 @@ module Splash
|
|
58
59
|
hostname = Socket.gethostname
|
59
60
|
url = "http://#{@config.prometheus_pushgateway_host}:#{@config.prometheus_pushgateway_port}"
|
60
61
|
Prometheus::Client::Push.new('Splash',hostname, url).add(@registry)
|
61
|
-
|
62
|
+
log.ok "Sending to Prometheus PushGateway done."
|
62
63
|
return {:case => :quiet_exit }
|
63
64
|
end
|
64
65
|
|
data/lib/splash/orchestrator.rb
CHANGED
@@ -12,27 +12,30 @@ module Splash
|
|
12
12
|
include Splash::Config
|
13
13
|
include Splash::Transports
|
14
14
|
include Splash::Orchestrator::Grammar
|
15
|
+
include Splash::Loggers
|
16
|
+
|
15
17
|
def initialize(options = {})
|
18
|
+
@log = get_logger
|
16
19
|
$stdout.sync = true
|
17
20
|
$stderr.sync = true
|
18
21
|
@server = Rufus::Scheduler::new
|
19
22
|
@server.extend SchedulerHooks
|
20
23
|
@config = get_config
|
21
24
|
@result = LogScanner::new
|
22
|
-
|
25
|
+
@log.info "Splash Orchestrator starting :"
|
23
26
|
if options[:scheduling] then
|
24
|
-
|
27
|
+
@log.item "Initializing commands Scheduling."
|
25
28
|
self.init_commands_scheduling
|
26
29
|
end
|
27
30
|
sched,value = @config.daemon_logmon_scheduling.flatten
|
28
|
-
|
31
|
+
@log.item "Initializing logs monitorings & notifications."
|
29
32
|
@server.send sched,value do
|
30
33
|
begin
|
34
|
+
@log.trigger "Logs monitoring for Scheduling : #{sched.to_s} #{value.to_s}"
|
31
35
|
@result.analyse
|
32
36
|
@result.notify
|
33
|
-
$stdout.flush
|
34
37
|
rescue Errno::ECONNREFUSED
|
35
|
-
|
38
|
+
@log.error "PushGateway seems to be done, please start it."
|
36
39
|
end
|
37
40
|
end
|
38
41
|
hostname = Socket.gethostname
|
@@ -43,21 +46,26 @@ module Splash
|
|
43
46
|
transport.subscribe(:block => true) do |delivery_info, properties, body|
|
44
47
|
content = YAML::load(body)
|
45
48
|
if VERBS.include? content[:verb]
|
46
|
-
|
49
|
+
@log.receive "Valid remote order, verb : #{content[:verb].to_s}"
|
47
50
|
if content[:payload] then
|
48
51
|
res = self.send content[:verb], content[:payload]
|
49
52
|
else
|
50
53
|
res = self.send content[:verb]
|
51
54
|
end
|
52
55
|
get_default_client.publish queue: content[:return_to], message: res.to_yaml
|
56
|
+
@log.send "Result to #{content[:return_to]}."
|
53
57
|
else
|
54
|
-
|
58
|
+
@log.receive "INVALID remote order, verb : #{content[:verb].to_s}"
|
55
59
|
get_default_client.publish queue: content[:return_to], message: "Unkown verb #{content[:verb]}".to_yaml
|
56
60
|
end
|
57
61
|
end
|
58
62
|
end
|
59
63
|
|
60
64
|
def terminate
|
65
|
+
@log.info "Splash daemon shutdown"
|
66
|
+
@server.shutdown
|
67
|
+
change_logger logger: :cli
|
68
|
+
splash_exit case: :quiet_exit
|
61
69
|
end
|
62
70
|
|
63
71
|
private
|
@@ -66,8 +74,9 @@ module Splash
|
|
66
74
|
commands = config.select{|key,value| value.include? :schedule}.keys
|
67
75
|
commands.each do |command|
|
68
76
|
sched,value = config[command][:schedule].flatten
|
69
|
-
|
77
|
+
@log.arrow "Scheduling command #{command.to_s}"
|
70
78
|
@server.send sched,value do
|
79
|
+
@log.trigger "Executing Scheduled command #{command.to_s} for Scheduling : #{sched.to_s} #{value.to_s}"
|
71
80
|
self.execute command: command.to_s
|
72
81
|
end
|
73
82
|
end
|