Current section
Files
Jump to
Current section
Files
lib/metric/counter.ex
# Copyright 2024 Clivern. All rights reserved.
# Use of this source code is governed by the MIT
# license that can be found in the LICENSE file.
defmodule Oak.Metric.Counter do
@moduledoc """
Represents a Counter metric.
A Counter is a cumulative metric that represents a single monotonically
increasing counter whose value can only increase or be reset to zero.
"""
defstruct [:name, :help, :labels, :value]
@doc """
Creates a new Counter metric.
## Parameters
* `name` - The name of the counter
* `help` - The help text of the counter
* `labels` - The labels of the counter
"""
def new(name, help, labels \\ %{}) do
if name == "" or help == "" do
raise "name and help cannot be empty"
end
%__MODULE__{
name: name,
help: help,
labels: labels,
value: 0
}
end
@doc """
Increments the counter by the given amount.
## Parameters
* `counter` - The counter to increment
* `amount` - The amount to increment by (defaults to 1)
"""
def inc(counter, amount \\ 1) when is_integer(amount) and amount >= 0 do
%{counter | value: counter.value + amount}
end
@doc """
Set the counter value
## Parameters
* `counter` - The counter to set
* `value` - The value to set (defaults to 1)
"""
def set(counter, value \\ 1) when is_integer(value) and value >= 0 do
%{counter | value: value}
end
@doc """
Returns the current value of the counter
## Parameters
* `counter` - The counter to get the value from
"""
def value(counter), do: counter.value
@doc """
Resets the counter to zero
## Parameters
* `counter` - The counter to reset
"""
def reset(counter) do
%{counter | value: 0}
end
@doc """
Returns the id of the counter
## Parameters
* `counter` - The counter to get the id from
"""
def id(counter),
do:
"#{counter.name}|#{format_labels(counter.labels)}"
|> String.replace(" ", "")
|> String.downcase()
defp format_labels(labels) when is_map(labels) and map_size(labels) == 0, do: ""
defp format_labels(labels) when is_map(labels) do
labels
|> Enum.sort_by(fn {key, _value} -> key end)
|> Enum.map(fn {key, value} -> "#{key}_#{value}" end)
|> Enum.join(",")
end
@doc """
Returns a string representation of the counter in Prometheus exposition format
## Parameters
* `counter` - The counter to convert to a string
"""
def to_string(counter) do
labels_str =
counter.labels
|> Enum.sort_by(fn {key, _value} -> key end)
|> Enum.map(fn {key, value} -> "#{key}=\"#{value}\"" end)
|> Enum.join(",")
labels_formatted = if labels_str == "", do: "", else: "{#{labels_str}}"
"""
# HELP #{counter.name} #{counter.help}
# TYPE #{counter.name} counter
#{counter.name}#{labels_formatted} #{counter.value}
"""
end
end