semantic_logger 2.21.0 → 3.0.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 7835135546f3ebf18ce484c594cd52fef0d4ecee
4
- data.tar.gz: 12cd7ddcbf431f070a0b57792ad436f100aca649
3
+ metadata.gz: 16e4711a6003653a8d7cf1668fe3180e10493e43
4
+ data.tar.gz: c0266b7ebb30904275543fc083e553260bead056
5
5
  SHA512:
6
- metadata.gz: cfb139be7ea5cb63d9787638e4e2e2bc464c8bd0bf49f60a9447b4b2b28033e66de8766c8c5b648e544d8bd3068813765d13cee9275130f2823416881e20bfde
7
- data.tar.gz: 92e4e1fc6e445696c04596f4f12839d6504d32a62df005baa83e82adb2b4ed4343b9a808193104bfd615ac159ceab7631e5cb36e70457c265efb6de1cb475e18
6
+ metadata.gz: cdbf75bce867ba9fae2a524447d62f65093fc6ada2cb2214b67f599b5ee77b3d997ffb29e3e6db34efb09fdab24b8cc662700b664a58835aa1d88763f4d893b7
7
+ data.tar.gz: 3eff413a5f6a09af3f4aa84b7eaf717bd10cedff41d49202d0882442ba53e3519aff4b88c37a06bcc5703e9b744c2dbbc6f5533948c24cfd03fd9bc90905412e
data/LICENSE.txt CHANGED
@@ -186,7 +186,7 @@
186
186
  same "printed page" as the copyright notice for easier
187
187
  identification within third-party archives.
188
188
 
189
- Copyright 2012, 2013, 2014 Reid Morrison
189
+ Copyright 2012, 2013, 2014, 2015, 2016 Reid Morrison
190
190
 
191
191
  Licensed under the Apache License, Version 2.0 (the "License");
192
192
  you may not use this file except in compliance with the License.
@@ -5,20 +5,24 @@ require 'semantic_logger/semantic_logger'
5
5
  # @formatter:off
6
6
  module SemanticLogger
7
7
  autoload :Base, 'semantic_logger/base'
8
+ autoload :DebugAsTraceLogger, 'semantic_logger/debug_as_trace_logger'
8
9
  autoload :Log, 'semantic_logger/log'
9
10
  autoload :Logger, 'semantic_logger/logger'
10
11
  autoload :Loggable, 'semantic_logger/loggable'
11
- autoload :DebugAsTraceLogger, 'semantic_logger/debug_as_trace_logger'
12
12
 
13
13
  module Appender
14
- autoload :Base, 'semantic_logger/appender/base'
15
- autoload :File, 'semantic_logger/appender/file'
16
- autoload :Wrapper, 'semantic_logger/appender/wrapper'
17
- autoload :MongoDB, 'semantic_logger/appender/mongodb'
18
- autoload :Syslog, 'semantic_logger/appender/syslog'
19
- autoload :NewRelic, 'semantic_logger/appender/new_relic'
20
- autoload :Splunk, 'semantic_logger/appender/splunk'
21
- autoload :Bugsnag, 'semantic_logger/appender/bugsnag'
14
+ autoload :Base, 'semantic_logger/appender/base'
15
+ autoload :Bugsnag, 'semantic_logger/appender/bugsnag'
16
+ autoload :Elasticsearch, 'semantic_logger/appender/elasticsearch'
17
+ autoload :File, 'semantic_logger/appender/file'
18
+ autoload :Graylog, 'semantic_logger/appender/graylog'
19
+ autoload :Http, 'semantic_logger/appender/http'
20
+ autoload :MongoDB, 'semantic_logger/appender/mongodb'
21
+ autoload :NewRelic, 'semantic_logger/appender/new_relic'
22
+ autoload :Splunk, 'semantic_logger/appender/splunk'
23
+ autoload :SplunkHttp, 'semantic_logger/appender/splunk_http'
24
+ autoload :Syslog, 'semantic_logger/appender/syslog'
25
+ autoload :Wrapper, 'semantic_logger/appender/wrapper'
22
26
  end
23
27
  # @formatter:on
24
28
 
@@ -48,7 +48,7 @@ module SemanticLogger
48
48
  # Generates logs of the form:
49
49
  # 2011-07-19 14:36:15.660 D [1149:ScriptThreadProcess] Rails -- Hello World
50
50
  def default_formatter
51
- Proc.new do |log|
51
+ Proc.new do |log, logger|
52
52
  # Header with date, time, log level and process info
