fluentd 0.10.35 → 0.10.36

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of fluentd might be problematic. Click here for more details.

@@ -16,189 +16,185 @@
16
16
  # limitations under the License.
17
17
  #
18
18
  module Fluent
19
+ class SyslogInput < Input
20
+ Plugin.register_input('syslog', self)
21
+
22
+ SYSLOG_REGEXP = /^\<([0-9]+)\>(.*)/
23
+ SYSLOG_ALL_REGEXP = /^\<(?<pri>[0-9]+)\>(?<time>[^ ]* {1,2}[^ ]* [^ ]*) (?<host>[^ ]*) (?<ident>[a-zA-Z0-9_\/\.\-]*)(?:\[(?<pid>[0-9]+)\])?[^\:]*\: *(?<message>.*)$/
24
+ TIME_FORMAT = "%b %d %H:%M:%S"
25
+
26
+ FACILITY_MAP = {
27
+ 0 => 'kern',
28
+ 1 => 'user',
29
+ 2 => 'mail',
30
+ 3 => 'daemon',
31
+ 4 => 'auth',
32
+ 5 => 'syslog',
33
+ 6 => 'lpr',
34
+ 7 => 'news',
35
+ 8 => 'uucp',
36
+ 9 => 'cron',
37
+ 10 => 'authpriv',
38
+ 11 => 'ftp',
39
+ 12 => 'ntp',
40
+ 13 => 'audit',
41
+ 14 => 'alert',
42
+ 15 => 'at',
43
+ 16 => 'local0',
44
+ 17 => 'local1',
45
+ 18 => 'local2',
46
+ 19 => 'local3',
47
+ 20 => 'local4',
48
+ 21 => 'local5',
49
+ 22 => 'local6',
50
+ 23 => 'local7'
51
+ }
19
52
 
53
+ PRIORITY_MAP = {
54
+ 0 => 'emerg',
55
+ 1 => 'alert',
56
+ 2 => 'crit',
57
+ 3 => 'err',
58
+ 4 => 'warn',
59
+ 5 => 'notice',
60
+ 6 => 'info',
61
+ 7 => 'debug'
62
+ }
20
63
 
21
- class SyslogInput < Input
22
- Plugin.register_input('syslog', self)
23
-
24
- SYSLOG_REGEXP = /^\<([0-9]+)\>(.*)/
25
- SYSLOG_ALL_REGEXP = /^\<(?<pri>[0-9]+)\>(?<time>[^ ]* {1,2}[^ ]* [^ ]*) (?<host>[^ ]*) (?<ident>[a-zA-Z0-9_\/\.\-]*)(?:\[(?<pid>[0-9]+)\])?[^\:]*\: *(?<message>.*)$/
26
- TIME_FORMAT = "%b %d %H:%M:%S"
27
-
28
- FACILITY_MAP = {
29
- 0 => 'kern',
30
- 1 => 'user',
31
- 2 => 'mail',
32
- 3 => 'daemon',
33
- 4 => 'auth',
34
- 5 => 'syslog',
35
- 6 => 'lpr',
36
- 7 => 'news',
37
- 8 => 'uucp',
38
- 9 => 'cron',
39
- 10 => 'authpriv',
40
- 11 => 'ftp',
41
- 12 => 'ntp',
42
- 13 => 'audit',
43
- 14 => 'alert',
44
- 15 => 'at',
45
- 16 => 'local0',
46
- 17 => 'local1',
47
- 18 => 'local2',
48
- 19 => 'local3',
49
- 20 => 'local4',
50
- 21 => 'local5',
51
- 22 => 'local6',
52
- 23 => 'local7'
53
- }
54
-
55
- PRIORITY_MAP = {
56
- 0 => 'emerg',
57
- 1 => 'alert',
58
- 2 => 'crit',
59
- 3 => 'err',
60
- 4 => 'warn',
61
- 5 => 'notice',
62
- 6 => 'info',
63
- 7 => 'debug'
64
- }
65
-
66
- def initialize
67
- super
68
- require 'fluent/plugin/socket_util'
69
- end
64
+ def initialize
65
+ super
66
+ require 'fluent/plugin/socket_util'
67
+ end
70
68
 
71
- config_param :port, :integer, :default => 5140
72
- config_param :bind, :string, :default => '0.0.0.0'
73
- config_param :tag, :string
69
+ config_param :port, :integer, :default => 5140
70
+ config_param :bind, :string, :default => '0.0.0.0'
71
+ config_param :tag, :string
74
72
 
75
- def configure(conf)
76
- super
73
+ def configure(conf)
74
+ super
77
75
 
