bmc-daemon-lib 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Gemfile.lock +7 -3
- data/bmc-daemon-lib.gemspec +2 -1
- data/lib/bmc-daemon-lib.rb +1 -0
- data/lib/bmc-daemon-lib/conf.rb +6 -5
- data/lib/bmc-daemon-lib/logger_helper.rb +14 -5
- data/lib/bmc-daemon-lib/logger_pool.rb +4 -2
- data/lib/bmc-daemon-lib/mq_consumer.rb +168 -0
- data/lib/bmc-daemon-lib/worker_base.rb +7 -9
- metadata +17 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 51d2fdee16ca885f005c34f7c8397a9d9204b43d
|
|
4
|
+
data.tar.gz: 4ec68d9f87a93f171cd02057af392500b11be85a
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 84f136ee87bec96835b716df93dc1faf3f3d49c9094f173928ac8b083bfb29b45cd582f7747430f2af5a2754d9c8da1ba6d8729ad54be1cbf2042a5969fa3855
|
|
7
|
+
data.tar.gz: f578421f1565e0a1cdbf15bb39eefa039e11e49dfa8173f0d825fd7a32ffacc6e703dfeb63538162989b362e864cfd9be730282ab1f37ecbe6e4cace6983963b
|
data/Gemfile.lock
CHANGED
|
@@ -1,13 +1,17 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: .
|
|
3
3
|
specs:
|
|
4
|
-
bmc-daemon-lib (0.
|
|
4
|
+
bmc-daemon-lib (0.3.0)
|
|
5
|
+
bunny
|
|
5
6
|
chamber (~> 2.9)
|
|
6
7
|
|
|
7
8
|
GEM
|
|
8
9
|
remote: https://rubygems.org/
|
|
9
10
|
specs:
|
|
11
|
+
amq-protocol (2.0.1)
|
|
10
12
|
ast (2.3.0)
|
|
13
|
+
bunny (2.5.1)
|
|
14
|
+
amq-protocol (>= 2.0.1)
|
|
11
15
|
chamber (2.9.0)
|
|
12
16
|
hashie (~> 3.3)
|
|
13
17
|
thor (~> 0.19.1)
|
|
@@ -22,7 +26,7 @@ GEM
|
|
|
22
26
|
rspec-core (~> 3.5.0)
|
|
23
27
|
rspec-expectations (~> 3.5.0)
|
|
24
28
|
rspec-mocks (~> 3.5.0)
|
|
25
|
-
rspec-core (3.5.
|
|
29
|
+
rspec-core (3.5.2)
|
|
26
30
|
rspec-support (~> 3.5.0)
|
|
27
31
|
rspec-expectations (3.5.0)
|
|
28
32
|
diff-lcs (>= 1.2.0, < 2.0)
|
|
@@ -31,7 +35,7 @@ GEM
|
|
|
31
35
|
diff-lcs (>= 1.2.0, < 2.0)
|
|
32
36
|
rspec-support (~> 3.5.0)
|
|
33
37
|
rspec-support (3.5.0)
|
|
34
|
-
rubocop (0.
|
|
38
|
+
rubocop (0.42.0)
|
|
35
39
|
parser (>= 2.3.1.1, < 3.0)
|
|
36
40
|
powerpack (~> 0.1)
|
|
37
41
|
rainbow (>= 1.99.1, < 3.0)
|
data/bmc-daemon-lib.gemspec
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# coding: utf-8
|
|
2
2
|
Gem::Specification.new do |spec|
|
|
3
3
|
# Project version
|
|
4
|
-
spec.version = "0.
|
|
4
|
+
spec.version = "0.3.0"
|
|
5
5
|
|
|
6
6
|
# Project description
|
|
7
7
|
spec.name = "bmc-daemon-lib"
|
|
@@ -27,4 +27,5 @@ Gem::Specification.new do |spec|
|
|
|
27
27
|
|
|
28
28
|
# Runtime dependencies
|
|
29
29
|
spec.add_runtime_dependency "chamber", "~> 2.9"
|
|
30
|
+
spec.add_runtime_dependency "bunny"
|
|
30
31
|
end
|
data/lib/bmc-daemon-lib.rb
CHANGED
data/lib/bmc-daemon-lib/conf.rb
CHANGED
|
@@ -81,7 +81,9 @@ module BmcDaemonLib
|
|
|
81
81
|
Encoding.default_external = "utf-8"
|
|
82
82
|
|
|
83
83
|
# Init New Relic
|
|
84
|
-
|
|
84
|
+
logs_newrelic = Conf.at :logs, :newrelic
|
|
85
|
+
logs_path = Conf.at :logs, :path
|
|
86
|
+
newrelic_logfile = File.expand_path logs_newrelic.to_s, logs_path.to_s
|
|
85
87
|
prepare_newrelic self[:newrelic], newrelic_logfile
|
|
86
88
|
|
|
87
89
|
# Try to access any key to force parsing of the files
|
|
@@ -171,16 +173,15 @@ module BmcDaemonLib
|
|
|
171
173
|
ENV["NEW_RELIC_MONITOR_MODE"] = "true"
|
|
172
174
|
|
|
173
175
|
# Build NewRelic app_name if not provided as-is
|
|
174
|
-
if section[:app_name]
|
|
175
|
-
ENV["NEW_RELIC_APP_NAME"] = section[:app_name].to_s
|
|
176
|
-
else
|
|
176
|
+
if !section[:app_name]
|
|
177
177
|
stack = []
|
|
178
178
|
stack << (section[:prefix] || @app_name)
|
|
179
179
|
stack << section[:platform] if section[:platform]
|
|
180
180
|
stack << @app_env
|
|
181
181
|
text = stack.join('-')
|
|
182
|
-
|
|
182
|
+
section[:app_name] = "#{text}; #{text}-#{host}"
|
|
183
183
|
end
|
|
184
|
+
ENV["NEW_RELIC_APP_NAME"] = section[:app_name].to_s
|
|
184
185
|
|
|
185
186
|
# Enable module
|
|
186
187
|
ENV["NEWRELIC_AGENT_ENABLED"] = "true"
|
|
@@ -25,16 +25,25 @@ module BmcDaemonLib
|
|
|
25
25
|
|
|
26
26
|
# Builds prefix if LOG_PREFIX_FORMAT defined and caller has log_prefix method to provide values
|
|
27
27
|
def build_prefix
|
|
28
|
+
# Skip if no format defined
|
|
29
|
+
return unless defined?('LOG_PREFIX_FORMAT')
|
|
30
|
+
return unless LOG_PREFIX_FORMAT.is_a? String
|
|
31
|
+
|
|
28
32
|
# Skip if no values from user class
|
|
29
33
|
return unless respond_to?(:log_prefix, true)
|
|
30
34
|
values = log_prefix
|
|
31
35
|
|
|
32
|
-
#
|
|
33
|
-
|
|
34
|
-
|
|
36
|
+
# Change to an array if not already
|
|
37
|
+
values = [values] if values.is_a? String
|
|
38
|
+
|
|
39
|
+
# Stop if still not an array
|
|
40
|
+
return unless values.is_a? Array
|
|
41
|
+
|
|
42
|
+
# Finally format the string
|
|
43
|
+
return LOG_PREFIX_FORMAT % values.map(&:to_s)
|
|
35
44
|
|
|
36
|
-
|
|
37
|
-
|
|
45
|
+
rescue ArgumentError
|
|
46
|
+
return "INVALID_FORMAT"
|
|
38
47
|
end
|
|
39
48
|
|
|
40
49
|
def build_messages severity, message, details = nil
|
|
@@ -6,7 +6,9 @@ module BmcDaemonLib
|
|
|
6
6
|
class LoggerPool
|
|
7
7
|
include Singleton
|
|
8
8
|
|
|
9
|
-
def get pipe
|
|
9
|
+
def get pipe = nil
|
|
10
|
+
pipe = :default if pipe.to_s.blank?
|
|
11
|
+
|
|
10
12
|
@loggers ||= {}
|
|
11
13
|
@loggers[pipe] ||= create(pipe)
|
|
12
14
|
end
|
|
@@ -31,7 +33,7 @@ module BmcDaemonLib
|
|
|
31
33
|
|
|
32
34
|
def logfile pipe
|
|
33
35
|
# Disabled if no valid config
|
|
34
|
-
return nil unless Conf[:logs].is_a?(Hash)
|
|
36
|
+
return nil unless Conf[:logs].is_a?(Hash) && Conf.at(:logs, pipe)
|
|
35
37
|
|
|
36
38
|
# Compute logfile and check if we can write there
|
|
37
39
|
logfile = File.expand_path(Conf[:logs][pipe].to_s, Conf[:logs][:path].to_s)
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
require "bunny"
|
|
2
|
+
|
|
3
|
+
module BmcDaemonLib
|
|
4
|
+
# class ShouterResponseError < StandardError; end
|
|
5
|
+
# class ShouterChannelClosed < StandardError; end
|
|
6
|
+
# class ShouterPreconditionFailed < StandardError; end
|
|
7
|
+
# class ShouterInterrupted < StandardError; end
|
|
8
|
+
# class EndpointTopicContext < StandardError; end
|
|
9
|
+
class EndpointConnexionContext < StandardError; end
|
|
10
|
+
class EndpointConnectionError < StandardError; end
|
|
11
|
+
class EndpointSubscribeContext < StandardError; end
|
|
12
|
+
class EndpointSubscribeError < StandardError; end
|
|
13
|
+
|
|
14
|
+
class MqConsumer
|
|
15
|
+
include LoggerHelper
|
|
16
|
+
attr_reader :logger
|
|
17
|
+
|
|
18
|
+
protected
|
|
19
|
+
|
|
20
|
+
def log_prefix
|
|
21
|
+
self.class.name.split('::').last
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def subscribe_on_queue name
|
|
25
|
+
info "use_queue [#{name}]"
|
|
26
|
+
|
|
27
|
+
# Queue for this rule
|
|
28
|
+
@queue = @channel.queue(name, auto_delete: false, durable: true)
|
|
29
|
+
|
|
30
|
+
# Create consumer on this queue
|
|
31
|
+
@queue.subscribe(manual_ack: AMQP_MANUAL_ACK, on_cancellation: :consumer_cancelled) do |delivery_info, metadata, payload|
|
|
32
|
+
# Prepare data
|
|
33
|
+
msg_exchange = delivery_info.exchange
|
|
34
|
+
msg_rkey = delivery_info.routing_key.force_encoding('UTF-8')
|
|
35
|
+
msg_tag = delivery_info.delivery_tag
|
|
36
|
+
|
|
37
|
+
msg_headers = metadata.headers || {}
|
|
38
|
+
|
|
39
|
+
# Extract payload
|
|
40
|
+
msg_data = payload_parse payload, metadata.content_type
|
|
41
|
+
|
|
42
|
+
# Announce
|
|
43
|
+
announce msg_rkey, msg_tag, msg_data, metadata, msg_exchange, payload.bytesize
|
|
44
|
+
|
|
45
|
+
# Hand to the callback
|
|
46
|
+
receive msg_rkey, msg_tag, msg_data, metadata, delivery_info
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def announce msg_rkey, msg_tag, msg_data, metadata, msg_exchange, payload_bytesize
|
|
51
|
+
# Prepare data
|
|
52
|
+
msg_headers = metadata.headers || {}
|
|
53
|
+
|
|
54
|
+
# Announce match
|
|
55
|
+
log_message MSG_RECV, msg_exchange, msg_rkey, msg_data, {
|
|
56
|
+
'channel.dtag' => "#{@channel.id}.#{msg_tag}",
|
|
57
|
+
'app-id' => metadata.app_id,
|
|
58
|
+
'content-type' => metadata.content_type,
|
|
59
|
+
'delay (ms)' => extract_delay(msg_headers),
|
|
60
|
+
'body size' => format_bytes(payload_bytesize, "B"),
|
|
61
|
+
}
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def bind_on topic, route
|
|
65
|
+
# Exchange to this rule
|
|
66
|
+
exchange = @channel.topic(topic, durable: true, persistent: false)
|
|
67
|
+
|
|
68
|
+
info "bind_on [#{topic}] [#{route}] > [#{@queue.name}]"
|
|
69
|
+
@queue.bind exchange, routing_key: route
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def consumer_cancelled all={}
|
|
73
|
+
error "consumer cancelled remotely: #{all.inspect}"
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
# Start connexion to RabbitMQ
|
|
77
|
+
def connect_to busconf
|
|
78
|
+
fail PushyDaemon::EndpointConnexionContext, "invalid bus host/port" unless busconf
|
|
79
|
+
info "connecting to bus", {
|
|
80
|
+
broker: busconf,
|
|
81
|
+
recover: AMQP_RECOVERY_INTERVAL,
|
|
82
|
+
heartbeat: AMQP_HEARTBEAT_INTERVAL,
|
|
83
|
+
prefetch: AMQP_PREFETCH
|
|
84
|
+
}
|
|
85
|
+
conn = Bunny.new busconf.to_s,
|
|
86
|
+
logger: @logger,
|
|
87
|
+
# heartbeat: :server,
|
|
88
|
+
automatically_recover: true,
|
|
89
|
+
network_recovery_interval: AMQP_RECOVERY_INTERVAL,
|
|
90
|
+
heartbeat_interval: AMQP_HEARTBEAT_INTERVAL,
|
|
91
|
+
read_write_timeout: AMQP_HEARTBEAT_INTERVAL*2
|
|
92
|
+
conn.start
|
|
93
|
+
|
|
94
|
+
rescue Bunny::TCPConnectionFailedForAllHosts, Bunny::AuthenticationFailureError, AMQ::Protocol::EmptyResponseError => e
|
|
95
|
+
fail PushyDaemon::EndpointConnectionError, "error connecting (#{e.class})"
|
|
96
|
+
rescue StandardError => e
|
|
97
|
+
fail PushyDaemon::EndpointConnectionError, "unknow (#{e.inspect})"
|
|
98
|
+
else
|
|
99
|
+
return conn
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def identifier len
|
|
103
|
+
rand(36**len).to_s(36)
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def log_message msg_way, msg_exchange, msg_key, msg_body = [], msg_attrs = {}
|
|
107
|
+
# Message header
|
|
108
|
+
info sprintf("%3s %-15s %s", msg_way, msg_exchange, msg_key)
|
|
109
|
+
|
|
110
|
+
# Body lines
|
|
111
|
+
if msg_body.is_a?(Enumerable) && !msg_body.empty?
|
|
112
|
+
body_json = JSON.pretty_generate(msg_body)
|
|
113
|
+
log_debug nil, body_json.lines
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
# Attributes lines
|
|
117
|
+
log_debug nil, msg_attrs if msg_attrs
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
def extract_delay msg_headers
|
|
121
|
+
return unless msg_headers['sent_at']
|
|
122
|
+
|
|
123
|
+
# Extract sent_at header
|
|
124
|
+
sent_at = Time.iso8601(msg_headers['sent_at']) rescue nil
|
|
125
|
+
# log_info "sent_at : #{sent_at.to_f}"
|
|
126
|
+
# log_info "timenow : #{Time.now.to_f}"
|
|
127
|
+
|
|
128
|
+
# Compute delay
|
|
129
|
+
return ((Time.now - sent_at)*1000).round(2)
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
def format_bytes number, unit="", decimals = 0
|
|
133
|
+
return "Ø" if number.nil? || number.to_f.zero?
|
|
134
|
+
|
|
135
|
+
units = ["", "k", "M", "G", "T", "P" ]
|
|
136
|
+
index = ( Math.log(number) / Math.log(2) ).to_i / 10
|
|
137
|
+
converted = number.to_f / (1024 ** index)
|
|
138
|
+
|
|
139
|
+
truncated = converted.round(decimals)
|
|
140
|
+
return "#{truncated} #{units[index]}#{unit}"
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
def receive delivery_info, metadata, payload
|
|
144
|
+
debug "MqConsumer.receive"
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
def payload_parse payload, content_type #, fields = []
|
|
148
|
+
# Force encoding (pftop...)
|
|
149
|
+
utf8payload = payload.to_s.force_encoding('UTF-8')
|
|
150
|
+
|
|
151
|
+
# Parse payload if content-type provided
|
|
152
|
+
case content_type
|
|
153
|
+
when "application/json"
|
|
154
|
+
return JSON.parse utf8payload rescue nil
|
|
155
|
+
when "text/plain"
|
|
156
|
+
return utf8payload.to_s
|
|
157
|
+
else
|
|
158
|
+
return utf8payload
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
# Handle body parse errors
|
|
162
|
+
rescue Encoding::UndefinedConversionError => e
|
|
163
|
+
log_error "parse: JSON PARSE ERROR: #{e.inspect}"
|
|
164
|
+
return {}
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
end
|
|
168
|
+
end
|
|
@@ -16,10 +16,8 @@ module BmcDaemonLib
|
|
|
16
16
|
@config = {}
|
|
17
17
|
|
|
18
18
|
# Set thread context
|
|
19
|
-
@pool = pool
|
|
20
|
-
@wid = wid
|
|
21
|
-
Thread.current.thread_variable_set :pool, pool
|
|
22
|
-
Thread.current.thread_variable_set :wid, wid
|
|
19
|
+
Thread.current.thread_variable_set :pool, (@pool = pool)
|
|
20
|
+
Thread.current.thread_variable_set :wid, (@wid = wid)
|
|
23
21
|
Thread.current.thread_variable_set :started_at, Time.now
|
|
24
22
|
worker_status WORKER_STATUS_STARTING
|
|
25
23
|
|
|
@@ -78,11 +76,11 @@ module BmcDaemonLib
|
|
|
78
76
|
return unless @log_worker_status_changes
|
|
79
77
|
|
|
80
78
|
# Log this status change
|
|
81
|
-
if job.is_a?(Job)
|
|
82
|
-
|
|
83
|
-
else
|
|
84
|
-
|
|
85
|
-
end
|
|
79
|
+
# if defined?'Job' && job.is_a?(Job)
|
|
80
|
+
# log_info "status [#{status}] on job[#{job.id}] status[#{job.status}] error[#{job.error}]"
|
|
81
|
+
# else
|
|
82
|
+
log_info "status [#{status}]"
|
|
83
|
+
# end
|
|
86
84
|
end
|
|
87
85
|
|
|
88
86
|
def worker_jid jid
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: bmc-daemon-lib
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.3.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Bruno MEDICI
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2016-
|
|
11
|
+
date: 2016-08-17 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: bundler
|
|
@@ -80,6 +80,20 @@ dependencies:
|
|
|
80
80
|
- - "~>"
|
|
81
81
|
- !ruby/object:Gem::Version
|
|
82
82
|
version: '2.9'
|
|
83
|
+
- !ruby/object:Gem::Dependency
|
|
84
|
+
name: bunny
|
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
|
86
|
+
requirements:
|
|
87
|
+
- - ">="
|
|
88
|
+
- !ruby/object:Gem::Version
|
|
89
|
+
version: '0'
|
|
90
|
+
type: :runtime
|
|
91
|
+
prerelease: false
|
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
93
|
+
requirements:
|
|
94
|
+
- - ">="
|
|
95
|
+
- !ruby/object:Gem::Version
|
|
96
|
+
version: '0'
|
|
83
97
|
description: 'Shared utilities to build a daemon: logger, configuration, helpers'
|
|
84
98
|
email: bmc-daemon-lib@bmconseil.com
|
|
85
99
|
executables: []
|
|
@@ -98,6 +112,7 @@ files:
|
|
|
98
112
|
- lib/bmc-daemon-lib/logger_formatter.rb
|
|
99
113
|
- lib/bmc-daemon-lib/logger_helper.rb
|
|
100
114
|
- lib/bmc-daemon-lib/logger_pool.rb
|
|
115
|
+
- lib/bmc-daemon-lib/mq_consumer.rb
|
|
101
116
|
- lib/bmc-daemon-lib/worker_base.rb
|
|
102
117
|
homepage: http://github.com/bmedici/bmc-daemon-lib
|
|
103
118
|
licenses:
|