fluentd 0.12.40 → 0.14.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.
- checksums.yaml +4 -4
- data/.github/ISSUE_TEMPLATE.md +6 -0
- data/.gitignore +2 -0
- data/.travis.yml +33 -21
- data/CONTRIBUTING.md +1 -0
- data/ChangeLog +810 -237
- data/README.md +0 -25
- data/Rakefile +2 -1
- data/Vagrantfile +17 -0
- data/appveyor.yml +35 -0
- data/example/filter_stdout.conf +5 -5
- data/example/in_forward.conf +2 -2
- data/example/in_http.conf +2 -2
- data/example/in_out_forward.conf +17 -0
- data/example/in_syslog.conf +2 -2
- data/example/in_tail.conf +2 -2
- data/example/in_tcp.conf +2 -2
- data/example/in_udp.conf +2 -2
- data/example/out_copy.conf +4 -4
- data/example/out_file.conf +2 -2
- data/example/out_forward.conf +2 -2
- data/example/out_forward_buf_file.conf +23 -0
- data/example/v0_12_filter.conf +8 -8
- data/fluent.conf +29 -0
- data/fluentd.gemspec +18 -11
- data/lib/fluent/agent.rb +60 -58
- data/lib/fluent/command/cat.rb +1 -1
- data/lib/fluent/command/debug.rb +7 -5
- data/lib/fluent/command/fluentd.rb +97 -2
- data/lib/fluent/compat/call_super_mixin.rb +67 -0
- data/lib/fluent/compat/filter.rb +50 -0
- data/lib/fluent/compat/formatter.rb +109 -0
- data/lib/fluent/compat/input.rb +50 -0
- data/lib/fluent/compat/output.rb +617 -0
- data/lib/fluent/compat/output_chain.rb +60 -0
- data/lib/fluent/compat/parser.rb +163 -0
- data/lib/fluent/compat/propagate_default.rb +62 -0
- data/lib/fluent/config.rb +23 -20
- data/lib/fluent/config/configure_proxy.rb +119 -70
- data/lib/fluent/config/dsl.rb +5 -18
- data/lib/fluent/config/element.rb +72 -8
- data/lib/fluent/config/error.rb +0 -3
- data/lib/fluent/config/literal_parser.rb +0 -2
- data/lib/fluent/config/parser.rb +4 -4
- data/lib/fluent/config/section.rb +39 -28
- data/lib/fluent/config/types.rb +2 -13
- data/lib/fluent/config/v1_parser.rb +1 -3
- data/lib/fluent/configurable.rb +48 -16
- data/lib/fluent/daemon.rb +15 -0
- data/lib/fluent/engine.rb +26 -52
- data/lib/fluent/env.rb +6 -4
- data/lib/fluent/event.rb +58 -11
- data/lib/fluent/event_router.rb +5 -5
- data/lib/fluent/filter.rb +2 -50
- data/lib/fluent/formatter.rb +4 -293
- data/lib/fluent/input.rb +2 -32
- data/lib/fluent/label.rb +2 -2
- data/lib/fluent/load.rb +3 -2
- data/lib/fluent/log.rb +107 -38
- data/lib/fluent/match.rb +0 -36
- data/lib/fluent/mixin.rb +117 -7
- data/lib/fluent/msgpack_factory.rb +62 -0
- data/lib/fluent/output.rb +7 -612
- data/lib/fluent/output_chain.rb +23 -0
- data/lib/fluent/parser.rb +4 -800
- data/lib/fluent/plugin.rb +100 -121
- data/lib/fluent/plugin/bare_output.rb +63 -0
- data/lib/fluent/plugin/base.rb +121 -0
- data/lib/fluent/plugin/buf_file.rb +101 -182
- data/lib/fluent/plugin/buf_memory.rb +9 -92
- data/lib/fluent/plugin/buffer.rb +473 -0
- data/lib/fluent/plugin/buffer/chunk.rb +135 -0
- data/lib/fluent/plugin/buffer/file_chunk.rb +339 -0
- data/lib/fluent/plugin/buffer/memory_chunk.rb +100 -0
- data/lib/fluent/plugin/exec_util.rb +80 -75
- data/lib/fluent/plugin/file_util.rb +33 -28
- data/lib/fluent/plugin/file_wrapper.rb +120 -0
- data/lib/fluent/plugin/filter.rb +51 -0
- data/lib/fluent/plugin/filter_grep.rb +13 -40
- data/lib/fluent/plugin/filter_record_transformer.rb +22 -18
- data/lib/fluent/plugin/formatter.rb +93 -0
- data/lib/fluent/plugin/formatter_csv.rb +48 -0
- data/lib/fluent/plugin/formatter_hash.rb +32 -0
- data/lib/fluent/plugin/formatter_json.rb +47 -0
- data/lib/fluent/plugin/formatter_ltsv.rb +42 -0
- data/lib/fluent/plugin/formatter_msgpack.rb +32 -0
- data/lib/fluent/plugin/formatter_out_file.rb +45 -0
- data/lib/fluent/plugin/formatter_single_value.rb +34 -0
- data/lib/fluent/plugin/formatter_stdout.rb +39 -0
- data/lib/fluent/plugin/in_debug_agent.rb +4 -0
- data/lib/fluent/plugin/in_dummy.rb +22 -18
- data/lib/fluent/plugin/in_exec.rb +18 -8
- data/lib/fluent/plugin/in_forward.rb +36 -79
- data/lib/fluent/plugin/in_gc_stat.rb +4 -0
- data/lib/fluent/plugin/in_http.rb +21 -18
- data/lib/fluent/plugin/in_monitor_agent.rb +15 -48
- data/lib/fluent/plugin/in_object_space.rb +6 -1
- data/lib/fluent/plugin/in_stream.rb +7 -3
- data/lib/fluent/plugin/in_syslog.rb +46 -95
- data/lib/fluent/plugin/in_tail.rb +51 -595
- data/lib/fluent/plugin/in_tcp.rb +8 -1
- data/lib/fluent/plugin/in_udp.rb +8 -14
- data/lib/fluent/plugin/input.rb +33 -0
- data/lib/fluent/plugin/multi_output.rb +95 -0
- data/lib/fluent/plugin/out_buffered_null.rb +59 -0
- data/lib/fluent/plugin/out_copy.rb +11 -7
- data/lib/fluent/plugin/out_exec.rb +15 -11
- data/lib/fluent/plugin/out_exec_filter.rb +18 -10
- data/lib/fluent/plugin/out_file.rb +34 -5
- data/lib/fluent/plugin/out_forward.rb +19 -9
- data/lib/fluent/plugin/out_null.rb +0 -14
- data/lib/fluent/plugin/out_roundrobin.rb +11 -7
- data/lib/fluent/plugin/out_stdout.rb +5 -7
- data/lib/fluent/plugin/out_stream.rb +3 -1
- data/lib/fluent/plugin/output.rb +979 -0
- data/lib/fluent/plugin/owned_by_mixin.rb +42 -0
- data/lib/fluent/plugin/parser.rb +244 -0
- data/lib/fluent/plugin/parser_apache.rb +24 -0
- data/lib/fluent/plugin/parser_apache2.rb +84 -0
- data/lib/fluent/plugin/parser_apache_error.rb +21 -0
- data/lib/fluent/plugin/parser_csv.rb +31 -0
- data/lib/fluent/plugin/parser_json.rb +79 -0
- data/lib/fluent/plugin/parser_ltsv.rb +50 -0
- data/lib/fluent/plugin/parser_multiline.rb +102 -0
- data/lib/fluent/plugin/parser_nginx.rb +24 -0
- data/lib/fluent/plugin/parser_none.rb +36 -0
- data/lib/fluent/plugin/parser_syslog.rb +82 -0
- data/lib/fluent/plugin/parser_tsv.rb +37 -0
- data/lib/fluent/plugin/socket_util.rb +120 -114
- data/lib/fluent/plugin/storage.rb +84 -0
- data/lib/fluent/plugin/storage_local.rb +116 -0
- data/lib/fluent/plugin/string_util.rb +16 -13
- data/lib/fluent/plugin_helper.rb +39 -0
- data/lib/fluent/plugin_helper/child_process.rb +298 -0
- data/lib/fluent/plugin_helper/compat_parameters.rb +99 -0
- data/lib/fluent/plugin_helper/event_emitter.rb +80 -0
- data/lib/fluent/plugin_helper/event_loop.rb +118 -0
- data/lib/fluent/plugin_helper/retry_state.rb +177 -0
- data/lib/fluent/plugin_helper/storage.rb +308 -0
- data/lib/fluent/plugin_helper/thread.rb +147 -0
- data/lib/fluent/plugin_helper/timer.rb +85 -0
- data/lib/fluent/plugin_id.rb +63 -0
- data/lib/fluent/process.rb +21 -30
- data/lib/fluent/registry.rb +21 -9
- data/lib/fluent/root_agent.rb +115 -40
- data/lib/fluent/supervisor.rb +330 -320
- data/lib/fluent/system_config.rb +42 -18
- data/lib/fluent/test.rb +6 -1
- data/lib/fluent/test/base.rb +23 -3
- data/lib/fluent/test/driver/base.rb +247 -0
- data/lib/fluent/test/driver/event_feeder.rb +98 -0
- data/lib/fluent/test/driver/filter.rb +35 -0
- data/lib/fluent/test/driver/input.rb +31 -0
- data/lib/fluent/test/driver/output.rb +78 -0
- data/lib/fluent/test/driver/test_event_router.rb +45 -0
- data/lib/fluent/test/filter_test.rb +0 -1
- data/lib/fluent/test/formatter_test.rb +2 -1
- data/lib/fluent/test/input_test.rb +23 -17
- data/lib/fluent/test/output_test.rb +28 -39
- data/lib/fluent/test/parser_test.rb +1 -1
- data/lib/fluent/time.rb +104 -1
- data/lib/fluent/{status.rb → unique_id.rb} +15 -24
- data/lib/fluent/version.rb +1 -1
- data/lib/fluent/winsvc.rb +72 -0
- data/test/compat/test_calls_super.rb +164 -0
- data/test/config/test_config_parser.rb +83 -0
- data/test/config/test_configurable.rb +547 -274
- data/test/config/test_configure_proxy.rb +146 -29
- data/test/config/test_dsl.rb +3 -181
- data/test/config/test_element.rb +274 -0
- data/test/config/test_literal_parser.rb +1 -1
- data/test/config/test_section.rb +79 -7
- data/test/config/test_system_config.rb +21 -0
- data/test/config/test_types.rb +3 -26
- data/test/helper.rb +78 -8
- data/test/plugin/test_bare_output.rb +118 -0
- data/test/plugin/test_base.rb +75 -0
- data/test/plugin/test_buf_file.rb +420 -521
- data/test/plugin/test_buf_memory.rb +32 -194
- data/test/plugin/test_buffer.rb +981 -0
- data/test/plugin/test_buffer_chunk.rb +110 -0
- data/test/plugin/test_buffer_file_chunk.rb +770 -0
- data/test/plugin/test_buffer_memory_chunk.rb +265 -0
- data/test/plugin/test_filter.rb +255 -0
- data/test/plugin/test_filter_grep.rb +2 -73
- data/test/plugin/test_filter_record_transformer.rb +24 -68
- data/test/plugin/test_filter_stdout.rb +6 -6
- data/test/plugin/test_in_debug_agent.rb +2 -0
- data/test/plugin/test_in_dummy.rb +11 -17
- data/test/plugin/test_in_exec.rb +6 -25
- data/test/plugin/test_in_forward.rb +112 -151
- data/test/plugin/test_in_gc_stat.rb +2 -0
- data/test/plugin/test_in_http.rb +106 -157
- data/test/plugin/test_in_object_space.rb +21 -5
- data/test/plugin/test_in_stream.rb +14 -13
- data/test/plugin/test_in_syslog.rb +30 -275
- data/test/plugin/test_in_tail.rb +95 -234
- data/test/plugin/test_in_tcp.rb +14 -0
- data/test/plugin/test_in_udp.rb +21 -13
- data/test/plugin/test_input.rb +122 -0
- data/test/plugin/test_multi_output.rb +180 -0
- data/test/plugin/test_out_buffered_null.rb +79 -0
- data/test/plugin/test_out_copy.rb +15 -2
- data/test/plugin/test_out_exec.rb +75 -25
- data/test/plugin/test_out_exec_filter.rb +74 -8
- data/test/plugin/test_out_file.rb +61 -7
- data/test/plugin/test_out_forward.rb +92 -15
- data/test/plugin/test_out_roundrobin.rb +1 -0
- data/test/plugin/test_out_stdout.rb +22 -13
- data/test/plugin/test_out_stream.rb +18 -0
- data/test/plugin/test_output.rb +515 -0
- data/test/plugin/test_output_as_buffered.rb +1540 -0
- data/test/plugin/test_output_as_buffered_overflow.rb +247 -0
- data/test/plugin/test_output_as_buffered_retries.rb +808 -0
- data/test/plugin/test_output_as_buffered_secondary.rb +776 -0
- data/test/plugin/test_output_as_standard.rb +362 -0
- data/test/plugin/test_owned_by.rb +35 -0
- data/test/plugin/test_storage.rb +167 -0
- data/test/plugin/test_storage_local.rb +8 -0
- data/test/plugin_helper/test_child_process.rb +599 -0
- data/test/plugin_helper/test_compat_parameters.rb +175 -0
- data/test/plugin_helper/test_event_emitter.rb +51 -0
- data/test/plugin_helper/test_event_loop.rb +52 -0
- data/test/plugin_helper/test_retry_state.rb +399 -0
- data/test/plugin_helper/test_storage.rb +411 -0
- data/test/plugin_helper/test_thread.rb +164 -0
- data/test/plugin_helper/test_timer.rb +100 -0
- data/test/scripts/exec_script.rb +0 -6
- data/test/scripts/fluent/plugin/out_test.rb +3 -0
- data/test/test_config.rb +13 -4
- data/test/test_event.rb +24 -13
- data/test/test_event_router.rb +8 -7
- data/test/test_event_time.rb +187 -0
- data/test/test_formatter.rb +13 -51
- data/test/test_input.rb +1 -1
- data/test/test_log.rb +239 -16
- data/test/test_mixin.rb +1 -1
- data/test/test_output.rb +53 -66
- data/test/test_parser.rb +105 -323
- data/test/test_plugin_helper.rb +81 -0
- data/test/test_root_agent.rb +4 -52
- data/test/test_supervisor.rb +272 -0
- data/test/test_unique_id.rb +47 -0
- metadata +180 -54
- data/lib/fluent/buffer.rb +0 -365
- data/lib/fluent/plugin/filter_parser.rb +0 -107
- data/lib/fluent/plugin/in_status.rb +0 -76
- data/lib/fluent/test/helpers.rb +0 -86
- data/test/plugin/data/log/foo/bar2 +0 -0
- data/test/plugin/test_filter_parser.rb +0 -744
- data/test/plugin/test_in_status.rb +0 -38
- data/test/test_buffer.rb +0 -624
|
@@ -19,16 +19,29 @@ require 'cool.io'
|
|
|
19
19
|
require 'fluent/input'
|
|
20
20
|
require 'fluent/config/error'
|
|
21
21
|
require 'fluent/event'
|
|
22
|
+
require 'fluent/system_config'
|
|
23
|
+
require 'fluent/plugin/buffer'
|
|
24
|
+
|
|
25
|
+
if Fluent.windows?
|
|
26
|
+
require_relative 'file_wrapper'
|
|
27
|
+
else
|
|
28
|
+
Fluent::FileWrapper = File
|
|
29
|
+
end
|
|
22
30
|
|
|
23
31
|
module Fluent
|
|
24
|
-
class
|
|
32
|
+
class TailInput < Input
|
|
33
|
+
include SystemConfig::Mixin
|
|
34
|
+
|
|
25
35
|
Plugin.register_input('tail', self)
|
|
26
36
|
|
|
37
|
+
FILE_PERMISSION = 0644
|
|
38
|
+
|
|
27
39
|
def initialize
|
|
28
40
|
super
|
|
29
41
|
@paths = []
|
|
30
42
|
@tails = {}
|
|
31
|
-
@
|
|
43
|
+
@pf_file = nil
|
|
44
|
+
@pf = nil
|
|
32
45
|
end
|
|
33
46
|
|
|
34
47
|
desc 'The paths to read. Multiple paths can be specified, separated by comma.'
|
|
@@ -49,22 +62,18 @@ module Fluent
|
|
|
49
62
|
config_param :read_lines_limit, :integer, default: 1000
|
|
50
63
|
desc 'The interval of flushing the buffer for multiline format'
|
|
51
64
|
config_param :multiline_flush_interval, :time, default: nil
|
|
52
|
-
desc 'Enable the option to emit unmatched lines.'
|
|
53
|
-
config_param :emit_unmatched_lines, :bool, default: false
|
|
54
65
|
desc 'Enable the additional watch timer.'
|
|
55
66
|
config_param :enable_watch_timer, :bool, default: true
|
|
56
|
-
desc 'The encoding after conversion of the input.'
|
|
57
|
-
config_param :encoding, :string, default: nil
|
|
58
67
|
desc 'The encoding of the input.'
|
|
59
|
-
config_param :
|
|
68
|
+
config_param :encoding, default: nil do |encoding_name|
|
|
69
|
+
begin
|
|
70
|
+
Encoding.find(encoding_name)
|
|
71
|
+
rescue ArgumentError => e
|
|
72
|
+
raise ConfigError, e.message
|
|
73
|
+
end
|
|
74
|
+
end
|
|
60
75
|
desc 'Add the log path being tailed to records. Specify the field name to be used.'
|
|
61
76
|
config_param :path_key, :string, default: nil
|
|
62
|
-
desc 'Limit the watching files that the modification time is within the specified time range (when use \'*\' in path).'
|
|
63
|
-
config_param :limit_recently_modified, :time, default: nil
|
|
64
|
-
desc 'Enable the option to skip the refresh of watching list on startup.'
|
|
65
|
-
config_param :skip_refresh_on_startup, :bool, default: false
|
|
66
|
-
desc 'Ignore repeated permission error logs'
|
|
67
|
-
config_param :ignore_repeated_permission_error, :bool, default: false
|
|
68
77
|
|
|
69
78
|
attr_reader :paths
|
|
70
79
|
|
|
@@ -83,7 +92,6 @@ module Fluent
|
|
|
83
92
|
|
|
84
93
|
configure_parser(conf)
|
|
85
94
|
configure_tag
|
|
86
|
-
configure_encoding
|
|
87
95
|
|
|
88
96
|
@multiline_mode = conf['format'] =~ /multiline/
|
|
89
97
|
@receive_handler = if @multiline_mode
|
|
@@ -91,6 +99,7 @@ module Fluent
|
|
|
91
99
|
else
|
|
92
100
|
method(:parse_singleline)
|
|
93
101
|
end
|
|
102
|
+
@file_perm = system_config.file_permission || FILE_PERMISSION
|
|
94
103
|
end
|
|
95
104
|
|
|
96
105
|
def configure_parser(conf)
|
|
@@ -101,7 +110,6 @@ module Fluent
|
|
|
101
110
|
def configure_tag
|
|
102
111
|
if @tag.index('*')
|
|
103
112
|
@tag_prefix, @tag_suffix = @tag.split('*')
|
|
104
|
-
@tag_prefix ||= ''
|
|
105
113
|
@tag_suffix ||= ''
|
|
106
114
|
else
|
|
107
115
|
@tag_prefix = nil
|
|
@@ -109,34 +117,17 @@ module Fluent
|
|
|
109
117
|
end
|
|
110
118
|
end
|
|
111
119
|
|
|
112
|
-
def configure_encoding
|
|
113
|
-
unless @encoding
|
|
114
|
-
if @from_encoding
|
|
115
|
-
raise ConfigError, "tail: 'from_encoding' parameter must be specified with 'encoding' parameter."
|
|
116
|
-
end
|
|
117
|
-
end
|
|
118
|
-
|
|
119
|
-
@encoding = parse_encoding_param(@encoding) if @encoding
|
|
120
|
-
@from_encoding = parse_encoding_param(@from_encoding) if @from_encoding
|
|
121
|
-
end
|
|
122
|
-
|
|
123
|
-
def parse_encoding_param(encoding_name)
|
|
124
|
-
begin
|
|
125
|
-
Encoding.find(encoding_name) if encoding_name
|
|
126
|
-
rescue ArgumentError => e
|
|
127
|
-
raise ConfigError, e.message
|
|
128
|
-
end
|
|
129
|
-
end
|
|
130
|
-
|
|
131
120
|
def start
|
|
121
|
+
super
|
|
122
|
+
|
|
132
123
|
if @pos_file
|
|
133
|
-
@pf_file = File.open(@pos_file, File::RDWR|File::CREAT,
|
|
124
|
+
@pf_file = File.open(@pos_file, File::RDWR|File::CREAT|File::BINARY, @file_perm)
|
|
134
125
|
@pf_file.sync = true
|
|
135
126
|
@pf = PositionFile.parse(@pf_file)
|
|
136
127
|
end
|
|
137
128
|
|
|
138
129
|
@loop = Coolio::Loop.new
|
|
139
|
-
refresh_watchers
|
|
130
|
+
refresh_watchers
|
|
140
131
|
|
|
141
132
|
@refresh_trigger = TailWatcher::TimerWatcher.new(@refresh_interval, true, log, &method(:refresh_watchers))
|
|
142
133
|
@refresh_trigger.attach(@loop)
|
|
@@ -150,30 +141,23 @@ module Fluent
|
|
|
150
141
|
@loop.stop rescue nil # when all watchers are detached, `stop` raises RuntimeError. We can ignore this exception.
|
|
151
142
|
@thread.join
|
|
152
143
|
@pf_file.close if @pf_file
|
|
144
|
+
|
|
145
|
+
super
|
|
153
146
|
end
|
|
154
147
|
|
|
155
148
|
def expand_paths
|
|
156
149
|
date = Time.now
|
|
157
150
|
paths = []
|
|
158
151
|
|
|
152
|
+
excluded = @exclude_path.map { |path| path = date.strftime(path); path.include?('*') ? Dir.glob(path) : path }.flatten.uniq
|
|
159
153
|
@paths.each { |path|
|
|
160
154
|
path = date.strftime(path)
|
|
161
155
|
if path.include?('*')
|
|
162
156
|
paths += Dir.glob(path).select { |p|
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
if @limit_recently_modified && File.mtime(p) < (date - @limit_recently_modified)
|
|
166
|
-
false
|
|
167
|
-
else
|
|
168
|
-
true
|
|
169
|
-
end
|
|
157
|
+
if File.readable?(p)
|
|
158
|
+
true
|
|
170
159
|
else
|
|
171
|
-
|
|
172
|
-
unless @ignore_list.include?(path)
|
|
173
|
-
log.warn "#{p} unreadable. It is excluded and would be examined next time."
|
|
174
|
-
@ignore_list << path if @ignore_repeated_permission_error
|
|
175
|
-
end
|
|
176
|
-
end
|
|
160
|
+
log.warn "#{p} unreadable. It is excluded and would be examined next time."
|
|
177
161
|
false
|
|
178
162
|
end
|
|
179
163
|
}
|
|
@@ -182,7 +166,6 @@ module Fluent
|
|
|
182
166
|
paths << path
|
|
183
167
|
end
|
|
184
168
|
}
|
|
185
|
-
excluded = @exclude_path.map { |path| path = date.strftime(path); path.include?('*') ? Dir.glob(path) : path }.flatten.uniq
|
|
186
169
|
paths - excluded
|
|
187
170
|
end
|
|
188
171
|
|
|
@@ -216,7 +199,7 @@ module Fluent
|
|
|
216
199
|
pe = @pf[path]
|
|
217
200
|
if @read_from_head && pe.read_inode.zero?
|
|
218
201
|
begin
|
|
219
|
-
pe.update(
|
|
202
|
+
pe.update(FileWrapper.stat(path).ino, 0)
|
|
220
203
|
rescue Errno::ENOENT
|
|
221
204
|
$log.warn "#{path} not found. Continuing without tailing it."
|
|
222
205
|
end
|
|
@@ -268,13 +251,7 @@ module Fluent
|
|
|
268
251
|
def flush_buffer(tw)
|
|
269
252
|
if lb = tw.line_buffer
|
|
270
253
|
lb.chomp!
|
|
271
|
-
if @encoding
|
|
272
|
-
if @from_encoding
|
|
273
|
-
lb.encode!(@encoding, @from_encoding)
|
|
274
|
-
else
|
|
275
|
-
lb.force_encoding(@encoding)
|
|
276
|
-
end
|
|
277
|
-
end
|
|
254
|
+
lb.force_encoding(@encoding) if @encoding
|
|
278
255
|
@parser.parse(lb) { |time, record|
|
|
279
256
|
if time && record
|
|
280
257
|
tag = if @tag_prefix || @tag_suffix
|
|
@@ -298,7 +275,7 @@ module Fluent
|
|
|
298
275
|
log.error_backtrace
|
|
299
276
|
end
|
|
300
277
|
|
|
301
|
-
# @return true if no error or unrecoverable error happens in emit action. false if got
|
|
278
|
+
# @return true if no error or unrecoverable error happens in emit action. false if got BufferOverflowError
|
|
302
279
|
def receive_lines(lines, tail_watcher)
|
|
303
280
|
es = @receive_handler.call(lines, tail_watcher)
|
|
304
281
|
unless es.empty?
|
|
@@ -309,7 +286,7 @@ module Fluent
|
|
|
309
286
|
end
|
|
310
287
|
begin
|
|
311
288
|
router.emit_stream(tag, es)
|
|
312
|
-
rescue
|
|
289
|
+
rescue Fluent::Plugin::Buffer::BufferOverflowError
|
|
313
290
|
return false
|
|
314
291
|
rescue
|
|
315
292
|
# ignore non BufferQueueLimitError errors because in_tail can't recover. Engine shows logs and backtraces.
|
|
@@ -323,23 +300,12 @@ module Fluent
|
|
|
323
300
|
def convert_line_to_event(line, es, tail_watcher)
|
|
324
301
|
begin
|
|
325
302
|
line.chomp! # remove \n
|
|
326
|
-
if @encoding
|
|
327
|
-
if @from_encoding
|
|
328
|
-
line.encode!(@encoding, @from_encoding)
|
|
329
|
-
else
|
|
330
|
-
line.force_encoding(@encoding)
|
|
331
|
-
end
|
|
332
|
-
end
|
|
303
|
+
line.force_encoding(@encoding) if @encoding
|
|
333
304
|
@parser.parse(line) { |time, record|
|
|
334
305
|
if time && record
|
|
335
306
|
record[@path_key] ||= tail_watcher.path unless @path_key.nil?
|
|
336
307
|
es.add(time, record)
|
|
337
308
|
else
|
|
338
|
-
if @emit_unmatched_lines
|
|
339
|
-
record = {'unmatched_line' => line}
|
|
340
|
-
record[@path_key] ||= tail_watcher.path unless @path_key.nil?
|
|
341
|
-
es.add(::Fluent::Engine.now, record)
|
|
342
|
-
end
|
|
343
309
|
log.warn "pattern not match: #{line.inspect}"
|
|
344
310
|
end
|
|
345
311
|
}
|
|
@@ -370,9 +336,6 @@ module Fluent
|
|
|
370
336
|
lb = line
|
|
371
337
|
else
|
|
372
338
|
if lb.nil?
|
|
373
|
-
if @emit_unmatched_lines
|
|
374
|
-
convert_line_to_event(line, es, tail_watcher)
|
|
375
|
-
end
|
|
376
339
|
log.warn "got incomplete line before first line from #{tail_watcher.path}: #{line.inspect}"
|
|
377
340
|
else
|
|
378
341
|
lb << line
|
|
@@ -509,26 +472,24 @@ module Fluent
|
|
|
509
472
|
io_handler = IOHandler.new(io, @pe, @log, @read_lines_limit, &method(:wrap_receive_lines))
|
|
510
473
|
@io_handler = io_handler
|
|
511
474
|
else # file is rotated and new file found
|
|
512
|
-
detach
|
|
513
475
|
@update_watcher.call(@path, swap_state(@pe))
|
|
514
476
|
end
|
|
515
477
|
else # file is rotated and new file not found
|
|
516
478
|
# Clear RotateHandler to avoid duplicated file watch in same path.
|
|
517
479
|
@rotate_handler = nil
|
|
518
|
-
detach
|
|
519
480
|
@update_watcher.call(@path, swap_state(@pe))
|
|
520
481
|
end
|
|
521
482
|
end
|
|
483
|
+
end
|
|
522
484
|
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
485
|
+
def swap_state(pe)
|
|
486
|
+
# Use MemoryPositionEntry for rotated file temporary
|
|
487
|
+
mpe = MemoryPositionEntry.new
|
|
488
|
+
mpe.update(pe.read_inode, pe.read_pos)
|
|
489
|
+
@pe = mpe
|
|
490
|
+
@io_handler.pe = mpe # Don't re-create IOHandler because IOHandler has an internal buffer.
|
|
529
491
|
|
|
530
|
-
|
|
531
|
-
end
|
|
492
|
+
pe # This pe will be updated in on_rotate after TailWatcher is initialized
|
|
532
493
|
end
|
|
533
494
|
|
|
534
495
|
class TimerWatcher < Coolio::TimerWatcher
|
|
@@ -609,8 +570,8 @@ module Fluent
|
|
|
609
570
|
else
|
|
610
571
|
@buffer << @io.readpartial(2048, @iobuf)
|
|
611
572
|
end
|
|
612
|
-
while
|
|
613
|
-
@lines <<
|
|
573
|
+
while line = @buffer.slice!(/.*?\n/m)
|
|
574
|
+
@lines << line
|
|
614
575
|
end
|
|
615
576
|
if @lines.size >= @read_lines_limit
|
|
616
577
|
# not to use too much memory in case the file is very large
|
|
@@ -668,7 +629,7 @@ module Fluent
|
|
|
668
629
|
|
|
669
630
|
def on_notify
|
|
670
631
|
begin
|
|
671
|
-
stat =
|
|
632
|
+
stat = FileWrapper.stat(@path)
|
|
672
633
|
inode = stat.ino
|
|
673
634
|
fsize = stat.size
|
|
674
635
|
rescue Errno::ENOENT
|
|
@@ -681,7 +642,7 @@ module Fluent
|
|
|
681
642
|
if @inode != inode || fsize < @fsize
|
|
682
643
|
# rotated or truncated
|
|
683
644
|
begin
|
|
684
|
-
io =
|
|
645
|
+
io = FileWrapper.open(@path)
|
|
685
646
|
rescue Errno::ENOENT
|
|
686
647
|
end
|
|
687
648
|
@on_rotate.call(io)
|
|
@@ -755,8 +716,6 @@ module Fluent
|
|
|
755
716
|
m = /^([^\t]+)\t([0-9a-fA-F]+)\t([0-9a-fA-F]+)/.match(line)
|
|
756
717
|
next unless m
|
|
757
718
|
path = m[1]
|
|
758
|
-
pos = m[2].to_i(16)
|
|
759
|
-
ino = m[3].to_i(16)
|
|
760
719
|
seek = file.pos - line.bytesize + path.bytesize + 1
|
|
761
720
|
map[path] = FilePositionEntry.new(file, seek)
|
|
762
721
|
}
|
|
@@ -844,508 +803,5 @@ module Fluent
|
|
|
844
803
|
end
|
|
845
804
|
end
|
|
846
805
|
|
|
847
|
-
|
|
848
|
-
# This class will be removed after release v1.
|
|
849
|
-
class TailInput < Input
|
|
850
|
-
def initialize
|
|
851
|
-
super
|
|
852
|
-
@paths = []
|
|
853
|
-
end
|
|
854
|
-
|
|
855
|
-
config_param :path, :string
|
|
856
|
-
config_param :tag, :string
|
|
857
|
-
config_param :rotate_wait, :time, :default => 5
|
|
858
|
-
config_param :pos_file, :string, :default => nil
|
|
859
|
-
|
|
860
|
-
attr_reader :paths
|
|
861
|
-
|
|
862
|
-
def configure(conf)
|
|
863
|
-
super
|
|
864
|
-
|
|
865
|
-
@paths = @path.split(',').map {|path| path.strip }
|
|
866
|
-
if @paths.empty?
|
|
867
|
-
raise ConfigError, "tail: 'path' parameter is required on tail input"
|
|
868
|
-
end
|
|
869
|
-
|
|
870
|
-
unless @pos_file
|
|
871
|
-
$log.warn "'pos_file PATH' parameter is not set to a 'tail' source."
|
|
872
|
-
$log.warn "this parameter is highly recommended to save the position to resume tailing."
|
|
873
|
-
end
|
|
874
|
-
|
|
875
|
-
configure_parser(conf)
|
|
876
|
-
end
|
|
877
|
-
|
|
878
|
-
def configure_parser(conf)
|
|
879
|
-
@parser = TextParser.new
|
|
880
|
-
@parser.configure(conf)
|
|
881
|
-
end
|
|
882
|
-
|
|
883
|
-
def start
|
|
884
|
-
if @pos_file
|
|
885
|
-
@pf_file = File.open(@pos_file, File::RDWR|File::CREAT, DEFAULT_FILE_PERMISSION)
|
|
886
|
-
@pf_file.sync = true
|
|
887
|
-
@pf = PositionFile.parse(@pf_file)
|
|
888
|
-
end
|
|
889
|
-
|
|
890
|
-
@loop = Coolio::Loop.new
|
|
891
|
-
@tails = @paths.map {|path|
|
|
892
|
-
pe = @pf ? @pf[path] : MemoryPositionEntry.new
|
|
893
|
-
tw = TailWatcher.new(path, @rotate_wait, pe, &method(:receive_lines))
|
|
894
|
-
tw.log = log
|
|
895
|
-
tw
|
|
896
|
-
}
|
|
897
|
-
@tails.each {|tail|
|
|
898
|
-
tail.attach(@loop)
|
|
899
|
-
}
|
|
900
|
-
@thread = Thread.new(&method(:run))
|
|
901
|
-
end
|
|
902
|
-
|
|
903
|
-
def shutdown
|
|
904
|
-
@tails.each {|tail|
|
|
905
|
-
tail.close
|
|
906
|
-
}
|
|
907
|
-
@loop.stop
|
|
908
|
-
@thread.join
|
|
909
|
-
@pf_file.close if @pf_file
|
|
910
|
-
end
|
|
911
|
-
|
|
912
|
-
def run
|
|
913
|
-
@loop.run
|
|
914
|
-
rescue
|
|
915
|
-
log.error "unexpected error", :error=>$!.to_s
|
|
916
|
-
log.error_backtrace
|
|
917
|
-
end
|
|
918
|
-
|
|
919
|
-
def receive_lines(lines)
|
|
920
|
-
es = MultiEventStream.new
|
|
921
|
-
lines.each {|line|
|
|
922
|
-
begin
|
|
923
|
-
line.chomp! # remove \n
|
|
924
|
-
time, record = parse_line(line)
|
|
925
|
-
if time && record
|
|
926
|
-
es.add(time, record)
|
|
927
|
-
else
|
|
928
|
-
log.warn "pattern not match: #{line.inspect}"
|
|
929
|
-
end
|
|
930
|
-
rescue
|
|
931
|
-
log.warn line.dump, :error=>$!.to_s
|
|
932
|
-
log.debug_backtrace
|
|
933
|
-
end
|
|
934
|
-
}
|
|
935
|
-
|
|
936
|
-
unless es.empty?
|
|
937
|
-
begin
|
|
938
|
-
router.emit_stream(@tag, es)
|
|
939
|
-
rescue
|
|
940
|
-
# ignore errors. Engine shows logs and backtraces.
|
|
941
|
-
end
|
|
942
|
-
end
|
|
943
|
-
end
|
|
944
|
-
|
|
945
|
-
def parse_line(line)
|
|
946
|
-
return @parser.parse(line)
|
|
947
|
-
end
|
|
948
|
-
|
|
949
|
-
class TailWatcher
|
|
950
|
-
def initialize(path, rotate_wait, pe, &receive_lines)
|
|
951
|
-
@path = path
|
|
952
|
-
@rotate_wait = rotate_wait
|
|
953
|
-
@pe = pe || MemoryPositionEntry.new
|
|
954
|
-
@receive_lines = receive_lines
|
|
955
|
-
|
|
956
|
-
@rotate_queue = []
|
|
957
|
-
|
|
958
|
-
@timer_trigger = TimerWatcher.new(1, true, &method(:on_notify))
|
|
959
|
-
@stat_trigger = StatWatcher.new(path, &method(:on_notify))
|
|
960
|
-
|
|
961
|
-
@rotate_handler = RotateHandler.new(path, &method(:on_rotate))
|
|
962
|
-
@io_handler = nil
|
|
963
|
-
@log = $log
|
|
964
|
-
end
|
|
965
|
-
|
|
966
|
-
# We use accessor approach to assign each logger, not passing log object at initialization,
|
|
967
|
-
# because several plugins depend on these internal classes.
|
|
968
|
-
# This approach avoids breaking plugins with new log_level option.
|
|
969
|
-
attr_accessor :log
|
|
970
|
-
|
|
971
|
-
def log=(logger)
|
|
972
|
-
@log = logger
|
|
973
|
-
@timer_trigger.log = logger
|
|
974
|
-
@stat_trigger.log = logger
|
|
975
|
-
@rotate_handler.log = logger
|
|
976
|
-
end
|
|
977
|
-
|
|
978
|
-
def attach(loop)
|
|
979
|
-
@timer_trigger.attach(loop)
|
|
980
|
-
@stat_trigger.attach(loop)
|
|
981
|
-
on_notify
|
|
982
|
-
end
|
|
983
|
-
|
|
984
|
-
def detach
|
|
985
|
-
@timer_trigger.detach if @timer_trigger.attached?
|
|
986
|
-
@stat_trigger.detach if @stat_trigger.attached?
|
|
987
|
-
end
|
|
988
|
-
|
|
989
|
-
def close
|
|
990
|
-
@rotate_queue.reject! {|req|
|
|
991
|
-
req.io.close
|
|
992
|
-
true
|
|
993
|
-
}
|
|
994
|
-
detach
|
|
995
|
-
end
|
|
996
|
-
|
|
997
|
-
def on_notify
|
|
998
|
-
@rotate_handler.on_notify
|
|
999
|
-
return unless @io_handler
|
|
1000
|
-
@io_handler.on_notify
|
|
1001
|
-
|
|
1002
|
-
# proceeds rotate queue
|
|
1003
|
-
return if @rotate_queue.empty?
|
|
1004
|
-
@rotate_queue.first.tick
|
|
1005
|
-
|
|
1006
|
-
while @rotate_queue.first.ready?
|
|
1007
|
-
if io = @rotate_queue.first.io
|
|
1008
|
-
stat = io.stat
|
|
1009
|
-
inode = stat.ino
|
|
1010
|
-
if inode == @pe.read_inode
|
|
1011
|
-
# rotated file has the same inode number with the last file.
|
|
1012
|
-
# assuming following situation:
|
|
1013
|
-
# a) file was once renamed and backed, or
|
|
1014
|
-
# b) symlink or hardlink to the same file is recreated
|
|
1015
|
-
# in either case, seek to the saved position
|
|
1016
|
-
pos = @pe.read_pos
|
|
1017
|
-
else
|
|
1018
|
-
pos = io.pos
|
|
1019
|
-
end
|
|
1020
|
-
@pe.update(inode, pos)
|
|
1021
|
-
io_handler = IOHandler.new(io, @pe, log, &@receive_lines)
|
|
1022
|
-
else
|
|
1023
|
-
io_handler = NullIOHandler.new
|
|
1024
|
-
end
|
|
1025
|
-
@io_handler.close
|
|
1026
|
-
@io_handler = io_handler
|
|
1027
|
-
@rotate_queue.shift
|
|
1028
|
-
break if @rotate_queue.empty?
|
|
1029
|
-
end
|
|
1030
|
-
end
|
|
1031
|
-
|
|
1032
|
-
def on_rotate(io)
|
|
1033
|
-
if @io_handler == nil
|
|
1034
|
-
if io
|
|
1035
|
-
# first time
|
|
1036
|
-
stat = io.stat
|
|
1037
|
-
fsize = stat.size
|
|
1038
|
-
inode = stat.ino
|
|
1039
|
-
|
|
1040
|
-
last_inode = @pe.read_inode
|
|
1041
|
-
if inode == last_inode
|
|
1042
|
-
# seek to the saved position
|
|
1043
|
-
pos = @pe.read_pos
|
|
1044
|
-
elsif last_inode != 0
|
|
1045
|
-
# this is FilePositionEntry and fluentd once started.
|
|
1046
|
-
# read data from the head of the rotated file.
|
|
1047
|
-
# logs never duplicate because this file is a rotated new file.
|
|
1048
|
-
pos = 0
|
|
1049
|
-
@pe.update(inode, pos)
|
|
1050
|
-
else
|
|
1051
|
-
# this is MemoryPositionEntry or this is the first time fluentd started.
|
|
1052
|
-
# seek to the end of the any files.
|
|
1053
|
-
# logs may duplicate without this seek because it's not sure the file is
|
|
1054
|
-
# existent file or rotated new file.
|
|
1055
|
-
pos = fsize
|
|
1056
|
-
@pe.update(inode, pos)
|
|
1057
|
-
end
|
|
1058
|
-
io.seek(pos)
|
|
1059
|
-
|
|
1060
|
-
@io_handler = IOHandler.new(io, @pe, log, &@receive_lines)
|
|
1061
|
-
else
|
|
1062
|
-
@io_handler = NullIOHandler.new
|
|
1063
|
-
end
|
|
1064
|
-
|
|
1065
|
-
else
|
|
1066
|
-
if io && @rotate_queue.find {|req| req.io == io }
|
|
1067
|
-
return
|
|
1068
|
-
end
|
|
1069
|
-
last_io = @rotate_queue.empty? ? @io_handler.io : @rotate_queue.last.io
|
|
1070
|
-
if last_io == nil
|
|
1071
|
-
log.info "detected rotation of #{@path}"
|
|
1072
|
-
# rotate imeediately if previous file is nil
|
|
1073
|
-
wait = 0
|
|
1074
|
-
else
|
|
1075
|
-
log.info "detected rotation of #{@path}; waiting #{@rotate_wait} seconds"
|
|
1076
|
-
wait = @rotate_wait
|
|
1077
|
-
wait -= @rotate_queue.first.wait unless @rotate_queue.empty?
|
|
1078
|
-
end
|
|
1079
|
-
@rotate_queue << RotationRequest.new(io, wait)
|
|
1080
|
-
end
|
|
1081
|
-
end
|
|
1082
|
-
|
|
1083
|
-
class TimerWatcher < Coolio::TimerWatcher
|
|
1084
|
-
def initialize(interval, repeat, &callback)
|
|
1085
|
-
@callback = callback
|
|
1086
|
-
@log = $log
|
|
1087
|
-
super(interval, repeat)
|
|
1088
|
-
end
|
|
1089
|
-
|
|
1090
|
-
attr_accessor :log
|
|
1091
|
-
|
|
1092
|
-
def on_timer
|
|
1093
|
-
@callback.call
|
|
1094
|
-
rescue
|
|
1095
|
-
# TODO log?
|
|
1096
|
-
@log.error $!.to_s
|
|
1097
|
-
@log.error_backtrace
|
|
1098
|
-
end
|
|
1099
|
-
end
|
|
1100
|
-
|
|
1101
|
-
class StatWatcher < Coolio::StatWatcher
|
|
1102
|
-
def initialize(path, &callback)
|
|
1103
|
-
@callback = callback
|
|
1104
|
-
@log = $log
|
|
1105
|
-
super(path)
|
|
1106
|
-
end
|
|
1107
|
-
|
|
1108
|
-
attr_accessor :log
|
|
1109
|
-
|
|
1110
|
-
def on_change(prev, cur)
|
|
1111
|
-
@callback.call
|
|
1112
|
-
rescue
|
|
1113
|
-
# TODO log?
|
|
1114
|
-
@log.error $!.to_s
|
|
1115
|
-
@log.error_backtrace
|
|
1116
|
-
end
|
|
1117
|
-
end
|
|
1118
|
-
|
|
1119
|
-
class RotationRequest
|
|
1120
|
-
def initialize(io, wait)
|
|
1121
|
-
@io = io
|
|
1122
|
-
@wait = wait
|
|
1123
|
-
end
|
|
1124
|
-
|
|
1125
|
-
attr_reader :io, :wait
|
|
1126
|
-
|
|
1127
|
-
def tick
|
|
1128
|
-
@wait -= 1
|
|
1129
|
-
end
|
|
1130
|
-
|
|
1131
|
-
def ready?
|
|
1132
|
-
@wait <= 0
|
|
1133
|
-
end
|
|
1134
|
-
end
|
|
1135
|
-
|
|
1136
|
-
MAX_LINES_AT_ONCE = 1000
|
|
1137
|
-
|
|
1138
|
-
class IOHandler
|
|
1139
|
-
def initialize(io, pe, log, &receive_lines)
|
|
1140
|
-
@log = log
|
|
1141
|
-
@log.info "following tail of #{io.path}"
|
|
1142
|
-
@io = io
|
|
1143
|
-
@pe = pe
|
|
1144
|
-
@receive_lines = receive_lines
|
|
1145
|
-
@buffer = ''.force_encoding('ASCII-8BIT')
|
|
1146
|
-
@iobuf = ''.force_encoding('ASCII-8BIT')
|
|
1147
|
-
end
|
|
1148
|
-
|
|
1149
|
-
attr_reader :io
|
|
1150
|
-
|
|
1151
|
-
def on_notify
|
|
1152
|
-
begin
|
|
1153
|
-
lines = []
|
|
1154
|
-
read_more = false
|
|
1155
|
-
|
|
1156
|
-
begin
|
|
1157
|
-
while true
|
|
1158
|
-
if @buffer.empty?
|
|
1159
|
-
@io.read_nonblock(2048, @buffer)
|
|
1160
|
-
else
|
|
1161
|
-
@buffer << @io.read_nonblock(2048, @iobuf)
|
|
1162
|
-
end
|
|
1163
|
-
while line = @buffer.slice!(/.*?\n/m)
|
|
1164
|
-
lines << line
|
|
1165
|
-
end
|
|
1166
|
-
if lines.size >= MAX_LINES_AT_ONCE
|
|
1167
|
-
# not to use too much memory in case the file is very large
|
|
1168
|
-
read_more = true
|
|
1169
|
-
break
|
|
1170
|
-
end
|
|
1171
|
-
end
|
|
1172
|
-
rescue EOFError
|
|
1173
|
-
end
|
|
1174
|
-
|
|
1175
|
-
unless lines.empty?
|
|
1176
|
-
@receive_lines.call(lines)
|
|
1177
|
-
@pe.update_pos(@io.pos - @buffer.bytesize)
|
|
1178
|
-
end
|
|
1179
|
-
|
|
1180
|
-
end while read_more
|
|
1181
|
-
|
|
1182
|
-
rescue
|
|
1183
|
-
@log.error $!.to_s
|
|
1184
|
-
@log.error_backtrace
|
|
1185
|
-
close
|
|
1186
|
-
end
|
|
1187
|
-
|
|
1188
|
-
def close
|
|
1189
|
-
@io.close unless @io.closed?
|
|
1190
|
-
end
|
|
1191
|
-
end
|
|
1192
|
-
|
|
1193
|
-
class NullIOHandler
|
|
1194
|
-
def initialize
|
|
1195
|
-
end
|
|
1196
|
-
|
|
1197
|
-
def io
|
|
1198
|
-
end
|
|
1199
|
-
|
|
1200
|
-
def on_notify
|
|
1201
|
-
end
|
|
1202
|
-
|
|
1203
|
-
def close
|
|
1204
|
-
end
|
|
1205
|
-
end
|
|
1206
|
-
|
|
1207
|
-
class RotateHandler
|
|
1208
|
-
def initialize(path, &on_rotate)
|
|
1209
|
-
@path = path
|
|
1210
|
-
@inode = nil
|
|
1211
|
-
@fsize = -1 # first
|
|
1212
|
-
@on_rotate = on_rotate
|
|
1213
|
-
@log = $log
|
|
1214
|
-
end
|
|
1215
|
-
|
|
1216
|
-
attr_accessor :log
|
|
1217
|
-
|
|
1218
|
-
def on_notify
|
|
1219
|
-
begin
|
|
1220
|
-
io = File.open(@path)
|
|
1221
|
-
stat = io.stat
|
|
1222
|
-
inode = stat.ino
|
|
1223
|
-
fsize = stat.size
|
|
1224
|
-
rescue Errno::ENOENT
|
|
1225
|
-
# moved or deleted
|
|
1226
|
-
inode = nil
|
|
1227
|
-
fsize = 0
|
|
1228
|
-
end
|
|
1229
|
-
|
|
1230
|
-
begin
|
|
1231
|
-
if @inode != inode || fsize < @fsize
|
|
1232
|
-
# rotated or truncated
|
|
1233
|
-
@on_rotate.call(io)
|
|
1234
|
-
io = nil
|
|
1235
|
-
end
|
|
1236
|
-
|
|
1237
|
-
@inode = inode
|
|
1238
|
-
@fsize = fsize
|
|
1239
|
-
ensure
|
|
1240
|
-
io.close if io
|
|
1241
|
-
end
|
|
1242
|
-
|
|
1243
|
-
rescue
|
|
1244
|
-
@log.error $!.to_s
|
|
1245
|
-
@log.error_backtrace
|
|
1246
|
-
end
|
|
1247
|
-
end
|
|
1248
|
-
end
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
class PositionFile
|
|
1252
|
-
def initialize(file, map, last_pos)
|
|
1253
|
-
@file = file
|
|
1254
|
-
@map = map
|
|
1255
|
-
@last_pos = last_pos
|
|
1256
|
-
end
|
|
1257
|
-
|
|
1258
|
-
def [](path)
|
|
1259
|
-
if m = @map[path]
|
|
1260
|
-
return m
|
|
1261
|
-
end
|
|
1262
|
-
|
|
1263
|
-
@file.pos = @last_pos
|
|
1264
|
-
@file.write path
|
|
1265
|
-
@file.write "\t"
|
|
1266
|
-
seek = @file.pos
|
|
1267
|
-
@file.write "0000000000000000\t00000000\n"
|
|
1268
|
-
@last_pos = @file.pos
|
|
1269
|
-
|
|
1270
|
-
@map[path] = FilePositionEntry.new(@file, seek)
|
|
1271
|
-
end
|
|
1272
|
-
|
|
1273
|
-
def self.parse(file)
|
|
1274
|
-
map = {}
|
|
1275
|
-
file.pos = 0
|
|
1276
|
-
file.each_line {|line|
|
|
1277
|
-
m = /^([^\t]+)\t([0-9a-fA-F]+)\t([0-9a-fA-F]+)/.match(line)
|
|
1278
|
-
next unless m
|
|
1279
|
-
path = m[1]
|
|
1280
|
-
pos = m[2].to_i(16)
|
|
1281
|
-
ino = m[3].to_i(16)
|
|
1282
|
-
seek = file.pos - line.bytesize + path.bytesize + 1
|
|
1283
|
-
map[path] = FilePositionEntry.new(file, seek)
|
|
1284
|
-
}
|
|
1285
|
-
new(file, map, file.pos)
|
|
1286
|
-
end
|
|
1287
|
-
end
|
|
1288
|
-
|
|
1289
|
-
# pos inode
|
|
1290
|
-
# ffffffffffffffff\tffffffff\n
|
|
1291
|
-
class FilePositionEntry
|
|
1292
|
-
POS_SIZE = 16
|
|
1293
|
-
INO_OFFSET = 17
|
|
1294
|
-
INO_SIZE = 8
|
|
1295
|
-
LN_OFFSET = 25
|
|
1296
|
-
SIZE = 26
|
|
1297
|
-
|
|
1298
|
-
def initialize(file, seek)
|
|
1299
|
-
@file = file
|
|
1300
|
-
@seek = seek
|
|
1301
|
-
end
|
|
1302
|
-
|
|
1303
|
-
def update(ino, pos)
|
|
1304
|
-
@file.pos = @seek
|
|
1305
|
-
@file.write "%016x\t%08x" % [pos, ino]
|
|
1306
|
-
@inode = ino
|
|
1307
|
-
end
|
|
1308
|
-
|
|
1309
|
-
def update_pos(pos)
|
|
1310
|
-
@file.pos = @seek
|
|
1311
|
-
@file.write "%016x" % pos
|
|
1312
|
-
end
|
|
1313
|
-
|
|
1314
|
-
def read_inode
|
|
1315
|
-
@file.pos = @seek + INO_OFFSET
|
|
1316
|
-
raw = @file.read(8)
|
|
1317
|
-
raw ? raw.to_i(16) : 0
|
|
1318
|
-
end
|
|
1319
|
-
|
|
1320
|
-
def read_pos
|
|
1321
|
-
@file.pos = @seek
|
|
1322
|
-
raw = @file.read(16)
|
|
1323
|
-
raw ? raw.to_i(16) : 0
|
|
1324
|
-
end
|
|
1325
|
-
end
|
|
1326
|
-
|
|
1327
|
-
class MemoryPositionEntry
|
|
1328
|
-
def initialize
|
|
1329
|
-
@pos = 0
|
|
1330
|
-
@inode = 0
|
|
1331
|
-
end
|
|
1332
|
-
|
|
1333
|
-
def update(ino, pos)
|
|
1334
|
-
@inode = ino
|
|
1335
|
-
@pos = pos
|
|
1336
|
-
end
|
|
1337
|
-
|
|
1338
|
-
def update_pos(pos)
|
|
1339
|
-
@pos = pos
|
|
1340
|
-
end
|
|
1341
|
-
|
|
1342
|
-
def read_pos
|
|
1343
|
-
@pos
|
|
1344
|
-
end
|
|
1345
|
-
|
|
1346
|
-
def read_inode
|
|
1347
|
-
@inode
|
|
1348
|
-
end
|
|
1349
|
-
end
|
|
1350
|
-
end
|
|
806
|
+
NewTailInput = TailInput # for backward compatibility
|
|
1351
807
|
end
|