78
- parser = TextParser.new
79
- if parser.configure(conf, false)
80
- @parser = parser
81
- else
82
- @parser = nil
83
- end
84
- end
85
-
86
- def start
87
- if @parser
88
- callback = method(:receive_data_parser)
89
- else
90
- callback = method(:receive_data)
76
+ parser = TextParser.new
77
+ if parser.configure(conf, false)
78
+ @parser = parser
79
+ else
80
+ @parser = nil
81
+ end
91
82
  end
92
83
 
93
- @loop = Coolio::Loop.new
94
-
95
- $log.debug "listening syslog socket on #{@bind}:#{@port}"
96
- @usock = SocketUtil.create_udp_socket(@bind)
97
- @usock.bind(@bind, @port)
84
+ def start
85
+ if @parser
86
+ callback = method(:receive_data_parser)
87
+ else
88
+ callback = method(:receive_data)
89
+ end
98
90
 
99
- @handler = UdpHandler.new(@usock, callback)
100
- @loop.attach(@handler)
91
+ @loop = Coolio::Loop.new
101
92
 
102
- @thread = Thread.new(&method(:run))
103
- end
93
+ $log.debug "listening syslog socket on #{@bind}:#{@port}"
94
+ @usock = SocketUtil.create_udp_socket(@bind)
95
+ @usock.bind(@bind, @port)
104
96
 
105
- def shutdown
106
- @loop.watchers.each {|w| w.detach }
107
- @loop.stop
108
- @handler.close
109
- @thread.join
110
- end
97
+ @handler = UdpHandler.new(@usock, callback)
98
+ @loop.attach(@handler)
111
99
 
112
- def run
113
- @loop.run
114
- rescue
115
- $log.error "unexpected error", :error=>$!.to_s
116
- $log.error_backtrace
117
- end
100
+ @thread = Thread.new(&method(:run))
101
+ end
118
102
 
119
- protected
120
- def receive_data_parser(data)
121
- m = SYSLOG_REGEXP.match(data)
122
- unless m
123
- $log.debug "invalid syslog message: #{data.dump}"
124
- return
103
+ def shutdown
104
+ @loop.watchers.each {|w| w.detach }
105
+ @loop.stop
106
+ @handler.close
107
+ @thread.join
125
108
  end
126
- pri = m[1].to_i
127
- text = m[2]
128
109
 
129
- time, record = @parser.parse(text)
130
- unless time && record
131
- return
110
+ def run
111
+ @loop.run
112
+ rescue
113
+ $log.error "unexpected error", :error=>$!.to_s
114
+ $log.error_backtrace
132
115
  end
133
116
 
134
- emit(pri, time, record)
117
+ protected
118
+ def receive_data_parser(data)
119
+ m = SYSLOG_REGEXP.match(data)
120
+ unless m
121
+ $log.debug "invalid syslog message: #{data.dump}"
122
+ return
123
+ end
124
+ pri = m[1].to_i
125
+ text = m[2]
135
126
 
136
- rescue
137
- $log.warn data.dump, :error=>$!.to_s
138
- $log.debug_backtrace
139
- end
127
+ time, record = @parser.parse(text)
128
+ unless time && record
129
+ return
130
+ end
131
+
132
+ emit(pri, time, record)
140
133
 
141
- def receive_data(data)
142
- m = SYSLOG_ALL_REGEXP.match(data)
143
- unless m
144
- $log.debug "invalid syslog message", :data=>data
145
- return
134
+ rescue
135
+ $log.warn data.dump, :error=>$!.to_s
136
+ $log.debug_backtrace
146
137
  end
147
138
 
148
- pri = nil
149
- time = nil
150
- record = {}
151
-
152
- m.names.each {|name|
153
- if value = m[name]
154
- case name
155
- when "pri"
156
- pri = value.to_i
157
- when "time"
158
- time = Time.strptime(value.gsub(/ +/, ' '), TIME_FORMAT).to_i
159
- else
160
- record[name] = value
161
- end
139
+ def receive_data(data)
140
+ m = SYSLOG_ALL_REGEXP.match(data)
141
+ unless m
142
+ $log.debug "invalid syslog message", :data=>data
143
+ return
162
144
  end
163
- }
164
145
 
165
- time ||= Engine.now
146
+ pri = nil
147
+ time = nil
148
+ record = {}
149
+
150
+ m.names.each {|name|
151
+ if value = m[name]
152
+ case name
153
+ when "pri"
154
+ pri = value.to_i
155
+ when "time"
156
+ time = Time.strptime(value.gsub(/ +/, ' '), TIME_FORMAT).to_i
157
+ else
158
+ record[name] = value
159
+ end
160
+ end
161
+ }
166
162
 
167
- emit(pri, time, record)
163
+ time ||= Engine.now
168
164
 
169
- rescue
170
- $log.warn data.dump, :error=>$!.to_s
171
- $log.debug_backtrace
172
- end
165
+ emit(pri, time, record)
173
166
 
