Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/marianoguerra/einfo
An Erlang library, macros and parse transform for structured, standard errors with more context
https://github.com/marianoguerra/einfo
Last synced: about 1 month ago
JSON representation
An Erlang library, macros and parse transform for structured, standard errors with more context
- Host: GitHub
- URL: https://github.com/marianoguerra/einfo
- Owner: marianoguerra
- License: other
- Created: 2016-10-08T18:13:21.000Z (about 8 years ago)
- Default Branch: master
- Last Pushed: 2016-10-09T16:17:33.000Z (about 8 years ago)
- Last Synced: 2023-10-26T11:21:34.664Z (about 1 year ago)
- Language: Erlang
- Size: 43.9 KB
- Stars: 6
- Watchers: 4
- Forks: 0
- Open Issues: 1
-
Metadata Files:
- Readme: README.rst
- License: LICENSE
Awesome Lists containing this project
README
einfo
=====A library, macros and parse transform for structured, standard errors with more
contextBuild
-----::
rebar3 compile
Test
----::
rebar3 ct
Use
---Add einfo as a dependency on your project, on rebar for example:
.. code-block:: erl
{einfo, {git, "https://github.com/marianoguerra/einfo", {branch, "master"}}}
Add the einfo_pt parse transform to your config, on rebar for example:
.. code-block:: erl
{erl_opts, [debug_info, {parse_transform, einfo_pt}]}.
For now, on the module you want to use it, include einfo.hrl:
.. code-block:: erl
-include_lib("einfo/include/einfo.hrl").
What does it do
---------------it will transform the module in test/pt_samples/module1.erl from:
.. code-block:: erl
-module(module1).
f1 () ->
A = einfo:error(my_bad),
f2(A).f2(1) -> one;
f2(2) -> two;
f2(X) -> einfo:error(badarg, io_lib:format("bad argument: ~p", [X])).f3(A, 0) ->
einfo:error(division_by_zero, "dividing " ++ integer_to_list(A) ++ " by 0");
f3(A, B) -> A / B.f_extra(A) ->
einfo:error(badarg, io_lib:format("bad argument: ~p", [A]),
#{arg => A, bad => true}).wrap() ->
einfo:wrap(badarg, {error, parent_cause}).wrap(Error) ->
einfo:wrap(badarg, Error).wrap_msg() ->
einfo:wrap(badarg, "Msg", {error, parent_cause}).wrap_extra() ->
einfo:wrap(badarg, "Msg", #{with_parent => true}, {error, parent_cause}).format(X) ->
einfo:format(badarg, "bad argument: ~p", [X]).format_extra(A) ->
einfo:format(badarg, "bad argument: ~p", [A], #{arg => A, bad => true}).wrap_format(X) ->
einfo:wrap_format(badarg, "bad argument: ~p", [X], {error, parent}).wrap_format_extra(A) ->
einfo:wrap_format(badarg, "bad argument: ~p", [A], #{arg => A, bad => true},
{error, parent}).to:
.. code-block:: erl
-module(module1).
-include_lib("einfo/include/einfo.hrl").
f1() ->
A = {error,
#einfo{type = my_bad, msg = "my_bad",
module = module1, function = f1, arity = 0, line = 8,
cause = undefined, extra = undefined}},
f2(A).f2(1) -> one;
f2(2) -> two;
f2(X) ->
{error,
#einfo{type = badarg,
msg = io_lib:format("bad argument: ~p", [X]),
module = module1, function = f2, arity = 1, line = 13,
cause = undefined, extra = undefined}}.f3(A, 0) ->
{error,
#einfo{type = division_by_zero,
msg = "dividing " ++ integer_to_list(A) ++ " by 0",
module = module1, function = f3, arity = 2, line = 16,
cause = undefined, extra = undefined}};
f3(A, B) -> A / B.f_extra(A) ->
{error,
#einfo{type = badarg,
msg = io_lib:format("bad argument: ~p", [A]),
module = module1, function = f_extra, arity = 1,
line = 20, cause = undefined,
extra = #{arg => A, bad => true}}}.wrap() ->
{error,
#einfo{type = badarg, msg = "badarg",
module = module1, function = wrap, arity = 0, line = 24,
cause = {error, parent_cause}, extra = undefined}}.wrap(Error) ->
{error,
#einfo{type = badarg, msg = "badarg",
module = module1, function = wrap, arity = 1, line = 27,
cause = Error, extra = undefined}}.wrap_msg() ->
{error,
#einfo{type = badarg, msg = "Msg",
module = module1, function = wrap_msg, arity = 0,
line = 30, cause = {error, parent_cause}, extra = undefined}}.wrap_extra() ->
{error,
#einfo{type = badarg, msg = "Msg",
module = module1, function = wrap_extra, arity = 0,
line = 33, cause = {error, parent_cause},
extra = #{with_parent => true}}}.format(X) ->
{error,
#einfo{type = badarg,
msg = io_lib:format("bad argument: ~p", [X]),
module = module1, function = format, arity = 1,
line = 36, cause = undefined, extra = undefined}}.format_extra(A) ->
{error,
#einfo{type = badarg,
msg = io_lib:format("bad argument: ~p", [A]),
module = module1, function = format_extra, arity = 1,
line = 39, cause = undefined,
extra = #{arg => A, bad => true}}}.wrap_format(X) ->
{error,
#einfo{type = badarg,
msg = io_lib:format("bad argument: ~p", [X]),
module = module1, function = wrap_format, arity = 1,
line = 42, cause = {error, parent}, extra = undefined}}.wrap_format_extra(A) ->
{error,
#einfo{type = badarg,
msg = io_lib:format("bad argument: ~p", [A]),
module = module1, function = wrap_format_extra,
arity = 1, line = 45, cause = {error, parent},
extra = #{arg => A, bad => true}}}.Note that include_lib for einfo.hrl will only be included if it wasn't there
API
---Parameters
..........Type
An atom describing the type of error in a computer friendly way
What you would put as second element in an error tuple: {error, Type}Msg
A string describing the error in human a friendly wayExtra
Extra data that serves as context for the error, for example if the error
was caused because of a bad key, you can add the key in the extra fieldCause
If this error was caused by another internal error you can put the internal
error in this field so you can have traceback-like informationModule
The module where the error was generated as an atomFunction
The function where the error was generated as an atomArity
The arity of the function where the error was generated as an intLine
The line where the error was generated as an intParse Transforms
................All calls set module, function, arity and line
einfo:error(Type)
Create an error with type set, msg is a string version of typeeinfo:error(Type, Msg)
Create an error with type and msg seteinfo:error(Type, Msg, Extra)
Create an error with type and msg and extra seteinfo:wrap(Type, Cause)
Create an error with type and cause set, msg is a string version of typeeinfo:wrap(Type, Msg, Cause)
Create an error with type, msg and cause seteinfo:wrap(Type, Msg, Extra, Cause)
Create an error with type, msg, extra and cause seteinfo:format(Type, Format, FormatData)
Create an error with type set, msg is a the result of calling at runtime
io_lib:format(Format, FormatData)einfo:format(Type, Format, FormatData, Extra)
Create an error with type and extra set,
msg is a the result of calling at runtime
io_lib:format(Format, FormatData)einfo:wrap_format(Type, Format, FormatData, Cause)
Create an error with type and cause set,
msg is a the result of calling at runtime
io_lib:format(Format, FormatData)einfo:wrap_format(Type, Format, FormatData, Extra, Cause)
Create an error with type, extra and cause set,
msg is a the result of calling at runtime
io_lib:format(Format, FormatData)Functions
.........einfo:to_string(EInfo | {error, EInfo})
Return a one line string representation of the error, without the cause
Something like:
'Error: {type}\@{module}:{function}/{arity}:{line} \"{msg}\" ({extra})'einfo:print(EInfo | {error, EInfo})
print string representation with io:formattype(EInfo)
Return the value of the type field
msg(EInfo)
Return the value of the msg field
module(EInfo)
Return the value of the module field
line(EInfo)
Return the value of the line field
function(EInfo)
Return the value of the function field
arity(EInfo)
Return the value of the arity field
cause(EInfo)
Return the value of the cause field
extra(EInfo)
Return the value of the extra field
extra(EInfo, Key)
Lookup Key in the extra field, works if Extra is a Map or PropList, returns
undefined if not found
extra(EInfo, Key, Default)
Lookup Key in the extra field, works if Extra is a Map or PropList, returns
Default if not foundto_plist(EInfo)
Returns the EInfo record as a proplistto_map(EInfo)
Returns the EInfo record as a map, supported on Erlang >= 17Macros
......Note: **function** and **arity** fields will only be set on Erlang >= 19
NEW_ERROR(Type)
Like einfo:error/1 but as a macro
NEW_ERROR(Type, Msg)
Like einfo:error/2 but as a macro
NEW_ERROR(Type, Msg, Extra)
Like einfo:error/3 but as a macroWRAP_ERROR(Type, Cause)
Like einfo:wrap/2 but as a macro
WRAP_ERROR(Type, Msg, Cause)
Like einfo:wrap/3 but as a macro
WRAP_ERROR(Type, Msg, Extra, Cause)
Like einfo:wrap/4 but as a macroTypes
....... code-block:: erl
-type einfo() :: #einfo{}.
-type type() :: atom().
-type msg() :: string().
-type line() :: non_neg_integer().
-type error() :: {error, einfo()} | {error, atom()} | undefined.
-type extra() :: any().TODO
----* automatic include_lib doesn't seem to be working
Ideas:
* maybe include only record definition instead of -include_lib einfo.hrl?
Author
------Mariano Guerra
License
-------BSD, see LICENSE