lumberjack 1.0.13 → 1.1.0

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.
Files changed (49) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +74 -0
  3. data/README.md +92 -20
  4. data/VERSION +1 -1
  5. data/lib/lumberjack.rb +51 -16
  6. data/lib/lumberjack/context.rb +35 -0
  7. data/lib/lumberjack/device.rb +20 -6
  8. data/lib/lumberjack/device/date_rolling_log_file.rb +2 -2
  9. data/lib/lumberjack/device/log_file.rb +12 -1
  10. data/lib/lumberjack/device/multi.rb +46 -0
  11. data/lib/lumberjack/device/null.rb +0 -2
  12. data/lib/lumberjack/device/rolling_log_file.rb +2 -2
  13. data/lib/lumberjack/device/size_rolling_log_file.rb +1 -1
  14. data/lib/lumberjack/device/writer.rb +86 -55
  15. data/lib/lumberjack/formatter.rb +54 -18
  16. data/lib/lumberjack/formatter/date_time_formatter.rb +26 -0
  17. data/lib/lumberjack/formatter/id_formatter.rb +23 -0
  18. data/lib/lumberjack/formatter/object_formatter.rb +12 -0
  19. data/lib/lumberjack/formatter/structured_formatter.rb +31 -0
  20. data/lib/lumberjack/log_entry.rb +41 -16
  21. data/lib/lumberjack/logger.rb +168 -63
  22. data/lib/lumberjack/rack.rb +3 -2
  23. data/lib/lumberjack/rack/context.rb +18 -0
  24. data/lib/lumberjack/rack/request_id.rb +4 -4
  25. data/lib/lumberjack/severity.rb +11 -9
  26. data/lib/lumberjack/tags.rb +24 -0
  27. data/lib/lumberjack/template.rb +74 -32
  28. data/lumberjack.gemspec +35 -0
  29. metadata +48 -37
  30. data/Rakefile +0 -40
  31. data/spec/device/date_rolling_log_file_spec.rb +0 -73
  32. data/spec/device/log_file_spec.rb +0 -48
  33. data/spec/device/null_spec.rb +0 -12
  34. data/spec/device/rolling_log_file_spec.rb +0 -151
  35. data/spec/device/size_rolling_log_file_spec.rb +0 -58
  36. data/spec/device/writer_spec.rb +0 -118
  37. data/spec/formatter/exception_formatter_spec.rb +0 -20
  38. data/spec/formatter/inspect_formatter_spec.rb +0 -13
  39. data/spec/formatter/pretty_print_formatter_spec.rb +0 -14
  40. data/spec/formatter/string_formatter_spec.rb +0 -12
  41. data/spec/formatter_spec.rb +0 -45
  42. data/spec/log_entry_spec.rb +0 -69
  43. data/spec/logger_spec.rb +0 -411
  44. data/spec/lumberjack_spec.rb +0 -29
  45. data/spec/rack/request_id_spec.rb +0 -48
  46. data/spec/rack/unit_of_work_spec.rb +0 -26
  47. data/spec/severity_spec.rb +0 -23
  48. data/spec/spec_helper.rb +0 -32
  49. data/spec/template_spec.rb +0 -34
@@ -2,7 +2,8 @@
2
2
 
3
3
  module Lumberjack
4
4
  module Rack
5
- require File.expand_path("../rack/unit_of_work.rb", __FILE__)
6
- require File.expand_path("../rack/request_id.rb", __FILE__)
5
+ require_relative "rack/unit_of_work.rb"
6
+ require_relative "rack/request_id.rb"
7
+ require_relative "rack/context.rb"
7
8
  end
8
9
  end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literals: true
2
+
3
+ module Lumberjack
4
+ module Rack
5
+ # Middleware to create a global context for Lumberjack for the scope of a rack request.
6
+ class Context
7
+ def initialize(app)
8
+ @app = app
9
+ end
10
+
11
+ def call(env)
12
+ Lumberjack.context do
13
+ @app.call(env)
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -6,17 +6,17 @@ module Lumberjack
6
6
  # The format is expected to be a random UUID and only the first chunk is used for terseness
