/* * Copyright 2011 Future Systems * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.krakenapps.snmpmon; import java.io.File; import java.io.IOException; import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Properties; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import org.apache.felix.ipojo.annotations.Component; import org.apache.felix.ipojo.annotations.Invalidate; import org.apache.felix.ipojo.annotations.Requires; import org.apache.felix.ipojo.annotations.Validate; import org.krakenapps.log.api.Log; import org.krakenapps.log.api.LogPipe; import org.krakenapps.log.api.Logger; import org.krakenapps.log.api.LoggerFactory; import org.krakenapps.log.api.LoggerFactoryEventListener; import org.krakenapps.log.api.LoggerFactoryRegistry; import org.krakenapps.rrd.CompactRrd; import org.krakenapps.rrd.ConsolidateFunc; import org.krakenapps.rrd.DataSourceConfig; import org.krakenapps.rrd.DataSourceType; import org.krakenapps.rrd.Rrd; import org.krakenapps.rrd.RrdConfig; import org.krakenapps.rrd.io.FilePersistentLayer; @Component(name = "snmpmon-rrd-updater") public class RrdUpdater implements LogPipe, LoggerFactoryEventListener { private org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(RrdUpdater.class); @Requires private LoggerFactoryRegistry factoryRegistry; private LoggerFactory factory; private File rootDir; private boolean run = true; private ConcurrentMap<String, Rrd> rrds; private ConcurrentMap<String, Cache> cache; @Validate public void validate() { factory = factoryRegistry.getLoggerFactory("snmpmon"); factory.addListener(this); rootDir = new File(System.getProperty("kraken.data.dir"), "kraken-snmpmon/rrd/"); rootDir.mkdirs(); rrds = new ConcurrentHashMap<String, Rrd>(); cache = new ConcurrentHashMap<String, Cache>(); } @Invalidate public void invalidate() { run = false; factory.removeListener(this); rrds.clear(); cache.clear(); } @Override public void loggerCreated(LoggerFactory factory, Logger logger, Properties config) { logger.addLogPipe(this); } @Override public void loggerDeleted(LoggerFactory factory, Logger logger) { logger.removeLogPipe(this); File file = new File(rootDir, logger.getFullName().replace("\\", "$") + ".rrd"); if (file.exists()) file.delete(); } @SuppressWarnings("unchecked") @Override public void onLog(Logger logger, Log log) { if (!run || !logger.getFactoryFullName().equals(factory.getFullName())) return; Map<String, Object> data = new HashMap<String, Object>(log.getParams()); data.remove("_total"); data.remove("msg"); if (!"network-usage".equals(data.remove("logtype"))) return; String[] columns = { "rx_bytes_delta", "tx_bytes_delta", "rx_discards_delta", "tx_discards_delta", "rx_errors_delta", "tx_errors_delta", "rx_ucast_pkts_delta", "tx_ucast_pkts_delta" }; try { Cache cache = this.cache.get(logger.getFullName()); if (cache == null) { cache = new Cache(); this.cache.put(logger.getFullName(), cache); } for (String key : data.keySet()) { try { Map<String, Object> value = (Map<String, Object>) data.get(key); for (String column : columns) { String cacheKey = key + ":" + column; double v = cache.delta.containsKey(cacheKey) ? cache.delta.get(cacheKey) : 0; try { v += ((Long) value.get(column)).doubleValue() / 60.0; cache.delta.put(cacheKey, v); } catch (ClassCastException e) { } catch (NullPointerException e) { } } } catch (ClassCastException e) { } } if (cache.beforeWrite.before(new Date(System.currentTimeMillis() - 60000))) { Rrd rrd = rrds.get(logger.getFullName()); if (rrd == null) { File file = new File(rootDir, logger.getFullName().replace("\\", "$") + ".rrd"); RrdConfig config = null; if (!file.exists()) { config = new RrdConfig(log.getDate(), 60); for (String key : data.keySet()) { for (String column : columns) config.addDataSource(key + ":" + column, DataSourceType.GAUGE, 120, Double.MIN_VALUE, Double.MAX_VALUE); } config.addArchive(ConsolidateFunc.AVERAGE, 0.5, 1, 360); // 6h / 1min config.addArchive(ConsolidateFunc.AVERAGE, 0.5, 5, 288); // Daily / 5min config.addArchive(ConsolidateFunc.AVERAGE, 0.5, 30, 336); // Weekly / 30min config.addArchive(ConsolidateFunc.AVERAGE, 0.5, 120, 360); // Monthly / 2h config.addArchive(ConsolidateFunc.AVERAGE, 0.5, 1440, 365); // Yearly / 1d } rrd = new CompactRrd(new FilePersistentLayer(file, 512 * 1024), config); rrds.put(logger.getFullName(), rrd); } Set<String> exist = new HashSet<String>(); for (DataSourceConfig ds : rrd.getDataSources()) exist.add(ds.getName().substring(0, ds.getName().indexOf(':'))); for (String key : data.keySet()) { if (!exist.contains(key)) { for (String column : columns) rrd.addDataSource(key + ":" + column, DataSourceType.GAUGE, 120, Double.MIN_VALUE, Double.MAX_VALUE); } } for (String key : exist) { if (!data.keySet().contains(key)) { for (String column : columns) rrd.removeDataSource(key + ":" + column); } } rrd.update(log.getDate(), cache.delta); cache.beforeWrite = new Date(); cache.delta.clear(); } } catch (IOException e) { this.logger.error("kraken snmpmon: io exception", e); } } private class Cache { private Date beforeWrite = new Date(); private Map<String, Double> delta = new HashMap<String, Double>(); } }