# pidfile
# td-agent: /var/run/td-agent/td-agent.pid
# - https://github.com/treasure-data/omnibus-td-agent/blob/master/templates/etc/systemd/td-agent.service.erb#L18
# - https://github.com/treasure-data/omnibus-td-agent/blob/master/templates/etc/init.d/deb/td-agent#L24
# - https://github.com/treasure-data/omnibus-td-agent/blob/master/templates/etc/init.d/rpm/td-agent#L24
# - https://github.com/treasure-data/omnibus-td-agent/blob/master/templates/etc/td-agent/logrotate.d/td-agent.logrotate#L10
# fluentd: nothing (or --daemon PIDFILE)
#
# logfile
# td-agent: /var/log/td-agent/td-agent.log
# - https://github.com/treasure-data/omnibus-td-agent/blob/master/templates/etc/systemd/td-agent.service.erb#L21
# - https://github.com/treasure-data/omnibus-td-agent/blob/master/templates/etc/init.d/deb/td-agent#L23
# - https://github.com/treasure-data/omnibus-td-agent/blob/master/templates/etc/init.d/rpm/td-agent#L23
# fluentd: stdout (or --log LOGFILE)
#
# config file
# td-agent: /etc/td-agent/td-agent.conf
# - https://github.com/treasure-data/omnibus-td-agent/blob/master/templates/etc/systemd/td-agent.service.erb#L14
# fluentd: /etc/fluent/fluent.conf (created by fluentd -s)
require "strscan"
class Fluentd
class Agent
module Common
attr_reader :extra_options
def self.included(base)
base.include(Fluentd::Agent::ProcessOperation)
end
# define these methods on each Agent class
%w(start stop restart version).each do |method|
define_method(method) do
raise NotImplementedError, "'#{method}' method is required to be defined"
end
end
def initialize(options = {})
@extra_options = options
end
def pid_file
extra_options[:pid_file] || self.class.default_options[:pid_file]
end
def log_file
extra_options[:log_file] || self.class.default_options[:log_file]
end
def log
@log ||= FluentdLog.new(log_file)
end
def config_file
extra_options[:config_file] || self.class.default_options[:config_file]
end
# -- config
def config
File.read(config_file)
end
def config_write(content)
backup_config
File.open(config_file, "w") do |f|
f.write content
end
end
def config_append(content)
backup_config
File.open(config_file, "a") do |f|
f.write "\n"
f.write content
end
end
def config_merge(content)
if content.start_with?("})
label, sections = parse_label_section(label_content, started)
contents["label:#{label}"] << { label: label, pos: started, sections: sections, size: label_content.size }
else
raise TypeError, "Unknown section: #{started}: #{section_type}"
end
end
contents
end
def parse_label_section(content, offset)
scanner = StringScanner.new(content)
scanner.scan_until(/^})
pos = scanner.pos
header = scanner.scan_until(/^\s*<(filter|match)/)
type = scanner[1]
source = header + scanner.scan_until(%r{^\s*(?:filter|match)>})
sections[type] << { label: label, pos: pos + offset, content: source.sub(/\n+/, "") }
end
return label, sections
end
def dump_parsed_config(parsed_config)
content = "".dup
sources = parsed_config["source"] || []
filters = parsed_config["filter"] || []
matches = parsed_config["match"] || []
labels = parsed_config.select do |key, sections|
key.start_with?("label:")
end
labels = labels.values.flatten
sorted_sections = (sources + filters + matches + labels).sort_by do |section|
section[:pos]
end
sorted_sections.each do |section|
if section.key?(:label)
label = section[:label]
sub_filters = section.dig(:sections, "filter") || []
sub_matches = section.dig(:sections, "match") || []
sub_sections = (sub_filters + sub_matches).sort_by do |sub_section|
sub_section[:pos]
end
content << "\n\n"
else
content << section[:content] << "\n\n"
end
end
content.chomp
end
end
end
end