fluentd 0.14.13-x64-mingw32 → 0.14.17-x64-mingw32

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.

Files changed (67) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +4 -5
  3. data/ChangeLog +106 -0
  4. data/MAINTAINERS.md +5 -0
  5. data/README.md +25 -0
  6. data/example/worker_section.conf +36 -0
  7. data/fluentd.gemspec +1 -1
  8. data/lib/fluent/agent.rb +5 -2
  9. data/lib/fluent/command/binlog_reader.rb +1 -0
  10. data/lib/fluent/command/fluentd.rb +28 -12
  11. data/lib/fluent/command/plugin_config_formatter.rb +0 -1
  12. data/lib/fluent/command/plugin_generator.rb +1 -1
  13. data/lib/fluent/compat/detach_process_mixin.rb +8 -0
  14. data/lib/fluent/compat/input.rb +0 -10
  15. data/lib/fluent/compat/output.rb +0 -10
  16. data/lib/fluent/config/element.rb +22 -0
  17. data/lib/fluent/config/literal_parser.rb +2 -0
  18. data/lib/fluent/config/types.rb +2 -2
  19. data/lib/fluent/engine.rb +27 -10
  20. data/lib/fluent/env.rb +3 -3
  21. data/lib/fluent/log.rb +4 -1
  22. data/lib/fluent/plugin/base.rb +3 -0
  23. data/lib/fluent/plugin/filter.rb +2 -2
  24. data/lib/fluent/plugin/filter_parser.rb +17 -6
  25. data/lib/fluent/plugin/in_forward.rb +1 -1
  26. data/lib/fluent/plugin/in_http.rb +4 -0
  27. data/lib/fluent/plugin/in_monitor_agent.rb +8 -3
  28. data/lib/fluent/plugin/in_syslog.rb +3 -2
  29. data/lib/fluent/plugin/in_tail.rb +14 -3
  30. data/lib/fluent/plugin/in_udp.rb +6 -2
  31. data/lib/fluent/plugin/out_file.rb +5 -0
  32. data/lib/fluent/plugin/out_forward.rb +5 -2
  33. data/lib/fluent/plugin/output.rb +13 -8
  34. data/lib/fluent/plugin/parser_apache2.rb +1 -1
  35. data/lib/fluent/plugin/parser_syslog.rb +40 -1
  36. data/lib/fluent/plugin_helper/cert_option.rb +2 -2
  37. data/lib/fluent/plugin_helper/compat_parameters.rb +1 -1
  38. data/lib/fluent/plugin_helper/storage.rb +1 -1
  39. data/lib/fluent/root_agent.rb +36 -4
  40. data/lib/fluent/supervisor.rb +37 -6
  41. data/lib/fluent/system_config.rb +7 -0
  42. data/lib/fluent/time.rb +1 -0
  43. data/lib/fluent/version.rb +1 -1
  44. data/lib/fluent/winsvc.rb +25 -11
  45. data/test/command/test_fluentd.rb +253 -4
  46. data/test/config/test_element.rb +63 -0
  47. data/test/config/test_literal_parser.rb +1 -1
  48. data/test/config/test_system_config.rb +36 -6
  49. data/test/config/test_types.rb +19 -0
  50. data/test/plugin/test_filter_parser.rb +35 -0
  51. data/test/plugin/test_in_http.rb +58 -4
  52. data/test/plugin/test_in_monitor_agent.rb +90 -9
  53. data/test/plugin/test_in_tail.rb +16 -0
  54. data/test/plugin/test_in_udp.rb +11 -1
  55. data/test/plugin/test_out_file.rb +9 -0
  56. data/test/plugin/test_out_forward.rb +45 -0
  57. data/test/plugin/test_output.rb +15 -15
  58. data/test/plugin/test_output_as_buffered.rb +30 -2
  59. data/test/plugin/test_parser_apache2.rb +8 -0
  60. data/test/plugin/test_parser_syslog.rb +176 -0
  61. data/test/plugin_helper/test_server.rb +37 -31
  62. data/test/plugin_helper/test_storage.rb +9 -0
  63. data/test/test_log.rb +6 -0
  64. data/test/test_plugin_classes.rb +50 -0
  65. data/test/test_root_agent.rb +245 -14
  66. data/test/test_time_parser.rb +12 -0
  67. metadata +13 -5
@@ -105,6 +105,11 @@ module Fluent::Plugin
105
105
  buffer_conf['path'] = conf['path'] || '/tmp/dummy_path'
106
106
  end
107
107
 
108
+ if conf.has_key?('utc') || conf.has_key?('localtime')
109
+ param_name = conf.has_key?('utc') ? 'utc' : 'localtime'
110
+ log.warn "'#{param_name}' is deperecated for output plugin. This parameter is used for formatter plugin in compatibility layer. If you want to use same feature, use timekey_use_utc parameter in <buffer> directive instead"
111
+ end
112
+
108
113
  super
109
114
 
110
115
  @compress_method = SUPPORTED_COMPRESS_MAP[@compress]
@@ -420,7 +420,7 @@ module Fluent::Plugin
420
420
  # return chunk id to be committed
421
421
  def read_ack_from_sock(sock, unpacker)
422
422
  begin
423
- raw_data = sock.recv(@read_length)
423
+ raw_data = sock.instance_of?(Fluent::PluginHelper::Socket::WrappedSocket::TLS) ? sock.readpartial(@read_length) : sock.recv(@read_length)
424
424
  rescue Errno::ECONNRESET
425
425
  raw_data = ""
426
426
  end
@@ -431,6 +431,7 @@ module Fluent::Plugin
431
431
  if raw_data.empty?
432
432
  log.warn "destination node closed the connection. regard it as unavailable.", host: info.node.host, port: info.node.port
433
433
  info.node.disable!
434
+ rollback_write(info.chunk_id)
434
435
  return nil
435
436
  else
436
437
  unpacker.feed(raw_data)
@@ -450,6 +451,8 @@ module Fluent::Plugin
450
451
  log.error "unexpected error while receiving ack message", error: e
451
452
  log.error_backtrace
452
453
  ensure
454
+ info.sock.close_write rescue nil
455
+ info.sock.close rescue nil
453
456
  @sock_ack_waiting_mutex.synchronize do
454
457
  @sock_ack_waiting.delete(info)
455
458
  end
@@ -492,7 +495,7 @@ module Fluent::Plugin
492
495
 
493
496
  readable_sockets.each do |sock|
494
497
  chunk_id = read_ack_from_sock(sock, unpacker)
495
- commit_write(chunk_id)
498
+ commit_write(chunk_id) if chunk_id
496
499
  end
497
500
  rescue => e
498
501
  log.error "unexpected error while receiving ack", error: e
@@ -122,12 +122,17 @@ module Fluent
122
122
  raise NotImplementedError, "BUG: output plugins MUST implement this method"
123
123
  end
124
124
 
125
- def formatted_to_msgpack_binary
125
+ def formatted_to_msgpack_binary?
126
126
  # To indicate custom format method (#format) returns msgpack binary or not.
127
127
  # If #format returns msgpack binary, override this method to return true.
128
128
  false
129
129
  end
130
130
 
131
+ # Compatibility for existing plugins
132
+ def formatted_to_msgpack_binary
133
+ formatted_to_msgpack_binary?
134
+ end
135
+
131
136
  def prefer_buffered_processing
132
137
  # override this method to return false only when all of these are true:
133
138
  # * plugin has both implementation for buffered and non-buffered methods
@@ -589,13 +594,13 @@ module Fluent
589
594
  example = @argument[:example]
590
595
  timekey = @argument[:timekey]
591
596
  if !sec && timekey
592
- raise Fluent::ConfigError, "Parameter '#{name}' doesn't have timestamp placeholders for timekey #{timekey.to_i}"
597
+ raise Fluent::ConfigError, "Parameter '#{name}: #{string}' doesn't have timestamp placeholders for timekey #{timekey.to_i}"
593
598
  end
594
599
  if sec && !timekey
595
- raise Fluent::ConfigError, "Parameter '#{name}' has timestamp placeholders, but chunk key 'time' is not configured"
600
+ raise Fluent::ConfigError, "Parameter '#{name}: #{string}' has timestamp placeholders, but chunk key 'time' is not configured"
596
601
  end
597
602
  if sec && timekey && timekey < sec
598
- raise Fluent::ConfigError, "Parameter '#{@name}' doesn't have timestamp placeholder for #{title}('#{example}') for timekey #{timekey.to_i}"
603
+ raise Fluent::ConfigError, "Parameter '#{name}: #{string}' doesn't have timestamp placeholder for #{title}('#{example}') for timekey #{timekey.to_i}"
599
604
  end
600
605
  end
601
606
 
@@ -603,10 +608,10 @@ module Fluent
603
608
  parts = @argument[:parts]
604
609
  tagkey = @argument[:tagkey]
605
610
  if tagkey && parts.empty?
606
- raise Fluent::ConfigError, "Parameter '#{@name}' doesn't have tag placeholder"
611
+ raise Fluent::ConfigError, "Parameter '#{name}: #{string}' doesn't have tag placeholder"
607
612
  end
608
613
  if !tagkey && !parts.empty?
609
- raise Fluent::ConfigError, "Parameter '#{@name}' has tag placeholders, but chunk key 'tag' is not configured"
614
+ raise Fluent::ConfigError, "Parameter '#{name}: #{string}' has tag placeholders, but chunk key 'tag' is not configured"
610
615
  end
611
616
  end
612
617
 
@@ -615,11 +620,11 @@ module Fluent
615
620
  chunk_keys = @argument[:chunkkeys]
616
621
  if (chunk_keys - keys).size > 0
617
622
  not_specified = (chunk_keys - keys).sort
618
- raise Fluent::ConfigError, "Parameter '#{@name}' doesn't have enough placeholders for keys #{not_specified.join(',')}"
623
+ raise Fluent::ConfigError, "Parameter '#{name}: #{string}' doesn't have enough placeholders for keys #{not_specified.join(',')}"
619
624
  end
620
625
  if (keys - chunk_keys).size > 0
621
626
  not_satisfied = (keys - chunk_keys).sort
622
- raise Fluent::ConfigError, "Parameter '#{@name}' has placeholders, but chunk keys doesn't have keys #{not_satisfied.join(',')}"
627
+ raise Fluent::ConfigError, "Parameter '#{name}: #{string}' has placeholders, but chunk keys doesn't have keys #{not_satisfied.join(',')}"
623
628
  end
624
629
  end
625
630
  end
@@ -21,7 +21,7 @@ module Fluent
21
21
  class Apache2Parser < Parser
22
22
  Plugin.register_parser('apache2', self)
23
23
 
24
- REGEXP = /^(?<host>[^ ]*) [^ ]* (?<user>[^ ]*) \[(?<time>[^\]]*)\] "(?<method>\S+)(?: +(?<path>[^\"]*?)(?: +\S*)?)?" (?<code>[^ ]*) (?<size>[^ ]*)(?: "(?<referer>[^\"]*)" "(?<agent>[^\"]*)")?$/
24
+ REGEXP = /^(?<host>[^ ]*) [^ ]* (?<user>[^ ]*) \[(?<time>[^\]]*)\] "(?<method>\S+)(?: +(?<path>(?:[^\"]|\\.)*?)(?: +\S*)?)?" (?<code>[^ ]*) (?<size>[^ ]*)(?: "(?<referer>(?:[^\"]|\\.)*)" "(?<agent>(?:[^\"]|\\.)*)")?$/
25
25
  TIME_FORMAT = "%d/%b/%Y:%H:%M:%S %z"
26
26
 
27
27
  def initialize
@@ -27,9 +27,13 @@ module Fluent
27
27
  REGEXP = /^(?<time>[^ ]*\s*[^ ]* [^ ]*) (?<host>[^ ]*) (?<ident>[a-zA-Z0-9_\/\.\-]*)(?:\[(?<pid>[0-9]+)\])?(?:[^\:]*\:)? *(?<message>.*)$/
28
28
  # From in_syslog default pattern
29
29
  REGEXP_WITH_PRI = /^\<(?<pri>[0-9]+)\>(?<time>[^ ]* {1,2}[^ ]* [^ ]*) (?<host>[^ ]*) (?<ident>[a-zA-Z0-9_\/\.\-]*)(?:\[(?<pid>[0-9]+)\])?(?:[^\:]*\:)? *(?<message>.*)$/
30
+ REGEXP_RFC5424 = /\A^\<(?<pri>[0-9]{1,3})\>[1-9]\d{0,2} (?<time>[^ ]+) (?<host>[^ ]+) (?<ident>[^ ]+) (?<pid>[-0-9]+) (?<msgid>[^ ]+) (?<extradata>(\[(.*)\]|[^ ])) (?<message>.+)$\z/
31
+ REGEXP_DETECT_RFC5424 = /^\<.*\>[1-9]\d{0,2}/
30
32
 
