semantic_logger 3.0.1 → 3.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +1 -1
- data/lib/semantic_logger.rb +29 -13
- data/lib/semantic_logger/ansi_colors.rb +27 -0
- data/lib/semantic_logger/appender/base.rb +54 -128
- data/lib/semantic_logger/appender/bugsnag.rb +29 -19
- data/lib/semantic_logger/appender/elasticsearch.rb +9 -9
- data/lib/semantic_logger/appender/file.rb +40 -18
- data/lib/semantic_logger/appender/graylog.rb +30 -26
- data/lib/semantic_logger/appender/http.rb +14 -19
- data/lib/semantic_logger/appender/mongodb.rb +20 -20
- data/lib/semantic_logger/appender/new_relic.rb +15 -15
- data/lib/semantic_logger/appender/splunk.rb +1 -1
- data/lib/semantic_logger/appender/splunk_http.rb +28 -25
- data/lib/semantic_logger/appender/syslog.rb +41 -42
- data/lib/semantic_logger/appender/wrapper.rb +19 -17
- data/lib/semantic_logger/base.rb +57 -32
- data/lib/semantic_logger/concerns/compatibility.rb +51 -0
- data/lib/semantic_logger/debug_as_trace_logger.rb +6 -2
- data/lib/semantic_logger/formatters/color.rb +66 -0
- data/lib/semantic_logger/formatters/default.rb +39 -0
- data/lib/semantic_logger/formatters/json.rb +16 -0
- data/lib/semantic_logger/jruby/garbage_collection_logger.rb +1 -1
- data/lib/semantic_logger/log.rb +13 -8
- data/lib/semantic_logger/loggable.rb +2 -2
- data/lib/semantic_logger/logger.rb +18 -13
- data/lib/semantic_logger/metrics/new_relic.rb +18 -0
- data/lib/semantic_logger/metrics/statsd.rb +48 -0
- data/lib/semantic_logger/semantic_logger.rb +122 -55
- data/lib/semantic_logger/version.rb +1 -1
- data/test/appender/bugsnag_test.rb +12 -3
- data/test/appender/mongodb_test.rb +6 -5
- data/test/appender/new_relic_test.rb +1 -1
- data/test/appender/splunk_http_test.rb +1 -0
- data/test/concerns/compatibility_test.rb +106 -0
- data/test/debug_as_trace_logger_test.rb +1 -1
- data/test/loggable_test.rb +1 -1
- data/test/logger_test.rb +183 -24
- metadata +12 -3
@@ -11,8 +11,12 @@ module SemanticLogger
|
|
11
11
|
trace?
|
12
12
|
end
|
13
13
|
|
14
|
+
def measure_debug(*args, &block)
|
15
|
+
measure_trace(*args, &block)
|
16
|
+
end
|
17
|
+
|
14
18
|
def benchmark_debug(*args, &block)
|
15
|
-
|
19
|
+
measure_trace(*args, &block)
|
16
20
|
end
|
17
21
|
end
|
18
|
-
end
|
22
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
# Load AwesomePrint if available
|
2
|
+
begin
|
3
|
+
require 'awesome_print'
|
4
|
+
rescue LoadError
|
5
|
+
end
|
6
|
+
|
7
|
+
module SemanticLogger
|
8
|
+
module Formatters
|
9
|
+
class Color
|
10
|
+
# Parameters:
|
11
|
+
# Any valid AwesomePrint option for rendering data.
|
12
|
+
# These options can also be changed be creating a `~/.aprc` file.
|
13
|
+
# See: https://github.com/michaeldv/awesome_print
|
14
|
+
#
|
15
|
+
# Note: The option :multiline is set to false if not supplied.
|
16
|
+
# Note: Has no effect if Awesome Print is not installed.
|
17
|
+
def initialize(options={})
|
18
|
+
@ai_options = options.dup
|
19
|
+
@ai_options[:multiline] = false unless @ai_options.has_key?(:multiline)
|
20
|
+
end
|
21
|
+
|
22
|
+
# Adds color to the default log formatter
|
23
|
+
# Example:
|
24
|
+
# SemanticLogger.add_appender(io: $stdout, formatter: :color)
|
25
|
+
def call(log, logger)
|
26
|
+
colors = SemanticLogger::AnsiColors
|
27
|
+
level_color = colors::LEVEL_MAP[log.level]
|
28
|
+
|
29
|
+
# Header with date, time, log level and process info
|
30
|
+
message = "#{log.formatted_time} #{level_color}#{log.level_to_s}#{colors::CLEAR} [#{log.process_info}]"
|
31
|
+
|
32
|
+
# Tags
|
33
|
+
message << ' ' << log.tags.collect { |tag| "[#{level_color}#{tag}#{colors::CLEAR}]" }.join(' ') if log.tags && (log.tags.size > 0)
|
34
|
+
|
35
|
+
# Duration
|
36
|
+
message << " (#{colors::BOLD}#{log.duration_human}#{colors::CLEAR})" if log.duration
|
37
|
+
|
38
|
+
# Class / app name
|
39
|
+
message << " #{level_color}#{log.name}#{colors::CLEAR}"
|
40
|
+
|
41
|
+
# Log message
|
42
|
+
message << " -- #{log.message}" if log.message
|
43
|
+
|
44
|
+
# Payload: Colorize the payload if the AwesomePrint gem is loaded
|
45
|
+
if log.has_payload?
|
46
|
+
payload = log.payload
|
47
|
+
message << ' -- ' <<
|
48
|
+
if !defined?(AwesomePrint) || !payload.respond_to?(:ai)
|
49
|
+
payload.inspect
|
50
|
+
else
|
51
|
+
payload.ai(@ai_options) rescue payload.inspect
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
# Exceptions
|
56
|
+
if log.exception
|
57
|
+
message << " -- Exception: #{colors::BOLD}#{log.exception.class}: #{log.exception.message}#{colors::CLEAR}\n"
|
58
|
+
message << log.backtrace_to_s
|
59
|
+
end
|
60
|
+
message
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module SemanticLogger
|
2
|
+
module Formatters
|
3
|
+
class Default
|
4
|
+
# Default log formatter
|
5
|
+
# Generates logs of the form:
|
6
|
+
# 2011-07-19 14:36:15.660 D [1149:ScriptThreadProcess] Rails -- Hello World
|
7
|
+
def call(log, logger)
|
8
|
+
# Header with date, time, log level and process info
|
9
|
+
message = "#{log.formatted_time} #{log.level_to_s} [#{log.process_info}]"
|
10
|
+
|
11
|
+
# Tags
|
12
|
+
message << ' ' << log.tags.collect { |tag| "[#{tag}]" }.join(' ') if log.tags && (log.tags.size > 0)
|
13
|
+
|
14
|
+
# Duration
|
15
|
+
message << " (#{log.duration_human})" if log.duration
|
16
|
+
|
17
|
+
# Class / app name
|
18
|
+
message << " #{log.name}"
|
19
|
+
|
20
|
+
# Log message
|
21
|
+
message << " -- #{log.message}" if log.message
|
22
|
+
|
23
|
+
# Payload
|
24
|
+
if payload = log.payload_to_s
|
25
|
+
message << ' -- ' << payload
|
26
|
+
end
|
27
|
+
|
28
|
+
# Exceptions
|
29
|
+
if log.exception
|
30
|
+
message << " -- Exception: #{log.exception.class}: #{log.exception.message}\n"
|
31
|
+
message << log.backtrace_to_s
|
32
|
+
end
|
33
|
+
message
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'json'
|
2
|
+
module SemanticLogger
|
3
|
+
module Formatters
|
4
|
+
class Json
|
5
|
+
# Returns log messages in JSON format
|
6
|
+
def call(log, logger)
|
7
|
+
h = log.to_h
|
8
|
+
h.delete(:time)
|
9
|
+
h[:timestamp] = log.time.utc.iso8601(defined?(JRuby) ? 3 : 6)
|
10
|
+
h.to_json
|
11
|
+
end
|
12
|
+
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
@@ -18,7 +18,7 @@ module SemanticLogger
|
|
18
18
|
gc_info = info.gc_info
|
19
19
|
duration = gc_info.duration
|
20
20
|
if duration >= @min_microseconds
|
21
|
-
SemanticLogger['GarbageCollector'].
|
21
|
+
SemanticLogger['GarbageCollector'].measure_warn "Garbage Collection completed: #{info.gc_name} ##{gc_info.id}", duration: duration.to_f / 1000
|
22
22
|
end
|
23
23
|
end
|
24
24
|
end
|
data/lib/semantic_logger/log.rb
CHANGED
@@ -23,7 +23,7 @@ module SemanticLogger
|
|
23
23
|
# The time at which the log entry was created
|
24
24
|
#
|
25
25
|
# duration
|
26
|
-
# The time taken to complete a
|
26
|
+
# The time taken to complete a measure call
|
27
27
|
#
|
28
28
|
# tags
|
29
29
|
# Any tags active on the thread when the log call was made
|
@@ -35,11 +35,15 @@ module SemanticLogger
|
|
35
35
|
# Ruby Exception object to log
|
36
36
|
#
|
37
37
|
# metric [Object]
|
38
|
-
# Object supplied when
|
38
|
+
# Object supplied when measure_x was called
|
39
39
|
#
|
40
40
|
# backtrace [Array<String>]
|
41
41
|
# The backtrace captured at source when the log level >= SemanticLogger.backtrace_level
|
42
|
-
|
42
|
+
#
|
43
|
+
# metric_amount [Numeric]
|
44
|
+
# Used for numeric or counter metrics.
|
45
|
+
# For example, the number of inquiries or, the amount purchased etc.
|
46
|
+
Log = Struct.new(:level, :thread_name, :name, :message, :payload, :time, :duration, :tags, :level_index, :exception, :metric, :backtrace, :metric_amount) do
|
43
47
|
|
44
48
|
MAX_EXCEPTIONS_TO_UNWRAP = 5
|
45
49
|
# Call the block for exception and any nested exception
|
@@ -147,12 +151,13 @@ module SemanticLogger
|
|
147
151
|
|
148
152
|
# Return the payload in text form
|
149
153
|
# Returns nil if payload is missing or empty
|
150
|
-
def payload_to_s
|
151
|
-
|
152
|
-
|
154
|
+
def payload_to_s
|
155
|
+
payload.inspect if has_payload?
|
156
|
+
end
|
153
157
|
|
154
|
-
|
155
|
-
|
158
|
+
# Returns [true|false] whether the log entry has a payload
|
159
|
+
def has_payload?
|
160
|
+
!(payload.nil? || (payload.respond_to?(:empty?) && payload.empty?))
|
156
161
|
end
|
157
162
|
|
158
163
|
if defined? JRuby
|
@@ -9,7 +9,7 @@
|
|
9
9
|
#
|
10
10
|
# require 'semantic_logger'
|
11
11
|
# SemanticLogger.default_level = :debug
|
12
|
-
# SemanticLogger.add_appender(STDOUT)
|
12
|
+
# SemanticLogger.add_appender(io: STDOUT, formatter: :color)
|
13
13
|
#
|
14
14
|
# class ExternalSupplier
|
15
15
|
# # Create class and instance logger methods
|
@@ -19,7 +19,7 @@
|
|
19
19
|
# logger.debug "Calculating with amount", { amount: amount, name: name }
|
20
20
|
#
|
21
21
|
# # Measure and log on completion how long the call took to the external supplier
|
22
|
-
# logger.
|
22
|
+
# logger.measure_info "Calling external interface" do
|
23
23
|
# # Code to call the external supplier ...
|
24
24
|
# end
|
25
25
|
# end
|
@@ -3,6 +3,8 @@ module SemanticLogger
|
|
3
3
|
# Logger stores the class name to be used for all log messages so that every
|
4
4
|
# log message written by this instance will include the class name
|
5
5
|
class Logger < Base
|
6
|
+
include SemanticLogger::Concerns::Compatibility
|
7
|
+
|
6
8
|
# Returns a Logger instance
|
7
9
|
#
|
8
10
|
# Return the logger for a specific class, supports class specific log levels
|
@@ -95,18 +97,27 @@ module SemanticLogger
|
|
95
97
|
queue_size
|
96
98
|
end
|
97
99
|
|
98
|
-
# Supply a block to be called whenever a metric is seen during
|
100
|
+
# Supply a block to be called whenever a metric is seen during measure logging
|
99
101
|
#
|
100
102
|
# Parameters
|
101
103
|
# block
|
102
104
|
# The block to be called
|
103
105
|
#
|
104
106
|
# Example:
|
105
|
-
# SemanticLogger.on_metric do |
|
106
|
-
# puts "#{
|
107
|
+
# SemanticLogger.on_metric do |log|
|
108
|
+
# puts "#{log.metric} was received. Log Struct: #{log.inspect}"
|
107
109
|
# end
|
108
|
-
def self.on_metric(&block)
|
109
|
-
(
|
110
|
+
def self.on_metric(object = nil, &block)
|
111
|
+
raise('When supplying an object, it must support the #call method') if object && !object.respond_to?(:call)
|
112
|
+
(@@metric_subscribers ||= Concurrent::Array.new) << (object || block)
|
113
|
+
end
|
114
|
+
|
115
|
+
# Place log request on the queue for the Appender thread to write to each
|
116
|
+
# appender in the order that they were registered
|
117
|
+
def log(log, message = nil, progname = nil, &block)
|
118
|
+
# Compatibility with ::Logger
|
119
|
+
return add(log, message, progname, &block) unless log.is_a?(SemanticLogger::Log)
|
120
|
+
self.class.queue << log if @@appender_thread
|
110
121
|
end
|
111
122
|
|
112
123
|
private
|
@@ -120,12 +131,6 @@ module SemanticLogger
|
|
120
131
|
@@queue
|
121
132
|
end
|
122
133
|
|
123
|
-
# Place log request on the queue for the Appender thread to write to each
|
124
|
-
# appender in the order that they were registered
|
125
|
-
def log(log)
|
126
|
-
self.class.queue << log if @@appender_thread
|
127
|
-
end
|
128
|
-
|
129
134
|
# Internal logger for SemanticLogger
|
130
135
|
# For example when an appender is not working etc..
|
131
136
|
# By default logs to STDERR
|
@@ -219,13 +224,13 @@ module SemanticLogger
|
|
219
224
|
end
|
220
225
|
|
221
226
|
# Call Metric subscribers
|
222
|
-
def self.call_metric_subscribers(
|
227
|
+
def self.call_metric_subscribers(log)
|
223
228
|
# If no subscribers registered, then return immediately
|
224
229
|
return unless @@metric_subscribers
|
225
230
|
|
226
231
|
@@metric_subscribers.each do |subscriber|
|
227
232
|
begin
|
228
|
-
subscriber.call(
|
233
|
+
subscriber.call(log)
|
229
234
|
rescue Exception => exc
|
230
235
|
logger.error 'Exception calling metrics subscriber', exc
|
231
236
|
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module SemanticLogger
|
2
|
+
module Metrics
|
3
|
+
class NewRelic
|
4
|
+
def call(log)
|
5
|
+
metric = log.metric
|
6
|
+
# Add 'Custom/' prefix for NewRelic
|
7
|
+
metric = "Custom/#{metric}" unless metric.start_with?('Custom')
|
8
|
+
|
9
|
+
if duration = log.duration
|
10
|
+
# Convert duration to seconds
|
11
|
+
::NewRelic::Agent.record_metric(metric, duration / 1000.0)
|
12
|
+
else
|
13
|
+
::NewRelic::Agent.increment_metric(metric, log.metric_amount || 1)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'uri'
|
2
|
+
begin
|
3
|
+
require 'statsd-ruby'
|
4
|
+
rescue LoadError
|
5
|
+
raise 'Gem statsd-ruby is required for logging metrics. Please add the gem "statsd-ruby" to your Gemfile.'
|
6
|
+
end
|
7
|
+
|
8
|
+
module SemanticLogger
|
9
|
+
module Metrics
|
10
|
+
class Statsd
|
11
|
+
# Create Statsd metrics subscriber
|
12
|
+
#
|
13
|
+
# Parameters:
|
14
|
+
# url: [String]
|
15
|
+
# Valid URL to post to.
|
16
|
+
# Example:
|
17
|
+
# udp://localhost:8125
|
18
|
+
# Example, send all metrics to a particular namespace:
|
19
|
+
# udp://localhost:8125/namespace
|
20
|
+
# Default: udp://localhost:8125
|
21
|
+
def initialize(options = {})
|
22
|
+
options = options.dup
|
23
|
+
@url = options.delete(:url) || 'udp://localhost:8125'
|
24
|
+
uri = URI.parse(@url)
|
25
|
+
raise('Statsd only supports udp. Example: "udp://localhost:8125"') if uri.scheme != 'udp'
|
26
|
+
|
27
|
+
@statsd = ::Statsd.new(uri.host, uri.port)
|
28
|
+
path = uri.path.chomp('/')
|
29
|
+
@statsd.namespace = path.sub('/', '') if path != ''
|
30
|
+
end
|
31
|
+
|
32
|
+
def call(log)
|
33
|
+
metric = log.metric
|
34
|
+
if duration = log.duration
|
35
|
+
$statsd.timing(metric, duration)
|
36
|
+
else
|
37
|
+
amount = (log.metric_amount || 1).round
|
38
|
+
if amount < 0
|
39
|
+
amount.times { $statsd.decrement(metric) }
|
40
|
+
else
|
41
|
+
amount.times { $statsd.increment(metric) }
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -81,40 +81,59 @@ module SemanticLogger
|
|
81
81
|
# more information on custom formatters
|
82
82
|
#
|
83
83
|
# Parameters
|
84
|
-
#
|
85
|
-
#
|
86
|
-
#
|
87
|
-
#
|
88
|
-
#
|
89
|
-
#
|
90
|
-
#
|
91
|
-
#
|
92
|
-
#
|
93
|
-
#
|
94
|
-
# A
|
95
|
-
#
|
96
|
-
#
|
97
|
-
#
|
98
|
-
#
|
99
|
-
#
|
100
|
-
#
|
101
|
-
#
|
102
|
-
#
|
103
|
-
#
|
84
|
+
# file_name: [String]
|
85
|
+
# File name to write log messages to.
|
86
|
+
#
|
87
|
+
# Or,
|
88
|
+
# io: [IO]
|
89
|
+
# An IO Stream to log to.
|
90
|
+
# For example STDOUT, STDERR, etc.
|
91
|
+
#
|
92
|
+
# Or,
|
93
|
+
# appender: [Symbol|SemanticLogger::Appender::Base]
|
94
|
+
# A symbol identifying the appender to create.
|
95
|
+
# For example:
|
96
|
+
# :bugsnag, :elasticsearch, :graylog, :http, :mongodb, :new_relic, :splunk_http, :syslog, :wrapper
|
97
|
+
# Or,
|
98
|
+
# An instance of an appender derived from SemanticLogger::Appender::Base
|
99
|
+
# For example:
|
100
|
+
# SemanticLogger::Appender::Http.new(url: 'http://localhost:8088/path')
|
101
|
+
#
|
102
|
+
# Or,
|
103
|
+
# logger: [Logger|Log4r]
|
104
|
+
# An instance of a Logger or a Log4r logger.
|
105
|
+
#
|
106
|
+
# level: [:trace | :debug | :info | :warn | :error | :fatal]
|
107
|
+
# Override the log level for this appender.
|
108
|
+
# Default: SemanticLogger.default_level
|
109
|
+
#
|
110
|
+
# formatter: [Symbol|Object|Proc]
|
111
|
+
# Any of the following symbol values: :default, :color, :json
|
112
|
+
# Or,
|
113
|
+
# An instance of a class that implements #call
|
114
|
+
# Or,
|
115
|
+
# A Proc to be used to format the output from this appender
|
116
|
+
# Default: :default
|
117
|
+
#
|
118
|
+
# filter: [Regexp|Proc]
|
119
|
+
# RegExp: Only include log messages where the class name matches the supplied.
|
120
|
+
# regular expression. All other messages will be ignored.
|
121
|
+
# Proc: Only include log messages where the supplied Proc returns true
|
122
|
+
# The Proc must return true or false.
|
104
123
|
#
|
105
124
|
# Examples:
|
106
125
|
#
|
107
126
|
# # Send all logging output to Standard Out (Screen)
|
108
|
-
# SemanticLogger.add_appender(STDOUT)
|
127
|
+
# SemanticLogger.add_appender(io: STDOUT)
|
109
128
|
#
|
110
129
|
# # Send all logging output to a file
|
111
|
-
# SemanticLogger.add_appender('logfile.log')
|
130
|
+
# SemanticLogger.add_appender(file_name: 'logfile.log')
|
112
131
|
#
|
113
132
|
# # Send all logging output to a file and only :info and above to standard output
|
114
|
-
# SemanticLogger.add_appender('logfile.log')
|
115
|
-
# SemanticLogger.add_appender(STDOUT, :info)
|
133
|
+
# SemanticLogger.add_appender(file_name: 'logfile.log')
|
134
|
+
# SemanticLogger.add_appender(io: STDOUT, level: :info)
|
116
135
|
#
|
117
|
-
# Log to
|
136
|
+
# Log to log4r, Logger, etc.:
|
118
137
|
#
|
119
138
|
# # Send Semantic logging output to an existing logger
|
120
139
|
# require 'logger'
|
@@ -125,37 +144,19 @@ module SemanticLogger
|
|
125
144
|
# log.level = Logger::DEBUG
|
126
145
|
#
|
127
146
|
# SemanticLogger.default_level = :debug
|
128
|
-
# SemanticLogger.add_appender(log)
|
147
|
+
# SemanticLogger.add_appender(logger: log)
|
129
148
|
#
|
130
149
|
# logger = SemanticLogger['Example']
|
131
150
|
# logger.info "Hello World"
|
132
151
|
# logger.debug("Login time", user: 'Joe', duration: 100, ip_address: '127.0.0.1')
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
# $stderr, STDOUT, other IO, or a filename
|
138
|
-
SemanticLogger::Appender::File.new(appender, level, &block)
|
139
|
-
elsif appender.is_a? Appender::Base
|
140
|
-
# Already an instance of an appender
|
141
|
-
appender.level = level if level
|
142
|
-
appender.formatter = block if block
|
143
|
-
appender
|
144
|
-
else
|
145
|
-
# Check if the custom appender responds to all the log levels. For example Ruby ::Logger
|
146
|
-
if does_not_implement = LEVELS[1..-1].find { |i| !appender.respond_to?(i) }
|
147
|
-
raise "Supplied appender does not implement:#{does_not_implement}. It must implement all of #{LEVELS[1..-1].inspect}"
|
148
|
-
end
|
149
|
-
|
150
|
-
raise "Change the log level to #{level}, update the log level directly against the supplied appender" if level
|
151
|
-
SemanticLogger::Appender::Wrapper.new(appender, &block)
|
152
|
-
end
|
153
|
-
@@appenders << appender_instance
|
152
|
+
def self.add_appender(options, deprecated_level = nil, &block)
|
153
|
+
options = options.is_a?(Hash) ? options.dup : convert_old_appender_args(options, deprecated_level)
|
154
|
+
appender = appender_from_options(options, &block)
|
155
|
+
@@appenders << appender
|
154
156
|
|
155
157
|
# Start appender thread if it is not already running
|
156
158
|
SemanticLogger::Logger.start_appender_thread
|
157
|
-
|
158
|
-
appender_instance
|
159
|
+
appender
|
159
160
|
end
|
160
161
|
|
161
162
|
# Remove an existing appender
|
@@ -188,18 +189,18 @@ module SemanticLogger
|
|
188
189
|
SemanticLogger::Logger.start_appender_thread
|
189
190
|
end
|
190
191
|
|
191
|
-
# Supply a block to be called whenever a metric is seen during
|
192
|
+
# Supply a block to be called whenever a metric is seen during measure logging
|
192
193
|
#
|
193
194
|
# Parameters
|
194
195
|
# block
|
195
196
|
# The block to be called
|
196
197
|
#
|
197
198
|
# Example:
|
198
|
-
# SemanticLogger.on_metric do |
|
199
|
-
# puts "#{
|
199
|
+
# SemanticLogger.on_metric do |log|
|
200
|
+
# puts "#{log.metric} was received. Log Struct: #{log.inspect}"
|
200
201
|
# end
|
201
|
-
def self.on_metric(&block)
|
202
|
-
SemanticLogger::Logger.on_metric(&block)
|
202
|
+
def self.on_metric(object = nil, &block)
|
203
|
+
SemanticLogger::Logger.on_metric(object, &block)
|
203
204
|
end
|
204
205
|
|
205
206
|
# Add signal handlers for Semantic Logger
|
@@ -279,7 +280,7 @@ module SemanticLogger
|
|
279
280
|
end
|
280
281
|
|
281
282
|
# Returns the symbolic level for the supplied level index
|
282
|
-
def index_to_level(level_index)
|
283
|
+
def self.index_to_level(level_index)
|
283
284
|
LEVELS[level_index]
|
284
285
|
end
|
285
286
|
|
@@ -309,6 +310,72 @@ module SemanticLogger
|
|
309
310
|
index
|
310
311
|
end
|
311
312
|
|
313
|
+
# Backward compatibility
|
314
|
+
def self.convert_old_appender_args(appender, level)
|
315
|
+
options = {}
|
316
|
+
options[:level] = level if level
|
317
|
+
|
318
|
+
if appender.is_a?(String)
|
319
|
+
options[:file_name] = appender
|
320
|
+
elsif appender.is_a?(IO)
|
321
|
+
options[:io] = appender
|
322
|
+
elsif appender.is_a?(Symbol) || appender.is_a?(Appender::Base)
|
323
|
+
options[:appender] = appender
|
324
|
+
else
|
325
|
+
options[:logger] = appender
|
326
|
+
end
|
327
|
+
warn "[DEPRECATED] SemanticLogger.add_appender parameters have changed. Please use: #{options.inspect}"
|
328
|
+
options
|
329
|
+
end
|
330
|
+
|
331
|
+
# Returns [SemanticLogger::Appender::Base] appender for the supplied options
|
332
|
+
def self.appender_from_options(options, &block)
|
333
|
+
if options[:io] || options[:file_name]
|
334
|
+
SemanticLogger::Appender::File.new(options, &block)
|
335
|
+
elsif appender = options.delete(:appender)
|
336
|
+
if appender.is_a?(Symbol)
|
337
|
+
named_appender(appender).new(options)
|
338
|
+
elsif appender.is_a?(Appender::Base)
|
339
|
+
appender
|
340
|
+
else
|
341
|
+
raise(ArgumentError, "Parameter :appender must be either a Symbol or an object derived from SemanticLogger::Appender::Base, not: #{appender.inspect}")
|
342
|
+
end
|
343
|
+
elsif options[:logger]
|
344
|
+
SemanticLogger::Appender::Wrapper.new(options, &block)
|
345
|
+
end
|
346
|
+
end
|
347
|
+
|
348
|
+
def self.named_appender(appender)
|
349
|
+
appender = appender.to_s
|
350
|
+
klass = appender.respond_to?(:camelize) ? appender.camelize : camelize(appender)
|
351
|
+
klass = "SemanticLogger::Appender::#{klass}"
|
352
|
+
begin
|
353
|
+
appender.respond_to?(:constantize) ? klass.constantize : eval(klass)
|
354
|
+
rescue NameError
|
355
|
+
raise(ArgumentError, "Could not find appender class: #{klass} for #{appender}")
|
356
|
+
end
|
357
|
+
end
|
358
|
+
|
359
|
+
def self.named_formatter(formatter)
|
360
|
+
formatter = formatter.to_s
|
361
|
+
klass = formatter.respond_to?(:camelize) ? formatter.camelize : camelize(formatter)
|
362
|
+
klass = "SemanticLogger::Formatters::#{klass}"
|
363
|
+
begin
|
364
|
+
formatter.respond_to?(:constantize) ? klass.constantize : eval(klass)
|
365
|
+
rescue NameError => exc
|
366
|
+
raise(ArgumentError, "Could not find formatter class: #{klass} for #{appender}")
|
367
|
+
end
|
368
|
+
end
|
369
|
+
|
370
|
+
# Borrow from Rails, when not running Rails
|
371
|
+
def self.camelize(term)
|
372
|
+
string = term.to_s
|
373
|
+
string = string.sub(/^[a-z\d]*/) { |match| match.capitalize }
|
374
|
+
string.gsub!(/(?:_|(\/))([a-z\d]*)/i) { "#{$1}#{inflections.acronyms[$2] || $2.capitalize}" }
|
375
|
+
string.gsub!('/'.freeze, '::'.freeze)
|
376
|
+
string
|
377
|
+
end
|
378
|
+
|
312
379
|
# Initial default Level for all new instances of SemanticLogger::Logger
|
313
380
|
@@default_level = :info
|
314
381
|
@@default_level_index = level_to_index(@@default_level)
|