7
7
  # if the abbreviated argument is true.
8
8
  class RequestId
9
- REQUEST_ID = "action_dispatch.request_id".freeze
10
-
9
+ REQUEST_ID = "action_dispatch.request_id"
10
+
11
11
  def initialize(app, abbreviated = false)
12
12
  @app = app
13
13
  @abbreviated = abbreviated
14
14
  end
15
-
15
+
16
16
  def call(env)
17
17
  request_id = env[REQUEST_ID]
18
18
  if request_id && @abbreviated
19
- request_id = request_id.split('-'.freeze, 2).first
19
+ request_id = request_id.split('-', 2).first
20
20
  end
21
21
  Lumberjack.unit_of_work(request_id) do
22
22
  @app.call(env)
@@ -3,23 +3,25 @@
3
3
  module Lumberjack
4
4
  # The standard severity levels for logging messages.
5
5
  module Severity
6
- UNKNOWN = 5
7
- FATAL = 4
8
- ERROR = 3
9
- WARN = 2
10
- INFO = 1
11
- DEBUG = 0
12
-
6
+ # Backward compatibilty with 1.0 API
7
+ DEBUG = ::Logger::Severity::DEBUG
8
+ INFO = ::Logger::Severity::INFO
9
+ WARN = ::Logger::Severity::WARN
10
+ ERROR = ::Logger::Severity::ERROR
11
+ FATAL = ::Logger::Severity::FATAL
12
+ UNKNOWN = ::Logger::Severity::UNKNOWN
13
+
13
14
  SEVERITY_LABELS = %w(DEBUG INFO WARN ERROR FATAL UNKNOWN).freeze
14
-
15
+
15
16
  class << self
16
17
  def level_to_label(severity)
17
18
  SEVERITY_LABELS[severity] || SEVERITY_LABELS.last
18
19
  end
19
-
20
+
20
21
  def label_to_level(label)
21
22
  SEVERITY_LABELS.index(label.to_s.upcase) || UNKNOWN
22
23
  end
23
24
  end
25
+
24
26
  end
25
27
  end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Lumberjack
4
+ class Tags
5
+ class << self
6
+ # Transform hash keys to strings. This method exists for optimization and backward compatibility.
7
+ # If a hash already has string keys, it will be returned as is.
8
+ def stringify_keys(hash)
9
+ return nil if hash.nil?
10
+ if hash.keys.all? { |key| key.is_a?(String) }
11
+ hash
12
+ elsif hash.respond_to?(:transform_keys)
13
+ hash.transform_keys(&:to_s)
14
+ else
15
+ copy = {}
16
+ hash.each do |key, value|
17
+ copy[key.to_s] = value
18
+ end
19
+ copy
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -4,70 +4,112 @@ module Lumberjack
4
4
  # A template converts entries to strings. Templates can contain the following place holders to
5
5
  # reference log entry values:
6
6
  #
7
- # * <tt>:time</tt>
8
- # * <tt>:severity</tt>
9
- # * <tt>:progname</tt>
10
- # * <tt>:unit_of_work_id</tt>
11
- # * <tt>:message</tt>
7
+ # * :time
8
+ # * :severity
9
+ # * :progname
10
+ # * :tags
11
+ # * :message
12
+ #
13
+ # Any other words prefixed with a colon will be substituted with the value of the tag with that name.
12
14
  class Template
13
- TEMPLATE_ARGUMENT_ORDER = %w(:time :severity :progname :pid :unit_of_work_id :message).freeze
14
- DEFAULT_TIME_FORMAT = "%Y-%m-%dT%H:%M:%S."
15
- MILLISECOND_FORMAT = "%03d"
16
- MICROSECOND_FORMAT = "%06d"
17
-
15
+ TEMPLATE_ARGUMENT_ORDER = %w(:time :severity :progname :pid :message :tags).freeze
16
+ MILLISECOND_TIME_FORMAT = "%Y-%m-%dT%H:%M:%S.%3N"
17
+ MICROSECOND_TIME_FORMAT = "%Y-%m-%dT%H:%M:%S.%6N"
18
+
18
19
  # Create a new template from the markup. The +first_line+ argument is used to format only the first
