syslog_protocol 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile ADDED
@@ -0,0 +1,2 @@
1
+ source :rubygems
2
+ gemspec
@@ -0,0 +1,84 @@
1
+ # Syslog protocol
2
+
3
+ roughly conforms to the murky shade of grey known as http://www.faqs.org/rfcs/rfc3164.html
4
+
5
+ ## Examples
6
+
7
+ ### Manipulate packets manually
8
+
9
+ require 'syslog_protocol'
10
+
11
+ p = SyslogProtocol::Packet.new
12
+ p.hostname = "space_station"
13
+ p.facility = "kern"
14
+ p.severity = "warn"
15
+ p.tag = "test"
16
+ p.content = "flight control broken"
17
+ p.to_s
18
+ # => "<4>Aug 1 14:01:17 space_station flight control broken"
19
+ p.pri
20
+ # => 4
21
+ p.facility
22
+ # => 0
23
+ p.facility_name
24
+ # => "kern"
25
+ p.severity_name
26
+ # => "warn"
27
+ p.warn?
28
+ # => true
29
+ p.info?
30
+ # => false
31
+
32
+
33
+ ### Use a Logger to generate packets
34
+
35
+ require 'syslog_protocol'
36
+
37
+ logger = SyslogProtocol::Logger.new("space_station", "uucp")
38
+ logger.debug("looking for uucp on board the space station")
39
+ # => "<67>Aug 1 14:02:29 space_station looking for uucp on board the space station"
40
+ logger.emerg("omg we cant find uucp on the space station")
41
+ # => "<64>Aug 1 14:03:56 space_station omg we cant find uucp on the space station"
42
+
43
+
44
+ ### Parse packets
45
+
46
+ require 'syslog_protocol'
47
+
48
+ p = SyslogProtocol.parse("<34>Oct 11 22:14:15 space_station space is really getting to me")
49
+ p.facility
50
+ # => 4
51
+ p.severity_name
52
+ # => "crit"
53
+ p.time
54
+ # => Sun Oct 11 22:14:15 -0700 2009
55
+ p.content
56
+ # => "space is really getting to me"
57
+
58
+
59
+ ### It yells at you for trying to abuse the protocol
60
+
61
+ p = SyslogProtocol::Packet.new
62
+ p.facility = 34534534
63
+ # => ArgumentError: Facility must be within 0-23
64
+ p.hostname = "my host"
65
+ # => ArgumentError: Hostname may not contain spaces
66
+ p.hostname = "h\000stname"
67
+ # => ArgumentError: Hostname may only contain ASCII characters 33-126
68
+ # ...etc.
69
+ # It will also unintelligently truncate messages > 1024 bytes so beware.
70
+
71
+
72
+ ## Caveats
73
+
74
+ Syslog is a terrible and loosely defined protocol. Many devices and programs do not
75
+ conform to it and so their packets may not be parsed correctly by this interpretation,
76
+ nor may the packets generated by this necessarily be recognized by other devices or programs ;)
77
+
78
+ This is probably wrong and buggy, and i know the code is ugly, thanks.
79
+
80
+ Good luck.
81
+
82
+ ## TODO
83
+
84
+ * Update to more closely map to the ruby `syslog` API where possible
@@ -0,0 +1,150 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+ require 'date'
4
+
5
+ #############################################################################
6
+ #
7
+ # Helper functions
8
+ #
9
+ #############################################################################
10
+
11
+ def name
12
+ @name ||= Dir['*.gemspec'].first.split('.').first
13
+ end
14
+
15
+ def version
16
+ line = File.read("lib/#{name}.rb")[/^\s*VERSION\s*=\s*.*/]
17
+ line.match(/.*VERSION\s*=\s*['"](.*)['"]/)[1]
18
+ end
19
+
20
+ def date
21
+ Date.today.to_s
22
+ end
23
+
24
+ def rubyforge_project
25
+ name
26
+ end
27
+
28
+ def gemspec_file
29
+ "#{name}.gemspec"
30
+ end
31
+
32
+ def gem_file
33
+ "#{name}-#{version}.gem"
34
+ end
35
+
36
+ def replace_header(head, header_name)
37
+ head.sub!(/(\.#{header_name}\s*= ').*'/) { "#{$1}#{send(header_name)}'"}
38
+ end
39
+
40
+ #############################################################################
41
+ #
42
+ # Standard tasks
43
+ #
44
+ #############################################################################
45
+
46
+ task :default => :test
47
+
48
+ require 'rake/testtask'
49
+ Rake::TestTask.new(:test) do |test|
50
+ test.libs << 'lib' << 'test'
51
+ test.pattern = 'test/**/test_*.rb'
52
+ test.verbose = true
53
+ end
54
+
55
+ desc "Generate RCov test coverage and open in your browser"
56
+ task :coverage do
57
+ require 'rcov'
58
+ sh "rm -fr coverage"
59
+ sh "rcov test/test_*.rb"
60
+ sh "open coverage/index.html"
61
+ end
62
+
63
+ require 'rake/rdoctask'
64
+ Rake::RDocTask.new do |rdoc|
65
+ rdoc.rdoc_dir = 'rdoc'
66
+ rdoc.title = "#{name} #{version}"
67
+ rdoc.rdoc_files.include('README*')
68
+ rdoc.rdoc_files.include('lib/**/*.rb')
69
+ end
70
+
71
+ desc "Open an irb session preloaded with this library"
72
+ task :console do
73
+ sh "irb -rubygems -r ./lib/#{name}.rb"
74
+ end
75
+
76
+ #############################################################################
77
+ #
78
+ # Custom tasks (add your own tasks here)
79
+ #
80
+ #############################################################################
81
+
82
+
83
+
84
+ #############################################################################
85
+ #
86
+ # Packaging tasks
87
+ #
88
+ #############################################################################
89
+
90
+ desc "Create tag v#{version} and build and push #{gem_file} to Rubygems"
91
+ task :release => :build do
92
+ unless `git branch` =~ /^\* master$/
93
+ puts "You must be on the master branch to release!"
94
+ exit!
95
+ end
96
+ sh "git commit --allow-empty -a -m 'Release #{version}'"
97
+ sh "git tag v#{version}"
98
+ sh "git push origin master"
99
+ sh "git push origin v#{version}"
100
+ sh "gem push pkg/#{name}-#{version}.gem"
101
+ end
102
+
103
+ desc "Build #{gem_file} into the pkg directory"
104
+ task :build => :gemspec do
105
+ sh "mkdir -p pkg"
106
+ sh "gem build #{gemspec_file}"
107
+ sh "mv #{gem_file} pkg"
108
+ end
109
+
110
+ desc "Generate #{gemspec_file}"
111
+ task :gemspec => :validate do
112
+ # read spec file and split out manifest section
113
+ spec = File.read(gemspec_file)
114
+ head, manifest, tail = spec.split(" # = MANIFEST =\n")
115
+
116
+ # replace name version and date
117
+ replace_header(head, :name)
118
+ replace_header(head, :version)
119
+ replace_header(head, :date)
120
+ #comment this out if your rubyforge_project has a different name
121
+ replace_header(head, :rubyforge_project)
122
+
123
+ # determine file list from git ls-files
124
+ files = `git ls-files`.
125
+ split("\n").
126
+ sort.
127
+ reject { |file| file =~ /^\./ }.
128
+ reject { |file| file =~ /^(rdoc|pkg)/ }.
129
+ map { |file| " #{file}" }.
130
+ join("\n")
131
+
132
+ # piece file back together and write
133
+ manifest = " s.files = %w[\n#{files}\n ]\n"
134
+ spec = [head, manifest, tail].join(" # = MANIFEST =\n")
135
+ File.open(gemspec_file, 'w') { |io| io.write(spec) }
136
+ puts "Updated #{gemspec_file}"
137
+ end
138
+
139
+ desc "Validate #{gemspec_file}"
140
+ task :validate do
141
+ libfiles = Dir['lib/*'] - ["lib/#{name}.rb", "lib/#{name}"]
142
+ unless libfiles.empty?
143
+ puts "Directory `lib` should only contain a `#{name}.rb` file and `#{name}` dir."
144
+ exit!
145
+ end
146
+ unless Dir['VERSION*'].empty?
147
+ puts "A `VERSION` file at root level violates Gem best practices."
148
+ exit!
149
+ end
150
+ end
@@ -0,0 +1,8 @@
1
+ require 'syslog_protocol/common'
2
+ require 'syslog_protocol/packet'
3
+ require 'syslog_protocol/logger'
4
+ require 'syslog_protocol/parser'
5
+
6
+ module SyslogProtocol
7
+ VERSION = '0.9.0'
8
+ end
@@ -0,0 +1,79 @@
1
+ module SyslogProtocol
2
+ # These hashes stolen from Syslog.pm
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
+ end
@@ -0,0 +1,21 @@
1
+ module SyslogProtocol
2
+ class Logger
3
+ def initialize(hostname, tag, facility)
4
+ @packet = Packet.new
5
+ @packet.hostname = hostname
6
+ @packet.tag = tag
7
+ @packet.facility = facility
8
+ end
9
+
10
+ SEVERITIES.each do |k,v|
11
+ define_method(k) do |content|
12
+ raise ArgumentError.new("Message may not be omitted") unless content and content.length > 0
13
+
14
+ p = @packet.dup
15
+ p.severity = k
16
+ p.content = content
17
+ p.assemble
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,122 @@
1
+ module SyslogProtocol
2
+ class Packet
3
+ attr_reader :facility, :severity, :hostname, :tag
4
+ attr_accessor :time, :content
5
+
6
+ def to_s
7
+ assemble
8
+ end
9
+
10
+ def assemble
11
+ unless @hostname and @facility and @severity and @tag
12
+ raise "Could not assemble packet without hostname, tag, facility, and severity"
13
+ end
14
+ data = "<#{pri}>#{generate_timestamp} #{@hostname} #{@tag}: #{@content}"
15
+ while data.bytesize > 1024
16
+ data = data[0..(data.length-2)]
17
+ end
18
+ data
19
+ end
20
+
21
+ def facility=(f)
22
+ if f.is_a? Integer
23
+ if (0..23).include?(f)
24
+ @facility = f
25
+ else
26
+ raise ArgumentError.new "Facility must be within 0-23"
27
+ end
28
+ elsif f.is_a? String
29
+ if facility = FACILITIES[f]
30
+ @facility = facility
31
+ else
32
+ raise ArgumentError.new "'#{f}' is not a designated facility"
33
+ end
34
+ else
35
+ raise ArgumentError.new "Facility must be a designated number or string"
36
+ end
37
+ end
38
+
39
+ def tag=(t)
40
+ unless t && t.is_a?(String) && t.length > 0
41
+ raise ArgumentError, "Tag must not be omitted"
42
+ end
43
+ if t.length > 32
44
+ raise ArgumentError, "Tag must not be longer than 32 characters"
45
+ end
46
+ if t =~ /\s/
47
+ raise ArgumentError, "Tag may not contain spaces"
48
+ end
49
+ if t =~ /[^\x21-\x7E]/
50
+ raise ArgumentError, "Tag may only contain ASCII characters 33-126"
51
+ end
52
+
53
+ @tag = t
54
+ end
55
+
56
+ def severity=(s)
57
+ if s.is_a? Integer
58
+ if (0..7).include?(s)
59
+ @severity = s
60
+ else
61
+ raise ArgumentError.new "Severity must be within 0-7"
62
+ end
63
+ elsif s.is_a? String
64
+ if severity = SEVERITIES[s]
65
+ @severity = severity
66
+ else
67
+ raise ArgumentError.new "'#{s}' is not a designated severity"
68
+ end
69
+ else
70
+ raise ArgumentError.new "Severity must be a designated number or string"
71
+ end
72
+ end
73
+
74
+ def hostname=(h)
75
+ unless h and h.is_a? String and h.length > 0
76
+ raise ArgumentError.new("Hostname may not be omitted")
77
+ end
78
+ if h =~ /\s/
79
+ raise ArgumentError.new("Hostname may not contain spaces")
80
+ end
81
+ if h =~ /[^\x21-\x7E]/
82
+ raise ArgumentError.new("Hostname may only contain ASCII characters 33-126")
83
+ end
84
+ @hostname = h
85
+ end
86
+
87
+ def facility_name
88
+ FACILITY_INDEX[@facility]
89
+ end
90
+
91
+ def severity_name
92
+ SEVERITY_INDEX[@severity]
93
+ end
94
+
95
+ def pri
96
+ (@facility * 8) + @severity
97
+ end
98
+
99
+ def pri=(p)
100
+ unless p.is_a? Integer and (0..191).include?(p)
101
+ raise ArgumentError.new "PRI must be a number between 0 and 191"
102
+ end
103
+ @facility = p / 8
104
+ @severity = p - (@facility * 8)
105
+ end
106
+
107
+ def generate_timestamp
108
+ time = @time || Time.now
109
+ # The timestamp format requires that a day with fewer than 2 digits have
110
+ # what would normally be a preceding zero, be instead an extra space.
111
+ day = time.strftime("%d")
112
+ day = day.sub(/^0/, ' ') if day =~ /^0\d/
113
+ time.strftime("%b #{day} %H:%M:%S")
114
+ end
115
+
116
+ SEVERITIES.each do |k,v|
117
+ define_method("#{k}?") {SEVERITIES[k] == @severity}
118
+ end
119
+
120
+ end
121
+
122
+ end
@@ -0,0 +1,57 @@
1
+ require 'time'
2
+
3
+ module SyslogProtocol
4
+
5
+ def self.parse(msg, origin=nil)
6
+ packet = Packet.new
7
+ original_msg = msg.dup
8
+ pri = parse_pri(msg)
9
+ if pri and (pri = pri.to_i).is_a? Integer and (0..191).include?(pri)
10
+ packet.pri = pri
11
+ else
12
+ # If there isn't a valid PRI, treat the entire message as content
13
+ packet.pri = 13
14
+ packet.time = Time.now
15
+ packet.hostname = origin || 'unknown'
16
+ packet.content = original_msg
17
+ return packet
18
+ end
19
+ time = parse_time(msg)
20
+ if time
21
+ packet.time = Time.parse(time)
22
+ else
23
+ packet.time = Time.now
24
+ end
25
+ hostname = parse_hostname(msg)
26
+ packet.hostname = hostname || origin
27
+ if m = msg.match(/^(\w+)(: | )(.*)$/)
28
+ packet.tag = m[1]
29
+ packet.content = m[3]
30
+ else
31
+ packet.tag = 'unknown'
32
+ packet.content = msg
33
+ end
34
+ packet
35
+ end
36
+
37
+ private
38
+
39
+ def self.parse_pri(msg)
40
+ pri = msg.slice!(/<(\d\d?\d?)>/)
41
+ pri = pri.slice(/\d\d?\d?/) if pri
42
+ if !pri or (pri =~ /^0/ and pri !~ /^0$/)
43
+ return nil
44
+ else
45
+ return pri
46
+ end
47
+ end
48
+
49
+ def self.parse_time(msg)
50
+ msg.slice!(/(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\s(\s|[1-9])\d\s\d\d:\d\d:\d\d\s/)
51
+ end
52
+
53
+ def self.parse_hostname(msg)
54
+ msg.slice!(/^[\x21-\x7E]+\s/).rstrip
55
+ end
56
+
57
+ end
@@ -0,0 +1,81 @@
1
+ ## This is the rakegem gemspec template. Make sure you read and understand
2
+ ## all of the comments. Some sections require modification, and others can
3
+ ## be deleted if you don't need them. Once you understand the contents of
4
+ ## this file, feel free to delete any comments that begin with two hash marks.
5
+ ## You can find comprehensive Gem::Specification documentation, at
6
+ ## http://docs.rubygems.org/read/chapter/20
7
+ Gem::Specification.new do |s|
8
+ s.specification_version = 2 if s.respond_to? :specification_version=
9
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
10
+ s.rubygems_version = '1.3.5'
11
+
12
+ ## Leave these as is they will be modified for you by the rake gemspec task.
13
+ ## If your rubyforge_project name is different, then edit it and comment out
14
+ ## the sub! line in the Rakefile
15
+ s.name = 'syslog_protocol'
16
+ s.version = '0.9.0'
17
+ s.date = "2009-08-01"
18
+ # s.rubyforge_project = 'syslog_protocol'
19
+
20
+ ## Make sure your summary is short. The description may be as long
21
+ ## as you like.
22
+ s.summary = "Syslog protocol parser and generator"
23
+ s.description = "Syslog protocol parser and generator"
24
+
25
+ ## List the primary authors. If there are a bunch of authors, it's probably
26
+ ## better to set the email to an email list or something. If you don't have
27
+ ## a custom homepage, consider using your GitHub URL or the like.
28
+ s.authors = ["Jake Douglas", 'Eric Lindvall']
29
+ s.email = [ "jakecdouglas@gmail.com", 'eric@5stops.com' ]
30
+ s.homepage = 'https://github.com/eric/syslog_protocol'
31
+
32
+ ## This gets added to the $LOAD_PATH so that 'lib/NAME.rb' can be required as
33
+ ## require 'NAME.rb' or'/lib/NAME/file.rb' can be as require 'NAME/file.rb'
34
+ s.require_paths = %w[lib]
35
+
36
+ ## This sections is only necessary if you have C extensions.
37
+ # s.require_paths << 'ext'
38
+ # s.extensions = %w[ext/extconf.rb]
39
+
40
+ ## If your gem includes any executables, list them here.
41
+ # s.executables = ["name"]
42
+ # s.default_executable = 'name'
43
+
44
+ ## Specify any RDoc options here. You'll want to add your README and
45
+ ## LICENSE files to the extra_rdoc_files list.
46
+ s.rdoc_options = ["--charset=UTF-8"]
47
+ s.extra_rdoc_files = %w[README.md]
48
+
49
+ ## List your runtime dependencies here. Runtime dependencies are those
50
+ ## that are needed for an end user to actually USE your code.
51
+ # s.add_dependency('DEPNAME', [">= 1.1.0", "< 2.0.0"])
52
+
53
+ ## List your development dependencies here. Development dependencies are
54
+ ## those that are only needed during development
55
+ s.add_development_dependency('bacon', [ '~> 1.1.0' ])
56
+
57
+ ## Leave this section as-is. It will be automatically generated from the
58
+ ## contents of your Git repository via the gemspec task. DO NOT REMOVE
59
+ ## THE MANIFEST COMMENTS, they are used as delimiters by the task.
60
+ # = MANIFEST =
61
+ s.files = %w[
62
+ Gemfile
63
+ README.md
64
+ Rakefile
65
+ lib/syslog_protocol.rb
66
+ lib/syslog_protocol/common.rb
67
+ lib/syslog_protocol/logger.rb
68
+ lib/syslog_protocol/packet.rb
69
+ lib/syslog_protocol/parser.rb
70
+ syslog_protocol.gemspec
71
+ test/helper.rb
72
+ test/test_logger.rb
73
+ test/test_packet.rb
74
+ test/test_parser.rb
75
+ ]
76
+ # = MANIFEST =
77
+
78
+ ## Test files will be grabbed from the file list. Make sure the path glob
79
+ ## matches what you actually use.
80
+ s.test_files = s.files.select { |path| path =~ /^test\/test_.*\.rb/ }
81
+ end
@@ -0,0 +1,13 @@
1
+ $:.unshift File.expand_path('../../lib', __FILE__)
2
+
3
+ unless ENV['BUNDLE_GEMFILE']
4
+ require 'rubygems'
5
+ require 'bundler'
6
+ Bundler.setup
7
+ Bundler.require
8
+ end
9
+
10
+ require 'bacon'
11
+ Bacon.summary_at_exit
12
+
13
+ require 'syslog_proto'
@@ -0,0 +1,28 @@
1
+ require File.expand_path('../helper', __FILE__)
2
+
3
+ describe "syslog logger" do
4
+
5
+ it "create a new logger with hostname and facility" do
6
+ lambda {@logger = SyslogProto::Logger.new("space_station", 'test', "local0")}.should.not.raise
7
+ end
8
+
9
+ it "hostname and facility must conform to the requirements of a Packet" do
10
+ lambda {SyslogProto::Logger.new("space station", "some shit", 'test test')}.should.raise ArgumentError
11
+ end
12
+
13
+ it "generates packets" do
14
+ # We have to set a time so we have a consistant timestamp to check against..
15
+ p = @logger.instance_variable_get("@packet")
16
+ p.time = Time.now
17
+ ts = p.generate_timestamp
18
+ @logger.debug("vacuum tubez are operational").should.equal "<135>#{ts} space_station test: vacuum tubez are operational"
19
+ @logger.info("firing thrusters at 13 degrees").should.equal "<134>#{ts} space_station test: firing thrusters at 13 degrees"
20
+ @logger.notice("the hyper drive has been activated").should.equal "<133>#{ts} space_station test: the hyper drive has been activated"
21
+ @logger.warn("meteorites incoming!").should.equal "<132>#{ts} space_station test: meteorites incoming!"
22
+ @logger.err("vacuum tube 3 in hyper drive failed").should.equal "<131>#{ts} space_station test: vacuum tube 3 in hyper drive failed"
23
+ @logger.crit("wing struck by a meteorite!").should.equal "<130>#{ts} space_station test: wing struck by a meteorite!"
24
+ @logger.alert("LEAKING ATMOSPHERE").should.equal "<129>#{ts} space_station test: LEAKING ATMOSPHERE"
25
+ @logger.emerg("LEAKING ASTRONAUTS WE ARE DONE").should.equal "<128>#{ts} space_station test: LEAKING ASTRONAUTS WE ARE DONE"
26
+ end
27
+
28
+ end
@@ -0,0 +1,92 @@
1
+ require File.expand_path('../helper', __FILE__)
2
+
3
+ describe "a syslog packet" do
4
+
5
+ @p = SyslogProto::Packet.new
6
+
7
+ it "should embarrass a person who does not set the fields" do
8
+ lambda { @p.to_s }.should.raise RuntimeError
9
+ end
10
+
11
+ it "hostname may not be omitted" do
12
+ lambda {@p.hostname = ""}.should.raise ArgumentError
13
+ end
14
+
15
+ it "hostname may only contain ASCII characters 33-126 (no spaces!)" do
16
+ lambda {@p.hostname = "linux box"}.should.raise ArgumentError
17
+ lambda {@p.hostname = "\000" + "linuxbox"}.should.raise ArgumentError
18
+ lambda {@p.hostname = "space_station"}.should.not.raise
19
+ end
20
+
21
+ it 'tag may only contain ASCII characters 33-126 (no spaces!)' do
22
+ lambda {@p.tag = "linux box"}.should.raise ArgumentError
23
+ lambda {@p.tag = "\000" + "linuxbox"}.should.raise ArgumentError
24
+ lambda {@p.tag = "test"}.should.not.raise
25
+ end
26
+
27
+ it "facility may only be set within 0-23 or with a proper string name" do
28
+ lambda {@p.facility = 666}.should.raise ArgumentError
29
+ lambda {@p.facility = "mir space station"}.should.raise ArgumentError
30
+
31
+ lambda {@p.facility = 16}.should.not.raise
32
+ @p.facility.should.equal 16
33
+ lambda {@p.facility = 'local0'}.should.not.raise
34
+ @p.facility.should.equal 16
35
+ end
36
+
37
+ it "severity may only be set within 0-7 or with a proper string name" do
38
+ lambda {@p.severity = 9876}.should.raise ArgumentError
39
+ lambda {@p.severity = "omgbroken"}.should.raise ArgumentError
40
+
41
+ lambda {@p.severity = 6}.should.not.raise
42
+ @p.severity.should.equal 6
43
+ lambda {@p.severity = 'info'}.should.not.raise
44
+ @p.severity.should.equal 6
45
+ end
46
+
47
+ it "severity can be checked using 'some_severity?' methods" do
48
+ @p.info?.should.equal true
49
+ @p.alert?.should.equal false
50
+ @p.emerg?.should.equal false
51
+ end
52
+
53
+ it "PRI is calculated from the facility and severity" do
54
+ @p.pri.should.equal 134
55
+ end
56
+
57
+ it "PRI may only be within 0-191" do
58
+ lambda {@p.pri = 22331}.should.raise ArgumentError
59
+ lambda {@p.pri = "foo"}.should.raise ArgumentError
60
+ end
61
+
62
+ it "facility and severity are deduced and set from setting a valid PRI" do
63
+ @p.pri = 165
64
+ @p.severity.should.equal 5
65
+ @p.facility.should.equal 20
66
+ end
67
+
68
+ it "return the proper names for facility and severity" do
69
+ @p.severity_name.should.equal 'notice'
70
+ @p.facility_name.should.equal 'local4'
71
+ end
72
+
73
+ it "set a message, which apparently can be anything" do
74
+ @p.content = "exploring ze black hole"
75
+ @p.content.should.equal "exploring ze black hole"
76
+ end
77
+
78
+ it "timestamp must conform to the retarded format" do
79
+ @p.generate_timestamp.should.match /(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\s(\s|[1-9])\d\s\d\d:\d\d:\d\d/
80
+ end
81
+
82
+ it "use the current time and assemble the packet" do
83
+ timestamp = @p.generate_timestamp
84
+ @p.to_s.should.equal "<165>#{timestamp} space_station test: exploring ze black hole"
85
+ end
86
+
87
+ it "packets larger than 1024 will be truncated" do
88
+ @p.content = "space warp" * 1000
89
+ @p.to_s.bytesize.should.equal 1024
90
+ end
91
+
92
+ end
@@ -0,0 +1,51 @@
1
+ require File.expand_path('../helper', __FILE__)
2
+
3
+ describe "syslog packet parser" do
4
+
5
+ it "parse some valid packets" do
6
+ p = SyslogProto.parse("<34>Oct 11 22:14:15 mymachine su: 'su root' failed for lonvick on /dev/pts/8")
7
+ p.facility.should.equal 4
8
+ p.severity.should.equal 2
9
+ p.pri.should.equal 34
10
+ p.hostname.should.equal "mymachine"
11
+ p.tag.should.equal 'su'
12
+ p.content.should.equal "'su root' failed for lonvick on /dev/pts/8"
13
+ p.time.should.equal Time.parse("Oct 11 22:14:15")
14
+
15
+ p = SyslogProto.parse("<13>Feb 5 17:32:18 10.0.0.99 test: Use the BFG!")
16
+ p.facility.should.equal 1
17
+ p.severity.should.equal 5
18
+ p.pri.should.equal 13
19
+ p.hostname.should.equal "10.0.0.99"
20
+ p.tag.should.equal 'test'
21
+ p.content.should.equal "Use the BFG!"
22
+ p.time.should.equal Time.parse("Feb 5 17:32:18")
23
+ end
24
+
25
+ it "treat a packet with no valid PRI as all content, setting defaults" do
26
+ p = SyslogProto.parse("nomnom")
27
+ p.facility.should.equal 1
28
+ p.severity.should.equal 5
29
+ p.pri.should.equal 13
30
+ p.hostname.should.equal 'unknown'
31
+ p.content.should.equal "nomnom"
32
+ end
33
+
34
+ it "PRI with preceding 0's shall be considered invalid" do
35
+ p = SyslogProto.parse("<045>Oct 11 22:14:15 space_station my PRI is not valid")
36
+ p.facility.should.equal 1
37
+ p.severity.should.equal 5
38
+ p.pri.should.equal 13
39
+ p.hostname.should.equal 'unknown'
40
+ p.content.should.equal "<045>Oct 11 22:14:15 space_station my PRI is not valid"
41
+ end
42
+
43
+ it "allow the user to pass an origin to be used as the hostname if packet is invalid" do
44
+ p = SyslogProto.parse("<045>Oct 11 22:14:15 space_station my PRI is not valid", '127.0.0.1')
45
+ p.facility.should.equal 1
46
+ p.severity.should.equal 5
47
+ p.pri.should.equal 13
48
+ p.hostname.should.equal '127.0.0.1'
49
+ p.content.should.equal "<045>Oct 11 22:14:15 space_station my PRI is not valid"
50
+ end
51
+ end
metadata ADDED
@@ -0,0 +1,99 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: syslog_protocol
3
+ version: !ruby/object:Gem::Version
4
+ hash: 59
5
+ prerelease: false
6
+ segments:
7
+ - 0
8
+ - 9
9
+ - 0
10
+ version: 0.9.0
11
+ platform: ruby
12
+ authors:
13
+ - Jake Douglas
14
+ - Eric Lindvall
15
+ autorequire:
16
+ bindir: bin
17
+ cert_chain: []
18
+
19
+ date: 2009-08-01 00:00:00 -07:00
20
+ default_executable:
21
+ dependencies:
22
+ - !ruby/object:Gem::Dependency
23
+ name: bacon
24
+ prerelease: false
25
+ requirement: &id001 !ruby/object:Gem::Requirement
26
+ none: false
27
+ requirements:
28
+ - - ~>
29
+ - !ruby/object:Gem::Version
30
+ hash: 19
31
+ segments:
32
+ - 1
33
+ - 1
34
+ - 0
35
+ version: 1.1.0
36
+ type: :development
37
+ version_requirements: *id001
38
+ description: Syslog protocol parser and generator
39
+ email:
40
+ - jakecdouglas@gmail.com
41
+ - eric@5stops.com
42
+ executables: []
43
+
44
+ extensions: []
45
+
46
+ extra_rdoc_files:
47
+ - README.md
48
+ files:
49
+ - Gemfile
50
+ - README.md
51
+ - Rakefile
52
+ - lib/syslog_protocol.rb
53
+ - lib/syslog_protocol/common.rb
54
+ - lib/syslog_protocol/logger.rb
55
+ - lib/syslog_protocol/packet.rb
56
+ - lib/syslog_protocol/parser.rb
57
+ - syslog_protocol.gemspec
58
+ - test/helper.rb
59
+ - test/test_logger.rb
60
+ - test/test_packet.rb
61
+ - test/test_parser.rb
62
+ has_rdoc: true
63
+ homepage: https://github.com/eric/syslog_protocol
64
+ licenses: []
65
+
66
+ post_install_message:
67
+ rdoc_options:
68
+ - --charset=UTF-8
69
+ require_paths:
70
+ - lib
71
+ required_ruby_version: !ruby/object:Gem::Requirement
72
+ none: false
73
+ requirements:
74
+ - - ">="
75
+ - !ruby/object:Gem::Version
76
+ hash: 3
77
+ segments:
78
+ - 0
79
+ version: "0"
80
+ required_rubygems_version: !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ">="
84
+ - !ruby/object:Gem::Version
85
+ hash: 3
86
+ segments:
87
+ - 0
88
+ version: "0"
89
+ requirements: []
90
+
91
+ rubyforge_project:
92
+ rubygems_version: 1.3.7
93
+ signing_key:
94
+ specification_version: 2
95
+ summary: Syslog protocol parser and generator
96
+ test_files:
97
+ - test/test_logger.rb
98
+ - test/test_packet.rb
99
+ - test/test_parser.rb