Browse Source

Add support for compression

pull/1/head
Fredrik Ekre 2 years ago
parent
commit
18c26b749c
  1. 4
      Project.toml
  2. 48
      src/Prometheus.jl
  3. 15
      test/runtests.jl

4
Project.toml

@ -3,11 +3,15 @@ uuid = "f25c1797-fe98-4e0c-b252-1b4fe3b6bde6" @@ -3,11 +3,15 @@ uuid = "f25c1797-fe98-4e0c-b252-1b4fe3b6bde6"
version = "1.0.0"
[deps]
CodecZlib = "944b1d66-785c-5afd-91f1-9de20f533193"
HTTP = "cd3eb016-35fb-5094-929b-558a96fad6f3"
SimpleBufferStream = "777ac1f9-54b0-4bf8-805c-2214025038e7"
Sockets = "6462fe0b-24de-5631-8697-dd941f90decc"
[compat]
CodecZlib = "0.7"
HTTP = "1"
SimpleBufferStream = "1"
Sockets = "1.6"
julia = "1.6"

48
src/Prometheus.jl

@ -1,6 +1,8 @@ @@ -1,6 +1,8 @@
module Prometheus
using CodecZlib: GzipCompressorStream
using HTTP: HTTP
using SimpleBufferStream: BufferStream
using Sockets: Sockets
abstract type Collector end
@ -50,6 +52,9 @@ if !isdefined(Base, Symbol("@atomic")) # v1.7.0 @@ -50,6 +52,9 @@ if !isdefined(Base, Symbol("@atomic")) # v1.7.0
end
end
end
if !isdefined(Base, :eachsplit) # v1.8.0
const eachsplit = split
end
#####################
@ -505,24 +510,55 @@ end @@ -505,24 +510,55 @@ end
const CONTENT_TYPE_LATEST = "text/plain; version=0.0.4; charset=utf-8"
function gzip_accepted(http::HTTP.Stream)
accept_encoding = HTTP.header(http.message, "Accept-Encoding")
for enc in eachsplit(accept_encoding, ',')
if lowercase(strip(first(eachsplit(enc, ';')))) == "gzip"
return true
end
end
return false
end
"""
expose(http::HTTP.Stream, reg::CollectorRegistry = DEFAULT_REGISTRY)
expose(http::HTTP.Stream, reg::CollectorRegistry = DEFAULT_REGISTRY; kwargs...)
Export all metrics in `reg` by writing them to the HTTP stream `http`.
The caller is responsible for checking e.g. the HTTP method and URI target. For
HEAD requests this method do not write a body, however.
"""
function expose(http::HTTP.Stream, reg::CollectorRegistry = DEFAULT_REGISTRY)
# TODO: Handle Accept request header
# TODO: Compression if requested/supported
function expose(http::HTTP.Stream, reg::CollectorRegistry = DEFAULT_REGISTRY; compress::Bool=true)
# TODO: Handle Accept request header for different formats?
# Compress by default if client supports it and user haven't disabled it
if compress
compress = gzip_accepted(http)
end
# Create the response
HTTP.setstatus(http, 200)
HTTP.setheader(http, "Content-Type" => CONTENT_TYPE_LATEST)
if compress
HTTP.setheader(http, "Content-Encoding" => "gzip")
end
HTTP.startwrite(http)
# The user is repsonsible for making sure that e.g. target and method is
# The user is responsible for making sure that e.g. target and method is
# correct, but at least we skip writing the body for HEAD requests.
if http.message.method != "HEAD"
expose_io(http, reg)
if compress
buf = BufferStream()
gzstream = GzipCompressorStream(buf)
tsk = @async try
expose_io(gzstream, reg)
finally
# Close the compressor stream to free resources in zlib and
# to let the write(http, buf) below finish.
close(gzstream)
end
write(http, buf)
wait(tsk)
else
expose_io(http, reg)
end
end
return
end

15
test/runtests.jl

@ -323,6 +323,8 @@ end @@ -323,6 +323,8 @@ end
return Prometheus.expose(http)
elseif http.message.target == "/metrics/reg"
return Prometheus.expose(http, Prometheus.DEFAULT_REGISTRY)
elseif http.message.target == "/metrics/nogzip"
return Prometheus.expose(http; compress=false)
else
HTTP.setstatus(http, 404)
HTTP.startwrite(http)
@ -340,6 +342,19 @@ end @@ -340,6 +342,19 @@ end
# Bad URI
r_bad = HTTP.request("GET", "http://localhost:8123"; status_exception=false)
@test r_bad.status == 404
# Compression
for enc in ("gzip", "br, compress, gzip", "br;q=1.0, gzip;q=0.8, *;q=0.1")
r_gzip = HTTP.request(
"GET", "http://localhost:8123/metrics/default", ["Accept-Encoding" => enc]
)
@test HTTP.header(r_gzip, "Content-Encoding") == "gzip"
@test String(r_gzip.body) == reference_output # HTTP.jl decompresses gzip
r_nogzip = HTTP.request(
"GET", "http://localhost:8123/metrics/nogzip", ["Accept-Encoding" => enc]
)
@test HTTP.header(r_nogzip, "Content-Encoding") != "gzip"
@test String(r_nogzip.body) == reference_output # HTTP.jl decompresses gzip
end
# Clean up
close(server)
wait(server)

Loading…
Cancel
Save