#!/usr/bin/ruby
OUTDIR = "/var/www/html/rrd"
RRD = "#{OUTDIR}/wis.rrd"
THR_FILE = "#{OUTDIR}/wis-thr.txt"
START = "-604800" # 7日
END_T = "now"
UPPER_LIMIT = 500.0
MARGIN = 1.1
$VERBOSE=true if STDERR.tty?
# ----------------------------
# 閾値読み込み
# ----------------------------
t_wnm, t_top, t_brw = File.read(THR_FILE).split.map(&:to_f)
# ----------------------------
# RRD fetch
# ----------------------------
raw = `rrdtool fetch #{RRD} AVERAGE --start #{START} --end #{END_T}`
data = []
raw.each_line do |line|
next unless line =~ /^\d+:/
ts, wnm, top, brw = line.split
next if wnm == "nan"
data << [ts.to_i, wnm.to_f, top.to_f, brw.to_f]
end
# ----------------------------
# kaku kenti script ga izyou ti to suru atai
# ----------------------------
def is_syserr val
val > 500.0
end
# ----------------------------
# 単発スパイク検出
# ----------------------------
def detect_spikes(series, threshold)
spikes = []
(1...(series.size - 1)).each do |i|
prev = series[i - 1]
curr = series[i]
nxt = series[i + 1]
if is_syserr(curr)
warn "syserr #{curr} excluded from spike-detecting"
next
end
if curr > threshold && prev <= threshold && nxt <= threshold
spikes << curr
end
end
spikes
end
wnm_series = data.map { |r| r[1] }
top_series = data.map { |r| r[2] }
brw_series = data.map { |r| r[3] }
wnm_spikes = detect_spikes(wnm_series, t_wnm)
top_spikes = detect_spikes(top_series, t_top)
brw_spikes = detect_spikes(brw_series, t_brw)
# ----------------------------
# 新しい閾値計算
# ----------------------------
def calc_new_threshold(spikes, current)
return current if spikes.empty?
max = spikes.max
new_val = max * MARGIN
# 上限適用
new_val = UPPER_LIMIT if new_val > UPPER_LIMIT
new_val
end
new_wnm = calc_new_threshold(wnm_spikes, t_wnm)
new_top = calc_new_threshold(top_spikes, t_top)
new_brw = calc_new_threshold(brw_spikes, t_brw)
updated =
(new_wnm != t_wnm) ||
(new_top != t_top) ||
(new_brw != t_brw)
fmsg=''
# ----------------------------
# 書き込み
# ----------------------------
begin
if updated then
File.write(
THR_FILE,
format("%.1f %.1f %.1f\n", new_wnm, new_top, new_brw)
)
end
rescue Errno::EACCES => e
fmsg=e.to_s
end
# ----------------------------
# ログ出力
# ----------------------------
subject =
if !fmsg.empty?
"[Error]WIS Monitor"
elsif updated
"[Adjusted]WIS Monitor"
else
"[NoChange]WIS Monitor"
end
open("|/usr/sbin/sendmail -t","wt"){|mail|
mail.puts "Subject: #{subject}\r"
mail.puts "To: news\r"
mail.puts "\r"
if updated
mail.puts "Thresholds were updated."
else
mail.puts "No threshold update was required."
mail.puts "No single-point spikes exceeding the current thresholds were found in the past 7 days."
end
mail.puts ""
mail.puts "---- Threshold Update ----"
mail.puts "WNM: #{t_wnm} -> #{new_wnm} (spikes=#{wnm_spikes.size})"
mail.puts "TOP: #{t_top} -> #{new_top} (spikes=#{top_spikes.size})"
mail.puts "BRW: #{t_brw} -> #{new_brw} (spikes=#{brw_spikes.size})"
mail.puts "WNM spikes: count=#{wnm_spikes.size} max=#{wnm_spikes.max || '-'}"
mail.puts "TOP spikes: count=#{top_spikes.size} max=#{top_spikes.max || '-'}"
mail.puts "BRW spikes: count=#{brw_spikes.size} max=#{brw_spikes.max || '-'}"
mail.puts "Upper limit applied: #{UPPER_LIMIT}"
unless fmsg.empty?
mail.puts ""
mail.puts fmsg
end
}