Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Prometheus metric extension #735

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions sentinel-extension/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
<module>sentinel-datasource-redis</module>
<module>sentinel-annotation-aspectj</module>
<module>sentinel-parameter-flow-control</module>
<module>sentinel-metric-prometheus</module>
</modules>

</project>
24 changes: 24 additions & 0 deletions sentinel-extension/sentinel-metric-prometheus/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Sentinel Metric Prometheus

Sentinel Metric Prometheus provides integration with Prometheus, so that Sentinel can expose its metrics in Prometheus format.

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

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

Then sentinel metric will automatic write to Prometheus client via Sentinel metric extension SPI.

You could export these metrics by any of [Prometheus exposition](https://github.com/prometheus/client_java#exporting). The The simplest of these may be the HTTPServer:

```java
HTTPServer server = new HTTPServer(1234);
```

We provide [PrometheusMetricExtensionDemo](./src/test/java/com/alibaba/csp/sentinel/metric/extension/prometheus/PrometheusMetricExtensionDemo.java) to show how to do this.

45 changes: 45 additions & 0 deletions sentinel-extension/sentinel-metric-prometheus/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<?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">
<parent>
<artifactId>sentinel-extension</artifactId>
<groupId>com.alibaba.csp</groupId>
<version>1.6.1-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>

<artifactId>sentinel-metric-prometheus</artifactId>
<packaging>jar</packaging>
<properties>
<java.source.version>1.7</java.source.version>
<java.target.version>1.7</java.target.version>
<prometheus.version>0.6.0</prometheus.version>
</properties>

<dependencies>
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-core</artifactId>
</dependency>
<!-- The client -->
<dependency>
<groupId>io.prometheus</groupId>
<artifactId>simpleclient</artifactId>
<version>${prometheus.version}</version>
</dependency>
<!-- Exposition HTTPServer-->
<dependency>
<groupId>io.prometheus</groupId>
<artifactId>simpleclient_httpserver</artifactId>
<version>${prometheus.version}</version>
</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,117 @@
package com.alibaba.csp.sentinel.metric.extension.prometheus;

import com.alibaba.csp.sentinel.metric.extension.MetricExtension;
import com.alibaba.csp.sentinel.slots.block.BlockException;

import io.prometheus.client.Counter;
import io.prometheus.client.Gauge;
import io.prometheus.client.Histogram;

/**
* Prometheus based Sentinel metric extension. This extension will expose metric
* in form of Prometheus.
*
* @author Carpenter Lee
* @since 1.6.1
*/
public class PrometheusMetricExtension implements MetricExtension {
private Counter passRequests;
private Counter blockRequests;
private Counter successRequests;
private Counter exceptionRequests;
private Histogram rtHist;
private Gauge currentThreads;

public PrometheusMetricExtension() {
passRequests = Counter.build()
.name("sentinel_pass_requests_total")
.help("total pass requests.")
.labelNames("resource")
.register();
blockRequests = Counter.build()
.name("sentinel_block_requests_total")
.help("total block requests.")
.labelNames("resource", "type", "ruleLimitApp", "limitApp")
.register();
successRequests = Counter.build()
.name("sentinel_success_requests_total")
.help("total success requests.")
.labelNames("resource")
.register();
exceptionRequests = Counter.build()
.name("sentinel_exception_requests_total")
.help("total exception requests.")
.labelNames("resource")
.register();
currentThreads = Gauge.build()
.name("sentinel_current_threads")
.help("current thread count.")
.labelNames("resource")
.register();
rtHist = Histogram.build()
.name("sentinel_requests_latency_seconds")
.help("request latency in seconds.")
.labelNames("resource")
.register();
}

public Counter getPassRequests() {
return passRequests;
}

public Counter getBlockRequests() {
return blockRequests;
}

public Counter getSuccessRequests() {
return successRequests;
}

public Counter getExceptionRequests() {
return exceptionRequests;
}

public Histogram getRtHist() {
return rtHist;
}

public Gauge getCurrentThreads() {
return currentThreads;
}

@Override
public void addPass(String resource, int n, Object... args) {
passRequests.labels(resource).inc(n);
}

@Override
public void addBlock(String resource, int n, String origin, BlockException ex, Object... args) {
blockRequests.labels(resource, ex.getClass().getSimpleName(), ex.getRuleLimitApp(), origin).inc(n);
}

@Override
public void addSuccess(String resource, int n, Object... args) {
successRequests.labels(resource).inc(n);
}

@Override
public void addException(String resource, int n, Throwable throwable) {
exceptionRequests.labels(resource).inc(n);
}

@Override
public void addRt(String resource, long rt, Object... args) {
// convert millisecond to second
rtHist.labels(resource).observe(((double)rt) / 1000);
}

@Override
public void increaseThreadNum(String resource, Object... args) {
currentThreads.labels(resource).inc();
}

@Override
public void decreaseThreadNum(String resource, Object... args) {
currentThreads.labels(resource).dec();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
com.alibaba.csp.sentinel.metric.extension.prometheus.PrometheusMetricExtension
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package com.alibaba.csp.sentinel.metric.extension.prometheus;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

import com.alibaba.csp.sentinel.Entry;
import com.alibaba.csp.sentinel.SphU;
import com.alibaba.csp.sentinel.Tracer;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.alibaba.csp.sentinel.slots.block.RuleConstant;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;

import io.prometheus.client.exporter.HTTPServer;

/**
* Start the demo and curl localhost:1234 , you could see metrics exposed by
* Sentinel Prometheus metric extension.
*
* @author Carpenter Lee
*/
public class PrometheusMetricExtensionDemo {
public static void main(String[] args) throws Exception {
HTTPServer server = new HTTPServer(1234);
System.out.println("server start...");

initFlowQpsRule();
Random random = new Random();
while (true) {
Entry entry = null;
try {
entry = SphU.entry("resource1");
Thread.sleep(random.nextInt(1000));
if (random.nextInt(2) == 1) {
throw new RuntimeException("biz exception");
}
} catch (BlockException e1) {
// block
Thread.sleep(random.nextInt(1000));
} catch (Exception e2) {
// biz exception
Tracer.trace(e2);
} finally {
if (entry != null) {
entry.exit();
}
}
}
}

private static void initFlowQpsRule() {
List<FlowRule> rules = new ArrayList<>();
FlowRule rule1 = new FlowRule();
rule1.setResource("resource1");
rule1.setCount(1);
rule1.setGrade(RuleConstant.FLOW_GRADE_QPS);
rule1.setLimitApp("default");
rules.add(rule1);
FlowRuleManager.loadRules(rules);
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
package com.alibaba.csp.sentinel.metric.extension.prometheus;

import java.util.List;

import com.alibaba.csp.sentinel.metric.extension.MetricExtension;
import com.alibaba.csp.sentinel.metric.extension.MetricExtensionProvider;
import com.alibaba.csp.sentinel.slots.block.flow.FlowException;

import io.prometheus.client.Collector.MetricFamilySamples;
import io.prometheus.client.Counter;
import io.prometheus.client.Gauge;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;

public class PrometheusMetricExtensionTest {

private String r = "resource1";
private PrometheusMetricExtension p;

@Before
public void before() {
for (MetricExtension extension : MetricExtensionProvider.getMetricExtensions()) {
if (extension instanceof PrometheusMetricExtension) {
p = (PrometheusMetricExtension)extension;
break;
}
}
if (p == null) {
p = new PrometheusMetricExtension();
}
}

@Test
public void addPass() {
p.getPassRequests().clear();
int n = 4;
p.addPass(r, n);
Counter requests = p.getPassRequests();
List<MetricFamilySamples> collect = requests.collect();
double value = collect.get(0).samples.get(0).value;
Assert.assertEquals(n, value, 0.001);
}

@Test
public void addBlock() {
p.getBlockRequests().clear();
int n = 5;
p.addBlock(r, n, "origin1", new FlowException("default"));
Counter requests = p.getBlockRequests();
List<MetricFamilySamples> collect = requests.collect();
double value = collect.get(0).samples.get(0).value;
Assert.assertEquals(n, value, 0.001);
}

@Test
public void addSuccess() {
p.getSuccessRequests().clear();
int n = 6;
p.addSuccess(r, n);
Counter requests = p.getSuccessRequests();
List<MetricFamilySamples> collect = requests.collect();
double value = collect.get(0).samples.get(0).value;
Assert.assertEquals(n, value, 0.001);
}

@Test
public void addException() {
p.getExceptionRequests().clear();
int n = 7;
p.addException(r, n, new RuntimeException("bizException"));
Counter requests = p.getExceptionRequests();
List<MetricFamilySamples> collect = requests.collect();
double value = collect.get(0).samples.get(0).value;
Assert.assertEquals(n, value, 0.001);
}

@Test
public void increaseThreadNum() {
p.getCurrentThreads().clear();
p.increaseThreadNum(r);
p.increaseThreadNum(r);
p.increaseThreadNum(r);
p.increaseThreadNum(r);
Gauge threads = p.getCurrentThreads();
List<MetricFamilySamples> collect = threads.collect();
double value = collect.get(0).samples.get(0).value;
Assert.assertEquals(4, value, 0.001);
}

@Test
public void decreaseThreadNum() {
p.getCurrentThreads().clear();
p.increaseThreadNum(r);
p.increaseThreadNum(r);
p.increaseThreadNum(r);
p.increaseThreadNum(r);

p.decreaseThreadNum(r);
Gauge threads = p.getCurrentThreads();
List<MetricFamilySamples> collect = threads.collect();
double value = collect.get(0).samples.get(0).value;
Assert.assertEquals(3, value, 0.001);
}
}