Created
July 30, 2018 17:05
-
-
Save Quintus/e1439c54c64fa23b56a7c050e1e7b60d to your computer and use it in GitHub Desktop.
Munin plugin for analysing xferlog (e.g. by vsftpd)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/ruby | |
LOGFILE = ENV["LOGFILE"] || "/var/log/vsftpd.log" | |
STATEFILE = ENV["STATEFILE"] || "#{ENV["MUNIN_PLUGSTATE"]}/munin-xferlog.state" | |
ROTLOGFILE = "#{LOGFILE}.1" | |
LOGFILE.freeze | |
STATEFILE.freeze | |
ROTLOGFILE.freeze | |
$asciitransfers = 0 | |
$bintransfers = 0 | |
def usage | |
puts "Usage: $0 [config]" | |
puts "This munin plugin monitors the FTP transfers over time." | |
end | |
def parse_logfile(filename, start, fin) | |
File.open(filename, "rb") do |file| | |
file.seek(start) | |
# It is guaranteed that fin is never beyond EOF. | |
# It can be equal to EOF, but that's okay. But | |
# if data has been written to the file while this | |
# programme is running, it will be smaller than EOF. | |
while file.tell < fin | |
line = file.gets.chomp.split(/\s+/) | |
if line[9] == "a" | |
$asciitransfers += line[7].to_i | |
elsif line[9] == "b" | |
$bintransfers += line[7].to_i | |
end | |
end | |
end | |
end | |
def get_values | |
# If the logfile is not there, indicate failure to munin. | |
unless File.exist?(LOGFILE) | |
puts "xferlog_ascii.value U" | |
puts "xferlog_binary.value U" | |
exit 2 | |
end | |
# Read values from last run | |
pos = nil | |
if File.exist?(STATEFILE) | |
str = File.read(STATEFILE) | |
pos, $asciitransfers, $bintransfers = str.split(":").map(&:to_i) | |
else | |
# Initial run, start at zero | |
$asciitransfers = 0 | |
$bintransfers = 0 | |
end | |
# Determine size of logfile | |
logsize = File.size(LOGFILE) | |
# If pos is not set, the statefile did not exist, | |
# i.e. this is the first run of the plugin. Use | |
# the current logfile size as the starting point | |
# (makes the first run a no-op). | |
pos = logsize unless pos | |
# If the size of the logfile is smaller than the | |
# last handled position, the log has been rotated. | |
# Process the rotated logfile prior to the current | |
# logfile, if that file exists. | |
if logsize < pos | |
if File.exist?(ROTLOGFILE) | |
parse_logfile ROTLOGFILE, pos, File.size(ROTLOGFILE) | |
end | |
# Process the current logfile from the beginning again. | |
pos = 0 | |
end | |
# Now parse the current logfile (use determined logsize | |
# to ignore data written to the logfile while this programme | |
# is running). | |
parse_logfile LOGFILE, pos, logsize | |
pos = logsize | |
# Tell munin | |
puts "xferlog_ascii.value #$asciitransfers" | |
puts "xferlog_binary.value #$bintransfers" | |
# Remember where we left off | |
File.open(STATEFILE, "w") do |f| | |
f.write("#{pos}:#$asciitransfers:#$bintransfers") | |
end | |
end | |
case ARGV.count | |
when 0 | |
get_values | |
when 1 | |
if ARGV.first == "config" | |
puts "graph_title FTP Transfers" | |
puts "graph_category network" | |
puts "graph_args --base 1000 -l 0" | |
puts "graph_vlabel Bytes/\${graph_period}" | |
puts "xferlog_ascii.label ASCII Transfers" | |
puts "xferlog_ascii.type DERIVE" | |
puts "xferlog_ascii.draw AREA" | |
puts "xferlog_ascii.min 0" | |
puts "xferlog_binary.label Binary Transfers" | |
puts "xferlog_binary.type DERIVE" | |
puts "xferlog_binary.draw STACK" | |
puts "xferlog_binary.min 0" | |
else | |
usage | |
exit 1 | |
end | |
else | |
usage | |
exit 1 | |
end | |
exit 0 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment