prometheus-splash 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +23 -0
- data/README.md +32 -0
- data/Rakefile +61 -0
- data/bin/splash +128 -0
- data/config/splash.yml +17 -0
- data/lib/splash/command.rb +29 -0
- data/lib/splash/config.rb +151 -0
- data/lib/splash/constants.rb +18 -0
- data/lib/splash/controller.rb +48 -0
- data/lib/splash/helpers.rb +205 -0
- data/lib/splash/logs.rb +39 -0
- data/splash.gemspec +33 -0
- data/templates/splashd.service +20 -0
- data/ultragreen_roodi_coding_convention.yml +25 -0
- metadata +186 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 6674f3e9608370fdb5cd83f68ad51c91f749230f1698009ddd811d795000af1b
|
4
|
+
data.tar.gz: 314e8c80cdcc580bf1ccc45fc887adb3907d5d2d9af1b3930d0fee04ff740e27
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: c8cbdb6c3b296602a997d95727abb23da02ef27227afe7654a9a6213795f156d70d117569a71192aa5768837d650e4f3e9b760196e5e471c743ae0999be06989
|
7
|
+
data.tar.gz: bfc21d04dafd15d23c5e6ddf9de3851d103f64e800be0875ffd6ca8d6d68bedeef29fe9d4c205caf8b3bdb130ee57062630bd1f2f572e4337edc7d16dbb2093a
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
Splash Copyright (c) 2020 Ultragreen Software, Romain GEORGES
|
2
|
+
All rights reserved.
|
3
|
+
|
4
|
+
Redistribution and use in source and binary forms, with or without
|
5
|
+
modification, are permitted provided that the following conditions
|
6
|
+
are met:
|
7
|
+
1. Redistributions of source code must retain the above copyright
|
8
|
+
notice, this list of conditions and the following disclaimer.
|
9
|
+
2. Redistributions in binary form must reproduce the above copyright
|
10
|
+
notice, this list of conditions and the following disclaimer in the
|
11
|
+
documentation and/or other materials provided with the distribution.
|
12
|
+
|
13
|
+
THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
14
|
+
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
15
|
+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
16
|
+
ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
17
|
+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
18
|
+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
19
|
+
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
20
|
+
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
21
|
+
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
22
|
+
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
23
|
+
SUCH DAMAGE.
|
data/README.md
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
# Splash
|
2
|
+
|
3
|
+
SPLASH is *Supervision with Prometheus of Logs and Asynchronous tasks for Services or Hosts*
|
4
|
+
|
5
|
+
|
6
|
+
Prometheus Logs and Batchs supervision over PushGateway
|
7
|
+
|
8
|
+
## Installation
|
9
|
+
|
10
|
+
Add this line to your application's Gemfile:
|
11
|
+
|
12
|
+
gem 'splash'
|
13
|
+
|
14
|
+
And then execute:
|
15
|
+
|
16
|
+
$ bundle
|
17
|
+
|
18
|
+
Or install it yourself as:
|
19
|
+
|
20
|
+
$ gem install splash
|
21
|
+
|
22
|
+
## Usage
|
23
|
+
|
24
|
+
TODO: Write usage instructions here
|
25
|
+
|
26
|
+
## Contributing
|
27
|
+
|
28
|
+
1. Fork it
|
29
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
30
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
31
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
32
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1,61 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
2
|
+
require 'rubygems'
|
3
|
+
require 'rspec'
|
4
|
+
require 'rake'
|
5
|
+
require "rake/clean"
|
6
|
+
require "rubygems/package_task"
|
7
|
+
require "rdoc/task"
|
8
|
+
require 'code_statistics'
|
9
|
+
require 'rspec/core/rake_task'
|
10
|
+
require 'yard'
|
11
|
+
require 'yard/rake/yardoc_task.rb'
|
12
|
+
require "rake/tasklib"
|
13
|
+
require "roodi"
|
14
|
+
require "roodi_task"
|
15
|
+
|
16
|
+
|
17
|
+
RoodiTask.new() do | t |
|
18
|
+
t.patterns = %w(lib/**/*.rb)
|
19
|
+
t.config = "ultragreen_roodi_coding_convention.yml"
|
20
|
+
end
|
21
|
+
|
22
|
+
|
23
|
+
CLEAN.include('*.tmp','*.old')
|
24
|
+
CLOBBER.include('*.tmp', 'build/*','#*#')
|
25
|
+
|
26
|
+
|
27
|
+
content = File::readlines(File.join(File.dirname(__FILE__), 'splash.gemspec')).join
|
28
|
+
spec = eval(content)
|
29
|
+
|
30
|
+
RSpec::Core::RakeTask.new('spec')
|
31
|
+
|
32
|
+
YARD::Rake::YardocTask.new do |t|
|
33
|
+
t.files = [ 'lib/**/*.rb', '-', 'doc/**/*','spec/**/*_spec.rb']
|
34
|
+
t.options += ['--title', "Gem Documentation"]
|
35
|
+
t.options += ['-o', "yardoc"]
|
36
|
+
t.options += ['-r', "doc/manual.rdoc"]
|
37
|
+
end
|
38
|
+
YARD::Config.load_plugin('yard-rspec')
|
39
|
+
|
40
|
+
namespace :yardoc do
|
41
|
+
task :clobber do
|
42
|
+
rm_r "yardoc" rescue nil
|
43
|
+
rm_r ".yardoc" rescue nil
|
44
|
+
end
|
45
|
+
end
|
46
|
+
task :clobber => "yardoc:clobber"
|
47
|
+
|
48
|
+
|
49
|
+
Gem::PackageTask.new(spec) do |pkg|
|
50
|
+
pkg.need_tar = true
|
51
|
+
pkg.need_zip = true
|
52
|
+
end
|
53
|
+
|
54
|
+
Rake::RDocTask.new('rdoc') do |d|
|
55
|
+
d.rdoc_files.include('doc/**/*','bin/*')
|
56
|
+
d.main = 'doc/manual.rdoc'
|
57
|
+
d.title = 'Dorsal : Yard'
|
58
|
+
d.options << '--line-numbers' << '--diagram' << '-SHN'
|
59
|
+
end
|
60
|
+
|
61
|
+
task :default => [:gem]
|
data/bin/splash
ADDED
@@ -0,0 +1,128 @@
|
|
1
|
+
#!/usr/bin/env ruby -W:no-deprecated
|
2
|
+
|
3
|
+
require 'prometheus/client'
|
4
|
+
require 'prometheus/client/push'
|
5
|
+
|
6
|
+
begin
|
7
|
+
require 'thor'
|
8
|
+
rescue Gem::GemNotFoundException
|
9
|
+
$stderr.puts "Loadind error, it's like you try to run Splash, with a lake of dependencies."
|
10
|
+
$stderr.puts "If you run on RVM, please run with rvmsudo and not with sudo."
|
11
|
+
$stderr.puts "If problem is percistant, please, proceed to new install and Setup."
|
12
|
+
end
|
13
|
+
|
14
|
+
require 'yaml'
|
15
|
+
|
16
|
+
require 'splash/constants'
|
17
|
+
require 'splash/helpers'
|
18
|
+
require 'splash/config'
|
19
|
+
|
20
|
+
require 'splash/command'
|
21
|
+
require 'splash/logs'
|
22
|
+
require 'splash/controller'
|
23
|
+
|
24
|
+
#inhibit warning : due to prometheus-client call to URI.encode warning
|
25
|
+
$-w = nil
|
26
|
+
|
27
|
+
include Splash::Helpers
|
28
|
+
|
29
|
+
module CLISplash
|
30
|
+
|
31
|
+
|
32
|
+
class Commands < Thor
|
33
|
+
|
34
|
+
option :ack, :type => :boolean
|
35
|
+
desc "wrap NAME", "wrapping for command or ack result"
|
36
|
+
def wrap(name)
|
37
|
+
command = Splash::CommandWrapper::new(name)
|
38
|
+
command.ack if options[:ack]
|
39
|
+
command.call_and_notify
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
|
44
|
+
class CLIController < Thor
|
45
|
+
include Splash::LogsMonitor::DaemonController
|
46
|
+
|
47
|
+
option :foreground, :type => :boolean
|
48
|
+
desc "start", "Starting Logs Monitor Daemon"
|
49
|
+
def start
|
50
|
+
run_as_root :startdaemon
|
51
|
+
end
|
52
|
+
|
53
|
+
desc "stop", "Stopping Logs Monitor Daemon"
|
54
|
+
def stop
|
55
|
+
run_as_root :stopdaemon
|
56
|
+
end
|
57
|
+
|
58
|
+
|
59
|
+
end
|
60
|
+
|
61
|
+
class Config < Thor
|
62
|
+
include Splash::Config
|
63
|
+
include Splash::Helpers
|
64
|
+
|
65
|
+
desc "setup", "Setup installation fo Splash"
|
66
|
+
def setup
|
67
|
+
run_as_root :setupsplash
|
68
|
+
|
69
|
+
end
|
70
|
+
|
71
|
+
desc "sanitycheck", "Verify installation fo Splash"
|
72
|
+
def sanitycheck
|
73
|
+
run_as_root :checkconfig
|
74
|
+
end
|
75
|
+
|
76
|
+
desc "version", "display current Splash version"
|
77
|
+
def version
|
78
|
+
config = get_config
|
79
|
+
puts "Splash version : #{config.version}, Author : #{config.author}"
|
80
|
+
puts config.copyright
|
81
|
+
end
|
82
|
+
|
83
|
+
|
84
|
+
end
|
85
|
+
|
86
|
+
|
87
|
+
class Logs < Thor
|
88
|
+
|
89
|
+
desc "analyse", "analyze logs in config"
|
90
|
+
def analyse
|
91
|
+
result = Splash::LogScanner::new
|
92
|
+
result.analyse
|
93
|
+
p result.output
|
94
|
+
end
|
95
|
+
|
96
|
+
desc "monitor", "monitor logs in config"
|
97
|
+
def monitor
|
98
|
+
result = Splash::LogScanner::new
|
99
|
+
result.analyse
|
100
|
+
result.notify
|
101
|
+
end
|
102
|
+
|
103
|
+
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
class CLI < Thor
|
108
|
+
def self.exit_on_failure?
|
109
|
+
true
|
110
|
+
end
|
111
|
+
|
112
|
+
include CLISplash
|
113
|
+
desc "commands SUBCOMMAND ...ARGS", "Managing commands/batchs supervision"
|
114
|
+
subcommand "commands", Commands
|
115
|
+
desc "logs SUBCOMMAND ...ARGS", "Managing Files/Logs supervision"
|
116
|
+
subcommand "logs", Logs
|
117
|
+
desc "daemon SUBCOMMAND ...ARGS", "Logs monitor daemon contoller"
|
118
|
+
subcommand "daemon", CLIController
|
119
|
+
desc "config SUBCOMMAND ...ARGS", "config tools for Splash"
|
120
|
+
subcommand "config", Config
|
121
|
+
end
|
122
|
+
|
123
|
+
|
124
|
+
|
125
|
+
|
126
|
+
|
127
|
+
|
128
|
+
CLI.start(ARGV)
|
data/config/splash.yml
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
:splash:
|
2
|
+
:logs:
|
3
|
+
- :log: /tmp/test
|
4
|
+
:pattern: ERROR
|
5
|
+
- :log: /var/log/message
|
6
|
+
:pattern: error
|
7
|
+
:daemon:
|
8
|
+
:user: daemon
|
9
|
+
:group: daemon
|
10
|
+
:process_name: "Splash : Prometheus logs monitoring."
|
11
|
+
:paths:
|
12
|
+
:pid_path: /tmp
|
13
|
+
:trace_path: /tmp/splash
|
14
|
+
:files:
|
15
|
+
:stdout_trace: stdout.txt
|
16
|
+
:stderr_trace: stderr.txt
|
17
|
+
:pid_file: splash.pid
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Splash
|
2
|
+
class CommandWrapper
|
3
|
+
def initialize(name)
|
4
|
+
@name = name
|
5
|
+
end
|
6
|
+
|
7
|
+
def ack
|
8
|
+
puts "Sending ack for command : '#{@name}'"
|
9
|
+
notify(0)
|
10
|
+
exit 0
|
11
|
+
end
|
12
|
+
|
13
|
+
def notify(value)
|
14
|
+
registry = Prometheus::Client.registry
|
15
|
+
metric = Prometheus::Client::Gauge.new(:errorcode, docstring: 'SPLASH metric batch errorcode')
|
16
|
+
registry.register(metric)
|
17
|
+
metric.set(value)
|
18
|
+
Prometheus::Client::Push.new(@name).add(registry)
|
19
|
+
end
|
20
|
+
|
21
|
+
|
22
|
+
def call_and_notify
|
23
|
+
puts "Executing command : '#{@name}' and notify Prometheus PushGateway"
|
24
|
+
system("#{@name} > /dev/null")
|
25
|
+
exit_code = $?.exitstatus
|
26
|
+
notify(exit_code)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,151 @@
|
|
1
|
+
module Splash
|
2
|
+
module Config
|
3
|
+
include Splash::Helpers
|
4
|
+
include Splash::Constants
|
5
|
+
|
6
|
+
|
7
|
+
|
8
|
+
class Configuration < Hash
|
9
|
+
include Splash::Constants
|
10
|
+
def initialize(config_file=CONFIG_FILE)
|
11
|
+
config_from_file = readconf config_file
|
12
|
+
self[:version] = VERSION
|
13
|
+
self[:author] = "#{AUTHOR} <#{EMAIL}>"
|
14
|
+
self[:copyright] = "#{COPYRIGHT} #{LICENSE}"
|
15
|
+
self[:daemon_process_name] = (config_from_file[:daemon][:process_name])? config_from_file[:daemon][:process_name] : DAEMON_PROCESS_NAME
|
16
|
+
self[:daemon_user] = (config_from_file[:daemon][:user])? config_from_file[:daemon][:user] : DAEMON_USER
|
17
|
+
self[:daemon_group] = (config_from_file[:daemon][:group])? config_from_file[:daemon][:group] : DAEMON_GROUP
|
18
|
+
self[:pid_path] = (config_from_file[:daemon][:paths][:pid_path])? config_from_file[:daemon][:paths][:pid_path] : PID_PATH
|
19
|
+
self[:trace_path] = (config_from_file[:daemon][:paths][:trace_path])? config_from_file[:daemon][:paths][:trace_path] : TRACE_PATH
|
20
|
+
self[:pid_file] = (config_from_file[:daemon][:files][:pid_file])? config_from_file[:daemon][:files][:pid_file] : PID_FILE
|
21
|
+
self[:stdout_trace] = (config_from_file[:daemon][:files][:stdout_trace])? config_from_file[:daemon][:files][:stdout_trace] : STDOUT_TRACE
|
22
|
+
self[:stderr_trace] = (config_from_file[:daemon][:files][:stderr_trace])? config_from_file[:daemon][:files][:stderr_trace] : STDERR_TRACE
|
23
|
+
self[:logs] = (config_from_file[:logs])? config_from_file[:logs] : {}
|
24
|
+
end
|
25
|
+
|
26
|
+
def logs
|
27
|
+
return self[:logs]
|
28
|
+
end
|
29
|
+
|
30
|
+
def author
|
31
|
+
return self[:author]
|
32
|
+
end
|
33
|
+
|
34
|
+
def copyright
|
35
|
+
return self[:copyright]
|
36
|
+
end
|
37
|
+
|
38
|
+
def version
|
39
|
+
return self[:version]
|
40
|
+
end
|
41
|
+
|
42
|
+
def daemon_process_name
|
43
|
+
return self[:daemon_process_name]
|
44
|
+
end
|
45
|
+
|
46
|
+
def daemon_user
|
47
|
+
return self[:daemon_user]
|
48
|
+
end
|
49
|
+
|
50
|
+
def daemon_group
|
51
|
+
return self[:daemon_group]
|
52
|
+
end
|
53
|
+
|
54
|
+
def full_pid_path
|
55
|
+
return "#{self[:pid_path]}/#{self[:pid_file]}"
|
56
|
+
end
|
57
|
+
|
58
|
+
def full_stdout_trace_path
|
59
|
+
return "#{self[:trace_path]}/#{self[:stdout_trace]}"
|
60
|
+
end
|
61
|
+
|
62
|
+
def full_stderr_trace_path
|
63
|
+
return "#{self[:trace_path]}/#{self[:stderr_trace]}"
|
64
|
+
end
|
65
|
+
|
66
|
+
private
|
67
|
+
def readconf(file = CONFIG_FILE)
|
68
|
+
return YAML.load_file(file)[:splash]
|
69
|
+
end
|
70
|
+
|
71
|
+
|
72
|
+
end
|
73
|
+
|
74
|
+
|
75
|
+
def get_config(config_file=CONFIG_FILE)
|
76
|
+
return Configuration::new config_file
|
77
|
+
end
|
78
|
+
|
79
|
+
|
80
|
+
def setupsplash
|
81
|
+
conf_in_path = search_file_in_gem "splash", "config/splash.yml"
|
82
|
+
|
83
|
+
print "* Installing Configuration file : #{CONFIG_FILE} : "
|
84
|
+
if install_file source: conf_in_path, target: CONFIG_FILE, mode: "644", owner: "root", group: "wheel" then
|
85
|
+
puts "[OK]"
|
86
|
+
else
|
87
|
+
puts "[KO]"
|
88
|
+
end
|
89
|
+
config = get_config
|
90
|
+
|
91
|
+
print "* Checking pid file path : #{config[:pid_path]}"
|
92
|
+
if make_folder path: config[:pid_path], mode: "644", owner: "root", group: "wheel" then
|
93
|
+
puts "[OK]"
|
94
|
+
else
|
95
|
+
puts "[KO]"
|
96
|
+
end
|
97
|
+
|
98
|
+
print "* Checking trace file path : #{config[:trace_path]}"
|
99
|
+
if make_folder path: config[:trace_path], mode: "777", owner: config.daemon_user, group: config.daemon_group then
|
100
|
+
puts "[OK]"
|
101
|
+
else
|
102
|
+
puts "[KO]"
|
103
|
+
end
|
104
|
+
|
105
|
+
puts "Splash config done. "
|
106
|
+
|
107
|
+
end
|
108
|
+
|
109
|
+
def checkconfig
|
110
|
+
config = get_config
|
111
|
+
print "Config file : #{CONFIG_FILE}"
|
112
|
+
res = verify_file(name: CONFIG_FILE, mode: "644", owner: "root", group: "wheel")
|
113
|
+
if res.empty? then
|
114
|
+
print "[OK]\n"
|
115
|
+
else
|
116
|
+
print "[KO]\n"
|
117
|
+
print res
|
118
|
+
end
|
119
|
+
|
120
|
+
|
121
|
+
end
|
122
|
+
|
123
|
+
private
|
124
|
+
|
125
|
+
def search_file_in_gem(_gem,_file)
|
126
|
+
if Gem::Specification.respond_to?(:find_by_name)
|
127
|
+
begin
|
128
|
+
spec = Gem::Specification.find_by_name(_gem)
|
129
|
+
rescue LoadError
|
130
|
+
spec = nil
|
131
|
+
end
|
132
|
+
else
|
133
|
+
spec = Gem.searcher.find(_gem)
|
134
|
+
end
|
135
|
+
if spec then
|
136
|
+
if Gem::Specification.respond_to?(:find_by_name)
|
137
|
+
res = spec.lib_dirs_glob.split('/')
|
138
|
+
else
|
139
|
+
res = Gem.searcher.lib_dirs_for(spec).split('/')
|
140
|
+
end
|
141
|
+
res.pop
|
142
|
+
services_path = res.join('/').concat("/#{_file}")
|
143
|
+
return services_path if File::exist?(services_path)
|
144
|
+
return false
|
145
|
+
else
|
146
|
+
return false
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
end
|
151
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Splash
|
2
|
+
module Constants
|
3
|
+
VERSION = "0.0.1"
|
4
|
+
CONFIG_FILE = "/etc/splash.yml"
|
5
|
+
DAEMON_USER = "root"
|
6
|
+
DAEMON_GROUP = "wheel"
|
7
|
+
PID_PATH="/var/run"
|
8
|
+
TRACE_PATH="/var/run/splash"
|
9
|
+
PID_FILE="splash.pid"
|
10
|
+
STDOUT_TRACE="stdout.txt"
|
11
|
+
STDERR_TRACE="stderr.txt"
|
12
|
+
DAEMON_PROCESS_NAME="Splash : Prometheus logs monitoring."
|
13
|
+
AUTHOR="Romain GEORGES"
|
14
|
+
EMAIL = "gems@ultragreen.net"
|
15
|
+
COPYRIGHT="Ultragreen (c) 2020"
|
16
|
+
LICENSE="BSD-2-Clause"
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
|
2
|
+
module Splash
|
3
|
+
module LogsMonitor
|
4
|
+
module DaemonController
|
5
|
+
include Splash::Constants
|
6
|
+
include Splash::Helpers
|
7
|
+
include Splash::Config
|
8
|
+
|
9
|
+
def startdaemon(options = {})
|
10
|
+
config = get_config
|
11
|
+
unless File::exist? config.full_pid_path then
|
12
|
+
return daemonize :description => config.daemon_process_name,
|
13
|
+
:pid_file => config.full_pid_path,
|
14
|
+
:daemon_user => config.daemon_user,
|
15
|
+
:daemon_group => config.daemon_group,
|
16
|
+
:stdout_trace => config.full_stdout_trace_path,
|
17
|
+
:stderr_trace => config.full_stderr_trace_path do
|
18
|
+
result = LogScanner::new
|
19
|
+
while true
|
20
|
+
sleep 5
|
21
|
+
puts "Notify"
|
22
|
+
result.analyse
|
23
|
+
result.notify
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def stopdaemon(options = {})
|
30
|
+
config = get_config
|
31
|
+
if File.exist?(config.full_pid_path) then
|
32
|
+
|
33
|
+
begin
|
34
|
+
pid = `cat #{config.full_pid_path}`.to_i
|
35
|
+
Process.kill("TERM", pid)
|
36
|
+
rescue Errno::ESRCH
|
37
|
+
$stderr.puts "Process of PID : #{pid} not found"
|
38
|
+
end
|
39
|
+
FileUtils::rm config.full_pid_path if File::exist? config.full_pid_path
|
40
|
+
return true
|
41
|
+
else
|
42
|
+
return false
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,205 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
require 'fileutils'
|
3
|
+
require 'etc'
|
4
|
+
|
5
|
+
# coding: utf-8
|
6
|
+
module Splash
|
7
|
+
module Helpers
|
8
|
+
|
9
|
+
def is_root?
|
10
|
+
case (Process.uid)
|
11
|
+
when 0
|
12
|
+
return true
|
13
|
+
else
|
14
|
+
return false
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def run_as_root(method)
|
19
|
+
unless is_root?
|
20
|
+
$stderr.puts "You need to be root to execute this subcommands : #{method.to_s}"
|
21
|
+
$stderr.puts "Please execute with sudo, or rvmsudo."
|
22
|
+
exit 10
|
23
|
+
else
|
24
|
+
self.send method
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
# method for daemonize blocks
|
29
|
+
# @param [Hash] _options the list of options, keys are symbols
|
30
|
+
# @option _options [String] :description the description of the process, use for $0
|
31
|
+
# @option _options [String] :pid_file the pid filenam
|
32
|
+
# @yield a process definion or block given
|
33
|
+
# @example usage inline
|
34
|
+
# class Test
|
35
|
+
# include Splash::Helpers::Application
|
36
|
+
# private :daemonize
|
37
|
+
# def initialize
|
38
|
+
# @loop = Proc::new do
|
39
|
+
# loop do
|
40
|
+
# sleep 1
|
41
|
+
# end
|
42
|
+
# end
|
43
|
+
# end
|
44
|
+
#
|
45
|
+
# def run
|
46
|
+
# daemonize({:description => "A loop daemon", :pid_file => '/tmp/pid.file'}, &@loop)
|
47
|
+
# end
|
48
|
+
# end
|
49
|
+
#
|
50
|
+
# @example usage block
|
51
|
+
# class Test
|
52
|
+
# include Splash::Helpers::Application
|
53
|
+
# include Dorsal::Privates
|
54
|
+
# private :daemonize
|
55
|
+
# def initialize
|
56
|
+
# end
|
57
|
+
#
|
58
|
+
# def run
|
59
|
+
# daemonize :description => "A loop daemon", :pid_file => '/tmp/pid.file' do
|
60
|
+
# loop do
|
61
|
+
# sleep 1
|
62
|
+
# end
|
63
|
+
# end
|
64
|
+
# end
|
65
|
+
# end
|
66
|
+
# @return [Fixnum] pid the pid of the forked processus
|
67
|
+
def daemonize(options)
|
68
|
+
#Process.euid = 0
|
69
|
+
#Process.egid = 0
|
70
|
+
return yield if options[:debug]
|
71
|
+
trap("SIGINT"){ exit! 0 }
|
72
|
+
trap("SIGTERM"){ exit! 0 }
|
73
|
+
trap("SIGHUP"){ exit! 0 }
|
74
|
+
|
75
|
+
fork do
|
76
|
+
#Process.daemon
|
77
|
+
File.open(options[:pid_file],"w"){|f| f.puts Process.pid } if options[:pid_file]
|
78
|
+
uid = Etc.getpwnam(options[:daemon_user]).uid
|
79
|
+
gid = Etc.getgrnam(options[:daemon_group]).gid
|
80
|
+
Process::UID.change_privilege(uid)
|
81
|
+
# Process::GID.change_privilege(gid)
|
82
|
+
$stdout.reopen(options[:stdout_trace], "w")
|
83
|
+
$stderr.reopen(options[:stderr_trace], "w")
|
84
|
+
|
85
|
+
#$0 = options[:description]
|
86
|
+
Process.setproctitle options[:description]
|
87
|
+
|
88
|
+
yield
|
89
|
+
|
90
|
+
end
|
91
|
+
return true
|
92
|
+
end
|
93
|
+
|
94
|
+
# @!group facilités sur le système de fichier
|
95
|
+
|
96
|
+
# facilité d'installation de fichier
|
97
|
+
# @param [Hash] options
|
98
|
+
# @option options [String] :source le chemin source du fichier
|
99
|
+
# @option options [String] :target le chemin cible du fichier
|
100
|
+
def install_file(options = {})
|
101
|
+
#begin
|
102
|
+
FileUtils::copy options[:source], options[:target] #unless File::exist? options[:target]
|
103
|
+
FileUtils.chmod options[:mode].to_i(8), options[:target] if options[:mode]
|
104
|
+
FileUtils.chown options[:owner], options[:group], options[:target] if options[:owner] and options[:group]
|
105
|
+
return true
|
106
|
+
#rescue StandardError
|
107
|
+
# return false
|
108
|
+
#end
|
109
|
+
end
|
110
|
+
|
111
|
+
# facilité de création de répertoire
|
112
|
+
# @param [Hash] options
|
113
|
+
# @option options [String] :path le répertoire à créer (relatif ou absolut)
|
114
|
+
def make_folder(options = {})
|
115
|
+
begin
|
116
|
+
FileUtils::mkdir_p options[:path] unless File::exist? options[:path]
|
117
|
+
FileUtils.chmod options[:mode].to_i(8), options[:path] if options[:mode]
|
118
|
+
FileUtils.chown options[:owner], options[:group], options[:path] if options[:owner] and options[:group]
|
119
|
+
return true
|
120
|
+
rescue StandardError
|
121
|
+
return false
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
# facilité de liaison symbolique de fichier
|
126
|
+
# @param [Hash] options
|
127
|
+
# @option options [String] :source le chemin source du fichier
|
128
|
+
# @option options [String] :link le chemin du lien symbolique
|
129
|
+
def make_link(options = {})
|
130
|
+
begin
|
131
|
+
FileUtils::rm options[:link] if (File::symlink? options[:link] and not File::exist? options[:link])
|
132
|
+
FileUtils::ln_s options[:source], options[:link] unless File::exist? options[:link]
|
133
|
+
return true
|
134
|
+
rescue StandardError
|
135
|
+
return false
|
136
|
+
end
|
137
|
+
end
|
138
|
+
# @!endgroup
|
139
|
+
|
140
|
+
|
141
|
+
#@!group Vérifiers de l'application
|
142
|
+
|
143
|
+
# verifier d'existence d'un repertoire
|
144
|
+
# @return [Bool] vrai ou faux
|
145
|
+
# @param [Hash] options
|
146
|
+
# @option options [String] :path le répertoire à créer (relatif ou absolut)
|
147
|
+
def verify_folder(options ={})
|
148
|
+
return File.directory?(options[:path])
|
149
|
+
end
|
150
|
+
|
151
|
+
# verifier d'existence d'un lien
|
152
|
+
# @return [Bool] vrai ou faux
|
153
|
+
# @param [Hash] options
|
154
|
+
# @option options [String] :name path du lien
|
155
|
+
def verify_link(options ={})
|
156
|
+
return File.file?(options[:name])
|
157
|
+
end
|
158
|
+
|
159
|
+
# verifier d'existence d'un fichier
|
160
|
+
# @return [Bool] vrai ou faux
|
161
|
+
# @param [Hash] options
|
162
|
+
# @option options [String] :name path du fichier
|
163
|
+
def verify_file(options ={})
|
164
|
+
res = Array::new
|
165
|
+
return [:inexistant] unless File.file?(options[:name])
|
166
|
+
stat = File.stat(options[:name])
|
167
|
+
if options[:mode] then
|
168
|
+
mode = "%o" % stat.mode
|
169
|
+
res << :mode if mode[-3..-1] != options[:mode]
|
170
|
+
end
|
171
|
+
if options[:owner] then
|
172
|
+
res << :owner if Etc.getpwuid(stat.uid).name != options[:owner]
|
173
|
+
end
|
174
|
+
if options[:group] then
|
175
|
+
res << :group if Etc.getgrgid(stat.gid).name != options[:group]
|
176
|
+
end
|
177
|
+
return res
|
178
|
+
end
|
179
|
+
|
180
|
+
# verifier de l'ecoute d'un service sur un host et port donné en TCP
|
181
|
+
# @return [Bool] vrai ou faux
|
182
|
+
# @param [Hash] options
|
183
|
+
# @option options [String] :host le nom d'hote
|
184
|
+
# @option options [String] :port le port TCP
|
185
|
+
def verify_service(options ={})
|
186
|
+
begin
|
187
|
+
Timeout::timeout(1) do
|
188
|
+
begin
|
189
|
+
s = TCPSocket.new(options[:host], options[:port])
|
190
|
+
s.close
|
191
|
+
return true
|
192
|
+
rescue Errno::ECONNREFUSED, Errno::EHOSTUNREACH
|
193
|
+
return false
|
194
|
+
end
|
195
|
+
end
|
196
|
+
rescue Timeout::Error
|
197
|
+
return false
|
198
|
+
end
|
199
|
+
end
|
200
|
+
#!@endgroup
|
201
|
+
|
202
|
+
|
203
|
+
|
204
|
+
end
|
205
|
+
end
|
data/lib/splash/logs.rb
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
module Splash
|
2
|
+
class LogScanner
|
3
|
+
include Splash::Constants
|
4
|
+
include Splash::Config
|
5
|
+
|
6
|
+
def initialize
|
7
|
+
@logs_target = get_config.logs
|
8
|
+
|
9
|
+
@registry = Prometheus::Client.registry
|
10
|
+
@metric = Prometheus::Client::Gauge.new(:logerror, docstring: 'SPLASH metric log error', labels: [:log ])
|
11
|
+
@registry.register(@metric)
|
12
|
+
end
|
13
|
+
|
14
|
+
def analyse
|
15
|
+
@logs_target.each do |record|
|
16
|
+
record[:count]=0 if record[:count].nil?
|
17
|
+
record[:status] = :clean if record[:status].nil?
|
18
|
+
if File.exist?(record[:log]) then
|
19
|
+
record[:count] = File.readlines(record[:log]).grep(/#{record[:pattern]}/).size
|
20
|
+
record[:status] = :matched if record[:count] > 0
|
21
|
+
else
|
22
|
+
record[:status] = :mssing
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def output
|
28
|
+
return @logs_target
|
29
|
+
end
|
30
|
+
|
31
|
+
def notify
|
32
|
+
@logs_target.each do |item|
|
33
|
+
@metric.set(item[:count], labels: { log: item[:log] })
|
34
|
+
end
|
35
|
+
Prometheus::Client::Push.new('Splash').add(@registry)
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
end
|
data/splash.gemspec
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'splash/constants'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "prometheus-splash"
|
8
|
+
spec.version = Splash::Constants::VERSION
|
9
|
+
spec.authors = [Splash::Constants::AUTHOR]
|
10
|
+
spec.email = [Splash::Constants::EMAIL]
|
11
|
+
spec.description = %q{Prometheus Logs and Batchs supervision over PushGateway}
|
12
|
+
spec.summary = %q{Supervision with Prometheus of Logs and Asynchronous tasks for Services or Hosts }
|
13
|
+
spec.homepage = "http://www.ultragreen.net"
|
14
|
+
spec.license = Splash::Constants::LICENSE
|
15
|
+
spec.require_paths << 'bin'
|
16
|
+
spec.bindir = 'bin'
|
17
|
+
spec.executables = Dir["bin/*"].map!{|item| item.gsub("bin/","")}
|
18
|
+
spec.files = `git ls-files`.split($/)
|
19
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
20
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
21
|
+
spec.require_paths = ["lib"]
|
22
|
+
spec.add_runtime_dependency 'thor','~> 1.0.1'
|
23
|
+
spec.add_runtime_dependency 'prometheus-client','~> 2.0.0'
|
24
|
+
spec.add_development_dependency 'rake', '~> 13.0.1'
|
25
|
+
spec.add_development_dependency 'rspec', '~> 3.9.0'
|
26
|
+
spec.add_development_dependency 'yard', '~> 0.9.24'
|
27
|
+
spec.add_development_dependency 'rdoc', '~> 6.2.1'
|
28
|
+
spec.add_development_dependency 'roodi', '~> 5.0.0'
|
29
|
+
spec.add_development_dependency 'code_statistics', '~> 0.2.13'
|
30
|
+
spec.add_development_dependency 'yard-rspec', '~> 0.1'
|
31
|
+
|
32
|
+
|
33
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
[Unit]
|
2
|
+
Description=Splash Daemon
|
3
|
+
After=network-online.target
|
4
|
+
|
5
|
+
[Service]
|
6
|
+
Type=simple
|
7
|
+
|
8
|
+
User=splash
|
9
|
+
Group=splash
|
10
|
+
UMask=007
|
11
|
+
|
12
|
+
ExecStart=/splash daemon start
|
13
|
+
|
14
|
+
Restart=on-failure
|
15
|
+
|
16
|
+
# Configures the time to wait before service is stopped forcefully.
|
17
|
+
TimeoutStopSec=300
|
18
|
+
|
19
|
+
[Install]
|
20
|
+
WantedBy=multi-user.target
|
@@ -0,0 +1,25 @@
|
|
1
|
+
AssignmentInConditionalCheck:
|
2
|
+
CaseMissingElseCheck:
|
3
|
+
ClassLineCountCheck:
|
4
|
+
line_count: 300
|
5
|
+
ClassNameCheck:
|
6
|
+
pattern: !ruby/regexp /^[A-Z][a-zA-Z0-9]*$/
|
7
|
+
#ClassVariableCheck:
|
8
|
+
CyclomaticComplexityBlockCheck:
|
9
|
+
complexity: 5
|
10
|
+
CyclomaticComplexityMethodCheck:
|
11
|
+
complexity: 10
|
12
|
+
EmptyRescueBodyCheck:
|
13
|
+
ForLoopCheck:
|
14
|
+
MethodLineCountCheck:
|
15
|
+
line_count: 30
|
16
|
+
MethodNameCheck:
|
17
|
+
pattern: !ruby/regexp /^[_a-z<>=\[|+-\/\*`]+[_a-z0-9_<>=~@\[\]]*[=!\?]?$/
|
18
|
+
# MissingForeignKeyIndexCheck:
|
19
|
+
ModuleLineCountCheck:
|
20
|
+
line_count: 500
|
21
|
+
ModuleNameCheck:
|
22
|
+
pattern: !ruby/regexp /^[A-Z][a-zA-Z0-9]*$/
|
23
|
+
ParameterNumberCheck:
|
24
|
+
parameter_count: 5
|
25
|
+
|
metadata
ADDED
@@ -0,0 +1,186 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: prometheus-splash
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Romain GEORGES
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2020-04-04 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: thor
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 1.0.1
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 1.0.1
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: prometheus-client
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 2.0.0
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 2.0.0
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rake
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: 13.0.1
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 13.0.1
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rspec
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 3.9.0
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: 3.9.0
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: yard
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: 0.9.24
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: 0.9.24
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: rdoc
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: 6.2.1
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: 6.2.1
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: roodi
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - "~>"
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: 5.0.0
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - "~>"
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: 5.0.0
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: code_statistics
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - "~>"
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: 0.2.13
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - "~>"
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: 0.2.13
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: yard-rspec
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - "~>"
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '0.1'
|
132
|
+
type: :development
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - "~>"
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '0.1'
|
139
|
+
description: Prometheus Logs and Batchs supervision over PushGateway
|
140
|
+
email:
|
141
|
+
- gems@ultragreen.net
|
142
|
+
executables:
|
143
|
+
- splash
|
144
|
+
extensions: []
|
145
|
+
extra_rdoc_files: []
|
146
|
+
files:
|
147
|
+
- Gemfile
|
148
|
+
- LICENSE.txt
|
149
|
+
- README.md
|
150
|
+
- Rakefile
|
151
|
+
- bin/splash
|
152
|
+
- config/splash.yml
|
153
|
+
- lib/splash/command.rb
|
154
|
+
- lib/splash/config.rb
|
155
|
+
- lib/splash/constants.rb
|
156
|
+
- lib/splash/controller.rb
|
157
|
+
- lib/splash/helpers.rb
|
158
|
+
- lib/splash/logs.rb
|
159
|
+
- splash.gemspec
|
160
|
+
- templates/splashd.service
|
161
|
+
- ultragreen_roodi_coding_convention.yml
|
162
|
+
homepage: http://www.ultragreen.net
|
163
|
+
licenses:
|
164
|
+
- BSD-2-Clause
|
165
|
+
metadata: {}
|
166
|
+
post_install_message:
|
167
|
+
rdoc_options: []
|
168
|
+
require_paths:
|
169
|
+
- lib
|
170
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
171
|
+
requirements:
|
172
|
+
- - ">="
|
173
|
+
- !ruby/object:Gem::Version
|
174
|
+
version: '0'
|
175
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
176
|
+
requirements:
|
177
|
+
- - ">="
|
178
|
+
- !ruby/object:Gem::Version
|
179
|
+
version: '0'
|
180
|
+
requirements: []
|
181
|
+
rubygems_version: 3.1.2
|
182
|
+
signing_key:
|
183
|
+
specification_version: 4
|
184
|
+
summary: Supervision with Prometheus of Logs and Asynchronous tasks for Services or
|
185
|
+
Hosts
|
186
|
+
test_files: []
|