fluent-plugin-newsyslog 0.1.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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: b2f88ad81aa87528440228c6f20196250b0e3ba1
4
+ data.tar.gz: 5ff2e7de0a8b987e692667f98fc206d235315655
5
+ SHA512:
6
+ metadata.gz: 0d0db0f3ec65e44cf136f4d95b83d51343db8794b62afd659265b15029d5de2c9cef76e1c080759101dee423ee6172481b7f696093786f353f777f0dc8de2b59
7
+ data.tar.gz: c8a934ca856137097371aa02f2e5948b9ede3f028142384f2bab7863b4e2c849c365516676259c0d3ea6514652aa850b5cc1c699b4cf0489ce97f9e1b7677170
@@ -0,0 +1,10 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ /.idea/
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format documentation
2
+ --color
@@ -0,0 +1 @@
1
+ 2.1.5@fluent-plugin-newsyslog
@@ -0,0 +1,3 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.1.5
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in fluent-plugin-newsyslog.gemspec
4
+ gemspec
@@ -0,0 +1,96 @@
1
+ # Fluent::Plugin::NewSyslog
2
+
3
+ This is a new syslog input and parser plugins for Fluentd.
4
+ It supports the newer rfc5424 syslog format along with the older rfc3164 format.
5
+ It also automatically parse the time formats using the build in
6
+ ruby time parser rather than specifying the expected format from the syslog message.
7
+ The parser plugin is backwards compatible with the built in syslog parser.
8
+
9
+ ## Installation
10
+
11
+ Add this line to your application's Gemfile:
12
+
13
+ ```ruby
14
+ gem 'fluent-plugin-newsyslog'
15
+ ```
16
+
17
+ And then execute:
18
+
19
+ $ bundle
20
+
21
+ Or install it yourself as:
22
+
23
+ $ gem install fluent-plugin-newsyslog
24
+
25
+ ## Usage
26
+
27
+ ### `in_newsyslog` Input plugin
28
+
29
+ The `in_newsyslog` Input plugin enables Fluentd to retrieve records via the syslog protocol on UDP or TCP.
30
+ The default parser is the `parser_newsyslog` plugin.
31
+
32
+ #### Example Configuration
33
+ ```
34
+ <source>
35
+ type newsyslog
36
+ port 5140
37
+ bind 0.0.0.0
38
+ tag system
39
+ </source>
40
+ ```
41
+ #### Parameters
42
+ **type (required)**
43
+ The value must be newsyslog.
44
+
45
+ **port**
46
+ The port to listen to. Default Value = 5140
47
+
48
+ **bind**
49
+ The bind address to listen to. Default Value = 0.0.0.0 (all addresses)
50
+
51
+ **protocol_type**
52
+ The transport protocol used to receive logs. “udp” and “tcp” are supported. “udp” by default.
53
+
54
+ **tag (required)**
55
+ The prefix of the tag. The tag itself is generated by the tag prefix, facility level, and priority.
56
+
57
+ ### `parser_newsyslog` Parser plugin
58
+
59
+ The `parser_newsyslog` Parser plugin enables Fluentd to parse syslog records in either rfc5424 or rfc3164 format.
60
+
61
+ #### Example Configuration
62
+ This is an example to use this parser with the syslog plugin.
63
+ ```
64
+ <source>
65
+ type syslog
66
+ port 5140
67
+ bind 0.0.0.0
68
+ format newsyslog
69
+ tag system
70
+ </source>
71
+ ```
72
+ #### Parameters
73
+
74
+ **payload_message**
75
+ When set to true, it will output the entire syslog message into the message field rather than the parsed message field.
76
+ Default Value = false, send the parsed syslog message field.
77
+
78
+ ## Development
79
+
80
+ After checking out the repo, run `bundle` to install dependencies.
81
+
82
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `fluent-plugin-newsyslog.gemspec`, and then run `bundle exec rake release` to create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
83
+
84
+ ### Running unit tests
85
+ This gem is using both rspec and test::unit
86
+
87
+ execute `bundle exec rspec` to run the rspec tests
88
+ execute `bundle exec rake test` to run test::unit tests
89
+
90
+ ## Contributing
91
+
92
+ 1. Fork it ( https://github.com/athenahealth/fluent-plugin-newsyslog/fork )
93
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
94
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
95
+ 4. Push to the branch (`git push origin my-new-feature`)
96
+ 5. Create a new Pull Request
@@ -0,0 +1,26 @@
1
+ require 'bundler/gem_tasks'
2
+
3
+ require 'rake/testtask'
4
+ require 'rake/clean'
5
+ require 'rspec/core/rake_task'
6
+
7
+ RSpec::Core::RakeTask.new(:spec)
8
+
9
+ desc 'Run test_unit based test'
10
+ Rake::TestTask.new(:test) do |t|
11
+ # To run test for only one file (or file path pattern)
12
+ # $ bundle exec rake base_test TEST=test/test_specified_path.rb
13
+ # $ bundle exec rake base_test TEST=test/test_*.rb
14
+ t.libs << "test"
15
+ t.test_files = Dir["test/**/test_*.rb"].sort
16
+ t.verbose = true
17
+ #t.warning = true
18
+ end
19
+
20
+ desc 'Run test with simplecov'
21
+ task :coverage do |t|
22
+ ENV['SIMPLE_COV'] = '1'
23
+ Rake::Task["test"].invoke
24
+ end
25
+
26
+ task :default => [:test, :build]
@@ -0,0 +1,39 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = "fluent-plugin-newsyslog"
7
+ spec.version = "0.1.0"
8
+ spec.authors = ["Kevin Scheunemann"]
9
+ spec.email = ["kscheunemann@athenahealth.com"]
10
+
11
+ spec.summary = %q{A better fluentd syslog input and parser}
12
+ spec.description = %q{A fluentd syslog parser that handles multiple formats }
13
+ spec.homepage = "https://github.com/athenahealth/fluent-plugin-newsyslog"
14
+
15
+ # Prevent pushing this gem to RubyGems.org by setting 'allowed_push_host', or
16
+ # delete this section to allow pushing this gem to any host.
17
+ # if spec.respond_to?(:metadata)
18
+ # spec.metadata['allowed_push_host'] = "TODO: Set to 'http://mygemserver.com'"
19
+ # else
20
+ # raise "RubyGems 2.0 or newer is required to protect against public gem pushes."
21
+ # end
22
+
23
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
24
+ spec.bindir = "exe"
25
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
26
+ spec.require_paths = ["lib"]
27
+
28
+ spec.add_runtime_dependency 'fluentd', '>= 0.10.59'
29
+ spec.add_development_dependency 'bundler', '~> 1.9'
30
+ spec.add_development_dependency 'rake', '~> 10.0'
31
+ spec.add_development_dependency 'rspec'
32
+ spec.add_development_dependency 'flexmock'
33
+ spec.add_development_dependency 'simplecov', '~> 0.6.4'
34
+ spec.add_development_dependency 'rr', '>= 1.0.0'
35
+ spec.add_development_dependency 'timecop', '>= 0.3.0'
36
+ spec.add_development_dependency 'test-unit', '~> 3.0.2'
37
+ spec.add_development_dependency 'test-unit-rr', '~> 1.0.3'
38
+
39
+ end
@@ -0,0 +1,139 @@
1
+ module Fluent
2
+ class NewSyslogInput < Input
3
+ Plugin.register_input('newsyslog', self)
4
+
5
+ FACILITY_MAP = {
6
+ 0 => 'kern',
7
+ 1 => 'user',
8
+ 2 => 'mail',
9
+ 3 => 'daemon',
10
+ 4 => 'auth',
11
+ 5 => 'syslog',
12
+ 6 => 'lpr',
13
+ 7 => 'news',
14
+ 8 => 'uucp',
15
+ 9 => 'cron',
16
+ 10 => 'authpriv',
17
+ 11 => 'ftp',
18
+ 12 => 'ntp',
19
+ 13 => 'audit',
20
+ 14 => 'alert',
21
+ 15 => 'at',
22
+ 16 => 'local0',
23
+ 17 => 'local1',
24
+ 18 => 'local2',
25
+ 19 => 'local3',
26
+ 20 => 'local4',
27
+ 21 => 'local5',
28
+ 22 => 'local6',
29
+ 23 => 'local7'
30
+ }
31
+
32
+ PRIORITY_MAP = {
33
+ 0 => 'emerg',
34
+ 1 => 'alert',
35
+ 2 => 'crit',
36
+ 3 => 'err',
37
+ 4 => 'warn',
38
+ 5 => 'notice',
39
+ 6 => 'info',
40
+ 7 => 'debug'
41
+ }
42
+
43
+ def initialize
44
+ super
45
+ require 'cool.io'
46
+ require 'fluent/plugin/socket_util'
47
+ end
48
+
49
+ config_param :port, :integer, :default => 5140
50
+ config_param :bind, :string, :default => '0.0.0.0'
51
+ config_param :tag, :string
52
+ config_param :protocol_type, :default => :udp do |val|
53
+ case val.downcase
54
+ when 'tcp'
55
+ :tcp
56
+ when 'udp'
57
+ :udp
58
+ else
59
+ raise ConfigError, "syslog input protocol type should be 'tcp' or 'udp'"
60
+ end
61
+ end
62
+ config_param :include_source_host, :bool, :default => false
63
+ config_param :source_host_key, :string, :default => 'source_host'.freeze
64
+ config_param :blocking_timeout, :time, :default => 0.5
65
+
66
+ def configure(conf)
67
+ super
68
+ conf['with_priority'] = true
69
+ @parser = TextParser::NewSyslogParser.new
70
+ @parser.configure(conf)
71
+ end
72
+
73
+ def start
74
+ @loop = Coolio::Loop.new
75
+ @handler = listen(method(:receive_data))
76
+ @loop.attach(@handler)
77
+
78
+ @thread = Thread.new(&method(:run))
79
+ end
80
+
81
+ def shutdown
82
+ @loop.watchers.each {|w| w.detach }
83
+ @loop.stop
84
+ @handler.close
85
+ @thread.join
86
+ end
87
+
88
+ def run
89
+ @loop.run(@blocking_timeout)
90
+ rescue
91
+ log.error "unexpected error", :error=>$!.to_s
92
+ log.error_backtrace
93
+ end
94
+
95
+ private
96
+
97
+ def receive_data(data, addr)
98
+ @parser.parse(data) { |time, record|
99
+ unless time && record
100
+ log.warn "invalid syslog message", :data => data
101
+ return
102
+ end
103
+
104
+ pri = record.delete('pri')
105
+ record[@source_host_key] = addr[2] if @include_source_host
106
+ emit(pri, time, record)
107
+ }
108
+ rescue => e
109
+ log.error data.dump, :error => e.to_s
110
+ log.error_backtrace
111
+ end
112
+
113
+ private
114
+
115
+ def listen(callback)
116
+ log.debug "listening syslog socket on #{@bind}:#{@port} with #{@protocol_type}"
117
+ if @protocol_type == :udp
118
+ @usock = SocketUtil.create_udp_socket(@bind)
119
+ @usock.bind(@bind, @port)
120
+ SocketUtil::UdpHandler.new(@usock, log, 2048, callback)
121
+ else
122
+ # syslog family add "\n" to each message and this seems only way to split messages in tcp stream
123
+ Coolio::TCPServer.new(@bind, @port, SocketUtil::TcpHandler, log, "\n", callback)
124
+ end
125
+ end
126
+
127
+ def emit(pri, time, record)
128
+ facility = FACILITY_MAP[pri >> 3]
129
+ priority = PRIORITY_MAP[pri & 0b111]
130
+
131
+ tag = "#{@tag}.#{facility}.#{priority}"
132
+
133
+ router.emit(tag, time, record)
134
+ rescue => e
135
+ log.error "syslog failed to emit", :error => e.to_s, :error_class => e.class.to_s, :tag => tag, :record => Yajl.dump(record)
136
+ end
137
+
138
+ end
139
+ end
@@ -0,0 +1,88 @@
1
+ require 'fluent/parser'
2
+
3
+ module Fluent
4
+ class TextParser
5
+ class NewSyslogParser < Parser
6
+ # register as newsyslog parser
7
+ Plugin.register_parser("newsyslog", self)
8
+
9
+ # default to using the built in ruby time parser rather than specifying a time format
10
+ config_param :time_format, :string, :default => nil #"%b %d %H:%M:%S"
11
+ config_param :payload_message, :bool, :default => false
12
+ config_param :with_priority, :bool, :default => false
13
+
14
+ def initialize
15
+ super
16
+ @mutex = Mutex.new
17
+ end
18
+
19
+ def configure(conf)
20
+ super
21
+ @time_parser = TimeParser.new(@time_format)
22
+ end
23
+
24
+ def parse(text)
25
+
26
+ if @with_priority
27
+ if /^\<.*\>\d/.match(text)
28
+ #match rfc5424 syslog format
29
+ regex = /^\<(?<pri>[0-9]+)\>(1)(?<time>[^ ]* {1,2}[^ ]*) (?<host>[^ ]*) (?<ident>[^ ]*) (?<pid>[^ ]*) (?<msgid>[^ ]*) (-|) *(?<message>.*)$/
30
+ elsif /^\<.*>/.match(text)
31
+ #match rfc3164 syslog format
32
+ regex = /^\<(?<pri>[0-9]+)\>(?<time>[^ ]* {1,2}[^ ]* [^ ]*) (?<host>[^ ]*) (?<ident>[a-zA-Z0-9_\/\.\-]*)(?:\[(?<pid>[0-9]+)\])?(?:[^\:]*\:)? *(?<message>.*)$/
33
+ else
34
+ #set an impossible regex match if not matching a the start of a syslog message above
35
+ regex = /a^/
36
+ end
37
+ else
38
+ # with_priorty = false to support in_syslog plugin
39
+ regex = /^(?<time>[^ ]*\s*[^ ]* [^ ]*) (?<host>[^ ]*) (?<ident>[a-zA-Z0-9_\/\.\-]*)(?:\[(?<pid>[0-9]+)\])?(?:[^\:]*\:)? *(?<message>.*)$/
40
+ end
41
+
42
+
43
+ m = regex.match(text)
44
+ unless m
45
+ if block_given?
46
+ yield nil, nil
47
+ return
48
+ else
49
+ return nil, nil
50
+ end
51
+ end
52
+
53
+ Regexp.union
54
+
55
+ time = nil
56
+ record = {}
57
+
58
+ m.names.each { |name|
59
+ if value = m[name]
60
+ case name
61
+ when 'pri'
62
+ record['pri'] = value.to_i
63
+ when 'time'
64
+ time = @mutex.synchronize { @time_parser.parse(value.gsub(/ +/, ' ')) }
65
+ when 'message'
66
+ record['message'] = @payload_message? text : value
67
+ else
68
+ record[name] = value
69
+ end
70
+ end
71
+ }
72
+
73
+ if @estimate_current_event
74
+ time ||= Engine.now
75
+ end
76
+
77
+ if block_given?
78
+ yield time, record
79
+ else
80
+ return time, record
81
+ end
82
+
83
+
84
+ end
85
+
86
+ end
87
+ end
88
+ end
metadata ADDED
@@ -0,0 +1,193 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: fluent-plugin-newsyslog
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Kevin Scheunemann
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2015-05-05 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: fluentd
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: 0.10.59
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: 0.10.59
27
+ - !ruby/object:Gem::Dependency
28
+ name: bundler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.9'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.9'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '10.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '10.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: flexmock
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: simplecov
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: 0.6.4
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: 0.6.4
97
+ - !ruby/object:Gem::Dependency
98
+ name: rr
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: 1.0.0
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: 1.0.0
111
+ - !ruby/object:Gem::Dependency
112
+ name: timecop
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: 0.3.0
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: 0.3.0
125
+ - !ruby/object:Gem::Dependency
126
+ name: test-unit
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - "~>"
130
+ - !ruby/object:Gem::Version
131
+ version: 3.0.2
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - "~>"
137
+ - !ruby/object:Gem::Version
138
+ version: 3.0.2
139
+ - !ruby/object:Gem::Dependency
140
+ name: test-unit-rr
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - "~>"
144
+ - !ruby/object:Gem::Version
145
+ version: 1.0.3
146
+ type: :development
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - "~>"
151
+ - !ruby/object:Gem::Version
152
+ version: 1.0.3
153
+ description: 'A fluentd syslog parser that handles multiple formats '
154
+ email:
155
+ - kscheunemann@athenahealth.com
156
+ executables: []
157
+ extensions: []
158
+ extra_rdoc_files: []
159
+ files:
160
+ - ".gitignore"
161
+ - ".rspec"
162
+ - ".ruby-version"
163
+ - ".travis.yml"
164
+ - Gemfile
165
+ - README.md
166
+ - Rakefile
167
+ - fluent-plugin-newsyslog.gemspec
168
+ - lib/fluent/plugin/in_newsyslog.rb
169
+ - lib/fluent/plugin/parser_newsyslog.rb
170
+ homepage: https://github.com/athenahealth/fluent-plugin-newsyslog
171
+ licenses: []
172
+ metadata: {}
173
+ post_install_message:
174
+ rdoc_options: []
175
+ require_paths:
176
+ - lib
177
+ required_ruby_version: !ruby/object:Gem::Requirement
178
+ requirements:
179
+ - - ">="
180
+ - !ruby/object:Gem::Version
181
+ version: '0'
182
+ required_rubygems_version: !ruby/object:Gem::Requirement
183
+ requirements:
184
+ - - ">="
185
+ - !ruby/object:Gem::Version
186
+ version: '0'
187
+ requirements: []
188
+ rubyforge_project:
189
+ rubygems_version: 2.4.3
190
+ signing_key:
191
+ specification_version: 4
192
+ summary: A better fluentd syslog input and parser
193
+ test_files: []