174
- private
175
- def emit(pri, time, record)
176
- facility = FACILITY_MAP[pri >> 3]
177
- priority = PRIORITY_MAP[pri & 0b111]
167
+ rescue
168
+ $log.warn data.dump, :error=>$!.to_s
169
+ $log.debug_backtrace
170
+ end
178
171
 
179
- tag = "#{@tag}.#{facility}.#{priority}"
172
+ private
173
+ def emit(pri, time, record)
174
+ facility = FACILITY_MAP[pri >> 3]
175
+ priority = PRIORITY_MAP[pri & 0b111]
180
176
 
181
- Engine.emit(tag, time, record)
182
- end
177
+ tag = "#{@tag}.#{facility}.#{priority}"
183
178
 
184
- class UdpHandler < Coolio::IO
185
- def initialize(io, callback)
186
- super(io)
187
- @io = io
188
- @callback = callback
179
+ Engine.emit(tag, time, record)
189
180
  end
190
181
 
191
- def on_readable
192
- msg, addr = @io.recvfrom_nonblock(2048)
193
- #host = addr[3]
194
- #port = addr[1]
195
- #@callback.call(host, port, msg)
196
- @callback.call(msg)
197
- rescue
198
- # TODO log?
182
+ class UdpHandler < Coolio::IO
183
+ def initialize(io, callback)
184
+ super(io)
185
+ @io = io
186
+ @callback = callback
187
+ end
188
+
189
+ def on_readable
190
+ msg, addr = @io.recvfrom_nonblock(2048)
191
+ #host = addr[3]
192
+ #port = addr[1]
193
+ #@callback.call(host, port, msg)
194
+ @callback.call(msg)
195
+ rescue
196
+ # TODO log?
197
+ end
199
198
  end
200
199
  end
201
200
  end
202
-
203
-
204
- end
@@ -16,485 +16,480 @@
16
16
  # limitations under the License.
17
17
  #
18
18
  module Fluent
19
+ class TailInput < Input
20
+ Plugin.register_input('tail', self)
19
21
 
22
+ def initialize
23
+ super
24
+ @paths = []
25
+ end
20
26
 
21
- class TailInput < Input
22
- Plugin.register_input('tail', self)
27
+ config_param :path, :string
28
+ config_param :tag, :string
29
+ config_param :rotate_wait, :time, :default => 5
30
+ config_param :pos_file, :string, :default => nil
23
31
 
24
- def initialize
25
- super
26
- @paths = []
27
- end
32
+ attr_reader :paths
28
33
 
29
- config_param :path, :string
30
- config_param :tag, :string
31
- config_param :rotate_wait, :time, :default => 5
32
- config_param :pos_file, :string, :default => nil
34
+ def configure(conf)
35
+ super
33
36
 
34
- attr_reader :paths
37
+ @paths = @path.split(',').map {|path| path.strip }
38
+ if @paths.empty?
39
+ raise ConfigError, "tail: 'path' parameter is required on tail input"
40
+ end
35
41
 
36
- def configure(conf)
37
- super
42
+ if @pos_file
43
+ @pf_file = File.open(@pos_file, File::RDWR|File::CREAT, DEFAULT_FILE_PERMISSION)
44
+ @pf_file.sync = true
45
+ @pf = PositionFile.parse(@pf_file)
46
+ else
47
+ $log.warn "'pos_file PATH' parameter is not set to a 'tail' source."
48
+ $log.warn "this parameter is highly recommended to save the position to resume tailing."
49
+ end
38
50
 
39
- @paths = @path.split(',').map {|path| path.strip }
40
- if @paths.empty?
41
- raise ConfigError, "tail: 'path' parameter is required on tail input"
51
+ configure_parser(conf)
42
52
  end
43
53
 
44
- if @pos_file
45
- @pf_file = File.open(@pos_file, File::RDWR|File::CREAT, DEFAULT_FILE_PERMISSION)
46
- @pf_file.sync = true
47
- @pf = PositionFile.parse(@pf_file)
48
- else
49
- $log.warn "'pos_file PATH' parameter is not set to a 'tail' source."
50
- $log.warn "this parameter is highly recommended to save the position to resume tailing."
54
+ def configure_parser(conf)
55
+ @parser = TextParser.new
56
+ @parser.configure(conf)
51
57
  end
52
58
 
53
- configure_parser(conf)
54
- end
55
-
56
- def configure_parser(conf)
57
- @parser = TextParser.new
58
- @parser.configure(conf)
59
- end
60
-
61
- def start
62
- @loop = Coolio::Loop.new
63
- @tails = @paths.map {|path|
64
- pe = @pf ? @pf[path] : MemoryPositionEntry.new
65
- TailWatcher.new(path, @rotate_wait, pe, &method(:receive_lines))
66
- }
67
- @tails.each {|tail|
68
- tail.attach(@loop)
69
- }
70
- @thread = Thread.new(&method(:run))
71
- end
59
+ def start
60
+ @loop = Coolio::Loop.new
61
+ @tails = @paths.map {|path|
62
+ pe = @pf ? @pf[path] : MemoryPositionEntry.new
63
+ TailWatcher.new(path, @rotate_wait, pe, &method(:receive_lines))
64
+ }
65
+ @tails.each {|tail|
66
+ tail.attach(@loop)
67
+ }
68
+ @thread = Thread.new(&method(:run))
69
+ end
72
70
 
