diff --git a/lib/fluent/command/unpacker.rb b/lib/fluent/command/unpacker.rb index d71f7db0fe..e1404803f7 100644 --- a/lib/fluent/command/unpacker.rb +++ b/lib/fluent/command/unpacker.rb @@ -64,31 +64,13 @@ def usage(msg = nil) module Command class Base - DEFAULT_OPTIONS = { - format: :out_file - } - def initialize(argv = ARGV) @argv = argv - @params = {} - if i = @argv.index('--') - @params = @argv[i+1..-1].reduce({}) do |acc, e| - k, v = e[1..-1].split('=') - acc.merge(k => v) - end - @argv = @argv[0...i] - end - @options = DEFAULT_OPTIONS.dup + @options = {} @opt_parser = OptionParser.new do |opt| - opt.banner = "Usage: fluent-unpacker #{self.class.to_s.split('::').last.downcase} [options] file [-- ]" - opt.separator 'Options:' - opt.on('-f TYPE', '--format', 'configure output format') do |v| - @options[:format] = v.to_sym - end - opt.on('-p DIR', '--plugins', 'add library path') do |v| @options[:plugins] = v end @@ -101,16 +83,56 @@ def call private - def unpacker(io) - MessagePack::Unpacker.new(io) - end - def usage(msg = nil) puts @opt_parser.to_s puts "Error: #{msg}" if msg exit 1 end + def parse_options! + ret = @opt_parser.parse(@argv) + + if @options[:plugins] && !Dir.exist?(@options[:plugins]) + usage "Directory #{@options[:plugins]} doesn't exist" + elsif @options[:plugins] + Fluent::Plugin.add_plugin_dir(@options[:plugins]) + end + + ret + end + end + + module Formattable + DEFAULT_OPTIONS = { + format: :out_file + } + + def initialize(argv = ARGV) + super + + @options.merge!(DEFAULT_OPTIONS) + @params = {} + if i = @argv.index('--') + @params = @argv[i+1..-1].reduce({}) do |acc, e| + k, v = e[1..-1].split('=') + acc.merge(k => v) + end + @argv = @argv[0...i] + end + + configure_option_parser + end + + private + + def configure_option_parser + @opt_parser.banner = "Usage: fluent-unpacker #{self.class.to_s.split('::').last.downcase} [options] file [-- ]" + + @opt_parser.on('-f TYPE', '--format', 'configure output format') do |v| + @options[:format] = v.to_sym + end + end + def lookup_formatter(format, params) conf = Fluent::Config::Element.new('ROOT', '', params, []) formatter = Fluent::Plugin.new_formatter(format) @@ -125,6 +147,8 @@ def lookup_formatter(format, params) end class Head < Base + include Formattable + DEFAULT_HEAD_OPTIONS = { count: 5 } @@ -132,7 +156,7 @@ class Head < Base def initialize(argv = ARGV) super @options.merge!(DEFAULT_HEAD_OPTIONS) - @path = configure_option_parser + @path = parse_options! end def call @@ -140,7 +164,7 @@ def call File.open(@path, 'r') do |io| i = 0 - unpacker(io).each do |(time, record)| + MessagePack::Unpacker.new(io).each do |(time, record)| break if i == @options[:count] i += 1 puts @formatter.format(@path, time, record) # tag is use for tag @@ -150,12 +174,12 @@ def call private - def configure_option_parser + def parse_options! @opt_parser.on('-n COUNT', 'Set the number of lines to display') do |v| @options[:count] = v.to_i end - path = @opt_parser.parse(@argv) + path = super case when path.empty? @@ -171,23 +195,25 @@ def configure_option_parser end class Cat < Base + include Formattable + def initialize(argv = ARGV) super - @path = configure_option_parser + @path = parse_options! end def call @formatter = lookup_formatter(@options[:format], @params) File.open(@path, 'r') do |io| - unpacker(io).each do |(time, record)| + MessagePack::Unpacker.new(io).each do |(time, record)| puts @formatter.format(@path, time, record) # @path is use for tag end end end - def configure_option_parser - path = @opt_parser.parse(@argv) + def parse_options! + path = super usage 'Path is required' if path.empty? usage "#{path.first} is not found" unless File.exist?(path.first) path.first @@ -195,26 +221,30 @@ def configure_option_parser end class Formats < Base + def initialize(argv = ARGV) + super + parse_options! + end + def call - pf = Fluent::Plugin::FORMATTER_REGISTRY.paths.last + prefix = Fluent::Plugin::FORMATTER_REGISTRY.dir_search_prefix || 'formatter_' - if prefix = Fluent::Plugin::FORMATTER_REGISTRY.dir_search_prefix - Dir.glob("#{pf}/#{prefix}*").each do |e| - require File.absolute_path(e) - end + new_path = Fluent::Plugin::FORMATTER_REGISTRY.paths.last + Dir.glob("#{new_path}/#{prefix}*").each do |e| + require File.absolute_path(e) + end - $LOAD_PATH.map do |lp| - Dir.glob("#{lp}/#{prefix}*").each do |e| - require e - end + $LOAD_PATH.map do |lp| + Dir.glob("#{lp}/#{prefix}*").each do |e| + require e end + end - specs = Gem::Specification.flat_map { |spec| spec.lib_files }.select do |e| - e.include?(prefix) - end - specs.each do |e| - require File.absolute_path(e) - end + specs = Gem::Specification.flat_map { |spec| spec.lib_files }.select do |e| + e.include?(prefix) + end + specs.each do |e| + require File.absolute_path(e) end puts Fluent::Plugin::FORMATTER_REGISTRY.map.keys diff --git a/test/command/test_unpacker.rb b/test/command/test_unpacker.rb index c1e6e205c3..3c6772cbf2 100644 --- a/test/command/test_unpacker.rb +++ b/test/command/test_unpacker.rb @@ -7,6 +7,12 @@ require 'fluent/event' class TestFluentUnpacker < ::Test::Unit::TestCase + module ::Command + class Dummy < Base + def call; end + end + end + def suppress_stdout out = StringIO.new $stdout = out @@ -15,12 +21,6 @@ def suppress_stdout $stdout = STDOUT end - module ::Command - class Dummy < Base - def call; end - end - end - sub_test_case 'call' do data( empty: [], @@ -99,7 +99,7 @@ class TestHead < TestBaseCommand end end - test 'should success if file is valid' do + test 'should succeed if a file is valid' do file_name = 'packed.log' argv = ["#{TMP_DIR}/#{file_name}"] create_message_packed_file(file_name) @@ -117,7 +117,7 @@ class TestHead < TestBaseCommand @record = { 'message' => 'dummy' } end - test 'should output the beginning of file with default format (out_file)' do + test 'should output the beginning of the file with default format (out_file)' do argv = ["#{TMP_DIR}/#{@file_name}"] timezone do @@ -128,7 +128,7 @@ class TestHead < TestBaseCommand end end - test 'should set the number of line to display' do + test 'should set the number of lines to display' do argv = ["#{TMP_DIR}/#{@file_name}", '-n', '1'] timezone do @@ -148,7 +148,7 @@ class TestHead < TestBaseCommand end end - test 'should output content of file with json format' do + test 'should output content of a file with json format' do argv = ["#{TMP_DIR}/#{@file_name}", '--format=json'] timezone do @@ -159,7 +159,7 @@ class TestHead < TestBaseCommand end end - test 'should fails with invalid format' do + test 'should fail with an invalid format' do argv = ["#{TMP_DIR}/#{@file_name}", '--format=invalid'] timezone do @@ -180,13 +180,13 @@ class TestCat < TestBaseCommand 'file is not passed' => [], 'file is not found' => %w(invalid_path.log) ) - test 'should fail if file is invalid' do |argv| + test 'should fail if a file is invalid' do |argv| assert_raise(SystemExit) do capture_stdout { Command::Head.new(argv) } end end - test 'should success if file is valid' do + test 'should succeed if a file is valid' do file_name = 'packed.log' argv = ["#{TMP_DIR}/#{file_name}"] create_message_packed_file(file_name) @@ -204,7 +204,7 @@ class TestCat < TestBaseCommand @record = { 'message' => 'dummy' } end - test 'should output the beginning of file with default format (out_file)' do + test 'should output the beginning of the file with default format (out_file)' do argv = ["#{TMP_DIR}/#{@file_name}"] timezone do @@ -215,7 +215,7 @@ class TestCat < TestBaseCommand end end - test 'should output content of file with json format' do + test 'should output content of a file with json format' do argv = ["#{TMP_DIR}/#{@file_name}", '--format=json'] timezone do @@ -226,7 +226,7 @@ class TestCat < TestBaseCommand end end - test 'should fails with invalid format' do + test 'should fail with an invalid format' do argv = ["#{TMP_DIR}/#{@file_name}", '--format=invalid'] timezone do @@ -240,3 +240,32 @@ class TestCat < TestBaseCommand end end end + +class TestFormats < TestBaseCommand + test 'parse_option!' do + assert_raise(SystemExit) do + capture_stdout do + Command::Formats.new(['--plugins=invalid_dir_path']) + end + end + end + + sub_test_case 'call' do + test 'display available plugins' do + f = Command::Formats.new + out = capture_stdout { f.call } + assert out.include?('json') + assert out.include?('csv') + end + + test 'can add new plugins' do + dir_path = File.expand_path(File.dirname(__FILE__) + '/../scripts/fluent/plugin') + + f = Command::Formats.new(["--plugins=#{dir_path}"]) + out = capture_stdout { f.call } + assert out.include?('json') + assert out.include?('csv') + assert out.include?('known') + end + end +end