开源库—Metrics指标度量工具

随着系统越来越大,越来越复杂,我们需要在业务方面加上一些监控服务。Metrics作为一款监控指标的度量类库,在JAVA代码中嵌入Metrics代码,可以方便的对业务代码的各个指标进行监控,同时,Metrics能够很好的跟Ganlia、Graphite结合,方便的提供图形化接口。

使用Metrics

使用Metrics,只需要在pom文件里面增加metrics-core的依赖:

1
2
3
4
5
<dependency>
<groupId>io.dropwizard.metrics</groupId>
<artifactId>metrics-core</artifactId>
<version>4.0.0</version>
</dependency>

core包主要提供如下核心功能:

  1. Metrics中MetricRegistry是中心容器,它是程序中所有度量的容器,所有新的度量工具都要注册到一个MetricRegistry实例中才可以使用,尽量在一个应用中保持让这个MetricRegistry实例保持单例。

  2. 支持五种metric类型:

    • Gauges(度量)
    • Counters(计数器)
    • Meters(TPS计算器)
    • Histograms(直方图数据)
    • Timers(计时器)
  3. 可以将metrics值通过JMX、Console,CSV文件和SLF4J loggers发布出来。

Gauge (仪表)

Gauge代表一个度量的即时值。 当你开汽车的时候, 当前速度是Gauge值。 你测体温的时候, 体温计的刻度是一个Gauge值。 当你的程序运行的时候,内存使用量和数据库连接数都可以通过Gauge值来度量。

下面是一个使用SpringBoot创建的domo示例:

配置类:MonitorConfiguration.java,将MetricRegistry的实例配置到Spring的IOC容器中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
package com.lzumetal.springboot.metrics.config;

import com.codahale.metrics.MetricRegistry;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
* <p>Description: </p>
*
* @author liaosi
* @date 2018-07-28
*/
@Configuration
public class MonitorConfiguration {

/**
* 其实就是一个metrics容器,因为该类的一个属性final ConcurrentMap<String, Metric> metrics,
* 在实际使用中做成单例的
* @return
*/
@Bean(name = "metricRegistry")
public MetricRegistry metricRegistry() {
return new MetricRegistry();
}


}

SpringBood项目启动类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package com.lzumetal.springboot.metrics;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

/**
* <p>Description: </p>
*
* @author liaosi
* @date 2018-07-28
*/
@SpringBootApplication
public class Bootstrap {

public static void main(String[] args) {
SpringApplication.run(Bootstrap.class, args);
}

}

测试类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
package com.lzumetal.springboot.metrics.test;

import com.codahale.metrics.ConsoleReporter;
import com.codahale.metrics.Gauge;
import com.codahale.metrics.MetricRegistry;
import com.codahale.metrics.Slf4jReporter;
import com.lzumetal.springboot.metrics.Bootstrap;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import java.util.Queue;
import java.util.Random;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.TimeUnit;

/**
* <p>Description: </p>
*
* @author liaosi
* @date 2018-07-28
*/
@RunWith(SpringRunner.class)
@SpringBootTest(classes = Bootstrap.class) //classes指定项目启动类
public class MetricsTest {

private static Queue<Integer> queue = new LinkedBlockingDeque<Integer>();

private static final Logger log = LoggerFactory.getLogger(MetricsTest.class);


@Autowired
private MetricRegistry registry;


@Test
public void GaugeTest() throws InterruptedException {
//让监控的数据输出到控制台
ConsoleReporter reporter = ConsoleReporter.forRegistry(registry).build();
reporter.start(3L, TimeUnit.SECONDS);

registry.register(MetricRegistry.name(MetricsTest.class, "queue", "size"), (Gauge) () -> {
return queue.size();
});

TimeUnit.SECONDS.sleep(5L);

for (int i = 0; i < 20; i++) {
queue.add(new Random().nextInt(100));
TimeUnit.SECONDS.sleep(1L);
}


}

@Test
public void GaugeTest2() throws InterruptedException {


registry.register(MetricRegistry.name(MetricsTest.class, "queue", "size"), (Gauge) () -> {
return queue.size();
});

//让监控的数据输出到slf4j的日志
Slf4jReporter.Builder builder = Slf4jReporter.forRegistry(registry);
builder.outputTo(log);
builder.withLoggingLevel(Slf4jReporter.LoggingLevel.ERROR);
builder.build().start(3, TimeUnit.SECONDS);

TimeUnit.SECONDS.sleep(5L);

for (int i = 0; i < 20; i++) {
queue.add(new Random().nextInt(100));
TimeUnit.SECONDS.sleep(1L);
}
}

}