19
20
  # line of a message. Additional lines will be added to the message unformatted. If you wish to format
20
- # the additional lines, use the <tt>:additional_lines</tt> options to specify a template. Note that you'll need
21
+ # the additional lines, use the :additional_lines options to specify a template. Note that you'll need
21
22
  # to provide the line separator character in this template if you want to keep the message on multiple lines.
22
23
  #
23
24
  # The time will be formatted as YYYY-MM-DDTHH:MM:SSS.SSS by default. If you wish to change the format, you
24
- # can specify the <tt>:time_format</tt> option which can be either a time format template as documented in
25
+ # can specify the :time_format option which can be either a time format template as documented in
25
26
  # +Time#strftime+ or the values +:milliseconds+ or +:microseconds+ to use the standard format with the
26
27
  # specified precision.
27
28
  #
28
29
  # Messages will have white space stripped from both ends.
29
30
  def initialize(first_line, options = {})
30
- @first_line_template = compile(first_line)
31
+ @first_line_template, @first_line_tags = compile(first_line)
31
32
  additional_lines = options[:additional_lines] || "#{Lumberjack::LINE_SEPARATOR}:message"
32
- @additional_line_template = compile(additional_lines)
33
+ @additional_line_template, @additional_line_tags = compile(additional_lines)
33
34
  # Formatting the time is relatively expensive, so only do it if it will be used
34
35
  @template_include_time = first_line.include?(":time") || additional_lines.include?(":time")
35
- @time_format = options[:time_format] || :milliseconds
36
+ self.datetime_format = (options[:time_format] || :milliseconds)
37
+ end
38
+
39
+ def datetime_format=(format)
40
+ if format == :milliseconds
41
+ format = MILLISECOND_TIME_FORMAT
42
+ elsif format == :microseconds
43
+ format = MICROSECOND_TIME_FORMAT
44
+ end
45
+ @time_formatter = Formatter::DateTimeFormatter.new(format)
36
46
  end
37
-
47
+
48
+ def datetime_format
49
+ @time_formatter.format
50
+ end
51
+
38
52
  # Convert an entry into a string using the template.
39
53
  def call(entry)
40
- lines = entry.message.strip.split(Lumberjack::LINE_SEPARATOR)
41
- formatted_time = format_time(entry.time) if @template_include_time
42
- message = @first_line_template % [formatted_time, entry.severity_label, entry.progname, entry.pid, entry.unit_of_work_id, lines.shift]
43
- lines.each do |line|
44
- message << @additional_line_template % [formatted_time, entry.severity_label, entry.progname, entry.pid, entry.unit_of_work_id, line]
54
+ return entry unless entry.is_a?(LogEntry)
55
+
56
+ first_line = entry.message.to_s
57
+ additional_lines = nil
58
+ if first_line.include?(Lumberjack::LINE_SEPARATOR)
59
+ additional_lines = first_line.split(Lumberjack::LINE_SEPARATOR)
60
+ first_line = additional_lines.shift
61
+ end
62
+
63
+ formatted_time = @time_formatter.call(entry.time) if @template_include_time
64
+ format_args = [formatted_time, entry.severity_label, entry.progname, entry.pid, first_line]
65
+ tag_arguments = tag_args(entry.tags, @first_line_tags)
66
+ message = (@first_line_template % (format_args + tag_arguments))
67
+ message.rstrip! if message.end_with?(" ")
68
+
69
+ if additional_lines && !additional_lines.empty?
70
+ tag_arguments = tag_args(entry.tags, @additional_line_tags) unless @additional_line_tags == @first_line_tags
71
+ additional_lines.each do |line|
72
+ format_args[format_args.size - 1] = line
73
+ line_message = (@additional_line_template % (format_args + tag_arguments)).rstrip
74
+ line_message.rstrip! if line_message.end_with?(" ")
75
+ message << line_message
76
+ end
45
77
  end
46
78
  message
47
79
  end
48
-
80
+
49
81
  private
50
82
 
