antisyslog 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (3) hide show
  1. checksums.yaml +7 -0
  2. data/lib/antisyslog.rb +270 -0
  3. metadata +43 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 75e7ccc2cef4565f778fed74829c3f2302d0e7fb
4
+ data.tar.gz: 144ac2818818f2a46c27624cf97689fa6a882a92
5
+ SHA512:
6
+ metadata.gz: b9f68d92d762190f29d5dd1ca8e479314a592cc4615dcec538decd592eaf69ca0b9291d5492082f1f2c3e29dd91b470098f91d3cdf4b65523b62c7c228a01a21
7
+ data.tar.gz: e46b01f10b1aee6469959c101a7b207448c551d43e98e8da22c1c86f94748a0b8cfbc9cee98db27208bc72bc650686a3f85968b590d9b123d97d8bec6cc96320
@@ -0,0 +1,270 @@
1
+ require 'logger'
2
+ require 'socket'
3
+
4
+ FACILITIES = {
5
+ 'kern' => 0,
6
+ 'user' => 1,
7
+ 'mail' => 2,
8
+ 'daemon' => 3,
9
+ 'auth' => 4,
10
+ 'syslog' => 5,
11
+ 'lpr' => 6,
12
+ 'news' => 7,
13
+ 'uucp' => 8,
14
+ 'cron' => 9,
15
+ 'authpriv' => 10,
16
+ 'ftp' => 11,
17
+ 'ntp' => 12,
18
+ 'audit' => 13,
19
+ 'alert' => 14,
20
+ 'at' => 15,
21
+ 'local0' => 16,
22
+ 'local1' => 17,
23
+ 'local2' => 18,
24
+ 'local3' => 19,
25
+ 'local4' => 20,
26
+ 'local5' => 21,
27
+ 'local6' => 22,
28
+ 'local7' => 23
29
+ }
30
+
31
+ FACILITY_INDEX = {
32
+ 0 => 'kern',
33
+ 1 => 'user',
34
+ 2 => 'mail',
35
+ 3 => 'daemon',
36
+ 4 => 'auth',
37
+ 5 => 'syslog',
38
+ 6 => 'lpr',
39
+ 7 => 'news',
40
+ 8 => 'uucp',
41
+ 9 => 'cron',
42
+ 10 => 'authpriv',
43
+ 11 => 'ftp',
44
+ 12 => 'ntp',
45
+ 13 => 'audit',
46
+ 14 => 'alert',
47
+ 15 => 'at',
48
+ 16 => 'local0',
49
+ 17 => 'local1',
50
+ 18 => 'local2',
51
+ 19 => 'local3',
52
+ 20 => 'local4',
53
+ 21 => 'local5',
54
+ 22 => 'local6',
55
+ 23 => 'local7'
56
+ }
57
+
58
+ SEVERITIES = {
59
+ 'emerg' => 0,
60
+ 'alert' => 1,
61
+ 'crit' => 2,
62
+ 'err' => 3,
63
+ 'warn' => 4,
64
+ 'notice' => 5,
65
+ 'info' => 6,
66
+ 'debug' => 7
67
+ }
68
+
69
+ SEVERITY_INDEX = {
70
+ 0 => 'emerg',
71
+ 1 => 'alert',
72
+ 2 => 'crit',
73
+ 3 => 'err',
74
+ 4 => 'warn',
75
+ 5 => 'notice',
76
+ 6 => 'info',
77
+ 7 => 'debug'
78
+ }
79
+
80
+ class AntisyslogPacket
81
+ attr_reader :facility, :severity, :hostname, :tag
82
+ attr_accessor :time, :content
83
+
84
+ def to_s
85
+ assemble
86
+ end
87
+
88
+ def assemble()
89
+ unless @hostname and @facility and @severity and @tag
90
+ raise "Could not assemble packet without hostname, tag, facility, and severity"
91
+ end
92
+ "<#{pri}>#{generate_timestamp} #{@hostname} #{@tag}: #{@content}"
93
+ end
94
+
95
+ def facility=(f)
96
+ if f.is_a? Integer
97
+ if (0..23).include?(f)
98
+ @facility = f
99
+ else
100
+ raise ArgumentError.new "Facility must be within 0-23"
101
+ end
102
+ elsif f.is_a? String
103
+ if facility = FACILITIES[f]
104
+ @facility = facility
105
+ else
106
+ raise ArgumentError.new "'#{f}' is not a designated facility"
107
+ end
108
+ else
109
+ raise ArgumentError.new "Facility must be a designated number or string"
110
+ end
111
+ end
112
+
113
+ def tag=(t)
114
+ unless t && t.is_a?(String) && t.length > 0
115
+ raise ArgumentError, "Tag must not be omitted"
116
+ end
117
+ if t.length > 32
118
+ raise ArgumentError, "Tag must not be longer than 32 characters"
119
+ end
120
+ if t =~ /\s/
121
+ raise ArgumentError, "Tag may not contain spaces"
122
+ end
123
+ if t =~ /[^\x21-\x7E]/
124
+ raise ArgumentError, "Tag may only contain ASCII characters 33-126"
125
+ end
126
+
127
+ @tag = t
128
+ end
129
+
130
+ def severity=(s)
131
+ if s.is_a? Integer
132
+ if (0..7).include?(s)
133
+ @severity = s
134
+ else
135
+ raise ArgumentError.new "Severity must be within 0-7"
136
+ end
137
+ elsif s.is_a? String
138
+ if severity = SEVERITIES[s]
139
+ @severity = severity
140
+ else
141
+ raise ArgumentError.new "'#{s}' is not a designated severity"
142
+ end
143
+ else
144
+ raise ArgumentError.new "Severity must be a designated number or string"
145
+ end
146
+ end
147
+
148
+ def hostname=(h)
149
+ unless h and h.is_a? String and h.length > 0
150
+ raise ArgumentError.new("Hostname may not be omitted")
151
+ end
152
+ if h =~ /\s/
153
+ raise ArgumentError.new("Hostname may not contain spaces")
154
+ end
155
+ if h =~ /[^\x21-\x7E]/
156
+ raise ArgumentError.new("Hostname may only contain ASCII characters 33-126")
157
+ end
158
+ @hostname = h
159
+ end
160
+
161
+ def facility_name
162
+ FACILITY_INDEX[@facility]
163
+ end
164
+
165
+ def severity_name
166
+ SEVERITY_INDEX[@severity]
167
+ end
168
+
169
+ def pri
170
+ (@facility * 8) + @severity
171
+ end
172
+
173
+ def pri=(p)
174
+ unless p.is_a? Integer and (0..191).include?(p)
175
+ raise ArgumentError.new "PRI must be a number between 0 and 191"
176
+ end
177
+ @facility = p / 8
178
+ @severity = p - (@facility * 8)
179
+ end
180
+
181
+ def generate_timestamp
182
+ time = @time || Time.now
183
+ # The timestamp format requires that a day with fewer than 2 digits have
184
+ # what would normally be a preceding zero, be instead an extra space.
185
+ day = time.strftime("%d")
186
+ day = day.sub(/^0/, ' ') if day =~ /^0\d/
187
+ time.strftime("%b #{day} %H:%M:%S")
188
+ end
189
+
190
+ if "".respond_to?(:bytesize)
191
+ def string_bytesize(string)
192
+ string.bytesize
193
+ end
194
+ else
195
+ def string_bytesize(string)
196
+ string.length
197
+ end
198
+ end
199
+
200
+ SEVERITIES.each do |k,v|
201
+ define_method("#{k}?") { SEVERITIES[k] == @severity }
202
+ end
203
+ end
204
+
205
+ class AntisyslogSender
206
+ def initialize(remote_hostname, remote_port, options = {})
207
+ @remote_hostname = remote_hostname
208
+ @remote_port = remote_port
209
+ @whinyerrors = options[:whinyerrors]
210
+ @protocol = options[:protocol] || 'tcp'
211
+ @splitlines = options[:split_lines] || false
212
+
213
+ @socket = @protocol == 'tcp' ? TCPSocket.new(@remote_hostname, @remote_port) : UDPSocket.new
214
+ @packet = AntisyslogPacket.new
215
+
216
+ local_hostname = options[:local_hostname] || (Socket.gethostname rescue `hostname`.chomp)
217
+ local_hostname = 'localhost' if local_hostname.nil? || local_hostname.empty?
218
+ @packet.hostname = local_hostname
219
+
220
+ @packet.facility = options[:facility] || 'user'
221
+ @packet.severity = options[:severity] || 'notice'
222
+ @packet.tag = options[:program] || "#{File.basename($0)}[#{$$}]"
223
+ end
224
+
225
+ def send_msg(msg)
226
+ packet = @packet.dup
227
+ packet.content = msg
228
+ if @protocol == 'tcp'
229
+ @socket.send(packet.assemble, 0)
230
+ else
231
+ @socket.send(packet.assemble, 0, @remote_hostname, @remote_port)
232
+ end
233
+ end
234
+
235
+ def transmit(message)
236
+ if @splitlines
237
+ message.split(/\r?\n/).each do |line|
238
+ begin
239
+ next if line =~ /^\s*$/
240
+ send_msg(line)
241
+ rescue
242
+ $stderr.puts "#{self.class} error: #{$!.class}: #{$!}\nOriginal message: #{line}"
243
+ raise if @whinyerrors
244
+ end
245
+ end
246
+ else
247
+ begin
248
+ send_msg(message)
249
+ rescue
250
+ $stderr.puts "#{self.class} error: #{$!.class}: #{$!}\nOriginal message: #{message}"
251
+ raise if @whinyerrors
252
+ end
253
+ end
254
+ end
255
+
256
+ # Make this act a little bit like an `IO` object
257
+ alias_method :write, :transmit
258
+
259
+ def close
260
+ @socket.close
261
+ end
262
+ end
263
+
264
+ module AntiSyslogLogger
265
+ VERSION = '0.0.1'
266
+
267
+ def self.new(remote_hostname, remote_port, options = {})
268
+ Logger.new(AntisyslogSender.new(remote_hostname, remote_port, options))
269
+ end
270
+ end
metadata ADDED
@@ -0,0 +1,43 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: antisyslog
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Benjamen Keroack
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-10-09 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: A totally non-compliant syslog Rails logger
14
+ email: benjamen@dollarshaveclub.com
15
+ executables: []
16
+ extensions: []
17
+ extra_rdoc_files: []
18
+ files:
19
+ - lib/antisyslog.rb
20
+ homepage: https://github.com/dollarshaveclub/antisyslog
21
+ licenses: []
22
+ metadata: {}
23
+ post_install_message:
24
+ rdoc_options: []
25
+ require_paths:
26
+ - lib
27
+ required_ruby_version: !ruby/object:Gem::Requirement
28
+ requirements:
29
+ - - ">="
30
+ - !ruby/object:Gem::Version
31
+ version: '0'
32
+ required_rubygems_version: !ruby/object:Gem::Requirement
33
+ requirements:
34
+ - - ">="
35
+ - !ruby/object:Gem::Version
36
+ version: '0'
37
+ requirements: []
38
+ rubyforge_project:
39
+ rubygems_version: 2.4.3
40
+ signing_key:
41
+ specification_version: 4
42
+ summary: A totally non-compliant syslog Rails logger
43
+ test_files: []