53
53
  entry = "#{log.formatted_time} #{log.level_to_s} [#{log.process_info}]"
54
54
 
@@ -70,9 +70,9 @@ module SemanticLogger
70
70
  end
71
71
 
72
72
  # Exceptions
73
- log.each_exception do |exception, i|
74
- entry << (i == 0 ? ' -- Exception: ' : "\nCause: ")
75
- entry << "#{exception.class}: #{exception.message}\n#{(exception.backtrace || []).join("\n")}"
73
+ if log.exception
74
+ entry << " -- Exception: #{log.exception.class}: #{log.exception.message}\n"
75
+ entry << log.backtrace_to_s
76
76
  end
77
77
  entry
78
78
  end
@@ -84,7 +84,7 @@ module SemanticLogger
84
84
  #
85
85
  # 2011-07-19 14:36:15.660 D [1149:ScriptThreadProcess] Rails -- Hello World
86
86
  def self.colorized_formatter
87
- Proc.new do |log|
87
+ Proc.new do |log, logger|
88
88
  colors = SemanticLogger::Appender::AnsiColors
89
89
  level_color = colors::LEVEL_MAP[log.level]
90
90
 
@@ -109,14 +109,26 @@ module SemanticLogger
109
109
  end
110
110
 
111
111
  # Exceptions
112
- log.each_exception do |exception, i|
113
- entry << (i == 0 ? ' -- Exception: ' : "\nCause: ")
114
- entry << "#{colors::BOLD}#{exception.class}: #{exception.message}#{colors::CLEAR}\n#{(exception.backtrace || []).join("\n")}"
112
+ if log.exception
113
+ entry << " -- Exception: #{colors::BOLD}#{log.exception.class}: #{log.exception.message}#{colors::CLEAR}\n"
114
+ entry << log.backtrace_to_s
115
115
  end
116
116
  entry
117
117
  end
118
118
  end
119
119
 
120
+ # Optional log formatter to output data in a hash format
121
+ # To use this formatter
122
+ # SemanticLogger.add_appender($stdout, &SemanticLogger::Appender::Base.json_formatter)
123
+ def self.json_formatter
124
+ Proc.new do |log, logger|
125
+ h = log.to_h
126
+ h.delete(:time)
127
+ h[:timestamp] = log.time.utc.iso8601(defined?(JRuby) ? 3 : 6)
128
+ h.to_json
129
+ end
130
+ end
131
+
120
132
  def flush
121
133
  # An appender can implement a flush method if it supports it.
122
134
  end
@@ -157,22 +169,6 @@ module SemanticLogger
157
169
  @level_index || 0
158
170
  end
159
171
 
160
- if defined? Java
161
- # Return the Time as a formatted string
162
- # JRuby only supports time in ms
163
- def self.formatted_time(time)
164
- warn '[deprecated] SemanticLogger::Base.formatted_time is deprecated please use log.formatted_time'
165
- "#{time.strftime('%Y-%m-%d %H:%M:%S')}.#{'%03d' % (time.usec/1000)}"
166
- end
167
- else
168
- # Return the Time as a formatted string
169
- # Ruby MRI supports micro seconds
170
- def self.formatted_time(time)
171
- warn '[deprecated] SemanticLogger::Base.formatted_time is deprecated please use log.formatted_time'
172
- "#{time.strftime('%Y-%m-%d %H:%M:%S')}.#{'%06d' % (time.usec)}"
173
- end
174
- end
175
-
176
172
  end
177
173
  end
178
174
  end
@@ -1,53 +1,35 @@
1
- =begin
2
- Bugsnag appender for SemanticLogger
3
-
4
- Skips the fatal log level because unrescued exceptions get logged as fatal and will be reported automatically by Bugsnag.
5
-
6
- Note: Payload information is not filtered, so take care not to push any sensitive information when logging with tags or a payload.
7
-
8
- Example 1
9
-
10
- Adding the Bugsnag appender will send :error log entries to Bugsnag with the error severity.
11
-
12
- For a Rails application already configured to use SemanticLogger and Bugsnag, create a file called <Rails Root>/config/initializers/bugsnag_appender.rb with the following contents and restart the application:
13
-
14
- # Send :error and log messages to Bugsnag
15
- SemanticLogger.add_appender(SemanticLogger::Appender::Bugsnag.new)
16
- Rails.logger.info 'SemanticLogger Bugsnag Appender added.'
17
-
18
- Example 2
19
-
20
- For a non-Rails application, send :info and more severe log entries to a file called application.log and also send :error log entries to Bugsnag.
21
-
22
- require 'semantic_logger'
23
- require 'bugsnag'
24
-
25
- # Bugsnag setup
26
- Bugsnag.configure do |config|
27
- config.api_key = 'abc123'
1
+ begin
2
+ require 'bugsnag'
3
+ rescue LoadError
4
+ raise 'Gem bugsnag is required for logging purposes. Please add the gem "bugsnag" to your Gemfile.'
28
5
  end