73
- def shutdown
74
- @tails.each {|tail|
75
- tail.close
76
- }
77
- @loop.stop
78
- @thread.join
79
- @pf_file.close if @pf_file
80
- end
71
+ def shutdown
72
+ @tails.each {|tail|
73
+ tail.close
74
+ }
75
+ @loop.stop
76
+ @thread.join
77
+ @pf_file.close if @pf_file
78
+ end
81
79
 
82
- def run
83
- @loop.run
84
- rescue
85
- $log.error "unexpected error", :error=>$!.to_s
86
- $log.error_backtrace
87
- end
80
+ def run
81
+ @loop.run
82
+ rescue
83
+ $log.error "unexpected error", :error=>$!.to_s
84
+ $log.error_backtrace
85
+ end
88
86
 
89
- def receive_lines(lines)
90
- es = MultiEventStream.new
91
- lines.each {|line|
92
- begin
93
- line.chomp! # remove \n
94
- time, record = parse_line(line)
95
- if time && record
96
- es.add(time, record)
87
+ def receive_lines(lines)
88
+ es = MultiEventStream.new
89
+ lines.each {|line|
90
+ begin
91
+ line.chomp! # remove \n
92
+ time, record = parse_line(line)
93
+ if time && record
94
+ es.add(time, record)
95
+ end
96
+ rescue
97
+ $log.warn line.dump, :error=>$!.to_s
98
+ $log.debug_backtrace
97
99
  end
98
- rescue
99
- $log.warn line.dump, :error=>$!.to_s
100
- $log.debug_backtrace
101
- end
102
- }
100
+ }
103
101
 
104
- unless es.empty?
105
- begin
106
- Engine.emit_stream(@tag, es)
107
- rescue
108
- # ignore errors. Engine shows logs and backtraces.
102
+ unless es.empty?
103
+ begin
104
+ Engine.emit_stream(@tag, es)
105
+ rescue
106
+ # ignore errors. Engine shows logs and backtraces.
107
+ end
109
108
  end
110
109
  end
111
- end
112
110
 
113
- def parse_line(line)
114
- return @parser.parse(line)
115
- end
111
+ def parse_line(line)
112
+ return @parser.parse(line)
113
+ end
116
114
 
117
- class TailWatcher
118
- def initialize(path, rotate_wait, pe, &receive_lines)
119
- @path = path
120
- @rotate_wait = rotate_wait
121
- @pe = pe || MemoryPositionEntry.new
122
- @receive_lines = receive_lines
115
+ class TailWatcher
116
+ def initialize(path, rotate_wait, pe, &receive_lines)
117
+ @path = path
118
+ @rotate_wait = rotate_wait
119
+ @pe = pe || MemoryPositionEntry.new
120
+ @receive_lines = receive_lines
123
121
 
124
- @rotate_queue = []
122
+ @rotate_queue = []
125
123
 
126
- @timer_trigger = TimerWatcher.new(1, true, &method(:on_notify))
127
- @stat_trigger = StatWatcher.new(path, &method(:on_notify))
124
+ @timer_trigger = TimerWatcher.new(1, true, &method(:on_notify))
125
+ @stat_trigger = StatWatcher.new(path, &method(:on_notify))
128
126
 
129
- @rotate_handler = RotateHandler.new(path, &method(:on_rotate))
130
- @io_handler = nil
131
- end
127
+ @rotate_handler = RotateHandler.new(path, &method(:on_rotate))
128
+ @io_handler = nil
129
+ end
132
130
 
133
- def attach(loop)
134
- @timer_trigger.attach(loop)
135
- @stat_trigger.attach(loop)
136
- on_notify
137
- end
131
+ def attach(loop)
132
+ @timer_trigger.attach(loop)
133
+ @stat_trigger.attach(loop)
134
+ on_notify
135
+ end
138
136
 
139
- def detach
140
- @timer_trigger.detach if @timer_trigger.attached?
141
- @stat_trigger.detach if @stat_trigger.attached?
142
- end
137
+ def detach
138
+ @timer_trigger.detach if @timer_trigger.attached?
139
+ @stat_trigger.detach if @stat_trigger.attached?
140
+ end
143
141
 
