acception-subscriber 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 77f56d09784b6c9d77a986455b5f18f8a0ae55e7
4
+ data.tar.gz: 46026ce3b88d330b1aaf6d89027ba948365f71e3
5
+ SHA512:
6
+ metadata.gz: caa67f69a4f6f13b3dfd5904e2aada8ebb9adfb5c38f0959df561871128c1d7012ea37aa4eb3cb6f2e172293132945ac914537aa1834ecbed0373ef3c61cb034
7
+ data.tar.gz: b6d0c9e860e241b3c7c08f275a7460b1547500e5aaea1412087b58ebb130fe2223d7860e8f8650be9c5be676890f58305303f4d335edc75fc12f28ed3489c6b6
@@ -0,0 +1,22 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ *.bundle
19
+ *.so
20
+ *.o
21
+ *.a
22
+ mkmf.log
@@ -0,0 +1 @@
1
+ acception-subscriber
@@ -0,0 +1 @@
1
+ 2.1.0
data/Gemfile ADDED
@@ -0,0 +1,11 @@
1
+ source 'https://rubygems.org'
2
+ source 'http://dev.staging.iberon.com/gemserver'
3
+
4
+ # Specify your gem's dependencies in replication-subscriber.gemspec
5
+ gemspec
6
+
7
+ group :development do
8
+ gem 'rake-iberon', '~> 1', require: false
9
+ end
10
+
11
+ #gem 'acception-client', path: '../acception-client'
@@ -0,0 +1,3 @@
1
+ Copyright (c) 2014 Iberon, LLC
2
+
3
+ No license granted
@@ -0,0 +1,21 @@
1
+ # Acception::Subscriber
2
+
3
+ A RabbitMQ subscriber that pushes messages to Acception's API.
4
+
5
+
6
+ ## Installation
7
+
8
+ Add this line to your application's Gemfile:
9
+
10
+ gem 'acception-subscriber'
11
+
12
+ And then execute:
13
+
14
+ $ bundle
15
+
16
+ Or install it yourself as:
17
+
18
+ $ gem install acception-subscriber
19
+
20
+ ## Usage
21
+
@@ -0,0 +1,2 @@
1
+ require "bundler/gem_tasks"
2
+
@@ -0,0 +1,32 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'acception/subscriber/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "acception-subscriber"
8
+ spec.version = Acception::Subscriber::VERSION
9
+ spec.authors = ["C. Jason Harrelson"]
10
+ spec.email = ["cjharrelson@iberon.com"]
11
+ spec.summary = %q{A RabbitMQ subscriber that pushes messages to Acception's API.}
12
+ spec.description = %q{A RabbitMQ subscriber that pushes messages to Acception's API. See README for more details.}
13
+ spec.homepage = "https://gitlab.staging.iberon.com/common/acception-subscriber"
14
+ spec.license = ""
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.6"
22
+ spec.add_development_dependency "rake"
23
+
24
+ spec.add_dependency "acception-client", ">= 1.2"
25
+ spec.add_dependency "bunny", "~> 1"
26
+ spec.add_dependency "celluloid", "~> 0"
27
+ spec.add_dependency "multi_json", "~> 1"
28
+ spec.add_dependency "oj", "~> 2"
29
+ spec.add_dependency "trollop", "~> 2"
30
+ spec.add_dependency "yell", "~> 1"
31
+
32
+ end
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env ruby
2
+ require 'acception/subscriber/cli'
3
+ $0 = Acception::Subscriber::APP_ID
4
+ Acception::Subscriber::Cli.new( ARGV ).run
@@ -0,0 +1 @@
1
+ require 'acception/subscriber'
@@ -0,0 +1,39 @@
1
+ require 'ansi'
2
+ require "acception/client"
3
+ require "acception/subscriber/version"
4
+
5
+ module Acception
6
+ module Subscriber
7
+
8
+ autoload :Configuration, 'acception/subscriber/configuration'
9
+ autoload :Logging, 'acception/subscriber/logging'
10
+ autoload :MessageHandler, 'acception/subscriber/message_handler'
11
+ autoload :Server, 'acception/subscriber/server'
12
+ autoload :ServerDaemon, 'acception/subscriber/server_daemon'
13
+ autoload :ServerLogging, 'acception/subscriber/server_logging'
14
+
15
+ APP_ID = "acception-sub"
16
+ APP_NAME = "Acception Subscriber"
17
+ COMPANY = "Iberon, LLC"
18
+ INT = "INT"
19
+ TERM = "TERM"
20
+ VERSION_COPYRIGHT = "v#{VERSION} \u00A9#{Time.now.year} #{COMPANY}"
21
+
22
+ def self.configuration
23
+ @configuration ||= Configuration.new
24
+ end
25
+
26
+ def self.configuration=( configuration )
27
+ @configuration = configuration
28
+ end
29
+
30
+ def self.configure
31
+ yield( configuration ) if block_given?
32
+ end
33
+
34
+ class << self
35
+ attr_accessor :logger
36
+ end
37
+
38
+ end
39
+ end
@@ -0,0 +1,132 @@
1
+ require 'rubygems'
2
+ require 'acception/subscriber'
3
+ require 'trollop'
4
+ require 'yell'
5
+
6
+ module Acception
7
+ module Subscriber
8
+ class Cli
9
+
10
+ attr_reader :cmd,
11
+ :options
12
+
13
+ SUB_COMMANDS = %w(
14
+ restart
15
+ start
16
+ status
17
+ stop
18
+ )
19
+
20
+ DEFAULT_CONFIG_PATH = "/etc/ncite/#{APP_ID}.conf"
21
+ DEFAULT_LOG_PATH = "/var/log/ncite/#{APP_ID}.log"
22
+ DEFAULT_PID_PATH = "/var/run/ncite/#{APP_ID}.pid"
23
+
24
+ DEFAULT_NUMBER_OF_THREADS = 1
25
+
26
+ def initialize( args )
27
+ Trollop::options do
28
+ version VERSION_COPYRIGHT
29
+ banner <<-EOS
30
+ #{APP_NAME} #{VERSION_COPYRIGHT}
31
+
32
+ Usage:
33
+ #{APP_ID} [command] [options]
34
+
35
+ commands:
36
+ #{SUB_COMMANDS.map { |sub_cmd| " #{sub_cmd}" }.join( "\n" )}
37
+
38
+ (For help with a command: #{APP_ID} [command] -h)
39
+
40
+ options:
41
+ EOS
42
+ stop_on SUB_COMMANDS
43
+ end
44
+
45
+ # Get the sub-command and its options
46
+ #
47
+ @cmd = ARGV.shift || ''
48
+ @options = case( cmd )
49
+ when "restart"
50
+ Trollop::options do
51
+ opt :config, "The path for the config file", :type => String, :short => '-c', :default => DEFAULT_CONFIG_PATH
52
+ opt :log_level, "The log level", :type => String, :default => 'info'
53
+ opt :log_level, "The log level", :type => String, :default => 'info', :short => '-o'
54
+ opt :log, "The path for the log file", :type => String, :short => '-l', :default => DEFAULT_LOG_PATH
55
+ opt :pid, "The path for the PID file", :type => String, :default => DEFAULT_PID_PATH
56
+ opt :threads, "The number of threads", :type => Integer, :default => DEFAULT_NUMBER_OF_THREADS, :short => '-t'
57
+ end
58
+ when "start"
59
+ Trollop::options do
60
+ opt :config, "The path for the config file", :type => String, :short => '-c', :default => DEFAULT_CONFIG_PATH
61
+ opt :interactive, "Execute the server in interactive mode", :short => '-i'
62
+ opt :log_level, "The log level", :type => String, :default => 'info', :short => '-o'
63
+ opt :log, "The path for the log file", :type => String, :short => '-l', :default => DEFAULT_LOG_PATH
64
+ opt :pid, "The path for the PID file", :type => String, :default => DEFAULT_PID_PATH
65
+ opt :threads, "The number of threads", :type => Integer, :default => DEFAULT_NUMBER_OF_THREADS, :short => '-t'
66
+ end
67
+ when "status"
68
+ Trollop::options do
69
+ opt :pid, "The path for the PID file", :type => String, :default => DEFAULT_PID_PATH
70
+ end
71
+ when "stop"
72
+ Trollop::options do
73
+ opt :pid, "The path for the PID file", :type => String, :default => DEFAULT_PID_PATH
74
+ end
75
+ else
76
+ Trollop::die "unknown command #{cmd.inspect}"
77
+ end
78
+
79
+ if cmd == 'start'
80
+ unless options[:interactive]
81
+ Trollop::die( :config, "is required when running as daemon" ) unless options[:config]
82
+ Trollop::die( :log, "is required when running as daemon" ) unless options[:log]
83
+ Trollop::die( :pid, "is required when running as daemon" ) unless options[:pid]
84
+ end
85
+ end
86
+
87
+ if %w(restart status stop).include?( cmd )
88
+ Trollop::die( :pid, "is required" ) unless options[:pid]
89
+ end
90
+ end
91
+
92
+ def run
93
+ send( cmd )
94
+ end
95
+
96
+ protected
97
+
98
+ def start
99
+ if options[:interactive]
100
+ start_interactive
101
+ else
102
+ start_daemon
103
+ end
104
+ end
105
+
106
+ def start_interactive
107
+ server = Acception::Subscriber::Server.new( options.merge( log: nil ))
108
+ server.start
109
+ end
110
+
111
+ def start_daemon
112
+ server = Acception::Subscriber::ServerDaemon.new( options )
113
+ server.start
114
+ end
115
+
116
+ def stop
117
+ server = Acception::Subscriber::ServerDaemon.new( options )
118
+ server.stop
119
+ end
120
+
121
+ def restart
122
+ stop
123
+ start_daemon
124
+ end
125
+
126
+ def status
127
+ Acception::Subscriber::ServerDaemon.new( options ).status
128
+ end
129
+
130
+ end
131
+ end
132
+ end
@@ -0,0 +1,48 @@
1
+ require 'oj'
2
+
3
+ module Acception
4
+ module Subscriber
5
+ class Configuration
6
+
7
+ def self.attributes
8
+ %w(
9
+ acception_auth_token
10
+ acception_url
11
+ host_uri
12
+ queue
13
+ )
14
+ end
15
+
16
+ attr_accessor( *attributes )
17
+
18
+ def self.from_file( file_path )
19
+ options = Oj.load( File.read( file_path ))
20
+ Acception::Subscriber.configuration = Configuration.new
21
+
22
+ attributes.each do |c|
23
+ if options[c]
24
+ Acception::Subscriber.configuration.send( :"#{c}=", options[c] )
25
+ end
26
+ end
27
+ end
28
+
29
+ def acception_auth_token
30
+ @acception_auth_token || "00-6TKIMQF4NZA"
31
+ end
32
+
33
+ def acception_url
34
+ @acception_url || "http://localhost:3004"
35
+ end
36
+
37
+ def host_uri
38
+ @host_uri || "amqp://guest:guest@127.0.0.1:5672"
39
+ end
40
+
41
+ def queue
42
+ #@queue || "error-repo"
43
+ @queue || "error"
44
+ end
45
+
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,23 @@
1
+ module Acception
2
+ module Subscriber
3
+ module Logging
4
+
5
+ %w(
6
+ debug
7
+ error
8
+ fatal
9
+ info
10
+ warn
11
+ ).each do |level|
12
+
13
+ define_method level do |*messages|
14
+ messages.each do |message|
15
+ Acception::Subscriber.logger.send level, message
16
+ end
17
+ end
18
+
19
+ end
20
+
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,119 @@
1
+ require 'celluloid/autostart'
2
+ require 'oj'
3
+
4
+ module Acception
5
+ module Subscriber
6
+ class MessageHandler
7
+
8
+ include Celluloid
9
+ include Logging
10
+
11
+ BLANK = '<<blank>>'
12
+ ERROR = 'error'
13
+ LICENSE_VIOLATION = 'license-violation'
14
+ REQUEUE = true
15
+
16
+ def call( options )
17
+ channel = options[:channel]
18
+ delivery_info = options[:delivery_info]
19
+ payload = options[:payload]
20
+ metadata = options[:metadata]
21
+ headers = metadata[:headers]
22
+
23
+ debug ANSI.cyan { 'HEADERS' } + " #{headers}"
24
+ debug ANSI.yellow { 'PAYLOAD' } + " #{payload}"
25
+
26
+ case resolve_type( payload )
27
+ when ERROR
28
+ handle_error( headers )
29
+ when LICENSE_VIOLATION
30
+ handle_license_violation( headers )
31
+ else
32
+ end
33
+
34
+ channel.acknowledge delivery_info.delivery_tag
35
+ rescue => e
36
+ debug ANSI.red { "NACK" } + " #{e.message}"
37
+ debug ANSI.red { "NACK" } + " #{e.backtrace}"
38
+ #channel.nack delivery_info.delivery_tag
39
+ end
40
+
41
+ protected
42
+
43
+ def handle_error( headers )
44
+ exception = headers['exception']
45
+ acception = Acception::Client::OpenMessages::Create.new( message_type: Acception::MessageType::ERROR,
46
+ application: (headers['application'] || BLANK),
47
+ environment: (headers['environment'] || BLANK),
48
+ occurred_at: (headers['occurred_at'] || BLANK),
49
+ message: (exception['message'] || BLANK),
50
+ request_headers: (headers['request_headers'] || BLANK),
51
+ request_parameters: (headers['request_parameters'] || BLANK),
52
+ session: (headers['session'] || BLANK),
53
+ type: (exception['class'] || BLANK),
54
+ stack: (exception['backtrace'] || BLANK) )
55
+ acception.call
56
+ end
57
+
58
+ def handle_license_violation( headers )
59
+ acception = Acception::Client::OpenMessages::Create.new( message_type: Acception::MessageType::LICENSE_VIOLATION,
60
+ application: headers['application'],
61
+ occurred_at: headers['occurred_at'],
62
+ variables: [
63
+ {
64
+ name: 'license-violation-type',
65
+ content: (headers['type'] || BLANK),
66
+ content_type: 'text/plain'
67
+ },
68
+ {
69
+ name: 'license-content',
70
+ content: (headers['content'] || BLANK),
71
+ content_type: 'application/base64'
72
+ },
73
+ {
74
+ name: 'nonce',
75
+ content: (headers['nonce'] || BLANK),
76
+ content_type: 'application/base64'
77
+ },
78
+ {
79
+ name: 'site-private-key',
80
+ content: (headers['site_private_key'] || BLANK),
81
+ content_type: 'application/base64'
82
+ },
83
+ {
84
+ name: 'iberon-public-key',
85
+ content: (headers['iiberon_public_key'] || BLANK),
86
+ content_type: 'application/base64'
87
+ }
88
+ ])
89
+ acception.call
90
+ end
91
+
92
+ def resolve_type( payload )
93
+ return ERROR if payload == ERROR
94
+ return LICENSE_VIOLATION if payload == LICENSE_VIOLATION
95
+ return nil
96
+ end
97
+
98
+ #def handle_error( channel, payload, e )
99
+ #error( ANSI.red { e.message + " | " + e.backtrace.inspect } )
100
+ #error_queue( channel ).publish( payload, headers: { application: Acception::Subscriber::APP_ID,
101
+ #exception_message: e.message,
102
+ #exception_class: e.class.name,
103
+ #exception_backtrace: e.backtrace } )
104
+ #rescue => ex
105
+ #error( ANSI.red { ex.message + " | " + ex.backtrace.inspect } )
106
+ #end
107
+
108
+ #def requeue( channel, delivery_info, e=nil )
109
+ #debug ANSI.yellow { 'REQUEUE ' + e.message }
110
+ #channel.reject delivery_info.delivery_tag, REQUEUE
111
+ #end
112
+
113
+ def config
114
+ Acception::Subscriber.configuration
115
+ end
116
+
117
+ end
118
+ end
119
+ end
@@ -0,0 +1,7 @@
1
+ module Acception
2
+ module Subscriber
3
+ class PublishError < RuntimeError
4
+
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,118 @@
1
+ require 'bunny'
2
+ require 'celluloid'
3
+
4
+ module Acception
5
+ module Subscriber
6
+ class Server
7
+
8
+ include ServerLogging
9
+ include Logging
10
+
11
+ attr_reader :message_consumer,
12
+ :options
13
+
14
+ def initialize( options )
15
+ @options = options
16
+
17
+ configure_server
18
+ end
19
+
20
+ def start
21
+ log_startup
22
+ run
23
+
24
+ trap( INT ) { finalize; exit }
25
+ sleep
26
+ end
27
+
28
+ protected
29
+
30
+ def finalize
31
+ info "SHUTTING DOWN"
32
+ message_consumer.cancel
33
+ mq.close
34
+ end
35
+
36
+ def mq
37
+ @mq ||= Bunny.new( host_uri ).tap do |bunny|
38
+ bunny.start
39
+ end
40
+ end
41
+
42
+ def channel
43
+ @channel ||= mq.create_channel
44
+ end
45
+
46
+ def queue
47
+ @queue ||= channel.queue( config.queue,
48
+ durable: true )
49
+ end
50
+
51
+ def pool
52
+ @pool ||= MessageHandler.pool( size: options[:threads] )
53
+ end
54
+
55
+ def run
56
+ if options[:threads] == 1
57
+ Celluloid::Actor[:message_handler] = MessageHandler.new
58
+ end
59
+
60
+ @message_consumer = queue.subscribe( manual_ack: true ) do |delivery_info, metadata, payload|
61
+ debug ANSI.magenta { "LISTENER RECEIVED #{payload}" }
62
+
63
+ if options[:threads] > 1
64
+ pool.async.call( payload: payload,
65
+ delivery_info: delivery_info,
66
+ metadata: metadata,
67
+ channel: channel )
68
+ else
69
+ message_handler.call( payload: payload,
70
+ delivery_info: delivery_info,
71
+ metadata: metadata,
72
+ channel: channel )
73
+ end
74
+ end
75
+ end
76
+
77
+ def message_handler
78
+ Celluloid::Actor[:message_handler]
79
+ end
80
+
81
+ def host_uri
82
+ config.host_uri
83
+ end
84
+
85
+ def config
86
+ Acception::Subscriber.configuration
87
+ end
88
+
89
+ def configure_server
90
+ load_configuration
91
+ configure_acception
92
+ initialize_loggers
93
+ end
94
+
95
+ def load_configuration
96
+ if File.exists?( options[:config] )
97
+ options[:config_loaded] = true
98
+ Configuration.from_file( options[:config] )
99
+ end
100
+ end
101
+
102
+ def configure_acception
103
+ Acception::Client.configure do |c|
104
+ c.authentication_token = config.acception_auth_token
105
+ c.base_url = config.acception_url
106
+ #c.graceful_errors_map = ServiceErrorHandling::GRACEFUL_ERRORS_MAP
107
+ c.logger = Acception::Subscriber.logger
108
+ #c.log_level = options.fetch( :log_level, :info ).to_sym
109
+ c.open_timeout_in_seconds = 10
110
+ c.read_timeout_in_seconds = 20
111
+ #c.retry_attempts = configatron.iols.retry_attempts.to_i || 1
112
+ #c.retry_sleep = configatron.iols.retry_sleep || false
113
+ end
114
+ end
115
+
116
+ end
117
+ end
118
+ end
@@ -0,0 +1,146 @@
1
+ require 'rubygems'
2
+ require 'fileutils'
3
+ require 'timeout'
4
+
5
+ module Acception
6
+ module Subscriber
7
+ class ServerDaemon
8
+
9
+ attr_reader :name,
10
+ :options,
11
+ :pid,
12
+ :pid_path,
13
+ :script,
14
+ :timeout
15
+
16
+ def initialize( options )
17
+ @options = options
18
+ @name = options[:name] || APP_NAME
19
+ @pid_path = options[:pid] || '.'
20
+ @pid = get_pid
21
+ @timeout = options[:timeout] || 10
22
+ end
23
+
24
+ def start
25
+ abort "Process already running!" if process_exists?
26
+
27
+ pid = fork do
28
+ exit if fork
29
+ Process.setsid
30
+ exit if fork
31
+ store_pid( Process.pid )
32
+ File.umask 0000
33
+ redirect_output!
34
+ run
35
+ end
36
+
37
+ Process.waitpid( pid )
38
+ end
39
+
40
+ def run
41
+ Server.new( options ).start
42
+ end
43
+
44
+ def stop
45
+ kill_process
46
+ FileUtils.rm pid_path
47
+ end
48
+
49
+ def status
50
+ out = "#{APP_NAME} "
51
+ if process_exists?
52
+ out << "process running with PID: #{pid}"
53
+ else
54
+ out << "process does not exist"
55
+ end
56
+ $stdout.puts out
57
+ end
58
+
59
+ protected
60
+
61
+ #def create_pid( pid )
62
+ def store_pid( pid )
63
+ File.open( pid_path, 'w' ) do |f|
64
+ f.puts pid
65
+ end
66
+ rescue => e
67
+ $stderr.puts "Unable to open #{pid_path} for writing:\n\t(#{e.class}) #{e.message}"
68
+ exit!
69
+ end
70
+
71
+ def get_pid
72
+ return nil unless File.exists?( pid_path )
73
+ pid = nil
74
+ File.open( @pid_path, 'r' ) do |f|
75
+ pid = f.readline.to_s.gsub( /[^0-9]/, '' )
76
+ end
77
+ pid.to_i
78
+ rescue Errno::ENOENT
79
+ nil
80
+ end
81
+
82
+ def remove_pidfile
83
+ File.unlink( pid_path )
84
+ rescue => e
85
+ $stderr.puts "Unable to unlink #{pid_path}:\n\t(#{e.class}) #{e.message}"
86
+ exit
87
+ end
88
+
89
+ def kill_process
90
+ abort "#{APP_NAME} process is not running" unless process_exists?
91
+ $stdout.write "Attempting to stop #{APP_NAME} process #{pid}..."
92
+ Process.kill INT, pid
93
+ iteration_num = 0
94
+ while process_exists? && iteration_num < 10
95
+ sleep 1
96
+ $stdout.write "."
97
+ iteration_num += 1
98
+ end
99
+ if process_exists?
100
+ $stderr.puts "\nFailed to stop #{APP_NAME} process #{pid}"
101
+ else
102
+ $stdout.puts "\nSuccessfuly stopped #{APP_NAME} process #{pid}"
103
+ end
104
+ rescue Errno::EPERM
105
+ $stderr.puts "No permission to query #{pid}!";
106
+ end
107
+
108
+ def process_exists?
109
+ return false unless pid
110
+ Process.kill( 0, pid )
111
+ true
112
+ rescue Errno::ESRCH, TypeError # "PID is NOT running or is zombied
113
+ false
114
+ rescue Errno::EPERM
115
+ $stderr.puts "No permission to query #{pid}!";
116
+ false
117
+ end
118
+
119
+ def redirect_output!
120
+ if log_path = options[:log]
121
+ #puts "redirecting to log"
122
+ # if the log directory doesn't exist, create it
123
+ FileUtils.mkdir_p( File.dirname( log_path ), :mode => 0755 )
124
+ # touch the log file to create it
125
+ FileUtils.touch( log_path )
126
+ # Set permissions on the log file
127
+ File.chmod( 0644, log_path )
128
+ # Reopen $stdout (NOT +STDOUT+) to start writing to the log file
129
+ $stdout.reopen( log_path, 'a' )
130
+ # Redirect $stderr to $stdout
131
+ $stderr.reopen $stdout
132
+ $stdout.sync = true
133
+ else
134
+ #puts "redirecting to /dev/null"
135
+ # We're not bothering to sync if we're dumping to /dev/null
136
+ # because /dev/null doesn't care about buffered output
137
+ $stdin.reopen '/dev/null'
138
+ $stdout.reopen '/dev/null', 'a'
139
+ $stderr.reopen $stdout
140
+ end
141
+ log_path = options[:log] ? options[:log] : '/dev/null'
142
+ end
143
+
144
+ end
145
+ end
146
+ end
@@ -0,0 +1,81 @@
1
+ require 'yell'
2
+
3
+ # Provides logging services for the base server.
4
+ #
5
+ module Acception
6
+ module Subscriber
7
+ module ServerLogging
8
+
9
+ protected
10
+
11
+ def initialize_loggers
12
+ Acception::Subscriber.logger = Yell.new do |l|
13
+ l.level = log_level
14
+ l.adapter $stdout, :level => [:debug, :info, :warn]
15
+ l.adapter $stderr, :level => [:error, :fatal]
16
+ end
17
+
18
+ #Celluloid.logger = Yell.new do |l|
19
+ #l.level = :info
20
+ #l.adapter :file, File.join( File.dirname( options[:log] ), "#{APP_ID}-celluloid.log" )
21
+ #end
22
+ end
23
+
24
+ def log_startup
25
+ start_banner( options ).each do |line|
26
+ Acception::Subscriber.logger.info line
27
+ end
28
+ end
29
+
30
+ def start_banner( options )
31
+ [
32
+ "",
33
+ "***",
34
+ "* #{APP_NAME} started",
35
+ "*",
36
+ "* #{VERSION_COPYRIGHT}",
37
+ "*",
38
+ "* Configuration:",
39
+ (options[:config_loaded] ? "* file: #{options[:config]}" : nil),
40
+ Acception::Subscriber::Configuration.attributes.map { |a| "* #{a}: #{config_value( a )}" },
41
+ "*",
42
+ "***",
43
+ ].flatten.reject( &:nil? )
44
+ end
45
+
46
+ def log_level
47
+ options.fetch( :log_level, :info ).to_sym
48
+ end
49
+
50
+
51
+ def config_value( key )
52
+ value = Acception::Subscriber.configuration.send( key )
53
+
54
+ return value unless value.is_a?( Hash )
55
+
56
+ return redacted_hash( value )
57
+ end
58
+
59
+ def redacted_hash( hash )
60
+ redacted_hash = {}
61
+
62
+ hash.keys.
63
+ collect( &:to_s ).
64
+ grep( /#{redacted_keys}/i ).
65
+ each do |blacklisted_key|
66
+ value = hash[blacklisted_key]
67
+ redacted_hash[blacklisted_key] = value.nil? ? nil : '[REDACTED]'
68
+ end
69
+
70
+ hash.merge( redacted_hash )
71
+ end
72
+
73
+ def redacted_keys
74
+ %w(
75
+ password
76
+ ).join( '|' )
77
+ end
78
+
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,7 @@
1
+ module Acception
2
+ module Subscriber
3
+
4
+ VERSION = "1.0.0"
5
+
6
+ end
7
+ end
metadata ADDED
@@ -0,0 +1,192 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: acception-subscriber
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - C. Jason Harrelson
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-06-23 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.6'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.6'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: acception-client
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '1.2'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '1.2'
55
+ - !ruby/object:Gem::Dependency
56
+ name: bunny
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '1'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '1'
69
+ - !ruby/object:Gem::Dependency
70
+ name: celluloid
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: multi_json
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '1'
90
+ type: :runtime
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '1'
97
+ - !ruby/object:Gem::Dependency
98
+ name: oj
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '2'
104
+ type: :runtime
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '2'
111
+ - !ruby/object:Gem::Dependency
112
+ name: trollop
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: '2'
118
+ type: :runtime
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: '2'
125
+ - !ruby/object:Gem::Dependency
126
+ name: yell
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - "~>"
130
+ - !ruby/object:Gem::Version
131
+ version: '1'
132
+ type: :runtime
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - "~>"
137
+ - !ruby/object:Gem::Version
138
+ version: '1'
139
+ description: A RabbitMQ subscriber that pushes messages to Acception's API. See README
140
+ for more details.
141
+ email:
142
+ - cjharrelson@iberon.com
143
+ executables:
144
+ - acception-sub
145
+ extensions: []
146
+ extra_rdoc_files: []
147
+ files:
148
+ - ".gitignore"
149
+ - ".ruby-gemset"
150
+ - ".ruby-version"
151
+ - Gemfile
152
+ - LICENSE.txt
153
+ - README.md
154
+ - Rakefile
155
+ - acception-subscriber.gemspec
156
+ - bin/acception-sub
157
+ - lib/acception-subscriber.rb
158
+ - lib/acception/subscriber.rb
159
+ - lib/acception/subscriber/cli.rb
160
+ - lib/acception/subscriber/configuration.rb
161
+ - lib/acception/subscriber/logging.rb
162
+ - lib/acception/subscriber/message_handler.rb
163
+ - lib/acception/subscriber/publish_error.rb
164
+ - lib/acception/subscriber/server.rb
165
+ - lib/acception/subscriber/server_daemon.rb
166
+ - lib/acception/subscriber/server_logging.rb
167
+ - lib/acception/subscriber/version.rb
168
+ homepage: https://gitlab.staging.iberon.com/common/acception-subscriber
169
+ licenses:
170
+ - ''
171
+ metadata: {}
172
+ post_install_message:
173
+ rdoc_options: []
174
+ require_paths:
175
+ - lib
176
+ required_ruby_version: !ruby/object:Gem::Requirement
177
+ requirements:
178
+ - - ">="
179
+ - !ruby/object:Gem::Version
180
+ version: '0'
181
+ required_rubygems_version: !ruby/object:Gem::Requirement
182
+ requirements:
183
+ - - ">="
184
+ - !ruby/object:Gem::Version
185
+ version: '0'
186
+ requirements: []
187
+ rubyforge_project:
188
+ rubygems_version: 2.2.1
189
+ signing_key:
190
+ specification_version: 4
191
+ summary: A RabbitMQ subscriber that pushes messages to Acception's API.
192
+ test_files: []