semantic_logger 3.2.1 → 3.3.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 +4 -4
- data/README.md +1 -1
- data/lib/semantic_logger.rb +22 -2
- data/lib/semantic_logger/appender/bugsnag.rb +2 -2
- data/lib/semantic_logger/appender/elasticsearch.rb +9 -1
- data/lib/semantic_logger/appender/file.rb +1 -1
- data/lib/semantic_logger/appender/graylog.rb +18 -21
- data/lib/semantic_logger/appender/honeybadger.rb +27 -12
- data/lib/semantic_logger/appender/http.rb +19 -11
- data/lib/semantic_logger/appender/mongodb.rb +23 -30
- data/lib/semantic_logger/appender/new_relic.rb +2 -2
- data/lib/semantic_logger/appender/splunk.rb +32 -21
- data/lib/semantic_logger/appender/splunk_http.rb +1 -3
- data/lib/semantic_logger/appender/syslog.rb +25 -10
- data/lib/semantic_logger/appender/tcp.rb +231 -0
- data/lib/semantic_logger/appender/udp.rb +106 -0
- data/lib/semantic_logger/appender/wrapper.rb +1 -1
- data/lib/semantic_logger/base.rb +9 -3
- data/lib/semantic_logger/formatters/base.rb +36 -0
- data/lib/semantic_logger/formatters/color.rb +13 -10
- data/lib/semantic_logger/formatters/default.rb +8 -5
- data/lib/semantic_logger/formatters/json.rb +10 -3
- data/lib/semantic_logger/formatters/raw.rb +13 -0
- data/lib/semantic_logger/formatters/syslog.rb +119 -0
- data/lib/semantic_logger/log.rb +7 -5
- data/lib/semantic_logger/loggable.rb +5 -0
- data/lib/semantic_logger/logger.rb +45 -10
- data/lib/semantic_logger/metrics/new_relic.rb +1 -1
- data/lib/semantic_logger/metrics/statsd.rb +5 -1
- data/lib/semantic_logger/metrics/udp.rb +80 -0
- data/lib/semantic_logger/semantic_logger.rb +23 -27
- data/lib/semantic_logger/subscriber.rb +127 -0
- data/lib/semantic_logger/version.rb +1 -1
- data/test/appender/elasticsearch_test.rb +6 -4
- data/test/appender/file_test.rb +12 -12
- data/test/appender/honeybadger_test.rb +7 -1
- data/test/appender/http_test.rb +4 -2
- data/test/appender/mongodb_test.rb +1 -2
- data/test/appender/splunk_http_test.rb +8 -6
- data/test/appender/splunk_test.rb +48 -45
- data/test/appender/syslog_test.rb +3 -3
- data/test/appender/tcp_test.rb +68 -0
- data/test/appender/udp_test.rb +61 -0
- data/test/appender/wrapper_test.rb +5 -5
- data/test/concerns/compatibility_test.rb +6 -6
- data/test/debug_as_trace_logger_test.rb +2 -2
- data/test/loggable_test.rb +2 -2
- data/test/logger_test.rb +48 -45
- metadata +13 -3
- data/lib/semantic_logger/appender/base.rb +0 -101
@@ -11,7 +11,7 @@ end
|
|
11
11
|
#
|
12
12
|
# Example:
|
13
13
|
# SemanticLogger.add_appender(appender: :new_relic)
|
14
|
-
class SemanticLogger::Appender::NewRelic < SemanticLogger::
|
14
|
+
class SemanticLogger::Appender::NewRelic < SemanticLogger::Subscriber
|
15
15
|
# Create Appender
|
16
16
|
#
|
17
17
|
# Parameters
|
@@ -39,7 +39,7 @@ class SemanticLogger::Appender::NewRelic < SemanticLogger::Appender::Base
|
|
39
39
|
|
40
40
|
# Returns [Hash] of parameters to send to New Relic.
|
41
41
|
def call(log, logger)
|
42
|
-
h = log.to_h
|
42
|
+
h = log.to_h(host, application)
|
43
43
|
h.delete(:time)
|
44
44
|
h.delete(:exception)
|
45
45
|
{metric: log.metric, custom_params: h}
|
@@ -18,8 +18,8 @@ end
|
|
18
18
|
# scheme: :https,
|
19
19
|
# index: 'main'
|
20
20
|
# )
|
21
|
-
class SemanticLogger::Appender::Splunk < SemanticLogger::
|
22
|
-
attr_reader :config, :index, :service, :service_index
|
21
|
+
class SemanticLogger::Appender::Splunk < SemanticLogger::Subscriber
|
22
|
+
attr_reader :config, :index, :service, :service_index, :source_type
|
23
23
|
|
24
24
|
# Write to Splunk.
|
25
25
|
#
|
@@ -37,7 +37,7 @@ class SemanticLogger::Appender::Splunk < SemanticLogger::Appender::Base
|
|
37
37
|
# Not required if username and password are supplied.
|
38
38
|
#
|
39
39
|
# :host [String]
|
40
|
-
# Splunk host name.
|
40
|
+
# Splunk server host name.
|
41
41
|
# Default: 'localhost'
|
42
42
|
#
|
43
43
|
# :port [Integer]
|
@@ -61,6 +61,17 @@ class SemanticLogger::Appender::Splunk < SemanticLogger::Appender::Base
|
|
61
61
|
# :ssl_client_key [OpenSSL::PKey::RSA | OpenSSL::PKey::DSA]
|
62
62
|
# Client key.
|
63
63
|
#
|
64
|
+
# source_type: [String]
|
65
|
+
# Optional: Source type to display in Splunk
|
66
|
+
#
|
67
|
+
# application: [String]
|
68
|
+
# The :source forwarded to Splunk
|
69
|
+
# Default: SemanticLogger.application
|
70
|
+
#
|
71
|
+
# host: [String]
|
72
|
+
# Name of this host to appear in log messages.
|
73
|
+
# Default: SemanticLogger.host
|
74
|
+
#
|
64
75
|
# level: [:trace | :debug | :info | :warn | :error | :fatal]
|
65
76
|
# Override the log level for this appender.
|
66
77
|
# Default: SemanticLogger.default_level
|
@@ -75,21 +86,16 @@ class SemanticLogger::Appender::Splunk < SemanticLogger::Appender::Base
|
|
75
86
|
# regular expression. All other messages will be ignored.
|
76
87
|
# Proc: Only include log messages where the supplied Proc returns true
|
77
88
|
# The Proc must return true or false.
|
78
|
-
def initialize(options, _deprecated_level = nil, &block)
|
89
|
+
def initialize(options = {}, _deprecated_level = nil, &block)
|
79
90
|
@config = options.dup
|
80
91
|
@config[:level] = _deprecated_level if _deprecated_level
|
81
92
|
@index = @config.delete(:index) || 'main'
|
93
|
+
@source_type = options.delete(:source_type)
|
82
94
|
|
83
|
-
options =
|
84
|
-
level: @config.delete(:level) || :error,
|
85
|
-
formatter: @config.delete(:formatter),
|
86
|
-
filter: @config.delete(:filter)
|
87
|
-
}
|
88
|
-
|
89
|
-
reopen
|
90
|
-
|
95
|
+
options = extract_subscriber_options!(@config)
|
91
96
|
# Pass on the level and custom formatter if supplied
|
92
97
|
super(options, &block)
|
98
|
+
reopen
|
93
99
|
end
|
94
100
|
|
95
101
|
# After forking an active process call #reopen to re-open
|
@@ -105,20 +111,25 @@ class SemanticLogger::Appender::Splunk < SemanticLogger::Appender::Base
|
|
105
111
|
# Log the message to Splunk
|
106
112
|
def log(log)
|
107
113
|
return false unless should_log?(log)
|
108
|
-
|
109
|
-
service_index.submit(
|
114
|
+
event = formatter.call(log, self)
|
115
|
+
service_index.submit(event.delete(:message), event)
|
110
116
|
true
|
111
117
|
end
|
112
118
|
|
113
|
-
# Returns [
|
119
|
+
# Returns [Hash] To send to Splunk
|
114
120
|
# For splunk format requirements see:
|
115
121
|
# http://dev.splunk.com/view/event-collector/SP-CAAAE6P
|
116
|
-
def call(log,
|
117
|
-
h = log.to_h
|
118
|
-
h.delete(:message)
|
119
|
-
h.delete(:application)
|
120
|
-
h.delete(:host)
|
122
|
+
def call(log, logger)
|
123
|
+
h = log.to_h(nil, nil)
|
121
124
|
h.delete(:time)
|
122
|
-
|
125
|
+
message = {
|
126
|
+
source: logger.application,
|
127
|
+
host: logger.host,
|
128
|
+
time: log.time.utc.to_f,
|
129
|
+
message: h.delete(:message),
|
130
|
+
event: h
|
131
|
+
}
|
132
|
+
message[:source_type] = source_type if source_type
|
133
|
+
message
|
123
134
|
end
|
124
135
|
end
|
@@ -83,9 +83,7 @@ class SemanticLogger::Appender::SplunkHttp < SemanticLogger::Appender::Http
|
|
83
83
|
# For splunk format requirements see:
|
84
84
|
# http://dev.splunk.com/view/event-collector/SP-CAAAE6P
|
85
85
|
def call(log, logger)
|
86
|
-
h = log.to_h
|
87
|
-
h.delete(:application)
|
88
|
-
h.delete(:host)
|
86
|
+
h = log.to_h(nil, nil)
|
89
87
|
h.delete(:time)
|
90
88
|
message = {
|
91
89
|
source: logger.application,
|
@@ -20,9 +20,7 @@ require 'socket'
|
|
20
20
|
# )
|
21
21
|
module SemanticLogger
|
22
22
|
module Appender
|
23
|
-
class Syslog < SemanticLogger::
|
24
|
-
|
25
|
-
attr_reader :remote_syslog, :url, :server, :port, :protocol, :facility, :host, :application
|
23
|
+
class Syslog < SemanticLogger::Subscriber
|
26
24
|
|
27
25
|
# Default mapping of ruby log levels to syslog log levels
|
28
26
|
#
|
@@ -42,6 +40,7 @@ module SemanticLogger
|
|
42
40
|
debug: ::Syslog::LOG_INFO,
|
43
41
|
trace: ::Syslog::LOG_DEBUG
|
44
42
|
}
|
43
|
+
attr_reader :remote_syslog, :url, :server, :port, :protocol, :facility
|
45
44
|
|
46
45
|
# Create a Syslog appender instance.
|
47
46
|
#
|
@@ -149,7 +148,6 @@ module SemanticLogger
|
|
149
148
|
# Default: :syslog
|
150
149
|
def initialize(options = {}, &block)
|
151
150
|
options = options.dup
|
152
|
-
@application = options.delete(:application) || options.delete(:ident) || 'ruby'
|
153
151
|
@options = options.delete(:options) || (::Syslog::LOG_PID | ::Syslog::LOG_CONS)
|
154
152
|
@facility = options.delete(:facility) || ::Syslog::LOG_USER
|
155
153
|
level_map = options.delete(:level_map)
|
@@ -159,7 +157,6 @@ module SemanticLogger
|
|
159
157
|
@protocol = (uri.scheme || :syslog).to_sym
|
160
158
|
@port = uri.port || 514
|
161
159
|
@server = 'localhost' if @protocol == :syslog
|
162
|
-
@host = options.delete(:host) || options.delete(:local_hostname) || SemanticLogger.host
|
163
160
|
@tcp_client_options = options.delete(:tcp_client)
|
164
161
|
|
165
162
|
raise "Unknown protocol #{@protocol}!" unless [:syslog, :tcp, :udp].include?(@protocol)
|
@@ -187,9 +184,8 @@ module SemanticLogger
|
|
187
184
|
end
|
188
185
|
end
|
189
186
|
|
190
|
-
reopen
|
191
|
-
|
192
187
|
super(options, &block)
|
188
|
+
reopen
|
193
189
|
end
|
194
190
|
|
195
191
|
# After forking an active process call #reopen to re-open
|
@@ -197,7 +193,7 @@ module SemanticLogger
|
|
197
193
|
def reopen
|
198
194
|
case @protocol
|
199
195
|
when :syslog
|
200
|
-
::Syslog.open(
|
196
|
+
::Syslog.open(application, @options, @facility)
|
201
197
|
when :tcp
|
202
198
|
# Use the local logger for @remote_syslog so errors with the remote logger can be recorded locally.
|
203
199
|
@tcp_client_options[:logger] = SemanticLogger::Logger.logger
|
@@ -264,13 +260,32 @@ module SemanticLogger
|
|
264
260
|
message
|
265
261
|
end
|
266
262
|
|
263
|
+
private
|
264
|
+
|
265
|
+
# Extract Syslog formatter options
|
266
|
+
def format_options(options, protocol, &block)
|
267
|
+
opts = options.delete(:options)
|
268
|
+
facility = options.delete(:facility)
|
269
|
+
level_map = options.delete(:level_map)
|
270
|
+
if formatter = options.delete(:formatter)
|
271
|
+
extract_formatter(formatter)
|
272
|
+
else
|
273
|
+
case protocol
|
274
|
+
when :syslog
|
275
|
+
extract_formatter(syslog: {options: opts, facility: facility, level_map: level_map})
|
276
|
+
when :tcp, :udp
|
277
|
+
extract_formatter(syslog: {options: opts, facility: facility, level_map: level_map})
|
278
|
+
end
|
279
|
+
end
|
280
|
+
end
|
281
|
+
|
267
282
|
# Format the syslog packet so it can be sent over TCP or UDP
|
268
283
|
def syslog_packet_formatter(log)
|
269
284
|
packet = SyslogProtocol::Packet.new
|
270
|
-
packet.hostname =
|
285
|
+
packet.hostname = host
|
271
286
|
packet.facility = @facility
|
272
287
|
packet.severity = @level_map[log.level]
|
273
|
-
packet.tag =
|
288
|
+
packet.tag = application.gsub(' ', '')
|
274
289
|
packet.content = formatter.call(log, self)
|
275
290
|
packet.time = log.time
|
276
291
|
packet.to_s
|
@@ -0,0 +1,231 @@
|
|
1
|
+
begin
|
2
|
+
require 'net/tcp_client'
|
3
|
+
rescue LoadError
|
4
|
+
raise 'Gem net_tcp_client is required for logging over TCP. Please add the gem "net_tcp_client" to your Gemfile.'
|
5
|
+
end
|
6
|
+
|
7
|
+
raise 'Net::TCPClient v2.0 or greater is required to log over TCP' unless Net::TCPClient::VERSION.to_f >= 2.0
|
8
|
+
|
9
|
+
module SemanticLogger
|
10
|
+
module Appender
|
11
|
+
# TCP log appender.
|
12
|
+
#
|
13
|
+
# Log to a server over a TCP Socket.
|
14
|
+
# By default messages are in JSON format.
|
15
|
+
#
|
16
|
+
# Features:
|
17
|
+
# * JSON Formatted messages.
|
18
|
+
# * SSL encryption.
|
19
|
+
# * Transparently reconnect when a connection is lost.
|
20
|
+
#
|
21
|
+
# Example:
|
22
|
+
# SemanticLogger.add_appender(
|
23
|
+
# appender: :tcp,
|
24
|
+
# server: 'server:3300',
|
25
|
+
# )
|
26
|
+
#
|
27
|
+
# Example, with connection retry options:
|
28
|
+
# SemanticLogger.add_appender(
|
29
|
+
# appender: :tcp,
|
30
|
+
# server: 'server:3300',
|
31
|
+
# connect_retry_interval: 0.1,
|
32
|
+
# connect_retry_count: 5
|
33
|
+
# )
|
34
|
+
#
|
35
|
+
# Example, with SSL enabled:
|
36
|
+
# SemanticLogger.add_appender(
|
37
|
+
# appender: :tcp,
|
38
|
+
# server: 'server:3300',
|
39
|
+
# ssl: true
|
40
|
+
# )
|
41
|
+
#
|
42
|
+
class Tcp < SemanticLogger::Subscriber
|
43
|
+
attr_accessor :separator
|
44
|
+
attr_reader :tcp_client
|
45
|
+
|
46
|
+
# Create TCP log appender.
|
47
|
+
#
|
48
|
+
# Net::TCPClient Parameters:
|
49
|
+
# :server [String]
|
50
|
+
# URL of the server to connect to with port number
|
51
|
+
# 'localhost:2000'
|
52
|
+
# '192.168.1.10:80'
|
53
|
+
#
|
54
|
+
# :servers [Array of String]
|
55
|
+
# Array of URL's of servers to connect to with port numbers
|
56
|
+
# ['server1:2000', 'server2:2000']
|
57
|
+
#
|
58
|
+
# The second server will only be attempted once the first server
|
59
|
+
# cannot be connected to or has timed out on connect
|
60
|
+
# A read failure or timeout will not result in switching to the second
|
61
|
+
# server, only a connection failure or during an automatic reconnect
|
62
|
+
#
|
63
|
+
# :connect_timeout [Float]
|
64
|
+
# Time in seconds to timeout when trying to connect to the server
|
65
|
+
# A value of -1 will cause the connect wait time to be infinite
|
66
|
+
# Default: Half of the :read_timeout ( 30 seconds )
|
67
|
+
#
|
68
|
+
# :read_timeout [Float]
|
69
|
+
# Time in seconds to timeout on read
|
70
|
+
# Can be overridden by supplying a timeout in the read call
|
71
|
+
# Default: 60
|
72
|
+
#
|
73
|
+
# :write_timeout [Float]
|
74
|
+
# Time in seconds to timeout on write
|
75
|
+
# Can be overridden by supplying a timeout in the write call
|
76
|
+
# Default: 60
|
77
|
+
#
|
78
|
+
# :log_level [Symbol]
|
79
|
+
# Optional: Set the logging level for the TCPClient
|
80
|
+
# Any valid SemanticLogger log level:
|
81
|
+
# :trace, :debug, :info, :warn, :error, :fatal
|
82
|
+
# Default: SemanticLogger.default_level
|
83
|
+
#
|
84
|
+
# :buffered [Boolean]
|
85
|
+
# Whether to use Nagle's Buffering algorithm (http://en.wikipedia.org/wiki/Nagle's_algorithm)
|
86
|
+
# Recommend disabling for RPC style invocations where we don't want to wait for an
|
87
|
+
# ACK from the server before sending the last partial segment
|
88
|
+
# Buffering is recommended in a browser or file transfer style environment
|
89
|
+
# where multiple sends are expected during a single response
|
90
|
+
# Default: true
|
91
|
+
#
|
92
|
+
# :connect_retry_count [Fixnum]
|
93
|
+
# Number of times to retry connecting when a connection fails
|
94
|
+
# Default: 10
|
95
|
+
#
|
96
|
+
# :connect_retry_interval [Float]
|
97
|
+
# Number of seconds between connection retry attempts after the first failed attempt
|
98
|
+
# Default: 0.5
|
99
|
+
#
|
100
|
+
# :retry_count [Fixnum]
|
101
|
+
# Number of times to retry when calling #retry_on_connection_failure
|
102
|
+
# This is independent of :connect_retry_count which still applies with
|
103
|
+
# connection failures. This retry controls upto how many times to retry the
|
104
|
+
# supplied block should a connection failure occurr during the block
|
105
|
+
# Default: 3
|
106
|
+
#
|
107
|
+
# :on_connect [Proc]
|
108
|
+
# Directly after a connection is established and before it is made available
|
109
|
+
# for use this Block is invoked.
|
110
|
+
# Typical Use Cases:
|
111
|
+
# - Initialize per connection session sequence numbers
|
112
|
+
# - Pass any authentication information to the server
|
113
|
+
# - Perform a handshake with the server
|
114
|
+
#
|
115
|
+
# :policy [Symbol|Proc]
|
116
|
+
# Specify the policy to use when connecting to servers.
|
117
|
+
# :ordered
|
118
|
+
# Select a server in the order supplied in the array, with the first
|
119
|
+
# having the highest priority. The second server will only be connected
|
120
|
+
# to if the first server is unreachable
|
121
|
+
# :random
|
122
|
+
# Randomly select a server from the list every time a connection
|
123
|
+
# is established, including during automatic connection recovery.
|
124
|
+
# :ping_time
|
125
|
+
# FUTURE - Not implemented yet - Pull request anyone?
|
126
|
+
# The server with the lowest ping time will be tried first
|
127
|
+
# Proc:
|
128
|
+
# When a Proc is supplied, it will be called passing in the list
|
129
|
+
# of servers. The Proc must return one server name
|
130
|
+
# Example:
|
131
|
+
# :policy => Proc.new do |servers|
|
132
|
+
# servers.last
|
133
|
+
# end
|
134
|
+
# Default: :ordered
|
135
|
+
#
|
136
|
+
# :close_on_error [True|False]
|
137
|
+
# To prevent the connection from going into an inconsistent state
|
138
|
+
# automatically close the connection if an error occurs
|
139
|
+
# This includes a Read Timeout
|
140
|
+
# Default: true
|
141
|
+
#
|
142
|
+
# Appender Parameters:
|
143
|
+
# separator: [String]
|
144
|
+
# Separator between every message
|
145
|
+
# Default: "\n"
|
146
|
+
# Note: The separator should not be something that could be output in the formatted log message.
|
147
|
+
#
|
148
|
+
# Common Appender Parameters:
|
149
|
+
# application: [String]
|
150
|
+
# Name of this application to appear in log messages.
|
151
|
+
# Default: SemanticLogger.application
|
152
|
+
#
|
153
|
+
# host: [String]
|
154
|
+
# Name of this host to appear in log messages.
|
155
|
+
# Default: SemanticLogger.host
|
156
|
+
#
|
157
|
+
# level: [:trace | :debug | :info | :warn | :error | :fatal]
|
158
|
+
# Override the log level for this appender.
|
159
|
+
# Default: SemanticLogger.default_level
|
160
|
+
#
|
161
|
+
# formatter: [Object|Proc]
|
162
|
+
# An instance of a class that implements #call, or a Proc to be used to format
|
163
|
+
# the output from this appender
|
164
|
+
# Default: Use the built-in formatter (See: #call)
|
165
|
+
#
|
166
|
+
# filter: [Regexp|Proc]
|
167
|
+
# RegExp: Only include log messages where the class name matches the supplied.
|
168
|
+
# regular expression. All other messages will be ignored.
|
169
|
+
# Proc: Only include log messages where the supplied Proc returns true
|
170
|
+
# The Proc must return true or false.
|
171
|
+
# Example:
|
172
|
+
# SemanticLogger.add_appender(
|
173
|
+
# appender: :tcp,
|
174
|
+
# server: 'server:3300'
|
175
|
+
# )
|
176
|
+
#
|
177
|
+
# Example, with connection retry options:
|
178
|
+
# SemanticLogger.add_appender(
|
179
|
+
# appender: :tcp,
|
180
|
+
# server: 'server:3300',
|
181
|
+
# connect_retry_interval: 0.1,
|
182
|
+
# connect_retry_count: 5
|
183
|
+
# )
|
184
|
+
def initialize(options = {}, &block)
|
185
|
+
@options = options.dup
|
186
|
+
@separator = @options.delete(:separator) || "\n"
|
187
|
+
|
188
|
+
# Use the internal logger so that errors with remote logging are only written locally.
|
189
|
+
Net::TCPClient.logger = SemanticLogger::Logger.logger.dup
|
190
|
+
Net::TCPClient.logger.name = 'Net::TCPClient'
|
191
|
+
|
192
|
+
options = extract_subscriber_options!(@options)
|
193
|
+
super(options, &block)
|
194
|
+
reopen
|
195
|
+
end
|
196
|
+
|
197
|
+
# After forking an active process call #reopen to re-open
|
198
|
+
# open the handles to resources
|
199
|
+
def reopen
|
200
|
+
close
|
201
|
+
@tcp_client = Net::TCPClient.new(@options)
|
202
|
+
end
|
203
|
+
|
204
|
+
# Write the log using the specified protocol and server.
|
205
|
+
def log(log)
|
206
|
+
return false unless should_log?(log)
|
207
|
+
|
208
|
+
@tcp_client.retry_on_connection_failure { @tcp_client.write("#{formatter.call(log, self)}#{separator}") }
|
209
|
+
true
|
210
|
+
end
|
211
|
+
|
212
|
+
# Flush is called by the semantic_logger during shutdown.
|
213
|
+
def flush
|
214
|
+
@tcp_client.flush if @tcp_client && @tcp_client.respond_to?(:flush)
|
215
|
+
end
|
216
|
+
|
217
|
+
# Close is called during shutdown, or with reopen
|
218
|
+
def close
|
219
|
+
@tcp_client.close if @tcp_client
|
220
|
+
end
|
221
|
+
|
222
|
+
private
|
223
|
+
|
224
|
+
# Returns [SemanticLogger::Formatters::Default] formatter default for this Appender
|
225
|
+
def default_formatter
|
226
|
+
SemanticLogger::Formatters::Json.new
|
227
|
+
end
|
228
|
+
|
229
|
+
end
|
230
|
+
end
|
231
|
+
end
|
@@ -0,0 +1,106 @@
|
|
1
|
+
require 'socket'
|
2
|
+
module SemanticLogger
|
3
|
+
module Appender
|
4
|
+
# UDP log appender.
|
5
|
+
#
|
6
|
+
# Write log messages to UDP.
|
7
|
+
# By default messages are in JSON format.
|
8
|
+
#
|
9
|
+
# Example:
|
10
|
+
# SemanticLogger.add_appender(
|
11
|
+
# appender: :udp,
|
12
|
+
# server: 'server:3300',
|
13
|
+
# )
|
14
|
+
class Udp < SemanticLogger::Subscriber
|
15
|
+
attr_accessor :server, :udp_flags
|
16
|
+
attr_reader :socket
|
17
|
+
|
18
|
+
# Create UDP log appender.
|
19
|
+
#
|
20
|
+
# server: [String]
|
21
|
+
# URL of the server to write UDP messages to.
|
22
|
+
#
|
23
|
+
# udp_flags: [Integer]
|
24
|
+
# Should be a bitwise OR of Socket::MSG_* constants.
|
25
|
+
# Default: 0
|
26
|
+
#
|
27
|
+
# Common Appender Parameters:
|
28
|
+
# application: [String]
|
29
|
+
# Name of this application to appear in log messages.
|
30
|
+
# Default: SemanticLogger.application
|
31
|
+
#
|
32
|
+
# host: [String]
|
33
|
+
# Name of this host to appear in log messages.
|
34
|
+
# Default: SemanticLogger.host
|
35
|
+
#
|
36
|
+
# level: [:trace | :debug | :info | :warn | :error | :fatal]
|
37
|
+
# Override the log level for this appender.
|
38
|
+
# Default: SemanticLogger.default_level
|
39
|
+
#
|
40
|
+
# formatter: [Object|Proc]
|
41
|
+
# An instance of a class that implements #call, or a Proc to be used to format
|
42
|
+
# the output from this appender
|
43
|
+
# Default: Use the built-in formatter (See: #call)
|
44
|
+
#
|
45
|
+
# filter: [Regexp|Proc]
|
46
|
+
# RegExp: Only include log messages where the class name matches the supplied.
|
47
|
+
# regular expression. All other messages will be ignored.
|
48
|
+
# Proc: Only include log messages where the supplied Proc returns true
|
49
|
+
# The Proc must return true or false.
|
50
|
+
#
|
51
|
+
# Limitations:
|
52
|
+
# * UDP packet size is limited by the connected network and any routers etc
|
53
|
+
# that the message has to traverse. See https://en.wikipedia.org/wiki/Maximum_transmission_unit
|
54
|
+
#
|
55
|
+
# Example:
|
56
|
+
# SemanticLogger.add_appender(
|
57
|
+
# appender: :udp,
|
58
|
+
# server: 'server:3300'
|
59
|
+
# )
|
60
|
+
def initialize(options = {}, &block)
|
61
|
+
options = options.dup
|
62
|
+
@server = options.delete(:server)
|
63
|
+
@udp_flags = options.delete(:udp_flags) || 0
|
64
|
+
raise(ArgumentError, 'Missing mandatory argument: :server') unless @server
|
65
|
+
|
66
|
+
super(options, &block)
|
67
|
+
reopen
|
68
|
+
end
|
69
|
+
|
70
|
+
# After forking an active process call #reopen to re-open
|
71
|
+
# open the handles to resources
|
72
|
+
def reopen
|
73
|
+
close
|
74
|
+
@socket = UDPSocket.new
|
75
|
+
host, port = server.split(':')
|
76
|
+
@socket.connect(host, port.to_i)
|
77
|
+
end
|
78
|
+
|
79
|
+
# Write the log using the specified protocol and server.
|
80
|
+
def log(log)
|
81
|
+
return false unless should_log?(log)
|
82
|
+
|
83
|
+
@socket.send(formatter.call(log, self), udp_flags)
|
84
|
+
true
|
85
|
+
end
|
86
|
+
|
87
|
+
# Flush is called by the semantic_logger during shutdown.
|
88
|
+
def flush
|
89
|
+
@socket.flush if @socket
|
90
|
+
end
|
91
|
+
|
92
|
+
# Close is called during shutdown, or with reopen
|
93
|
+
def close
|
94
|
+
@socket.close if @socket
|
95
|
+
end
|
96
|
+
|
97
|
+
private
|
98
|
+
|
99
|
+
# Returns [SemanticLogger::Formatters::Default] formatter default for this Appender
|
100
|
+
def default_formatter
|
101
|
+
SemanticLogger::Formatters::Json.new
|
102
|
+
end
|
103
|
+
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|