144
- def close
145
- @rotate_queue.reject! {|req|
146
- req.io.close
147
- true
148
- }
149
- detach
150
- end
142
+ def close
143
+ @rotate_queue.reject! {|req|
144
+ req.io.close
145
+ true
146
+ }
147
+ detach
148
+ end
151
149
 
152
- def on_notify
153
- @rotate_handler.on_notify
154
- return unless @io_handler
155
- @io_handler.on_notify
156
-
157
- # proceeds rotate queue
158
- return if @rotate_queue.empty?
159
- @rotate_queue.first.tick
160
-
161
- while @rotate_queue.first.ready?
162
- if io = @rotate_queue.first.io
163
- stat = io.stat
164
- inode = stat.ino
165
- if inode == @pe.read_inode
166
- # rotated file has the same inode number with the last file.
167
- # assuming following situation:
168
- # a) file was once renamed and backed, or
169
- # b) symlink or hardlink to the same file is recreated
170
- # in either case, seek to the saved position
171
- pos = @pe.read_pos
150
+ def on_notify
151
+ @rotate_handler.on_notify
152
+ return unless @io_handler
153
+ @io_handler.on_notify
154
+
155
+ # proceeds rotate queue
156
+ return if @rotate_queue.empty?
157
+ @rotate_queue.first.tick
158
+
159
+ while @rotate_queue.first.ready?
160
+ if io = @rotate_queue.first.io
161
+ stat = io.stat
162
+ inode = stat.ino
163
+ if inode == @pe.read_inode
164
+ # rotated file has the same inode number with the last file.
165
+ # assuming following situation:
166
+ # a) file was once renamed and backed, or
167
+ # b) symlink or hardlink to the same file is recreated
168
+ # in either case, seek to the saved position
169
+ pos = @pe.read_pos
170
+ else
171
+ pos = io.pos
172
+ end
173
+ @pe.update(inode, pos)
174
+ io_handler = IOHandler.new(io, @pe, &@receive_lines)
172
175
  else
173
- pos = io.pos
176
+ io_handler = NullIOHandler.new
174
177
  end
175
- @pe.update(inode, pos)
176
- io_handler = IOHandler.new(io, @pe, &@receive_lines)
177
- else
178
- io_handler = NullIOHandler.new
178
+ @io_handler.close
179
+ @io_handler = io_handler
180
+ @rotate_queue.shift
181
+ break if @rotate_queue.empty?
179
182
  end
180
- @io_handler.close
181
- @io_handler = io_handler
182
- @rotate_queue.shift
183
- break if @rotate_queue.empty?
184
183
  end
185
- end
186
184
 
187
- def on_rotate(io)
188
- if @io_handler == nil
189
- if io
190
- # first time
191
- stat = io.stat
192
- fsize = stat.size
193
- inode = stat.ino
194
-
195
- last_inode = @pe.read_inode
196
- if inode == last_inode
197
- # seek to the saved position
198
- pos = @pe.read_pos
199
- elsif last_inode != 0
200
- # this is FilePositionEntry and fluentd once started.
201
- # read data from the head of the rotated file.
202
- # logs never duplicate because this file is a rotated new file.
203
- pos = 0
204
- @pe.update(inode, pos)
185
+ def on_rotate(io)
186
+ if @io_handler == nil
187
+ if io
188
+ # first time
189
+ stat = io.stat
190
+ fsize = stat.size
191
+ inode = stat.ino
192
+
193
+ last_inode = @pe.read_inode
194
+ if inode == last_inode
195
+ # seek to the saved position
196
+ pos = @pe.read_pos
197
+ elsif last_inode != 0
198
+ # this is FilePositionEntry and fluentd once started.
199
+ # read data from the head of the rotated file.
200
+ # logs never duplicate because this file is a rotated new file.
201
+ pos = 0
202
+ @pe.update(inode, pos)
203
+ else
204
+ # this is MemoryPositionEntry or this is the first time fluentd started.
205
+ # seek to the end of the any files.
206
+ # logs may duplicate without this seek because it's not sure the file is
207
+ # existent file or rotated new file.
208
+ pos = fsize
209
+ @pe.update(inode, pos)
210
+ end
211
+ io.seek(pos)
212
+
213
+ @io_handler = IOHandler.new(io, @pe, &@receive_lines)
205
214
  else
206
- # this is MemoryPositionEntry or this is the first time fluentd started.
207
- # seek to the end of the any files.
208
- # logs may duplicate without this seek because it's not sure the file is
209
- # existent file or rotated new file.
210
- pos = fsize
211
- @pe.update(inode, pos)
215
+ @io_handler = NullIOHandler.new
212
216
  end
213
- io.seek(pos)
214
217
 
215
- @io_handler = IOHandler.new(io, @pe, &@receive_lines)
216
218
  else
