scrolls 0.3.9 → 0.9.3

Sign up to get free protection for your applications and to get access to all the features.
data/lib/scrolls.rb CHANGED
@@ -1,6 +1,4 @@
1
- require "thread"
2
- require "scrolls/atomic"
3
- require "scrolls/log"
1
+ require "scrolls/logger"
4
2
  require "scrolls/version"
5
3
 
6
4
  module Scrolls
@@ -8,33 +6,27 @@ module Scrolls
8
6
 
9
7
  # Public: Initialize a Scrolls logger
10
8
  #
11
- # Convienence method to prepare for future releases. Currently mimics
12
- # behavior found in other methods. This prepares the developer for a future
13
- # backward incompatible change, see:
14
- # https://github.com/asenchi/scrolls/pull/54
15
- #
16
9
  # options - A hash of key/values for configuring Scrolls
17
- #
18
- def init(options)
19
- stream = options.fetch(:stream, STDOUT)
20
- facility = options.fetch(:facility, Syslog::LOG_USER)
21
- time_unit = options.fetch(:time_unit, "seconds")
22
- timestamp = options.fetch(:timestamp, false)
23
- exceptions = options.fetch(:exceptions, "multi")
24
- global_ctx = options.fetch(:global_context, {})
25
-
26
- Log.stream = stream
27
- Log.facility = facility if facility
28
- Log.time_unit = time_unit unless time_unit == "seconds"
29
- Log.add_timestamp = timestamp unless timestamp == false
30
-
31
- if exceptions == "single"
32
- Log.single_line_exceptions = true
33
- end
10
+ # stream - Stream to output data (default: STDOUT)
11
+ # log_facility - Syslog facility (default: Syslog::LOG_USER)
12
+ # time_unit - Unit of time (default: seconds)
13
+ # timestamp - Prepend logs with a timestamp (default: false)
14
+ # exceptions - Method for outputting exceptions (default: single line)
15
+ # global_context - Immutable context to prepend all messages with
16
+ # syslog_options - Syslog options (default: Syslog::LOG_PID|Syslog::LOG_CONS)
17
+ # escape_keys - Escape chars in keys
18
+ # strict_logfmt - Always use double quotes to quote values
19
+ #
20
+ def init(options={})
21
+ # Set a hint whether #init was called.
22
+ @initialized = true
23
+ @log = Logger.new(options)
24
+ end
34
25
 
35
- unless global_ctx == {}
36
- Log.global_context = global_ctx
37
- end
26
+ # Public: Get the primary logger
27
+ #
28
+ def logger
29
+ @log.logger
38
30
  end
39
31
 
40
32
  # Public: Set a context in a block for logs
@@ -45,37 +37,13 @@ module Scrolls
45
37
  # Examples:
46
38
  #
47
39
  def context(data, &blk)
48
- Log.with_context(data, &blk)
49
- end
50
-
51
- # Deprecated: Get or set a global context that prefixs all logs
52
- #
53
- # data - A hash of key/values to prepend to each log
54
- #
55
- # This method will be deprecated two releases after 0.3.8.
56
- # See https://github.com/asenchi/scrolls/releases/tag/v0.3.8
57
- # for more details.
58
- #
59
- def global_context(data=nil)
60
- $stderr.puts "global_context() will be deprecated after v0.3.8, please see https://github.com/asenchi/scrolls for more information."
61
- if data
62
- Log.global_context = data
63
- else
64
- Log.global_context
65
- end
40
+ @log.with_context(data, &blk)
66
41
  end
67
42
 
68
- # Deprecated: Get or set a global context that prefixs all logs
69
- #
70
- # data - A hash of key/values to prepend to each log
71
- #
72
- # This method will be deprecated two releases after 0.3.8.
73
- # See https://github.com/asenchi/scrolls/releases/tag/v0.3.8
74
- # for more details.
43
+ # Public: Get the global context that prefixs all logs
75
44
  #
