ougai 1.7.1-java

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/Rakefile ADDED
@@ -0,0 +1,17 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+ require 'yard'
4
+ require 'yard/rake/yardoc_task'
5
+
6
+ RSpec::Core::RakeTask.new(:spec)
7
+
8
+ task :default => :spec
9
+
10
+ FILES = ['lib/**/*.rb']
11
+ OPTIONS = ['--debug', '--verbose']
12
+
13
+ YARD::Rake::YardocTask.new do |t|
14
+ t.files = FILES
15
+ t.options = []
16
+ t.options << OPTIONS if $trace
17
+ end
data/lib/ougai.rb ADDED
@@ -0,0 +1,11 @@
1
+ require 'logger'
2
+ require 'ougai/version'
3
+ require 'ougai/logging'
4
+ require 'ougai/formatters/base'
5
+ require 'ougai/formatters/for_json'
6
+ require 'ougai/formatters/bunyan'
7
+ require 'ougai/formatters/readable'
8
+ require 'ougai/formatters/pino'
9
+ require 'ougai/serializer'
10
+ require 'ougai/child_logger'
11
+ require 'ougai/logger'
@@ -0,0 +1,62 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ougai
4
+ # A logger created by the `child` method of parent logger
5
+ class ChildLogger
6
+ include Logging
7
+
8
+ # @private
9
+ def initialize(parent, fields)
10
+ @before_log = nil
11
+ @parent = parent
12
+ @with_fields = fields
13
+ end
14
+
15
+ def level
16
+ @parent.level
17
+ end
18
+
19
+ # Whether the current severity level allows for logging DEBUG.
20
+ # @return [Boolean] true if allows
21
+ def debug?
22
+ @parent.debug?
23
+ end
24
+
25
+ # Whether the current severity level allows for logging INFO.
26
+ # @return [Boolean] true if allows
27
+ def info?
28
+ @parent.info?
29
+ end
30
+
31
+ # Whether the current severity level allows for logging WARN.
32
+ # @return [Boolean] true if allows
33
+ def warn?
34
+ @parent.warn?
35
+ end
36
+
37
+ # Whether the current severity level allows for logging ERROR.
38
+ # @return [Boolean] true if allows
39
+ def error?
40
+ @parent.error?
41
+ end
42
+
43
+ # Whether the current severity level allows for logging FATAL.
44
+ # @return [Boolean] true if allows
45
+ def fatal?
46
+ @parent.fatal?
47
+ end
48
+
49
+ # @private
50
+ def chain(severity, args, fields, hooks)
51
+ hooks.push(@before_log) if @before_log
52
+ @parent.chain(severity, args, weak_merge!(fields, @with_fields), hooks)
53
+ end
54
+
55
+ protected
56
+
57
+ def append(severity, args)
58
+ hooks = @before_log ? [@before_log] : []
59
+ @parent.chain(severity, args, @with_fields.dup, hooks)
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,84 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'time'
4
+ require 'socket'
5
+
6
+ module Ougai
7
+ module Formatters
8
+ # Base formatter
9
+ # Custom formatter must override `_call`.
10
+ # @attr [Fixnum] trace_indent Specify exception backtrace indent (by default this is 2).
11
+ # @attr [Fixnum] trace_max_lines Keep exception backtrace lines (by default this is 100).
12
+ # @attr [Boolean] serialize_backtrace Whether exception should converts String (by default this is on).
13
+ class Base < Logger::Formatter
14
+ attr_accessor :trace_indent, :trace_max_lines
15
+ attr_accessor :serialize_backtrace
16
+ attr_reader :app_name, :hostname
17
+
18
+ # Intialize a formatter
19
+ # @param [String] app_name application name
20
+ # @param [String] hostname hostname
21
+ # @param [Hash] opts the initial values of attributes
22
+ # @option opts [String] :trace_indent (2) the value of trace_indent attribute
23
+ # @option opts [String] :trace_max_lines (100) the value of trace_max_lines attribute
24
+ # @option opts [String] :serialize_backtrace (true) the value of serialize_backtrace attribute
25
+ def initialize(app_name = nil, hostname = nil, opts = {})
26
+ @app_name = app_name || File.basename($0, ".rb")
27
+ @hostname = hostname || Socket.gethostname.force_encoding('UTF-8')
28
+ @trace_indent = opts.fetch(:trace_indent, 2)
29
+ @trace_max_lines = opts.fetch(:trace_max_lines, 100)
30
+ @serialize_backtrace = opts.fetch(:serialize_backtrace, true)
31
+ self.datetime_format = nil
32
+ end
33
+
34
+ def call(severity, time, progname, data)
35
+ _call(severity, time, progname, data.is_a?(Hash) ? data : { msg: data.to_s })
36
+ end
37
+
38
+ def _call(severity, time, progname, data)
39
+ raise NotImplementedError, "_call must be implemented"
40
+ end
41
+
42
+ def datetime_format=(value)
43
+ @datetime_format = value || default_datetime_format
44
+ end
45
+
46
+ def serialize_exc(ex)
47
+ err = {
48
+ name: ex.class.name,
49
+ message: ex.to_s
50
+ }
51
+ if ex.backtrace
52
+ bt = ex.backtrace.slice(0, @trace_max_lines)
53
+ err[:stack] = @serialize_backtrace ? serialize_trace(bt) : bt
54
+ end
55
+ err
56
+ end
57
+
58
+ def serialize_trace(trace)
59
+ sp = "\n" + ' ' * @trace_indent
60
+ trace.join(sp)
61
+ end
62
+
63
+ private
64
+
65
+ def format_datetime(time)
66
+ time.strftime(@datetime_format)
67
+ end
68
+
69
+ def default_datetime_format
70
+ "%FT%T.%3N#{(Time.new.utc? ? 'Z' : '%:z')}"
71
+ end
72
+
73
+ def self.parse_new_params(args)
74
+ idx = args.index {|i| i.is_a?(Hash) }
75
+ return args if idx == 2
76
+ opts = args[idx]
77
+ app_name = opts.delete(:app_name)
78
+ hostname = opts.delete(:hostname)
79
+ app_name ||= args[0] if idx > 0
80
+ [app_name, hostname, opts]
81
+ end
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'ougai/formatters/base'
4
+
5
+ module Ougai
6
+ module Formatters
7
+ # A JSON formatter compatible with node-bunyan
8
+ class Bunyan < Base
9
+ include ForJson
10
+
11
+ # Intialize a formatter
12
+ # @param [String] app_name application name (execution program name if nil)
13
+ # @param [String] hostname hostname (hostname if nil)
14
+ # @param [Hash] opts the initial values of attributes
15
+ # @option opts [String] :trace_indent (2) the value of trace_indent attribute
16
+ # @option opts [String] :trace_max_lines (100) the value of trace_max_lines attribute
17
+ # @option opts [String] :serialize_backtrace (true) the value of serialize_backtrace attribute
18
+ # @option opts [String] :jsonize (true) the value of jsonize attribute
19
+ # @option opts [String] :with_newline (true) the value of with_newline attribute
20
+ def initialize(app_name = nil, hostname = nil, opts = {})
21
+ aname, hname, opts = Base.parse_new_params([app_name, hostname, opts])
22
+ super(aname, hname, opts)
23
+ init_opts_for_json(opts)
24
+ end
25
+
26
+ def _call(severity, time, progname, data)
27
+ dump({
28
+ name: progname || @app_name,
29
+ hostname: @hostname,
30
+ pid: $$,
31
+ level: to_level(severity),
32
+ time: time,
33
+ v: 0
34
+ }.merge(data))
35
+ end
36
+
37
+ def convert_time(data)
38
+ data[:time] = format_datetime(data[:time])
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ougai
4
+ # The features for JSON formatter
5
+ # @attr [Boolean] jsonize Whether log should converts JSON
6
+ # @attr [Boolean] with_newline Whether tailing NL should be appended
7
+ module Formatters::ForJson
8
+ attr_accessor :jsonize, :with_newline
9
+
10
+ protected
11
+
12
+ def init_opts_for_json(opts)
13
+ @jsonize = opts.fetch(:jsonize, true)
14
+ @with_newline = opts.fetch(:with_newline, true)
15
+ @serializer = Ougai::Serializer.for_json
16
+ end
17
+
18
+ def to_level(severity)
19
+ case severity
20
+ when 'TRACE'
21
+ 10
22
+ when 'DEBUG'
23
+ 20
24
+ when 'INFO'
25
+ 30
26
+ when 'WARN'
27
+ 40
28
+ when 'ERROR'
29
+ 50
30
+ when 'FATAL'
31
+ 60
32
+ else
33
+ 70
34
+ end
35
+ end
36
+
37
+ # requires convert_time(data) method
38
+ def dump(data)
39
+ return data unless @jsonize
40
+ convert_time(data)
41
+ str = @serializer.serialize(data)
42
+ str << "\n" if @with_newline
43
+ str
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,60 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'ougai/formatters/base'
4
+
5
+ module Ougai
6
+ module Formatters
7
+ # A JSON formatter compatible with pino
8
+ class Pino < Base
9
+ include ForJson
10
+
11
+ # Intialize a formatter
12
+ # @param [String] app_name application name (execution program name if nil)
13
+ # @param [String] hostname hostname (hostname if nil)
14
+ # @param [Hash] opts the initial values of attributes
15
+ # @option opts [String] :trace_indent (4) the value of trace_indent attribute
16
+ # @option opts [String] :trace_max_lines (100) the value of trace_max_lines attribute
17
+ # @option opts [String] :serialize_backtrace (true) the value of serialize_backtrace attribute
18
+ # @option opts [String] :jsonize (true) the value of jsonize attribute
19
+ # @option opts [String] :with_newline (true) the value of with_newline attribute
20
+ def initialize(app_name = nil, hostname = nil, opts = {})
21
+ aname, hname, opts = Base.parse_new_params([app_name, hostname, opts])
22
+ super(aname, hname, opts)
23
+ init_opts_for_json(opts)
24
+ @trace_indent = opts.fetch(:trace_indent, 4)
25
+ @serialize_backtrace = true
26
+ end
27
+
28
+ def datetime_format=(val)
29
+ raise NotImplementedError, 'Not support datetime_format attribute' unless val.nil?
30
+ end
31
+
32
+ def _call(severity, time, progname, data)
33
+ flat_err(data)
34
+ dump({
35
+ name: progname || @app_name,
36
+ hostname: @hostname,
37
+ pid: $$,
38
+ level: to_level(severity),
39
+ time: time,
40
+ v: 1
41
+ }.merge(data))
42
+ end
43
+
44
+ def flat_err(data)
45
+ return unless data.key?(:err)
46
+ err = data.delete(:err)
47
+ msg = err[:message]
48
+ data[:type] ||= 'Error'
49
+ data[:msg] ||= msg
50
+ stack = "#{err[:name]}: #{msg}"
51
+ stack += "\n" + (" " * @trace_indent) + err[:stack] if err.key?(:stack)
52
+ data[:stack] ||= stack
53
+ end
54
+
55
+ def convert_time(data)
56
+ data[:time] = (data[:time].to_f * 1000).to_i
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,96 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'ougai/formatters/base'
4
+
5
+ module Ougai
6
+ module Formatters
7
+ # A human readble formatter with awesome_print
8
+ # @attr [Boolean] plain Whether log should be plain not colorized.
9
+ # @attr [Array<String, Symbol>] excluded_fields The fields excluded from all logs
10
+ class Readable < Base
11
+ attr_accessor :plain, :excluded_fields
12
+
13
+ # Intialize a formatter
14
+ # @param [String] app_name application name (execution program name if nil)
15
+ # @param [String] hostname hostname (hostname if nil)
16
+ # @param [Hash] opts the initial values of attributes
17
+ # @option opts [String] :trace_indent (4) the value of trace_indent attribute
18
+ # @option opts [String] :trace_max_lines (100) the value of trace_max_lines attribute
19
+ # @option opts [String] :plain (false) the value of plain attribute
20
+ # @option opts [String] :excluded_fields ([]) the value of excluded_fields attribute
21
+ def initialize(app_name = nil, hostname = nil, opts = {})
22
+ aname, hname, opts = Base.parse_new_params([app_name, hostname, opts])
23
+ super(aname, hname, opts)
24
+ @trace_indent = opts.fetch(:trace_indent, 4)
25
+ @plain = opts.fetch(:plain, false)
26
+ @excluded_fields = opts[:excluded_fields] || []
27
+ @serialize_backtrace = true
28
+ load_dependent
29
+ end
30
+
31
+ def _call(severity, time, progname, data)
32
+ msg = data.delete(:msg)
33
+ level = @plain ? severity : colored_level(severity)
34
+ dt = format_datetime(time)
35
+ err_str = create_err_str(data)
36
+
37
+ @excluded_fields.each { |f| data.delete(f) }
38
+ data_str = create_data_str(data)
39
+ format_log_parts(dt, level, msg, err_str, data_str)
40
+ end
41
+
42
+ def serialize_backtrace=(value)
43
+ raise NotImplementedError, 'Not support serialize_backtrace'
44
+ end
45
+
46
+ protected
47
+
48
+ def format_log_parts(datetime, level, msg, err, data)
49
+ strs = ["[#{datetime}] #{level}: #{msg}"]
50
+ strs.push(err) if err
51
+ strs.push(data) if data
52
+ strs.join("\n") + "\n"
53
+ end
54
+
55
+ def colored_level(severity)
56
+ case severity
57
+ when 'TRACE'
58
+ color = '0;34'
59
+ when 'DEBUG'
60
+ color = '0;37'
61
+ when 'INFO'
62
+ color = '0;36'
63
+ when 'WARN'
64
+ color = '0;33'
65
+ when 'ERROR'
66
+ color = '0;31'
67
+ when 'FATAL'
68
+ color = '0;35'
69
+ else
70
+ color = '0;32'
71
+ end
72
+ "\e[#{color}m#{severity}\e[0m"
73
+ end
74
+
75
+ def create_err_str(data)
76
+ return nil unless data.key?(:err)
77
+ err = data.delete(:err)
78
+ err_str = " #{err[:name]} (#{err[:message]}):"
79
+ err_str += "\n" + (" " * @trace_indent) + err[:stack] if err.key?(:stack)
80
+ err_str
81
+ end
82
+
83
+ def create_data_str(data)
84
+ return nil if data.empty?
85
+ data.ai({ plain: @plain })
86
+ end
87
+
88
+ def load_dependent
89
+ require 'awesome_print'
90
+ rescue LoadError
91
+ puts 'You must install the awesome_print gem to use this output.'
92
+ raise
93
+ end
94
+ end
95
+ end
96
+ end
@@ -0,0 +1,158 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ougai
4
+ # Main Logger
5
+ # @attr [String] default_message Use this if log message is not specified (by default this is 'No message').
6
+ # @attr [String] exc_key The field name of Exception (by default this is :err).
7
+ # @attr [Hash] with_fields The fields appending to all logs.
8
+ # @attr [Proc] before_log Hook before logging.
9
+ class Logger < ::Logger
10
+ include Logging
11
+
12
+ attr_accessor :default_message, :exc_key
13
+
14
+ def initialize(*args)
15
+ super(*args)
16
+ @before_log = nil
17
+ @default_message = 'No message'
18
+ @exc_key = :err
19
+ @with_fields = {}
20
+ @formatter = create_formatter
21
+ end
22
+
23
+ # Broadcasts the same logs to the another logger
24
+ # @param logger [Logger] The logger receiving broadcast logs.
25
+ def self.broadcast(logger)
26
+ Module.new do |mdl|
27
+ Logger::Severity.constants.each do |severity|
28
+ method_name = severity.downcase.to_sym
29
+
30
+ mdl.send(:define_method, method_name) do |*args|
31
+ logger.send(method_name, *args)
32
+ super(*args)
33
+ end
34
+ end
35
+
36
+ define_method(:level=) do |level|
37
+ logger.level = level
38
+ super(level)
39
+ end
40
+
41
+ define_method(:close) do
42
+ logger.close
43
+ super()
44
+ end
45
+ end
46
+ end
47
+
48
+ def level=(severity)
49
+ if severity.is_a?(Integer)
50
+ @level = severity
51
+ return
52
+ end
53
+
54
+ if severity.to_s.downcase == 'trace'
55
+ @level = TRACE
56
+ return
57
+ end
58
+
59
+ super
60
+ end
61
+
62
+ # @private
63
+ def chain(severity, args, fields, hooks)
64
+ hooks.push(@before_log) if @before_log
65
+ write(severity, args, weak_merge!(fields, @with_fields), hooks)
66
+ end
67
+
68
+ protected
69
+
70
+ # @private
71
+ def append(severity, args)
72
+ hooks = @before_log ? [@before_log] : []
73
+ write(severity, args, @with_fields, hooks)
74
+ end
75
+
76
+ def create_formatter
77
+ Formatters::Bunyan.new
78
+ end
79
+
80
+ private
81
+
82
+ def format_severity(severity)
83
+ to_label(severity)
84
+ end
85
+
86
+ def write(severity, args, fields, hooks)
87
+ data = weak_merge!(to_item(args), fields)
88
+ hooks.each do |hook|
89
+ return false if hook.call(data) == false
90
+ end
91
+ add(severity, data)
92
+ end
93
+
94
+ def to_item(args)
95
+ msg, ex, data = args
96
+
97
+ if msg.nil?
98
+ { msg: @default_message }
99
+ elsif ex.nil?
100
+ create_item_with_1arg(msg)
101
+ elsif data.nil?
102
+ create_item_with_2args(msg, ex)
103
+ else
104
+ create_item_with_3args(msg, ex, data)
105
+ end
106
+ end
107
+
108
+ def create_item_with_1arg(arg)
109
+ item = {}
110
+ if arg.is_a?(Exception)
111
+ item[:msg] = arg.to_s
112
+ set_exc(item, arg)
113
+ elsif arg.is_a?(String)
114
+ item[:msg] = arg
115
+ else
116
+ item.merge!(as_hash(arg))
117
+ item[:msg] ||= @default_message
118
+ end
119
+ item
120
+ end
121
+
122
+ def create_item_with_2args(arg1, arg2)
123
+ item = {}
124
+ if arg2.is_a?(Exception) # msg, ex
125
+ item[:msg] = arg1.to_s
126
+ set_exc(item, arg2)
127
+ elsif arg1.is_a?(Exception) # ex, data
128
+ set_exc(item, arg1)
129
+ item.merge!(as_hash(arg2))
130
+ item[:msg] ||= arg1.to_s
131
+ else # msg, data
132
+ item[:msg] = arg1.to_s
133
+ item.merge!(as_hash(arg2))
134
+ end
135
+ item
136
+ end
137
+
138
+ def create_item_with_3args(msg, ex, data)
139
+ {}.tap do |item|
140
+ set_exc(item, ex) if ex.is_a?(Exception)
141
+ item.merge!(as_hash(data))
142
+ item[:msg] = msg.to_s
143
+ end
144
+ end
145
+
146
+ def set_exc(item, exc)
147
+ item[@exc_key] = @formatter.serialize_exc(exc)
148
+ end
149
+
150
+ def as_hash(data)
151
+ if data.is_a?(Hash) || data.respond_to?(:to_hash)
152
+ data
153
+ else
154
+ { data: data }
155
+ end
156
+ end
157
+ end
158
+ end