All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.opendaylight.serviceutils.metrics.internal.MetricsFileReporter Maven / Gradle / Ivy

/*
 * Copyright (c) 2018 Ericsson India Global Services Pvt Ltd. and others.  All rights reserved.
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
 * and is available at http://www.eclipse.org/legal/epl-v10.html
 */
package org.opendaylight.serviceutils.metrics.internal;

import com.codahale.metrics.Counter;
import com.codahale.metrics.Gauge;
import com.codahale.metrics.Histogram;
import com.codahale.metrics.Meter;
import com.codahale.metrics.Metered;
import com.codahale.metrics.MetricFilter;
import com.codahale.metrics.MetricRegistry;
import com.codahale.metrics.Sampling;
import com.codahale.metrics.ScheduledReporter;
import com.codahale.metrics.Snapshot;
import com.codahale.metrics.Timer;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.time.Duration;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.SortedMap;
import java.util.concurrent.TimeUnit;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class MetricsFileReporter extends ScheduledReporter {

    private static final Logger LOG = LoggerFactory.getLogger(MetricsFileReporter.class);

    private static final String DATA_DIRECTORY = "data";
    private static final String COUNTERS_DIRECTORY = "metrics";
    private static final String COUNTER_FILE_PREFIX = "metrics.";
    private static final Charset DEFAULT_ENCODING = StandardCharsets.UTF_8;
    private static final String SEPARATOR = ",";

    private final File parentDirectory;
    private final Map oldCounters = new HashMap<>();
    private final MetricRegistry registry;
    private final Duration interval;

    public MetricsFileReporter(MetricRegistry registry, Duration interval) {
        super(registry, "file-reporter", MetricFilter.ALL, TimeUnit.SECONDS, TimeUnit.SECONDS);
        this.parentDirectory = new File(DATA_DIRECTORY, COUNTERS_DIRECTORY);
        this.registry = registry;
        this.interval = interval;
    }

    public void startReporter() {
        start(interval.getSeconds(), TimeUnit.SECONDS);
    }

    Duration getInterval() {
        return interval;
    }

    public void report(PrintWriter pw) {
        report(pw, registry.getGauges(), registry.getCounters(),
                registry.getHistograms(), registry.getMeters(), registry.getTimers());
    }

    private void report(PrintWriter pw, @SuppressWarnings("rawtypes") SortedMap gauges,
            SortedMap counters, SortedMap histograms,
            SortedMap meters, SortedMap timers) {
        pw.print("date,");
        pw.print(new Date());
        pw.println();

        pw.println("Counters:");
        for (Map.Entry entry : counters.entrySet()) {
            Counter newCounter = entry.getValue();
            // avoid unnecessary write to report file
            // report the counter only if there is a change
            Long oldCounterObj = oldCounters.get(entry.getKey());
            long oldCounter = oldCounterObj != null ? oldCounterObj.longValue() : 0;
            if (newCounter.getCount() != oldCounter) {
                pw.print(entry.getKey());
                printWithSeparator(pw, "count", entry.getValue().getCount());
                printWithSeparator(pw, "diff",
                        entry.getValue().getCount() - oldCounter);
                pw.println();
            }
        }
        pw.println("Gauges:");
        for (@SuppressWarnings("rawtypes") Map.Entry entry : gauges.entrySet()) {
            pw.print(entry.getKey());
            pw.println(entry.getValue().getValue());
        }
        pw.println("Histograms:");
        for (Map.Entry entry : histograms.entrySet()) {
            pw.print(entry.getKey());
            printWithSeparator(pw, "count", entry.getValue().getCount());
            printSampling(pw, entry.getValue());
            pw.println();
        }
        pw.println("Meters:");
        for (Map.Entry entry : meters.entrySet()) {
            pw.print(entry.getKey());
            printMeter(pw, entry.getValue());
        }
        pw.println("Timers:");
        for (Map.Entry entry : timers.entrySet()) {
            pw.print(entry.getKey());
            printSampling(pw, entry.getValue());
            printMeter(pw, entry.getValue());
        }
        counters.forEach((key, value) -> oldCounters.put(key, value.getCount()));
    }

    @Override
    public void report(@SuppressWarnings("rawtypes")
                       SortedMap gauges,
                       SortedMap counters,
                       SortedMap histograms,
                       SortedMap meters,
                       SortedMap timers) {
        try {
            Calendar calendar = Calendar.getInstance();
            int hourOfTheDay = calendar.get(Calendar.HOUR_OF_DAY);
            int dayOfTheWeek = calendar.get(Calendar.DAY_OF_WEEK);
            // retains one week worth of counters
            rotateLastWeekFile(dayOfTheWeek, hourOfTheDay);
            boolean append = true;
            File file = createFile(dayOfTheWeek, hourOfTheDay);
            PrintWriter pw = new PrintWriter(new OutputStreamWriter(new FileOutputStream(file, append),
                    DEFAULT_ENCODING));
            report(pw, gauges, counters, histograms, meters, timers);
            pw.close();
        } catch (IOException e) {
            LOG.error("Failed to report counters to files", e);
        }
    }

    private static void printSampling(PrintWriter pw, Sampling sampling) {
        Snapshot snapshot = sampling.getSnapshot();
        printWithSeparator(pw, "min", snapshot.getMin());
        printWithSeparator(pw, "max", snapshot.getMax());
        printWithSeparator(pw, "mean", snapshot.getMean());
    }

    private static void printMeter(PrintWriter pw, Metered meter) {
        printWithSeparator(pw, "count", meter.getCount());
        printWithSeparator(pw, "oneMinuteRate", meter.getOneMinuteRate());
        printWithSeparator(pw, "fiveMinuteRate", meter.getFiveMinuteRate());
        printWithSeparator(pw, "fifteenMinuteRate", meter.getFifteenMinuteRate());
        pw.println();
    }

    private static void printWithSeparator(PrintWriter pw, String name, Object val) {
        printSeparator(pw);
        pw.print(name);
        printSeparator(pw);
        pw.print(val);
    }

    private static void printSeparator(PrintWriter pw) {
        pw.print(SEPARATOR);
    }

    private static String getFileName(int dayOfTheWeek, int hourOfTheDay) {
        return COUNTER_FILE_PREFIX + dayOfTheWeek + "." + hourOfTheDay;
    }

    public File createFile(int dayOfTheWeek, int hourOfTheDay) throws IOException {
        if (!parentDirectory.exists()) {
            LOG.info("Directory does not exist, creating it: {}", parentDirectory.getName());
            if (!parentDirectory.mkdirs()) {
                throw new IOException("Failed to make directories: " + parentDirectory.toString());
            }
        }
        File file = new File(parentDirectory, getFileName(dayOfTheWeek, hourOfTheDay));
        if (!file.exists()) {
            LOG.info("File does not exist, creating it: {}", file.getPath());
            if (!file.createNewFile()) {
                throw new IOException("Failed to create file: " + file.toString());
            }
        }
        return file;
    }

    private void rotateLastWeekFile(int dayOfTheWeek, int hourOfTheDay) throws IOException {
        int nextHour = hourOfTheDay < 23 ? hourOfTheDay + 1 : 0;
        File nextHourFile = new File(parentDirectory , getFileName(dayOfTheWeek, nextHour));
        if (nextHourFile.exists()) {
            boolean append = false;
            PrintWriter pw = new PrintWriter(new OutputStreamWriter(new FileOutputStream(nextHourFile, append),
                    DEFAULT_ENCODING));
            pw.write(new Date().toString());
            pw.close();
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy