unicorn-cuba-base 1.1.2 → 1.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +1 -0
- data/Gemfile.lock +2 -0
- data/VERSION +1 -1
- data/lib/unicorn-cuba-base/default_error_reporter.rb +7 -1
- data/lib/unicorn-cuba-base/rack/common_logger_xid.rb +15 -0
- data/lib/unicorn-cuba-base/rack/error_handling.rb +1 -3
- data/lib/unicorn-cuba-base/rack/xid_logging.rb +24 -0
- data/lib/unicorn-cuba-base/root_logger.rb +144 -31
- data/lib/unicorn-cuba-base/stats_reporter.rb +2 -2
- data/lib/unicorn-cuba-base/uri_ext.rb +20 -0
- data/lib/unicorn-cuba-base.rb +44 -23
- data/spec/root_logger_spec.rb +101 -7
- data/unicorn-cuba-base.gemspec +9 -3
- metadata +23 -4
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
1.
|
1
|
+
1.2.0
|
@@ -1,4 +1,6 @@
|
|
1
|
-
|
1
|
+
require 'pp'
|
2
|
+
|
3
|
+
class DefaultErrorReporter < Controller
|
2
4
|
self.define do
|
3
5
|
on error Rack::UnhandledRequest::UnhandledRequestError do |error|
|
4
6
|
write_error 404, error
|
@@ -9,6 +11,10 @@ class DefaultErrorReporter < Controler
|
|
9
11
|
raise error
|
10
12
|
end
|
11
13
|
|
14
|
+
on error URI::InvalidURIError do |error|
|
15
|
+
write_error 400, error
|
16
|
+
end
|
17
|
+
|
12
18
|
on error StandardError do |error|
|
13
19
|
log.error "unhandled error while processing request: #{env['REQUEST_METHOD']} #{env['SCRIPT_NAME']}[#{env["PATH_INFO"]}]", error
|
14
20
|
log.debug {
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Rack
|
2
|
+
class CommonLoggerXID < Rack::CommonLogger
|
3
|
+
def log(env, *args)
|
4
|
+
# this is called after body was sent so it won't be in scope of XIDLogging - setting xid again
|
5
|
+
xid = env['xid'] && env['xid'].first.last
|
6
|
+
if xid
|
7
|
+
@logger.with_meta_context(xid: xid) do
|
8
|
+
super(env, *args)
|
9
|
+
end
|
10
|
+
else
|
11
|
+
super(env, *args)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Rack
|
2
|
+
class XIDLogging
|
3
|
+
def initialize(app, root_logger, header_name = 'XID', &block)
|
4
|
+
@root_logger = root_logger
|
5
|
+
@header_name = header_name
|
6
|
+
@app = app
|
7
|
+
end
|
8
|
+
|
9
|
+
def call(env)
|
10
|
+
begin
|
11
|
+
xid = env["HTTP_#{@header_name.upcase.tr('-', '_')}"]
|
12
|
+
if xid
|
13
|
+
env['xid'] = {@header_name => xid}
|
14
|
+
@root_logger.with_meta_context(xid: xid) do
|
15
|
+
return @app.call(env)
|
16
|
+
end
|
17
|
+
else
|
18
|
+
return @app.call(env)
|
19
|
+
end
|
20
|
+
ensure
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -6,10 +6,7 @@ class RootLogger < Logger
|
|
6
6
|
|
7
7
|
def initialize(root_logger, class_obj)
|
8
8
|
@root_logger = root_logger
|
9
|
-
@
|
10
|
-
@root_logger.formatter = proc do |severity, datetime, progname, msg|
|
11
|
-
"[#{datetime.utc.strftime "%Y-%m-%d %H:%M:%S.%6N %Z"}] [#{$$} #{progname}] #{severity}: #{msg}\n"
|
12
|
-
end
|
9
|
+
@class_name = class_obj.name
|
13
10
|
end
|
14
11
|
|
15
12
|
def respond_to?(method)
|
@@ -18,22 +15,24 @@ class RootLogger < Logger
|
|
18
15
|
|
19
16
|
def method_missing(name, *args, &block)
|
20
17
|
if @@levels.include? name
|
21
|
-
|
22
|
-
|
18
|
+
root_logger = @root_logger.with_meta('className' => @class_name)
|
19
|
+
|
20
|
+
if block
|
21
|
+
root_logger.send(name, &block)
|
23
22
|
else
|
24
|
-
args.
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
end
|
31
|
-
end
|
23
|
+
message = args.first
|
24
|
+
|
25
|
+
if args.last.is_a? Exception
|
26
|
+
error = args.last
|
27
|
+
root_logger = root_logger.with_meta('exceptionClass' => error.class.name)
|
28
|
+
message = "#{message}: #{error.class.name}: #{error.message}\n#{error.backtrace.join("\n")}"
|
29
|
+
end
|
32
30
|
|
33
|
-
|
34
|
-
|
35
|
-
|
31
|
+
# log with class name
|
32
|
+
root_logger.send(name, message.chomp, &block)
|
33
|
+
end
|
36
34
|
else
|
35
|
+
# forward to root logger
|
37
36
|
@root_logger.send(name, *args, &block)
|
38
37
|
end
|
39
38
|
end
|
@@ -45,6 +44,50 @@ class RootLogger < Logger
|
|
45
44
|
end
|
46
45
|
end
|
47
46
|
|
47
|
+
class MetaData < Hash
|
48
|
+
def initialize(parent = nil)
|
49
|
+
@parent = parent
|
50
|
+
end
|
51
|
+
|
52
|
+
attr_accessor :parent
|
53
|
+
|
54
|
+
def to_s
|
55
|
+
chain = []
|
56
|
+
parent = self
|
57
|
+
while parent
|
58
|
+
chain << parent
|
59
|
+
parent = parent.parent
|
60
|
+
end
|
61
|
+
|
62
|
+
hash = {}
|
63
|
+
|
64
|
+
chain.reverse.each do |child|
|
65
|
+
hash.merge! child
|
66
|
+
end
|
67
|
+
|
68
|
+
"[meta #{hash.map{|k, v| "#{k}=\"#{v.to_s.tr('"', "'")}\""}.join(' ')}]"
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def initialize(logdev = STDERR, &formatter)
|
73
|
+
super(logdev)
|
74
|
+
|
75
|
+
@ext_formatter = proc do |severity, datetime, progname, meta, msg|
|
76
|
+
if formatter
|
77
|
+
formatter.call(severity, datetime, progname, meta, msg)
|
78
|
+
else
|
79
|
+
"#{datetime.utc.strftime "%Y-%m-%d %H:%M:%S.%6N %Z"} #{meta.to_s} #{severity}: #{msg}\n"
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
@meta = MetaData.new
|
84
|
+
@meta['pid'] = $$
|
85
|
+
|
86
|
+
self.formatter = proc do |severity, datetime, progname, msg|
|
87
|
+
@ext_formatter.call(severity, datetime, progname, @meta, msg)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
48
91
|
def logger_for(class_obj)
|
49
92
|
ClassLogger.new(self, class_obj)
|
50
93
|
end
|
@@ -53,11 +96,87 @@ class RootLogger < Logger
|
|
53
96
|
self
|
54
97
|
end
|
55
98
|
|
99
|
+
attr_accessor :meta
|
100
|
+
|
101
|
+
def with_meta(hash)
|
102
|
+
n = self.dup
|
103
|
+
n.meta = MetaData.new(@meta)
|
104
|
+
n.meta.merge! hash
|
105
|
+
|
106
|
+
# capture new meta hash with this new formatter proc - needed since old formatter proc will point to old object
|
107
|
+
n.formatter = proc do |severity, datetime, progname, msg|
|
108
|
+
@ext_formatter.call(severity, datetime, progname, n.meta, msg)
|
109
|
+
end
|
110
|
+
n
|
111
|
+
end
|
112
|
+
|
113
|
+
def with_meta_context(hash)
|
114
|
+
old_meta = @meta
|
115
|
+
new_meta = MetaData.new(old_meta)
|
116
|
+
new_meta.merge! hash
|
117
|
+
|
118
|
+
begin
|
119
|
+
@meta = new_meta
|
120
|
+
yield
|
121
|
+
ensure
|
122
|
+
@meta = old_meta
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
56
126
|
def inspect
|
57
127
|
"#<RootLogger #{"0x%X" % object_id}>"
|
58
128
|
end
|
59
129
|
end
|
60
130
|
|
131
|
+
class SyslogLogDev
|
132
|
+
def initialize(program_name, facility = 'daemon', log_to_stderr = false)
|
133
|
+
require 'syslog'
|
134
|
+
|
135
|
+
facility = "LOG_#{facility.upcase}".to_sym
|
136
|
+
Syslog.constants.include? facility or fail "No such syslog facility: #{facility}"
|
137
|
+
facility = Syslog.const_get facility
|
138
|
+
|
139
|
+
@log_level_mapping = Hash[%w{DEBUG INFO WARN ERROR FATAL}.zip(
|
140
|
+
[Syslog::LOG_DEBUG, Syslog::LOG_INFO, Syslog::LOG_WARNING, Syslog::LOG_ERR, Syslog::LOG_CRIT]
|
141
|
+
)]
|
142
|
+
@log_level_mapping.default = Syslog::LOG_NOTICE
|
143
|
+
|
144
|
+
flags = Syslog::LOG_PID | Syslog::LOG_NDELAY
|
145
|
+
|
146
|
+
if log_to_stderr
|
147
|
+
STDERR.sync = true
|
148
|
+
flags |= Syslog::LOG_PERROR
|
149
|
+
end
|
150
|
+
|
151
|
+
@syslog = Syslog.open(program_name, flags, facility)
|
152
|
+
end
|
153
|
+
|
154
|
+
def write(msg)
|
155
|
+
log_level, msg = *msg.match(/([^ ]+) (.*)/m).captures
|
156
|
+
@syslog.log(@log_level_mapping[log_level], "%s", msg.chomp)
|
157
|
+
end
|
158
|
+
|
159
|
+
def close
|
160
|
+
@syslog.close
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
class RootSyslogLogger < RootLogger
|
165
|
+
def initialize(program_name, facility = 'daemon', log_to_stderr = false)
|
166
|
+
super(SyslogLogDev.new(program_name, facility, log_to_stderr)) do |severity, datetime, progname, meta, msg|
|
167
|
+
# provide severity to SyslogLogDev
|
168
|
+
"#{severity} #{meta} #{msg}\n"
|
169
|
+
end
|
170
|
+
|
171
|
+
@meta.delete 'pid' # pid is already within syslog message header
|
172
|
+
end
|
173
|
+
|
174
|
+
# used when obj is used as log device (access logs)
|
175
|
+
def write(msg)
|
176
|
+
info(msg)
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
61
180
|
module ClassLogging
|
62
181
|
module ClassMethods
|
63
182
|
def init_logger
|
@@ -69,22 +188,16 @@ module ClassLogging
|
|
69
188
|
end
|
70
189
|
|
71
190
|
def log
|
72
|
-
unless @@logger
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
else
|
79
|
-
new_root_logger = true
|
80
|
-
Logger.new(STDERR)
|
191
|
+
unless @@logger.include? self
|
192
|
+
root_logger = if an = ancestors.find{|an| an != self and an.respond_to? :log and an.log.respond_to? :root_logger}
|
193
|
+
an.log.root_logger
|
194
|
+
else
|
195
|
+
RootLogger.new.tap do |logger|
|
196
|
+
logger.warn 'no root logger found; using default logger'
|
81
197
|
end
|
198
|
+
end
|
82
199
|
|
83
|
-
|
84
|
-
|
85
|
-
logger = RootLogger::ClassLogger.new(root_logger, self)
|
86
|
-
logger.warn "new default logger crated" if new_root_logger
|
87
|
-
@@logger[self] = logger
|
200
|
+
@@logger[self] = RootLogger::ClassLogger.new(root_logger, self)
|
88
201
|
end
|
89
202
|
@@logger[self]
|
90
203
|
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'uri'
|
2
|
+
|
3
|
+
module URI
|
4
|
+
class << self
|
5
|
+
alias_method :pct_decode, :decode
|
6
|
+
end
|
7
|
+
|
8
|
+
# From http://en.wikipedia.org/wiki/Percent-encoding:
|
9
|
+
# The generic URI syntax mandates that new URI schemes that provide for the representation of character data in a URI must, in effect, represent characters from the unreserved set without translation, and should convert all other characters to bytes according to UTF-8, and then percent-encode those values.
|
10
|
+
def self.utf_decode(str)
|
11
|
+
pct_decode(str).force_encoding('UTF-8').tap do |u|
|
12
|
+
raise URI::InvalidURIError, "invalid UTF-8 encoding in URI: #{u.inspect}" if not u.valid_encoding?
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
# Use it by default
|
17
|
+
def self.decode(str)
|
18
|
+
self.utf_decode(str)
|
19
|
+
end
|
20
|
+
end
|
data/lib/unicorn-cuba-base.rb
CHANGED
@@ -6,6 +6,7 @@ require 'facter'
|
|
6
6
|
require 'pathname'
|
7
7
|
require 'ip'
|
8
8
|
|
9
|
+
require_relative 'unicorn-cuba-base/uri_ext'
|
9
10
|
require_relative 'unicorn-cuba-base/stats'
|
10
11
|
require_relative 'unicorn-cuba-base/root_logger'
|
11
12
|
require_relative 'unicorn-cuba-base/plugin/error_matcher'
|
@@ -15,8 +16,10 @@ require_relative 'unicorn-cuba-base/plugin/memory_limit'
|
|
15
16
|
require_relative 'unicorn-cuba-base/rack/error_handling'
|
16
17
|
require_relative 'unicorn-cuba-base/rack/unhandled_request'
|
17
18
|
require_relative 'unicorn-cuba-base/rack/memory_limit'
|
19
|
+
require_relative 'unicorn-cuba-base/rack/xid_logging'
|
20
|
+
require_relative 'unicorn-cuba-base/rack/common_logger_xid'
|
18
21
|
|
19
|
-
class
|
22
|
+
class Controller < Cuba
|
20
23
|
include ClassLogging
|
21
24
|
end
|
22
25
|
|
@@ -46,12 +49,19 @@ class Application
|
|
46
49
|
@cli = setup_cli(program_name, defaults, @cli_setup) or fail 'no cli defined'
|
47
50
|
@settings = @settings_setup ? setup_settings(@settings_setup) : @cli.parse!
|
48
51
|
|
49
|
-
root_logger =
|
52
|
+
root_logger = if @settings.syslog_facility
|
53
|
+
# open /dev/null as log file if we are using syslog and we are not in foreground
|
54
|
+
@settings.log_file = Pathname.new '/dev/null' unless @settings.foreground
|
55
|
+
RootSyslogLogger.new(program_name, @settings.syslog_facility, @settings.foreground)
|
56
|
+
else
|
57
|
+
RootLogger.new
|
58
|
+
end
|
59
|
+
|
50
60
|
root_logger.level = RootLogger::WARN
|
51
61
|
root_logger.level = RootLogger::INFO if @settings.verbose
|
52
62
|
root_logger.level = RootLogger::DEBUG if @settings.debug
|
53
|
-
|
54
|
-
MemoryLimit.logger =
|
63
|
+
Controller.logger = root_logger
|
64
|
+
MemoryLimit.logger = Controller.logger_for(MemoryLimit)
|
55
65
|
|
56
66
|
unicorn_settings = {}
|
57
67
|
unicorn_settings[:logger] = root_logger.logger_for(Unicorn::HttpServer)
|
@@ -67,7 +77,7 @@ class Application
|
|
67
77
|
unicorn_settings[:stderr_path] = @settings.log_file.to_s
|
68
78
|
unicorn_settings[:stdout_path] = @settings.log_file.to_s
|
69
79
|
|
70
|
-
Unicorn::Launcher.daemonize!(unicorn_settings)
|
80
|
+
Unicorn::Launcher.daemonize!(unicorn_settings)
|
71
81
|
|
72
82
|
# capture startup messages
|
73
83
|
@settings.log_file.open('ab') do |log|
|
@@ -77,25 +87,30 @@ class Application
|
|
77
87
|
end
|
78
88
|
end
|
79
89
|
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
@main_setup or fail 'no main
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
90
|
+
Controller.settings[:listeners] = @settings.listener
|
91
|
+
#Controller.settings[:access_log_file] = @settings.access_log_file
|
92
|
+
|
93
|
+
Controller.plugin Plugin::ErrorMatcher
|
94
|
+
Controller.plugin Plugin::Logging
|
95
|
+
Controller.plugin Plugin::ResponseHelpers
|
96
|
+
Controller.plugin Plugin::MemoryLimit
|
97
|
+
|
98
|
+
@main_setup or fail 'no main controller provided'
|
99
|
+
main_controller = setup_main(@main_setup) or fail 'no main controller class returned'
|
100
|
+
|
101
|
+
main_controller.use Rack::ErrorHandling
|
102
|
+
main_controller.use Rack::XIDLogging, root_logger, @settings.xid_header if @settings.xid_header
|
103
|
+
if @settings.syslog_facility
|
104
|
+
main_controller.use Rack::CommonLoggerXID, root_logger.with_meta(type: 'http-access')
|
105
|
+
else
|
106
|
+
access_log_file = @settings.access_log_file.open('a+')
|
107
|
+
access_log_file.sync = true
|
108
|
+
main_controller.use Rack::CommonLogger, access_log_file
|
109
|
+
end
|
110
|
+
main_controller.use Rack::MemoryLimit, @settings.limit_memory * 1024 ** 2
|
111
|
+
main_controller.use Rack::UnhandledRequest
|
97
112
|
|
98
|
-
Unicorn::HttpServer.new(
|
113
|
+
Unicorn::HttpServer.new(main_controller, unicorn_settings).start.join
|
99
114
|
end
|
100
115
|
|
101
116
|
private
|
@@ -108,11 +123,17 @@ class Application
|
|
108
123
|
cast: Pathname,
|
109
124
|
description: 'log file location',
|
110
125
|
default: "#{program_name}.log"
|
126
|
+
option :syslog_facility,
|
127
|
+
short: :s,
|
128
|
+
description: 'when set logs will be sent to syslog instead of log files; one of: auth, authpriv, cron, daemon, ftp, kern, lpr, mail, news, syslog, user, uucp, local0, local1, local2, local3, local4, local5, local6, local7'
|
111
129
|
option :access_log_file,
|
112
130
|
short: :a,
|
113
131
|
cast: Pathname,
|
114
132
|
description: 'NCSA access log file location',
|
115
133
|
default: "#{program_name}_access.log"
|
134
|
+
option :xid_header,
|
135
|
+
short: :x,
|
136
|
+
description: 'log value of named request header with request context'
|
116
137
|
option :pid_file,
|
117
138
|
short: :p,
|
118
139
|
cast: Pathname,
|
data/spec/root_logger_spec.rb
CHANGED
@@ -3,7 +3,7 @@ require_relative 'spec_helper'
|
|
3
3
|
require 'unicorn-cuba-base/root_logger'
|
4
4
|
require 'stringio'
|
5
5
|
|
6
|
-
describe
|
6
|
+
describe RootLogger do
|
7
7
|
let! :log_out do
|
8
8
|
StringIO.new
|
9
9
|
end
|
@@ -44,15 +44,109 @@ describe do
|
|
44
44
|
subject.logger_for(String).info 'hello world'
|
45
45
|
log_out.string.should include 'String'
|
46
46
|
end
|
47
|
+
end
|
48
|
+
|
49
|
+
it 'should log exceptions' do
|
50
|
+
begin
|
51
|
+
raise RuntimeError, 'bad luck'
|
52
|
+
rescue => error
|
53
|
+
subject.logger_for(String).error 'hello world', error
|
54
|
+
end
|
55
|
+
log_out.string.should include 'hello world: RuntimeError: bad luck'
|
56
|
+
end
|
57
|
+
|
58
|
+
describe 'meta data' do
|
59
|
+
it 'should log with metadata in RFC5424 format' do
|
60
|
+
subject.with_meta(type: 'access-log').info 'GET /asdfas'
|
61
|
+
log_out.string.should include 'type="access-log"'
|
47
62
|
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
63
|
+
subject.info 'GET /asdfas'
|
64
|
+
log_out.string.lines.to_a.last.should_not include 'type="access-log"'
|
65
|
+
end
|
66
|
+
|
67
|
+
it 'should work with chaining' do
|
68
|
+
subject.with_meta(type: 'access-log').with_meta(blah: 'xxx').info 'GET /asdfas'
|
69
|
+
log_out.string.should include 'type="access-log" blah="xxx"'
|
70
|
+
end
|
71
|
+
|
72
|
+
it 'should log with metadata context' do
|
73
|
+
subject.with_meta_context(type: 'app-log') do
|
74
|
+
subject.info 'GET /asdfas'
|
53
75
|
end
|
54
|
-
log_out.string.should include '
|
76
|
+
log_out.string.should include 'type="app-log"'
|
77
|
+
|
78
|
+
subject.info 'GET /asdfas'
|
79
|
+
log_out.string.lines.to_a.last.should_not include 'type="app-log"'
|
55
80
|
end
|
56
81
|
end
|
57
82
|
end
|
58
83
|
|
84
|
+
require 'capture-output'
|
85
|
+
|
86
|
+
describe SyslogLogDev do
|
87
|
+
subject do
|
88
|
+
SyslogLogDev.new('unicorn-cuba-base-test', 'daemon', true)
|
89
|
+
end
|
90
|
+
|
91
|
+
after :each do
|
92
|
+
subject.close
|
93
|
+
end
|
94
|
+
|
95
|
+
it 'should write messages to syslog expecting first word to be log level' do
|
96
|
+
Capture.stderr{subject.write 'INFO hello world'}.should include '<Info>'
|
97
|
+
Capture.stderr{subject.write 'WARN hello world'}.should include '<Warning>'
|
98
|
+
Capture.stderr{subject.write 'INFO hello world'}.should include 'hello world'
|
99
|
+
end
|
100
|
+
|
101
|
+
it 'should handle multiline log entries' do
|
102
|
+
Capture.stderr{subject.write "INFO hello\nworld"}.should include "<Info>: hello\n\tworld\n"
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
describe RootSyslogLogger do
|
107
|
+
subject do
|
108
|
+
@subject ||= RootSyslogLogger.new('unicorn-cuba-base-test', 'daemon', true).logger_for(RSpec)
|
109
|
+
end
|
110
|
+
|
111
|
+
after :each do
|
112
|
+
subject.close
|
113
|
+
end
|
114
|
+
|
115
|
+
it 'should log to syslog' do
|
116
|
+
log_out = Capture.stderr{subject.info 'hello world'}
|
117
|
+
|
118
|
+
log_out.should include 'unicorn-cuba-base-test'
|
119
|
+
log_out.should match /\[[0-9]+\]/
|
120
|
+
log_out.should include '<Info>:'
|
121
|
+
end
|
122
|
+
|
123
|
+
it 'should include message' do
|
124
|
+
Capture.stderr{subject.info 'hello world'}.should include 'hello world'
|
125
|
+
end
|
126
|
+
|
127
|
+
it 'should include class name' do
|
128
|
+
Capture.stderr{subject.info 'hello world'}.should include 'RSpec'
|
129
|
+
end
|
130
|
+
|
131
|
+
it 'should map log levels to syslog severities' do
|
132
|
+
Capture.stderr{subject.debug 'hello world'}.should include '<Debug>'
|
133
|
+
Capture.stderr{subject.info 'hello world'}.should include '<Info>'
|
134
|
+
Capture.stderr{subject.warn 'hello world'}.should include '<Warning>'
|
135
|
+
Capture.stderr{subject.error 'hello world'}.should include '<Error>'
|
136
|
+
Capture.stderr{subject.fatal 'hello world'}.should include '<Critical>'
|
137
|
+
end
|
138
|
+
|
139
|
+
it 'should handle multiline logs by appending tab after new line (done by syslog?)' do
|
140
|
+
Capture.stderr{subject.info "hello\nworld\ntest"}.should include "hello\n\tworld\n\ttest\n"
|
141
|
+
end
|
142
|
+
|
143
|
+
describe 'direct wirtes' do
|
144
|
+
it 'should use Info level' do
|
145
|
+
Capture.stderr{subject.write "hello world"}.should include '<Info>'
|
146
|
+
end
|
147
|
+
|
148
|
+
it 'should allow use of meta data' do
|
149
|
+
Capture.stderr{subject.with_meta('type' => 'access-log').write "hello world"}.should include 'type="access-log"'
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
data/unicorn-cuba-base.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = "unicorn-cuba-base"
|
8
|
-
s.version = "1.
|
8
|
+
s.version = "1.2.0"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Jakub Pastuszek"]
|
12
|
-
s.date = "
|
12
|
+
s.date = "2014-07-28"
|
13
13
|
s.description = "web application base powered by Unicorn HTTP server and based on Cuba framework extended with additional Rack middleware and Cuba plugins"
|
14
14
|
s.email = "jpastuszek@gmail.com"
|
15
15
|
s.extra_rdoc_files = [
|
@@ -32,12 +32,15 @@ Gem::Specification.new do |s|
|
|
32
32
|
"lib/unicorn-cuba-base/plugin/logging.rb",
|
33
33
|
"lib/unicorn-cuba-base/plugin/memory_limit.rb",
|
34
34
|
"lib/unicorn-cuba-base/plugin/response_helpers.rb",
|
35
|
+
"lib/unicorn-cuba-base/rack/common_logger_xid.rb",
|
35
36
|
"lib/unicorn-cuba-base/rack/error_handling.rb",
|
36
37
|
"lib/unicorn-cuba-base/rack/memory_limit.rb",
|
37
38
|
"lib/unicorn-cuba-base/rack/unhandled_request.rb",
|
39
|
+
"lib/unicorn-cuba-base/rack/xid_logging.rb",
|
38
40
|
"lib/unicorn-cuba-base/root_logger.rb",
|
39
41
|
"lib/unicorn-cuba-base/stats.rb",
|
40
42
|
"lib/unicorn-cuba-base/stats_reporter.rb",
|
43
|
+
"lib/unicorn-cuba-base/uri_ext.rb",
|
41
44
|
"spec/memory_limit_spec.rb",
|
42
45
|
"spec/root_logger_spec.rb",
|
43
46
|
"spec/spec_helper.rb",
|
@@ -46,7 +49,7 @@ Gem::Specification.new do |s|
|
|
46
49
|
s.homepage = "http://github.com/jpastuszek/unicorn-cuba-base"
|
47
50
|
s.licenses = ["MIT"]
|
48
51
|
s.require_paths = ["lib"]
|
49
|
-
s.rubygems_version = "1.8.
|
52
|
+
s.rubygems_version = "1.8.23"
|
50
53
|
s.summary = "web appliaction base powered by Unicorn and Cuba"
|
51
54
|
|
52
55
|
if s.respond_to? :specification_version then
|
@@ -62,6 +65,7 @@ Gem::Specification.new do |s|
|
|
62
65
|
s.add_development_dependency(%q<rspec>, ["~> 2.13"])
|
63
66
|
s.add_development_dependency(%q<rdoc>, ["~> 3.9"])
|
64
67
|
s.add_development_dependency(%q<jeweler>, ["~> 1.8.4"])
|
68
|
+
s.add_development_dependency(%q<capture-output>, ["~> 1.0"])
|
65
69
|
else
|
66
70
|
s.add_dependency(%q<cuba>, ["~> 3.0"])
|
67
71
|
s.add_dependency(%q<unicorn>, [">= 4.6.2"])
|
@@ -72,6 +76,7 @@ Gem::Specification.new do |s|
|
|
72
76
|
s.add_dependency(%q<rspec>, ["~> 2.13"])
|
73
77
|
s.add_dependency(%q<rdoc>, ["~> 3.9"])
|
74
78
|
s.add_dependency(%q<jeweler>, ["~> 1.8.4"])
|
79
|
+
s.add_dependency(%q<capture-output>, ["~> 1.0"])
|
75
80
|
end
|
76
81
|
else
|
77
82
|
s.add_dependency(%q<cuba>, ["~> 3.0"])
|
@@ -83,6 +88,7 @@ Gem::Specification.new do |s|
|
|
83
88
|
s.add_dependency(%q<rspec>, ["~> 2.13"])
|
84
89
|
s.add_dependency(%q<rdoc>, ["~> 3.9"])
|
85
90
|
s.add_dependency(%q<jeweler>, ["~> 1.8.4"])
|
91
|
+
s.add_dependency(%q<capture-output>, ["~> 1.0"])
|
86
92
|
end
|
87
93
|
end
|
88
94
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: unicorn-cuba-base
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.2.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2014-07-28 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: cuba
|
@@ -155,6 +155,22 @@ dependencies:
|
|
155
155
|
- - ~>
|
156
156
|
- !ruby/object:Gem::Version
|
157
157
|
version: 1.8.4
|
158
|
+
- !ruby/object:Gem::Dependency
|
159
|
+
name: capture-output
|
160
|
+
requirement: !ruby/object:Gem::Requirement
|
161
|
+
none: false
|
162
|
+
requirements:
|
163
|
+
- - ~>
|
164
|
+
- !ruby/object:Gem::Version
|
165
|
+
version: '1.0'
|
166
|
+
type: :development
|
167
|
+
prerelease: false
|
168
|
+
version_requirements: !ruby/object:Gem::Requirement
|
169
|
+
none: false
|
170
|
+
requirements:
|
171
|
+
- - ~>
|
172
|
+
- !ruby/object:Gem::Version
|
173
|
+
version: '1.0'
|
158
174
|
description: web application base powered by Unicorn HTTP server and based on Cuba
|
159
175
|
framework extended with additional Rack middleware and Cuba plugins
|
160
176
|
email: jpastuszek@gmail.com
|
@@ -179,12 +195,15 @@ files:
|
|
179
195
|
- lib/unicorn-cuba-base/plugin/logging.rb
|
180
196
|
- lib/unicorn-cuba-base/plugin/memory_limit.rb
|
181
197
|
- lib/unicorn-cuba-base/plugin/response_helpers.rb
|
198
|
+
- lib/unicorn-cuba-base/rack/common_logger_xid.rb
|
182
199
|
- lib/unicorn-cuba-base/rack/error_handling.rb
|
183
200
|
- lib/unicorn-cuba-base/rack/memory_limit.rb
|
184
201
|
- lib/unicorn-cuba-base/rack/unhandled_request.rb
|
202
|
+
- lib/unicorn-cuba-base/rack/xid_logging.rb
|
185
203
|
- lib/unicorn-cuba-base/root_logger.rb
|
186
204
|
- lib/unicorn-cuba-base/stats.rb
|
187
205
|
- lib/unicorn-cuba-base/stats_reporter.rb
|
206
|
+
- lib/unicorn-cuba-base/uri_ext.rb
|
188
207
|
- spec/memory_limit_spec.rb
|
189
208
|
- spec/root_logger_spec.rb
|
190
209
|
- spec/spec_helper.rb
|
@@ -204,7 +223,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
204
223
|
version: '0'
|
205
224
|
segments:
|
206
225
|
- 0
|
207
|
-
hash:
|
226
|
+
hash: 668318932229336882
|
208
227
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
209
228
|
none: false
|
210
229
|
requirements:
|
@@ -213,7 +232,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
213
232
|
version: '0'
|
214
233
|
requirements: []
|
215
234
|
rubyforge_project:
|
216
|
-
rubygems_version: 1.8.
|
235
|
+
rubygems_version: 1.8.23
|
217
236
|
signing_key:
|
218
237
|
specification_version: 3
|
219
238
|
summary: web appliaction base powered by Unicorn and Cuba
|