Skip to content

Commit

Permalink
metric: Add Prometheus exporter module for Sentinel metrics (#3173)
Browse files Browse the repository at this point in the history
  • Loading branch information
karl-sy authored Dec 27, 2023
1 parent 6879fdd commit fb7d85d
Show file tree
Hide file tree
Showing 11 changed files with 564 additions and 0 deletions.
1 change: 1 addition & 0 deletions sentinel-extension/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
<module>sentinel-datasource-eureka</module>
<module>sentinel-annotation-cdi-interceptor</module>
<module>sentinel-metric-exporter</module>
<module>sentinel-prometheus-metric-exporter</module>
<module>sentinel-datasource-opensergo</module>
<module>sentinel-datasource-xds</module>
</modules>
Expand Down
102 changes: 102 additions & 0 deletions sentinel-extension/sentinel-prometheus-metric-exporter/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
# Sentinel Prometheus Exporter

Sentinel Prometheus Exporter is a module which provides the Sentinel metrics data for prometheus.

You can integrate it into your Sentinel application, and then get the sentinel metrics in your prometheus.

## How it works

when the prometheus server collect the sentinel metrics,it get metrics from sentinel logs
![image](https://github.com/alibaba/Sentinel/assets/71377602/2982209b-a3c7-403b-ae50-1dc7a17f90b7)

## How to use

To use Sentinel Prometheus Exporter, you should add the following dependency:

### 1. add sentinel-prometheus-exporter

```xml
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-prometheus-metric-exporter</artifactId>
<version>x.y.z</version>
</dependency>
```

### 2. add prometheus dependency

```xml
<dependency>
<groupId>io.prometheus</groupId>
<artifactId>simpleclient</artifactId>
<version>0.3.0</version>
</dependency>
```

```xml
<dependency>
<groupId>io.prometheus</groupId>
<artifactId>simpleclient_httpserver</artifactId>
<version>0.3.0</version>
</dependency>
```

### 3. set prometheus.yml with fetch config

```yaml
scrape_configs:
- job_name: 'sentinelMetrics'
static_configs:
- targets: ['localhost:9092']
```
```yaml
Note: the port needs to be the same as the value in the configuration (csp.sentinel.prometheus.fetch.port)
```
## Params for exporter
you can set system params to control the exporter behavior
### 1.csp.sentinel.prometheus.fetch.port
the port for prometheus exporter,default 9092
### 2.csp.sentinel.prometheus.fetch.size
the max fetch nums for prometheus exporter,in case the memory is not enough,default 1024
### 3.csp.sentinel.prometheus.fetch.delay
the delay time for fetching , may be it is still do some statistics work according to the sliding window size when fetching,
so need to set the delay time to insure the accuracy.
unit: second
default: 0
### 4.csp.sentinel.prometheus.fetch.identify
set the resource which need to fetch,default null,fetch all resources
### 5.csp.sentinel.prometheus.fetch.types
the types need to fetch,such as passQps,concurrency
format: "xx|xx|xx"
default: "passQps|blockQps|exceptionQps|rt|concurrency"
you can reset the types as you need to,exm: "passQps|rt|concurrency|occupiedPassQps"
the type is same as the MetricNode class variables, with range:
{"passQps","blockQps","successQps","exceptionQps","rt","occupiedPassQps","concurrency"}
### 6.csp.sentinel.prometheus.app
set the appName when do PromSQL
## how it looks
![image](https://github.com/alibaba/Sentinel/assets/71377602/dedde134-53ed-4b4e-b184-98e55184aacf)
42 changes: 42 additions & 0 deletions sentinel-extension/sentinel-prometheus-metric-exporter/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-parent</artifactId>
<version>2.0.0-alpha</version>
<relativePath>../../pom.xml</relativePath>
</parent>

<artifactId>sentinel-prometheus-metric-exporter</artifactId>

<dependencies>
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-core</artifactId>
</dependency>

<dependency>
<groupId>io.prometheus</groupId>
<artifactId>simpleclient</artifactId>
<version>0.3.0</version>
<scope>provided</scope>
</dependency>

<dependency>
<groupId>io.prometheus</groupId>
<artifactId>simpleclient_httpserver</artifactId>
<version>0.3.0</version>
<scope>provided</scope>
</dependency>

<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
</dependencies>

</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/*
* Copyright 1999-2019 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.csp.sentinel.metric.prom;

/**
* The{@link PromExporterInit} the Collector for prometheus exporter.
*
* @author karl-sy
* @date 2023-08-08 09:30
* @since 2.0.0
*/
public final class MetricConstants {

public static final String METRIC_HELP = "sentinel_metrics";

public static final String RESOURCE = "resource";

public static final String CLASSIFICATION = "classification";

public static final String METRIC_TYPE = "type";

public static final String PASS_QPS = "passQps";

public static final String BLOCK_QPS = "blockQps";

public static final String SUCCESS_QPS = "successQps";

public static final String EXCEPTION_QPS = "exceptionQps";

public static final String RT = "rt";

public static final String OCC_PASS_QPS = "occupiedPassQps";

public static final String CONCURRENCY = "concurrency";

private MetricConstants() {
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/*
* Copyright 1999-2021 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.csp.sentinel.metric.prom;

import com.alibaba.csp.sentinel.init.InitFunc;
import com.alibaba.csp.sentinel.log.RecordLog;
import com.alibaba.csp.sentinel.metric.prom.collector.SentinelCollector;
import com.alibaba.csp.sentinel.metric.prom.config.PrometheusGlobalConfig;
import io.prometheus.client.exporter.HTTPServer;

/**
* The{@link PromExporterInit} the InitFunc for prometheus exporter.
*
* @author karl-sy
* @date 2023-07-13 21:15
* @since 2.0.0
*/
public class PromExporterInit implements InitFunc {

@Override
public void init() throws Exception {
HTTPServer server = null;
try {
new SentinelCollector().register();
// 开启http服务供prometheus调用
// 默认只提供一个接口 http://ip:port/metrics,返回所有指标
int promPort = PrometheusGlobalConfig.getPromFetchPort();
server = new HTTPServer(promPort);
} catch (Throwable e) {
RecordLog.warn("[PromExporterInit] failed to init prometheus exporter with exception:", e);
}

HTTPServer finalServer = server;
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
if (finalServer != null) {
finalServer.stop();
}
}));
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
/*
* Copyright 1999-2021 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.csp.sentinel.metric.prom.collector;

import com.alibaba.csp.sentinel.config.SentinelConfig;
import com.alibaba.csp.sentinel.log.RecordLog;
import com.alibaba.csp.sentinel.metric.prom.MetricConstants;
import com.alibaba.csp.sentinel.metric.prom.config.PrometheusGlobalConfig;
import com.alibaba.csp.sentinel.metric.prom.types.GaugeMetricFamily;
import com.alibaba.csp.sentinel.node.metric.MetricNode;
import com.alibaba.csp.sentinel.node.metric.MetricSearcher;
import com.alibaba.csp.sentinel.node.metric.MetricWriter;
import com.alibaba.csp.sentinel.util.PidUtil;
import io.prometheus.client.Collector;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
* The{@link PromExporterInit} Collector for prometheus exporter.
*
* @author karl-sy
* @date 2023-07-13 21:15
* @since 2.0.0
*/
public class SentinelCollector extends Collector {

private final Object lock = new Object();

private static final int ONE_SECOND = 1000;
private static final String appName = PrometheusGlobalConfig.getPromFetchApp();

private static final String[] types = PrometheusGlobalConfig.getPromFetchTypes();

private static final String identify = PrometheusGlobalConfig.getPromFetchIdentify();

private static final int fetchSize = PrometheusGlobalConfig.getPromFetchSize();

private static final int delayTime = PrometheusGlobalConfig.getPromFetchDelayTime();

private volatile MetricSearcher searcher;

private volatile Long lastFetchTime;

@Override
public List<MetricFamilySamples> collect() {
if (searcher == null) {
synchronized (lock) {
if (searcher == null) {
searcher = new MetricSearcher(MetricWriter.METRIC_BASE_DIR,
MetricWriter.formMetricFileName(SentinelConfig.getAppName(), PidUtil.getPid()));
}
RecordLog.warn("[SentinelCollector] init sentinel metrics searcher with appName:{}", appName);
lastFetchTime = System.currentTimeMillis() / ONE_SECOND * ONE_SECOND;
}
}

List<MetricFamilySamples> list = new ArrayList<>();

long endTime = System.currentTimeMillis() / ONE_SECOND * ONE_SECOND - (long) delayTime * ONE_SECOND;
try {
List<MetricNode> nodes = searcher.findByTimeAndResource(lastFetchTime, endTime, identify);
if(nodes == null){
return list;
}
if(nodes.size() > fetchSize){
nodes = nodes.subList(0,fetchSize);
}
GaugeMetricFamily metricFamily = new GaugeMetricFamily(appName, MetricConstants.METRIC_HELP,
Arrays.asList(MetricConstants.RESOURCE, MetricConstants.CLASSIFICATION,
MetricConstants.METRIC_TYPE));
for (MetricNode node : nodes) {
long recordTime = node.getTimestamp();
for (String type : types) {
double val = getTypeVal(node,type);
metricFamily.addMetric(Arrays.asList(node.getResource(), String.valueOf(node.getClassification()),type), val,recordTime);
}
}
list.add(metricFamily);
} catch (Exception e) {
RecordLog.warn("[SentinelCollector] failed to fetch sentinel metrics with exception:", e);
}finally {
lastFetchTime = endTime + ONE_SECOND;
}

return list;
}

public double getTypeVal(MetricNode node,String type){
if(MetricConstants.PASS_QPS.equals(type)){
return node.getPassQps();
}
if(MetricConstants.BLOCK_QPS.equals(type)){
return node.getBlockQps();
}
if(MetricConstants.SUCCESS_QPS.equals(type)){
return node.getSuccessQps();
}
if(MetricConstants.EXCEPTION_QPS.equals(type)){
return node.getExceptionQps();
}
if(MetricConstants.RT.equals(type)){
return node.getRt();
}
if(MetricConstants.OCC_PASS_QPS.equals(type)){
return node.getOccupiedPassQps();
}
if(MetricConstants.CONCURRENCY.equals(type)){
return node.getConcurrency();
}
return -1.0;
}
}
Loading

0 comments on commit fb7d85d

Please sign in to comment.