syslogstash 2.2.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 +4 -4
- data/.editorconfig +7 -0
- data/.travis.yml +11 -0
- data/Dockerfile +3 -6
- data/README.md +38 -29
- data/bin/syslogstash +3 -55
- data/lib/syslogstash.rb +49 -44
- data/lib/syslogstash/syslog_reader.rb +212 -180
- data/syslogstash.gemspec +27 -26
- metadata +25 -14
- data/Makefile +0 -14
- data/lib/syslogstash/config.rb +0 -118
- data/lib/syslogstash/logstash_writer.rb +0 -202
- data/lib/syslogstash/prometheus_exporter.rb +0 -47
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 24900387c20afb629c78879987193840d830df0973b1a57131306ae01f47a0cf
|
4
|
+
data.tar.gz: 2236f3b6bca37894f160688e0cc7432e4877f753548b6eea93fcc270df0eebfc
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e82d6d53e887428310b2c03e6e3d11f5f16f55b62485595f20650b4061c1e59469f9955a03b9c885a1d5f1d843c4687f1b0c8b87b844a8a3dd1892b1d067252d
|
7
|
+
data.tar.gz: b9b16ddc853c60d08302af3eeb4965fdd1c2a29ea91f4ca695b6c30765e4c12bca5bf64de3645a094c39004af181f5db394bbd6f8978704b0c250d42c0286770
|
data/.editorconfig
ADDED
data/.travis.yml
ADDED
data/Dockerfile
CHANGED
@@ -1,13 +1,10 @@
|
|
1
|
-
FROM ruby:2.
|
1
|
+
FROM ruby:2.6
|
2
2
|
|
3
3
|
ARG GEM_VERSION="> 0"
|
4
4
|
|
5
5
|
COPY pkg/syslogstash-$GEM_VERSION.gem /tmp/syslogstash.gem
|
6
6
|
|
7
|
-
RUN
|
8
|
-
&&
|
9
|
-
&& gem install /tmp/syslogstash.gem \
|
10
|
-
&& apk del build-base \
|
11
|
-
&& rm -f /var/cache/apk/* /tmp/syslogstash.gem
|
7
|
+
RUN gem install /tmp/syslogstash.gem \
|
8
|
+
&& rm -f /tmp/syslogstash.gem
|
12
9
|
|
13
10
|
ENTRYPOINT ["/usr/local/bundle/bin/syslogstash"]
|
data/README.md
CHANGED
@@ -49,8 +49,8 @@ least, `syslogstash` needs to know where logstash is (`LOGSTASH_SERVER`),
|
|
49
49
|
and the socket to listen on for syslog messages (`SYSLOG_SOCKET`). You
|
50
50
|
specify those on the command line, like so:
|
51
51
|
|
52
|
-
|
53
|
-
|
52
|
+
SYSLOGSTASH_LOGSTASH_SERVER=logstash-json \
|
53
|
+
SYSLOGSTASH_SYSLOG_SOCKET=/dev/log \
|
54
54
|
syslogstash
|
55
55
|
|
56
56
|
The full set of environment variables, and their meaning, is described in
|
@@ -92,6 +92,12 @@ aspects of runtime operation. They are:
|
|
92
92
|
the logstash server from DNS, then SIGHUP syslogstash to make it switch
|
93
93
|
to another server.
|
94
94
|
|
95
|
+
* **`SIGQUIT`** -- dump thread stacktraces and allocation information to
|
96
|
+
`stderr`.
|
97
|
+
|
98
|
+
* **`SIGINT`** / **`SIGTERM`** -- gracefully terminate. Sending either signal
|
99
|
+
twice will cause shutdown to be done somewhat less gracefully.
|
100
|
+
|
95
101
|
|
96
102
|
## Use with Docker
|
97
103
|
|
@@ -139,8 +145,8 @@ All configuration of syslogstash is done by placing values in environment
|
|
139
145
|
variables. The environment variables that syslogstash recognises are listed
|
140
146
|
below.
|
141
147
|
|
142
|
-
* **`
|
143
|
-
logstash server(s) you wish to send entries to. This can be any of:
|
148
|
+
* **`SYSLOGSTASH_LOGSTASH_SERVER`** (required) -- the domain name or address of
|
149
|
+
the logstash server(s) you wish to send entries to. This can be any of:
|
144
150
|
|
145
151
|
* An IPv4 address and port, separated by a colon. For example,
|
146
152
|
`192.0.2.42:5151`. The port *must* be specified.
|
@@ -161,35 +167,33 @@ below.
|
|
161
167
|
In all cases, syslogstash respects DNS record TTLs and SRV record
|
162
168
|
weight/priority selection rules. We're not monsters.
|
163
169
|
|
164
|
-
* **`
|
165
|
-
syslogstash should create and listen on for syslog format messages.
|
170
|
+
* **`SYSLOGSTASH_SYSLOG_SOCKET`** (required) -- the absolute path to the socket
|
171
|
+
which syslogstash should create and listen on for syslog format messages.
|
166
172
|
|
167
|
-
* **`
|
168
|
-
messages to queue if the logstash servers are unavailable. Under
|
169
|
-
operation, syslog messages are immediately relayed to the logstash
|
170
|
-
as they are received. However, if no logstash servers are available,
|
171
|
-
syslogstash will maintain a backlog of up to this many syslog messages,
|
172
|
-
|
173
|
-
again.
|
173
|
+
* **`SYSLOGSTASH_BACKLOG_SIZE`** (optional; default `"1000000"`) -- the maximum
|
174
|
+
number of messages to queue if the logstash servers are unavailable. Under
|
175
|
+
normal operation, syslog messages are immediately relayed to the logstash
|
176
|
+
server as they are received. However, if no logstash servers are available,
|
177
|
+
syslogstash will maintain a backlog of up to this many syslog messages, and
|
178
|
+
will send the entire backlog once a logstash server becomes available again.
|
174
179
|
|
175
180
|
In the event that the queue size limit is reached, the oldest messages
|
176
181
|
will be dropped to make way for the new ones.
|
177
182
|
|
178
|
-
* **`
|
183
|
+
* **`SYSLOGSTASH_RELAY_TO_STDOUT`** (optional; default `"no"`) -- if set to a
|
179
184
|
true-ish string (any of `true`, `yes`, `on`, or `1`, compared
|
180
185
|
case-insensitively), then all the syslog messages which are received will
|
181
186
|
be printed to stdout (with the priority/facility prefix removed). This
|
182
187
|
isn't a replacement for a fully-featured syslog server, merely a quick way
|
183
188
|
to dump messages if absolutely required.
|
184
189
|
|
185
|
-
* **`
|
186
|
-
|
187
|
-
|
188
|
-
listening on all interfaces on port 9159.
|
190
|
+
* **`SYSLOGSTASH_METRICS_PORT`** (optional; default `""`) -- if set to a
|
191
|
+
valid port number (1-65535), a Prometheus-compatible statistics exporter will be
|
192
|
+
started, listening on all interfaces on the specified port.
|
189
193
|
|
190
|
-
* **`
|
191
|
-
the entries which are forwarded to logstash, you can specify them
|
192
|
-
for example:
|
194
|
+
* **`SYSLOGSTASH_ADD_FIELD_<name>`** (optional) -- if you want to add extra
|
195
|
+
fields to the entries which are forwarded to logstash, you can specify them
|
196
|
+
here, for example:
|
193
197
|
|
194
198
|
ADD_FIELD_foo=bar ADD_FIELD_baz=wombat [...] syslogstash
|
195
199
|
|
@@ -199,14 +203,19 @@ below.
|
|
199
203
|
than strings, are not supported. Also, if you specify a field name also
|
200
204
|
used by syslogstash, the results are explicitly undefined.
|
201
205
|
|
202
|
-
* **`
|
203
|
-
to feed the syslog messages that syslogstash receives to another
|
206
|
+
* **`SYSLOGSTASH_RELAY_SOCKETS`** (optional; default `""`) -- on the off-chance
|
207
|
+
you want to feed the syslog messages that syslogstash receives to another
|
204
208
|
syslog-compatible consumer (say, an old-school syslogd) you can specify
|
205
|
-
additional filenames to use here. Multiple socket filenames can be
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
209
|
+
additional filenames to use here. Multiple socket filenames can be specified
|
210
|
+
by separating each file name with a colon. Syslogstash will open each of the
|
211
|
+
specified sockets, if they exist, and write each received message to the
|
212
|
+
socket. If the socket does not exist, or the open or write operations fail,
|
213
|
+
syslogstash **will not** retry.
|
214
|
+
|
215
|
+
* **`SYSLOGSTASH_DROP_REGEX`** (optional) -- Regular expression to run on
|
216
|
+
input, if it matches then the message will be dropped and not sent to
|
217
|
+
logstash. However, it *will* still be sent to stdout and any relay sockets,
|
218
|
+
if those options are enabled.
|
210
219
|
|
211
220
|
|
212
221
|
# Contributing
|
@@ -222,7 +231,7 @@ request](https://github.com/discourse/syslogstash/pulls].
|
|
222
231
|
Unless otherwise stated, everything in this repo is covered by the following
|
223
232
|
copyright notice:
|
224
233
|
|
225
|
-
Copyright (C) 2015, 2018 Civilized Discourse Construction Kit Inc.
|
234
|
+
Copyright (C) 2015, 2018, 2019 Civilized Discourse Construction Kit Inc.
|
226
235
|
|
227
236
|
This program is free software: you can redistribute it and/or modify it
|
228
237
|
under the terms of the GNU General Public License version 3, as
|
data/bin/syslogstash
CHANGED
@@ -1,62 +1,10 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
3
|
require 'syslogstash'
|
4
|
-
require 'logger'
|
5
|
-
|
6
|
-
logger = Logger.new($stderr)
|
7
|
-
logger.formatter = ->(s, t, p, m) { "#{s[0]} [#{p}] #{m}\n" }
|
8
|
-
logger.level = Logger.const_get(ENV['SYSLOGSTASH_LOG_LEVEL'] || "INFO")
|
9
4
|
|
10
5
|
begin
|
11
|
-
|
12
|
-
rescue
|
13
|
-
$stderr.puts "
|
6
|
+
Syslogstash.new(ENV).start
|
7
|
+
rescue ServiceSkeleton::Error::InvalidEnvironmentError => ex
|
8
|
+
$stderr.puts "Configuration error: #{ex.message}"
|
14
9
|
exit 1
|
15
10
|
end
|
16
|
-
|
17
|
-
syslogstash = Syslogstash.new(cfg)
|
18
|
-
|
19
|
-
sig_r, sig_w = IO.pipe
|
20
|
-
|
21
|
-
Signal.trap("USR1") do
|
22
|
-
sig_w.print '1'
|
23
|
-
end
|
24
|
-
Signal.trap("USR2") do
|
25
|
-
sig_w.print '2'
|
26
|
-
end
|
27
|
-
Signal.trap("URG") do
|
28
|
-
sig_w.print 'U'
|
29
|
-
end
|
30
|
-
Signal.trap("HUP") do
|
31
|
-
sig_w.print 'H'
|
32
|
-
end
|
33
|
-
|
34
|
-
Thread.new do
|
35
|
-
loop do
|
36
|
-
begin
|
37
|
-
c = sig_r.getc
|
38
|
-
if c == '1'
|
39
|
-
logger.level -= 1 unless logger.level == Logger::DEBUG
|
40
|
-
logger.info("SignalHandler") { "Received SIGUSR1; log level is now #{Logger::SEV_LABEL[logger.level]}." }
|
41
|
-
elsif c == '2'
|
42
|
-
logger.level += 1 unless logger.level == Logger::ERROR
|
43
|
-
logger.info("SignalHandler") { "Received SIGUSR2; log level is now #{Logger::SEV_LABEL[logger.level]}." }
|
44
|
-
elsif c == 'U'
|
45
|
-
cfg.relay_to_stdout = !cfg.relay_to_stdout
|
46
|
-
logger.info("SignalHandler") { "Received SIGURG; Relaying to stdout is now #{cfg.relay_to_stdout ? "enabled" : "disabled"}" }
|
47
|
-
elsif c== 'H'
|
48
|
-
logger.info("SignalHandler") { "Received SIGHUP" }
|
49
|
-
syslogstash.force_disconnect!
|
50
|
-
else
|
51
|
-
logger.error("SignalHandler") { "Got an unrecognised character from signal pipe: #{c.inspect}" }
|
52
|
-
end
|
53
|
-
rescue StandardError => ex
|
54
|
-
logger.error("SignalHandler") { (["Exception raised: #{ex.message} (#{ex.class})"] + ex.backtrace).join("\n ") }
|
55
|
-
rescue Exception => ex
|
56
|
-
$stderr.puts (["Fatal exception in syslogstash signal handler: #{ex.message} (#{ex.class})"] + ex.backtrace).join("\n ")
|
57
|
-
exit 42
|
58
|
-
end
|
59
|
-
end
|
60
|
-
end
|
61
|
-
|
62
|
-
syslogstash.run
|
data/lib/syslogstash.rb
CHANGED
@@ -2,54 +2,59 @@ require 'uri'
|
|
2
2
|
require 'socket'
|
3
3
|
require 'json'
|
4
4
|
require 'thwait'
|
5
|
+
require 'logstash_writer'
|
6
|
+
require 'service_skeleton'
|
5
7
|
|
6
8
|
# Read syslog messages from one or more sockets, and send it to a logstash
|
7
9
|
# server.
|
8
10
|
#
|
9
|
-
class Syslogstash
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
11
|
+
class Syslogstash < ServiceSkeleton
|
12
|
+
string :SYSLOGSTASH_LOGSTASH_SERVER
|
13
|
+
string :SYSLOGSTASH_SYSLOG_SOCKET
|
14
|
+
string :SYSLOGSTASH_RELAY_TO_STDOUT, default: false
|
15
|
+
string :SYSLOGSTASH_DROP_REGEX, default: nil
|
16
|
+
integer :SYSLOGSTASH_BACKLOG_SIZE, default: 1_000_000, range: 0..(2**31-1)
|
17
|
+
path_list :SYSLOGSTASH_RELAY_SOCKETS, default: []
|
18
|
+
kv_list :SYSLOGSTASH_ADD_FIELDS, default: {}, key_pattern: /\ASYSLOGSTASH_ADD_FIELD_(.*)\z/
|
19
|
+
|
20
|
+
def initialize(*_)
|
21
|
+
super
|
22
|
+
|
23
|
+
hook_signal("URG") do
|
24
|
+
config.relay_to_stdout = !config.relay_to_stdout
|
25
|
+
logger.info(logloc) { "SIGURG received; relay_to_stdout is now #{config.relay_to_stdout.inspect}" }
|
26
|
+
end
|
27
|
+
|
28
|
+
@shutdown_reader, @shutdown_writer = IO.pipe
|
29
|
+
|
30
|
+
metrics.counter(:syslogstash_messages_received_total, "The number of syslog messages received from the log socket")
|
31
|
+
metrics.counter(:syslogstash_messages_sent_total, "The number of logstash messages sent to each logstash server")
|
32
|
+
metrics.gauge(:syslogstash_last_relayed_message_timestamp, "When the last message that was successfully relayed to logstash was originally received")
|
33
|
+
metrics.gauge(:syslogstash_queue_size, "How many messages are currently in the queue to be sent")
|
34
|
+
metrics.counter(:syslogstash_dropped_total, "Number of log entries that were not forwarded due to matching the drop regex")
|
35
|
+
|
36
|
+
@writer = LogstashWriter.new(server_name: config.logstash_server, backlog: config.backlog_size, logger: config.logger, metrics_registry: metrics)
|
37
|
+
@reader = SyslogReader.new(config, @writer, metrics)
|
38
|
+
end
|
39
|
+
|
40
|
+
def run
|
41
|
+
@writer.run
|
42
|
+
@reader.start!
|
43
|
+
|
44
|
+
@shutdown_reader.getc
|
45
|
+
@shutdown_reader.close
|
46
|
+
end
|
47
|
+
|
48
|
+
def shutdown
|
49
|
+
@reader.stop!
|
50
|
+
@writer.stop
|
51
|
+
|
52
|
+
@shutdown_writer.close
|
53
|
+
end
|
54
|
+
|
55
|
+
def force_disconnect!
|
56
|
+
@writer.force_disconnect!
|
57
|
+
end
|
50
58
|
end
|
51
59
|
|
52
|
-
require_relative 'syslogstash/config'
|
53
60
|
require_relative 'syslogstash/syslog_reader'
|
54
|
-
require_relative 'syslogstash/logstash_writer'
|
55
|
-
require_relative 'syslogstash/prometheus_exporter'
|
@@ -1,184 +1,216 @@
|
|
1
1
|
# A single socket reader.
|
2
2
|
#
|
3
3
|
class Syslogstash::SyslogReader
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
4
|
+
include ServiceSkeleton::BackgroundWorker
|
5
|
+
|
6
|
+
def initialize(config, logstash, metrics)
|
7
|
+
@config, @logstash, @metrics = config, logstash, metrics
|
8
|
+
|
9
|
+
@logger = config.logger
|
10
|
+
|
11
|
+
@shutdown_reader, @shutdown_writer = IO.pipe
|
12
|
+
|
13
|
+
super
|
14
|
+
end
|
15
|
+
|
16
|
+
# Start reading from the socket file, parsing entries, and flinging
|
17
|
+
# them at logstash.
|
18
|
+
#
|
19
|
+
def start
|
20
|
+
config.logger.debug(logloc) { "off we go!" }
|
21
|
+
|
22
|
+
begin
|
23
|
+
socket = Socket.new(Socket::AF_UNIX, Socket::SOCK_DGRAM, 0)
|
24
|
+
socket.bind(Socket.pack_sockaddr_un(config.syslog_socket))
|
25
|
+
File.chmod(0666, config.syslog_socket)
|
26
|
+
rescue Errno::EEXIST, Errno::EADDRINUSE
|
27
|
+
config.logger.info(logloc) { "socket file #{config.syslog_socket} already exists; deleting" }
|
28
|
+
File.unlink(config.syslog_socket) rescue nil
|
29
|
+
retry
|
30
|
+
rescue StandardError => ex
|
31
|
+
raise ex.class, "Error while trying to bind to #{config.syslog_socket}: #{ex.message}", ex.backtrace
|
32
|
+
end
|
33
|
+
|
34
|
+
begin
|
35
|
+
loop do
|
36
|
+
IO.select([@shutdown_reader, socket]).first.each do |fd|
|
37
|
+
if fd == socket
|
38
|
+
begin
|
39
|
+
msg = socket.recvmsg_nonblock
|
40
|
+
rescue IO::WaitWritable
|
41
|
+
config.logger.debug(logloc) { "select said a message was waiting, but it wasn't. o.O" }
|
42
|
+
else
|
43
|
+
config.logger.debug(logloc) { "Message received: #{msg.inspect}" }
|
44
|
+
@metrics.messages_received_total.increment(socket_path: config.syslog_socket)
|
45
|
+
@metrics.queue_size.increment({})
|
46
|
+
relay_message msg.first
|
47
|
+
process_message msg.first.chomp
|
48
|
+
end
|
49
|
+
elsif fd == @shutdown_reader
|
50
|
+
@shutdown_reader.close
|
51
|
+
config.logger.debug(logloc) { "Tripped over shutdown reader" }
|
52
|
+
break
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
ensure
|
57
|
+
socket.close
|
58
|
+
config.logger.debug(logloc) { "removing socket file #{config.syslog_socket}" }
|
59
|
+
File.unlink(config.syslog_socket) rescue nil
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def shutdown
|
64
|
+
@shutdown_writer.close
|
65
|
+
end
|
66
|
+
|
67
|
+
private
|
68
|
+
|
69
|
+
attr_reader :config, :logger
|
70
|
+
|
71
|
+
def process_message(msg)
|
72
|
+
if msg =~ /^<(\d+)>(\w{3} [ 0-9]{2} [0-9:]{8}) (.*)$/
|
73
|
+
flags = $1.to_i
|
74
|
+
timestamp = $2
|
75
|
+
content = $3
|
76
|
+
|
77
|
+
# Lo! the many ways that syslog messages can be formatted
|
78
|
+
hostname, program, pid, message = case content
|
79
|
+
# the gold standard: hostname, program name with optional PID
|
80
|
+
when /^([a-zA-Z0-9._-]*[^:]) (\S+?)(\[(\d+)\])?: (.*)$/
|
81
|
+
[$1, $2, $4, $5]
|
82
|
+
# hostname, no program name
|
83
|
+
when /^([a-zA-Z0-9._-]+) (\S+[^:] .*)$/
|
84
|
+
[$1, nil, nil, $2]
|
85
|
+
# program name, no hostname (yeah, you heard me, non-RFC compliant!)
|
86
|
+
when /^(\S+?)(\[(\d+)\])?: (.*)$/
|
87
|
+
[nil, $1, $3, $4]
|
88
|
+
else
|
89
|
+
# I have NFI
|
90
|
+
[nil, nil, nil, content]
|
91
|
+
end
|
92
|
+
|
93
|
+
if config.drop_regex && message && message.match?(config.drop_regex)
|
94
|
+
@metrics.dropped_total.increment({})
|
95
|
+
config.logger.debug(logloc) { "dropping message #{message}" }
|
96
|
+
return
|
97
|
+
end
|
98
|
+
|
99
|
+
severity = flags % 8
|
100
|
+
facility = flags / 8
|
101
|
+
|
102
|
+
log_entry = log_entry(
|
103
|
+
syslog_timestamp: timestamp,
|
104
|
+
severity: severity,
|
105
|
+
facility: facility,
|
106
|
+
hostname: hostname,
|
107
|
+
program: program,
|
108
|
+
pid: pid.nil? ? nil : pid.to_i,
|
109
|
+
message: message,
|
110
|
+
)
|
111
|
+
|
112
|
+
@logstash.send_event(log_entry)
|
113
|
+
else
|
114
|
+
config.logger.warn(logloc) { "Unparseable message: #{msg.inspect}" }
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
def log_entry(h)
|
119
|
+
{}.tap do |e|
|
120
|
+
e['@version'] = '1'
|
121
|
+
e['@timestamp'] = Time.now.utc.strftime("%FT%T.%LZ")
|
122
|
+
|
123
|
+
h[:facility_name] = FACILITIES[h[:facility]]
|
124
|
+
h[:severity_name] = SEVERITIES[h[:severity]]
|
125
|
+
|
126
|
+
e.merge!(h.delete_if { |k,v| v.nil? })
|
127
|
+
e.merge!(config.add_fields)
|
128
|
+
|
129
|
+
config.logger.debug(logloc) { "Complete log entry is: #{e.inspect}" }
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
def relay_message(msg)
|
134
|
+
@currently_failed ||= {}
|
135
|
+
|
136
|
+
if config.relay_to_stdout
|
137
|
+
# This one's easy
|
138
|
+
puts msg.sub(/\A<\d+>/, '')
|
139
|
+
$stdout.flush
|
140
|
+
end
|
141
|
+
|
142
|
+
config.relay_sockets.each do |f|
|
143
|
+
relay_to_socket(f)
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
def relay_to_socket(f)
|
148
|
+
begin
|
149
|
+
s = Socket.new(Socket::AF_UNIX, Socket::SOCK_DGRAM, 0)
|
150
|
+
begin
|
151
|
+
s.connect(Socket.pack_sockaddr_un(f))
|
152
|
+
rescue Errno::ENOENT
|
153
|
+
# Socket doesn't exist; we don't care enough about this to bother
|
154
|
+
# reporting it. People will figure it out themselves soon enough.
|
155
|
+
rescue StandardError => ex
|
156
|
+
unless @currently_failed[f]
|
157
|
+
config.logger.warn(logloc) { "Error while connecting to relay socket #{f}: #{ex.message} (#{ex.class})" }
|
158
|
+
@currently_failed[f] = true
|
159
|
+
end
|
160
|
+
return
|
161
|
+
end
|
162
|
+
|
163
|
+
begin
|
164
|
+
# We really, *really* don't want to block the world just because
|
165
|
+
# whoever's on the other end of the relay socket can't process
|
166
|
+
# messages quick enough.
|
167
|
+
s.sendmsg_nonblock(msg)
|
168
|
+
if @currently_failed[f]
|
169
|
+
config.logger.info(logloc) { "Error on socket #{f} has cleared; messages are being delivered again" }
|
170
|
+
@currently_failed[f] = false
|
171
|
+
end
|
172
|
+
rescue Errno::ENOTCONN
|
173
|
+
unless @currently_failed[f]
|
174
|
+
config.logger.debug(logloc) { "Nothing is listening on socket #{f}" }
|
175
|
+
@currently_failed[f] = true
|
176
|
+
end
|
177
|
+
rescue IO::EAGAINWaitWritable
|
178
|
+
unless @currently_failed[f]
|
179
|
+
config.logger.warn(logloc) { "Socket #{f} is currently backlogged; messages to this socket are now being discarded undelivered" }
|
180
|
+
@currently_failed[f] = true
|
181
|
+
end
|
182
|
+
rescue StandardError => ex
|
183
|
+
config.logger.warn(logloc) { (["Failed to relay message to socket #{f} from #{config.syslog_socket}: #{ex.message} (#{ex.class})"] + ex.backtrace).join("\n ") }
|
184
|
+
end
|
185
|
+
ensure
|
186
|
+
s.close
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
FACILITIES = %w{
|
191
|
+
kern
|
192
|
+
user
|
193
|
+
mail
|
194
|
+
daemon
|
195
|
+
auth
|
196
|
+
syslog
|
197
|
+
lpr
|
198
|
+
news
|
199
|
+
uucp
|
200
|
+
cron
|
201
|
+
authpriv
|
202
|
+
ftp
|
203
|
+
local0 local1 local2 local3 local4 local5 local6 local7
|
204
|
+
}
|
205
|
+
|
206
|
+
SEVERITIES = %w{
|
207
|
+
emerg
|
208
|
+
alert
|
209
|
+
crit
|
210
|
+
err
|
211
|
+
warning
|
212
|
+
notice
|
213
|
+
info
|
214
|
+
debug
|
215
|
+
}
|
184
216
|
end
|