Skip to content

Instantly share code, notes, and snippets.

@gesellix
Last active December 16, 2015 12:49
Show Gist options
  • Save gesellix/d8bae86dce6f22c91dbc to your computer and use it in GitHub Desktop.
Save gesellix/d8bae86dce6f22c91dbc to your computer and use it in GitHub Desktop.
A Spring PublicMetrics ExpositionHook for Prometheus
compile 'io.prometheus:client:0.0.8'
compile 'com.matttproud.accepts:accepts:0.0.2'
compile 'args4j:args4j:2.0.16'
package de.gesellix.example
import com.matttproud.accepts.Accept
import com.matttproud.accepts.Parser
import io.prometheus.client.Prometheus
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.ResponseStatus
import org.springframework.web.bind.annotation.RestController
import javax.annotation.PostConstruct
import javax.servlet.http.HttpServletRequest
import javax.servlet.http.HttpServletResponse
import static org.springframework.http.HttpStatus.OK
import static org.springframework.web.bind.annotation.RequestMethod.GET
@RestController
class ExampleMetricsService {
@Autowired
SpringBootMetricsExpositionHook springBootMetricsExpositionHook
@PostConstruct
def init() {
Prometheus.defaultInitialize()
Prometheus.defaultAddPreexpositionHook(springBootMetricsExpositionHook)
}
@RequestMapping(value = "/prom", method = GET)
@ResponseStatus(OK)
def metrics(HttpServletRequest request, HttpServletResponse response) throws IOException {
boolean dispensed = false
try {
for (final Accept spec : Parser.parse(request)) {
if ("application".equals(spec.getType()) && "vnd.google.protobuf".equals(spec.getSubtype())) {
final Map<String, String> params = spec.getParams()
if ("io.prometheus.client.MetricFamily".equals(params.get("proto"))
&& "delimited".equals(params.get("encoding"))) {
dumpProto(response)
dispensed = true
break
}
}
}
}
catch (final IllegalArgumentException ignore) {
}
finally {
dispensed || dumpJson(response)
}
}
def dumpJson(final HttpServletResponse resp) throws IOException {
resp.setContentType("application/json; schema=\"prometheus/telemetry\"; version=0.0.2")
Prometheus.defaultDumpJson(resp.getWriter())
}
def dumpProto(final HttpServletResponse resp) throws IOException {
resp.setContentType("application/vnd.google.protobuf; proto=\"io.prometheus.client.MetricFamily\"; encoding=\"delimited\"")
final BufferedOutputStream buf = new BufferedOutputStream(resp.getOutputStream())
Prometheus.defaultDumpProto(buf)
buf.close()
}
}
package de.gesellix.example
import io.prometheus.client.Prometheus
import io.prometheus.client.metrics.Gauge
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.actuate.endpoint.PublicMetrics
import org.springframework.boot.actuate.endpoint.VanillaPublicMetrics
import org.springframework.boot.actuate.metrics.Metric
import org.springframework.boot.actuate.metrics.reader.MetricReader
import org.springframework.boot.actuate.metrics.repository.InMemoryMetricRepository
import org.springframework.stereotype.Component
import javax.annotation.PostConstruct
@Component
class SpringBootMetricsExpositionHook implements Prometheus.ExpositionHook {
@Autowired
def MetricReader metricRepository = new InMemoryMetricRepository()
def PublicMetrics metrics
def static final Gauge publicMetrics = Gauge.newBuilder()
.namespace("spring")
.name("metrics")
.labelNames("name")
.documentation("All Spring public metrics")
.build()
@PostConstruct
def init() {
metrics = new VanillaPublicMetrics(metricRepository)
}
@Override
void run() {
for (Metric<? extends Number> metric : metrics.metrics()) {
publicMetrics.newPartial()
.labelPair("name", metric.getName())
.apply()
.set(metric.getValue().doubleValue())
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment