/******************************************************************************* * Copyright (c) 2005, 2014 springside.github.io * * Licensed under the Apache License, Version 2.0 (the "License"); *******************************************************************************/ package org.springside.modules.metrics.reporter; import java.util.ArrayList; import java.util.List; import java.util.SortedMap; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ThreadFactory; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springside.modules.metrics.Counter; import org.springside.modules.metrics.Histogram; import org.springside.modules.metrics.MetricRegistry; import org.springside.modules.metrics.Timer; /** * Reporter线程.由用户负责初始化reporter及管理起停。 * * @author calvin */ public class ReportScheduler { private static final String SCHEDULER_NAME = "metrics-reporter"; private static Logger logger = LoggerFactory.getLogger(ReportScheduler.class); private MetricRegistry metricRegistry; private List<Reporter> reporters; private ScheduledExecutorService executor; public ReportScheduler(MetricRegistry metricRegistry, Reporter... reporters) { this(metricRegistry, new ArrayList<Reporter>()); for (Reporter reporter : reporters) { this.addReporter(reporter); } } public ReportScheduler(MetricRegistry metricRegistry, List<Reporter> reporters) { this.metricRegistry = metricRegistry; this.reporters = reporters; this.executor = Executors.newSingleThreadScheduledExecutor(new NamedThreadFactory(SCHEDULER_NAME)); } public void addReporter(Reporter reporter) { reporters.add(reporter); } public void removeReporter(Reporter reporter) { reporters.remove(reporter); } public void start(long period, TimeUnit unit) { executor.scheduleAtFixedRate(new Runnable() { @Override public void run() { try { report(); } catch (Throwable e) { logger.error(e.getMessage(), e); } } }, period, period, unit); logger.info("metric reporters started."); } public void stop() { executor.shutdownNow(); try { if (executor.awaitTermination(2, TimeUnit.SECONDS)) { logger.info("metric reporters stopped."); } else { logger.info("metric reporters can't stop in 2 seconds, force stopped."); } } catch (InterruptedException ignored) { // do nothing } } public void report() { // 取出所有Metrics,已按名称排序. SortedMap<String, Counter> counterMap = metricRegistry.getCounters(); SortedMap<String, Histogram> histogramMap = metricRegistry.getHistograms(); SortedMap<String, Timer> timerMap = metricRegistry.getTimers(); // 调度每个Metrics的caculateMetrics()方法,计算单位时间内的metrics值 for (Counter counter : counterMap.values()) { counter.calculateMetric(); } for (Histogram histogram : histogramMap.values()) { histogram.calculateMetric(); } for (Timer timer : timerMap.values()) { timer.calculateMetric(); } // 调度所有Reporters 输出 metrics值 for (Reporter reporter : reporters) { reporter.report(counterMap, histogramMap, timerMap); } } /** * 给线程命名的线程工厂类,为了减少项目依赖,没有直接使用Guava里的实现。 */ private static class NamedThreadFactory implements ThreadFactory { private final ThreadGroup group; private final AtomicInteger threadNumber = new AtomicInteger(1); private final String namePrefix; private NamedThreadFactory(String name) { final SecurityManager s = System.getSecurityManager(); this.group = (s != null) ? s.getThreadGroup() : Thread.currentThread().getThreadGroup(); this.namePrefix = name; } @Override public Thread newThread(Runnable r) { final Thread t = new Thread(group, r, namePrefix + threadNumber.getAndIncrement(), 0); t.setDaemon(true); if (t.getPriority() != Thread.NORM_PRIORITY) { t.setPriority(Thread.NORM_PRIORITY); } return t; } } }