217
- @io_handler = NullIOHandler.new
218
- end
219
-
220
- else
221
- if io && @rotate_queue.find {|req| req.io == io }
222
- return
223
- end
224
- last_io = @rotate_queue.empty? ? @io_handler.io : @rotate_queue.last.io
225
- if last_io == nil
226
- $log.info "detected rotation of #{@path}"
227
- # rotate imeediately if previous file is nil
228
- wait = 0
229
- else
230
- $log.info "detected rotation of #{@path}; waiting #{@rotate_wait} seconds"
231
- wait = @rotate_wait
232
- wait -= @rotate_queue.first.wait unless @rotate_queue.empty?
219
+ if io && @rotate_queue.find {|req| req.io == io }
220
+ return
221
+ end
222
+ last_io = @rotate_queue.empty? ? @io_handler.io : @rotate_queue.last.io
223
+ if last_io == nil
224
+ $log.info "detected rotation of #{@path}"
225
+ # rotate imeediately if previous file is nil
226
+ wait = 0
227
+ else
228
+ $log.info "detected rotation of #{@path}; waiting #{@rotate_wait} seconds"
229
+ wait = @rotate_wait
230
+ wait -= @rotate_queue.first.wait unless @rotate_queue.empty?
231
+ end
232
+ @rotate_queue << RotationRequest.new(io, wait)
233
233
  end
234
- @rotate_queue << RotationRequest.new(io, wait)
235
234
  end
236
- end
237
235
 
238
- class TimerWatcher < Coolio::TimerWatcher
239
- def initialize(interval, repeat, &callback)
240
- @callback = callback
241
- super(interval, repeat)
242
- end
236
+ class TimerWatcher < Coolio::TimerWatcher
237
+ def initialize(interval, repeat, &callback)
238
+ @callback = callback
239
+ super(interval, repeat)
240
+ end
243
241
 
244
- def on_timer
245
- @callback.call
246
- rescue
247
- # TODO log?
248
- $log.error $!.to_s
249
- $log.error_backtrace
242
+ def on_timer
243
+ @callback.call
244
+ rescue
245
+ # TODO log?
246
+ $log.error $!.to_s
247
+ $log.error_backtrace
248
+ end
250
249
  end
251
- end
252
250
 
253
- class StatWatcher < Coolio::StatWatcher
254
- def initialize(path, &callback)
255
- @callback = callback
256
- super(path)
257
- end
251
+ class StatWatcher < Coolio::StatWatcher
252
+ def initialize(path, &callback)
253
+ @callback = callback
254
+ super(path)
255
+ end
258
256
 
259
- def on_change(prev, cur)
260
- @callback.call
261
- rescue
262
- # TODO log?
263
- $log.error $!.to_s
264
- $log.error_backtrace
257
+ def on_change(prev, cur)
258
+ @callback.call
259
+ rescue
260
+ # TODO log?
261
+ $log.error $!.to_s
262
+ $log.error_backtrace
263
+ end
265
264
  end
266
- end
267
265
 
268
- class RotationRequest
269
- def initialize(io, wait)
270
- @io = io
271
- @wait = wait
272
- end
266
+ class RotationRequest
267
+ def initialize(io, wait)
268
+ @io = io
269
+ @wait = wait
270
+ end
273
271
 
274
- attr_reader :io, :wait
272
+ attr_reader :io, :wait
275
273
 
276
- def tick
277
- @wait -= 1
278
- end
274
+ def tick
275
+ @wait -= 1
276
+ end
279
277
 
280
- def ready?
281
- @wait <= 0
278
+ def ready?
279
+ @wait <= 0
280
+ end
282
281
  end
283
- end
284
282
 
285
- MAX_LINES_AT_ONCE = 1000
286
-
287
- class IOHandler
288
- def initialize(io, pe, &receive_lines)
289
- $log.info "following tail of #{io.path}"
290
- @io = io
291
- @pe = pe
292
- @receive_lines = receive_lines
293
- @buffer = ''.force_encoding('ASCII-8BIT')
294
- @iobuf = ''.force_encoding('ASCII-8BIT')
295
- end
283
+ MAX_LINES_AT_ONCE = 1000
296
284
 
297
- attr_reader :io
285
+ class IOHandler
286
+ def initialize(io, pe, &receive_lines)
287
+ $log.info "following tail of #{io.path}"
288
+ @io = io
289
+ @pe = pe
290
+ @receive_lines = receive_lines
291
+ @buffer = ''.force_encoding('ASCII-8BIT')
292
+ @iobuf = ''.force_encoding('ASCII-8BIT')
293
+ end
298
294
 
299
- def on_notify
300
- begin
301
- lines = []
302
- read_more = false
295
+ attr_reader :io
303
296
 
297
+ def on_notify
304
298
  begin
