semantic_logger 2.21.0 → 3.0.0

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