Skip to content

Commit

Permalink
use credo
Browse files Browse the repository at this point in the history
  • Loading branch information
deadtrickster committed Oct 22, 2016
1 parent 1f3f1fe commit e3e3d3a
Show file tree
Hide file tree
Showing 28 changed files with 345 additions and 167 deletions.
64 changes: 64 additions & 0 deletions .credo.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
%{
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.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.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},
]
}
]
}
4 changes: 4 additions & 0 deletions .dir-locals.el
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
((nil . ((indent-tabs-mode . nil)
(fill-column . 90)
(eval . (turn-on-fci-mode))))
)
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,5 @@ erl_crash.dump

# Also ignore archive artifacts (built via "mix archive.build").
*.ez

.\#*
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,4 @@ sudo: false
before_script:
- mix deps.get --only test
script:
- "MIX_ENV=test mix coveralls.travis"
- "MIX_ENV=test mix credo --strict && MIX_ENV=test mix coveralls.travis"
45 changes: 29 additions & 16 deletions lib/prometheus.ex
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
defmodule Prometheus do

@moduledoc"""
[Prometheus.io](http://prometheus.io) client library powered by [prometheus.erl](https://hexdocs.pm/prometheus)
[Prometheus.io](http://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:
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.
- configuration helpers that are really handy if you plan to write your custom
instrumenter.
```elixir
defmodule ExampleInstrumenter do
Expand All @@ -23,7 +25,9 @@ defmodule Prometheus do
end
def instrument(%{time: time, method: method}) do
Histogram.observe([name: :http_request_duration_milliseconds, labels: [method]], time)
Histogram.observe([name: :http_request_duration_milliseconds,
labels: [method]],
time)
end
end
Expand All @@ -33,7 +37,8 @@ defmodule Prometheus do
- [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);
- [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).
Expand All @@ -49,24 +54,28 @@ defmodule Prometheus do
### Standard Metrics & Registry
- `Prometheus.Metric.Counter` - counter metric, to track counts of events or running totals;
- `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.
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).
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.
Histogram also accepts `buckets` option. Please refer to respective modules docs
for the more information.
### General Helpers
Expand All @@ -75,16 +84,20 @@ defmodule Prometheus do
### Integration Helpers
- `Prometheus.Config` - provides standard configuration mechanism for custom instrumenters/exporters.
- `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.
- `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.
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.
Expand Down
7 changes: 4 additions & 3 deletions lib/prometheus/buckets.ex
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ defmodule Prometheus.Buckets do
iex(2)> Prometheus.Buckets.default()
[0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1, 2.5, 5, 10]
Please note these buckets are floats and represent seconds so you'll have to use `Prometheus.Metric.Histogram.dobserve/2` or
configure duration_unit as `:seconds`.
Please note these buckets are floats and represent seconds so you'll have to use
`Prometheus.Metric.Histogram.dobserve/2` or configure duration_unit as `:seconds`.
"""
defmacro default do
Expand Down Expand Up @@ -43,7 +43,8 @@ defmodule Prometheus.Buckets do
iex(2)> Prometheus.Buckets.linear(10, 5, 6)
[10, 15, 20, 25, 30, 35]
The function raises `Prometheus.InvalidValueError` exception if `count` is zero or negative.
The function raises `Prometheus.InvalidValueError` exception
if `count` is zero or negative.
"""
defmacro linear(start, step, count) do
Erlang.call([start, step, count])
Expand Down
16 changes: 9 additions & 7 deletions lib/prometheus/collector.ex
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@ defmodule Prometheus.Collector do
@moduledoc """
A collector for a set of metrics.
Normal users should use `Prometheus.Metric.Gauge`, `Prometheus.Metric.Counter`, `Prometheus.Metric.Summary`
Normal users should use `Prometheus.Metric.Gauge`, `Prometheus.Metric.Counter`,
`Prometheus.Metric.Summary`
and `Prometheus.Metric.Histogram`.
Implementing `:prometheus_collector` behaviour is for advanced uses such as proxying metrics from another monitoring system.
Implementing `:prometheus_collector` behaviour is for advanced uses such as proxying
metrics from another monitoring system.
It is the responsibility of the implementer to ensure produced metrics are valid.
You will be working with Prometheus data model directly (see `Prometheus.Model` ).
Expand All @@ -24,9 +26,9 @@ defmodule Prometheus.Collector do
```
iex(3)> defmodule Prometheus.VMMemoryCollector do
...(3)> use Prometheus.Collector
...(3)>
...(3)>
...(3)> @labels [:processes, :atom, :binary, :code, :ets]
...(3)>
...(3)>
...(3)> def collect_mf(_registry, callback) do
...(3)> memory = :erlang.memory()
...(3)> callback.(create_gauge(
Expand All @@ -35,22 +37,22 @@ defmodule Prometheus.Collector do
...(3)> memory))
...(3)> :ok
...(3)> end
...(3)>
...(3)>
...(3)> def collect_metrics(:erlang_vm_bytes_total, memory) do
...(3)> Prometheus.Model.gauge_metrics(
...(3)> for label <- @labels do
...(3)> {[type: label], memory[label]}
...(3)> end)
...(3)> end
...(3)>
...(3)>
...(3)> defp create_gauge(name, help, data) do
...(3)> Prometheus.Model.create_mf(name, help, :gauge, __MODULE__, data)
...(3)> end
...(3)> end
iex(4)> Prometheus.Registry.register_collector(Prometheus.VMMemoryCollector)
:ok
iex(5)> r = ~r/# TYPE erlang_vm_bytes_total gauge
...(5)> # HELP erlang_vm_bytes_total
...(5)> # HELP erlang_vm_bytes_total
...(5)> The total amount of memory currently allocated.
...(5)> erlang_vm_bytes_total{type=\"processes\"} [1-9]
...(5)> erlang_vm_bytes_total{type=\"atom\"} [1-9]
Expand Down
12 changes: 8 additions & 4 deletions lib/prometheus/config.ex
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ defmodule Prometheus.Config do
: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, [required_option: "Hello world!"])
iex(7)> Application.put_env(:prometheus, MyInstrumenter,
...(7)> [required_option: "Hello world!"])
:ok
iex(8)> MyInstrumenter.Config.required_option!(MyInstrumenter)
"Hello world!"
Expand All @@ -29,7 +30,8 @@ defmodule Prometheus.Config do

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"
"mandatory option :#{option} not found" <>
" in #{friendly_key_name} instrumenter/collector config"
end
end

Expand All @@ -51,13 +53,15 @@ defmodule Prometheus.Config do
end

defp config(key, option, default) do
config(key)
key
|> config()
|> Keyword.get(option, default)
end

defp config(key, option) do
try do
config(key)
key
|> config()
|> Keyword.fetch!(option)
rescue
e in KeyError -> raise %KeyNotFoundError{key: key, option: option}
Expand Down
2 changes: 1 addition & 1 deletion lib/prometheus/contrib/http.ex
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ defmodule Prometheus.Contrib.HTTP do
quote do
require Prometheus.Error
Prometheus.Error.with_prometheus_error(
:prometheus_http.status_class(unquote(code))
:prometheus_http.status_class(unquote(code))
)
end
end
Expand Down
19 changes: 12 additions & 7 deletions lib/prometheus/erlang.ex
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,8 @@ defmodule Prometheus.Erlang do
require Prometheus.Error

Prometheus.Error.with_prometheus_error(
unquote(module).unquote(function)(unquote(registry), unquote(name), unquote(labels),
unquote_splicing(arguments)))
unquote(module).unquote(function)(unquote(registry), unquote(name),
unquote(labels), unquote_splicing(arguments)))

end
_ ->
Expand All @@ -75,14 +75,19 @@ defmodule Prometheus.Erlang do

defp parse_metric_call_args(mf_or_spec, spec, arguments) do
case mf_or_spec do
{_,_} -> {mf_or_spec, spec, arguments} ## Erlang.metric_call({:prometheus_counter, :dinc}, spec, [value])
_ when is_atom(mf_or_spec) -> {mf_or_spec, spec, arguments} ## Erlang.metric_call(:inc, spec, [value])
## Erlang.metric_call({:prometheus_counter, :dinc}, spec, [value])
{_,_} -> {mf_or_spec, spec, arguments}
## Erlang.metric_call(:inc, spec, [value])
_ when is_atom(mf_or_spec) -> {mf_or_spec, spec, arguments}
_ ->
[] = arguments ## args are 'shifted' to left
## args are 'shifted' to left
[] = arguments
if spec == false do
{false, mf_or_spec, []} ## only spec is needed, e.g. Erlang.metric_call(spec)
## only spec is needed, e.g. Erlang.metric_call(spec)
{false, mf_or_spec, []}
else
{false, mf_or_spec, spec} ## Erlang.metric_call(spec, [value])
## Erlang.metric_call(spec, [value])
{false, mf_or_spec, spec}
end
end
end
Expand Down
16 changes: 10 additions & 6 deletions lib/prometheus/error.ex
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
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`.
Raised when given `value` is invalid i.e. when you pass a negative number to
`Prometheus.Metric.Counter.inc/2`.
"""
defexception [:value, :orig_message]

Expand All @@ -11,8 +12,8 @@ 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.
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]

Expand Down Expand Up @@ -66,8 +67,8 @@ 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 `__`.
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.
"""
Expand Down Expand Up @@ -142,6 +143,8 @@ end
defmodule Prometheus.Error do
@moduledoc false

@lint [{Credo.Check.Refactor.ABCSize, false},
{Credo.Check.Refactor.CyclomaticComplexity, false}]
def normalize(erlang_error) do
case erlang_error do
%ErlangError{original: original} ->
Expand All @@ -165,7 +168,8 @@ defmodule Prometheus.Error do
{:histogram_no_buckets, buckets} ->
%Prometheus.HistogramNoBucketsError{buckets: buckets}
{:histogram_invalid_buckets, buckets, message} ->
%Prometheus.HistogramInvalidBucketsError{buckets: buckets, orig_message: message}
%Prometheus.HistogramInvalidBucketsError{buckets: buckets,
orig_message: message}
{:histogram_invalid_bound, bound} ->
%Prometheus.HistogramInvalidBoundError{bound: bound}
{:missing_metric_spec_key, key, spec} ->
Expand Down
Loading

0 comments on commit e3e3d3a

Please sign in to comment.