Browse Source

Family{C}: use n-tuples for label names and values.

pull/4/head
Fredrik Ekre 2 years ago
parent
commit
daa23c3ea6
  1. 4
      docs/src/index.md
  2. 32
      src/Prometheus.jl
  3. 16
      src/gc_collector.jl
  4. 6
      src/process_collector.jl
  5. 28
      test/runtests.jl

4
docs/src/index.md

@ -167,8 +167,8 @@ See <https://prometheus.io/docs/concepts/data_model/#metric-names-and-labels> fo
```@docs ```@docs
Prometheus.Family{C}(::String, ::String, ::Any; kwargs...) where C Prometheus.Family{C}(::String, ::String, ::Any; kwargs...) where C
Prometheus.labels(::Prometheus.Family, ::Vector{String}) Prometheus.labels(::Prometheus.Family{C, N}, ::NTuple{N, String}) where {C, N}
Prometheus.remove(::Prometheus.Family, ::Vector{String}) Prometheus.remove(::Prometheus.Family{C, N}, ::NTuple{N, String}) where {C, N}
Prometheus.clear(::Prometheus.Family) Prometheus.clear(::Prometheus.Family)
``` ```

32
src/Prometheus.jl

@ -355,12 +355,12 @@ end
# Family{<:Collector} <: Collector # # Family{<:Collector} <: Collector #
#################################### ####################################
struct LabelNames struct LabelNames{N}
labelnames::Vector{String} labelnames::NTuple{N, String}
end end
struct LabelValues struct LabelValues{N}
labelvalues::Vector{String} labelvalues::NTuple{N, String}
end end
function Base.hash(l::LabelValues, h::UInt) function Base.hash(l::LabelValues, h::UInt)
h = hash(0x94a2d04ee9e5a55b, h) # hash("Prometheus.LabelValues") on Julia 1.9.3 h = hash(0x94a2d04ee9e5a55b, h) # hash("Prometheus.LabelValues") on Julia 1.9.3
@ -373,20 +373,20 @@ function Base.:(==)(l1::LabelValues, l2::LabelValues)
return l1.labelvalues == l2.labelvalues return l1.labelvalues == l2.labelvalues
end end
struct Family{C} <: Collector struct Family{C, N} <: Collector
metric_name::String metric_name::String
help::String help::String
labelnames::LabelNames labelnames::LabelNames{N}
children::Dict{LabelValues, C} children::Dict{LabelValues{N}, C}
lock::ReentrantLock lock::ReentrantLock
function Family{C}( function Family{C}(
metric_name::String, help::String, labelnames::Vector{String}; metric_name::String, help::String, labelnames::NTuple{N, String};
registry::Union{CollectorRegistry, Nothing}=DEFAULT_REGISTRY, registry::Union{CollectorRegistry, Nothing}=DEFAULT_REGISTRY,
) where C ) where {C, N}
children = Dict{LabelValues, C}() children = Dict{LabelValues{N}, C}()
lock = ReentrantLock() lock = ReentrantLock()
family = new(metric_name, help, LabelNames(labelnames), children, lock) family = new{C, N}(metric_name, help, LabelNames(labelnames), children, lock)
if registry !== nothing if registry !== nothing
register(registry, family) register(registry, family)
end end
@ -403,7 +403,7 @@ label values encountered a new collector of type `C <: Collector` will be create
**Arguments** **Arguments**
- `name :: String`: the name of the family metric. - `name :: String`: the name of the family metric.
- `help :: String`: the documentation for the family metric. - `help :: String`: the documentation for the family metric.
- `labelnames :: Vector{String}`: the label names. - `labelnames :: Tuple{String, ...}`: the label names.
**Keyword arguments** **Keyword arguments**
- `registry :: Prometheus.CollectorRegistry`: the registry in which to register the - `registry :: Prometheus.CollectorRegistry`: the registry in which to register the
@ -433,7 +433,7 @@ function metric_names(family::Family)
end end
""" """
Prometheus.labels(family::Family{C}, labelvalues::Vector{String}) where C Prometheus.labels(family::Family{C}, labelvalues::Tuple{String, ...}) where C
Return the collector of type `C` from the family corresponding to the labels given by Return the collector of type `C` from the family corresponding to the labels given by
`labelvalues`. `labelvalues`.
@ -444,7 +444,7 @@ Return the collector of type `C` from the family corresponding to the labels giv
matter (below 100ns for some basic benchmarks) but it is safe to cache the returned matter (below 100ns for some basic benchmarks) but it is safe to cache the returned
collector if required. collector if required.
""" """
function labels(family::Family{C}, labelvalues::Vector{String}) where C function labels(family::Family{C, N}, labelvalues::NTuple{N, String}) where {C, N}
collector = @lock family.lock get!(family.children, LabelValues(labelvalues)) do collector = @lock family.lock get!(family.children, LabelValues(labelvalues)) do
C(family.metric_name, family.help; registry=nothing) C(family.metric_name, family.help; registry=nothing)
end end
@ -452,7 +452,7 @@ function labels(family::Family{C}, labelvalues::Vector{String}) where C
end end
""" """
Prometheus.remove(family::Family, labelvalues::Vector{String}) Prometheus.remove(family::Family, labelvalues::Tuple{String, ...})
Remove the collector corresponding to `labelvalues`. Effectively this resets the collector Remove the collector corresponding to `labelvalues`. Effectively this resets the collector
since [`Prometheus.labels`](@ref) will recreate the collector when called with the same since [`Prometheus.labels`](@ref) will recreate the collector when called with the same
@ -461,7 +461,7 @@ label names.
!!! note !!! note
This method invalidates cached collectors for the label names. This method invalidates cached collectors for the label names.
""" """
function remove(family::Family, labelvalues::Vector{String}) function remove(family::Family{<:Any, N}, labelvalues::NTuple{N, String}) where N
@lock family.lock delete!(family.children, LabelValues(labelvalues)) @lock family.lock delete!(family.children, LabelValues(labelvalues))
return return
end end

