Page MenuHomePhorge

No OneTemporary

Size
14 KB
Referenced Files
None
Subscribers
None
diff --git a/lib/prometheus/error.ex b/lib/prometheus/error.ex
index 749dc22..a2f4a75 100644
--- a/lib/prometheus/error.ex
+++ b/lib/prometheus/error.ex
@@ -1,220 +1,230 @@
defmodule Prometheus.InvalidValueError do
@moduledoc """
Raised when given `value` is invalid i.e. when you pass a negative number to
`Prometheus.Metric.Counter.inc/2`.
"""
defexception [:value, :orig_message]
def message(%{value: value, orig_message: message}) do
"Invalid value: #{inspect(value)} (#{message})."
end
end
defmodule Prometheus.InvalidMetricNameError do
@moduledoc """
Raised when given metric `name` is invalid i.e. can't be represented as printable utf-8
string that matches `^[a-zA-Z_:][a-zA-Z0-9_:]*$` regular expression.
"""
defexception [:name]
def message(%{name: name}) do
"Invalid metric name: #{name}."
end
end
defmodule Prometheus.InvalidMetricLabelsError do
@moduledoc """
Raised when `labels` isn't a list.
"""
defexception [:labels]
def message(%{labels: labels}) do
"Invalid metric labels: #{labels}."
end
end
defmodule Prometheus.InvalidMetricHelpError do
@moduledoc """
Raised when given metric `help` is invalid i.e. isn't a printable utf-8 string.
"""
defexception [:help]
def message(%{help: help}) do
"Invalid metric help: #{help}."
end
end
defmodule Prometheus.InvalidMetricArityError do
@moduledoc """
Raised when metric arity is invalid e.g. counter metric was created with two labels but
only one label value is passed to `Prometheus.Metric.Counter.inc/2`.
"""
defexception [:present, :expected]
def message(%{present: present, expected: expected}) do
"Invalid metric arity: got #{present}, expected #{expected}."
end
end
defmodule Prometheus.UnknownMetricError do
defexception [:registry, :name]
def message(%{registry: registry, name: name}) do
"Unknown metric {registry: #{registry}, name: #{name}}."
end
end
defmodule Prometheus.InvalidLabelNameError do
@moduledoc """
Raised when label `name` is invalid i.e. can't be represented as printable utf-8 string
that matches `^[a-zA-Z_][a-zA-Z0-9_]*$` regular expression or starts with `__`.
Metric can impose further restrictions on label names.
"""
defexception [:name, :orig_message]
def message(%{name: name, orig_message: message}) do
"Invalid label name: #{name} (#{message})."
end
end
defmodule Prometheus.MFAlreadyExistsError do
@moduledoc """
Raised when one tries to create metric in `registry` with `name` it already exists.
"""
defexception [:registry, :name]
def message(%{registry: registry, name: name}) do
"Metric #{registry}:#{name} already exists."
end
end
defmodule Prometheus.NoBucketsError do
@moduledoc """
Raised by histogram constructors when buckets can't be found in spec, or
found value is empty list.
"""
defexception [:buckets]
def message(%{buckets: buckets}) do
"Invalid histogram buckets: #{buckets}."
end
end
defmodule Prometheus.InvalidBucketsError do
@moduledoc """
Raised by histogram constructors when buckets are invalid i.e. not sorted in increasing
order or generator spec is unknown.
"""
defexception [:buckets, :orig_message]
def message(%{buckets: buckets, orig_message: message}) do
buckets = :io_lib.format("~p", [buckets])
"Invalid histogram buckets: #{buckets} (#{message})."
end
end
defmodule Prometheus.InvalidBoundError do
@moduledoc """
Raised by histogram constructors when bucket bound isn't a number.
"""
defexception [:bound]
def message(%{bound: bound}) do
"Invalid histogram bound: #{bound}."
end
end
defmodule Prometheus.MissingMetricSpecKeyError do
@moduledoc """
Raised when required metric `spec` `key` is missing. All metrics
require at least `name` and when metric created `help`.
Metrics can have their specific required keys.
"""
defexception [:key, :spec]
def message(%{key: key}) do
"Required key #{key} is missing from metric spec."
end
end
defmodule Prometheus.InvalidBlockArityError do
@moduledoc """
Raised when fn passed as block has more then 0 arguments
"""
defexception [:args]
def message(%{args: args}) do
insp = Enum.map_join(args, ", ", &inspect/1)
"Fn with arity #{length(args)} (args: #{insp}) passed as block."
end
end
defmodule Prometheus.Error do
@moduledoc false
# credo:disable-for-this-file Credo.Check.Refactor.ABCSize
# credo:disable-for-this-file Credo.Check.Refactor.CyclomaticComplexity
def normalize(erlang_error) do
case erlang_error do
%ErlangError{original: original} ->
case original do
{:invalid_value, value, message} ->
%Prometheus.InvalidValueError{value: value, orig_message: message}
{:invalid_metric_name, name, _message} ->
%Prometheus.InvalidMetricNameError{name: name}
{:invalid_metric_help, help, _message} ->
%Prometheus.InvalidMetricHelpError{help: help}
{:invalid_metric_arity, present, expected} ->
%Prometheus.InvalidMetricArityError{present: present, expected: expected}
{:unknown_metric, registry, name} ->
%Prometheus.UnknownMetricError{registry: registry, name: name}
{:invalid_metric_labels, labels, _message} ->
%Prometheus.InvalidMetricLabelsError{labels: labels}
{:invalid_metric_label_name, name, message} ->
%Prometheus.InvalidLabelNameError{name: name, orig_message: message}
{:mf_already_exists, {registry, name}, _message} ->
%Prometheus.MFAlreadyExistsError{registry: registry, name: name}
{:no_buckets, buckets} ->
%Prometheus.NoBucketsError{buckets: buckets}
{:invalid_buckets, buckets, message} ->
%Prometheus.InvalidBucketsError{
buckets: buckets,
orig_message: message
}
{:invalid_bound, bound} ->
%Prometheus.InvalidBoundError{bound: bound}
{:missing_metric_spec_key, key, spec} ->
%Prometheus.MissingMetricSpecKeyError{key: key, spec: spec}
_ ->
erlang_error
end
_ ->
erlang_error
end
end
defmacro with_prometheus_error(block) do
quote do
try do
unquote(block)
rescue
- e in ErlangError -> reraise Prometheus.Error.normalize(e), System.stacktrace()
+ e in ErlangError ->
+ reraise(
+ Prometheus.Error.normalize(e),
+ unquote(
+ if macro_exported?(Kernel.SpecialForms, :__STACKTRACE__, 0) do
+ quote(do: __STACKTRACE__)
+ else
+ quote(do: System.stacktrace())
+ end
+ )
+ )
end
end
end
end
diff --git a/lib/prometheus/metric/counter.ex b/lib/prometheus/metric/counter.ex
index b524424..ecd0495 100644
--- a/lib/prometheus/metric/counter.ex
+++ b/lib/prometheus/metric/counter.ex
@@ -1,223 +1,231 @@
defmodule Prometheus.Metric.Counter do
@moduledoc """
Counter is a Metric that represents a single numerical value that only ever
goes up. That implies that it cannot be used to count items whose number can
also go down, e.g. the number of currently running processes. Those
"counters" are represented by `Prometheus.Metric.Gauge`.
A Counter is typically used to count requests served, tasks completed, errors
occurred, etc.
Example use cases for Counters:
- Number of requests processed;
- Number of items that were inserted into a queue;
- Total amount of data that a system has processed.
Use the [`rate()`](https://prometheus.io/docs/querying/functions/#rate())/
[`irate()`](https://prometheus.io/docs/querying/functions/#irate())
functions in Prometheus to calculate the rate of increase of a Counter.
By convention, the names of Counters are suffixed by `_total`.
To create a counter use either `new/1` or `declare/1`, the difference is that
`new/` will raise `Prometheus.MFAlreadyExistsError` exception if counter with
the same `registry`, `name` and `labels` combination already exists.
Both accept `spec` `Keyword` with the same set of keys:
- `:registry` - optional, default is `:default`;
- `:name` - required, can be an atom or a string;
- `:help` - required, must be a string;
- `:labels` - optional, default is `[]`.
Example:
```
defmodule MyServiceInstrumenter do
use Prometheus.Metric
## to be called at app/supervisor startup.
## to tolerate restarts use declare.
def setup() do
Counter.declare([name: :my_service_requests_total,
help: "Requests count.",
labels: [:caller]])
end
def inc(caller) do
Counter.inc([name: :my_service_requests_total,
labels: [caller]])
end
end
```
"""
use Prometheus.Erlang, :prometheus_counter
@doc """
Creates a counter using `spec`.
Raises `Prometheus.MissingMetricSpecKeyError` if required `spec` key is missing.<br>
Raises `Prometheus.InvalidMetricNameError` if metric name is invalid.<br>
Raises `Prometheus.InvalidMetricHelpError` if help is invalid.<br>
Raises `Prometheus.InvalidMetricLabelsError` if labels isn't a list.<br>
Raises `Prometheus.InvalidLabelNameError` if label name is invalid.<br>
Raises `Prometheus.MFAlreadyExistsError` if a counter with
the same `spec` already exists.
"""
defmacro new(spec) do
Erlang.call([spec])
end
@doc """
Creates a counter using `spec`.
If a counter with the same `spec` exists returns `false`.
Raises `Prometheus.MissingMetricSpecKeyError` if required `spec` key is missing.<br>
Raises `Prometheus.InvalidMetricNameError` if metric name is invalid.<br>
Raises `Prometheus.InvalidMetricHelpError` if help is invalid.<br>
Raises `Prometheus.InvalidMetricLabelsError` if labels isn't a list.<br>
Raises `Prometheus.InvalidLabelNameError` if label name is invalid.
"""
defmacro declare(spec) do
Erlang.call([spec])
end
@doc """
Increments the counter identified by `spec` by `value`.
Raises `Prometheus.InvalidValueError` exception if `value` isn't a positive number.<br>
Raises `Prometheus.UnknownMetricError` exception if a counter
for `spec` can't be found.<br>
Raises `Prometheus.InvalidMetricArityError` exception if labels count mismatch.
"""
defmacro inc(spec, value \\ 1) do
Erlang.metric_call(:inc, spec, [value])
end
@doc """
Increments the counter identified by `spec` by 1 when `body` executed.
Read more about bodies: `Prometheus.Injector`.
Raises `Prometheus.UnknownMetricError` exception if a counter
for `spec` can't be found.<br>
Raises `Prometheus.InvalidMetricArityError` exception if labels count mismatch.
"""
defmacro count(spec, body) do
env = __CALLER__
Prometheus.Injector.inject(
fn block ->
quote do
Prometheus.Metric.Counter.inc(unquote(spec), 1)
unquote(block)
end
end,
env,
body
)
end
@doc """
Increments the counter identified by `spec` by 1 when `body` raises `exception`.
Read more about bodies: `Prometheus.Injector`.
Raises `Prometheus.UnknownMetricError` exception if a counter
for `spec` can't be found.<br>
Raises `Prometheus.InvalidMetricArityError` exception if labels count mismatch.
"""
defmacro count_exceptions(spec, exception \\ :_, body) do
env = __CALLER__
Prometheus.Injector.inject(
fn block ->
quote do
require Prometheus.Error
Prometheus.Error.with_prometheus_error(
try do
unquote(block)
rescue
e in unquote(exception) ->
- stacktrace = System.stacktrace()
+ stacktrace =
+ unquote(
+ if macro_exported?(Kernel.SpecialForms, :__STACKTRACE__, 0) do
+ quote(do: __STACKTRACE__)
+ else
+ quote(do: System.stacktrace())
+ end
+ )
+
{registry, name, labels} = Prometheus.Metric.parse_spec(unquote(spec))
:prometheus_counter.inc(registry, name, labels, 1)
reraise(e, stacktrace)
end
)
end
end,
env,
body
)
end
@doc """
Increments the counter identified by `spec` by 1 when `body` raises no exceptions.
Read more about bodies: `Prometheus.Injector`.
Raises `Prometheus.UnknownMetricError` exception if a counter
for `spec` can't be found.<br>
Raises `Prometheus.InvalidMetricArityError` exception if labels count mismatch.
"""
defmacro count_no_exceptions(spec, body) do
env = __CALLER__
Prometheus.Injector.inject(
fn block ->
quote do
require Prometheus.Error
try do
unquote(block)
else
value ->
Prometheus.Metric.Counter.inc(unquote(spec), 1)
value
end
end
end,
env,
body
)
end
@doc """
Removes counter series identified by spec.
Raises `Prometheus.UnknownMetricError` exception if a counter
for `spec` can't be found.<br>
Raises `Prometheus.InvalidMetricArityError` exception if labels count mismatch.
"""
defmacro remove(spec) do
Erlang.metric_call(spec)
end
@doc """
Resets the value of the counter identified by `spec`.
Raises `Prometheus.UnknownMetricError` exception if a counter
for `spec` can't be found.<br>
Raises `Prometheus.InvalidMetricArityError` exception if labels count mismatch.
"""
defmacro reset(spec) do
Erlang.metric_call(spec)
end
@doc """
Returns the value of the counter identified by `spec`. If there is no counter for
given labels combination, returns `:undefined`.
Raises `Prometheus.UnknownMetricError` exception if a counter
for `spec` can't be found.<br>
Raises `Prometheus.InvalidMetricArityError` exception if labels count mismatch.
"""
defmacro value(spec) do
Erlang.metric_call(spec)
end
end

File Metadata

Mime Type
text/x-diff
Expires
Tue, Nov 26, 10:42 PM (1 d, 12 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
40477
Default Alt Text
(14 KB)

Event Timeline