WANG 6 anni fa
parent
commit
5d52146c44

+ 28 - 0
src/main/java/cn/com/qmth/examcloud/web/actuator/ApiStatusEndpoint.java

@@ -0,0 +1,28 @@
+package cn.com.qmth.examcloud.web.actuator;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
+import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * 接口状态
+ *
+ * @author WANGWEI
+ * @date 2019年7月25日
+ * @Copyright (c) 2018-? http://qmth.com.cn All Rights Reserved.
+ */
+@Configuration
+@Endpoint(id = "api-status")
+public class ApiStatusEndpoint {
+
+	@ReadOperation(produces = "application/json")
+	public Map<String, Object> endpoint() {
+		Map<String, Object> map = new HashMap<>(16);
+		map.put("message", "this is my endpoint");
+		return map;
+	}
+
+}

+ 423 - 0
src/main/java/cn/com/qmth/examcloud/web/actuator/ApiStatusReportor.java

@@ -0,0 +1,423 @@
+package cn.com.qmth.examcloud.web.actuator;
+
+import java.io.PrintStream;
+import java.text.DateFormat;
+import java.util.Collections;
+import java.util.Date;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
+import java.util.SortedMap;
+import java.util.TimeZone;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
+
+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.MetricAttribute;
+import com.codahale.metrics.MetricFilter;
+import com.codahale.metrics.MetricRegistry;
+import com.codahale.metrics.ScheduledReporter;
+import com.codahale.metrics.Snapshot;
+import com.codahale.metrics.Timer;
+
+/**
+ * A reporter which outputs measurements to a {@link PrintStream}, like
+ * {@code System.out}.
+ */
+public class ApiStatusReportor extends ScheduledReporter {
+	/**
+	 * Returns a new {@link Builder} for {@link ApiStatusReportor}.
+	 *
+	 * @param registry
+	 *            the registry to report
+	 * @return a {@link Builder} instance for a {@link ApiStatusReportor}
+	 */
+	public static Builder forRegistry(MetricRegistry registry) {
+		return new Builder(registry);
+	}
+
+	/**
+	 * A builder for {@link ApiStatusReportor} instances. Defaults to using the
+	 * default locale and time zone, writing to {@code System.out}, converting
+	 * rates to events/second, converting durations to milliseconds, and not
+	 * filtering metrics.
+	 */
+	public static class Builder {
+		private final MetricRegistry registry;
+
+		private PrintStream output;
+
+		private Locale locale;
+
+		private Clock clock;
+
+		private TimeZone timeZone;
+
+		private TimeUnit rateUnit;
+
+		private TimeUnit durationUnit;
+
+		private MetricFilter filter;
+
+		private ScheduledExecutorService executor;
+
+		private boolean shutdownExecutorOnStop;
+
+		private Set<MetricAttribute> disabledMetricAttributes;
+
+		private Builder(MetricRegistry registry) {
+			this.registry = registry;
+			this.output = System.out;
+			this.locale = Locale.getDefault();
+			this.clock = Clock.defaultClock();
+			this.timeZone = TimeZone.getDefault();
+			this.rateUnit = TimeUnit.SECONDS;
+			this.durationUnit = TimeUnit.MILLISECONDS;
+			this.filter = MetricFilter.ALL;
+			this.executor = null;
+			this.shutdownExecutorOnStop = true;
+			disabledMetricAttributes = Collections.emptySet();
+		}
+
+		/**
+		 * Specifies whether or not, the executor (used for reporting) will be
+		 * stopped with same time with reporter. Default value is true. Setting
+		 * this parameter to false, has the sense in combining with providing
+		 * external managed executor via
+		 * {@link #scheduleOn(ScheduledExecutorService)}.
+		 *
+		 * @param shutdownExecutorOnStop
+		 *            if true, then executor will be stopped in same time with
+		 *            this reporter
+		 * @return {@code this}
+		 */
+		public Builder shutdownExecutorOnStop(boolean shutdownExecutorOnStop) {
+			this.shutdownExecutorOnStop = shutdownExecutorOnStop;
+			return this;
+		}
+
+		/**
+		 * Specifies the executor to use while scheduling reporting of metrics.
+		 * Default value is null. Null value leads to executor will be auto
+		 * created on start.
+		 *
+		 * @param executor
+		 *            the executor to use while scheduling reporting of metrics.
+		 * @return {@code this}
+		 */
+		public Builder scheduleOn(ScheduledExecutorService executor) {
+			this.executor = executor;
+			return this;
+		}
+
+		/**
+		 * Write to the given {@link PrintStream}.
+		 *
+		 * @param output
+		 *            a {@link PrintStream} instance.
+		 * @return {@code this}
+		 */
+		public Builder outputTo(PrintStream output) {
+			this.output = output;
+			return this;
+		}
+
+		/**
+		 * Format numbers for the given {@link Locale}.
+		 *
+		 * @param locale
+		 *            a {@link Locale}
+		 * @return {@code this}
+		 */
+		public Builder formattedFor(Locale locale) {
+			this.locale = locale;
+			return this;
+		}
+
+		/**
+		 * Use the given {@link Clock} instance for the time.
+		 *
+		 * @param clock
+		 *            a {@link Clock} instance
+		 * @return {@code this}
+		 */
+		public Builder withClock(Clock clock) {
+			this.clock = clock;
+			return this;
+		}
+
+		/**
+		 * Use the given {@link TimeZone} for the time.
+		 *
+		 * @param timeZone
+		 *            a {@link TimeZone}
+		 * @return {@code this}
+		 */
+		public Builder formattedFor(TimeZone timeZone) {
+			this.timeZone = timeZone;
+			return this;
+		}
+
+		/**
+		 * Convert rates to the given time unit.
+		 *
+		 * @param rateUnit
+		 *            a unit of time
+		 * @return {@code this}
+		 */
+		public Builder convertRatesTo(TimeUnit rateUnit) {
+			this.rateUnit = rateUnit;
+			return this;
+		}
+
+		/**
+		 * Convert durations to the given time unit.
+		 *
+		 * @param durationUnit
+		 *            a unit of time
+		 * @return {@code this}
+		 */
+		public Builder convertDurationsTo(TimeUnit durationUnit) {
+			this.durationUnit = durationUnit;
+			return this;
+		}
+
+		/**
+		 * Only report metrics which match the given filter.
+		 *
+		 * @param filter
+		 *            a {@link MetricFilter}
+		 * @return {@code this}
+		 */
+		public Builder filter(MetricFilter filter) {
+			this.filter = filter;
+			return this;
+		}
+
+		/**
+		 * Don't report the passed metric attributes for all metrics (e.g.
+		 * "p999", "stddev" or "m15"). See {@link MetricAttribute}.
+		 *
+		 * @param disabledMetricAttributes
+		 *            a {@link MetricFilter}
+		 * @return {@code this}
+		 */
+		public Builder disabledMetricAttributes(Set<MetricAttribute> disabledMetricAttributes) {
+			this.disabledMetricAttributes = disabledMetricAttributes;
+			return this;
+		}
+
+		/**
+		 * Builds a {@link ApiStatusReportor} with the given properties.
+		 *
+		 * @return a {@link ApiStatusReportor}
+		 */
+		public ApiStatusReportor build() {
+			return new ApiStatusReportor(registry, output, locale, clock, timeZone, rateUnit,
+					durationUnit, filter, executor, shutdownExecutorOnStop,
+					disabledMetricAttributes);
+		}
+	}
+
+	private static final int CONSOLE_WIDTH = 80;
+
+	private final PrintStream output;
+
+	private final Locale locale;
+
+	private final Clock clock;
+
+	private final DateFormat dateFormat;
+
+	private ApiStatusReportor(MetricRegistry registry, PrintStream output, Locale locale,
+			Clock clock, TimeZone timeZone, TimeUnit rateUnit, TimeUnit durationUnit,
+			MetricFilter filter, ScheduledExecutorService executor, boolean shutdownExecutorOnStop,
+			Set<MetricAttribute> disabledMetricAttributes) {
+		super(registry, "console-reporter", filter, rateUnit, durationUnit, executor,
+				shutdownExecutorOnStop, disabledMetricAttributes);
+		this.output = output;
+		this.locale = locale;
+		this.clock = clock;
+		this.dateFormat = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.MEDIUM,
+				locale);
+		dateFormat.setTimeZone(timeZone);
+	}
+
+	@Override
+	@SuppressWarnings("rawtypes")
+	public void report(SortedMap<String, Gauge> gauges, SortedMap<String, Counter> counters,
+			SortedMap<String, Histogram> histograms, SortedMap<String, Meter> meters,
+			SortedMap<String, Timer> timers) {
+		final String dateTime = dateFormat.format(new Date(clock.getTime()));
+		printWithBanner(dateTime, '=');
+		output.println();
+
+		if (!gauges.isEmpty()) {
+			printWithBanner("-- Gauges", '-');
+			for (Map.Entry<String, Gauge> entry : gauges.entrySet()) {
+				output.println(entry.getKey());
+				printGauge(entry.getValue());
+			}
+			output.println();
+		}
+
+		if (!counters.isEmpty()) {
+			printWithBanner("-- Counters", '-');
+			for (Map.Entry<String, Counter> entry : counters.entrySet()) {
+				output.println(entry.getKey());
+				printCounter(entry);
+			}
+			output.println();
+		}
+
+		if (!histograms.isEmpty()) {
+			printWithBanner("-- Histograms", '-');
+			for (Map.Entry<String, Histogram> entry : histograms.entrySet()) {
+				output.println(entry.getKey());
+				printHistogram(entry.getValue());
+			}
+			output.println();
+		}
+
+		if (!meters.isEmpty()) {
+			printWithBanner("-- Meters", '-');
+			for (Map.Entry<String, Meter> entry : meters.entrySet()) {
+				output.println(entry.getKey());
+				printMeter(entry.getValue());
+			}
+			output.println();
+		}
+
+		if (!timers.isEmpty()) {
+			printWithBanner("-- Timers", '-');
+			for (Map.Entry<String, Timer> entry : timers.entrySet()) {
+				output.println(entry.getKey());
+				printTimer(entry.getValue());
+			}
+			output.println();
+		}
+
+		output.println();
+		output.flush();
+	}
+
+	private void printMeter(Meter meter) {
+		printIfEnabled(MetricAttribute.COUNT,
+				String.format(locale, "             count = %d", meter.getCount()));
+		printIfEnabled(MetricAttribute.MEAN_RATE,
+				String.format(locale, "         mean rate = %2.2f events/%s",
+						convertRate(meter.getMeanRate()), getRateUnit()));
+		printIfEnabled(MetricAttribute.M1_RATE,
+				String.format(locale, "     1-minute rate = %2.2f events/%s",
+						convertRate(meter.getOneMinuteRate()), getRateUnit()));
+		printIfEnabled(MetricAttribute.M5_RATE,
+				String.format(locale, "     5-minute rate = %2.2f events/%s",
+						convertRate(meter.getFiveMinuteRate()), getRateUnit()));
+		printIfEnabled(MetricAttribute.M15_RATE,
+				String.format(locale, "    15-minute rate = %2.2f events/%s",
+						convertRate(meter.getFifteenMinuteRate()), getRateUnit()));
+	}
+
+	private void printCounter(Map.Entry<String, Counter> entry) {
+		output.printf(locale, "             count = %d%n", entry.getValue().getCount());
+	}
+
+	private void printGauge(Gauge<?> gauge) {
+		output.printf(locale, "             value = %s%n", gauge.getValue());
+	}
+
+	private void printHistogram(Histogram histogram) {
+		printIfEnabled(MetricAttribute.COUNT,
+				String.format(locale, "             count = %d", histogram.getCount()));
+		Snapshot snapshot = histogram.getSnapshot();
+		printIfEnabled(MetricAttribute.MIN,
+				String.format(locale, "               min = %d", snapshot.getMin()));
+		printIfEnabled(MetricAttribute.MAX,
+				String.format(locale, "               max = %d", snapshot.getMax()));
+		printIfEnabled(MetricAttribute.MEAN,
+				String.format(locale, "              mean = %2.2f", snapshot.getMean()));
+		printIfEnabled(MetricAttribute.STDDEV,
+				String.format(locale, "            stddev = %2.2f", snapshot.getStdDev()));
+		printIfEnabled(MetricAttribute.P50,
+				String.format(locale, "            median = %2.2f", snapshot.getMedian()));
+		printIfEnabled(MetricAttribute.P75,
+				String.format(locale, "              75%% <= %2.2f", snapshot.get75thPercentile()));
+		printIfEnabled(MetricAttribute.P95,
+				String.format(locale, "              95%% <= %2.2f", snapshot.get95thPercentile()));
+		printIfEnabled(MetricAttribute.P98,
+				String.format(locale, "              98%% <= %2.2f", snapshot.get98thPercentile()));
+		printIfEnabled(MetricAttribute.P99,
+				String.format(locale, "              99%% <= %2.2f", snapshot.get99thPercentile()));
+		printIfEnabled(MetricAttribute.P999, String.format(locale, "            99.9%% <= %2.2f",
+				snapshot.get999thPercentile()));
+	}
+
+	private void printTimer(Timer timer) {
+		final Snapshot snapshot = timer.getSnapshot();
+		printIfEnabled(MetricAttribute.COUNT,
+				String.format(locale, "             count = %d", timer.getCount()));
+		printIfEnabled(MetricAttribute.MEAN_RATE,
+				String.format(locale, "         mean rate = %2.2f calls/%s",
+						convertRate(timer.getMeanRate()), getRateUnit()));
+		printIfEnabled(MetricAttribute.M1_RATE,
+				String.format(locale, "     1-minute rate = %2.2f calls/%s",
+						convertRate(timer.getOneMinuteRate()), getRateUnit()));
+		printIfEnabled(MetricAttribute.M5_RATE,
+				String.format(locale, "     5-minute rate = %2.2f calls/%s",
+						convertRate(timer.getFiveMinuteRate()), getRateUnit()));
+		printIfEnabled(MetricAttribute.M15_RATE,
+				String.format(locale, "    15-minute rate = %2.2f calls/%s",
+						convertRate(timer.getFifteenMinuteRate()), getRateUnit()));
+
+		printIfEnabled(MetricAttribute.MIN, String.format(locale, "               min = %2.2f %s",
+				convertDuration(snapshot.getMin()), getDurationUnit()));
+		printIfEnabled(MetricAttribute.MAX, String.format(locale, "               max = %2.2f %s",
+				convertDuration(snapshot.getMax()), getDurationUnit()));
+		printIfEnabled(MetricAttribute.MEAN, String.format(locale, "              mean = %2.2f %s",
+				convertDuration(snapshot.getMean()), getDurationUnit()));
+		printIfEnabled(MetricAttribute.STDDEV,
+				String.format(locale, "            stddev = %2.2f %s",
+						convertDuration(snapshot.getStdDev()), getDurationUnit()));
+		printIfEnabled(MetricAttribute.P50, String.format(locale, "            median = %2.2f %s",
+				convertDuration(snapshot.getMedian()), getDurationUnit()));
+		printIfEnabled(MetricAttribute.P75, String.format(locale, "              75%% <= %2.2f %s",
+				convertDuration(snapshot.get75thPercentile()), getDurationUnit()));
+		printIfEnabled(MetricAttribute.P95, String.format(locale, "              95%% <= %2.2f %s",
+				convertDuration(snapshot.get95thPercentile()), getDurationUnit()));
+		printIfEnabled(MetricAttribute.P98, String.format(locale, "              98%% <= %2.2f %s",
+				convertDuration(snapshot.get98thPercentile()), getDurationUnit()));
+		printIfEnabled(MetricAttribute.P99, String.format(locale, "              99%% <= %2.2f %s",
+				convertDuration(snapshot.get99thPercentile()), getDurationUnit()));
+		printIfEnabled(MetricAttribute.P999, String.format(locale, "            99.9%% <= %2.2f %s",
+				convertDuration(snapshot.get999thPercentile()), getDurationUnit()));
+	}
+
+	private void printWithBanner(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();
+	}
+
+	/**
+	 * Print only if the attribute is enabled
+	 *
+	 * @param type
+	 *            Metric attribute
+	 * @param status
+	 *            Status to be logged
+	 */
+	private void printIfEnabled(MetricAttribute type, String status) {
+		if (getDisabledMetricAttributes().contains(type)) {
+			return;
+		}
+
+		output.println(status);
+	}
+}

+ 26 - 0
src/main/java/cn/com/qmth/examcloud/web/actuator/MetricRegistryHolder.java

@@ -0,0 +1,26 @@
+package cn.com.qmth.examcloud.web.actuator;
+
+import com.codahale.metrics.MetricRegistry;
+
+/**
+ * MetricRegistryHolder
+ *
+ * @author WANGWEI
+ * @date 2019年7月25日
+ * @Copyright (c) 2018-? http://qmth.com.cn All Rights Reserved.
+ */
+public class MetricRegistryHolder {
+
+	private static MetricRegistry defaultMetricRegistry = new MetricRegistry();
+
+	/**
+	 * 获取默认
+	 *
+	 * @author WANGWEI
+	 * @return
+	 */
+	public static MetricRegistry getDefalut() {
+		return defaultMetricRegistry;
+	}
+
+}