erlang-lager / lager

A logging framework for Erlang/OTP
Apache License 2.0
1.12k stars 455 forks source link

Add docs about using lager in elixir [JIRA: RIAK-2495] #348

Closed jadeallenx closed 7 years ago

jadeallenx commented 8 years ago

We should include in the readme a section about using lager in the context of elixir apps or logging abstraction libs like hut

zhaohansprt commented 7 years ago

then how it goes?

zhaohansprt commented 7 years ago

i found there is the way to call lager in elixir but seemed not like in erlang :lager.log(:error, self(), "message ~p",[:erlang.node()])

jadeallenx commented 7 years ago

Hi - I don't think anyone who works on lager day-to-day has the necessary experience with elixir to write a documentation section like this. But we would welcome someone who does to help with that section of the docs.

That's why I tagged this issue as "help wanted"

holsee commented 7 years ago

I'll give this a shot. A few things worth figuring out first...

I would say as an elixir dev there would be a few options that come to mind when including lager in a project.

I would be asking myself:

Questions like this would be great to have an answer for, to help potential consumers decide which way to go an when.

So the first thing to think about would be to figure out if I wished to use lager as a Logger backend, or directly. If I opt for directly, I would then decide if I wanted to use a wrapper weighing up the usual pros and cons of doing such a thing.

Option 1: The Elixir Logging abstraction (with a lager backend)

see: https://hexdocs.pm/logger/Logger.html#module-backends

The elixir Logger is pretty nice, and allows for "backends" to be plugged in, whilst providing a nice idiomatic logging api. Other benefits of this approach come from the elixir macro system which enables caller introspection and the logging calls to be stripped out during compile time for the logging levels that the application doesn't wish to include for a given build type.

From what I remember backends are super simple to plug in, back pressure is handled quite nicely and the adapter is supervised in a standard OTP fashion.

I would for sure be opting for this approach myself if I was, say, writing a library for redistribution in elixir so the logging strategy of choice can be plugged in. On the same note many elixir libs that I may be pulling in would also use the elixir Logger, so this scenario is certainly going to be common and should probably be mentioned.

Now wether or not lager contributors wish to provide a reference implementation is open to discussion.

Option 2: Using lager directly

Elixir modules are the same as Erlang, both are actually atoms under the hood, just Elixir provides a explicit Pascal Case module syntax that hides the fact that under the hood it is an atom prefixed with Elixir..

So as @zhaohansprt mentions, when calling Erlang from elixir it looks as follows:

iex(1)> :erlang.module_info()
[module: :erlang,
 exports: [bitsize: 1, check_process_code: 2, check_process_code: 3,
  garbage_collect: 1, garbage_collect: 2, garbage_collect_message_area: 0,
...

Option 3: Provide an Elixir Wrapper

It is not uncommon to see Elixir wrappers around Erlang libraries e.g. https://github.com/meh/amnesia

You can then tell the compiler to inline the body of the call, removing any penalty for the elixir wrapper being in place.

@compile {:inline, myfun: 1}

When you inline a function, its calls will be replaced with the function body itself at compile time. This can be used to squeeze the last bit of performance out of a specific function call, eliminating the overhead of one single function call.

As mentioned previously the elixir modules, with the same name as the Erlang modules would not clash due to the Elixir. prefix that is implicitly added under the hood.

Elixir App Config style

Another consideration regarding docs would be an Elixir specific configuration guide given the syntax elixir has for proplists and the config macro:

# config/config.exs
config :lager,
  log_root: '/var/log/hello',
  handlers: [
    lager_console_backend: :info,
    lager_file_backend: [file: "error.log", level: :error],
    lager_file_backend: [file: "console.log", level: :info]
  ]

What everyone really wants: The Quick Start :)

The most basic thing would be the quick start that would show how to add lager as a dependency properly something like:

# mix.exs
def application do
  [
    applications: [:lager],
    erl_opts: [parse_transform: "lager_transform"]
  ]
end

defp deps do
  [{:lager, github: "erlang-lager/lager"}]
end

Hope that is helpful, giving a little insight to an elixir devs point of view. I will start to put something together and it can be tweaked as needs be.

jadeallenx commented 7 years ago

Wow, lovely @holsee. Would be great to get this in a PR :)

jadeallenx commented 7 years ago

Any further progress on this?

holsee commented 7 years ago

@mrallen1 it has been on my todo list, not been forgotten 👍 . I just wanted to verify that the parse transforms and the api in the comment was working ok and that was taking a little more time that I have had free recently.

I plan to mimic the Erlang snippets with the elixir versions and add a section for "elixir considerations" that dumps some of the pertinent info from my last comment.

Tis St Patrick's tomorrow ☘️ but I am sure I could get a PR in tomorrow morning if not in by later this evening if all goes to plan.

holsee commented 7 years ago

Dang!

https://github.com/elixir-lang/elixir/issues/5762 Deprecate usage of parse_transforms

https://github.com/elixir-lang/elixir/blob/master/lib/elixir/lib/module.ex#L1064

# TODO: Remove on Elixir v2.0
case value do
  {:parse_transform, _} when key == :compile and is_list(stack) ->
    IO.warn "@compile {:parse_transform, _} is deprecated. " <>
            "Elixir will no longer support Erlang-based transforms in future versions", stack
  _ ->
    :ok
end

Reaching out to the core team to see what's up, as we wont want to recommend using parse transforms if this is going to be removed from the language!

This isn't a show stopper for lager use in elixir, as a shim would still allow for the same functionality via elixir's macros, but that would have to be another project.

fishcakez commented 7 years ago

@holsee I believe some additional config/advise will be required to prevent lager and logger squabbling over error_logger handlers. I have not used logger since the 2.* so might be incorrect about this.

holsee commented 7 years ago

I am wondering if we even document anything for elixir at this point, as a related elixir_lagger project with the wrapper seems in order. We could however put something in lager README for now to help folks out, I have a good idea of what to put in to help people get started.

@fishcakez can you be specific please, code example? Not familiar with this issue.

fishcakez commented 7 years ago

@holsee a lager -> logger forwarded had this config to prevent lager removing the logger handler: https://github.com/PSPDFKit-labs/lager_logger/blob/master/config/config.exs#L7. Note that parse transforms are not going to stop working for quite a while. The deprecation is there to give people ample time to move away from them so that Elixir is not bound to Erlang AST in the long term.

jadeallenx commented 7 years ago

OK, I merged #398 so I'm going to close this issue. Thanks @holsee for the writing and @fishcakez for your comments and review!