/* Copyright (c) 2011 Danish Maritime Authority. * * 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 net.maritimecloud.mms.server.rest; import com.codahale.metrics.Clock; import com.codahale.metrics.Counter; import com.codahale.metrics.Gauge; import com.codahale.metrics.Histogram; import com.codahale.metrics.Meter; import com.codahale.metrics.MetricRegistry; import com.codahale.metrics.Snapshot; import com.codahale.metrics.Timer; import javax.ws.rs.Produces; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.MultivaluedMap; import javax.ws.rs.ext.MessageBodyWriter; import javax.ws.rs.ext.Provider; import java.io.IOException; import java.io.OutputStream; import java.io.PrintWriter; import java.lang.annotation.Annotation; import java.lang.reflect.Type; import java.text.DateFormat; import java.util.Date; import java.util.Locale; import java.util.Map; import java.util.SortedMap; import java.util.TimeZone; import java.util.concurrent.TimeUnit; /** * MessageBodyWriter implementation for the MetricRegistry class */ @Produces("text/plain") @Provider public class JSONMetricRegistryBodyWriter implements MessageBodyWriter<MetricRegistry> { private static final int CONSOLE_WIDTH = 80; @Override public boolean isWriteable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) { return type == MetricRegistry.class; } @Override public long getSize(MetricRegistry myBean, Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) { return -1; // deprecated by JAX-RS 2.0 and ignored by Jersey runtime } @Override public void writeTo(MetricRegistry registry, Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType, MultivaluedMap<String, Object> httpHeaders, OutputStream entityStream) throws IOException { PrintWriter output = new PrintWriter(entityStream); report(output, registry.getGauges(), registry.getCounters(), registry.getHistograms(), registry.getMeters(), registry.getTimers()); } /** * This method is more or less copied from the ConsoleReporter class. */ @SuppressWarnings("rawtypes") public void report(PrintWriter output, SortedMap<String, Gauge> gauges, SortedMap<String, Counter> counters, SortedMap<String, Histogram> histograms, SortedMap<String, Meter> meters, SortedMap<String, Timer> timers) { Locale locale = Locale.ENGLISH; DateFormat dateFormat = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.MEDIUM, locale); dateFormat.setTimeZone(TimeZone.getDefault()); final String dateTime = dateFormat.format(new Date(Clock.defaultClock().getTime())); printWithBanner(output, dateTime, '='); output.println(); if (!gauges.isEmpty()) { printWithBanner(output, "-- Gauges", '-'); for (Map.Entry<String, Gauge> entry : gauges.entrySet()) { output.println(entry.getKey()); printGauge(output, locale, entry); } output.println(); } if (!counters.isEmpty()) { printWithBanner(output, "-- Counters", '-'); for (Map.Entry<String, Counter> entry : counters.entrySet()) { output.println(entry.getKey()); printCounter(output, locale, entry); } output.println(); } if (!histograms.isEmpty()) { printWithBanner(output, "-- Histograms", '-'); for (Map.Entry<String, Histogram> entry : histograms.entrySet()) { output.println(entry.getKey()); printHistogram(output, locale, entry.getValue()); } output.println(); } if (!meters.isEmpty()) { printWithBanner(output, "-- Meters", '-'); for (Map.Entry<String, Meter> entry : meters.entrySet()) { output.println(entry.getKey()); printMeter(output, locale, entry.getValue()); } output.println(); } if (!timers.isEmpty()) { printWithBanner(output, "-- Timers", '-'); for (Map.Entry<String, Timer> entry : timers.entrySet()) { output.println(entry.getKey()); printTimer(output, locale, entry.getValue()); } output.println(); } output.println(); output.flush(); } private void printMeter(PrintWriter output, Locale locale, Meter meter) { output.printf(locale, " count = %d%n", meter.getCount()); output.printf(locale, " mean rate = %2.2f events/%s%n", convertRate(meter.getMeanRate()), getRateUnit()); output.printf(locale, " 1-minute rate = %2.2f events/%s%n", convertRate(meter.getOneMinuteRate()), getRateUnit()); output.printf(locale, " 5-minute rate = %2.2f events/%s%n", convertRate(meter.getFiveMinuteRate()), getRateUnit()); output.printf(locale, " 15-minute rate = %2.2f events/%s%n", convertRate(meter.getFifteenMinuteRate()), getRateUnit()); } private void printCounter(PrintWriter output, Locale locale, Map.Entry<String, Counter> entry) { output.printf(locale, " count = %d%n", entry.getValue().getCount()); } private void printGauge(PrintWriter output, Locale locale, @SuppressWarnings("rawtypes") Map.Entry<String, Gauge> entry) { output.printf(locale, " value = %s%n", entry.getValue().getValue()); } private void printHistogram(PrintWriter output, Locale locale, Histogram histogram) { output.printf(locale, " count = %d%n", histogram.getCount()); Snapshot snapshot = histogram.getSnapshot(); output.printf(locale, " min = %d%n", snapshot.getMin()); output.printf(locale, " max = %d%n", snapshot.getMax()); output.printf(locale, " mean = %2.2f%n", snapshot.getMean()); output.printf(locale, " stddev = %2.2f%n", snapshot.getStdDev()); output.printf(locale, " median = %2.2f%n", snapshot.getMedian()); output.printf(locale, " 75%% <= %2.2f%n", snapshot.get75thPercentile()); output.printf(locale, " 95%% <= %2.2f%n", snapshot.get95thPercentile()); output.printf(locale, " 98%% <= %2.2f%n", snapshot.get98thPercentile()); output.printf(locale, " 99%% <= %2.2f%n", snapshot.get99thPercentile()); output.printf(locale, " 99.9%% <= %2.2f%n", snapshot.get999thPercentile()); } private void printTimer(PrintWriter output, Locale locale, Timer timer) { final Snapshot snapshot = timer.getSnapshot(); output.printf(locale, " count = %d%n", timer.getCount()); output.printf(locale, " mean rate = %2.2f calls/%s%n", convertRate(timer.getMeanRate()), getRateUnit()); output.printf(locale, " 1-minute rate = %2.2f calls/%s%n", convertRate(timer.getOneMinuteRate()), getRateUnit()); output.printf(locale, " 5-minute rate = %2.2f calls/%s%n", convertRate(timer.getFiveMinuteRate()), getRateUnit()); output.printf(locale, " 15-minute rate = %2.2f calls/%s%n", convertRate(timer.getFifteenMinuteRate()), getRateUnit()); output.printf(locale, " min = %2.2f %s%n", convertDuration(snapshot.getMin()), getDurationUnit()); output.printf(locale, " max = %2.2f %s%n", convertDuration(snapshot.getMax()), getDurationUnit()); output.printf(locale, " mean = %2.2f %s%n", convertDuration(snapshot.getMean()), getDurationUnit()); output.printf(locale, " stddev = %2.2f %s%n", convertDuration(snapshot.getStdDev()), getDurationUnit()); output.printf(locale, " median = %2.2f %s%n", convertDuration(snapshot.getMedian()), getDurationUnit()); output.printf(locale, " 75%% <= %2.2f %s%n", convertDuration(snapshot.get75thPercentile()), getDurationUnit()); output.printf(locale, " 95%% <= %2.2f %s%n", convertDuration(snapshot.get95thPercentile()), getDurationUnit()); output.printf(locale, " 98%% <= %2.2f %s%n", convertDuration(snapshot.get98thPercentile()), getDurationUnit()); output.printf(locale, " 99%% <= %2.2f %s%n", convertDuration(snapshot.get99thPercentile()), getDurationUnit()); output.printf(locale, " 99.9%% <= %2.2f %s%n", convertDuration(snapshot.get999thPercentile()), getDurationUnit()); } private void printWithBanner(PrintWriter output, String s, char c) { output.print(s); output.print(' '); for (int i = 0; i < (CONSOLE_WIDTH - s.length() - 1); i++) { output.print(c); } output.println(); } protected String getRateUnit() { return calculateRateUnit(TimeUnit.SECONDS); } protected String getDurationUnit() { return TimeUnit.MILLISECONDS.toString().toLowerCase(Locale.US); } protected double convertDuration(double duration) { return duration * 1.0 / TimeUnit.MILLISECONDS.toNanos(1); } protected double convertRate(double rate) { return rate * TimeUnit.SECONDS.toSeconds(1); } private String calculateRateUnit(TimeUnit unit) { final String s = unit.toString().toLowerCase(Locale.US); return s.substring(0, s.length() - 1); } }