Page MenuHomePhorge

No OneTemporary

Size
61 KB
Referenced Files
None
Subscribers
None
diff --git a/.credo.exs b/.credo.exs
index 37bca19..46b5210 100644
--- a/.credo.exs
+++ b/.credo.exs
@@ -1,64 +1,65 @@
%{
configs: [
%{
name: "default",
check_for_updates: false,
files: %{
included: ["lib/", "src/", "web/", "apps/", "test/"],
excluded: [~r"/_build/", ~r"/deps/"]
},
checks: [
{Credo.Check.Consistency.ExceptionNames},
{Credo.Check.Consistency.LineEndings},
{Credo.Check.Consistency.SpaceAroundOperators},
{Credo.Check.Consistency.SpaceInParentheses},
{Credo.Check.Consistency.TabsOrSpaces},
{Credo.Check.Design.AliasUsage, false},
{Credo.Check.Design.DuplicatedCode, excluded_macros: [:schema, :setup, :test]},
{Credo.Check.Design.TagTODO, exit_status: 0},
{Credo.Check.Design.TagFIXME, exit_status: 0},
{Credo.Check.Readability.FunctionNames},
{Credo.Check.Readability.LargeNumbers},
{Credo.Check.Readability.MaxLineLength, priority: :low, max_length: 90, exit_status: 0},
{Credo.Check.Readability.ModuleAttributeNames},
{Credo.Check.Readability.ModuleDoc, false},
{Credo.Check.Readability.ModuleNames},
{Credo.Check.Readability.ParenthesesInCondition},
{Credo.Check.Readability.PredicateFunctionNames},
{Credo.Check.Readability.TrailingBlankLine},
{Credo.Check.Readability.TrailingWhiteSpace},
+ {Credo.Check.Readability.ParenthesesOnZeroArityDefs, false},
{Credo.Check.Readability.VariableNames},
{Credo.Check.Refactor.ABCSize},
{Credo.Check.Refactor.CondStatements},
{Credo.Check.Refactor.FunctionArity},
{Credo.Check.Refactor.MatchInCondition},
{Credo.Check.Refactor.PipeChainStart},
{Credo.Check.Refactor.CyclomaticComplexity},
{Credo.Check.Refactor.NegatedConditionsInUnless},
{Credo.Check.Refactor.NegatedConditionsWithElse},
- {Credo.Check.Refactor.Nesting},
+ {Credo.Check.Refactor.Nesting, max_nesting: 3},
{Credo.Check.Refactor.UnlessWithElse},
{Credo.Check.Warning.IExPry},
{Credo.Check.Warning.IoInspect},
{Credo.Check.Warning.NameRedeclarationByAssignment},
{Credo.Check.Warning.NameRedeclarationByCase},
{Credo.Check.Warning.NameRedeclarationByDef},
{Credo.Check.Warning.NameRedeclarationByFn},
{Credo.Check.Warning.OperationOnSameValues},
{Credo.Check.Warning.BoolOperationOnSameValues},
{Credo.Check.Warning.UnusedEnumOperation},
{Credo.Check.Warning.UnusedKeywordOperation},
{Credo.Check.Warning.UnusedListOperation},
{Credo.Check.Warning.UnusedStringOperation},
{Credo.Check.Warning.UnusedTupleOperation},
{Credo.Check.Warning.OperationWithConstantResult},
]
}
]
}
diff --git a/lib/prometheus.ex b/lib/prometheus.ex
index 0b7f950..01ac441 100644
--- a/lib/prometheus.ex
+++ b/lib/prometheus.ex
@@ -1,121 +1,119 @@
defmodule Prometheus do
@moduledoc"""
[Prometheus.io](https://prometheus.io) client library powered by
[prometheus.erl](https://hexdocs.pm/prometheus)
Prometheus.ex is a thin, mostly macro-based wrapper around prometheus.erl.
While it's pretty straightforward to use prometheus.erl from Elixir,
you might prefer prometheus.ex because it gives you:
- native Elixir syntax;
- native Elixir exceptions;
- configuration helpers that are really handy if you plan to write your custom
instrumenter.
```elixir
defmodule ExampleInstrumenter do
use Prometheus ## require common Prometheus modules, also alias metrics.
def setup do
Histogram.new([name: :http_request_duration_milliseconds,
labels: [:method],
buckets: [100, 300, 500, 750, 1000],
help: "Http Request execution time"])
end
def instrument(%{time: time, method: method}) do
Histogram.observe([name: :http_request_duration_milliseconds,
labels: [method]],
time)
end
end
```
## Integrations
- [Ecto Instrumenter](https://hex.pm/packages/prometheus_ecto);
- [Elixir plugs Instrumenters and Exporter](https://hex.pm/packages/prometheus_plugs);
- [Fuse plugin](https://github.com/jlouis/fuse#fuse_stats_prometheus)
- [OS process info Collector](https://hex.pm/packages/prometheus_process_collector)
(linux-only);
- [Phoenix Instrumenter](https://hex.pm/packages/prometheus_phoenix);
- [RabbitMQ Exporter](https://github.com/deadtrickster/prometheus_rabbitmq_exporter).
-
## Erlang VM Collectors
- [Memory Collector](vm-memory-collector.html);
- [Statistics Collector](vm-statistics-collector.html);
- [System Information Collector](vm-system-info-collector.html).
## API
API can be grouped like this:
### Standard Metrics & Registry
- `Prometheus.Metric.Counter` - counter metric, to track counts of events or running
totals;
- `Prometheus.Metric.Gauge` - histogram metric, to track distributions of events;
- `Prometheus.Metric.Histogram` - gauge metric, to report instantaneous values;
- `Prometheus.Metric.Summary` - summary metric, to track the size of events;
- `Prometheus.Registry` - working with Prometheus registries.
All metrics created via `new/1` or `declare/1` macros. The difference is that `new/1`
actually wants metric to be new and raises `Prometheus.MFAlreadyExistsError`
if it isn't.
Both `new/1` and `declare/1` accept options as
[Keyword](http://elixir-lang.org/docs/stable/elixir/Keyword.html).
Common options are:
- name - metric name, can be an atom or a string (required);
- help - metric help, string (required);
- labels - metric labels, label can be an atom or a string (default is []);
- registry - Prometheus registry for the metric, can be any term. (default is :default)
Histogram also accepts `buckets` option. Please refer to respective modules docs
for the more information.
### General Helpers
- `Prometheus.Buckets` - linear or exponential bucket generators;
- `Prometheus.Contrib.HTTP` - helpers for HTTP instrumenters.
### Integration Helpers
- `Prometheus.Config` - provides standard configuration mechanism
for custom instrumenters/exporters.
### Exposition Formats
- `Prometheus.Format.Text` - renders metrics for a given registry
(default is `:default`) in text format;
- `Prometheus.Format.Protobuf` - renders metrics for a given registry
(default is `:default`) in protobuf v2 format.
### Advanced
You will need this modules only if you're writing custom collector for app/lib
that can't be instrumented directly.
- `Prometheus.Collector` - exports macros for managing/creating collectors;
- `Prometheus.Model` - provides API for working with underlying Prometheus models.
You'll use that if you want to create custom collector.
-
"""
defmacro __using__(_opts) do
quote do
require Prometheus.Collector
require Prometheus.Registry
require Prometheus.Buckets
use Prometheus.Metric
require Prometheus.Contrib.HTTP
require Prometheus.Contrib.Mnesia
end
end
end
diff --git a/lib/prometheus/config.ex b/lib/prometheus/config.ex
index cc879a1..97ac266 100644
--- a/lib/prometheus/config.ex
+++ b/lib/prometheus/config.ex
@@ -1,92 +1,91 @@
defmodule Prometheus.Config do
@moduledoc """
Configuration templates for custom collectors/exporters.
When `use`ed, generates accessor for each configuration option:
iex(4)> defmodule MyInstrumenter do
...(4)> use Prometheus.Config, [:required_option,
...(4)> registry: :default]
...(4)> end
iex(5)> MyInstrumenter.Config.registry(MyInstrumenter)
:default
iex(6)> MyInstrumenter.Config.required_option!(MyInstrumenter)
** (Prometheus.Config.KeyNotFoundError) mandatory option :required_option not found in PrometheusTest.MyInstrumenter instrumenter/collector config
iex(7)> Application.put_env(:prometheus, MyInstrumenter,
...(7)> [required_option: "Hello world!"])
:ok
iex(8)> MyInstrumenter.Config.required_option!(MyInstrumenter)
"Hello world!"
"""
defmodule KeyNotFoundError do
@moduledoc """
Raised when mandatory configuration option not found in app env.
"""
defexception [:option, :key]
def message(%{option: option, key: key}) do
friendly_key_name = String.replace_leading("#{key}", "Elixir.", "")
"mandatory option :#{option} not found" <>
" in #{friendly_key_name} instrumenter/collector config"
end
end
defmacro __using__(default_config) do
keyword_default_config = Enum.reject(default_config, fn(option) ->
case option do
{_, _} -> false
_ -> true
end
end)
quote do
defmodule Config do
@moduledoc false
def config(key) do
Application.get_env(:prometheus, key, unquote(keyword_default_config))
end
defp config(key, option, default) do
key
|> config()
|> Keyword.get(option, default)
end
defp config(key, option) do
- try do
- key
- |> config()
- |> Keyword.fetch!(option)
- rescue
- e in KeyError -> raise %KeyNotFoundError{key: key, option: option}
- end
+ key
+ |> config()
+ |> Keyword.fetch!(option)
+ rescue
+ # credo:disable-for-next-line Credo.Check.Warning.RaiseInsideRescue
+ e in KeyError -> raise %KeyNotFoundError{key: key, option: option}
end
unquote do
for config <- default_config do
case config do
{option, default} ->
quote do
def unquote(option)(key) do
config(key, unquote(option), unquote(default))
end
end
option ->
quote do
def unquote(:"#{option}!")(key) do
config(key, unquote(option))
end
end
end
end
end
end
end
end
end
diff --git a/lib/prometheus/erlang.ex b/lib/prometheus/erlang.ex
index d15e2cb..7a10f02 100644
--- a/lib/prometheus/erlang.ex
+++ b/lib/prometheus/erlang.ex
@@ -1,135 +1,135 @@
defmodule Prometheus.Erlang do
@moduledoc false
require Prometheus.Metric
alias Prometheus.Metric
defmacro __using__(erlang_module) do
quote do
@erlang_module unquote(erlang_module)
alias Prometheus.Erlang
end
end
defmacro call(mf \\ false, arguments \\ []) do
{module, function, arguments} = parse_mfa(__CALLER__, mf, arguments)
quote do
Prometheus.Erlang.call_body(unquote(module), unquote(function), unquote(arguments))
end
end
def call_body(module, function, arguments) do
quote do
require Prometheus.Error
Prometheus.Error.with_prometheus_error(
unquote(module).unquote(function)(unquote_splicing(arguments)))
end
end
defmacro metric_call(mf_or_spec, spec \\ false, arguments \\ []) do
{mf, spec, arguments} = parse_metric_call_args(mf_or_spec, spec, arguments)
{module, function, arguments} = parse_mfa(__CALLER__, mf, arguments)
quote do
Prometheus.Erlang.metric_call_body(unquote(module), unquote(function),
unquote(spec), unquote(arguments))
end
end
def metric_call_body(module, function, spec, arguments) do
case spec do
_ when Metric.ct_parsable_spec?(spec) ->
{registry, name, labels} = Prometheus.Metric.parse_spec(spec)
quote do
require Prometheus.Error
Prometheus.Error.with_prometheus_error(
unquote(module).unquote(function)(unquote(registry), unquote(name),
unquote(labels), unquote_splicing(arguments)))
end
_ ->
quote do
require Prometheus.Error
{registry, name, labels} = Metric.parse_spec(unquote(spec))
Prometheus.Error.with_prometheus_error(
unquote(module).unquote(function)(registry, name, labels,
unquote_splicing(arguments)))
end
end
end
defp parse_metric_call_args(mf_or_spec, spec, arguments) do
case mf_or_spec do
## Erlang.metric_call({:prometheus_counter, :dinc}, spec, [value])
- {_,_} -> {mf_or_spec, spec, arguments}
+ {_, _} -> {mf_or_spec, spec, arguments}
## Erlang.metric_call(:inc, spec, [value])
_ when is_atom(mf_or_spec) -> {mf_or_spec, spec, arguments}
_ ->
## args are 'shifted' to left
[] = arguments
if spec == false do
## only spec is needed, e.g. Erlang.metric_call(spec)
{false, mf_or_spec, []}
else
## Erlang.metric_call(spec, [value])
{false, mf_or_spec, spec}
end
end
end
defp parse_mfa(__CALLER__, mf, arguments) do
arguments = case mf do
_ when is_list(mf) ->
[] = arguments
mf
_ ->
arguments
end
{module, function} = case mf do
false ->
{f, _arity} = __CALLER__.function
{Module.get_attribute(__CALLER__.module, :erlang_module), f}
_ when is_list(mf) ->
{f, _arity} = __CALLER__.function
{Module.get_attribute(__CALLER__.module, :erlang_module), f}
- {_,_} ->
+ {_, _} ->
mf
_ when is_atom(mf) ->
{Module.get_attribute(__CALLER__.module, :erlang_module), mf}
end
{module, function, arguments}
end
def ensure_fn(var) do
case var do
[do: block] ->
quote do
fn ->
unquote(block)
end
end
fun ->
quote do
unquote(fun)
end
end
end
end
diff --git a/lib/prometheus/error.ex b/lib/prometheus/error.ex
index 7ec9185..62e0037 100644
--- a/lib/prometheus/error.ex
+++ b/lib/prometheus/error.ex
@@ -1,207 +1,206 @@
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.HistogramNoBucketsError 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.HistogramInvalidBucketsError 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.HistogramInvalidBoundError 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
- @lint [{Credo.Check.Refactor.ABCSize, false},
- {Credo.Check.Refactor.CyclomaticComplexity, 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}
{:histogram_no_buckets, buckets} ->
%Prometheus.HistogramNoBucketsError{buckets: buckets}
{:histogram_invalid_buckets, buckets, message} ->
%Prometheus.HistogramInvalidBucketsError{buckets: buckets,
orig_message: message}
{:histogram_invalid_bound, bound} ->
%Prometheus.HistogramInvalidBoundError{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
end
end
end
end
diff --git a/lib/prometheus/metric.ex b/lib/prometheus/metric.ex
index bbf3dc6..fe5f9ab 100644
--- a/lib/prometheus/metric.ex
+++ b/lib/prometheus/metric.ex
@@ -1,151 +1,157 @@
defmodule Prometheus.Metric do
@moduledoc """
Prometheus metrics shortcuts.
Aliases and requires respective metric modules so they are
accessible without `Prometheus.Metric` prefix.
Allows to automatically setup metrics with
`@<type`> attributes. Metrics will be declared in
the `@on_load` callback. If the module already
has `@on_laod` callback, metrics will be declared
iff the callback returns `:ok`.
iex(1)> defmodule MyCoolModule do
...(1)> use Prometheus.Metric
...(1)>
...(1)> @counter name: :test_counter3, labels: [], help: "qwe"
...(1)> end
iex(2)> require Prometheus.Metric.Counter
Prometheus.Metric.Counter
iex(3)> Prometheus.Metric.Counter.value(:test_counter3)
0
"""
@metrics [:counter, :gauge, :boolean, :summary, :histogram]
defmacro __using__(_opts) do
module_name = __CALLER__.module
quote do
+ # credo:disable-for-next-line Credo.Check.Readability.SpaceAfterCommas
alias Prometheus.Metric.{Counter,Gauge,Histogram,Summary,Boolean}
+ # credo:disable-for-next-line Credo.Check.Readability.SpaceAfterCommas
require Prometheus.Metric.{Counter,Gauge,Histogram,Summary,Boolean}
require Prometheus.Error
unquote_splicing(
for metric <- @metrics do
quote do
- Module.register_attribute unquote(module_name), unquote(metric), accumulate: true
+ Module.register_attribute(unquote(module_name), unquote(metric),
+ accumulate: true)
end
end)
@before_compile unquote(__MODULE__)
end
end
defmacro __before_compile__(env) do
quote do
def __declare_prometheus_metrics__() do
if List.keymember?(Application.started_applications(), :prometheus, 0) do
unquote_splicing(
for metric <- @metrics do
declarations = Module.get_attribute(env.module, metric)
Module.delete_attribute(env.module, metric)
quote do
unquote_splicing(
for params <- declarations do
emit_create_metric(metric, params)
end)
:ok
end
end)
else
:ok
end
end
- unquote(
- case get_on_load_attribute(env.module) do
- nil ->
- quote do
- @on_load :__declare_prometheus_metrics__
- end
- on_load ->
- Module.delete_attribute(env.module, :on_load)
- Module.put_attribute(env.module, :on_load, :__prometheus_on_load_override__)
- quote do
- def __prometheus_on_load_override__() do
- case unquote(on_load)() do
- :ok -> __declare_prometheus_metrics__()
- result -> result
- end
- end
+ unquote(gen_on_load(env))
+ end
+ end
+
+ defp gen_on_load(env) do
+ case get_on_load_attribute(env.module) do
+ nil ->
+ quote do
+ @on_load :__declare_prometheus_metrics__
+ end
+ on_load ->
+ Module.delete_attribute(env.module, :on_load)
+ Module.put_attribute(env.module, :on_load, :__prometheus_on_load_override__)
+ quote do
+ def __prometheus_on_load_override__() do
+ case unquote(on_load)() do
+ :ok -> __declare_prometheus_metrics__()
+ result -> result
end
- end)
+ end
+ end
end
end
defp get_on_load_attribute(module) do
case Module.get_attribute(module, :on_load) do
[] ->
nil
nil ->
nil
atom when is_atom(atom) ->
atom
{atom, 0} when is_atom(atom) ->
atom
[{atom, 0}] when is_atom(atom) ->
atom
other ->
raise ArgumentError,
"expected the @on_load attribute to be an atom or a " <>
"{atom, 0} tuple, got: #{inspect(other)}"
end
end
defp emit_create_metric(:counter, params) do
quote do
Prometheus.Metric.Counter.declare(unquote(params))
end
end
defp emit_create_metric(:gauge, params) do
quote do
Prometheus.Metric.Gauge.declare(unquote(params))
end
end
defp emit_create_metric(:boolean, params) do
quote do
Prometheus.Metric.Boolean.declare(unquote(params))
end
end
defp emit_create_metric(:summary, params) do
quote do
Prometheus.Metric.Summary.declare(unquote(params))
end
end
defp emit_create_metric(:histogram, params) do
quote do
Prometheus.Metric.Histogram.declare(unquote(params))
end
end
defmacro ct_parsable_spec?(spec) do
quote do
is_list(unquote(spec)) or is_atom(unquote(spec))
end
end
def parse_spec(spec) when is_list(spec) do
registry = Keyword.get(spec, :registry, :default)
name = Keyword.fetch!(spec, :name)
labels = Keyword.get(spec, :labels, [])
{registry, name, labels}
end
def parse_spec(spec) when is_atom(spec) do
{:default, spec, []}
end
end
diff --git a/test/contrib/mnesia_test.exs b/test/contrib/mnesia_test.exs
index fd084bc..4ba8123 100644
--- a/test/contrib/mnesia_test.exs
+++ b/test/contrib/mnesia_test.exs
@@ -1,36 +1,34 @@
defmodule Prometheus.Contrib.MnesiaTest do
use ExUnit.Case
use Prometheus
test "table disk size" do
{:ok, root} = :file.get_cwd()
mnesia_dir = root ++ '/test/mnesia'
set_custom_mnesia_dir(mnesia_dir)
assert mnesia_dir == :mnesia.system_info(:directory)
assert 3 = Prometheus.Contrib.Mnesia.table_disk_size(mnesia_dir, :table)
assert 21 = Prometheus.Contrib.Mnesia.table_disk_size(:my_table)
end
test "tm info test" do
try do
:mnesia.start()
assert {_, _} = Prometheus.Contrib.Mnesia.tm_info()
after
:mnesia.stop()
end
end
defp set_custom_mnesia_dir(dir) do
- try do
- :ets.lookup_element(:mnesia_gvar, :dir, 2)
- :ets.update_element(:mnesia_gvar, :dir, dir)
- rescue
- ArgumentError ->
- :application.set_env(:mnesia, :dir, dir)
- end
+ :ets.lookup_element(:mnesia_gvar, :dir, 2)
+ :ets.update_element(:mnesia_gvar, :dir, dir)
+ rescue
+ ArgumentError ->
+ :application.set_env(:mnesia, :dir, dir)
end
end
diff --git a/test/format/protobuf_test.exs b/test/format/protobuf_test.exs
index 9b9959e..32b6928 100644
--- a/test/format/protobuf_test.exs
+++ b/test/format/protobuf_test.exs
@@ -1,125 +1,126 @@
+# credo:disable-for-this-file Credo.Check.Readability.SpaceAfterCommas
defmodule Prometheus.Format.ProtobufTest do
use Prometheus.Case
require Prometheus.Format.Protobuf
test "content_type" do
assert "application/vnd.google.protobuf; " <>
"proto=io.prometheus.client.MetricFamily; " <>
"encoding=delimited" == Prometheus.Format.Protobuf.content_type
end
test "gauge" do
Gauge.new([name: :pool_size, help: "MongoDB Connections pool size"])
Gauge.set([name: :pool_size], 365)
assert <<57,10,9,112,111,111,108,95,115,105,122,101,18,29,77,111,
110,103,111,68,66,32,67,111,110,110,101,99,116,105,111,
110,115,32,112,111,111,108,32,115,105,122,101,24,1,34,
11,18,9,9,0,0,0,0,0,208,118,64>> == Prometheus.Format.Protobuf.format()
end
test "counter" do
Counter.new([name: :http_requests_total, help: "Http request count"])
Counter.inc([name: :http_requests_total])
assert <<56,10,19,104,116,116,112,95,114,101,113,117,101,115,116,
115,95,116,111,116,97,108,18,18,72,116,116,112,32,114,
101,113,117,101,115,116,32,99,111,117,110,116,24,0,34,
11,26,9,9,0,0,0,0,0,0,240,63>> == Prometheus.Format.Protobuf.format()
end
test "dcounter" do
Counter.new([name: :dtest, help: "qw\"\\e"])
Counter.dinc([name: :dtest], 1.5)
Counter.dinc([name: :dtest], 3.5)
Counter.dinc([name: :dtest], 1.5)
:timer.sleep(10)
assert <<29,10,5,100,116,101,115,116,18,5,113,119,34,92,101,24,0,
34,11,26,9,9,0,0,0,0,0,0,26,64>> == Prometheus.Format.Protobuf.format()
end
test "summary" do
Summary.new([name: :orders_summary, help: "Track orders count/total sum"])
Summary.observe([name: :orders_summary], 10)
Summary.observe([name: :orders_summary], 15)
assert <<63,10,14,111,114,100,101,114,115,95,115,117,109,109,97,
114,121,18,28,84,114,97,99,107,32,111,114,100,101,114,
115,32,99,111,117,110,116,47,116,111,116,97,108,32,115,
117,109,24,2,34,13,34,11,8,2,17,0,0,0,0,0,0,57,64>> ==
Prometheus.Format.Protobuf.format()
end
test "dsummary" do
Summary.new([name: :dsummary, help: "qwe"])
Summary.dobserve([name: :dsummary], 1.5)
Summary.dobserve([name: :dsummary], 2.7)
:timer.sleep(10)
assert <<32,10,8,100,115,117,109,109,97,114,121,18,3,113,119,101,
24,2,34,13,34,11,8,2,17,205,204,204,204,204,204,16,64>> ==
Prometheus.Format.Protobuf.format()
end
test "histogram" do
Histogram.new([name: :http_request_duration_milliseconds,
labels: [:method],
buckets: [100, 300, 500, 750, 1000],
help: "Http Request execution time",
duration_unit: false])
Histogram.observe([name: :http_request_duration_milliseconds, labels: [:get]], 95)
Histogram.observe([name: :http_request_duration_milliseconds, labels: [:get]], 100)
Histogram.observe([name: :http_request_duration_milliseconds, labels: [:get]], 102)
Histogram.observe([name: :http_request_duration_milliseconds, labels: [:get]], 150)
Histogram.observe([name: :http_request_duration_milliseconds, labels: [:get]], 250)
Histogram.observe([name: :http_request_duration_milliseconds, labels: [:get]], 75)
Histogram.observe([name: :http_request_duration_milliseconds, labels: [:get]], 350)
Histogram.observe([name: :http_request_duration_milliseconds, labels: [:get]], 550)
Histogram.observe([name: :http_request_duration_milliseconds, labels: [:get]], 950)
assert <<175,1,10,34,104,116,116,112,95,114,101,113,117,101,115,
116,95,100,117,114,97,116,105,111,110,95,109,105,108,
108,105,115,101,99,111,110,100,115,18,27,72,116,116,112,
32,82,101,113,117,101,115,116,32,101,120,101,99,117,116,
105,111,110,32,116,105,109,101,24,4,34,106,10,13,10,6,
109,101,116,104,111,100,18,3,103,101,116,58,89,8,9,17,0,
0,0,0,0,124,164,64,26,11,8,3,17,0,0,0,0,0,0,89,64,26,11,
8,6,17,0,0,0,0,0,192,114,64,26,11,8,7,17,0,0,0,0,0,64,
127,64,26,11,8,8,17,0,0,0,0,0,112,135,64,26,11,8,9,17,0,
0,0,0,0,64,143,64,26,11,8,9,17,0,0,0,0,0,0,240,127>> ==
Prometheus.Format.Protobuf.format()
end
test "dhistogram" do
Histogram.new([name: :http_request_duration_milliseconds,
labels: [:method],
buckets: [100, 300, 500, 750, 1000],
help: "Http Request execution time",
duration_unit: false])
Histogram.dobserve(
[name: :http_request_duration_milliseconds, labels: [:post]], 500.2)
Histogram.dobserve(
[name: :http_request_duration_milliseconds, labels: [:post]], 150.4)
Histogram.dobserve(
[name: :http_request_duration_milliseconds, labels: [:post]], 450.5)
Histogram.dobserve(
[name: :http_request_duration_milliseconds, labels: [:post]], 850.3)
Histogram.dobserve(
[name: :http_request_duration_milliseconds, labels: [:post]], 750.9)
Histogram.dobserve(
[name: :http_request_duration_milliseconds, labels: [:post]], 1650.23)
:timer.sleep(10)
assert <<176,1,10,34,104,116,116,112,95,114,101,113,117,101,115,
116,95,100,117,114,97,116,105,111,110,95,109,105,108,
108,105,115,101,99,111,110,100,115,18,27,72,116,116,112,
32,82,101,113,117,101,115,116,32,101,120,101,99,117,116,
105,111,110,32,116,105,109,101,24,4,34,107,10,14,10,6,
109,101,116,104,111,100,18,4,112,111,115,116,58,89,8,6,
17,225,122,20,174,135,0,177,64,26,11,8,0,17,0,0,0,0,0,0,
89,64,26,11,8,1,17,0,0,0,0,0,192,114,64,26,11,8,2,17,0,
0,0,0,0,64,127,64,26,11,8,3,17,0,0,0,0,0,112,135,64,26,
11,8,5,17,0,0,0,0,0,64,143,64,26,11,8,6,17,0,0,0,0,0,0,
240,127>> == Prometheus.Format.Protobuf.format()
end
end
diff --git a/test/injector_test.exs b/test/injector_test.exs
index 7210ceb..c697cdd 100644
--- a/test/injector_test.exs
+++ b/test/injector_test.exs
@@ -1,158 +1,158 @@
defmodule Injector do
defmacro test(ast) do
Prometheus.Injector.inject(fn(block) ->
quote do
try do
IO.puts("before block")
unquote(block)
after
IO.puts("after block")
end
end
end, __CALLER__, ast)
end
end
defmodule Prometheus.InjectorTest do
use Prometheus.Case
require Injector
Injector.test do
def fun1() do
IO.puts("fun1")
end
def fun2() do
IO.puts("fun2")
end
Injector.test do
def fun3() do
IO.puts("fun3")
rescue
e in RuntimeError ->
IO.puts(e)
end
end
end
def do_dangerous_work(x) do
Injector.test do
IO.puts("Doing dangerous work #{x}")
rescue
_ -> IO.puts("Died")
after
IO.puts("Done anyway")
end
end
test "fn" do
assert capture_io(fn ->
Injector.test(fn () -> IO.puts("qwe") end)
end) ==
"before block\nqwe\nafter block\n"
end
test "blocks" do
assert capture_io(fn () ->
Injector.test IO.puts("qwe")
end) == "before block\nqwe\nafter block\n"
assert capture_io(fn () ->
Injector.test do: IO.puts("qwe")
end) == "before block\nqwe\nafter block\n"
assert capture_io(fn () ->
Injector.test do
IO.puts("qwe")
IO.puts("qwa")
end
end) == "before block\nqwe\nqwa\nafter block\n"
end
test "implicit try" do
assert capture_io(fn () ->
do_dangerous_work(5)
end) == "before block\nDoing dangerous work 5\nDone anyway\nafter block\n"
assert capture_io(fn () ->
do_dangerous_work({})
end) == "before block\nDied\nDone anyway\nafter block\n"
end
test "defs" do
assert capture_io(fn () ->
fun1()
end) == "before block\nfun1\nafter block\n"
assert capture_io(fn () ->
fun2()
end) == "before block\nfun2\nafter block\n"
assert capture_io(fn () ->
fun3()
end) == "before block\nbefore block\nfun3\nafter block\nafter block\n"
end
defmodule QweInjector do
defmacro inject_(body) do
Prometheus.Injector.inject_(body, fn(b) ->
quote do
IO.puts("qwe")
try do
unquote(b)
after
IO.puts("after_qwe")
end
end
end)
end
defmacro inject1(body) do
body
end
end
defmodule UsefulModule do
require QweInjector
def do_work(x) do
QweInjector.inject_ do
IO.puts("Doing work #{inspect x}")
end
end
def do_dangerous_work(x) do
QweInjector.inject_ do
IO.puts("Doing dangerous work #{x}")
rescue
- _-> IO.puts("Died")
+ _ -> IO.puts("Died")
after
IO.puts("Done anyway")
end
end
QweInjector.inject_ do
def mildly_interesting(what) do
IO.puts("#{what} is mildly interesting")
end
def wtf(what) do
IO.puts("#{what} is wtf")
rescue
_ -> IO.puts("Oh my, #{inspect what} is real wtf")
else
_ -> IO.puts("Saw wtf and still stronk")
end
end
end
test "UsefulModule" do
assert capture_io(fn () ->
UsefulModule.wtf({})
end) ==
"qwe\nOh my, {} is real wtf\nafter_qwe\n"
end
end
diff --git a/test/metric/counter_test.exs b/test/metric/counter_test.exs
index 4d318f0..3b96625 100644
--- a/test/metric/counter_test.exs
+++ b/test/metric/counter_test.exs
@@ -1,312 +1,312 @@
defmodule Prometheus.CounterTest do
use Prometheus.Case
test "registration" do
spec = [name: :name,
help: "",
registry: :qwe]
assert true == Counter.declare(spec)
assert false == Counter.declare(spec)
assert_raise Prometheus.MFAlreadyExistsError,
"Metric qwe:name already exists.",
fn ->
Counter.new(spec)
end
end
test "spec errors" do
assert_raise Prometheus.MissingMetricSpecKeyError,
"Required key name is missing from metric spec.",
fn ->
Counter.new([help: ""])
end
assert_raise Prometheus.InvalidMetricNameError,
"Invalid metric name: 12.",
fn ->
Counter.new([name: 12, help: ""])
end
assert_raise Prometheus.InvalidMetricLabelsError,
"Invalid metric labels: 12.",
fn ->
Counter.new([name: "qwe", labels: 12, help: ""])
end
assert_raise Prometheus.InvalidMetricHelpError,
"Invalid metric help: 12.",
fn ->
Counter.new([name: "qwe", help: 12])
end
end
test "counter specific errors" do
spec = [name: :http_requests_total,
help: ""]
## inc
assert_raise Prometheus.InvalidValueError,
"Invalid value: -1 (inc accepts only non-negative integers).",
fn ->
Counter.inc(spec, -1)
end
assert_raise Prometheus.InvalidValueError,
"Invalid value: 1.5 (inc accepts only non-negative integers).",
fn ->
Counter.inc(spec, 1.5)
end
assert_raise Prometheus.InvalidValueError,
"Invalid value: \"qwe\" (inc accepts only non-negative integers).",
fn ->
Counter.inc(spec, "qwe")
end
## dinc
assert_raise Prometheus.InvalidValueError,
"Invalid value: -1 (dinc accepts only non-negative numbers).",
fn ->
Counter.dinc(spec, -1)
end
assert_raise Prometheus.InvalidValueError,
"Invalid value: \"qwe\" (dinc accepts only non-negative numbers).",
fn ->
Counter.dinc(spec, "qwe")
end
end
test "mf/arity errors" do
spec = [name: :metric_with_label,
labels: [:label],
help: ""]
Counter.declare(spec)
## inc
assert_raise Prometheus.UnknownMetricError,
"Unknown metric {registry: default, name: unknown_metric}.",
fn ->
Counter.inc(:unknown_metric)
end
assert_raise Prometheus.InvalidMetricArityError,
"Invalid metric arity: got 2, expected 1.",
fn ->
Counter.inc([name: :metric_with_label, labels: [:l1, :l2]])
end
## dinc
assert_raise Prometheus.UnknownMetricError,
"Unknown metric {registry: default, name: unknown_metric}.",
fn ->
Counter.dinc(:unknown_metric)
end
assert_raise Prometheus.InvalidMetricArityError,
"Invalid metric arity: got 2, expected 1.",
fn ->
Counter.dinc([name: :metric_with_label, labels: [:l1, :l2]])
end
## remove
assert_raise Prometheus.UnknownMetricError,
"Unknown metric {registry: default, name: unknown_metric}.",
fn ->
Counter.remove(:unknown_metric)
end
assert_raise Prometheus.InvalidMetricArityError,
"Invalid metric arity: got 2, expected 1.",
fn ->
Counter.remove([name: :metric_with_label, labels: [:l1, :l2]])
end
## reset
assert_raise Prometheus.UnknownMetricError,
"Unknown metric {registry: default, name: unknown_metric}.",
fn ->
Counter.reset(:unknown_metric)
end
assert_raise Prometheus.InvalidMetricArityError,
"Invalid metric arity: got 2, expected 1.",
fn ->
Counter.reset([name: :metric_with_label, labels: [:l1, :l2]])
end
## value
assert_raise Prometheus.UnknownMetricError,
"Unknown metric {registry: default, name: unknown_metric}.",
fn ->
Counter.value(:unknown_metric)
end
assert_raise Prometheus.InvalidMetricArityError,
"Invalid metric arity: got 2, expected 1.",
fn ->
Counter.value([name: :metric_with_label, labels: [:l1, :l2]])
end
end
test "inc" do
spec = [name: :http_requests_total,
labels: [:method],
help: ""]
Counter.new(spec)
Counter.inc(spec)
Counter.inc(spec, 3)
assert 4 == Counter.value(spec)
Counter.reset(spec)
assert 0 == Counter.value(spec)
end
test "dinc" do
spec = [name: :http_requests_total,
help: ""]
Counter.new(spec)
Counter.dinc(spec)
Counter.dinc(spec, 3.5)
## dinc is async. let's make sure gen_server processed our request
Process.sleep(10)
assert 4.5 == Counter.value(spec)
Counter.reset(spec)
assert 0 == Counter.value(spec)
end
test "remove" do
spec = [name: :http_requests_total,
labels: [:method],
help: ""]
wl_spec = [name: :simple_counter,
help: ""]
Counter.new(spec)
Counter.new(wl_spec)
Counter.inc(spec)
Counter.inc(wl_spec)
assert 1 == Counter.value(spec)
assert 1 == Counter.value(wl_spec)
assert true == Counter.remove(spec)
assert true == Counter.remove(wl_spec)
assert :undefined == Counter.value(spec)
assert :undefined == Counter.value(wl_spec)
assert false == Counter.remove(spec)
assert false == Counter.remove(wl_spec)
end
test "default value" do
lspec = [name: :http_requests_total,
labels: [:method],
help: ""]
Counter.new(lspec)
assert :undefined == Counter.value(lspec)
spec = [name: :something_total,
labels: [],
help: ""]
Counter.new(spec)
assert 0 == Counter.value(spec)
end
defmodule CounterInjectorsTest do
use Prometheus.Metric
@counter name: :calls_total, help: ""
@counter name: :sometimes_total, help: ""
@counter name: :exceptions_total, help: ""
@counter name: :no_exceptions_total, help: ""
Counter.count name: :calls_total do
def decorated_fun() do
IO.puts("I'm decorated fun")
end
def decorated_fun1() do
IO.puts("I'm decorated fun1")
IO.puts("I'm decorated fun1")
end
end
def sometimes_count(arg) do
if arg do
Counter.count [name: :sometimes_total], do: IO.puts "Called indeed!"
else
IO.puts("Not this time")
end
end
Counter.count_no_exceptions [name: :no_exceptions_total] do
Counter.count_exceptions [name: :exceptions_total], ArithmeticError do
def sometimes_raise(arg) do
- 5/arg
+ 5 / arg
end
end
def sometimes_raise1(arg) when is_list(arg) do
- 5/arg
+ 5 / arg
end
end
def qwe () do
Counter.count_no_exceptions [name: :no_exceptions_total], fn () ->
IO.puts 1
IO.puts 2
end
end
Counter.count_exceptions [name: :exceptions_total] do
def sometimes_raise_any(arg) do
- 5/arg
+ 5 / arg
end
end
end
test "decorators test" do
CounterInjectorsTest.__declare_prometheus_metrics__()
assert 0 == Counter.value name: :calls_total
assert capture_io(fn -> CounterInjectorsTest.decorated_fun() end) ==
"I'm decorated fun\n"
assert 1 == Counter.value name: :calls_total
assert capture_io(fn -> CounterInjectorsTest.decorated_fun1() end) ==
"I'm decorated fun1\nI'm decorated fun1\n"
assert 2 == Counter.value name: :calls_total
assert 0 == Counter.value name: :sometimes_total
assert capture_io(fn -> CounterInjectorsTest.sometimes_count(true) end) ==
"Called indeed!\n"
assert capture_io(fn -> CounterInjectorsTest.sometimes_count(false) end) ==
"Not this time\n"
assert 1 == Counter.value name: :sometimes_total
assert 0 == Counter.value name: :exceptions_total
assert 0 == Counter.value name: :no_exceptions_total
assert 1 == CounterInjectorsTest.sometimes_raise(5)
assert 0 == Counter.value name: :exceptions_total
assert 1 == Counter.value name: :no_exceptions_total
assert_raise ArithmeticError,
fn ->
CounterInjectorsTest.sometimes_raise(0)
end
assert 1 == Counter.value name: :exceptions_total
assert 1 == Counter.value name: :no_exceptions_total
assert 1 == Counter.value name: :exceptions_total
assert 1 == CounterInjectorsTest.sometimes_raise(5)
assert 1 == Counter.value name: :exceptions_total
assert_raise ArithmeticError,
fn ->
CounterInjectorsTest.sometimes_raise(0)
end
assert 2 == Counter.value name: :exceptions_total
end
end
diff --git a/test/metric/gauge_test.exs b/test/metric/gauge_test.exs
index 0612d2c..03d2476 100644
--- a/test/metric/gauge_test.exs
+++ b/test/metric/gauge_test.exs
@@ -1,462 +1,461 @@
defmodule Prometheus.GaugeTest do
use Prometheus.Case
test "registration" do
spec = [name: :name,
help: "",
registry: :qwe]
assert true == Gauge.declare(spec)
assert false == Gauge.declare(spec)
assert_raise Prometheus.MFAlreadyExistsError,
"Metric qwe:name already exists.",
fn ->
Gauge.new(spec)
end
end
test "spec errors" do
assert_raise Prometheus.MissingMetricSpecKeyError,
"Required key name is missing from metric spec.",
fn ->
Gauge.new([help: ""])
end
assert_raise Prometheus.InvalidMetricNameError,
"Invalid metric name: 12.",
fn ->
Gauge.new([name: 12, help: ""])
end
assert_raise Prometheus.InvalidMetricLabelsError,
"Invalid metric labels: 12.",
fn ->
Gauge.new([name: "qwe", labels: 12, help: ""])
end
assert_raise Prometheus.InvalidMetricHelpError,
"Invalid metric help: 12.",
fn ->
Gauge.new([name: "qwe", help: 12])
end
end
test "gauge specific errors" do
spec = [name: :http_requests_total,
help: ""]
## set
assert_raise Prometheus.InvalidValueError,
"Invalid value: \"qwe\" (set accepts only numbers).",
fn ->
Gauge.set(spec, "qwe")
end
## inc
assert_raise Prometheus.InvalidValueError,
"Invalid value: \"qwe\" (inc accepts only integers).",
fn ->
Gauge.inc(spec, "qwe")
end
assert_raise Prometheus.InvalidValueError,
"Invalid value: -1.5 (inc accepts only integers).",
fn ->
Gauge.inc(spec, -1.5)
end
## dec
assert_raise Prometheus.InvalidValueError,
"Invalid value: \"qwe\" (dec accepts only integers).",
fn ->
Gauge.dec(spec, "qwe")
end
assert_raise Prometheus.InvalidValueError,
"Invalid value: -1.5 (dec accepts only integers).",
fn ->
Gauge.dec(spec, -1.5)
end
## dinc
assert_raise Prometheus.InvalidValueError,
"Invalid value: \"qwe\" (dinc accepts only numbers).",
fn ->
Gauge.dinc(spec, "qwe")
end
## ddec
assert_raise Prometheus.InvalidValueError,
"Invalid value: \"qwe\" (ddec accepts only numbers).",
fn ->
Gauge.ddec(spec, "qwe")
end
## track_inprogress
assert_raise Prometheus.InvalidBlockArityError,
"Fn with arity 2 (args: :x, :y) passed as block.",
fn ->
Macro.expand(quote do
Gauge.track_inprogress(spec, fn(x, y) -> 1 + x + y end)
end, __ENV__)
end
## set_duration
assert_raise Prometheus.InvalidBlockArityError,
"Fn with arity 2 (args: :x, :y) passed as block.",
fn ->
Macro.expand(quote do
Gauge.set_duration(spec, fn(x, y) -> 1 + x + y end)
end, __ENV__)
end
end
test "mf/arity errors" do
spec = [name: :metric_with_label,
labels: [:label],
help: ""]
Gauge.declare(spec)
## set
assert_raise Prometheus.UnknownMetricError,
"Unknown metric {registry: default, name: unknown_metric}.",
fn ->
Gauge.set(:unknown_metric, 1)
end
assert_raise Prometheus.InvalidMetricArityError,
"Invalid metric arity: got 2, expected 1.",
fn ->
Gauge.set([name: :metric_with_label, labels: [:l1, :l2]], 1)
end
## inc
assert_raise Prometheus.UnknownMetricError,
"Unknown metric {registry: default, name: unknown_metric}.",
fn ->
Gauge.inc(:unknown_metric)
end
assert_raise Prometheus.InvalidMetricArityError,
"Invalid metric arity: got 2, expected 1.",
fn ->
Gauge.inc([name: :metric_with_label, labels: [:l1, :l2]])
end
## dinc
assert_raise Prometheus.UnknownMetricError,
"Unknown metric {registry: default, name: unknown_metric}.",
fn ->
Gauge.dinc(:unknown_metric)
end
assert_raise Prometheus.InvalidMetricArityError,
"Invalid metric arity: got 2, expected 1.",
fn ->
Gauge.dinc([name: :metric_with_label, labels: [:l1, :l2]])
end
## dec
assert_raise Prometheus.UnknownMetricError,
"Unknown metric {registry: default, name: unknown_metric}.",
fn ->
Gauge.dec(:unknown_metric)
end
assert_raise Prometheus.InvalidMetricArityError,
"Invalid metric arity: got 2, expected 1.",
fn ->
Gauge.dec([name: :metric_with_label, labels: [:l1, :l2]])
end
## ddec
assert_raise Prometheus.UnknownMetricError,
"Unknown metric {registry: default, name: unknown_metric}.",
fn ->
Gauge.ddec(:unknown_metric)
end
assert_raise Prometheus.InvalidMetricArityError,
"Invalid metric arity: got 2, expected 1.",
fn ->
Gauge.ddec([name: :metric_with_label, labels: [:l1, :l2]])
end
## set_to_current_time
assert_raise Prometheus.UnknownMetricError,
"Unknown metric {registry: default, name: unknown_metric}.",
fn ->
Gauge.set_to_current_time(:unknown_metric)
end
assert_raise Prometheus.InvalidMetricArityError,
"Invalid metric arity: got 2, expected 1.",
fn ->
Gauge.set_to_current_time([name: :metric_with_label, labels: [:l1, :l2]])
end
## track_inprogress
assert_raise Prometheus.UnknownMetricError,
"Unknown metric {registry: default, name: unknown_metric}.",
fn ->
Gauge.track_inprogress(:unknown_metric, fn -> 1 end)
end
assert_raise Prometheus.InvalidMetricArityError,
"Invalid metric arity: got 2, expected 1.",
fn ->
Gauge.track_inprogress([name: :metric_with_label, labels: [:l1, :l2]], fn -> 1 end)
end
## set_duration
assert_raise Prometheus.UnknownMetricError,
"Unknown metric {registry: default, name: unknown_metric}.",
fn ->
Gauge.set_duration(:unknown_metric, fn -> 1 end)
end
assert_raise Prometheus.InvalidMetricArityError,
"Invalid metric arity: got 2, expected 1.",
fn ->
Gauge.set_duration([name: :metric_with_label, labels: [:l1, :l2]], fn -> 1 end)
end
## remove
assert_raise Prometheus.UnknownMetricError,
"Unknown metric {registry: default, name: unknown_metric}.",
fn ->
Gauge.remove(:unknown_metric)
end
assert_raise Prometheus.InvalidMetricArityError,
"Invalid metric arity: got 2, expected 1.",
fn ->
Gauge.remove([name: :metric_with_label, labels: [:l1, :l2]])
end
## reset
assert_raise Prometheus.UnknownMetricError,
"Unknown metric {registry: default, name: unknown_metric}.",
fn ->
Gauge.reset(:unknown_metric)
end
assert_raise Prometheus.InvalidMetricArityError,
"Invalid metric arity: got 2, expected 1.",
fn ->
Gauge.reset([name: :metric_with_label, labels: [:l1, :l2]])
end
## value
assert_raise Prometheus.UnknownMetricError,
"Unknown metric {registry: default, name: unknown_metric}.",
fn ->
Gauge.value(:unknown_metric)
end
assert_raise Prometheus.InvalidMetricArityError,
"Invalid metric arity: got 2, expected 1.",
fn ->
Gauge.value([name: :metric_with_label, labels: [:l1, :l2]])
end
end
test "set" do
spec = [name: :metric_with_label,
labels: [:label],
help: ""]
Gauge.declare(spec)
Gauge.set(spec, 100)
assert 100 == Gauge.value(spec)
Gauge.set(spec, 105)
assert 105 == Gauge.value(spec)
Gauge.reset(spec)
assert 0 == Gauge.value(spec)
end
test "inc" do
spec = [name: :http_requests_total,
labels: [:method],
help: ""]
Gauge.new(spec)
Gauge.inc(spec)
Gauge.inc(spec, 3)
assert 4 == Gauge.value(spec)
Gauge.reset(spec)
assert 0 == Gauge.value(spec)
end
test "dinc" do
spec = [name: :http_requests_total,
help: ""]
Gauge.new(spec)
Gauge.dinc(spec)
Gauge.dinc(spec, 3.5)
## dinc is async. let's make sure gen_server processed our request
Process.sleep(10)
assert 4.5 == Gauge.value(spec)
Gauge.reset(spec)
assert 0 == Gauge.value(spec)
end
test "dec" do
spec = [name: :http_requests_total,
labels: [:method],
help: ""]
Gauge.new(spec)
Gauge.dec(spec)
Gauge.dec(spec, 3)
- assert -4 == Gauge.value(spec)
+ assert (-4 == Gauge.value(spec))
Gauge.reset(spec)
assert 0 == Gauge.value(spec)
end
test "ddec" do
spec = [name: :http_requests_total,
help: ""]
Gauge.new(spec)
Gauge.ddec(spec)
Gauge.ddec(spec, 3.5)
## ddec is async. let's make sure gen_server processed our request
Process.sleep(10)
- assert -4.5 == Gauge.value(spec)
+ assert (-4.5 == Gauge.value(spec))
Gauge.reset(spec)
assert 0 == Gauge.value(spec)
end
test "set_to_current_time" do
spec = [name: :http_requests_total,
labels: [:method],
help: ""]
Gauge.new(spec)
Gauge.set_to_current_time(spec)
assert :os.system_time(:seconds) == Gauge.value(spec)
end
test "test_track_inprogress fn" do
spec = [name: :http_requests_total,
labels: [:method],
help: ""]
Gauge.new(spec)
assert 1 == Gauge.track_inprogress(spec, fn ->
Gauge.value(spec)
end)
assert_raise ErlangError, fn ->
Gauge.track_inprogress(spec, fn ->
:erlang.error({:qwe})
end)
end
assert 0 = Gauge.value(spec)
end
test "test_track_inprogress block" do
spec = [name: :http_requests_total,
labels: [:method],
help: ""]
Gauge.new(spec)
assert 1 == Gauge.track_inprogress(spec, do: Gauge.value(spec))
-
assert_raise ErlangError, fn ->
Gauge.track_inprogress spec do
:erlang.error({:qwe})
end
end
assert 0 = Gauge.value(spec)
end
test "set_duration fn" do
spec = [name: :http_requests_total,
labels: [:method],
help: "",
duration_unit: :seconds]
Gauge.new(spec)
assert 1 == Gauge.set_duration(spec, fn ->
Process.sleep(1000)
1
end)
assert 1 < Gauge.value(spec) and Gauge.value(spec) < 1.2
assert_raise ErlangError, fn ->
Gauge.set_duration(spec, fn ->
:erlang.error({:qwe})
end)
end
assert 0.0 < Gauge.value(spec) and Gauge.value(spec) < 0.2
end
test "set_duration block" do
spec = [name: :http_requests_total,
labels: [:method],
help: "",
duration_unit: :seconds]
Gauge.new(spec)
assert :ok == Gauge.set_duration(spec, do: Process.sleep(1000))
assert 1 < Gauge.value(spec) and Gauge.value(spec) < 1.2
assert_raise ErlangError, fn ->
Gauge.set_duration spec do
:erlang.error({:qwe})
end
end
assert 0.0 < Gauge.value(spec) and Gauge.value(spec) < 0.2
end
test "remove" do
spec = [name: :http_requests_total,
labels: [:method],
help: ""]
wl_spec = [name: :simple_gauge,
help: ""]
Gauge.new(spec)
Gauge.new(wl_spec)
Gauge.inc(spec)
Gauge.inc(wl_spec)
assert 1 == Gauge.value(spec)
assert 1 == Gauge.value(wl_spec)
assert true == Gauge.remove(spec)
assert true == Gauge.remove(wl_spec)
assert :undefined == Gauge.value(spec)
assert :undefined == Gauge.value(wl_spec)
assert false == Gauge.remove(spec)
assert false == Gauge.remove(wl_spec)
end
test "default value" do
lspec = [name: :http_requests_gauge,
labels: [:method],
help: ""]
Gauge.new(lspec)
assert :undefined == Gauge.value(lspec)
spec = [name: :something_gauge,
labels: [],
help: ""]
Gauge.new(spec)
assert 0 == Gauge.value(spec)
end
end
diff --git a/test/metric_test.exs b/test/metric_test.exs
index 53871c3..5c3ccaa 100644
--- a/test/metric_test.exs
+++ b/test/metric_test.exs
@@ -1,68 +1,70 @@
defmodule Prometheus.MetricTest do
use Prometheus.Case
doctest Prometheus.Metric
defmacro __before_compile__(_env) do
quote do
def injected_fun() do
1
end
end
end
test "@metric attributes leads to metric declaration" do
defmodule ModuleWithMetrics do
use Prometheus.Metric
@before_compile Prometheus.MetricTest
@counter name: :test_counter1, labels: [], help: "qwe"
@counter name: :test_counter2, labels: [:tag], help: "qwa"
@gauge name: :test_gauge1, labels: [], help: "qwe"
@gauge name: :test_gauge2, labels: [:tag], help: "qwa"
@boolean name: :test_boolean1, labels: [], help: "qwe"
@boolean name: :test_boolean2, labels: [:tag], help: "qwa"
@summary name: :test_summary1, labels: [], help: "qwe"
@summary name: :test_summary2, labels: [:tag], help: "qwa"
@histogram name: :test_histogram1, labels: [], buckets: [1, 2], help: "qwe"
@histogram name: :test_histogram2, labels: [:tag], buckets: [1, 2], help: "qwa"
@on_load :custom_on_load_fun
def custom_on_load_fun() do
Counter.declare(name: :custom_counter, labels: [], help: "qwe")
:ok
end
end
defmodule ModuleWithoutOnLoad do
use Prometheus.Metric
@counter name: :test_counter3, labels: [], help: "qwe"
end
assert 1 == ModuleWithMetrics.injected_fun()
assert false == Counter.declare(name: :custom_counter, labels: [], help: "qwe")
assert false == Counter.declare(name: :test_counter3, labels: [], help: "qwe")
assert false == Counter.declare(name: :test_counter1, labels: [], help: "qwe")
assert false == Counter.declare(name: :test_counter2, labels: [:tag], help: "qwa")
assert false == Gauge.declare(name: :test_gauge1, labels: [], help: "qwe")
assert false == Gauge.declare(name: :test_gauge2, labels: [:tag], help: "qwa")
assert false == Boolean.declare(name: :test_boolean1, labels: [], help: "qwe")
assert false == Boolean.declare(name: :test_boolean2, labels: [:tag], help: "qwa")
assert false == Summary.declare(name: :test_summary1, labels: [], help: "qwe")
assert false == Summary.declare(name: :test_summary2, labels: [:tag], help: "qwa")
- assert false == Histogram.declare(name: :test_histogram1, labels: [], buckets: [1, 2], help: "qwe")
- assert false == Histogram.declare(name: :test_histogram2, labels: [:tag], buckets: [1, 2], help: "qwa")
+ assert false ==
+ Histogram.declare(name: :test_histogram1, labels: [], buckets: [1, 2], help: "")
+ assert false ==
+ Histogram.declare(name: :test_histogram2, labels: [:tag], buckets: [1, 2], help: "")
end
end
diff --git a/test/model_test.exs b/test/model_test.exs
index 49a348c..b3b25bc 100644
--- a/test/model_test.exs
+++ b/test/model_test.exs
@@ -1,21 +1,21 @@
defmodule Prometheus.ModelTest do
use Prometheus.Case
require Prometheus.Model
doctest Prometheus.Model
def collect_metrics(:pool_size, _) do
Prometheus.Model.untyped_metric(365)
end
test "create_mf" do
- assert {:MetricFamily,<<"pool_size">>,<<"help">>,:UNTYPED,
- [{:Metric,[],:undefined,:undefined,:undefined,
- {:Untyped,365},
- :undefined,:undefined}]} ==
+ assert {:MetricFamily, <<"pool_size">>, <<"help">>, :UNTYPED,
+ [{:Metric, [], :undefined, :undefined, :undefined,
+ {:Untyped, 365},
+ :undefined, :undefined}]} ==
Prometheus.Model.create_mf(
:pool_size, "help", :untyped, Prometheus.ModelTest, :undefined)
end
end

File Metadata

Mime Type
text/x-diff
Expires
Thu, Nov 28, 2:26 PM (1 d, 20 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
41049
Default Alt Text
(61 KB)

Event Timeline