GaugeTest()方法(监控数据输出到控制台)运行结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
-- Gauges ----------------------------------------------------------------------
com.lzumetal.springboot.metrics.test.MetricsTest.queue.size
value = 0


18-7-29 22:56:36 ===============================================================

-- Gauges ----------------------------------------------------------------------
com.lzumetal.springboot.metrics.test.MetricsTest.queue.size
value = 2


18-7-29 22:56:39 ===============================================================

-- Gauges ----------------------------------------------------------------------
com.lzumetal.springboot.metrics.test.MetricsTest.queue.size
value = 5


18-7-29 22:56:42 ===============================================================

-- Gauges ----------------------------------------------------------------------
com.lzumetal.springboot.metrics.test.MetricsTest.queue.size
value = 8


18-7-29 22:56:45 ===============================================================

-- Gauges ----------------------------------------------------------------------
com.lzumetal.springboot.metrics.test.MetricsTest.queue.size
value = 10


18-7-29 22:56:48 ===============================================================

-- Gauges ----------------------------------------------------------------------
com.lzumetal.springboot.metrics.test.MetricsTest.queue.size
value = 13


18-7-29 22:56:51 ===============================================================

-- Gauges ----------------------------------------------------------------------
com.lzumetal.springboot.metrics.test.MetricsTest.queue.size
value = 16


18-7-29 22:56:54 ===============================================================

-- Gauges ----------------------------------------------------------------------
com.lzumetal.springboot.metrics.test.MetricsTest.queue.size
value = 19

GaugeTest()方法(监控数据输出到slf4j日志)运行结果:

1
2
3
4
5
6
7
8
2018-07-29 22:45:16.154 ERROR 15484 --- [rter-1-thread-1] c.l.springboot.metrics.test.MetricsTest  : type=GAUGE, name=com.lzumetal.springboot.metrics.test.MetricsTest.queue.size, value=0
2018-07-29 22:45:19.147 ERROR 15484 --- [rter-1-thread-1] c.l.springboot.metrics.test.MetricsTest : type=GAUGE, name=com.lzumetal.springboot.metrics.test.MetricsTest.queue.size, value=2
2018-07-29 22:45:22.147 ERROR 15484 --- [rter-1-thread-1] c.l.springboot.metrics.test.MetricsTest : type=GAUGE, name=com.lzumetal.springboot.metrics.test.MetricsTest.queue.size, value=5
2018-07-29 22:45:25.147 ERROR 15484 --- [rter-1-thread-1] c.l.springboot.metrics.test.MetricsTest : type=GAUGE, name=com.lzumetal.springboot.metrics.test.MetricsTest.queue.size, value=8
2018-07-29 22:45:28.147 ERROR 15484 --- [rter-1-thread-1] c.l.springboot.metrics.test.MetricsTest : type=GAUGE, name=com.lzumetal.springboot.metrics.test.MetricsTest.queue.size, value=10
2018-07-29 22:45:31.148 ERROR 15484 --- [rter-1-thread-1] c.l.springboot.metrics.test.MetricsTest : type=GAUGE, name=com.lzumetal.springboot.metrics.test.MetricsTest.queue.size, value=13
2018-07-29 22:45:34.148 ERROR 15484 --- [rter-1-thread-1] c.l.springboot.metrics.test.MetricsTest : type=GAUGE, name=com.lzumetal.springboot.metrics.test.MetricsTest.queue.size, value=16
2018-07-29 22:45:37.148 ERROR 15484 --- [rter-1-thread-1] c.l.springboot.metrics.test.MetricsTest : type=GAUGE, name=com.lzumetal.springboot.metrics.test.MetricsTest.queue.size, value=19

------ 本文完 ------