51
- def format_time(time) #:nodoc:
52
- if @time_format.is_a?(String)
53
- time.strftime(@time_format)
54
- elsif @time_format == :milliseconds
55
- time.strftime(DEFAULT_TIME_FORMAT) << MILLISECOND_FORMAT % (time.usec / 1000.0).round
56
- else
57
- time.strftime(DEFAULT_TIME_FORMAT) << MICROSECOND_FORMAT % time.usec
83
+ def tag_args(tags, tag_vars)
84
+ return [nil] * (tag_vars.size + 1) if tags.nil? || tags.size == 0
85
+
86
+ tags_string = String.new
87
+ tags.each do |name, value|
88
+ unless tag_vars.include?(name)
89
+ tags_string << "[#{name}:#{value.inspect}] "
90
+ end
91
+ end
92
+
93
+ args = [tags_string.chop]
94
+ tag_vars.each do |name|
95
+ args << tags[name]
58
96
  end
97
+ args
59
98
  end
60
-
99
+
61
100
  # Compile the template string into a value that can be used with sprintf.
62
101
  def compile(template) #:nodoc:
63
- template.gsub(/:[a-z0-9_]+/) do |match|
102
+ tag_vars = []
103
+ template = template.gsub(/:[a-z0-9_]+/) do |match|
64
104
  position = TEMPLATE_ARGUMENT_ORDER.index(match)
65
105
  if position
66
106
  "%#{position + 1}$s"
67
107
  else
68
- match
108
+ tag_vars << match[1, match.length]
109
+ "%#{TEMPLATE_ARGUMENT_ORDER.size + tag_vars.size}$s"
69
110
  end
70
111
  end
112
+ [template, tag_vars]
71
113
  end
72
114
  end
73
115
  end
@@ -0,0 +1,35 @@
1
+ Gem::Specification.new do |spec|
2
+ spec.name = 'lumberjack'
3
+ spec.version = File.read(File.expand_path("../VERSION", __FILE__)).strip
4
+ spec.authors = ['Brian Durand']
5
+ spec.email = ['bbdurand@gmail.com']
6
+
7
+ spec.summary = "A simple, powerful, and very fast logging utility that can be a drop in replacement for Logger or ActiveSupport::BufferedLogger."
8
+ spec.homepage = "https://github.com/bdurand/lumberjack"
9
+ spec.license = "MIT"
10
+
11
+ # Specify which files should be added to the gem when it is released.
12
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
13
+ ignore_files = %w(
14
+ .gitignore
15
+ .travis.yml
16
+ Appraisals
17
+ Gemfile
18
+ Gemfile.lock
19
+ Rakefile
20
+ gemfiles/
21
+ spec/
22
+ )
23
+ spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
24
+ `git ls-files -z`.split("\x0").reject{ |f| ignore_files.any?{ |path| f.start_with?(path) } }
25
+ end
26
+
27
+ spec.require_paths = ['lib']
28
+
29
+ spec.required_ruby_version = '>= 2.3.0'
30
+
31
+ spec.add_development_dependency("rspec", ["~> 3.0"])
32
+ spec.add_development_dependency("timecop")
33
+ spec.add_development_dependency "rake"
34
+ spec.add_development_dependency "appraisal"
35
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lumberjack
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.13
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brian Durand
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-03-29 00:00:00.000000000 Z
11
+ date: 2020-01-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rspec
@@ -28,76 +28,88 @@ dependencies:
28
28
  name: timecop
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - "~>"
31
+ - - ">="
32
32
  - !ruby/object:Gem::Version
33
- version: '0.8'
33
+ version: '0'
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - "~>"
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
39
53
  - !ruby/object:Gem::Version
40
- version: '0.8'
41
- description: A simple, powerful, and very fast logging utility that can be a drop
42
- in replacement for Logger or ActiveSupport::BufferedLogger. Provides support for
43
- automatically rolling log files even with multiple processes writing the same log
44
- file.
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: appraisal
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ description:
45
70
  email:
46
71
  - bbdurand@gmail.com
47
72
  executables: []
48
73
  extensions: []
49
74
  extra_rdoc_files: []
50
75
  files:
