antisyslog 0.0.1

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.
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: []