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 +4 -4
- data/LICENSE.txt +1 -1
- data/lib/semantic_logger.rb +13 -9
- data/lib/semantic_logger/appender/base.rb +20 -24
- data/lib/semantic_logger/appender/bugsnag.rb +37 -53
- data/lib/semantic_logger/appender/elasticsearch.rb +53 -0
- data/lib/semantic_logger/appender/file.rb +17 -3
- data/lib/semantic_logger/appender/graylog.rb +123 -0
- data/lib/semantic_logger/appender/http.rb +169 -0
- data/lib/semantic_logger/appender/mongodb.rb +90 -111
- data/lib/semantic_logger/appender/new_relic.rb +38 -72
- data/lib/semantic_logger/appender/splunk.rb +10 -5
- data/lib/semantic_logger/appender/splunk_http.rb +99 -0
- data/lib/semantic_logger/appender/syslog.rb +116 -103
- data/lib/semantic_logger/appender/wrapper.rb +26 -11
- data/lib/semantic_logger/base.rb +13 -16
- data/lib/semantic_logger/log.rb +85 -5
- data/lib/semantic_logger/logger.rb +1 -1
- data/lib/semantic_logger/semantic_logger.rb +24 -0
- data/lib/semantic_logger/version.rb +1 -1
- data/test/appender/bugsnag_test.rb +39 -41
- data/test/appender/graylog_test.rb +63 -0
- data/test/appender/http_test.rb +61 -0
- data/test/appender/mongodb_test.rb +20 -20
- data/test/appender/new_relic_test.rb +4 -3
- data/test/appender/splunk_http_test.rb +78 -0
- data/test/logger_test.rb +1 -1
- metadata +27 -3
@@ -0,0 +1,169 @@
|
|
1
|
+
require 'net/http'
|
2
|
+
require 'uri'
|
3
|
+
require 'socket'
|
4
|
+
require 'json'
|
5
|
+
|
6
|
+
# Log to any HTTP(S) server that accepts log messages in JSON form
|
7
|
+
#
|
8
|
+
# Features:
|
9
|
+
# * JSON Formatted messages.
|
10
|
+
# * Uses a persistent http connection, if the server supports it.
|
11
|
+
# * SSL encryption (https).
|
12
|
+
#
|
13
|
+
# Example:
|
14
|
+
# appender = SemanticLogger::Appender::Http.new(
|
15
|
+
# url: 'http://localhost:8088/path'
|
16
|
+
# )
|
17
|
+
#
|
18
|
+
# # Optional: Exclude health_check log entries, etc.
|
19
|
+
# appender.filter = Proc.new { |log| log.message !~ /(health_check|Not logged in)/}
|
20
|
+
#
|
21
|
+
# SemanticLogger.add_appender(appender)
|
22
|
+
class SemanticLogger::Appender::Http < SemanticLogger::Appender::Base
|
23
|
+
attr_accessor :username, :application, :host, :compress, :header
|
24
|
+
attr_reader :http, :url, :server, :port, :request_uri, :ssl_options
|
25
|
+
|
26
|
+
# Create HTTP(S) log appender
|
27
|
+
#
|
28
|
+
# Parameters:
|
29
|
+
# url: [String]
|
30
|
+
# Valid URL to post to.
|
31
|
+
# Example: http://example.com/some_path
|
32
|
+
# To enable SSL include https in the URL.
|
33
|
+
# Example: https://example.com/some_path
|
34
|
+
# verify_mode will default: OpenSSL::SSL::VERIFY_PEER
|
35
|
+
#
|
36
|
+
# application: [String]
|
37
|
+
# Name of this application to appear in log messages.
|
38
|
+
# Default: SemanticLogger.application
|
39
|
+
#
|
40
|
+
# host: [String]
|
41
|
+
# Name of this host to appear in log messages.
|
42
|
+
# Default: SemanticLogger.host
|
43
|
+
#
|
44
|
+
# username: [String]
|
45
|
+
# User name for basic Authentication.
|
46
|
+
# Default: nil ( do not use basic auth )
|
47
|
+
#
|
48
|
+
# password: [String]
|
49
|
+
# Password for basic Authentication.
|
50
|
+
#
|
51
|
+
# compress: [true|false]
|
52
|
+
# Whether to compress the JSON string with GZip.
|
53
|
+
# Default: false
|
54
|
+
#
|
55
|
+
# ssl: [Hash]
|
56
|
+
# Specific SSL options: For more details see NET::HTTP.start
|
57
|
+
# ca_file, ca_path, cert, cert_store, ciphers, key, open_timeout, read_timeout, ssl_timeout,
|
58
|
+
# ssl_version, use_ssl, verify_callback, verify_depth and verify_mode.
|
59
|
+
#
|
60
|
+
# level: [:trace | :debug | :info | :warn | :error | :fatal]
|
61
|
+
# Override the log level for this appender.
|
62
|
+
# Default: SemanticLogger.default_level
|
63
|
+
#
|
64
|
+
# filter: [Regexp|Proc]
|
65
|
+
# RegExp: Only include log messages where the class name matches the supplied.
|
66
|
+
# regular expression. All other messages will be ignored.
|
67
|
+
# Proc: Only include log messages where the supplied Proc returns true
|
68
|
+
# The Proc must return true or false.
|
69
|
+
def initialize(options, &block)
|
70
|
+
@options = options.dup
|
71
|
+
level = @options.delete(:level)
|
72
|
+
filter = @options.delete(:filter)
|
73
|
+
@url = options.delete(:url)
|
74
|
+
@ssl_options = options.delete(:ssl)
|
75
|
+
@username = options.delete(:username)
|
76
|
+
@password = options.delete(:password)
|
77
|
+
@application = options.delete(:application) || 'Semantic Logger'
|
78
|
+
@host = options.delete(:host) || SemanticLogger.host
|
79
|
+
@compress = options.delete(:compress) || false
|
80
|
+
raise(ArgumentError, "Unknown options: #{options.inspect}") if options.size > 0
|
81
|
+
|
82
|
+
raise(ArgumentError, 'Missing mandatory parameter :url') unless @url
|
83
|
+
|
84
|
+
@header = {
|
85
|
+
'Accept' => 'application/json',
|
86
|
+
'Content-Type' => 'application/json'
|
87
|
+
}
|
88
|
+
@header['Content-Encoding'] = 'gzip' if @compress
|
89
|
+
|
90
|
+
uri = URI.parse(@url)
|
91
|
+
(@ssl_options ||= {})[:use_ssl] = true if uri.scheme == 'https'
|
92
|
+
|
93
|
+
@server = uri.host
|
94
|
+
@port = uri.port
|
95
|
+
@username = uri.user if !@username && uri.user
|
96
|
+
@password = uri.password if !@password && uri.password
|
97
|
+
@request_uri = uri.request_uri
|
98
|
+
|
99
|
+
reopen
|
100
|
+
|
101
|
+
# Pass on the level and custom formatter if supplied
|
102
|
+
super(level, filter, &block)
|
103
|
+
end
|
104
|
+
|
105
|
+
# Re-open after process fork
|
106
|
+
def reopen
|
107
|
+
# On Ruby v2.0 and greater, Net::HTTP.new uses a persistent connection if the server allows it
|
108
|
+
@http = @ssl_options ? Net::HTTP.new(server, port, @ssl_options) : Net::HTTP.new(server, port)
|
109
|
+
end
|
110
|
+
|
111
|
+
# Forward log messages to HTTP Server
|
112
|
+
def log(log)
|
113
|
+
return false if (level_index > (log.level_index || 0)) ||
|
114
|
+
!include_message?(log) # Filtered out?
|
115
|
+
|
116
|
+
post(formatter.call(log, self))
|
117
|
+
end
|
118
|
+
|
119
|
+
# Use the JSON formatter
|
120
|
+
def default_formatter
|
121
|
+
self.class.json_formatter
|
122
|
+
end
|
123
|
+
|
124
|
+
private
|
125
|
+
|
126
|
+
def compress_data(data)
|
127
|
+
str = StringIO.new
|
128
|
+
gz = Zlib::GzipWriter.new(str)
|
129
|
+
gz << data
|
130
|
+
gz.close
|
131
|
+
str.string
|
132
|
+
end
|
133
|
+
|
134
|
+
# HTTP Post
|
135
|
+
def post(body, request_uri = nil)
|
136
|
+
request = Net::HTTP::Post.new(request_uri || @request_uri, @header)
|
137
|
+
process_request(request, body)
|
138
|
+
end
|
139
|
+
|
140
|
+
# HTTP Put
|
141
|
+
def put(body, request_uri = nil)
|
142
|
+
request = Net::HTTP::Put.new(request_uri || @request_uri, @header)
|
143
|
+
process_request(request, body)
|
144
|
+
end
|
145
|
+
|
146
|
+
# HTTP Delete
|
147
|
+
def delete(request_uri = nil)
|
148
|
+
request = Net::HTTP::Delete.new(request_uri || @request_uri, @header)
|
149
|
+
process_request(request)
|
150
|
+
end
|
151
|
+
|
152
|
+
# Process HTTP Request
|
153
|
+
def process_request(request, body = nil)
|
154
|
+
if body
|
155
|
+
body = compress_data(body) if compress
|
156
|
+
request.body = body
|
157
|
+
end
|
158
|
+
request.basic_auth(@username, @password) if @username
|
159
|
+
response = @http.request(request)
|
160
|
+
if response.code == '200' || response.code == '201'
|
161
|
+
true
|
162
|
+
else
|
163
|
+
# Failures are logged to the global semantic logger failsafe logger (Usually stderr or file)
|
164
|
+
SemanticLogger::Logger.logger.error("Bad HTTP response code: #{response.code}, #{response.body}")
|
165
|
+
false
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
end
|
@@ -1,98 +1,115 @@
|
|
1
1
|
require 'socket'
|
2
|
-
|
2
|
+
begin
|
3
|
+
require 'mongo'
|
4
|
+
rescue LoadError
|
5
|
+
raise 'Gem mongo is required for logging to MongoDB. Please add the gem "mongo" to your Gemfile.'
|
6
|
+
end
|
7
|
+
|
3
8
|
module SemanticLogger
|
4
9
|
module Appender
|
5
10
|
# The Mongo Appender for the SemanticLogger
|
6
11
|
#
|
7
12
|
# Mongo Document Schema:
|
8
|
-
# _id
|
9
|
-
# time
|
10
|
-
#
|
11
|
-
# application
|
12
|
-
# pid
|
13
|
-
#
|
14
|
-
# name
|
15
|
-
# level
|
13
|
+
# _id: ObjectId("4d9cbcbf7abb3abdaf9679cd"),
|
14
|
+
# time: ISODate("2011-04-06T19:19:27.006Z"),
|
15
|
+
# host: 'Name of the host on which this log entry originated',
|
16
|
+
# application 'Name of application or service logging the data - clarity_base, nginx, tomcat',
|
17
|
+
# pid: process id
|
18
|
+
# thread: "name or id of thread",
|
19
|
+
# name: "com.clarity.MyClass",
|
20
|
+
# level: 'trace|debug|info|warn|error|fatal'
|
16
21
|
# level_index: 0|1|2|3|4|5
|
17
|
-
# message
|
18
|
-
# duration
|
19
|
-
#
|
20
|
-
#
|
21
|
-
# Optional. Any user supplied data, including any thread specific context variables
|
22
|
-
# values supplied on a per log entry will override any thread context values
|
23
|
-
# }
|
24
|
-
# # When an exception is supplied as the first or second parameter
|
25
|
-
# # If supplied as the first parameter, message='exception name'
|
22
|
+
# message: "Message supplied to the logging call",
|
23
|
+
# duration: 'human readable duration',
|
24
|
+
# duration_ms: ms,
|
25
|
+
# tags: ["id1", "id2"]
|
26
26
|
# exception: {
|
27
27
|
# name: 'MyException',
|
28
28
|
# message: 'Invalid value',
|
29
29
|
# stack_trace: []
|
30
30
|
# }
|
31
31
|
# # When a backtrace is captured
|
32
|
-
# file_name:
|
32
|
+
# file_name: 'my_class.rb'
|
33
33
|
# line_number: 42
|
34
34
|
#
|
35
|
+
# Example:
|
36
|
+
# require 'semantic_logger'
|
37
|
+
#
|
38
|
+
# client = Mongo::MongoClient.new
|
39
|
+
# database = client['test']
|
40
|
+
#
|
41
|
+
# appender = SemanticLogger::Appender::MongoDB.new(
|
42
|
+
# db: database,
|
43
|
+
# collection_size: 1024**3 # 1.gigabyte
|
44
|
+
# )
|
45
|
+
# SemanticLogger.add_appender(appender)
|
46
|
+
#
|
47
|
+
# logger = SemanticLogger['Example']
|
48
|
+
#
|
49
|
+
# # Log some messages
|
50
|
+
# logger.info 'This message is written to mongo as a document'
|
35
51
|
class MongoDB < SemanticLogger::Appender::Base
|
36
52
|
attr_reader :db, :collection_name, :collection
|
37
|
-
attr_accessor :
|
53
|
+
attr_accessor :host, :write_concern, :application
|
38
54
|
|
39
55
|
# Create a MongoDB Appender instance
|
40
56
|
#
|
41
|
-
# SemanticLogger::Appender::MongoDB.new(db: Mongo::Connection.new['database'])
|
42
|
-
#
|
43
57
|
# Parameters:
|
44
|
-
#
|
45
|
-
#
|
58
|
+
# db: [Mongo::Database]
|
59
|
+
# The MongoDB database connection to use, not the database name
|
46
60
|
#
|
47
|
-
#
|
48
|
-
#
|
49
|
-
#
|
61
|
+
# collection_name: [String]
|
62
|
+
# Name of the collection to store log data in
|
63
|
+
# Default: semantic_logger
|
50
64
|
#
|
51
|
-
#
|
52
|
-
#
|
53
|
-
#
|
65
|
+
# write_concern: [Integer]
|
66
|
+
# Write concern to use
|
67
|
+
# see: http://docs.mongodb.org/manual/reference/write-concern/
|
68
|
+
# Default: 0
|
54
69
|
#
|
55
|
-
#
|
56
|
-
#
|
57
|
-
#
|
58
|
-
# Default: 1
|
70
|
+
# host: [String]
|
71
|
+
# host name to include in the document logged to Mongo
|
72
|
+
# Default: SemanticLogger.host_name
|
59
73
|
#
|
60
|
-
#
|
61
|
-
#
|
62
|
-
#
|
74
|
+
# application: [String]
|
75
|
+
# Name of the application to include in the document written to mongo
|
76
|
+
# Default: nil (None)
|
63
77
|
#
|
64
|
-
#
|
65
|
-
#
|
66
|
-
#
|
78
|
+
# collection_size: [Integer]
|
79
|
+
# The size of the MongoDB capped collection to create in bytes
|
80
|
+
# Default: 1 GB
|
81
|
+
# Examples:
|
82
|
+
# Prod: 25GB (.5GB per day across 4 servers over 10 days)
|
83
|
+
# Dev: .5GB
|
84
|
+
# Test: File
|
85
|
+
# Release: 4GB
|
67
86
|
#
|
68
|
-
#
|
69
|
-
#
|
70
|
-
# Dev: .5GB
|
71
|
-
# Test: File
|
72
|
-
# Release: 4GB
|
87
|
+
# collection_max: [Integer]
|
88
|
+
# Maximum number of log entries that the capped collection will hold.
|
73
89
|
#
|
74
|
-
#
|
75
|
-
#
|
90
|
+
# level: [:trace | :debug | :info | :warn | :error | :fatal]
|
91
|
+
# Override the log level for this appender.
|
92
|
+
# Default: SemanticLogger.default_level
|
76
93
|
#
|
77
|
-
#
|
78
|
-
#
|
79
|
-
#
|
80
|
-
#
|
81
|
-
#
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
@db =
|
87
|
-
@collection_name =
|
88
|
-
@
|
89
|
-
@write_concern =
|
90
|
-
@application =
|
91
|
-
filter = params[:filter]
|
94
|
+
# filter: [Regexp|Proc]
|
95
|
+
# RegExp: Only include log messages where the class name matches the supplied.
|
96
|
+
# regular expression. All other messages will be ignored.
|
97
|
+
# Proc: Only include log messages where the supplied Proc returns true
|
98
|
+
# The Proc must return true or false.
|
99
|
+
def initialize(options = {}, &block)
|
100
|
+
options = options.dup
|
101
|
+
level = options.delete(:level)
|
102
|
+
filter = options.delete(:filter)
|
103
|
+
@db = options.delete(:db) || raise('Missing mandatory parameter :db')
|
104
|
+
@collection_name = options.delete(:collection_name) || 'semantic_logger'
|
105
|
+
@host = options.delete(:host) || options.delete(:host_name) || SemanticLogger.host
|
106
|
+
@write_concern = options.delete(:write_concern) || 0
|
107
|
+
@application = options.delete(:application) || SemanticLogger.application
|
92
108
|
|
93
109
|
# Create a collection that will hold the lesser of 1GB space or 10K documents
|
94
|
-
@collection_size =
|
95
|
-
@collection_max =
|
110
|
+
@collection_size = options.delete(:collection_size) || 1024**3
|
111
|
+
@collection_max = options.delete(:collection_max)
|
112
|
+
raise(ArgumentError, "Unknown options: #{options.inspect}") if options.size > 0
|
96
113
|
|
97
114
|
reopen
|
98
115
|
|
@@ -100,7 +117,7 @@ module SemanticLogger
|
|
100
117
|
create_indexes
|
101
118
|
|
102
119
|
# Set the log level and formatter
|
103
|
-
super(
|
120
|
+
super(level, filter, &block)
|
104
121
|
end
|
105
122
|
|
106
123
|
# After forking an active process call #reopen to re-open
|
@@ -109,7 +126,8 @@ module SemanticLogger
|
|
109
126
|
@collection = db[@collection_name]
|
110
127
|
end
|
111
128
|
|
112
|
-
# Create the required capped collection
|
129
|
+
# Create the required capped collection.
|
130
|
+
#
|
113
131
|
# Features of capped collection:
|
114
132
|
# * No indexes by default (not even on _id)
|
115
133
|
# * Documents cannot be deleted,
|
@@ -117,7 +135,7 @@ module SemanticLogger
|
|
117
135
|
# * Documents are always stored in insertion order
|
118
136
|
# * A find will always return the documents in their insertion order
|
119
137
|
#
|
120
|
-
# Creates an index based on tags to support faster
|
138
|
+
# Creates an index based on tags to support faster searches.
|
121
139
|
def create_indexes
|
122
140
|
options = {capped: true, size: @collection_size}
|
123
141
|
options[:max] = @collection_max if @collection_max
|
@@ -144,59 +162,20 @@ module SemanticLogger
|
|
144
162
|
# Replace this formatter by supplying a Block to the initializer
|
145
163
|
def default_formatter
|
146
164
|
Proc.new do |log|
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
thread_name: log.thread_name,
|
152
|
-
name: log.name,
|
153
|
-
level: log.level,
|
154
|
-
level_index: log.level_index,
|
155
|
-
}
|
156
|
-
document[:application] = application if application
|
157
|
-
document[:message] = log.cleansed_message if log.message
|
158
|
-
document[:duration] = log.duration if log.duration
|
159
|
-
document[:tags] = log.tags if log.tags && (log.tags.size > 0)
|
160
|
-
document[:payload] = log.payload if log.payload
|
161
|
-
if log.exception
|
162
|
-
root = document
|
163
|
-
log.each_exception do |exception, i|
|
164
|
-
name = i == 0 ? :exception : :cause
|
165
|
-
root[name] = {
|
166
|
-
name: exception.class.name,
|
167
|
-
message: exception.message,
|
168
|
-
stack_trace: exception.backtrace
|
169
|
-
}
|
170
|
-
root = root[name]
|
171
|
-
end
|
172
|
-
end
|
173
|
-
|
174
|
-
file, line = log.file_name_and_line
|
175
|
-
if file
|
176
|
-
document[:file_name] = file
|
177
|
-
document[:line_number] = line.to_i
|
178
|
-
end
|
179
|
-
document
|
165
|
+
h = log.to_h
|
166
|
+
h[:host] = host
|
167
|
+
h[:application] = application
|
168
|
+
h
|
180
169
|
end
|
181
170
|
end
|
182
171
|
|
183
|
-
# Default host_name to use if none is supplied to the appenders initializer
|
184
|
-
def self.host_name
|
185
|
-
@@host_name ||= Socket.gethostname.split('.').first
|
186
|
-
end
|
187
|
-
|
188
|
-
# Override the default host_name
|
189
|
-
def self.host_name=(host_name)
|
190
|
-
@@host_name = host_name
|
191
|
-
end
|
192
|
-
|
193
172
|
# Log the message to MongoDB
|
194
173
|
def log(log)
|
195
174
|
# Ensure minimum log level is met, and check filter
|
196
175
|
return false if (level_index > (log.level_index || 0)) || !include_message?(log)
|
197
176
|
|
198
177
|
# Insert log entry into Mongo
|
199
|
-
collection.insert(formatter.call(log), w: @write_concern)
|
178
|
+
collection.insert(formatter.call(log, self), w: @write_concern)
|
200
179
|
true
|
201
180
|
end
|
202
181
|
|
@@ -1,81 +1,47 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
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
|
-
|
9
|
-
Example 1
|
10
|
-
|
11
|
-
Adding the New Relic appender will send :error and :fatal log entries to New Relic as error events.
|
12
|
-
|
13
|
-
For a Rails application already configured to use SemanticLogger and New Relic, create a file called <Rails Root>/config/initializers/newrelic_appender.rb with the following contents and restart the application:
|
14
|
-
|
15
|
-
# Send :error and :fatal log messages to New Relic
|
16
|
-
SemanticLogger.add_appender(SemanticLogger::Appender::NewRelic.new)
|
17
|
-
Rails.logger.info 'SemanticLogger New Relic Appender added.'
|
18
|
-
|
19
|
-
|
20
|
-
Example 2
|
21
|
-
|
22
|
-
For a non-Rails application, send :info and more severe log entries to a file called application.log and also send :error and :fatal log entries to New Relic.
|
23
|
-
|
24
|
-
# ./newrelic.yml needs to be set up -- see https://docs.newrelic.com/docs/ruby/ruby-agent-installation for more information.
|
25
|
-
|
26
|
-
require 'semantic_logger'
|
27
|
-
require 'newrelic_rpm'
|
28
|
-
|
29
|
-
# New Relic setup
|
30
|
-
NewRelic::Agent.manual_start
|
31
|
-
|
32
|
-
# SemanticLogger setup
|
33
|
-
SemanticLogger.default_level = :info
|
34
|
-
SemanticLogger.add_appender('application.log')
|
35
|
-
SemanticLogger.add_appender(SemanticLogger::Appender::NewRelic.new)
|
36
|
-
logger = SemanticLogger['Example']
|
37
|
-
|
38
|
-
# Log some messages
|
39
|
-
logger.info 'This is only written to application.log'
|
40
|
-
logger.error 'This is written to application.log and will also be sent to New Relic as an error event'
|
41
|
-
|
42
|
-
# The appender will send tags, payloads and benchmark duration to New Relic
|
43
|
-
logger.tagged('test') do
|
44
|
-
logger.with_payload( {key1: 123, key2: 'abc'} ) do
|
45
|
-
logger.benchmark_error(@message) do
|
46
|
-
sleep 0.001
|
47
|
-
end
|
48
|
-
end
|
1
|
+
begin
|
2
|
+
require 'newrelic_rpm'
|
3
|
+
rescue LoadError
|
4
|
+
raise 'Gem newrelic_rpm is required for logging to New Relic. Please add the gem "newrelic_rpm" to your Gemfile.'
|
49
5
|
end
|
50
6
|
|
51
|
-
#
|
52
|
-
|
53
|
-
|
54
|
-
#
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
require 'newrelic_rpm'
|
60
|
-
|
7
|
+
# Send log messages to NewRelic
|
8
|
+
#
|
9
|
+
# The :error and :fatal log entries will show up under
|
10
|
+
# "Applications" > "Application Name" > "Events" > "Errors" in New Relic.
|
11
|
+
#
|
12
|
+
# Example:
|
13
|
+
# SemanticLogger.add_appender(SemanticLogger::Appender::NewRelic.new)
|
14
|
+
#
|
61
15
|
class SemanticLogger::Appender::NewRelic < SemanticLogger::Appender::Base
|
62
|
-
#
|
63
|
-
#
|
64
|
-
#
|
65
|
-
|
66
|
-
|
16
|
+
# Create Appender
|
17
|
+
#
|
18
|
+
# Parameters
|
19
|
+
# level: [:trace | :debug | :info | :warn | :error | :fatal]
|
20
|
+
# Override the log level for this appender.
|
21
|
+
# Default: :error
|
22
|
+
#
|
23
|
+
# filter: [Regexp|Proc]
|
24
|
+
# RegExp: Only include log messages where the class name matches the supplied.
|
25
|
+
# regular expression. All other messages will be ignored.
|
26
|
+
# Proc: Only include log messages where the supplied Proc returns true
|
27
|
+
# The Proc must return true or false.
|
28
|
+
def initialize(options = {}, &block)
|
29
|
+
# Backward compatibility
|
30
|
+
options = {level: options} unless options.is_a?(Hash)
|
31
|
+
@options = options.dup
|
32
|
+
level = @options.delete(:level) || :error
|
33
|
+
filter = @options.delete(:filter)
|
34
|
+
|
35
|
+
super(level, filter, &block)
|
67
36
|
end
|
68
37
|
|
69
38
|
# Returns [Hash] of parameters to send to New Relic.
|
70
39
|
def default_formatter
|
71
|
-
Proc.new do |log|
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
custom_params[:message] = log.message if log.exception
|
77
|
-
|
78
|
-
{metric: log.metric, custom_params: custom_params}
|
40
|
+
Proc.new do |log, logger|
|
41
|
+
h = log.to_h
|
42
|
+
h.delete(:time)
|
43
|
+
h.delete(:exception)
|
44
|
+
{metric: log.metric, custom_params: h}
|
79
45
|
end
|
80
46
|
end
|
81
47
|
|
@@ -96,7 +62,7 @@ class SemanticLogger::Appender::NewRelic < SemanticLogger::Appender::Base
|
|
96
62
|
# For more documentation on the NewRelic::Agent.notice_error method see:
|
97
63
|
# http://rubydoc.info/github/newrelic/rpm/NewRelic/Agent#notice_error-instance_method
|
98
64
|
# and https://docs.newrelic.com/docs/ruby/ruby-agent-api
|
99
|
-
NewRelic::Agent.notice_error(exception, formatter.call(log))
|
65
|
+
NewRelic::Agent.notice_error(exception, formatter.call(log, self))
|
100
66
|
true
|
101
67
|
end
|
102
68
|
|