Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F115686
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Award Token
Flag For Later
Size
61 KB
Referenced Files
None
Subscribers
None
View Options
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
Details
Attached
Mime Type
text/x-diff
Expires
Thu, Nov 28, 2:26 PM (1 d, 18 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
41049
Default Alt Text
(61 KB)
Attached To
Mode
R26 prometheus.ex
Attached
Detach File
Event Timeline
Log In to Comment