31
33
  config_set_default :time_format, "%b %d %H:%M:%S"
32
34
  config_param :with_priority, :bool, default: false
35
+ config_param :message_format, :enum, list: [:rfc3164, :rfc5424, :auto], default: :rfc3164
36
+ config_param :rfc5424_time_format, :string, default: "%Y-%m-%dT%H:%M:%S.%L%z"
33
37
 
34
38
  def initialize
35
39
  super
@@ -39,7 +43,27 @@ module Fluent
39
43
  def configure(conf)
40
44
  super
41
45
 
42
- @regexp = @with_priority ? REGEXP_WITH_PRI : REGEXP
46
+ @time_parser_rfc3164 = @time_parser_rfc5424 = nil
47
+ @regexp = case @message_format
48
+ when :rfc3164
49
+ class << self
50
+ alias_method :parse, :parse_plain
51
+ end
52
+ @with_priority ? REGEXP_WITH_PRI : REGEXP
53
+ when :rfc5424
54
+ class << self
55
+ alias_method :parse, :parse_plain
56
+ end
57
+ @time_format = @rfc5424_time_format unless conf.has_key?('time_format')
58
+ REGEXP_RFC5424
59
+ when :auto
60
+ class << self
61
+ alias_method :parse, :parse_auto
62
+ end
63
+ @time_parser_rfc3164 = time_parser_create(format: @time_format)
64
+ @time_parser_rfc5424 = time_parser_create(format: @rfc5424_time_format)
65
+ nil
66
+ end
43
67
  @time_parser = time_parser_create
44
68
  end
45
69
 
@@ -48,6 +72,21 @@ module Fluent
48
72
  end
49
73
 
50
74
  def parse(text)
75
+ # This is overwritten in configure
76
+ end
77
+
78
+ def parse_auto(text, &block)
79
+ if REGEXP_DETECT_RFC5424.match(text)
80
+ @regexp = REGEXP_RFC5424
81
+ @time_parser = @time_parser_rfc5424
82
+ else
83
+ @regexp = @with_priority ? REGEXP_WITH_PRI : REGEXP
84
+ @time_parser = @time_parser_rfc3164
85
+ end
86
+ parse_plain(text, &block)
87
+ end
88
+
89
+ def parse_plain(text, &block)
51
90
  m = @regexp.match(text)
52
91
  unless m
53
92
  yield nil, nil
@@ -46,12 +46,12 @@ module Fluent
46
46
  case
47
47
  when conf.cert_path
48
48
  raise Fluent::ConfigError, "private_key_path is required when cert_path is specified" unless conf.private_key_path
49
- raise Fluent::ConfigError, "private_key_passphrase is required when cert_path is specified" unless conf.private_key_passphrase
49
+ log.warn "For security reason, setting private_key_passphrase is recommended when cert_path is specified" unless conf.private_key_passphrase
50
50
  cert_option_load(conf.cert_path, conf.private_key_path, conf.private_key_passphrase)
51
51
 
52
52
  when conf.ca_cert_path
53
53
  raise Fluent::ConfigError, "ca_private_key_path is required when ca_cert_path is specified" unless conf.ca_private_key_path
54
- raise Fluent::ConfigError, "ca_private_key_passphrase is required when ca_cert_path is specified" unless conf.ca_private_key_passphrase
54
+ log.warn "For security reason, setting ca_private_key_passphrase is recommended when ca_cert_path is specified" unless conf.ca_private_key_passphrase
55
55
  generate_opts = cert_option_cert_generation_opts_from_conf(conf)
56
56
  cert_option_generate_server_pair_by_ca(
57
57
  conf.ca_cert_path,
@@ -55,7 +55,7 @@ module Fluent
55
55
  "keys" => "keys", # CSVParser, TSVParser (old ValuesParser)
56
56
  "time_key" => "time_key",
57
57
  "time_format" => "time_format",
58
- "localtim" => nil,
58
+ "localtime" => nil,
59
59
  "utc" => nil,
60
60
  "delimiter" => "delimiter",
61
61
  "keep_time_key" => "keep_time_key",
@@ -30,7 +30,7 @@ module Fluent
30
30
  StorageState = Struct.new(:storage, :running)
31
31
 
32
32
  def storage_create(usage: '', type: nil, conf: nil, default_type: nil)
33
- if conf && !conf.arg.empty?
33
+ if conf && conf.respond_to?(:arg) && !conf.arg.empty?
34
34
  usage = conf.arg
35
35
  end
36
36
  if !usage.empty? && usage !~ /^[a-zA-Z][-_.a-zA-Z0-9]*$/
@@ -64,11 +64,37 @@ module Fluent
64
64
  attr_reader :labels
65
65
 
66
66
  def configure(conf)
67
+ # initialize <worker> elements
68
+ conf.elements(name: 'worker').each do |e|
69
+ target_worker_id_str = e.arg
70
+ if target_worker_id_str.empty?
71
+ raise ConfigError, "Missing worker id on <worker> directive"
72
+ end
73
+
74
+ target_worker_id = target_worker_id_str.to_i
75
+ if target_worker_id < 0 || target_worker_id > (Fluent::Engine.system_config.workers - 1)
76
+ raise ConfigError, "worker id #{target_worker_id} specified by <worker> directive is not allowed. Available worker id is between 0 and #{(Fluent::Engine.system_config.workers - 1)}"
77
+ end
78
+
79
+ ## On dry_run mode, all worker sections have to be configured on supervisor (recognized as worker_id = 0).
80
+ target_worker_id = 0 if Fluent::Engine.dry_run_mode
81
+
82
+ e.elements.each do |elem|
83
+ unless ['source', 'match', 'filter', 'label'].include?(elem.name)
84
+ raise ConfigError, "<worker> section cannot have <#{elem.name}> directive"
85
+ end
86
+ elem.set_target_worker_id(target_worker_id)
87
+ end
88
+ conf += e
89
+ end
90
+ conf.elements.delete_if{|e| e.name == 'worker'}
91
+
67
92
  error_label_config = nil
68
93
 
69
94
  # initialize <label> elements before configuring all plugins to avoid 'label not found' in input, filter and output.
70
95
  label_configs = {}
71
96
  conf.elements(name: 'label').each { |e|
97
+ next if e.for_another_worker?
72
98
  name = e.arg
73
99
  raise ConfigError, "Missing symbol argument on <label> directive" if name.empty?
74
100
 
@@ -90,6 +116,7 @@ module Fluent
90
116
  log.info :worker0, "'--without-source' is applied. Ignore <source> sections"
91
117
  else
92
118
  conf.elements(name: 'source').each { |e|
119
+ next if e.for_another_worker?
93
120
  type = e['@type']
94
121
  raise ConfigError, "Missing '@type' parameter on <source> directive" unless type
95
122
  add_source(type, e)
@@ -136,8 +163,12 @@ module Fluent
136
163
  def start
137
164
  lifecycle(desc: true) do |i| # instance
138
165
  i.start unless i.started?
139
- end
140
- lifecycle(desc: true) do |i|
166
+ # Input#start sometimes emits lots of evetns with in_tail/`read_from_head true` case
167
+ # and it causes deadlock for small buffer/queue output. To avoid such problem,
168
+ # buffer related output threads should be run before `Input#start`.
169
+ # This is why after_start should be called immediately after start call.
170
+ # This depends on `desc: true` because calling plugin order of `desc: true` is
171
+ # Output, Filter, Label, Output with Router, then Input.
141
172
  i.after_start unless i.after_started?
142
173
  end
143
174
  end
@@ -173,7 +204,7 @@ module Fluent
173
204
  log.debug "calling #{method} on #{kind} plugin", type: Plugin.lookup_type_from_class(instance.class), plugin_id: instance.plugin_id
174
205
  instance.send(method) unless instance.send(checker)
175
206
  rescue Exception => e
176
- log.warn "unexpected error while calling #{method} on #{kind} plugin", pluguin: instance.class, plugin_id: instance.plugin_id, error: e
207
+ log.warn "unexpected error while calling #{method} on #{kind} plugin", plugin: instance.class, plugin_id: instance.plugin_id, error: e
177
208
  log.warn_backtrace
178
209
  end
179
210
  end
@@ -231,7 +262,8 @@ module Fluent
231
262
  end
232
263
 
233
264
  def add_source(type, conf)
234
- log.info :worker0, "adding source", type: type
265
+ log_type = conf.for_this_worker? ? :default : :worker0
266
+ log.info log_type, "adding source", type: type
235
267
 
236
268
  input = Plugin.new_input(type)
237
269
  # <source> emits events to the top-level event router (RootAgent#event_router).
@@ -61,6 +61,7 @@ module Fluent
61
61
 
62
62
  def after_run
63
63
  stop_rpc_server if @rpc_endpoint
64
+ Fluent::Supervisor.cleanup_resources
64
65
  end
65
66
 
66
67
  def run_rpc_server
@@ -383,10 +384,17 @@ module Fluent
383
384
  supervise: true,
384
385
  standalone_worker: false,
385
386
  signame: nil,
386
- winsvcreg: nil,
387
387
  }
388
388
  end
389
389
 
390
+ def self.cleanup_resources
391
+ unless Fluent.windows?
392
+ if ENV.has_key?('SERVERENGINE_SOCKETMANAGER_PATH')
393
+ FileUtils.rm_f(ENV['SERVERENGINE_SOCKETMANAGER_PATH'])
394
+ end
395
+ end
396
+ end
397
+
390
398
  def initialize(opt)
391
399
  @daemonize = opt[:daemonize]
392
400
  @supervise = opt[:supervise]
@@ -449,7 +457,7 @@ module Fluent
449
457
  end
450
458
  end
451
459
 
452
- dry_run if @dry_run
460
+ dry_run_cmd if @dry_run
453
461
  supervise
454
462
  end
455
463
 
@@ -482,6 +490,10 @@ module Fluent
482
490
  read_config
483
491
  set_system_config
484
492
 
493
+ if @standalone_worker && @workers != 1
494
+ raise Fluent::ConfigError, "invalid number of workers (must be 1 or unspecified) with --no-supervisor: #{@workers}"
495
+ end
496
+
485
497
  install_main_process_signal_handlers
486
498
 
487
499
  # This is the only log messsage for @standalone_worker
@@ -493,6 +505,7 @@ module Fluent
493
505
  init_engine
494
506
  run_configure
495
507
  run_engine
508
+ self.class.cleanup_resources if @standalone_worker
496
509
  exit 0
497
510
  end
498
511
  end
@@ -505,17 +518,32 @@ module Fluent
505
518
  ENV['SERVERENGINE_SOCKETMANAGER_PATH'] = socket_manager_path.to_s
506
519
  end
507
520
 
508
- def dry_run
521
+ def dry_run_cmd
509
522
  $log.info "starting fluentd-#{Fluent::VERSION} as dry run mode"
510
- change_privilege
511
- init_engine
512
- run_configure
523
+ @system_config.suppress_config_dump = true
524
+ dry_run
513
525
  exit 0
514
526
  rescue => e
515
527
  $log.error "dry run failed: #{e}"
516
528
  exit 1
517
529
  end
518
530
 
531
+ ## Set Engine's dry_run_mode true to override all target_id of worker sections
532
+ def dry_run
533
+ begin
534
+ Fluent::Engine.dry_run_mode = true
535
+ change_privilege
536
+ init_engine
537
+ run_configure
538
+ rescue Fluent::ConfigError => e
539
+ $log.error "config error", file: @config_path, error: e
540
+ $log.debug_backtrace
541
+ exit!(1)
542
+ ensure
543
+ Fluent::Engine.dry_run_mode = false
544
+ end
545
+ end
546
+
519
547
  def show_plugin_config
520
548
  name, type = @show_plugin_config.split(":") # input:tail
521
549
  $log.info "Use fluent-plugin-config-format --format=txt #{name} #{type}"
@@ -523,6 +551,9 @@ module Fluent
523
551
  end
524
552
 
525
553
  def supervise
554
+ # Make dumpable conf, which is set corresponding_proxies for all elements in all worker sections
555
+ dry_run
556
+
526
557
  Process.setproctitle("supervisor:#{@process_name}") if @process_name
527
558
  $log.info "starting fluentd-#{Fluent::VERSION}", pid: Process.pid
528
559
 
@@ -98,6 +98,13 @@ module Fluent
98
98
  next # doesn't exist in command line options
99
99
  when :emit_error_log_interval
100
100
  system.emit_error_log_interval = @suppress_interval if @suppress_interval
101
+ when :log_level
102
+ ll_value = instance_variable_get("@log_level")
103
+ # info level can't be specified via command line option.
104
+ # log_level is info here, it is default value and <system>'s log_level should be applied if exists.
105
+ if ll_value != Fluent::Log::LEVEL_INFO
106
+ system.log_level = ll_value
107
+ end
101
108
  else
102
109
  next unless instance_variable_defined?("@#{param}")
103
110
  supervisor_value = instance_variable_get("@#{param}")
@@ -208,6 +208,7 @@ module Fluent
208
208
  @parse = case
209
209
  when format_with_timezone && strptime then ->(v){ Fluent::EventTime.from_time(strptime.exec(v)) }
210
210
  when format_with_timezone then ->(v){ Fluent::EventTime.from_time(Time.strptime(v, format)) }
211
+ when format == '%iso8601' then ->(v){ Fluent::EventTime.from_time(Time.iso8601(v)) }
211
212
  when strptime then ->(v){ t = strptime.exec(v); Fluent::EventTime.new(t.to_i + offset_diff, t.nsec) }
212
213
  when format then ->(v){ t = Time.strptime(v, format); Fluent::EventTime.new(t.to_i + offset_diff, t.nsec) }
213
214
  else ->(v){ Fluent::EventTime.parse(v) }
@@ -16,6 +16,6 @@
16
16
 
17
17
  module Fluent
18
18
 
19
- VERSION = '0.14.13'
19
+ VERSION = '0.14.17'
20
20
 
21
21
  end
@@ -14,10 +14,9 @@
14
14
  # limitations under the License.
15
15
  #
16
16
 
17
- INTEVENTOBJ_NAME = "fluentdwinsvc"
18
-
19
17
  begin
20
18
 
19
+ require 'optparse'
21
20
  require 'windows/debug'
22
21
  require 'Windows/Library'
23
22
  require 'win32/daemon'
@@ -27,34 +26,50 @@ begin
27
26
  include Windows::Library
28
27
  include Windows::Debug
29
28
 
30
- def read_fluentdopt
29
+ op = OptionParser.new
30
+ opts = {service_name: nil}
31
+ op.on('--service-name NAME', "The name of the Windows Service") {|name|
32
+ opts[:service_name] = name
33
+ }
34
+ op.parse(ARGV)
35
+ if opts[:service_name] == nil
36
+ raise "Error: No Windows Service name set. Use '--service-name'"
37
+ end
38
+
39
+ def read_fluentdopt(service_name)
31
40
  require 'win32/Registry'
32
- Win32::Registry::HKEY_LOCAL_MACHINE.open("SYSTEM\\CurrentControlSet\\Services\\fluentdwinsvc") do |reg|
41
+ Win32::Registry::HKEY_LOCAL_MACHINE.open("SYSTEM\\CurrentControlSet\\Services\\#{service_name}") do |reg|
33
42
  reg.read("fluentdopt")[1] rescue ""
34
43
  end
35
44
  end
36
45
 
37
- def service_main_start
46
+ def service_main_start(service_name)
38
47
  ruby_path = 0.chr * 260
39
48
  GetModuleFileName.call(0, ruby_path,260)
40
49
  ruby_path = ruby_path.rstrip.gsub(/\\/, '/')
41
50
  rubybin_dir = ruby_path[0, ruby_path.rindex("/")]
42
- opt = read_fluentdopt
43
- Process.spawn(rubybin_dir + "/ruby.exe " + rubybin_dir + "/fluentd " + opt + " -x " + INTEVENTOBJ_NAME)
51
+ opt = read_fluentdopt(service_name)
52
+ Process.spawn("\"#{rubybin_dir}/ruby.exe\" \"#{rubybin_dir}/fluentd\" #{opt} -x #{service_name}")
44
53
  end
45
54
 
46
55
  class FluentdService < Daemon
47
56
  @pid = 0
57
+ @service_name = ''
48
58
 
59
+ def initialize(service_name)
60
+ @service_name = service_name
61
+ end
62
+
49
63
  def service_main
50
- @pid = service_main_start
64
+
65
+ @pid = service_main_start(@service_name)
51
66
  while running?
52
67
  sleep 10
53
68
  end
54
69
  end
55
70
 
56
71
  def service_stop
57
- ev = Win32::Event.open(INTEVENTOBJ_NAME)
72
+ ev = Win32::Event.open(@service_name)
58
73
  ev.set
59
74
  ev.close
60
75
  if @pid > 0
@@ -63,9 +78,8 @@ begin
63
78
  end
64
79
  end
65
80
 
66
- FluentdService.mainloop
81
+ FluentdService.new(opts[:service_name]).mainloop
67
82
 
68
83
  rescue Exception => err
69
84
  raise
70
85
  end
71
-