16
src/gc_collector.jl

@ -46,12 +46,12 @@ function collect!(metrics::Vector, ::GCCollector)
push!(metrics, push!(metrics,
Metric( Metric(
"counter", "julia_gc_alloc_total", "Total number of allocations (calls to malloc, realloc, etc)", "counter", "julia_gc_alloc_total", "Total number of allocations (calls to malloc, realloc, etc)",
LabelNames(["type"]), LabelNames(("type",)),
[ [
Sample(nothing, LabelValues(["bigalloc"]), gc_num.bigalloc), Sample(nothing, LabelValues(("bigalloc",)), gc_num.bigalloc),
Sample(nothing, LabelValues(["malloc"]), gc_num.malloc), Sample(nothing, LabelValues(("malloc",)), gc_num.malloc),
Sample(nothing, LabelValues(["poolalloc"]), gc_num.poolalloc), Sample(nothing, LabelValues(("poolalloc",)), gc_num.poolalloc),
Sample(nothing, LabelValues(["realloc"]), gc_num.realloc), Sample(nothing, LabelValues(("realloc",)), gc_num.realloc),
], ],
), ),
Metric( Metric(
@ -72,10 +72,10 @@ function collect!(metrics::Vector, ::GCCollector)
), ),
Metric( Metric(
"counter", "julia_gc_collections_total", "Total number of calls to garbage collection", "counter", "julia_gc_collections_total", "Total number of calls to garbage collection",
LabelNames(["type"]), LabelNames(("type",)),
[ [
Sample(nothing, LabelValues(["full"]), gc_num.full_sweep), Sample(nothing, LabelValues(("full",)), gc_num.full_sweep),
Sample(nothing, LabelValues(["minor"]), gc_num.pause - gc_num.full_sweep), Sample(nothing, LabelValues(("minor",)), gc_num.pause - gc_num.full_sweep),
], ],
), ),
) )

6
src/process_collector.jl

@ -121,10 +121,10 @@ function collect!(metrics::Vector, procc::ProcessCollector)
proc_cpu_seconds = Metric( proc_cpu_seconds = Metric(
"counter", "process_cpu_seconds_total", "counter", "process_cpu_seconds_total",
"Total CPU time (user and system mode) in seconds.", "Total CPU time (user and system mode) in seconds.",
LabelNames(["mode"]), LabelNames(("mode",)),
[ [
Sample(nothing, LabelValues(["system"]), stime), Sample(nothing, LabelValues(("system",)), stime),
Sample(nothing, LabelValues(["user"]), utime), Sample(nothing, LabelValues(("user",)), utime),
], ],
) )
push!(metrics, proc_cpu_seconds) push!(metrics, proc_cpu_seconds)

28
test/runtests.jl

