require 'logger' require 'tempfile' require 'jrjackson' require_relative 'mjolnir' require_relative 'metadata' require_relative 'store' require_relative 'stats' require_relative 'input' require_relative 'filter' require_relative 'output' module Anschel class Main < Mjolnir desc 'version', 'Show application version' def version puts VERSION end desc 'art', 'Show application art' def art puts "\n%s\n" % ART end desc 'agent', 'Run application' option :config, \ type: :string, aliases: %w[ -c ], desc: 'Path to primary configuration file', default: '/etc/anschel.json' include_common_options def agent log.info \ event: 'hello', version: VERSION, options: options.to_hash, num_cpus: num_cpus input, filter, output, store, stats, ts = \ nil, nil, nil, nil, nil, nil, nil begin # Allow for //-style inline comments in JSON raw_config = File.read(options.config).gsub(/^\s*\/\/ .*/, '') config = JrJackson::Json.load \ raw_config, symbolize_keys: true setup_log4j config[:log4j] store = Store.new config[:store], log stats = Stats.new config[:stats_interval], log filter = Filter.new config[:filter], stats, log output = Output.new config[:output], stats, log input = Input.new \ config[:input], config[:queue_size], stats, log, store[:input] stats.create 'event' stats.get 'event' ts = num_cpus.times.map do Thread.new do loop do event = JrJackson::Json.load \ input.shift, symbolize_keys: true output.push filter.apply(event) stats.inc 'event' end end end ts.each { |t| t.abort_on_exception = true } rescue Exception => e log.fatal \ event: 'exception', exception: e.inspect, class: e.class, message: e.message, backtrace: e.backtrace bye output, input, store, log, :error exit 2 end log.info event: 'all-systems-clear' trap('SIGINT') do bye output, input, store, log exit end ts.map &:join end private def bye output, input, store, log, level=:info if input && output output.stop ; input.stop store[:input] = input.leftovers log.debug event: 'flush' end log.send level, event: 'goodbye', version: VERSION end end end