76
- def add_global_context(data)
77
- $stderr.puts "add_global_context will be deprecated after v0.3.8, please see https://github.com/asenchi/scrolls for more information."
78
- Log.add_global_context(data)
45
+ def global_context
46
+ @log.global_context
79
47
  end
80
48
 
81
49
  # Public: Log data and/or wrap a block with start/finish
@@ -96,26 +64,32 @@ module Scrolls
96
64
  # => nil
97
65
  #
98
66
  def log(data, &blk)
99
- Log.log(data, &blk)
67
+ # Allows us to call #log directly and initialize defaults
68
+ @log = Logger.new({}) unless @initialized
69
+
70
+ @log.log(data, &blk)
100
71
  end
101
72
 
102
73
  # Public: Log an exception
103
74
  #
104
- # data - A hash of key/values to log
105
75
  # e - An exception to pass to the logger
76
+ # data - A hash of key/values to log
106
77
  #
107
78
  # Examples:
108
79
  #
109
80
  # begin
110
81
  # raise Exception
111
82
  # rescue Exception => e
112
- # Scrolls.log_exception({test: "test"}, e)
83
+ # Scrolls.log_exception(e, {test: "test"})
113
84
  # end
114
85
  # test=test at=exception class=Exception message=Exception exception_id=70321999017240
115
86
  # ...
116
87
  #
117
- def log_exception(data, e)
118
- Log.log_exception(data, e)
88
+ def log_exception(e, data)
89
+ # Allows us to call #log directly and initialize defaults
90
+ @log = Logger.new({}) unless @initialized
91
+
92
+ @log.log_exception(e, data)
119
93
  end
120
94
 
121
95
  # Public: Setup a logging facility (default: Syslog::LOG_USER)
@@ -127,7 +101,7 @@ module Scrolls
127
101
  # Scrolls.facility = Syslog::LOG_LOCAL7
128
102
  #
129
103
  def facility=(f)
130
- Log.facility=(f)
104
+ @log.facility=(f)
131
105
  end
132
106
 
133
107
  # Public: Return the Syslog facility
@@ -138,7 +112,7 @@ module Scrolls
138
112
  # => 8
139
113
  #
140
114
  def facility
141
- Log.facility
115
+ @log.facility
142
116
  end
143
117
 
144
118
  # Public: Setup a new output (default: STDOUT)
@@ -154,7 +128,7 @@ module Scrolls
154
128
  # Scrolls.stream = StringIO.new
155
129
  #
156
130
  def stream=(out)
157
- Log.stream=(out)
131
+ @log.stream=(out)
158
132
  end
159
133
 
160
134
  # Public: Return the stream
@@ -165,7 +139,7 @@ module Scrolls
165
139
  # => #<IO:<STDOUT>>
166
140
  #
167
141
  def stream
168
- Log.stream
142
+ @log.stream
169
143
  end
170
144
 
171
145
  # Public: Set the time unit we use for 'elapsed' (default: "seconds")
@@ -177,7 +151,7 @@ module Scrolls
177
151
  # Scrolls.time_unit = "milliseconds"
178
152
  #
179
153
  def time_unit=(unit)
180
- Log.time_unit=(unit)
154
+ @log.time_unit = unit
181
155
  end
182
156
 
183
157
  # Public: Return the time unit currently configured
@@ -188,7 +162,7 @@ module Scrolls
188
162
  # => "seconds"
189
163
  #
190
164
  def time_unit
191
- Log.time_unit
165
+ @log.time_unit
192
166
  end
193
167
 
194
168
  # Public: Set whether to include a timestamp (now=<ISO8601>) field in the log
@@ -199,7 +173,7 @@ module Scrolls
199
173
  # Scrolls.add_timestamp = true
200
174
  #
201
175
  def add_timestamp=(boolean)
202
- Log.add_timestamp = boolean
176
+ @log.timestamp = boolean
203
177
  end
204
178
 
205
179
  # Public: Return whether the timestamp field will be included in the log
@@ -211,7 +185,7 @@ module Scrolls
211
185
  # => true