76
+ - CHANGELOG.md
51
77
  - MIT_LICENSE
52
78
  - README.md
53
- - Rakefile
54
79
  - VERSION
55
80
  - lib/lumberjack.rb
81
+ - lib/lumberjack/context.rb
56
82
  - lib/lumberjack/device.rb
57
83
  - lib/lumberjack/device/date_rolling_log_file.rb
58
84
  - lib/lumberjack/device/log_file.rb
85
+ - lib/lumberjack/device/multi.rb
59
86
  - lib/lumberjack/device/null.rb
60
87
  - lib/lumberjack/device/rolling_log_file.rb
61
88
  - lib/lumberjack/device/size_rolling_log_file.rb
62
89
  - lib/lumberjack/device/writer.rb
63
90
  - lib/lumberjack/formatter.rb
91
+ - lib/lumberjack/formatter/date_time_formatter.rb
64
92
  - lib/lumberjack/formatter/exception_formatter.rb
93
+ - lib/lumberjack/formatter/id_formatter.rb
65
94
  - lib/lumberjack/formatter/inspect_formatter.rb
95
+ - lib/lumberjack/formatter/object_formatter.rb
66
96
  - lib/lumberjack/formatter/pretty_print_formatter.rb
67
97
  - lib/lumberjack/formatter/string_formatter.rb
98
+ - lib/lumberjack/formatter/structured_formatter.rb
68
99
  - lib/lumberjack/log_entry.rb
69
100
  - lib/lumberjack/logger.rb
70
101
  - lib/lumberjack/rack.rb
102
+ - lib/lumberjack/rack/context.rb
71
103
  - lib/lumberjack/rack/request_id.rb
72
104
  - lib/lumberjack/rack/unit_of_work.rb
73
105
  - lib/lumberjack/severity.rb
106
+ - lib/lumberjack/tags.rb
74
107
  - lib/lumberjack/template.rb
75
- - spec/device/date_rolling_log_file_spec.rb
76
- - spec/device/log_file_spec.rb
77
- - spec/device/null_spec.rb
78
- - spec/device/rolling_log_file_spec.rb
79
- - spec/device/size_rolling_log_file_spec.rb
80
- - spec/device/writer_spec.rb
81
- - spec/formatter/exception_formatter_spec.rb
82
- - spec/formatter/inspect_formatter_spec.rb
83
- - spec/formatter/pretty_print_formatter_spec.rb
84
- - spec/formatter/string_formatter_spec.rb
85
- - spec/formatter_spec.rb
86
- - spec/log_entry_spec.rb
87
- - spec/logger_spec.rb
88
- - spec/lumberjack_spec.rb
89
- - spec/rack/request_id_spec.rb
90
- - spec/rack/unit_of_work_spec.rb
91
- - spec/severity_spec.rb
92
- - spec/spec_helper.rb
93
- - spec/template_spec.rb
108
+ - lumberjack.gemspec
94
109
  homepage: https://github.com/bdurand/lumberjack
95
110
  licenses:
96
111
  - MIT
97
- metadata:
98
- homepage_uri: https://github.com/bdurand/lumberjack
99
- changelog_uri: https://github.com/bdurand/lumberjack/blob/master/CHANGELOG.md
100
- source_code_uri: https://github.com/bdurand/lumberjack
112
+ metadata: {}
101
113
  post_install_message:
102
114
  rdoc_options: []
103
115
  require_paths:
@@ -106,15 +118,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
106
118
  requirements:
107
119
  - - ">="
108
120
  - !ruby/object:Gem::Version
109
- version: '0'
121
+ version: 2.3.0
110
122
  required_rubygems_version: !ruby/object:Gem::Requirement
111
123
  requirements:
112
124
  - - ">="
113
125
  - !ruby/object:Gem::Version
114
126
  version: '0'
115
127
  requirements: []
116
- rubyforge_project:
117
- rubygems_version: 2.5.2.2
128
+ rubygems_version: 3.0.3
118
129
  signing_key:
119
130
  specification_version: 4
120
131
  summary: A simple, powerful, and very fast logging utility that can be a drop in replacement