lumberjack 1.0.13 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
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