212
186
  #
213
187
  def add_timestamp
214
- Log.add_timestamp
188
+ @log.timestamp
215
189
  end
216
190
 
217
191
  # Public: Set whether exceptions should generate a single log
@@ -222,7 +196,7 @@ module Scrolls
222
196
  # Scrolls.single_line_exceptions = true
223
197
  #
224
198
  def single_line_exceptions=(boolean)
225
- Log.single_line_exceptions = boolean
199
+ @log.exceptions = boolean
226
200
  end
227
201
 
228
202
  # Public: Return whether exceptions generate a single log message.
@@ -233,7 +207,7 @@ module Scrolls
233
207
  # => true
234
208
  #
235
209
  def single_line_exceptions?
236
- Log.single_line_exceptions
210
+ @log.single_line_exceptions?
237
211
  end
238
212
 
239
213
  # Public: Convience method for Logger replacement
@@ -249,7 +223,7 @@ module Scrolls
249
223
  #
250
224
  def debug(data, &blk)
251
225
  data = data.merge(:level => "debug") if data.is_a?(Hash)
252
- Log.log(data, &blk)
226
+ @log.log(data, &blk)
253
227
  end
254
228
 
255
229
  # Public: Convience method for Logger replacement
@@ -267,7 +241,7 @@ module Scrolls
267
241
  #
268
242
  def error(data, &blk)
269
243
  data = data.merge(:level => "warning") if data.is_a?(Hash)
270
- Log.log(data, &blk)
244
+ @log.log(data, &blk)
271
245
  end
272
246
 
273
247
  # Public: Convience method for Logger replacement
@@ -285,7 +259,7 @@ module Scrolls
285
259
  #
286
260
  def fatal(data, &blk)
287
261
  data = data.merge(:level => "error") if data.is_a?(Hash)
288
- Log.log(data, &blk)
262
+ @log.log(data, &blk)
289
263
  end
290
264
 
291
265
  # Public: Convience method for Logger replacement
@@ -303,7 +277,7 @@ module Scrolls
303
277
  #
304
278
  def info(data, &blk)
305
279
  data = data.merge(:level => "info") if data.is_a?(Hash)
306
- Log.log(data, &blk)
280
+ @log.log(data, &blk)
307
281
  end
308
282
 
309
283
  # Public: Convience method for Logger replacement
@@ -321,7 +295,7 @@ module Scrolls
321
295
  #
322
296
  def warn(data, &blk)
323
297
  data = data.merge(:level => "notice") if data.is_a?(Hash)
324
- Log.log(data, &blk)
298
+ @log.log(data, &blk)
325
299
  end
326
300
 
327
301
  # Public: Convience method for Logger replacement
@@ -339,7 +313,13 @@ module Scrolls
339
313
  #
340
314
  def unknown(data, &blk)
341
315
  data = data.merge(:level => "alert") if data.is_a?(Hash)
342
- Log.log(data, &blk)
316
+ @log.log(data, &blk)
317
+ end
318
+
319
+ # Internal: The Logger initialized by #init
320
+ #
321
+ def internal
322
+ @log
343
323
  end
344
324
 
345
325
  end
data/test/test_helper.rb CHANGED
@@ -1,6 +1,9 @@
1
- require "test/unit"
1
+ require "minitest/autorun"
2
+ require "minitest/reporters"
2
3
  require "stringio"
3
4
 
5
+ Minitest::Reporters.use! Minitest::Reporters::SpecReporter.new
6
+
4
7
  $: << File.expand_path("../../lib", __FILE__)
5
8
 
6
9
  require "scrolls"
data/test/test_parser.rb CHANGED
@@ -1,6 +1,6 @@
1
- require_relative "test_helper"
1
+ require File.expand_path("../test_helper", __FILE__)
2
2
 
3
- class TestScrollsParser < Test::Unit::TestCase
3
+ class TestScrollsParser < Minitest::Test
4
4
  include Scrolls::Parser
5
5
 
6
6
  def test_parse_bool
