2 * Copyright (c) 2018 Ericsson India Global Services Pvt Ltd. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
8 package org.opendaylight.infrautils.metrics.internal;
10 import com.codahale.metrics.Counter;
11 import com.codahale.metrics.Gauge;
12 import com.codahale.metrics.Histogram;
13 import com.codahale.metrics.Meter;
14 import com.codahale.metrics.Metered;
15 import com.codahale.metrics.MetricFilter;
16 import com.codahale.metrics.MetricRegistry;
17 import com.codahale.metrics.Sampling;
18 import com.codahale.metrics.ScheduledReporter;
19 import com.codahale.metrics.Snapshot;
20 import com.codahale.metrics.Timer;
23 import java.io.FileOutputStream;
24 import java.io.IOException;
25 import java.io.OutputStreamWriter;
26 import java.io.PrintWriter;
27 import java.time.Duration;
28 import java.util.Calendar;
29 import java.util.Date;
30 import java.util.HashMap;
32 import java.util.SortedMap;
33 import java.util.concurrent.TimeUnit;
35 import org.slf4j.Logger;
36 import org.slf4j.LoggerFactory;
38 public class MetricsFileReporter extends ScheduledReporter {
40 private static final Logger LOG = LoggerFactory.getLogger(MetricsFileReporter.class);
42 private static final String DATA_DIRECTORY = "data";
43 private static final String COUNTERS_DIRECTORY = "metrics";
44 private static final String COUNTER_FILE_PREFIX = "metrics.";
45 private static final String DEFAULT_ENCODING = "UTF-8";
46 private static final String SEPARATOR = ",";
48 private final File parentDirectory;
49 private final Map<String, Long> oldCounters = new HashMap<>();
50 private final Duration interval;
52 public MetricsFileReporter(MetricRegistry registry, Duration interval) {
53 super(registry, "file-reporter", MetricFilter.ALL, TimeUnit.SECONDS, TimeUnit.SECONDS);
54 this.parentDirectory = new File(DATA_DIRECTORY, COUNTERS_DIRECTORY);
55 this.interval = interval;
58 public void startReporter() {
59 start(interval.getSeconds(), TimeUnit.SECONDS);
62 Duration getInterval() {
67 public void report(@SuppressWarnings("rawtypes")
68 SortedMap<String, Gauge> gauges,
69 SortedMap<String, Counter> counters,
70 SortedMap<String, Histogram> histograms,
71 SortedMap<String, Meter> meters,
72 SortedMap<String, Timer> timers) {
74 Calendar calendar = Calendar.getInstance();
75 int hourOfTheDay = calendar.get(Calendar.HOUR_OF_DAY);
76 int dayOfTheWeek = calendar.get(Calendar.DAY_OF_WEEK);
77 // retains one week worth of counters
78 rotateLastWeekFile(dayOfTheWeek, hourOfTheDay);
79 boolean append = true;
80 File file = createFile(dayOfTheWeek, hourOfTheDay);
81 PrintWriter pw = new PrintWriter(new OutputStreamWriter(new FileOutputStream(file, append),
87 pw.println("Counters:");
88 for (Map.Entry<String, Counter> entry : counters.entrySet()) {
89 Counter newCounter = entry.getValue();
90 // avoid unnecessary write to report file
91 // report the counter only if there is a change
92 Long oldCounterObj = oldCounters.get(entry.getKey());
93 long oldCounter = oldCounterObj != null ? oldCounterObj.longValue() : 0;
94 if (newCounter.getCount() != oldCounter) {
95 pw.print(entry.getKey());
96 printWithSeparator(pw, "count", entry.getValue().getCount());
97 printWithSeparator(pw, "diff",
98 entry.getValue().getCount() - oldCounter);
102 pw.println("Gauges:");
103 for (@SuppressWarnings("rawtypes") Map.Entry<String, Gauge> entry : gauges.entrySet()) {
104 pw.print(entry.getKey());
105 pw.println(entry.getValue().getValue());
107 pw.println("Histograms:");
108 for (Map.Entry<String, Histogram> entry : histograms.entrySet()) {
109 pw.print(entry.getKey());
110 printWithSeparator(pw, "count", entry.getValue().getCount());
111 printSampling(pw, entry.getValue());
114 pw.println("Meters:");
115 for (Map.Entry<String, Meter> entry : meters.entrySet()) {
116 pw.print(entry.getKey());
117 printMeter(pw, entry.getValue());
119 pw.println("Timers:");
120 for (Map.Entry<String, Timer> entry : timers.entrySet()) {
121 pw.print(entry.getKey());
122 printSampling(pw, entry.getValue());
123 printMeter(pw, entry.getValue());
125 counters.forEach((key, value) -> oldCounters.put(key, value.getCount()));
127 } catch (IOException e) {
128 LOG.error("Failed to report counters to files", e);
132 private static void printSampling(PrintWriter pw, Sampling sampling) {
133 Snapshot snapshot = sampling.getSnapshot();
134 printWithSeparator(pw, "min", snapshot.getMin());
135 printWithSeparator(pw, "max", snapshot.getMax());
136 printWithSeparator(pw, "mean", snapshot.getMean());
139 private static void printMeter(PrintWriter pw, Metered meter) {
140 printWithSeparator(pw, "count", meter.getCount());
141 printWithSeparator(pw, "oneMinuteRate", meter.getOneMinuteRate());
142 printWithSeparator(pw, "fiveMinuteRate", meter.getFiveMinuteRate());
143 printWithSeparator(pw, "fifteenMinuteRate", meter.getFifteenMinuteRate());
147 private static void printWithSeparator(PrintWriter pw, String name, Object val) {
154 private static void printSeparator(PrintWriter pw) {
158 private static String getFileName(int dayOfTheWeek, int hourOfTheDay) {
159 return COUNTER_FILE_PREFIX + dayOfTheWeek + "." + hourOfTheDay;
162 public File createFile(int dayOfTheWeek, int hourOfTheDay) throws IOException {
163 if (!parentDirectory.exists()) {
164 LOG.info("Directory does not exist, creating it: {}", parentDirectory.getName());
165 if (!parentDirectory.mkdirs()) {
166 throw new IOException("Failed to make directories: " + parentDirectory.toString());
169 File file = new File(parentDirectory, getFileName(dayOfTheWeek, hourOfTheDay));
170 if (!file.exists()) {
171 LOG.info("File does not exist, creating it: {}", file.getPath());
172 if (!file.createNewFile()) {
173 throw new IOException("Failed to create file: " + file.toString());
179 private void rotateLastWeekFile(int dayOfTheWeek, int hourOfTheDay) throws IOException {
180 int nextHour = hourOfTheDay < 23 ? hourOfTheDay + 1 : 0;
181 File nextHourFile = new File(parentDirectory , getFileName(dayOfTheWeek, nextHour));
182 if (nextHourFile.exists()) {
183 boolean append = false;
184 PrintWriter pw = new PrintWriter(new OutputStreamWriter(new FileOutputStream(nextHourFile, append),
186 pw.write(new Date().toString());