fastly_fluent 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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 908f50379a7eebc384dadea58ff75cab3452ee55
4
+ data.tar.gz: 4bff227b7727af33b38d45afef1600b0b1c02935
5
+ SHA512:
6
+ metadata.gz: 1c4125fdf6248b2a62f5fd1916c85749e4ac3921c689f62555f3d7913c5a98cdd65f16df999f499a84dd03e74988494231be2ff75302d10ff8b2e6d7428d74ed
7
+ data.tar.gz: 3b33e3ed78c7bcea9c13b69ee51eea4ef764c6d4c5bce813e7af94da3bde49a7ae1488cd772c4a619ba87c763ae51ae4cd5d9e3b47220b8c86c5f533c6557011
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in fastly_fluent.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Benjamin Bryant
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,29 @@
1
+ # FastlyTd
2
+
3
+ TODO: Write a gem description
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'fastly_td'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install fastly_td
18
+
19
+ ## Usage
20
+
21
+ TODO: Write usage instructions here
22
+
23
+ ## Contributing
24
+
25
+ 1. Fork it
26
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
27
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
28
+ 4. Push to the branch (`git push origin my-new-feature`)
29
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,10 @@
1
+ require "bundler/gem_tasks"
2
+ require 'rake/testtask'
3
+
4
+ Rake::TestTask.new(:test) do |test|
5
+ test.libs << 'lib' << 'test'
6
+ test.pattern = 'test/**/test_*.rb'
7
+ test.verbose = true
8
+ end
9
+
10
+ task :default => :test
@@ -0,0 +1,23 @@
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 = "fastly_fluent"
7
+ spec.version = '0.0.1'
8
+ spec.authors = ["Benjamin Bryant"]
9
+ spec.email = ["benjaminhbryant@gmail.com"]
10
+ spec.description = %q{fluent plugin for JSON encoded fastly syslogs}
11
+ spec.summary = %q{}
12
+ spec.homepage = ""
13
+ spec.license = "MIT"
14
+
15
+ spec.files = `git ls-files`.split($/)
16
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
17
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
18
+ spec.require_paths = ["lib"]
19
+
20
+ spec.add_development_dependency "bundler", "~> 1.3"
21
+ spec.add_development_dependency "rake"
22
+ spec.add_runtime_dependency "fluentd"
23
+ end
@@ -0,0 +1,124 @@
1
+ #
2
+ # Fluent
3
+ #
4
+ # Copyright (C) 2011 FURUHASHI Sadayuki
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+ #
18
+ module Fluent
19
+ class FastlyInput < Input
20
+ Plugin.register_input('fastly', self)
21
+
22
+ #FASTLY_REGEXP = /^\<(?<pri>[0-9]+)\>(?<time>[^ ]+)\s(?<fastly_host>[^ ]+)\s(?<tag>[^\[]\[\d+\]\:)\s+(?<message>.*)$/
23
+ FASTLY_REGEXP = /^\<(?<pri>[0-9]+)\>(?<time>[^ ]+)\s(?<fastly_host>[^ ]+)\s(?<tag>[^\[]+)\[\d+\]:\s(?<message>.*)$/
24
+ FASTLY_TIME_FORMAT = "%Y-%m-%dT%H:%M:%SZ"
25
+
26
+ #{"method="}%t {"code"}%>s {"request"}%r
27
+
28
+ def initialize
29
+ super
30
+ require 'cool.io'
31
+ require 'fluent/plugin/socket_util'
32
+ end
33
+
34
+ config_param :port, :integer, :default => 5140
35
+ config_param :bind, :string, :default => '0.0.0.0'
36
+ config_param :tag, :string
37
+ config_param :protocol_type, :default => :udp do |val|
38
+ case val.downcase
39
+ when 'tcp'
40
+ :tcp
41
+ when 'udp'
42
+ :udp
43
+ else
44
+ raise ConfigError, "syslog input protocol type should be 'tcp' or 'udp'"
45
+ end
46
+ end
47
+
48
+ def configure(conf)
49
+ super
50
+ @parser = TextParser::RegexpParser.new(FASTLY_REGEXP, {'time_format' => FASTLY_TIME_FORMAT})
51
+ end
52
+
53
+ def start
54
+ callback = method(:receive_data)
55
+
56
+ @loop = Coolio::Loop.new
57
+ @handler = listen(callback)
58
+ @loop.attach(@handler)
59
+
60
+ @thread = Thread.new(&method(:run))
61
+ end
62
+
63
+ def shutdown
64
+ @loop.watchers.each {|w| w.detach }
65
+ @loop.stop
66
+ @handler.close
67
+ @thread.join
68
+ end
69
+
70
+ def run
71
+ @loop.run
72
+ rescue
73
+ log.error "unexpected error", :error=>$!.to_s
74
+ log.error_backtrace
75
+ end
76
+
77
+ protected
78
+
79
+ def receive_data(data, addr)
80
+
81
+ @parser.call(data) { |time, record|
82
+ unless time && record
83
+ log.warn "invalid syslog message", :data => data
84
+ return
85
+ end
86
+
87
+ pri = record.delete('pri').to_i
88
+
89
+ tag = record.delete('tag')
90
+
91
+ message = JSON.parse(record.delete('message'))
92
+ message.each do |k,v|
93
+ record[k] = v unless v == "(null)"
94
+ end
95
+
96
+
97
+ emit(tag, time, record)
98
+ }
99
+ rescue => e
100
+ log.error data.dump, :error => e.to_s
101
+ log.error_backtrace
102
+ end
103
+
104
+ private
105
+
106
+ def listen(callback)
107
+ log.debug "listening syslog socket on #{@bind}:#{@port} with #{@protocol_type}"
108
+ if @protocol_type == :udp
109
+ @usock = SocketUtil.create_udp_socket(@bind)
110
+ @usock.bind(@bind, @port)
111
+ SocketUtil::UdpHandler.new(@usock, log, 2048, callback)
112
+ else
113
+ # syslog family add "\n" to each message and this seems only way to split messages in tcp stream
114
+ Coolio::TCPServer.new(@bind, @port, SocketUtil::TcpHandler, log, "\n", callback)
115
+ end
116
+ end
117
+
118
+ def emit(tag, time, record)
119
+ Engine.emit(tag, time, record)
120
+ rescue => e
121
+ log.error "fastly failed to emit", :error => e.to_s, :error_class => e.class.to_s, :tag => tag, :record => Yajl.dump(record)
122
+ end
123
+ end
124
+ end
data/test/helper.rb ADDED
@@ -0,0 +1,31 @@
1
+ require 'test/unit'
2
+ require 'fileutils'
3
+ require 'fluent/log'
4
+ require 'fluent/test'
5
+
6
+ require 'fluent/plugin/in_fastly'
7
+
8
+ unless defined?(Test::Unit::AssertionFailedError)
9
+ class Test::Unit::AssertionFailedError < StandardError
10
+ end
11
+ end
12
+
13
+ def unused_port
14
+ s = TCPServer.open(0)
15
+ port = s.addr[1]
16
+ s.close
17
+ port
18
+ end
19
+
20
+ def ipv6_enabled?
21
+ require 'socket'
22
+
23
+ begin
24
+ TCPServer.open("::1", 0)
25
+ true
26
+ rescue
27
+ false
28
+ end
29
+ end
30
+
31
+ $log = Fluent::Log.new(Fluent::Test::DummyLogDevice.new, Fluent::Log::LEVEL_WARN)
@@ -0,0 +1,153 @@
1
+ require 'fluent/test'
2
+ require 'helper'
3
+
4
+ class FastlyInputTest < Test::Unit::TestCase
5
+ def setup
6
+ Fluent::Test.setup
7
+ require 'fluent/plugin/socket_util'
8
+ end
9
+
10
+ PORT = unused_port
11
+ CONFIG = %[
12
+ port #{PORT}
13
+ bind 127.0.0.1
14
+ tag fastly
15
+ ]
16
+
17
+ IPv6_CONFIG = %[
18
+ port #{PORT}
19
+ bind ::1
20
+ tag fastly
21
+ ]
22
+
23
+ def create_driver(conf=CONFIG)
24
+ Fluent::Test::InputTestDriver.new(Fluent::FastlyInput).configure(conf)
25
+ end
26
+
27
+ def test_configure
28
+ configs = {'127.0.0.1' => CONFIG}
29
+ configs.merge!('::1' => IPv6_CONFIG) if ipv6_enabled?
30
+
31
+ configs.each_pair { |k, v|
32
+ d = create_driver(v)
33
+ assert_equal PORT, d.instance.port
34
+ assert_equal k, d.instance.bind
35
+ }
36
+ end
37
+
38
+ def test_time_format
39
+ configs = {'127.0.0.1' => CONFIG}
40
+ configs.merge!('::1' => IPv6_CONFIG) if ipv6_enabled?
41
+
42
+ configs.each_pair { |k, v|
43
+ d = create_driver(v)
44
+
45
+ tests = [
46
+ {'msg' => "<134>2014-07-10T23:18:15Z cache-hk91 td.server.requests[11226]: {\"ip\":\"166.137.213.198\",\"client_id\":\"17a8e5f8f64a9a7c85d1ccab51bcfdf6\",\"status\":200,\"user_agent\":\"Mozilla/5.0 (iPhone; CPU iPhone OS 7_0_3 like Mac OS X) AppleWebKit/537.51.1 (KHTML, like Gecko) Version/7.0 Mobile/11B511 Safari/9537.53\",\"null_val\":\"(null)\"}", 'expected' => Time.new(2014,7,10,23,18,15).to_i },
47
+
48
+ {'msg' => "<134>2014-07-13T14:57:46Z cache-dfw1829 td.server.requests[524]: {\"ip\":\"166.137.213.198\",\"client_id\":\"17a8e5f8f64a9a7c85d1ccab51bcfdf6\",\"status\":200,\"user_agent\":\"Mozilla/5.0 (iPhone; CPU iPhone OS 7_0_3 like Mac OS X) AppleWebKit/537.51.1 (KHTML, like Gecko) Version/7.0 Mobile/11B511 Safari/9537.53\",\"null_val\":\"(null)\"}", 'expected' => Time.new(2014,07,13,14,57,46).to_i}
49
+
50
+ ]
51
+
52
+
53
+ d.run do
54
+ u = Fluent::SocketUtil.create_udp_socket(k)
55
+ u.connect(k, PORT)
56
+ tests.each {|test|
57
+ u.send(test['msg'], 0)
58
+ }
59
+ sleep 1
60
+ end
61
+
62
+ emits = d.emits
63
+
64
+ tests.each_index {|i|
65
+
66
+ assert_equal(tests[i]['expected'], emits[i][1])
67
+ }
68
+ }
69
+ end
70
+
71
+ def test_msg_size
72
+ d = create_driver
73
+ tests = create_test_case
74
+
75
+ d.run do
76
+ u = UDPSocket.new
77
+ u.connect('127.0.0.1', PORT)
78
+ tests.each {|test|
79
+ u.send(test['msg'], 0)
80
+ }
81
+ sleep 1
82
+ end
83
+
84
+ compare_test_result(d.emits, tests)
85
+ end
86
+
87
+ def test_msg_size_with_tcp
88
+ d = create_driver([CONFIG, 'protocol_type tcp'].join("\n"))
89
+ tests = create_test_case
90
+
91
+ d.run do
92
+ tests.each {|test|
93
+ TCPSocket.open('127.0.0.1', PORT) do |s|
94
+ s.send(test['msg'], 0)
95
+ end
96
+ }
97
+ sleep 1
98
+ end
99
+
100
+ compare_test_result(d.emits, tests)
101
+ end
102
+
103
+ def test_msg_size_with_same_tcp_connection
104
+ d = create_driver([CONFIG, 'protocol_type tcp'].join("\n"))
105
+ tests = create_test_case
106
+
107
+ d.run do
108
+ TCPSocket.open('127.0.0.1', PORT) do |s|
109
+ tests.each {|test|
110
+ s.send(test['msg'], 0)
111
+ }
112
+ end
113
+ sleep 1
114
+ end
115
+
116
+ compare_test_result(d.emits, tests)
117
+ end
118
+
119
+ def test_msg_size_with_json_format
120
+ d = create_driver([CONFIG, 'format json'].join("\n"))
121
+ time = Time.parse('2013-09-18 12:00:00 +0900').to_i
122
+ tests = ['Hello!', 'Syslog!'].map { |msg|
123
+ event = {'time' => time, 'message' => msg}
124
+ {'msg' => '<6>' + event.to_json + "\n", 'expected' => msg}
125
+ }
126
+
127
+ d.run do
128
+ u = UDPSocket.new
129
+ u.connect('127.0.0.1', PORT)
130
+ tests.each {|test|
131
+ u.send(test['msg'], 0)
132
+ }
133
+ sleep 1
134
+ end
135
+
136
+ compare_test_result(d.emits, tests)
137
+ end
138
+
139
+ def create_test_case
140
+ # actual syslog message has "\n"
141
+ [
142
+ {'msg' => '<6>Sep 10 00:00:00 localhost logger: ' + 'x' * 100 + "\n", 'expected' => 'x' * 100},
143
+ {'msg' => '<6>Sep 10 00:00:00 localhost logger: ' + 'x' * 1024 + "\n", 'expected' => 'x' * 1024},
144
+ ]
145
+ end
146
+
147
+ def compare_test_result(emits, tests)
148
+ emits.each_index { |i|
149
+ assert_equal('fastly.kern.info', emits[0][0]) # <6> means kern.info
150
+ assert_equal(tests[i]['expected'], emits[i][2]['message'])
151
+ }
152
+ end
153
+ end
metadata ADDED
@@ -0,0 +1,97 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: fastly_fluent
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Benjamin Bryant
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-07-13 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: '1.3'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: '1.3'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: fluentd
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - '>='
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ description: fluent plugin for JSON encoded fastly syslogs
56
+ email:
57
+ - benjaminhbryant@gmail.com
58
+ executables: []
59
+ extensions: []
60
+ extra_rdoc_files: []
61
+ files:
62
+ - .gitignore
63
+ - Gemfile
64
+ - LICENSE.txt
65
+ - README.md
66
+ - Rakefile
67
+ - fastly_fluent.gemspec
68
+ - lib/fluent/plugin/in_fastly.rb
69
+ - test/helper.rb
70
+ - test/plugin/test_fastly_fluent.rb
71
+ homepage: ''
72
+ licenses:
73
+ - MIT
74
+ metadata: {}
75
+ post_install_message:
76
+ rdoc_options: []
77
+ require_paths:
78
+ - lib
79
+ required_ruby_version: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - '>='
82
+ - !ruby/object:Gem::Version
83
+ version: '0'
84
+ required_rubygems_version: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - '>='
87
+ - !ruby/object:Gem::Version
88
+ version: '0'
89
+ requirements: []
90
+ rubyforge_project:
91
+ rubygems_version: 2.0.3
92
+ signing_key:
93
+ specification_version: 4
94
+ summary: ''
95
+ test_files:
96
+ - test/helper.rb
97
+ - test/plugin/test_fastly_fluent.rb