@@ -79,6 +79,21 @@ class TestScrollsParser < Test::Unit::TestCase
79
79
  assert_equal 't="2012-06-19T16:02:35+01:00"', unparse(data)
80
80
  end
81
81
 
82
+ def test_unparse_escape_keys
83
+ html = "<p>p</p>"
84
+ slash = "p/p"
85
+
86
+ data = { html => "d", slash => "d" }
87
+ assert_equal '&lt;p&gt;p&lt;&#x2F;p&gt;=d p&#x2F;p=d',
88
+ unparse(data, escape_keys=true)
89
+ end
90
+
91
+ def test_unparse_strict_logfmt
92
+ data = { s: 'echo "hello"' }
93
+ assert_equal 's="echo \"hello\""', unparse(data, escape_keys=false, strict_logfmt=true)
94
+ assert_equal data.inspect, parse(unparse(data, escape_keys=false, strict_logfmt=true)).inspect
95
+ end
96
+
82
97
  def test_parse_time
83
98
  time = Time.new(2012, 06, 19, 16, 02, 35, "+01:00")
84
99
  string = "t=2012-06-19T16:02:35+01:00"
data/test/test_scrolls.rb CHANGED
@@ -1,44 +1,35 @@
1
- require_relative "test_helper"
1
+ require File.expand_path("../test_helper", __FILE__)
2
2
 
3
- class TestScrolls < Test::Unit::TestCase
3
+ class TestScrolls < Minitest::Test
4
4
  def setup
5
5
  @out = StringIO.new
6
- Scrolls.init(:stream => @out)
7
- end
8
-
9
- def teardown
10
- Scrolls.global_context({})
11
- # Reset our syslog context
12
- Scrolls.facility = Scrolls::LOG_FACILITY
13
- Scrolls.add_timestamp = false
6
+ Scrolls.init(
7
+ :stream => @out
8
+ )
14
9
  end
15
10
 
16
- def test_construct
17
- assert_equal Scrolls::IOLog, Scrolls.stream.class
11
+ def test_default_construct
12
+ Scrolls.init
13
+ assert_equal Scrolls::IOLogger, Scrolls.logger.class
18
14
  end
19
15
 
20
16
  def test_default_global_context
17
+ Scrolls.init(:stream => @out)
21
18
  assert_equal Hash.new, Scrolls.global_context
22
19
  end
23
20
 
24
21
  def test_setting_global_context
25
- Scrolls.global_context(:g => "g")
26
- Scrolls.log(:d => "d")
27
- global = @out.string.gsub("\n", 'XX')
28
- assert_match /g=g.*d=d/, global
29
- end
30
-
31
- def test_adding_to_global_context
32
- Scrolls.global_context(:g => "g")
33
- Scrolls.add_global_context(:h => "h")
22
+ Scrolls.init(
23
+ :stream => @out,
24
+ :global_context => {:g => "g"},
25
+ )
34
26
  Scrolls.log(:d => "d")
35
- global = @out.string.gsub("\n", 'XX')
36
- assert_match /g=g.*h=h.*d=d/, global
27
+ assert_equal "g=g d=d\n", @out.string
37
28
  end
38
29
 
39
30
  def test_default_context
40
- Scrolls.log(:data => "d")
41
- assert_equal Hash.new, Scrolls::Log.context
31
+ Scrolls.log(:d => "d")
32
+ assert_equal Hash.new, Scrolls.internal.context
42
33
  end
43
34
 
44
35
  def test_setting_context
@@ -48,15 +39,19 @@ class TestScrolls < Test::Unit::TestCase
48
39
  end
49
40
 
50
41
  def test_all_the_contexts
51
- Scrolls.global_context(:g => "g")
42
+ Scrolls.init(
43
+ :stream => @out,
44
+ :global_context => {:g => "g"},
45
+ )
52
46
  Scrolls.log(:o => "o") do
53
47
  Scrolls.context(:c => "c") do
54
48
  Scrolls.log(:ic => "i")