305
- while true
306
- if @buffer.empty?
307
- @io.read_nonblock(2048, @buffer)
308
- else
309
- @buffer << @io.read_nonblock(2048, @iobuf)
310
- end
311
- while line = @buffer.slice!(/.*?\n/m)
312
- lines << line
313
- end
314
- if lines.size >= MAX_LINES_AT_ONCE
315
- # not to use too much memory in case the file is very large
316
- read_more = true
317
- break
299
+ lines = []
300
+ read_more = false
301
+
302
+ begin
303
+ while true
304
+ if @buffer.empty?
305
+ @io.read_nonblock(2048, @buffer)
306
+ else
307
+ @buffer << @io.read_nonblock(2048, @iobuf)
308
+ end
309
+ while line = @buffer.slice!(/.*?\n/m)
310
+ lines << line
311
+ end
312
+ if lines.size >= MAX_LINES_AT_ONCE
313
+ # not to use too much memory in case the file is very large
314
+ read_more = true
315
+ break
316
+ end
318
317
  end
318
+ rescue EOFError
319
319
  end
320
- rescue EOFError
321
- end
322
320
 
323
- unless lines.empty?
324
- @receive_lines.call(lines)
325
- @pe.update_pos(@io.pos - @buffer.bytesize)
326
- end
321
+ unless lines.empty?
322
+ @receive_lines.call(lines)
323
+ @pe.update_pos(@io.pos - @buffer.bytesize)
324
+ end
327
325
 
328
- end while read_more
326
+ end while read_more
329
327
 
330
- rescue
331
- $log.error $!.to_s
332
- $log.error_backtrace
333
- close
334
- end
335
-
336
- def close
337
- @io.close unless @io.closed?
338
- end
339
- end
328
+ rescue
329
+ $log.error $!.to_s
330
+ $log.error_backtrace
331
+ close
332
+ end
340
333
 
341
- class NullIOHandler
342
- def initialize
334
+ def close
335
+ @io.close unless @io.closed?
336
+ end
343
337
  end
344
338
 
345
- def io
346
- end
339
+ class NullIOHandler
340
+ def initialize
341
+ end
347
342
 
348
- def on_notify
349
- end
343
+ def io
344
+ end
350
345
 
351
- def close
352
- end
353
- end
346
+ def on_notify
347
+ end
354
348
 
355
- class RotateHandler
356
- def initialize(path, &on_rotate)
357
- @path = path
358
- @inode = nil
359
- @fsize = -1 # first
360
- @on_rotate = on_rotate
361
- @path = path
349
+ def close
350
+ end
362
351
  end
363
352
 
364
- def on_notify
365
- begin
366
- io = File.open(@path)
367
- stat = io.stat
368
- inode = stat.ino
369
- fsize = stat.size
370
- rescue Errno::ENOENT
371
- # moved or deleted
372
- inode = nil
373
- fsize = 0
353
+ class RotateHandler
354
+ def initialize(path, &on_rotate)
355
+ @path = path
356
+ @inode = nil
357
+ @fsize = -1 # first
358
+ @on_rotate = on_rotate
359
+ @path = path
374
360
  end
375
361
 
376
- begin
377
- if @inode != inode || fsize < @fsize
378
- # rotated or truncated
379
- @on_rotate.call(io)
380
- io = nil
362
+ def on_notify
363
+ begin
364
+ io = File.open(@path)
365
+ stat = io.stat
366
+ inode = stat.ino
367
+ fsize = stat.size
368
+ rescue Errno::ENOENT
369
+ # moved or deleted
370
+ inode = nil
371
+ fsize = 0
381
372
  end
382
373
 
383
- @inode = inode
384
- @fsize = fsize
385
- ensure
386
- io.close if io
387
- end
374
+ begin
375
+ if @inode != inode || fsize < @fsize
376
+ # rotated or truncated
377
+ @on_rotate.call(io)
378
+ io = nil
379
+ end
380
+
381
+ @inode = inode
382
+ @fsize = fsize
383
+ ensure
384
+ io.close if io
385
+ end
388
386
 
389
- rescue
390
- $log.error $!.to_s
391
- $log.error_backtrace
387
+ rescue
388
+ $log.error $!.to_s
389
+ $log.error_backtrace
390
+ end
392
391
  end
393
392
  end
394
- end
395
393
 
396
394
 
397
- class PositionFile
398
- def initialize(file, map, last_pos)
399
- @file = file
400
- @map = map
401
- @last_pos = last_pos
402
- end
403
-
404
- def [](path)
405
- if m = @map[path]
406
- return m
395
+ class PositionFile
396
+ def initialize(file, map, last_pos)
397
+ @file = file
398
+ @map = map
399
+ @last_pos = last_pos
407
400
  end
408
401
 
409
- @file.pos = @last_pos
410
- @file.write path
411
- @file.write "\t"
412
- seek = @file.pos
413
- @file.write "0000000000000000\t00000000\n"
414
- @last_pos = @file.pos
402
+ def [](path)
403
+ if m = @map[path]
404
+ return m
405
+ end
415
406
 
416
- @map[path] = FilePositionEntry.new(@file, seek)
417
- end
407
+ @file.pos = @last_pos
408
+ @file.write path
409
+ @file.write "\t"
410
+ seek = @file.pos
411
+ @file.write "0000000000000000\t00000000\n"
412
+ @last_pos = @file.pos
418
413
 
419
- def self.parse(file)
420
- map = {}
421
- file.pos = 0
422
- file.each_line {|line|
423
- m = /^([^\t]+)\t([0-9a-fA-F]+)\t([0-9a-fA-F]+)/.match(line)
424
- next unless m
425
- path = m[1]
426
- pos = m[2].to_i(16)
427
- ino = m[3].to_i(16)
428
- seek = file.pos - line.bytesize + path.bytesize + 1
429
- map[path] = FilePositionEntry.new(file, seek)
430
- }
431
- new(file, map, file.pos)
432
- end
433
- end
414
+ @map[path] = FilePositionEntry.new(@file, seek)
415
+ end
434
416
 
435
- # pos inode
436
- # ffffffffffffffff\tffffffff\n
437
- class FilePositionEntry
438
- POS_SIZE = 16
439
- INO_OFFSET = 17
440
- INO_SIZE = 8
441
- LN_OFFSET = 25
442
- SIZE = 26
443
-
444
- def initialize(file, seek)
445
- @file = file
446
- @seek = seek
417
+ def self.parse(file)
418
+ map = {}
419
+ file.pos = 0
420
+ file.each_line {|line|
421
+ m = /^([^\t]+)\t([0-9a-fA-F]+)\t([0-9a-fA-F]+)/.match(line)
422
+ next unless m
423
+ path = m[1]
424
+ pos = m[2].to_i(16)
425
+ ino = m[3].to_i(16)
426
+ seek = file.pos - line.bytesize + path.bytesize + 1
427
+ map[path] = FilePositionEntry.new(file, seek)
428
+ }
429
+ new(file, map, file.pos)
430
+ end
447
431
  end
448
432
 
449
- def update(ino, pos)
450
- @file.pos = @seek
451
- @file.write "%016x\t%08x" % [pos, ino]
452
- @inode = ino
453
- end
433
+ # pos inode
434
+ # ffffffffffffffff\tffffffff\n
435
+ class FilePositionEntry
436
+ POS_SIZE = 16
437
+ INO_OFFSET = 17
438
+ INO_SIZE = 8
439
+ LN_OFFSET = 25
440
+ SIZE = 26
441
+
442
+ def initialize(file, seek)
443
+ @file = file
444
+ @seek = seek
445
+ end
454
446
 
455
- def update_pos(pos)
456
- @file.pos = @seek
457
- @file.write "%016x" % pos
458
- end
447
+ def update(ino, pos)
448
+ @file.pos = @seek
449
+ @file.write "%016x\t%08x" % [pos, ino]
450
+ @inode = ino
451
+ end
459
452
 
460
- def read_inode
461
- @file.pos = @seek + INO_OFFSET
462
- raw = @file.read(8)
463
- raw ? raw.to_i(16) : 0
464
- end
453
+ def update_pos(pos)
454
+ @file.pos = @seek
455
+ @file.write "%016x" % pos
456
+ end
465
457
 
466
- def read_pos
467
- @file.pos = @seek
468
- raw = @file.read(16)
469
- raw ? raw.to_i(16) : 0
470
- end
471
- end
458
+ def read_inode
459
+ @file.pos = @seek + INO_OFFSET
460
+ raw = @file.read(8)
461
+ raw ? raw.to_i(16) : 0
462
+ end
472
463
 
473
- class MemoryPositionEntry
474
- def initialize
475
- @pos = 0
476
- @inode = 0
464
+ def read_pos
465
+ @file.pos = @seek
466
+ raw = @file.read(16)
467
+ raw ? raw.to_i(16) : 0
468
+ end
477
469
  end
478
470
 
479
- def update(ino, pos)
480
- @inode = ino
481
- @pos = pos
482
- end
471
+ class MemoryPositionEntry
472
+ def initialize
473
+ @pos = 0
474
+ @inode = 0
475
+ end
483
476
 
484
- def update_pos(pos)
485
- @pos = pos
486
- end
477
+ def update(ino, pos)
478
+ @inode = ino
479
+ @pos = pos
480
+ end
487
481
 
488
- def read_pos
489
- @pos
490
- end
482
+ def update_pos(pos)
483
+ @pos = pos
484
+ end
491
485
 
492
- def read_inode
493
- @inode
486
+ def read_pos
487
+ @pos
488
+ end
489
+
490
+ def read_inode
491
+ @inode
492
+ end
494
493
  end
495
494
  end
496
495
  end
497
-
498
-
499
- end
500
-