bmc-daemon-lib 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: cd041b445612d4933a4f5f69ccb0158051892ed7
4
- data.tar.gz: 5a4a9aa4dd013fb2369498d46380d5d815ebdaba
3
+ metadata.gz: 51d2fdee16ca885f005c34f7c8397a9d9204b43d
4
+ data.tar.gz: 4ec68d9f87a93f171cd02057af392500b11be85a
5
5
  SHA512:
6
- metadata.gz: b98b2147d8abeb9b4f6e5214b363a14142c3beb7feff0d673b5b387a05d395f0b986f06df2735e7ea86b6dcb96c5994b01c5cd3568581a426fa2b4e1d552a813
7
- data.tar.gz: 454958f16430d0be771750e5b88244d9619d3eb7e425b9c7f23bdce810fc2988c5ea22d01efc1a5b37d7c43c2c04be16894608009d61fc6ba525142860229d39
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.2.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.1)
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.41.2)
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)
@@ -1,7 +1,7 @@
1
1
  # coding: utf-8
2
2
  Gem::Specification.new do |spec|
3
3
  # Project version
4
- spec.version = "0.2.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
@@ -10,3 +10,4 @@ require_relative "bmc-daemon-lib/logger_formatter"
10
10
  require_relative "bmc-daemon-lib/logger_helper"
11
11
  require_relative "bmc-daemon-lib/logger_pool"
12
12
  require_relative "bmc-daemon-lib/worker_base"
13
+ require_relative "bmc-daemon-lib/mq_consumer"
@@ -81,7 +81,9 @@ module BmcDaemonLib
81
81
  Encoding.default_external = "utf-8"
82
82
 
83
83
  # Init New Relic
84
- newrelic_logfile = File.expand_path(Conf[:logs][:newrelic].to_s, Conf[:logs][:path].to_s)
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
- ENV["NEW_RELIC_APP_NAME"] = "#{text}-#{host};#{text}"
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
- # Skip if no format defined
33
- return unless defined?('LOG_PREFIX_FORMAT')
34
- return unless LOG_PREFIX_FORMAT.is_a? String
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
- # Build prefix string
37
- LOG_PREFIX_FORMAT % values.map(&:to_s)
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 "&Oslash;" 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
- log_info "status [#{status}] on job[#{job.id}] status[#{job.status}] error[#{job.error}]"
83
- else
84
- log_info "status [#{status}]"
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.2.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-07-21 00:00:00.000000000 Z
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: