munin-contrib/plugins/ejabberd/ejabberd_scanlog

168 lines
4.4 KiB
Ruby
Executable File

#!/usr/bin/env ruby
require 'yaml'
# ejabberd_scanlog revision 2 (Mar 2012)
#
# Scans ejabberd 2.1.x log for known error signatures and counts them
#
# Required privileges: read ejabberd log (user ejabberd or, in some cases, root)
#
# OS: Unix
#
# Configuration:
# env.log: ejabberd log file (defaults to /var...)
#
# Author: Artem Sheremet <dot.doom@gmail.com>
#
# Run with 'debug' argument to initiate full log rescan.
# This will also print out unparsed log entries to stderr.
# Cache file will be untouched.
#
LOG_FILE = ENV['log'] || '/var/log/ejabberd/ejabberd.log'
CACHE_FILE = '/tmp/ejabberd_scanlog_cache'.freeze # cache file position
DEFAULT_CACHE = { start: 0 }.freeze
$debug_mode = ARGV.first == 'debug'
if $debug_mode
log_info = DEFAULT_CACHE
else
begin
log_info = YAML.load IO.read(CACHE_FILE)
rescue StandardError
log_info = DEFAULT_CACHE
end
if File.size(LOG_FILE) < log_info[:start]
# logrotate?
log_info = DEFAULT_CACHE
end
end
if ARGV.first == 'reset'
log_info = { start: File.size(LOG_FILE) - 1 }
puts 'Log reset'
end
new_data = ''
File.open(LOG_FILE, 'rb') do |flog|
flog.seek(log_info[:start])
new_data = flog.read
end
KNOWN_LOG_TYPES = [
# each element is an instance of Array. 1st item: error description, others: text to search log for
['EJAB-1482 Crash when waiting for item',
['wait_for_']],
['EJAB-1483 ODBC sup failure (wrong PID?)',
['ejabberd_odbc_sup']],
['EJAB-1483 ODBC sup wrong PID failure echo',
["mod_pubsub_odbc,'-unsubscribe"]],
['DNS failure',
['You should check your DNS configuration']],
['Database unavailable/too slow',
['Database was not available or too slow']],
['State machine terminated: timeout',
['State machine',
'terminating',
'Reason for',
'timeout']],
['The auth module returned an error',
['The authentication module',
'returned an error']],
['MySQL disconnected',
['mysql',
'Received unknown signal, exiting']],
['Connecting to MySQL: failed',
['mysql',
'Failed connecting to']],
['Timeout while running a hook',
%w[ejabberd_hooks
timeout]],
['SQL transaction restarts exceeded',
['SQL transaction restarts exceeded']],
['Unexpected info',
['nexpected info']],
['Other sql_cmd timeout',
['sql_cmd']],
['System limit hit: ports', # check with length(erlang:ports())., set in ejabberdctl config file
%w[system_limit
open_port]],
['Other system limit hit', # processes? check with erlang:system_info(process_count)., erlang:system_info(process_limit)., set in ejabberdctl cfg
['system_limit']],
['Generic server terminating',
['Generic server',
'terminating']],
['Mnesia table shrinked',
['shrinking table']],
['Admin access failed',
['Access of',
'failed with error']],
['MySQL sock timedout',
['mysql_',
': Socket',
'timedout']],
['Configuration error',
['{badrecord,config}']],
['Strange vCard error (vhost)',
['error found when trying to get the vCard']],
['Mnesia is overloaded',
['Mnesia is overloaded']],
['MySQL: init failed recv data',
['mysql_conn: init failed receiving data']],
['TCP Error',
['Failed TCP']]
].freeze
def log_type(text)
KNOWN_LOG_TYPES.find_index do |entry|
entry[1].all? { |substr| text.include? substr }
end
end
new_data.split("\n=").each do |report|
next if report.empty?
report =~ /\A(\w+) REPORT==== (.*) ===\n(.*)\z/m
type = Regexp.last_match(1)
time = Regexp.last_match(2)
text = Regexp.last_match(3)
next unless type && time && text
log_info[type] = (log_info[type] || 0) + 1
if sub_type = log_type(text)
log_info[sub_type] = (log_info[sub_type] || 0) + 1
elsif $debug_mode
warn "Unparsed log entry #{type}: #{text} at #{time}"
end
end
log_info[:start] += new_data.size
File.open(CACHE_FILE, 'w') { |f| f.write log_info.to_yaml } unless $debug_mode
if ARGV.first == 'config'
puts <<~CONFIG
graph_title Ejabberd Log
graph_vlabel total
graph_category chat
graph_args -l 0
CONFIG
end
(KNOWN_LOG_TYPES + %w[ERROR WARNING INFO DEBUG]).each.with_index do |log_type, index|
label, index = if log_type.is_a? Array
[log_type.first, index]
else
[log_type, log_type]
end
if ARGV.first == 'config'
puts "T#{index}.label #{label}"
puts "T#{index}.draw LINE"
else
puts "T#{index}.value #{log_info[index] or 0}"
end
end