依赖jar的pom配置
<!--metrics相关--> <dependency> <groupId>io.dropwizard.metrics</groupId> <artifactId>metrics-core</artifactId> <version>4.0.0</version> </dependency> <!-- https://mvnrepository.com/artifact/io.dropwizard.metrics/metrics-jvm --> <dependency> <groupId>io.dropwizard.metrics</groupId> <artifactId>metrics-jvm</artifactId> <version>4.0.0</version> </dependency> <dependency> <groupId>com.github.davidb</groupId> <artifactId>metrics-influxdb</artifactId> <version>1.1.0</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-beans</artifactId> <scope>compile</scope> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <scope>compile</scope> </dependency>
spring中bean配置
<context:component-scan base-package="com.example.common.metrics"/> <bean id="metricRegistry" class="com.codahale.metrics.MetricRegistry"/>
基础工具:MetricsBase.java
import com.codahale.metrics.Histogram; import com.codahale.metrics.Meter; import com.codahale.metrics.MetricRegistry; import com.codahale.metrics.Timer; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; public class MetricsBase { private final Map<String, Meter> meterMap = new ConcurrentHashMap<>(); private final Map<String, Timer> timerMap = new ConcurrentHashMap<>(); private final Map<String, Histogram> histogramMap = new ConcurrentHashMap<>(); public static String keyGen(String meterMeasurements) { String[] parent = parent(); return MetricRegistry.name(parent[0], parent[1], meterMeasurements); } /** * 获取Meter实例 * * @param metricsKey * @return */ public Meter getMeter(String metricsKey, MetricRegistry metricRegistry) { Meter m = meterMap.get(metricsKey); if (m != null) { return m; } synchronized (MetricsBase.class) { Meter metrics = meterMap.get(metricsKey); if (metrics != null) { return metrics; } else { Meter object = metricRegistry.meter(metricsKey); meterMap.putIfAbsent(metricsKey, object); return object; } } } /** * 获取Timer实例 * * @param metricsKey * @return */ public Timer getTimer(String metricsKey, MetricRegistry metricRegistry) { Timer t = timerMap.get(metricsKey); if (t != null) { return t; } synchronized (MetricsBase.class) { Timer timer = timerMap.get(metricsKey); if (timer != null) { return timer; } else { Timer object = metricRegistry.timer(metricsKey); timerMap.putIfAbsent(metricsKey, object); return object; } } } /** * Histogram 直方图数据 * @param metricsKey * @return */ public Histogram getHistogram(String metricsKey, MetricRegistry metricRegistry) { Histogram t = histogramMap.get(metricsKey); if (t != null) { return t; } synchronized (MetricsBase.class) { Histogram histogram = histogramMap.get(metricsKey); if (histogram != null) { return histogram; } else { Histogram object = metricRegistry.histogram(metricsKey); histogramMap.putIfAbsent(metricsKey, object); return object; } } } public static String[] parent(){ StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace(); StackTraceElement stackTraceElement = stackTrace[4]; String className = stackTraceElement.getClassName(); String []classNames = className.split("\."); return new String[]{classNames[classNames.length-1], stackTraceElement.getMethodName()}; } }
调用方法:MetricsFactory.java
import com.codahale.metrics.Histogram; import com.codahale.metrics.Meter; import com.codahale.metrics.MetricRegistry; import com.codahale.metrics.Timer; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class MetricsFactory extends MetricsBase{ protected Logger log = LoggerFactory.getLogger(this.getClass()); private final static String TIMER_MEASUREMENTS = "smsTimer"; private final static String METER_MEASUREMENTS = "smsMeter"; private final static String HISTOGRAM_MEASUREMENTS = "smsHistogram"; private MetricsFactory() { } private static class MetricsFactoryInstance { private static final MetricsFactory INSTANCE = new MetricsFactory(); } public static MetricsFactory getInstance() { return MetricsFactoryInstance.INSTANCE; } /** * 接口TPS统计 * @param metricRegistry * @return */ public void getMeter(MetricRegistry metricRegistry) { try { String metricKey = keyGen(METER_MEASUREMENTS); log.info("MetricsFactory.getMeter.metricKey:{}",metricKey); getMeter(metricKey, metricRegistry).mark(); } catch (Exception e) { log.error("[NoticeCenter]create metrics(meter) error", e); } } /** * 接口耗时统计 * @param metricRegistry * @return */ public Timer.Context getTimer(MetricRegistry metricRegistry) { try { String metricKey = keyGen(TIMER_MEASUREMENTS); log.info("MetricsFactory.getTimer.metricKey:{}",metricKey); return getTimer(metricKey, metricRegistry).time(); } catch (Exception e) { log.error("[NoticeCenter]create metrics(timer) error", e); return null; } } /** * 停止Metrics.Timer记录 * @param context */ public void stopTimer(Timer.Context context) { try { if (context != null) { context.stop(); } } catch (Exception e) { log.error("[NoticeCenter]metrics(timer) stop error", e); } } /** * 直方图数据 * @param metricRegistry * @return */ public Histogram getHistogram(MetricRegistry metricRegistry) { try { String metricKey = keyGen(HISTOGRAM_MEASUREMENTS); return getHistogram(metricKey, metricRegistry); } catch (Exception e) { log.error("[NoticeCenter]create metrics(timer) error", e); return null; } } }
初始化:APPMertics.java
import com.codahale.metrics.ConsoleReporter; import com.codahale.metrics.MetricFilter; import com.codahale.metrics.MetricRegistry; import com.codahale.metrics.ScheduledReporter; import com.codahale.metrics.jvm.*; import metrics_influxdb.HttpInfluxdbProtocol; import metrics_influxdb.InfluxdbReporter; import metrics_influxdb.api.measurements.CategoriesMetricMeasurementTransformer; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; import org.springframework.util.StringUtils; import java.lang.management.ManagementFactory; import java.net.InetAddress; import java.util.Calendar; import java.util.Date; import java.util.concurrent.TimeUnit; @Component public class AppMetrics implements InitializingBean { private static final Logger log = LoggerFactory.getLogger(AppMetrics.class); @Autowired private MetricRegistry metricRegistry; @Value("${server.port}") private int port; @Value("${influxdb.reportJvm}") private boolean reportJvm; @Value("${influxdb.host}") private String influxHost; // @Value("${influxdb.user}") // private String influxUser; // // @Value("${influxdb.passwd}") // private String influxPasswd; @Value("${influxdb.db}") private String influxDB; @Value("${influxdb.port}") private int influxPort; @Value("${metrics.reporterInterval}") private long reporterInterval; public void afterPropertiesSet() throws Exception { log.info("AppMetrics init ***********,port: {}, reportJvm: {}, influxdb: {}, influxPort: {},influxDB: {}", port,reportJvm, influxHost, influxPort, influxDB); if (reportJvm){ initJVM(); } if (StringUtils.isEmpty(influxHost)) { startConsoleReporter(); } else { try { influxDbReporter(); } catch (Exception e) { e.printStackTrace(); } } } private void initJVM() { metricRegistry.register("jvm.gc", new GarbageCollectorMetricSet()); metricRegistry.register("jvm.thread-state", new CachedThreadStatesGaugeSet(10, TimeUnit.SECONDS)); metricRegistry.register("jvm.mem", new MemoryUsageGaugeSet()); metricRegistry.register("jvm.attr", new JvmAttributeGaugeSet()); metricRegistry.register("jvm.buffer-pool", new BufferPoolMetricSet(ManagementFactory.getPlatformMBeanServer())); metricRegistry.register("jvm.fd.usage", new FileDescriptorRatioGauge()); } private void influxDbReporter() throws Exception{ log.info("use influxdb as reporter {}:{}, {}", influxHost, influxPort, influxDB); final ScheduledReporter reporter = InfluxdbReporter.forRegistry(metricRegistry) // .protocol(new HttpInfluxdbProtocol("http", influxHost, influxPort, influxUser, influxPasswd, influxDB)) .protocol(new HttpInfluxdbProtocol(influxHost, influxPort, influxDB)) .convertRatesTo(TimeUnit.SECONDS) .convertDurationsTo(TimeUnit.MILLISECONDS) .filter(MetricFilter.ALL) .skipIdleMetrics(false) .tag("client", Integer.toString(port)) .tag("server", InetAddress.getLocalHost().getHostAddress()) .transformer(new CategoriesMetricMeasurementTransformer("noticeName", "ruleName", "measurement")) .build(); long initalDelay = getBeginTime().getTimeInMillis() - System.currentTimeMillis(); long period = reporterInterval * 1000; reporter.start(initalDelay, period, TimeUnit.MILLISECONDS); } private void startConsoleReporter() { log.info("use console as reporter"); ConsoleReporter reporter = ConsoleReporter.forRegistry(metricRegistry) .convertRatesTo(TimeUnit.SECONDS) .convertDurationsTo(TimeUnit.MILLISECONDS) .build(); long initalDelay = getBeginTime().getTimeInMillis() - System.currentTimeMillis(); long period = reporterInterval * 1000; reporter.start(initalDelay, period, TimeUnit.MILLISECONDS); } /** * 获取Metrics报告时间: * Metrics报告时间设定为启动后1分钟0秒开始, * 保证所有机器上的数据的开始时间都是从某分钟开始 * * @return */ private Calendar getBeginTime() { Calendar beginTime = Calendar.getInstance(); beginTime.setTime(new Date()); beginTime.add(Calendar.MINUTE, 1); beginTime.set(Calendar.SECOND, 0);// 秒 beginTime.set(Calendar.MILLISECOND, 0);// 毫秒 return beginTime; } }
以上工具类完成后在项目中就可以使用了!
项目中properties属性配置
#influxdb 配置参数 #是否上报JVM性能数据 influxdb.reportJvm=false influxdb.host=${content.influxdb.host} #当前服务端口 server.port=-1 #influxdb.port=${content.influxdb.port} influxdb.port=8086 influxdb.user=root influxdb.passwd=root #influxdb.db=#{content.influxdb.name} influxdb.db=metrics #metrics数据上报时间间隔 metrics.reporterInterval=10
工具类的使用demo:
@CrossOrigin(methods={RequestMethod.GET, RequestMethod.POST,RequestMethod.OPTIONS}) @Controller @RequestMapping("/metrics") public class MetricsController extends BaseController { private final static Logger logger = LoggerFactory.getLogger(MetricsController.class); @Autowired MetricRegistry metricRegistry; @ResponseBody() @ResponseStatus(HttpStatus.CREATED) @RequestMapping(value="/detailQuery",method={RequestMethod.GET,RequestMethod.POST,RequestMethod.OPTIONS}) public void detailQuery( HttpServletResponse response, @RequestParam(required = false) String jsonpcallback) { logger.info("metrics detailQuery"); RpcResponseDTO<String> result = new RpcResponseDTO<>(); result.setPayload("hello word"); //接口耗时统计 Timer.Context timerContext = MetricsFactory.getInstance().getTimer(metricRegistry);
// excute method ... MetricsFactory.getInstance().stopTimer(timerContext); //接口TPS统计 MetricsFactory.getInstance().getMeter(metricRegistry); SpringMVCRpcHelper.renderJson(response, jsonpcallback, result); } }