Skip to content

Commit fb7d85d

Browse files
authored
metric: Add Prometheus exporter module for Sentinel metrics (#3173)
1 parent 6879fdd commit fb7d85d

File tree

11 files changed

+564
-0
lines changed

11 files changed

+564
-0
lines changed

sentinel-extension/pom.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
<module>sentinel-datasource-eureka</module>
2626
<module>sentinel-annotation-cdi-interceptor</module>
2727
<module>sentinel-metric-exporter</module>
28+
<module>sentinel-prometheus-metric-exporter</module>
2829
<module>sentinel-datasource-opensergo</module>
2930
<module>sentinel-datasource-xds</module>
3031
</modules>
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
# Sentinel Prometheus Exporter
2+
3+
Sentinel Prometheus Exporter is a module which provides the Sentinel metrics data for prometheus.
4+
5+
You can integrate it into your Sentinel application, and then get the sentinel metrics in your prometheus.
6+
7+
## How it works
8+
9+
when the prometheus server collect the sentinel metrics,it get metrics from sentinel logs
10+
![image](https://github.com/alibaba/Sentinel/assets/71377602/2982209b-a3c7-403b-ae50-1dc7a17f90b7)
11+
12+
## How to use
13+
14+
To use Sentinel Prometheus Exporter, you should add the following dependency:
15+
16+
### 1. add sentinel-prometheus-exporter
17+
18+
```xml
19+
<dependency>
20+
<groupId>com.alibaba.csp</groupId>
21+
<artifactId>sentinel-prometheus-metric-exporter</artifactId>
22+
<version>x.y.z</version>
23+
</dependency>
24+
```
25+
26+
### 2. add prometheus dependency
27+
28+
```xml
29+
<dependency>
30+
<groupId>io.prometheus</groupId>
31+
<artifactId>simpleclient</artifactId>
32+
<version>0.3.0</version>
33+
</dependency>
34+
```
35+
36+
```xml
37+
<dependency>
38+
<groupId>io.prometheus</groupId>
39+
<artifactId>simpleclient_httpserver</artifactId>
40+
<version>0.3.0</version>
41+
</dependency>
42+
```
43+
44+
### 3. set prometheus.yml with fetch config
45+
46+
```yaml
47+
scrape_configs:
48+
- job_name: 'sentinelMetrics'
49+
static_configs:
50+
- targets: ['localhost:9092']
51+
```
52+
53+
```yaml
54+
Note: the port needs to be the same as the value in the configuration (csp.sentinel.prometheus.fetch.port)
55+
```
56+
57+
## Params for exporter
58+
59+
you can set system params to control the exporter behavior
60+
61+
### 1.csp.sentinel.prometheus.fetch.port
62+
63+
the port for prometheus exporter,default 9092
64+
65+
### 2.csp.sentinel.prometheus.fetch.size
66+
67+
the max fetch nums for prometheus exporter,in case the memory is not enough,default 1024
68+
69+
### 3.csp.sentinel.prometheus.fetch.delay
70+
71+
the delay time for fetching , may be it is still do some statistics work according to the sliding window size when fetching,
72+
73+
so need to set the delay time to insure the accuracy.
74+
75+
unit: second
76+
77+
default: 0
78+
79+
### 4.csp.sentinel.prometheus.fetch.identify
80+
81+
set the resource which need to fetch,default null,fetch all resources
82+
83+
### 5.csp.sentinel.prometheus.fetch.types
84+
85+
the types need to fetch,such as passQps,concurrency
86+
87+
format: "xx|xx|xx"
88+
89+
default: "passQps|blockQps|exceptionQps|rt|concurrency"
90+
91+
you can reset the types as you need to,exm: "passQps|rt|concurrency|occupiedPassQps"
92+
93+
the type is same as the MetricNode class variables, with range:
94+
{"passQps","blockQps","successQps","exceptionQps","rt","occupiedPassQps","concurrency"}
95+
96+
### 6.csp.sentinel.prometheus.app
97+
98+
set the appName when do PromSQL
99+
100+
## how it looks
101+
102+
![image](https://github.com/alibaba/Sentinel/assets/71377602/dedde134-53ed-4b4e-b184-98e55184aacf)
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0"
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
5+
<modelVersion>4.0.0</modelVersion>
6+
<parent>
7+
<groupId>com.alibaba.csp</groupId>
8+
<artifactId>sentinel-parent</artifactId>
9+
<version>2.0.0-alpha</version>
10+
<relativePath>../../pom.xml</relativePath>
11+
</parent>
12+
13+
<artifactId>sentinel-prometheus-metric-exporter</artifactId>
14+
15+
<dependencies>
16+
<dependency>
17+
<groupId>com.alibaba.csp</groupId>
18+
<artifactId>sentinel-core</artifactId>
19+
</dependency>
20+
21+
<dependency>
22+
<groupId>io.prometheus</groupId>
23+
<artifactId>simpleclient</artifactId>
24+
<version>0.3.0</version>
25+
<scope>provided</scope>
26+
</dependency>
27+
28+
<dependency>
29+
<groupId>io.prometheus</groupId>
30+
<artifactId>simpleclient_httpserver</artifactId>
31+
<version>0.3.0</version>
32+
<scope>provided</scope>
33+
</dependency>
34+
35+
<dependency>
36+
<groupId>junit</groupId>
37+
<artifactId>junit</artifactId>
38+
<scope>test</scope>
39+
</dependency>
40+
</dependencies>
41+
42+
</project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
/*
2+
* Copyright 1999-2019 Alibaba Group Holding Ltd.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package com.alibaba.csp.sentinel.metric.prom;
17+
18+
/**
19+
* The{@link PromExporterInit} the Collector for prometheus exporter.
20+
*
21+
* @author karl-sy
22+
* @date 2023-08-08 09:30
23+
* @since 2.0.0
24+
*/
25+
public final class MetricConstants {
26+
27+
public static final String METRIC_HELP = "sentinel_metrics";
28+
29+
public static final String RESOURCE = "resource";
30+
31+
public static final String CLASSIFICATION = "classification";
32+
33+
public static final String METRIC_TYPE = "type";
34+
35+
public static final String PASS_QPS = "passQps";
36+
37+
public static final String BLOCK_QPS = "blockQps";
38+
39+
public static final String SUCCESS_QPS = "successQps";
40+
41+
public static final String EXCEPTION_QPS = "exceptionQps";
42+
43+
public static final String RT = "rt";
44+
45+
public static final String OCC_PASS_QPS = "occupiedPassQps";
46+
47+
public static final String CONCURRENCY = "concurrency";
48+
49+
private MetricConstants() {
50+
}
51+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
/*
2+
* Copyright 1999-2021 Alibaba Group Holding Ltd.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package com.alibaba.csp.sentinel.metric.prom;
17+
18+
import com.alibaba.csp.sentinel.init.InitFunc;
19+
import com.alibaba.csp.sentinel.log.RecordLog;
20+
import com.alibaba.csp.sentinel.metric.prom.collector.SentinelCollector;
21+
import com.alibaba.csp.sentinel.metric.prom.config.PrometheusGlobalConfig;
22+
import io.prometheus.client.exporter.HTTPServer;
23+
24+
/**
25+
* The{@link PromExporterInit} the InitFunc for prometheus exporter.
26+
*
27+
* @author karl-sy
28+
* @date 2023-07-13 21:15
29+
* @since 2.0.0
30+
*/
31+
public class PromExporterInit implements InitFunc {
32+
33+
@Override
34+
public void init() throws Exception {
35+
HTTPServer server = null;
36+
try {
37+
new SentinelCollector().register();
38+
// 开启http服务供prometheus调用
39+
// 默认只提供一个接口 http://ip:port/metrics,返回所有指标
40+
int promPort = PrometheusGlobalConfig.getPromFetchPort();
41+
server = new HTTPServer(promPort);
42+
} catch (Throwable e) {
43+
RecordLog.warn("[PromExporterInit] failed to init prometheus exporter with exception:", e);
44+
}
45+
46+
HTTPServer finalServer = server;
47+
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
48+
if (finalServer != null) {
49+
finalServer.stop();
50+
}
51+
}));
52+
}
53+
54+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
/*
2+
* Copyright 1999-2021 Alibaba Group Holding Ltd.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package com.alibaba.csp.sentinel.metric.prom.collector;
17+
18+
import com.alibaba.csp.sentinel.config.SentinelConfig;
19+
import com.alibaba.csp.sentinel.log.RecordLog;
20+
import com.alibaba.csp.sentinel.metric.prom.MetricConstants;
21+
import com.alibaba.csp.sentinel.metric.prom.config.PrometheusGlobalConfig;
22+
import com.alibaba.csp.sentinel.metric.prom.types.GaugeMetricFamily;
23+
import com.alibaba.csp.sentinel.node.metric.MetricNode;
24+
import com.alibaba.csp.sentinel.node.metric.MetricSearcher;
25+
import com.alibaba.csp.sentinel.node.metric.MetricWriter;
26+
import com.alibaba.csp.sentinel.util.PidUtil;
27+
import io.prometheus.client.Collector;
28+
29+
import java.util.ArrayList;
30+
import java.util.Arrays;
31+
import java.util.List;
32+
33+
/**
34+
* The{@link PromExporterInit} Collector for prometheus exporter.
35+
*
36+
* @author karl-sy
37+
* @date 2023-07-13 21:15
38+
* @since 2.0.0
39+
*/
40+
public class SentinelCollector extends Collector {
41+
42+
private final Object lock = new Object();
43+
44+
private static final int ONE_SECOND = 1000;
45+
private static final String appName = PrometheusGlobalConfig.getPromFetchApp();
46+
47+
private static final String[] types = PrometheusGlobalConfig.getPromFetchTypes();
48+
49+
private static final String identify = PrometheusGlobalConfig.getPromFetchIdentify();
50+
51+
private static final int fetchSize = PrometheusGlobalConfig.getPromFetchSize();
52+
53+
private static final int delayTime = PrometheusGlobalConfig.getPromFetchDelayTime();
54+
55+
private volatile MetricSearcher searcher;
56+
57+
private volatile Long lastFetchTime;
58+
59+
@Override
60+
public List<MetricFamilySamples> collect() {
61+
if (searcher == null) {
62+
synchronized (lock) {
63+
if (searcher == null) {
64+
searcher = new MetricSearcher(MetricWriter.METRIC_BASE_DIR,
65+
MetricWriter.formMetricFileName(SentinelConfig.getAppName(), PidUtil.getPid()));
66+
}
67+
RecordLog.warn("[SentinelCollector] init sentinel metrics searcher with appName:{}", appName);
68+
lastFetchTime = System.currentTimeMillis() / ONE_SECOND * ONE_SECOND;
69+
}
70+
}
71+
72+
List<MetricFamilySamples> list = new ArrayList<>();
73+
74+
long endTime = System.currentTimeMillis() / ONE_SECOND * ONE_SECOND - (long) delayTime * ONE_SECOND;
75+
try {
76+
List<MetricNode> nodes = searcher.findByTimeAndResource(lastFetchTime, endTime, identify);
77+
if(nodes == null){
78+
return list;
79+
}
80+
if(nodes.size() > fetchSize){
81+
nodes = nodes.subList(0,fetchSize);
82+
}
83+
GaugeMetricFamily metricFamily = new GaugeMetricFamily(appName, MetricConstants.METRIC_HELP,
84+
Arrays.asList(MetricConstants.RESOURCE, MetricConstants.CLASSIFICATION,
85+
MetricConstants.METRIC_TYPE));
86+
for (MetricNode node : nodes) {
87+
long recordTime = node.getTimestamp();
88+
for (String type : types) {
89+
double val = getTypeVal(node,type);
90+
metricFamily.addMetric(Arrays.asList(node.getResource(), String.valueOf(node.getClassification()),type), val,recordTime);
91+
}
92+
}
93+
list.add(metricFamily);
94+
} catch (Exception e) {
95+
RecordLog.warn("[SentinelCollector] failed to fetch sentinel metrics with exception:", e);
96+
}finally {
97+
lastFetchTime = endTime + ONE_SECOND;
98+
}
99+
100+
return list;
101+
}
102+
103+
public double getTypeVal(MetricNode node,String type){
104+
if(MetricConstants.PASS_QPS.equals(type)){
105+
return node.getPassQps();
106+
}
107+
if(MetricConstants.BLOCK_QPS.equals(type)){
108+
return node.getBlockQps();
109+
}
110+
if(MetricConstants.SUCCESS_QPS.equals(type)){
111+
return node.getSuccessQps();
112+
}
113+
if(MetricConstants.EXCEPTION_QPS.equals(type)){
114+
return node.getExceptionQps();
115+
}
116+
if(MetricConstants.RT.equals(type)){
117+
return node.getRt();
118+
}
119+
if(MetricConstants.OCC_PASS_QPS.equals(type)){
120+
return node.getOccupiedPassQps();
121+
}
122+
if(MetricConstants.CONCURRENCY.equals(type)){
123+
return node.getConcurrency();
124+
}
125+
return -1.0;
126+
}
127+
}

0 commit comments

Comments
 (0)