scrolls 0.3.9 → 0.9.3

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.
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