29
6
 
30
- # SemanticLogger setup
31
- SemanticLogger.default_level = :info
32
- SemanticLogger.add_appender('application.log')
33
- SemanticLogger.add_appender(SemanticLogger::Appender::Bugsnag.new)
34
- logger = SemanticLogger['Example']
35
-
36
- # Log some messages
37
- logger.info 'This is only written to application.log'
38
- logger.error 'This is written to application.log and will also be sent to Bugsnag as an error event'
39
-
40
- # The appender will send payloads to Bugsnag
41
- logger.error 'Something bad happened', info: 'Related information'
42
- =end
43
-
44
- require 'bugsnag'
45
-
7
+ # Send log messages to Bugsnag
8
+ #
9
+ # Example:
10
+ # SemanticLogger.add_appender(SemanticLogger::Appender::Bugsnag.new)
11
+ #
46
12
  class SemanticLogger::Appender::Bugsnag < SemanticLogger::Appender::Base
47
- # Allow the level for this appender to be overwritten
48
- # Default: :error
49
- # Note: Not recommended to set the log level to :info, :debug, or :trace as that would flood Bugsnag with Error notices
50
- def initialize(level = :error, &block)
13
+ # Create Appender
14
+ #
15
+ # Parameters
16
+ # level: [:trace | :debug | :info | :warn | :error | :fatal]
17
+ # Override the log level for this appender.
18
+ # Default: :error
19
+ #
20
+ # filter: [Regexp|Proc]
21
+ # RegExp: Only include log messages where the class name matches the supplied.
22
+ # regular expression. All other messages will be ignored.
23
+ # Proc: Only include log messages where the supplied Proc returns true
24
+ # The Proc must return true or false.
25
+ def initialize(options = {}, &block)
26
+ options = {level: options} unless options.is_a?(Hash)
27
+ @options = options.dup
28
+ level = @options.delete(:level) || :error
29
+ filter = @options.delete(:filter)
30
+
31
+ raise 'Bugsnag only supports :info, :warn, or :error log levels' unless [:info, :warn, :error].include?(level)
32
+
51
33
  # Replace the Bugsnag logger so that we can identify its log messages and not forward them to Bugsnag
52
34
  Bugsnag.configure { |config| config.logger = SemanticLogger[Bugsnag] }
53
35
  super(level, &block)
@@ -55,10 +37,11 @@ class SemanticLogger::Appender::Bugsnag < SemanticLogger::Appender::Base
55
37
 
56
38
  # Returns [Hash] of parameters to send to Bugsnag.
57
39
  def default_formatter
58
- proc do |log|
59
- h = {severity: log_level(log), tags: log.tags, class: log.name}
60
- h[:message] = log.message if log.exception
61
- h.merge!(log.payload) if log.payload
40
+ Proc.new do |log|
41
+ h = log.to_h
42
+ h[:severity] = log_level(log)
43
+ h.delete(:time)
44
+ h.delete(:exception)
62
45
  h
63
46
  end
64
47
  end
@@ -68,7 +51,7 @@ class SemanticLogger::Appender::Bugsnag < SemanticLogger::Appender::Base
68
51
  # Only log if level is warn, or error.
69
52
  return false if (level_index > (log.level_index || 0)) ||
70
53
  # We don't want to send fatal as those are already captured by Bugsnag.
71
- (log.level == :fatal) ||
54
+ #(log.level == :fatal) ||
72
55
  # Ignore logs coming from Bugsnag itself
73
56
  (log.name == 'Bugsnag') ||
74
57
  # Filtered out?
@@ -83,9 +66,10 @@ class SemanticLogger::Appender::Bugsnag < SemanticLogger::Appender::Base
83
66
  error.set_backtrace(log.backtrace) if log.backtrace
84
67
  error
85
68
  end
69
+
86
70
  # For more documentation on the Bugsnag.notify method see:
87
71
  # https://bugsnag.com/docs/notifiers/ruby#sending-handled-exceptions