55
49
  end
56
50
  Scrolls.log(:i => "i")
57
51
  end
58
- global = @out.string.gsub("\n", 'XX')
59
- assert_match /g=g.*at=start.*i=i/, global
52
+ @out.truncate(37)
53
+ output = "g=g o=o at=start\ng=g c=c ic=i\ng=g i=i"
54
+ assert_equal output, @out.string
60
55
  end
61
56
 
62
57
  def test_deeply_nested_context
@@ -89,12 +84,27 @@ class TestScrolls < Test::Unit::TestCase
89
84
  raise "Error from inside of context"
90
85
  end
91
86
  fail "Exception did not escape context block"
92
- rescue => e
87
+ rescue
93
88
  Scrolls.log(:o => 'o')
94
89
  assert_equal "o=o\n", @out.string
95
90
  end
96
91
  end
97
92
 
93
+ def test_deeply_nested_context_after_exception
94
+ Scrolls.log(:o => "o") do
95
+ begin
96
+ Scrolls.log(:io => 'io') do
97
+ raise "Error from inside of nested logging"
98
+ end
99
+ rescue
100
+ Scrolls.log(:o => 'o')
101
+ end
102
+ end
103
+ @out.truncate(124)
104
+ output = "o=o at=start\nio=io at=start\nio=io at=exception reraise=true class=RuntimeError message=\"Error from inside of nested logging\""
105
+ assert_equal output, @out.string
106
+ end
107
+
98
108
  def test_default_time_unit
99
109
  assert_equal "seconds", Scrolls.time_unit
100
110
  end
@@ -105,8 +115,15 @@ class TestScrolls < Test::Unit::TestCase
105
115
  end
106
116
 
107
117
  def test_setting_incorrect_time_unit
108
- assert_raise Scrolls::TimeUnitError do
118
+ assert_raises Scrolls::TimeUnitError do
109
119
  Scrolls.time_unit = "years"
120
+ Scrolls.log(:tu => "yrs")
121
+ end
122
+ end
123
+
124
+ def test_unknown_log_level
125
+ assert_raises Scrolls::LogLevelError do
126
+ Scrolls.log(:level => "nope")
110
127
  end
111
128
  end
112
129
 
@@ -125,28 +142,28 @@ class TestScrolls < Test::Unit::TestCase
125
142
  begin
126
143
  raise Exception
127
144
  rescue Exception => e
128
- Scrolls.log_exception({:test => "exception"}, e)
145
+ Scrolls.log_exception(e, {:test => "exception"})
129
146
  end
130
147
 
131
- oneline_backtrace = @out.string.gsub("\n", 'XX')
132
-
133
- assert_match /test=exception at=exception.*test_log_exception.*XX/,
134
- oneline_backtrace
148
+ oneline_bt = @out.string.gsub("\n", 'XX')
149
+ assert_match(/test=exception at=exception.*test_log_exception.*XX/, oneline_bt)
135
150
  end
136
151
 
137
- def test_single_line_exceptions
138
- Scrolls.single_line_exceptions = true
152
+ def test_multi_line_exceptions
153
+ Scrolls.single_line_exceptions = "multi"
139
154
  begin
140
155
  raise Exception
141
156
  rescue Exception => e
142
- Scrolls.log_exception({:o => "o"}, e)
157
+ Scrolls.log_exception(e, {:o => "o"})
143
158
  end
144
- assert_equal 1, @out.string.scan(/.*site=.*/).size
159
+
160
+ oneline_bt = @out.string.gsub("\n", 'XX')
161
+ assert_match(/o=o at=exception.*test_multi_line_exceptions.*XX/, oneline_bt)
145
162
  end
146
163
 
147
164
  def test_syslog_integration
148
165
  Scrolls.stream = 'syslog'
149
- assert_equal Scrolls::SyslogLogger, Scrolls.stream.class
166
+ assert_equal Scrolls::SyslogLogger, Scrolls.internal.logger.class
150
167
  end
151
168
 
