You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by ro...@apache.org on 2017/08/22 09:07:03 UTC

svn commit: r1805734 - in /sling/trunk/bundles/commons/metrics-rrd4j/src: main/java/org/apache/sling/commons/metrics/rrd4j/impl/RRD4JReporter.java test/java/org/apache/sling/commons/metrics/rrd4j/impl/ReporterTest.java

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;
+    }
 }