88
- Bugsnag.notify(exception, formatter.call(log))
72
+ Bugsnag.notify(exception, formatter.call(log, self))
89
73
  true
90
74
  end
91
75
 
@@ -0,0 +1,53 @@
1
+ require 'date'
2
+ # Forward all log messages to Elasticsearch.
3
+ #
4
+ # Example:
5
+ # appender = SemanticLogger::Appender::Elasticsearch.new(
6
+ # url: 'http://localhost:9200'
7
+ # )
8
+ #
9
+ # # Optional: Exclude health_check log entries
10
+ # appender.filter = Proc.new { |log| log.message !~ /(health_check|Not logged in)/}
11
+ #
12
+ # SemanticLogger.add_appender(appender)
13
+ #
14
+ class SemanticLogger::Appender::Elasticsearch < SemanticLogger::Appender::Http
15
+ attr_accessor :index, :type
16
+
17
+ # Create Elasticsearch appender over persistent HTTP(S)
18
+ #
19
+ # Parameters:
20
+ # index: [String]
21
+ # Index to store the logs in Elasticsearch.
22
+ # Default: 'semantic_logger-YYYY.MM.DD'
23
+ #
24
+ # type: [String]
25
+ # Document type to associate with logs when they are written.
26
+ # Default: 'log'
27
+ #
28
+ # level: [:trace | :debug | :info | :warn | :error | :fatal]
29
+ # Override the log level for this appender.
30
+ # Default: SemanticLogger.default_level
31
+ #
32
+ # filter: [Regexp|Proc]
33
+ # RegExp: Only include log messages where the class name matches the supplied.
34
+ # regular expression. All other messages will be ignored.
35
+ # Proc: Only include log messages where the supplied Proc returns true
36
+ # The Proc must return true or false.
37
+ def initialize(options, &block)
38
+ options = options.dup
39
+ @index = options.delete(:index) || "semantic_logger-#{Date.today.to_s.gsub('-', '.')}"
40
+ @type = options.delete(:type) || 'log'
41
+ options[:url] ||= 'http://localhost:9200'
42
+
43
+ super(options, &block)
44
+
45
+ @request_uri = "#{@index}/#{@type}"
46
+ end
47
+
48
+ # Deletes all log data captured for this index
49
+ def delete_all
50
+ delete(index)
51
+ end
52
+
53
+ end
@@ -6,7 +6,22 @@ module SemanticLogger
6
6
  module Appender
7
7
  class File < SemanticLogger::Appender::Base
8
8
 
9
- # Create a File Logger appender instance
9
+ # Create a File Logger appender instance.
10
+ #
11
+ # Parameters
12
+ # filename [String|IO]
13
+ # Name of file to write to.
14
+ # Or, an IO stream to which to write the log message to.
15
+ #
16
+ # level [:trace | :debug | :info | :warn | :error | :fatal]
17
+ # Override the log level for this appender.
18
+ # Default: SemanticLogger.default_level
19
+ #
20
+ # filter [Regexp|Proc]
21
+ # RegExp: Only include log messages where the class name matches the supplied
22
+ # regular expression. All other messages will be ignored.
23
+ # Proc: Only include log messages where the supplied Proc returns true
24
+ # The Proc must return true or false.
10
25
  #
11
26
  # Example
12
27
  # require 'semantic_logger'
@@ -38,7 +53,6 @@ module SemanticLogger
38
53
  #
39
54
  # logger = SemanticLogger['test']
40
55
  # logger.info 'Hello World'
41
- #
42
56
  def initialize(filename, level=nil, filter=nil, &block)
43
57
  raise 'filename cannot be null when initializing the SemanticLogging::Appender::File' unless filename
44
58
  @log =
@@ -79,7 +93,7 @@ module SemanticLogger
79
93
  # Since only one appender thread will be writing to the file at a time
80
94
  # it is not necessary to protect access to the file with a semaphore
81
95
  # Allow this logger to filter out log levels lower than it's own
82
- @log.write(@formatter.call(log) << "\n")
96
+ @log.write(@formatter.call(log, self) << "\n")
83
97
  true
84
98
  end
85
99
 
@@ -0,0 +1,123 @@
1
+ require 'uri'
2
+ begin
3
+ require 'gelf'
4
+ rescue LoadError
5
+ raise 'Gem gelf is required for logging to Graylog. Please add the gem "gelf" to your Gemfile.'
6
+ end
7
+
8
+ # Forward log entries to a Graylog server.
9
+ #
10
+ # Example:
11
+ # appender = SemanticLogger::Appender::Graylog.new(
12
+ # url: 'udp://localhost:12201'
13
+ # )
14
+ #
15
+ # # Optional: Add filter to exclude health_check, or other log entries
16
+ # appender.filter = Proc.new { |log| log.message !~ /(health_check|Not logged in)/ }
17
+ #
18
+ # SemanticLogger.add_appender(appender)
19
+ #
20
+ # Notes:
21
+ # * trace is not supported by Graylog, so trace level logging will appear as debug in Graylog.
22
+ #
23
+ # In the Graylog Web UI search screen, it is recommended to include the following fields:
24
+ # `duration`, `level`, `message`, `metric`, `name`, `tags
25
+ class SemanticLogger::Appender::Graylog < SemanticLogger::Appender::Base
26
+ # Map Semantic Logger levels to Graylog levels
27
+ LEVEL_MAP = {
28
+ fatal: GELF::FATAL,
29
+ error: GELF::ERROR,
30
+ warn: GELF::WARN,
31
+ info: GELF::INFO,
32
+ debug: GELF::DEBUG,
33
+ trace: GELF::DEBUG
34
+ }
35
+
36
+ attr_reader :notifier
37
+
38
+ # Create Graylog log appender.
39
+ #
40
+ # Options:
41
+ # url: [String]
42
+ # Valid URL to post to.
43
+ # Log to UDP Example:
44
+ # 'udp://localhost:12201'
45
+ # Log to TCP Example:
46
+ # 'tcp://localhost:12201'
47
+ # Default: 'udp://localhost:12201'
48
+ #
49
+ # host: [String]
50
+ # Name of this host to appear in log messages.
51
+ # Default: Socket.gethostname
52
+ #
53
+ # application: [String]
54
+ # Name of this application to appear in log messages.
55
+ # Default: SemanticLogger.application
56
+ #
57
+ # max_size: [String]
58
+ # Max udp packet size. Ignored when protocol is :tcp
59
+ # Default: "WAN"
60
+ #
61
+ # level: [:trace | :debug | :info | :warn | :error | :fatal]
62
+ # Override the log level for this appender.
63
+ # Default: SemanticLogger.default_level
64
+ #
65
+ # filter: [Regexp|Proc]
66
+ # RegExp: Only include log messages where the class name matches the supplied.
67
+ # regular expression. All other messages will be ignored.
68
+ # Proc: Only include log messages where the supplied Proc returns true
69
+ # The Proc must return true or false.
70
+ def initialize(options = {}, &block)
71
+ @options = options.dup
72
+ level = @options.delete(:level)
73
+ filter = @options.delete(:filter)
74
+ @url = options.delete(:url) || 'udp://localhost:12201'
75
+ @max_size = @options.delete(:max_size) || 'WAN'
76
+
77
+ uri = URI.parse(@url)
78
+ @server = uri.host
79
+ @port = uri.port
80
+ protocol = uri.scheme.to_sym
81
+
82
+ raise(ArgumentError, "Invalid protocol value: #{protocol}. Must be :udp or :tcp") unless [:udp, :tcp].include?(protocol)
83
+
84
+ @options[:protocol] = protocol == :tcp ? GELF::Protocol::TCP : GELF::Protocol::UDP
85
+ @options[:facility] = @options.delete(:application) || SemanticLogger.application
86
+ reopen
87
+ super(level, filter, &block)
88
+ end
89
+
90
+ # Re-open after process fork
91
+ def reopen
92
+ @notifier = GELF::Notifier.new(@server, @port, @max_size, @options)
93
+ @notifier.collect_file_and_line = false
94
+ end
95
+
96
+ # Returns [Hash] of parameters to send
97
+ def default_formatter
98
+ Proc.new do |log, logger|
99
+ h = log.to_h
100
+ h.delete(:time)
101
+ h[:timestamp] = log.time.utc.to_f
102
+ h[:level] = logger.map_level(log)
103
+ h[:level_str] = log.level.to_s
104
+ h[:short_message] = h.delete(:message) if log.message
105
+ h
106
+ end
107
+ end
108
+
109
+ # Forward log messages
110
+ def log(log)
111
+ return false if (level_index > (log.level_index || 0)) ||
112
+ !include_message?(log) # Filtered out?
113
+
114
+ @notifier.notify!(formatter.call(log, self))
115
+ true
116
+ end
117
+
118
+ # Returns the Graylog level for the supplied log message
119
+ def map_level(log)
120
+ LEVEL_MAP[log.level]
121
+ end
122
+
123
+ end