-
Notifications
You must be signed in to change notification settings - Fork 805
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #100 from prometheus/graphite
Add graphite bridge.
- Loading branch information
Showing
4 changed files
with
229 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
<?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>io.prometheus</groupId> | ||
<artifactId>parent</artifactId> | ||
<version>0.0.13-SNAPSHOT</version> | ||
</parent> | ||
|
||
<groupId>io.prometheus</groupId> | ||
<artifactId>simpleclient_graphite_bridge</artifactId> | ||
<packaging>bundle</packaging> | ||
|
||
<name>Prometheus Java Simpleclient Graphite Bridge</name> | ||
<description> | ||
Graphite bridge for the simpleclient. | ||
</description> | ||
|
||
<licenses> | ||
<license> | ||
<name>The Apache Software License, Version 2.0</name> | ||
<url>http://www.apache.org/licenses/LICENSE-2.0.txt</url> | ||
<distribution>repo</distribution> | ||
</license> | ||
</licenses> | ||
|
||
<developers> | ||
<developer> | ||
<id>brian-brazil</id> | ||
<name>Brian Brazil</name> | ||
<email>[email protected]</email> | ||
</developer> | ||
</developers> | ||
|
||
|
||
<dependencies> | ||
<dependency> | ||
<groupId>io.prometheus</groupId> | ||
<artifactId>simpleclient</artifactId> | ||
<version>0.0.13-SNAPSHOT</version> | ||
</dependency> | ||
<!-- Test Dependencies Follow --> | ||
<dependency> | ||
<groupId>junit</groupId> | ||
<artifactId>junit</artifactId> | ||
<version>4.11</version> | ||
<scope>test</scope> | ||
</dependency> | ||
</dependencies> | ||
</project> |
120 changes: 120 additions & 0 deletions
120
simpleclient_graphite_bridge/src/main/java/io/prometheus/client/bridge/Graphite.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,120 @@ | ||
package io.prometheus.client.bridge; | ||
|
||
import io.prometheus.client.Collector; | ||
import io.prometheus.client.CollectorRegistry; | ||
|
||
import java.io.BufferedWriter; | ||
import java.io.IOException; | ||
import java.io.PrintWriter; | ||
import java.net.Socket; | ||
import java.util.Collections; | ||
import java.util.logging.Level; | ||
import java.util.logging.Logger; | ||
import java.util.regex.Pattern; | ||
import java.util.regex.Matcher; | ||
|
||
/** | ||
* Export metrics in the Graphite plaintext format. | ||
* <p> | ||
* <pre> | ||
* {@code | ||
* Graphite g = new Graphite("localhost", 2003); | ||
* // Push the default registry once. | ||
* g.push(CollectorRegistry.defaultRegistry); | ||
* | ||
* // Push the default registry every 60 seconds. | ||
* Thread thread = g.start(CollectorRegistry.defaultRegistry, 60); | ||
* // Stop pushing. | ||
* thread.interrupt(); | ||
* thread.joi(); | ||
* } | ||
* </pre> | ||
* <p> | ||
* See <a href="https://github.com/prometheus/pushgateway">https://github.com/prometheus/pushgateway</a> | ||
*/ | ||
public class Graphite { | ||
private static final Logger logger = Logger.getLogger(Graphite.class.getName()); | ||
|
||
private final String host; | ||
private final int port; | ||
private static final Pattern INVALID_GRAPHITE_CHARS = Pattern.compile("[^a-zA-Z0-9_-]"); | ||
/** | ||
* Construct a Graphite Bridge with the given host:port. | ||
*/ | ||
public Graphite(String host, int port) { | ||
this.host = host; | ||
this.port = port; | ||
} | ||
|
||
/** | ||
* Push samples from the given registry to Graphite. | ||
*/ | ||
public void push(CollectorRegistry registry) throws IOException { | ||
Socket s = new Socket(host, port); | ||
BufferedWriter writer = new BufferedWriter(new PrintWriter(s.getOutputStream())); | ||
Matcher m = INVALID_GRAPHITE_CHARS.matcher(""); | ||
long now = System.currentTimeMillis() / 1000; | ||
for (Collector.MetricFamilySamples metricFamilySamples: Collections.list(registry.metricFamilySamples())) { | ||
for (Collector.MetricFamilySamples.Sample sample: metricFamilySamples.samples) { | ||
m.reset(sample.name); | ||
writer.write(m.replaceAll("_")); | ||
for (int i = 0; i < sample.labelNames.size(); ++i) { | ||
m.reset(sample.labelValues.get(i)); | ||
writer.write("." + sample.labelNames.get(i) + "." + m.replaceAll("_")); | ||
} | ||
writer.write(" " + sample.value + " " + now + "\n"); | ||
} | ||
} | ||
writer.close(); | ||
s.close(); | ||
} | ||
|
||
/** | ||
* Push samples from the given registry to Graphite every minute. | ||
*/ | ||
public Thread start(CollectorRegistry registry) { | ||
return start(registry, 60); | ||
} | ||
|
||
/** | ||
* Push samples from the given registry to Graphite at the given interval. | ||
*/ | ||
public Thread start(CollectorRegistry registry, int intervalSeconds) { | ||
Thread thread = new PushThread(registry, intervalSeconds); | ||
thread.setDaemon(true); | ||
thread.start(); | ||
return thread; | ||
} | ||
|
||
private class PushThread extends Thread { | ||
private final CollectorRegistry registry; | ||
private final int intervalSeconds; | ||
|
||
PushThread(CollectorRegistry registry, int intervalSeconds) { | ||
this.registry = registry; | ||
this.intervalSeconds = intervalSeconds; | ||
} | ||
|
||
public void run() { | ||
long waitUntil = System.currentTimeMillis(); | ||
while (true) { | ||
try { | ||
push(registry); | ||
} catch (IOException e) { | ||
logger.log(Level.WARNING, "Exception " + e + " pushing to " + host + ":" + port, e); | ||
} | ||
|
||
long now = System.currentTimeMillis(); | ||
// We may skip some pushes if we're falling behind. | ||
while (now >= waitUntil) { | ||
waitUntil += intervalSeconds * 1000; | ||
} | ||
try { | ||
Thread.sleep(waitUntil - now); | ||
} catch (InterruptedException e) { | ||
return; | ||
} | ||
} | ||
} | ||
} | ||
} |
57 changes: 57 additions & 0 deletions
57
simpleclient_graphite_bridge/src/test/java/io/prometheus/client/bridge/GraphiteTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
package io.prometheus.client.bridge; | ||
|
||
import static org.junit.Assert.assertEquals; | ||
import static org.junit.Assert.fail; | ||
|
||
import org.junit.Test; | ||
|
||
import io.prometheus.client.CollectorRegistry; | ||
import io.prometheus.client.Gauge; | ||
|
||
import java.io.BufferedReader; | ||
import java.io.IOException; | ||
import java.io.InputStreamReader; | ||
import java.net.ServerSocket; | ||
import java.net.Socket; | ||
|
||
public class GraphiteTest { | ||
@Test | ||
public void testPush() throws Exception { | ||
// Create a metric. | ||
CollectorRegistry registry = new CollectorRegistry(); | ||
Gauge labels = Gauge.build().name("labels").help("help").labelNames("l").register(registry); | ||
labels.labels("fo*o").inc(); | ||
|
||
|
||
// Server to accept push. | ||
final ServerSocket ss = new ServerSocket(0); | ||
final StringBuilder result = new StringBuilder(); | ||
Thread t = new Thread() { | ||
public void run() { | ||
try { | ||
Socket s = ss.accept(); | ||
BufferedReader reader = new BufferedReader(new InputStreamReader(s.getInputStream())); | ||
result.append(reader.readLine()); | ||
s.close(); | ||
} catch (Exception e) { | ||
e.printStackTrace(); | ||
fail(); | ||
} | ||
} | ||
}; | ||
t.start(); | ||
|
||
// Push. | ||
Graphite g = new Graphite("localhost", ss.getLocalPort()); | ||
g.push(registry); | ||
t.join(); | ||
ss.close(); | ||
|
||
// Check result. | ||
String[] parts = result.toString().split(" "); | ||
assertEquals(3, parts.length); | ||
assertEquals("labels.l.fo_o", parts[0]); | ||
assertEquals("1.0", parts[1]); | ||
Integer.parseInt(parts[2]); // This shouldn't throw an exception. | ||
} | ||
} |