ougai 1.7.1-java

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