152
169
  def test_syslog_facility
@@ -162,13 +179,7 @@ class TestScrolls < Test::Unit::TestCase
162
179
  def test_setting_syslog_facility_after_instantiation
163
180
  Scrolls.stream = 'syslog'
164
181
  Scrolls.facility = 'local7'
165
- assert_match /facility=184/, Scrolls.stream.inspect
166
- end
167
-
168
- def test_logging_message_with_syslog
169
- Scrolls.stream = 'syslog'
170
- Scrolls.facility = 'local7'
171
- Scrolls.log "scrolls test"
182
+ assert_match(/facility=184/, Scrolls.internal.logger.inspect)
172
183
  end
173
184
 
174
185
  def test_add_timestamp
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: scrolls
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.9
4
+ version: 0.9.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Curt Micol
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-08-22 00:00:00.000000000 Z
11
+ date: 2021-10-15 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: Logging, easier, more consistent.
14
14
  email:
@@ -25,15 +25,13 @@ files:
25
25
  - docs/global-context.md
26
26
  - docs/syslog.md
27
27
  - lib/scrolls.rb
28
- - lib/scrolls/atomic.rb
29
- - lib/scrolls/iolog.rb
30
- - lib/scrolls/log.rb
28
+ - lib/scrolls/iologger.rb
29
+ - lib/scrolls/logger.rb
31
30
  - lib/scrolls/parser.rb
32
- - lib/scrolls/syslog.rb
31
+ - lib/scrolls/sysloglogger.rb
33
32
  - lib/scrolls/utils.rb
34
33
  - lib/scrolls/version.rb
35
34
  - scrolls.gemspec
36
- - test/test_atomic.rb
37
35
  - test/test_helper.rb
38
36
  - test/test_parser.rb
39
37
  - test/test_scrolls.rb
@@ -56,13 +54,11 @@ required_rubygems_version: !ruby/object:Gem::Requirement
56
54
  - !ruby/object:Gem::Version
57
55
  version: '0'
58
56
  requirements: []
59
- rubyforge_project:
60
- rubygems_version: 2.6.11
57
+ rubygems_version: 3.2.29
61
58
  signing_key:
62
59
  specification_version: 4
63
60
  summary: When do we log? All the time.
64
61
  test_files:
65
- - test/test_atomic.rb
66
62
  - test/test_helper.rb
67
63
  - test/test_parser.rb
68
64
  - test/test_scrolls.rb
@@ -1,59 +0,0 @@
1
- require 'thread'
2
-
3
- module Scrolls
4
- # The result of issues with an update I made to Scrolls. After talking with
5
- # Fabio Kung about a fix I started work on an atomic object, but he added some
6
- # fixes to #context without it and then used Headius' atomic gem.
7
- #
8
- # The code below is the start and cleanup of my atomic object. It's slim on
9
- # details and eventually cleaned up around inspiration from Headius' code.
10
- #
11
- # LICENSE: Apache 2.0
12
- #
13
- # See Headius' atomic gem here:
14
- # https://github.com/headius/ruby-atomic
15
- class AtomicObject
16
- def initialize(o)
17
- @mtx = Mutex.new
18
- @o = o
19
- end
20
-
21
- def get
22
- @mtx.synchronize { @o }
23
- end
24
-
25
- def set(n)
26
- @mtx.synchronize { @o = n }
27
- end
28
-
29
- def verify_set(o, n)
30
- return false unless @mtx.try_lock
31
- begin
32
- return false unless @o.equal? o
33
- @o = n
34
- ensure
35
- @mtx.unlock
36
- end
37
- end
38
- end
39
-
40
- class Atomic < AtomicObject
41
- def initialize(v=nil)
42
- super(v)
43
- end
44
-
45
- def value
46
- self.get
47
- end
48
-
49
- def value=(v)
50
- self.set(v)
51
- v
52
- end
53
-
54
- def update
55
- true until self.verify_set(o = self.get, n = yield(o))
56
- n
57
- end
58
- end
59
- end