Skip to content

Commit 682e5ec

Browse files
committed
Add basic openmetrics exposition
Signed-off-by: Brian Brazil <brian.brazil@robustperception.io>
1 parent a4dd93b commit 682e5ec

File tree

4 files changed

+49
-7
lines changed

4 files changed

+49
-7
lines changed

prometheus_client/exposition.py

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
from wsgiref.simple_server import make_server, WSGIRequestHandler
1212

1313
from . import core
14+
import openmetrics.exposition
1415
try:
1516
from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer
1617
from SocketServer import ThreadingMixIn
@@ -36,12 +37,13 @@ def make_wsgi_app(registry=core.REGISTRY):
3637
def prometheus_app(environ, start_response):
3738
params = parse_qs(environ.get('QUERY_STRING', ''))
3839
r = registry
40+
encoder, content_type = choose_encoder(environ.get['HTTP_ACCEPT'])
3941
if 'name[]' in params:
4042
r = r.restricted_registry(params['name[]'])
41-
output = generate_latest(r)
43+
output = encoder(r)
4244

4345
status = str('200 OK')
44-
headers = [(str('Content-type'), CONTENT_TYPE_LATEST)]
46+
headers = [(str('Content-type'), content_type)]
4547
start_response(status, headers)
4648
return [output]
4749
return prometheus_app
@@ -87,22 +89,32 @@ def generate_latest(registry=core.REGISTRY):
8789
return ''.join(output).encode('utf-8')
8890

8991

92+
def choose_encoder(accept_header):
93+
accept_header = accept_header or ''
94+
for accepted in accept_header.split(','):
95+
if accepted == 'text/openmetrics; version=0.0.1':
96+
return (openmetrics.exposition.generate_latest,
97+
openmetrics.exposition.CONTENT_TYPE_LATEST)
98+
return (generate_latest, CONTENT_TYPE_LATEST)
99+
100+
90101
class MetricsHandler(BaseHTTPRequestHandler):
91102
"""HTTP handler that gives metrics from ``core.REGISTRY``."""
92103
registry = core.REGISTRY
93104

94105
def do_GET(self):
95106
registry = self.registry
96107
params = parse_qs(urlparse(self.path).query)
108+
encoder, content_type = choose_encoder(self.headers.get('Accept'))
97109
if 'name[]' in params:
98110
registry = registry.restricted_registry(params['name[]'])
99111
try:
100-
output = generate_latest(registry)
112+
output = encoder(registry)
101113
except:
102114
self.send_error(500, 'error generating metric output')
103115
raise
104116
self.send_response(200)
105-
self.send_header('Content-Type', CONTENT_TYPE_LATEST)
117+
self.send_header('Content-Type', content_type)
106118
self.end_headers()
107119
self.wfile.write(output)
108120

prometheus_client/openmetrics/__init__.py

Whitespace-only changes.
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
#!/usr/bin/python
2+
3+
from __future__ import unicode_literals
4+
5+
from .. import core
6+
7+
CONTENT_TYPE_LATEST = str('text/openmetrics; version=0.0.1; charset=utf-8')
8+
'''Content type of the latest OpenMetrics text format'''
9+
10+
def generate_latest(registry):
11+
'''Returns the metrics from the registry in latest text format as a string.'''
12+
output = []
13+
for metric in registry.collect():
14+
mname = metric.name
15+
output.append('# HELP {0} {1}'.format(
16+
mname, metric.documentation.replace('\\', r'\\').replace('\n', r'\n').replace('"', r'\"')))
17+
output.append('\n# TYPE {0} {1}\n'.format(mname, metric.type))
18+
for name, labels, value in metric.samples:
19+
if labels:
20+
labelstr = '{{{0}}}'.format(','.join(
21+
['{0}="{1}"'.format(
22+
k, v.replace('\\', r'\\').replace('\n', r'\n').replace('"', r'\"'))
23+
for k, v in sorted(labels.items())]))
24+
else:
25+
labelstr = ''
26+
output.append('{0}{1} {2}\n'.format(name, labelstr, core._floatToGoString(value)))
27+
output.append('# EOF\n')
28+
return ''.join(output).encode('utf-8')
29+

prometheus_client/twisted/_exposition.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
from __future__ import absolute_import, unicode_literals
2-
from .. import REGISTRY, generate_latest, CONTENT_TYPE_LATEST
2+
from .. import REGISTRY, exposition
33

44
from twisted.web.resource import Resource
55

@@ -14,5 +14,6 @@ def __init__(self, registry=REGISTRY):
1414
self.registry = registry
1515

1616
def render_GET(self, request):
17-
request.setHeader(b'Content-Type', CONTENT_TYPE_LATEST.encode('ascii'))
18-
return generate_latest(self.registry)
17+
encoder, content_type = exposition.choose_encoder(request.getHeader('Accept'))
18+
request.setHeader(b'Content-Type', content_type.encode('ascii'))
19+
return encoder(self.registry)

0 commit comments

Comments
 (0)