Author: rombert Date: Tue Aug 22 09:07:03 2017 New Revision: 1805734 URL: http://svn.apache.org/viewvc?rev=1805734&view=rev Log: SLING-7071 - Rename metrics file on configuration change
Submitted-By: Marcel Reutegger Modified: sling/trunk/bundles/commons/metrics-rrd4j/src/main/java/org/apache/sling/commons/metrics/rrd4j/impl/RRD4JReporter.java sling/trunk/bundles/commons/metrics-rrd4j/src/test/java/org/apache/sling/commons/metrics/rrd4j/impl/ReporterTest.java Modified: sling/trunk/bundles/commons/metrics-rrd4j/src/main/java/org/apache/sling/commons/metrics/rrd4j/impl/RRD4JReporter.java URL: http://svn.apache.org/viewvc/sling/trunk/bundles/commons/metrics-rrd4j/src/main/java/org/apache/sling/commons/metrics/rrd4j/impl/RRD4JReporter.java?rev=1805734&r1=1805733&r2=1805734&view=diff ============================================================================== --- sling/trunk/bundles/commons/metrics-rrd4j/src/main/java/org/apache/sling/commons/metrics/rrd4j/impl/RRD4JReporter.java (original) +++ sling/trunk/bundles/commons/metrics-rrd4j/src/main/java/org/apache/sling/commons/metrics/rrd4j/impl/RRD4JReporter.java Tue Aug 22 09:07:03 2017 @@ -36,6 +36,8 @@ import org.slf4j.LoggerFactory; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; @@ -46,10 +48,13 @@ import java.util.SortedMap; import java.util.concurrent.TimeUnit; import static java.lang.String.join; +import static java.nio.file.StandardCopyOption.REPLACE_EXISTING; class RRD4JReporter extends ScheduledReporter { private static final Logger LOGGER = LoggerFactory.getLogger(RRD4JReporter.class); + + private static final String PROPERTIES_SUFFIX = ".properties"; static final int DEFAULT_STEP = 5; private final Map<String, Integer> dictionary = new HashMap<>(); @@ -151,7 +156,7 @@ class RRD4JReporter extends ScheduledRep super(registry, name, filter, rateUnit, durationUnit); this.dictionary.putAll(dictionary); this.rrdDB = createDB(rrdDef); - storeDictionary(rrdDef.getPath() + ".properties"); + storeDictionary(rrdDef.getPath() + PROPERTIES_SUFFIX); } @Override @@ -170,31 +175,37 @@ class RRD4JReporter extends ScheduledRep SortedMap<String, Histogram> histograms, SortedMap<String, Meter> meters, SortedMap<String, Timer> timers) { - + long time = System.nanoTime(); + int total = gauges.size() + counters.size() + histograms.size() + meters.size() + timers.size(); + int reported = 0; try { Sample sample = rrdDB.createSample(System.currentTimeMillis() / 1000); for (Map.Entry<String, Gauge> entry : gauges.entrySet()) { - update(sample, indexForName(entry.getKey()), entry.getValue()); + reported += update(sample, indexForName(entry.getKey()), entry.getValue()); } for (Map.Entry<String, Counter> entry : counters.entrySet()) { - update(sample, indexForName(entry.getKey()), entry.getValue()); + reported += update(sample, indexForName(entry.getKey()), entry.getValue()); } for (Map.Entry<String, Histogram> entry : histograms.entrySet()) { - update(sample, indexForName(entry.getKey()), entry.getValue()); + reported += update(sample, indexForName(entry.getKey()), entry.getValue()); } for (Map.Entry<String, Meter> entry : meters.entrySet()) { - update(sample, indexForName(entry.getKey()), entry.getValue()); + reported += update(sample, indexForName(entry.getKey()), entry.getValue()); } for (Map.Entry<String, Timer> entry : timers.entrySet()) { - update(sample, indexForName(entry.getKey()), entry.getValue()); + reported += update(sample, indexForName(entry.getKey()), entry.getValue()); } sample.update(); } catch (IOException e) { LOGGER.warn("Unable to write sample to RRD", e); + } finally { + time = System.nanoTime() - time; + LOGGER.debug("{} out of {} metrics reported in {} \u03bcs", + reported, total, TimeUnit.NANOSECONDS.toMicros(time)); } } @@ -207,44 +218,49 @@ class RRD4JReporter extends ScheduledRep return name.replaceAll(":", "_"); } - private void update(Sample sample, int nameIdx, Gauge g) { + private int update(Sample sample, int nameIdx, Gauge g) { if (nameIdx < 0) { - return; + return 0; } Object value = g.getValue(); if (value instanceof Number) { sample.setValue(nameIdx, ((Number) value).doubleValue()); + return 1; } + return 0; } - private void update(Sample sample, int nameIdx, Counter c) { + private int update(Sample sample, int nameIdx, Counter c) { if (nameIdx < 0) { - return; + return 0; } sample.setValue(nameIdx, c.getCount()); + return 1; } - private void update(Sample sample, int nameIdx, Histogram h) { + private int update(Sample sample, int nameIdx, Histogram h) { if (nameIdx < 0) { - return; + return 0; } sample.setValue(nameIdx, h.getCount()); + return 1; } - private void update(Sample sample, int nameIdx, Timer t) { + private int update(Sample sample, int nameIdx, Timer t) { if (nameIdx < 0) { - return; + return 0; } sample.setValue(nameIdx, t.getCount()); + return 1; } - private void update(Sample sample, int nameIdx, Meter m) { + private int update(Sample sample, int nameIdx, Meter m) { if (nameIdx < 0) { - return; + return 0; } - LOGGER.debug("Sample: {} = {}", nameIdx, m.getCount()); sample.setValue(nameIdx, m.getCount()); + return 1; } private void storeDictionary(String path) throws IOException { @@ -274,10 +290,9 @@ class RRD4JReporter extends ScheduledRep if (!db.getRrdDef().equals(definition)) { // definition changed -> re-create DB db.close(); - if (!dbFile.delete()) { - throw new IOException("Unable to delete RRD file: " + dbFile.getPath()); - } - LOGGER.warn("Configuration changed, recreating RRD file for metrics: " + dbFile.getPath()); + File renamed = renameDB(dbFile); + LOGGER.info("Configuration changed, renamed existing RRD file to: {}", + renamed.getPath()); db = null; } } @@ -286,4 +301,32 @@ class RRD4JReporter extends ScheduledRep } return db; } + + private File renameDB(File dbFile) throws IOException { + // find a suitable suffix + int idx = 0; + while (new File(dbFile.getPath() + suffix(idx)).exists()) { + idx++; + } + // rename rrd file + rename(dbFile.toPath(), dbFile.getName() + suffix(idx)); + // rename properties file + rename(dbFile.toPath().resolveSibling(dbFile.getName() + PROPERTIES_SUFFIX), + dbFile.getName() + suffix(idx) + PROPERTIES_SUFFIX); + + return new File(dbFile.getParentFile(), dbFile.getName() + suffix(idx)); + } + + private static String suffix(int idx) { + return "." + idx; + } + + private void rename(Path path, String newName) throws IOException { + if (!Files.exists(path)) { + // nothing to rename + return; + } + Path target = path.resolveSibling(newName); + Files.move(path, target, REPLACE_EXISTING); + } } Modified: sling/trunk/bundles/commons/metrics-rrd4j/src/test/java/org/apache/sling/commons/metrics/rrd4j/impl/ReporterTest.java URL: http://svn.apache.org/viewvc/sling/trunk/bundles/commons/metrics-rrd4j/src/test/java/org/apache/sling/commons/metrics/rrd4j/impl/ReporterTest.java?rev=1805734&r1=1805733&r2=1805734&view=diff ============================================================================== --- sling/trunk/bundles/commons/metrics-rrd4j/src/test/java/org/apache/sling/commons/metrics/rrd4j/impl/ReporterTest.java (original) +++ sling/trunk/bundles/commons/metrics-rrd4j/src/test/java/org/apache/sling/commons/metrics/rrd4j/impl/ReporterTest.java Tue Aug 22 09:07:03 2017 @@ -25,19 +25,21 @@ import java.util.Map; import com.codahale.metrics.Gauge; import com.codahale.metrics.MetricRegistry; -import org.apache.sling.commons.metrics.rrd4j.impl.CodahaleMetricsReporter; +import org.apache.sling.testing.mock.osgi.MockOsgi; import org.apache.sling.testing.mock.osgi.junit.OsgiContext; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.rrd4j.core.RrdDb; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; public class ReporterTest { private static final File RRD = new File(new File("target", "metrics"), "metrics.rrd"); + private static final File RRD_0 = new File(new File("target", "metrics"), "metrics.rrd.0"); private static final long TEST_VALUE = 42; @@ -51,13 +53,10 @@ public class ReporterTest { @Before public void before() throws Exception { RRD.delete(); + RRD_0.delete(); context.registerService(MetricRegistry.class, registry, "name", "sling"); - Map<String, Object> properties = new HashMap<>(); - properties.put("step", 1L); - properties.put("datasources", new String[]{"DS:sling_myMetric:GAUGE:300:0:U"}); - properties.put("archives", new String[]{"RRA:AVERAGE:0.5:1:60"}); - properties.put("path", RRD.getPath()); + Map<String, Object> properties = newConfig(); context.registerInjectActivateService(reporter, properties); registry.register("myMetric", new TestGauge(TEST_VALUE)); @@ -81,6 +80,19 @@ public class ReporterTest { fail("RRD4J reporter did not update database in time"); } + @Test + public void reconfigure() throws Exception { + assertFalse(RRD_0.exists()); + MockOsgi.deactivate(reporter, context.bundleContext()); + + // re-activate with changed configuration + Map<String, Object> properties = newConfig(); + properties.put("step", 5L); + MockOsgi.activate(reporter, context.bundleContext(), properties); + + assertTrue(RRD_0.exists()); + } + private static final class TestGauge implements Gauge<Long> { private final long value; @@ -94,4 +106,13 @@ public class ReporterTest { return value; } } + + private static Map<String, Object> newConfig() { + Map<String, Object> properties = new HashMap<>(); + properties.put("step", 1L); + properties.put("datasources", new String[]{"DS:sling_myMetric:GAUGE:300:0:U"}); + properties.put("archives", new String[]{"RRA:AVERAGE:0.5:1:60"}); + properties.put("path", RRD.getPath()); + return properties; + } }