triglav-agent 1.0.0.pre1
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/.gitignore +11 -0
- data/.rspec +2 -0
- data/.travis.yml +6 -0
- data/.yardopts +6 -0
- data/CHANGELOG.md +3 -0
- data/CODE_OF_CONDUCT.md +49 -0
- data/Gemfile +5 -0
- data/LICENSE.txt +21 -0
- data/README.md +59 -0
- data/Rakefile +11 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/docs/Triglav/Agent/ApiClient/AuthenticationError.html +150 -0
- data/docs/Triglav/Agent/ApiClient/ConnectionError.html +150 -0
- data/docs/Triglav/Agent/ApiClient/Error.html +296 -0
- data/docs/Triglav/Agent/ApiClient.html +545 -0
- data/docs/Triglav/Agent/Base/CLI.html +498 -0
- data/docs/Triglav/Agent/Base/Connection.html +258 -0
- data/docs/Triglav/Agent/Base/Monitor.html +370 -0
- data/docs/Triglav/Agent/Base/Processor.html +623 -0
- data/docs/Triglav/Agent/Base/Setting.html +1081 -0
- data/docs/Triglav/Agent/Base/Worker.html +635 -0
- data/docs/Triglav/Agent/Base.html +121 -0
- data/docs/Triglav/Agent/Configuration.html +967 -0
- data/docs/Triglav/Agent/Error.html +130 -0
- data/docs/Triglav/Agent/HashUtil.html +351 -0
- data/docs/Triglav/Agent/LogFormatter.html +271 -0
- data/docs/Triglav/Agent/Logger.html +287 -0
- data/docs/Triglav/Agent/StorageFile.html +1130 -0
- data/docs/Triglav/Agent/Timer.html +424 -0
- data/docs/Triglav/Agent/TooManyError.html +134 -0
- data/docs/Triglav/Agent.html +131 -0
- data/docs/Triglav.html +119 -0
- data/docs/_index.html +335 -0
- data/docs/class_list.html +51 -0
- data/docs/css/common.css +1 -0
- data/docs/css/full_list.css +58 -0
- data/docs/css/style.css +481 -0
- data/docs/file.LICENSE.html +72 -0
- data/docs/file.README.html +137 -0
- data/docs/file_list.html +61 -0
- data/docs/frames.html +17 -0
- data/docs/index.html +137 -0
- data/docs/js/app.js +243 -0
- data/docs/js/full_list.js +216 -0
- data/docs/js/jquery.js +4 -0
- data/docs/method_list.html +659 -0
- data/docs/top-level-namespace.html +112 -0
- data/example/config.yml +40 -0
- data/lib/triglav/agent/api_client.rb +199 -0
- data/lib/triglav/agent/base/cli.rb +98 -0
- data/lib/triglav/agent/base/connection.rb +30 -0
- data/lib/triglav/agent/base/monitor.rb +32 -0
- data/lib/triglav/agent/base/processor.rb +136 -0
- data/lib/triglav/agent/base/setting.rb +112 -0
- data/lib/triglav/agent/base/worker.rb +95 -0
- data/lib/triglav/agent/configuration.rb +79 -0
- data/lib/triglav/agent/error.rb +4 -0
- data/lib/triglav/agent/hash_util.rb +36 -0
- data/lib/triglav/agent/logger.rb +50 -0
- data/lib/triglav/agent/storage_file.rb +144 -0
- data/lib/triglav/agent/timer.rb +80 -0
- data/lib/triglav/agent/version.rb +5 -0
- data/lib/triglav/agent.rb +20 -0
- data/lib/triglav-agent.rb +1 -0
- data/triglav-agent.gemspec +33 -0
- metadata +250 -0
@@ -0,0 +1,112 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<meta charset="utf-8">
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
6
|
+
<title>
|
7
|
+
Top Level Namespace
|
8
|
+
|
9
|
+
— Documentation by YARD 0.9.5
|
10
|
+
|
11
|
+
</title>
|
12
|
+
|
13
|
+
<link rel="stylesheet" href="css/style.css" type="text/css" charset="utf-8" />
|
14
|
+
|
15
|
+
<link rel="stylesheet" href="css/common.css" type="text/css" charset="utf-8" />
|
16
|
+
|
17
|
+
<script type="text/javascript" charset="utf-8">
|
18
|
+
pathId = "";
|
19
|
+
relpath = '';
|
20
|
+
</script>
|
21
|
+
|
22
|
+
|
23
|
+
<script type="text/javascript" charset="utf-8" src="js/jquery.js"></script>
|
24
|
+
|
25
|
+
<script type="text/javascript" charset="utf-8" src="js/app.js"></script>
|
26
|
+
|
27
|
+
|
28
|
+
</head>
|
29
|
+
<body>
|
30
|
+
<div class="nav_wrap">
|
31
|
+
<iframe id="nav" src="class_list.html"></iframe>
|
32
|
+
<div id="resizer"></div>
|
33
|
+
</div>
|
34
|
+
|
35
|
+
<div id="main" tabindex="-1">
|
36
|
+
<div id="header">
|
37
|
+
<div id="menu">
|
38
|
+
|
39
|
+
<a href="_index.html">Index</a> »
|
40
|
+
|
41
|
+
|
42
|
+
<span class="title">Top Level Namespace</span>
|
43
|
+
|
44
|
+
</div>
|
45
|
+
|
46
|
+
<div id="search">
|
47
|
+
|
48
|
+
<a class="full_list_link" id="class_list_link"
|
49
|
+
href="class_list.html">
|
50
|
+
|
51
|
+
<svg width="24" height="24">
|
52
|
+
<rect x="0" y="4" width="24" height="4" rx="1" ry="1"></rect>
|
53
|
+
<rect x="0" y="12" width="24" height="4" rx="1" ry="1"></rect>
|
54
|
+
<rect x="0" y="20" width="24" height="4" rx="1" ry="1"></rect>
|
55
|
+
</svg>
|
56
|
+
</a>
|
57
|
+
|
58
|
+
</div>
|
59
|
+
<div class="clear"></div>
|
60
|
+
</div>
|
61
|
+
|
62
|
+
<iframe id="search_frame" src="class_list.html"></iframe>
|
63
|
+
|
64
|
+
<div id="content"><h1>Top Level Namespace
|
65
|
+
|
66
|
+
|
67
|
+
|
68
|
+
</h1>
|
69
|
+
<div class="box_info">
|
70
|
+
|
71
|
+
|
72
|
+
|
73
|
+
|
74
|
+
|
75
|
+
|
76
|
+
|
77
|
+
|
78
|
+
|
79
|
+
|
80
|
+
|
81
|
+
</div>
|
82
|
+
|
83
|
+
<h2>Defined Under Namespace</h2>
|
84
|
+
<p class="children">
|
85
|
+
|
86
|
+
|
87
|
+
<strong class="modules">Modules:</strong> <span class='object_link'><a href="Triglav.html" title="Triglav (module)">Triglav</a></span>
|
88
|
+
|
89
|
+
|
90
|
+
|
91
|
+
|
92
|
+
</p>
|
93
|
+
|
94
|
+
|
95
|
+
|
96
|
+
|
97
|
+
|
98
|
+
|
99
|
+
|
100
|
+
|
101
|
+
|
102
|
+
</div>
|
103
|
+
|
104
|
+
<div id="footer">
|
105
|
+
Generated on Thu Feb 23 23:20:33 2017 by
|
106
|
+
<a href="http://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
|
107
|
+
0.9.5 (ruby-2.3.2).
|
108
|
+
</div>
|
109
|
+
|
110
|
+
</div>
|
111
|
+
</body>
|
112
|
+
</html>
|
data/example/config.yml
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
defaults: &defaults
|
2
|
+
serverengine:
|
3
|
+
log: 'STDOUT'
|
4
|
+
log_level: 'debug'
|
5
|
+
log_rotate_age: 5
|
6
|
+
log_rotate_size: 10485760
|
7
|
+
triglav:
|
8
|
+
url: <%= ENV['TRIGLAV_URL'] || 'http://localhost:7800' %>
|
9
|
+
credential:
|
10
|
+
username: <%= ENV['TRIGLAV_USERNAME'] || 'triglav_test' %>
|
11
|
+
password: <%= ENV['TRIGLAV_PASSWORD'] || 'triglav_test' %>
|
12
|
+
authenticator: local
|
13
|
+
timeout: 60
|
14
|
+
debugging: false
|
15
|
+
retries: 3
|
16
|
+
retry_interval: 3 # sec
|
17
|
+
vertica:
|
18
|
+
monitor_interval: 5
|
19
|
+
parallel_size: 1 # default: 1
|
20
|
+
parallel_type: 'thread' # thread or process. default: thread
|
21
|
+
connection_pool_size: 1 # default: same with parallel.size
|
22
|
+
connection_pool_timeout: 60 # sec. default: 60
|
23
|
+
date_column: d
|
24
|
+
timestamp_column: t
|
25
|
+
connection_info:
|
26
|
+
"vertica://":
|
27
|
+
host: <%= ENV['VERTICA_HOST'] %>
|
28
|
+
port: <%= ENV['VERTICA_PORT'] %>
|
29
|
+
database: <%= ENV['VERTICA_DATABASE'] %>
|
30
|
+
user: <%= ENV['VERTICA_USER'] %>
|
31
|
+
password: <%= ENV['VERTICA_PASSWORD'] %>
|
32
|
+
resource_pool: <%= ENV['VERTICA_RESOURCE_POOL'] %>
|
33
|
+
interruptable: true
|
34
|
+
read_timeout: 5
|
35
|
+
|
36
|
+
development:
|
37
|
+
<<: *defaults
|
38
|
+
|
39
|
+
test:
|
40
|
+
<<: *defaults
|
@@ -0,0 +1,199 @@
|
|
1
|
+
require 'triglav/agent/storage_file'
|
2
|
+
require 'triglav_client'
|
3
|
+
|
4
|
+
module Triglav::Agent
|
5
|
+
# This Triglav client connects to triglav API with $setting.triglav.url,
|
6
|
+
# and authenticates with $setting.triglav.credential, and
|
7
|
+
# stores the token into $setting.token_file.
|
8
|
+
#
|
9
|
+
# Re-authenticate automatically if token is expired
|
10
|
+
#
|
11
|
+
# require 'triglav/agent/api_client'
|
12
|
+
#
|
13
|
+
# api_client = Triglav::Agent::ApiClient.new
|
14
|
+
# resources = api_client.list_resources(uri_prefix)
|
15
|
+
# resources.each do |resource|
|
16
|
+
# events = get_events(resource) # implement this!
|
17
|
+
# api_client.send_messages(events)
|
18
|
+
# end
|
19
|
+
class ApiClient
|
20
|
+
class Error < StandardError
|
21
|
+
attr_reader :cause
|
22
|
+
def initialize(message, cause)
|
23
|
+
@cause = cause
|
24
|
+
super(message)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
class AuthenticationError < Error; end
|
28
|
+
class ConnectionError < Error; end
|
29
|
+
|
30
|
+
# Initialize TriglavClient
|
31
|
+
def initialize(opts = {})
|
32
|
+
@opts = opts || {}
|
33
|
+
config = TriglavClient::Configuration.new do |config|
|
34
|
+
uri = URI.parse(triglav_url)
|
35
|
+
config.scheme = uri.scheme
|
36
|
+
config.host = "#{uri.host}:#{uri.port}"
|
37
|
+
config.timeout = timeout if timeout
|
38
|
+
config.debugging = debugging if debugging
|
39
|
+
end
|
40
|
+
@api_client = TriglavClient::ApiClient.new(config)
|
41
|
+
initialize_current_token
|
42
|
+
authenticate
|
43
|
+
end
|
44
|
+
|
45
|
+
def close
|
46
|
+
# typhoeus makes a new connection and disconnects it on each request
|
47
|
+
end
|
48
|
+
|
49
|
+
# List resources required to be monitored
|
50
|
+
#
|
51
|
+
# @param [String] uri_prefix
|
52
|
+
# @return [Array of TriglavClient::ResourceEachResponse] array of resources
|
53
|
+
# @see TriglavClient::ResourceEachResponse
|
54
|
+
def list_aggregated_resources(uri_prefix)
|
55
|
+
$logger.debug { "ApiClient#list_aggregated_resources(#{uri_prefix.inspect})" }
|
56
|
+
resources_api = TriglavClient::ResourcesApi.new(@api_client)
|
57
|
+
handle_error { resources_api.list_aggregated_resources(uri_prefix) }
|
58
|
+
end
|
59
|
+
|
60
|
+
# Send messages
|
61
|
+
#
|
62
|
+
# @param [Array of TriglavClient::MessageRequest] array of event messages
|
63
|
+
# @see TriglavClient::MessageRequest
|
64
|
+
def send_messages(events)
|
65
|
+
$logger.debug { "ApiClient#send_messages(#{events.inspect})" }
|
66
|
+
messages_api = TriglavClient::MessagesApi.new(@api_client)
|
67
|
+
handle_error { messages_api.send_messages(events) }
|
68
|
+
end
|
69
|
+
|
70
|
+
def authorized?
|
71
|
+
@current_token.has_key?(:access_token)
|
72
|
+
end
|
73
|
+
|
74
|
+
private
|
75
|
+
|
76
|
+
# Authenticate
|
77
|
+
#
|
78
|
+
# 1. Another process saved a newer token onto the token_file => read it
|
79
|
+
# 2. The token saved on the token_file is same with current token => re-authenticate
|
80
|
+
# 3. The token saved on the token_file is older than the current token
|
81
|
+
# => unknown situation, re-authenticate and save into token_file to refresh anyway
|
82
|
+
# 4. No token is saved on the token_file => authenticate
|
83
|
+
def authenticate
|
84
|
+
$logger.debug { 'ApiClient#authenticate' }
|
85
|
+
StorageFile.open(token_file) do |fp|
|
86
|
+
token = fp.load
|
87
|
+
if should_read_token_from_file?(token)
|
88
|
+
$logger.debug { "Read token from file" }
|
89
|
+
update_current_token(token)
|
90
|
+
return
|
91
|
+
end
|
92
|
+
$logger.debug { "AuthApi#create_token" }
|
93
|
+
auth_api = TriglavClient::AuthApi.new(@api_client)
|
94
|
+
credential = TriglavClient::Credential.new(
|
95
|
+
username: username, password: password, authenticator: authenticator
|
96
|
+
)
|
97
|
+
handle_auth_error do
|
98
|
+
$logger.debug { 'TriglavClient::AuthApi' }
|
99
|
+
result = auth_api.create_token(credential)
|
100
|
+
token = {access_token: result.access_token}
|
101
|
+
update_current_token(token)
|
102
|
+
fp.dump(token)
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
def initialize_current_token
|
108
|
+
@current_token = {
|
109
|
+
access_token: (@api_client.config.api_key['Authorization'] = String.new),
|
110
|
+
}
|
111
|
+
end
|
112
|
+
|
113
|
+
def update_current_token(token)
|
114
|
+
@current_token[:access_token].replace(token[:access_token])
|
115
|
+
end
|
116
|
+
|
117
|
+
def should_read_token_from_file?(token)
|
118
|
+
return true if @current_token[:access_token].empty? && !(token[:access_token] ||= '').empty?
|
119
|
+
return @current_token[:access_token] != token[:access_token]
|
120
|
+
end
|
121
|
+
|
122
|
+
def handle_auth_error(&block)
|
123
|
+
retries = 0
|
124
|
+
begin
|
125
|
+
yield
|
126
|
+
rescue TriglavClient::ApiError => e
|
127
|
+
if e.code == 0
|
128
|
+
if retries < max_retries
|
129
|
+
sleep retry_interval
|
130
|
+
retries += 1
|
131
|
+
retry
|
132
|
+
end
|
133
|
+
raise ConnectionError.new("Could not connect to #{triglav_url} with #{retries} retries", e)
|
134
|
+
elsif e.message == 'Unauthorized'.freeze
|
135
|
+
raise AuthenticationError.new("Failed to authenticate on triglav API.".freeze, e)
|
136
|
+
else
|
137
|
+
raise Error.new(e.message, e)
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
def handle_error(&block)
|
143
|
+
retries = 0
|
144
|
+
begin
|
145
|
+
yield
|
146
|
+
rescue TriglavClient::ApiError => e
|
147
|
+
if e.code == 0
|
148
|
+
if retries < max_retries
|
149
|
+
sleep retry_interval
|
150
|
+
retries += 1
|
151
|
+
retry
|
152
|
+
end
|
153
|
+
raise ConnectionError.new("Could not connect to #{triglav_url} with #{retries} retries", e)
|
154
|
+
elsif e.message == 'Unauthorized'.freeze
|
155
|
+
authenticate
|
156
|
+
retry
|
157
|
+
else
|
158
|
+
raise Error.new(e.message, e)
|
159
|
+
end
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
def triglav_url
|
164
|
+
@opts[:url] || $setting.dig(:triglav, :url)
|
165
|
+
end
|
166
|
+
|
167
|
+
def username
|
168
|
+
@opts.dig(:credential, :username) || $setting.dig(:triglav, :credential, :username)
|
169
|
+
end
|
170
|
+
|
171
|
+
def password
|
172
|
+
@opts.dig(:credential, :password) || $setting.dig(:triglav, :credential, :password)
|
173
|
+
end
|
174
|
+
|
175
|
+
def authenticator
|
176
|
+
@opts.dig(:credential, :authenticator) || $setting.dig(:triglav, :credential, :authenticator)
|
177
|
+
end
|
178
|
+
|
179
|
+
def timeout
|
180
|
+
@opts[:timeout] || $setting.dig(:triglav, :timeout)
|
181
|
+
end
|
182
|
+
|
183
|
+
def debugging
|
184
|
+
@opts[:debugging] || $setting.dig(:triglav, :debugging)
|
185
|
+
end
|
186
|
+
|
187
|
+
def max_retries
|
188
|
+
@opts[:retries] || $setting.dig(:triglav, :retries) || 3
|
189
|
+
end
|
190
|
+
|
191
|
+
def retry_interval
|
192
|
+
@opts[:retry_interval] || $setting.dig(:triglav, :retry_interval) || 3 # second
|
193
|
+
end
|
194
|
+
|
195
|
+
def token_file
|
196
|
+
@opts[:token_file] || $setting.token_file
|
197
|
+
end
|
198
|
+
end
|
199
|
+
end
|
@@ -0,0 +1,98 @@
|
|
1
|
+
require "triglav/agent/configuration"
|
2
|
+
require "triglav/agent/base/setting"
|
3
|
+
require 'optparse'
|
4
|
+
require 'serverengine'
|
5
|
+
|
6
|
+
module Triglav::Agent
|
7
|
+
module Base
|
8
|
+
# A base class for cli option parser
|
9
|
+
#
|
10
|
+
# This base class usually should be enough for agent plugins, but
|
11
|
+
# you can override this class and configure with Configuration#cli_classe=
|
12
|
+
class CLI
|
13
|
+
def run
|
14
|
+
opts, _ = parse_options(ARGV)
|
15
|
+
$setting = Configuration.setting_class.new(opts)
|
16
|
+
$logger = $setting.logger
|
17
|
+
se = ServerEngine.create(nil, Configuration.worker_module) do
|
18
|
+
$setting.serverengine_options
|
19
|
+
end
|
20
|
+
se.run
|
21
|
+
end
|
22
|
+
|
23
|
+
def default_opts
|
24
|
+
{
|
25
|
+
config: 'config.yml',
|
26
|
+
dotenv: false,
|
27
|
+
debug: false,
|
28
|
+
}
|
29
|
+
end
|
30
|
+
|
31
|
+
def option_parser(opts = {})
|
32
|
+
op = OptionParser.new
|
33
|
+
|
34
|
+
self.class.module_eval do
|
35
|
+
define_method(:usage) do |msg = nil|
|
36
|
+
puts op.to_s
|
37
|
+
puts "error: #{msg}" if msg
|
38
|
+
exit 1
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
op.on('-c', '--config VALUE', "Config file (default: #{opts[:config]})") {|v|
|
43
|
+
opts[:config] = v
|
44
|
+
}
|
45
|
+
op.on('-s', '--status VALUE', "Status stroage file (default: status.yml)") {|v|
|
46
|
+
opts[:status] = v
|
47
|
+
}
|
48
|
+
op.on('-t', '--token VALUE', "Triglav access token storage file (default: token.yml)") {|v|
|
49
|
+
opts[:token] = v
|
50
|
+
}
|
51
|
+
op.on('--dotenv', "Load environment variables from .env file (default: #{opts[:dotenv]})") {|v|
|
52
|
+
opts[:dotenv] = v
|
53
|
+
}
|
54
|
+
op.on('--debug', "Debug mode (default: #{opts[:debug]})") {|v|
|
55
|
+
opts[:debug] = v
|
56
|
+
}
|
57
|
+
op.on('-h', '--help', "help") {|v|
|
58
|
+
opts[:help] = v
|
59
|
+
}
|
60
|
+
# serverengine options
|
61
|
+
op.on('--log VALUE', "Log path (default: #{Setting::DEFAULT_LOG})") {|v|
|
62
|
+
opts[:log] = v
|
63
|
+
}
|
64
|
+
op.on('--log-level VALUE', "Log level (default: #{Setting::DEFAULT_LOG_LEVEL})") {|v|
|
65
|
+
opts[:log_level] = v
|
66
|
+
}
|
67
|
+
|
68
|
+
op.banner += ''
|
69
|
+
|
70
|
+
op
|
71
|
+
end
|
72
|
+
|
73
|
+
def parse_options(argv = ARGV)
|
74
|
+
opts = default_opts
|
75
|
+
op = option_parser(opts)
|
76
|
+
|
77
|
+
begin
|
78
|
+
args = op.parse(argv)
|
79
|
+
rescue OptionParser::InvalidOption => e
|
80
|
+
usage e.message
|
81
|
+
end
|
82
|
+
|
83
|
+
if opts[:help]
|
84
|
+
usage
|
85
|
+
end
|
86
|
+
|
87
|
+
if opts[:config].nil?
|
88
|
+
usage "--config VALUE is required"
|
89
|
+
end
|
90
|
+
if !File.readable?(opts[:config])
|
91
|
+
usage "Config file '#{opts[:config]}' does not exist or not readable"
|
92
|
+
end
|
93
|
+
|
94
|
+
[opts, args]
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Triglav::Agent
|
2
|
+
module Base
|
3
|
+
# An abstract base class of Connection.
|
4
|
+
#
|
5
|
+
# Wrap a connection to a storage.
|
6
|
+
# You can implement any methods which you want to use in your Monitor class.
|
7
|
+
#
|
8
|
+
# You have to implement following methods:
|
9
|
+
#
|
10
|
+
# * initialize
|
11
|
+
# * close
|
12
|
+
#
|
13
|
+
# An instance is created for each `resource_uri_prefix`, that is,
|
14
|
+
# shared among resources with of same `resource_uri_prefix`.
|
15
|
+
#
|
16
|
+
# Note that multiple connection instances would be created
|
17
|
+
# when multiple parallel threads are created in Processor class.
|
18
|
+
class Connection
|
19
|
+
# @param [Hash] connection_info
|
20
|
+
def initialize(connection_info)
|
21
|
+
raise NotImplementedError
|
22
|
+
end
|
23
|
+
|
24
|
+
# close the connection
|
25
|
+
def close
|
26
|
+
raise NotImplementedError
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module Triglav::Agent
|
2
|
+
module Base
|
3
|
+
# An abstract class of Monitor.
|
4
|
+
#
|
5
|
+
# Monitor your storage and send messages to triglav.
|
6
|
+
#
|
7
|
+
# You have to implement following methods:
|
8
|
+
#
|
9
|
+
# * initialize
|
10
|
+
# * process
|
11
|
+
#
|
12
|
+
# An instance is created per a `resource`.
|
13
|
+
# Connection is shared among same `resource_uri_prefix`.
|
14
|
+
#
|
15
|
+
# Note that multiple instances would be created,
|
16
|
+
# one instance for one parallel thread basically, and
|
17
|
+
# `#process` is ran concurrently.
|
18
|
+
class Monitor
|
19
|
+
# @param [Triglav::Agent::Base::Connection] connection
|
20
|
+
# @param [TriglavClient::ResourceResponse] resource
|
21
|
+
def initialize(connection, resource)
|
22
|
+
raise NotImplementedError
|
23
|
+
end
|
24
|
+
|
25
|
+
# @yield [events] Gives an array of events
|
26
|
+
def process(&block)
|
27
|
+
raise NotImplementedError
|
28
|
+
# yield(events) if block_given?
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,136 @@
|
|
1
|
+
require 'parallel'
|
2
|
+
require 'connection_pool'
|
3
|
+
|
4
|
+
module Triglav::Agent
|
5
|
+
module Base
|
6
|
+
# Triglav agent processor class.
|
7
|
+
#
|
8
|
+
# An instance is created for a `resource_uri_prefix`.
|
9
|
+
#
|
10
|
+
# You usually do not need to customize this class, but if you want to
|
11
|
+
# implement your original, configure
|
12
|
+
#
|
13
|
+
# Triglav::Agent::Configuration.processor_class
|
14
|
+
class Processor
|
15
|
+
attr_reader :worker, :resource_uri_prefix
|
16
|
+
|
17
|
+
def initialize(worker, resource_uri_prefix)
|
18
|
+
@worker = worker
|
19
|
+
@resource_uri_prefix = resource_uri_prefix
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.max_consecuitive_error_count
|
23
|
+
3
|
24
|
+
end
|
25
|
+
|
26
|
+
def process
|
27
|
+
before_process
|
28
|
+
success_count = 0
|
29
|
+
consecutive_error_count = 0
|
30
|
+
Parallel.each(resources, parallel_opts) do |resource|
|
31
|
+
raise Parallel::Break if stopped?
|
32
|
+
events = nil
|
33
|
+
begin
|
34
|
+
@connection_pool.with do |connection|
|
35
|
+
monitor = monitor_class.new(connection, resource)
|
36
|
+
monitor.process do |_events|
|
37
|
+
events = _events
|
38
|
+
$logger.info { "send_messages:#{events.map(&:to_hash).to_json}" }
|
39
|
+
@api_client_pool.with {|api_client| api_client.send_messages(events) }
|
40
|
+
end
|
41
|
+
end
|
42
|
+
@mutex.synchronize do
|
43
|
+
success_count += 1
|
44
|
+
consecutive_error_count = 0
|
45
|
+
end
|
46
|
+
rescue => e
|
47
|
+
log_error(e)
|
48
|
+
$logger.info { "failed_events:#{events.map(&:to_hash).to_json}" } if events
|
49
|
+
@mutex.synchronize do
|
50
|
+
raise TooManyError if (consecutive_error_count += 1) > self.class.max_consecuitive_error_count
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
success_count
|
55
|
+
ensure
|
56
|
+
after_process
|
57
|
+
end
|
58
|
+
|
59
|
+
def total_count
|
60
|
+
resources.size
|
61
|
+
end
|
62
|
+
|
63
|
+
private
|
64
|
+
|
65
|
+
def before_process
|
66
|
+
@connection_pool = ConnectionPool.new(connection_pool_opts) {
|
67
|
+
connection_class.new(get_connection_info(resource_uri_prefix))
|
68
|
+
}
|
69
|
+
@api_client_pool = ConnectionPool.new(connection_pool_opts) {
|
70
|
+
ApiClient.new # renew connection
|
71
|
+
}
|
72
|
+
@mutex = Mutex.new
|
73
|
+
end
|
74
|
+
|
75
|
+
def after_process
|
76
|
+
@connection_pool.shutdown {|conn| conn.close rescue nil }
|
77
|
+
@api_client_pool.shutdown {|conn| conn.close rescue nil }
|
78
|
+
end
|
79
|
+
|
80
|
+
def connection_class
|
81
|
+
Configuration.connection_class
|
82
|
+
end
|
83
|
+
|
84
|
+
def monitor_class
|
85
|
+
Configuration.monitor_class
|
86
|
+
end
|
87
|
+
|
88
|
+
def name
|
89
|
+
Configuration.name
|
90
|
+
end
|
91
|
+
|
92
|
+
def resources
|
93
|
+
return @resources if @resources
|
94
|
+
@resources = ApiClient.new.list_aggregated_resources(resource_uri_prefix) || []
|
95
|
+
$logger.debug { "resource_uri_prefix:#{resource_uri_prefix} resources.size:#{@resources.size}" }
|
96
|
+
@resources
|
97
|
+
end
|
98
|
+
|
99
|
+
def parallel_opts
|
100
|
+
parallel_type == 'process' ? {in_processes: parallel_size} : {in_threads: parallel_size}
|
101
|
+
end
|
102
|
+
|
103
|
+
def connection_pool_opts
|
104
|
+
{size: connection_pool_size, timeout: connection_pool_timeout}
|
105
|
+
end
|
106
|
+
|
107
|
+
def parallel_size
|
108
|
+
$setting.dig(name, :parallel_size) || 1
|
109
|
+
end
|
110
|
+
|
111
|
+
def parallel_type
|
112
|
+
$setting.dig(name, :parallel_type) || 'thread'
|
113
|
+
end
|
114
|
+
|
115
|
+
def connection_pool_size
|
116
|
+
$setting.dig(name, :connection_pool_size) || parallel_size
|
117
|
+
end
|
118
|
+
|
119
|
+
def connection_pool_timeout
|
120
|
+
$setting.dig(name, :connection_pool_timeout) || 60
|
121
|
+
end
|
122
|
+
|
123
|
+
def get_connection_info(resource_uri_prefix)
|
124
|
+
$setting.dig(name, :connection_info)[resource_uri_prefix]
|
125
|
+
end
|
126
|
+
|
127
|
+
def log_error(e)
|
128
|
+
$logger.error { "#{e.class} #{e.message} #{e.backtrace.join("\\n")}" } # one line
|
129
|
+
end
|
130
|
+
|
131
|
+
def stopped?
|
132
|
+
worker.stopped? if worker and worker.respond_to?(:stopped?)
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|