@ -151,9 +151,9 @@ end
@testset "Prometheus.LabelNames and Prometheus.LabelValues" begin @testset "Prometheus.LabelNames and Prometheus.LabelValues" begin
# Custom hashing # Custom hashing
v1 = Prometheus.LabelValues(["foo", "bar"]) v1 = Prometheus.LabelValues(("foo", "bar"))
v2 = Prometheus.LabelValues(["foo", "bar"]) v2 = Prometheus.LabelValues(("foo", "bar"))
v3 = Prometheus.LabelValues(["foo", "baz"]) v3 = Prometheus.LabelValues(("foo", "baz"))
@test hash(v1) == hash(v2) @test hash(v1) == hash(v2)
@test hash(v1) != hash(v3) @test hash(v1) != hash(v3)
@test v1 == v2 @test v1 == v2
@ -167,20 +167,20 @@ end
empty!(Prometheus.DEFAULT_REGISTRY.collectors) empty!(Prometheus.DEFAULT_REGISTRY.collectors)
c = Prometheus.Family{Collector}( c = Prometheus.Family{Collector}(
"http_requests", "Number of HTTP requests.", "http_requests", "Number of HTTP requests.",
["endpoint", "status_code"], ("endpoint", "status_code"),
) )
@test c in Prometheus.DEFAULT_REGISTRY.collectors @test c in Prometheus.DEFAULT_REGISTRY.collectors
r = Prometheus.CollectorRegistry() r = Prometheus.CollectorRegistry()
c = Prometheus.Family{Collector}( c = Prometheus.Family{Collector}(
"http_requests", "Number of HTTP requests.", "http_requests", "Number of HTTP requests.",
["endpoint", "status_code"]; ("endpoint", "status_code");
registry = r, registry = r,
) )
@test c in r.collectors @test c in r.collectors
@test length(c.children) == 0 @test length(c.children) == 0
# Prometheus.labels(...), Prometheus.remove(...), Prometheus.clear() # Prometheus.labels(...), Prometheus.remove(...), Prometheus.clear()
l1 = ["/foo/", "200"] l1 = ("/foo/", "200")
l2 = ["/bar/", "404"] l2 = ("/bar/", "404")
@test Prometheus.labels(c, l1) === Prometheus.labels(c, l1) @test Prometheus.labels(c, l1) === Prometheus.labels(c, l1)
@test Prometheus.labels(c, l2) === Prometheus.labels(c, l2) @test Prometheus.labels(c, l2) === Prometheus.labels(c, l2)
@test length(c.children) == 2 @test length(c.children) == 2
@ -207,8 +207,8 @@ end
@test metric.help == c.help @test metric.help == c.help
@test length(metric.samples) == 2 @test length(metric.samples) == 2
s1, s2 = metric.samples[1], metric.samples[2] s1, s2 = metric.samples[1], metric.samples[2]
@test s1.labels.labelvalues == ["/bar/", "404"] @test s1.labels.labelvalues == ("/bar/", "404")
@test s2.labels.labelvalues == ["/foo/", "200"] @test s2.labels.labelvalues == ("/foo/", "200")
@test s1.value == 3 @test s1.value == 3
@test s2.value == 3 @test s2.value == 3
# Prometheus.expose_metric(...) # Prometheus.expose_metric(...)
@ -227,14 +227,14 @@ end
r = Prometheus.CollectorRegistry() r = Prometheus.CollectorRegistry()
c = Prometheus.Family{Prometheus.Summary}( c = Prometheus.Family{Prometheus.Summary}(
"http_request_time", "Time to process requests.", "http_request_time", "Time to process requests.",
["endpoint", "status_code"]; ("endpoint", "status_code");
registry = r, registry = r,
) )
@test c in r.collectors @test c in r.collectors
@test length(c.children) == 0 @test length(c.children) == 0
# Prometheus.inc(...) # Prometheus.inc(...)
l1 = ["/foo/", "200"] l1 = ("/foo/", "200")
l2 = ["/bar/", "404"] l2 = ("/bar/", "404")
@test Prometheus.labels(c, l1) === Prometheus.labels(c, l1) @test Prometheus.labels(c, l1) === Prometheus.labels(c, l1)
@test Prometheus.labels(c, l2) === Prometheus.labels(c, l2) @test Prometheus.labels(c, l2) === Prometheus.labels(c, l2)
@test length(c.children) == 2 @test length(c.children) == 2
@ -262,8 +262,8 @@ end
@test metric.help == c.help @test metric.help == c.help
@test length(metric.samples) == 4 @test length(metric.samples) == 4
s1, s2, s3, s4 = metric.samples s1, s2, s3, s4 = metric.samples
@test s1.labels.labelvalues == s2.labels.labelvalues == ["/bar/", "404"] @test s1.labels.labelvalues == s2.labels.labelvalues == ("/bar/", "404")
@test s3.labels.labelvalues == s4.labels.labelvalues == ["/foo/", "200"] @test s3.labels.labelvalues == s4.labels.labelvalues == ("/foo/", "200")
@test s1.value == 2 # _count @test s1.value == 2 # _count
@test s2.value == 6.4 # _sum @test s2.value == 6.4 # _sum
@test s3.value == 2 # _count @test s3.value == 2 # _count

Loading…
Cancel
Save