#!/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 # ---------------------------- # 閾値読み込み # ---------------------------- 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 # ---------------------------- # 単発スパイク検出 # ---------------------------- 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 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) fmsg='' # ---------------------------- # 書き込み # ---------------------------- begin File.write( THR_FILE, format("%.1f %.1f %.1f\n", new_wnm, new_top, new_brw) ) rescue Errno::EACCES => e fmsg=e.to_s end # ---------------------------- # ログ出力 # ---------------------------- open("|/usr/sbin/sendmail -t","wt"){|mail| mail.puts "Subject: [Adjusted]WIS Monitor\r" mail.puts "To: news\r" mail.puts "\r" 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 "Upper limit applied: #{UPPER_LIMIT}" unless fmsg.empty? mail.puts "" mail.puts fmsg end }