driv3r

driv3r

Questions: How does Logger metadata works?

Metadata

Adds the given keyword list to the current process metadata.

  • How exactly does it work? Two examples in specific would be nice:
    • plug app: i.e. if I set metadata at the beginning of request in one of the plugs, and log something further on within the main app or lets say ecto, will I have this metadata there?
    • OTP app: I set metadata in core app, and ecto logs something, will it have this metadata as well?
    • when it wouldn’t work?
  • when it’s being cleaned up?

Logger.Backends.Console

You can set metadata via Logger.metadata() and add more of it with Logger.info("msg", [meta: :data]) - how does it behave in backend? Is it merged? or can I access them separately?

Why is there so much magic in log_event? wouldn’t it be enough to have IO.puts? If no then should I do exactly the same while building another logger backend?

node(gl) != node() what’s the purpose here?

Btw. it’s quite difficult to navigate through this “example” backend impelemntation, especially when it’s not documented. It would be way easier to have some kind of documented template why required and optional stuff in it.

Best,
Leszek

Most Liked

josevalim

josevalim

Creator of Elixir

I am not sure how exactly to extract that. Because it requires passing state around, you would still need to receive the messages and put them in the buffer. Maybe a Buffer data structure is what we need but I doubt it would transparently solve the problem.

The other option is to have a process that does the batching for you. It wouldn’t be useful for the Logger, because in this case we already have the Logger process, but it could be used for general batching for any party interested. pobox provides such solution.

It comes from Erlang. It is the process responsible for doing IO. There is a very detailed explanation here.

Whenever you perform an IO operation, that operation is forwarded to the “group leader”. Every process has a group leader and that can be configured. For example, Phoenix Code Reloader uses the group leader to proxy all the output that happens during compilation so it can also show compilation errors in your browser.

By default, the group leader process is the user process:

$ elixir -e "IO.inspect {Process.group_leader, Process.whereis(:user)}"
{#PID<0.24.0>, #PID<0.24.0>}

However, when you start IEx, the group leader is no longer the user process. That’s because IEx wants to have full control when your sessions output to the shell. Let’s see it:

$ iex
Erlang/OTP 18 [erts-7.1] [source] [64-bit] [smp:4:4] [async-threads:10] [hipe] [kernel-poll:false] [dtrace]

Interactive Elixir (1.4.0-dev) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)> {Process.group_leader, Process.whereis(:user)}
{#PID<0.26.0>, #PID<0.25.0>}

To see why this matters, let’s start another IEx session and have it print hello and over again:

iex(1)> Stream.interval(1000) |> Stream.each(fn _ -> IO.puts "hello" end) |> Stream.run
{:ok, #PID<0.58.0>}
hello
hello
hello
iex(2)>
User switch command (Ctrl+G)
 --> s 'Elixir.IEx'
 --> c
Interactive Elixir (1.4.0-dev) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)> Process.group_leader
#PID<0.58.0>

Notice that, after we hit Ctrl+G, we started a new shell, connected to it and we no longer see “hello” printed. That’s because the previous shell is writing to its own group leader, which is now being silenced, and the new shell got a new one.

However, if you rewrite the previous example to write to IO.puts(:user, "hello"), then it will output to whatever shell you are connected to. Let’s try it:

iex(1)> Stream.interval(1000) |> Stream.each(fn _ -> IO.puts :user, "hello" end) |> Stream.run
hello
hello

User switch command (Ctrl+G)
 --> s 'Elixir.IEx'
 --> c
hello
Interactive Elixir (1.4.0-dev) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)> hello
hello
hello
hello

In other words, the :user process allows you to always write to IO, bypassing the group leader. In most cases, the group leader is the user process though, and you don’t have to care about it.

99.9% of the times you don’t need to care about the examples or concepts above, but, since you asked, you got it. :slight_smile:

driv3r

driv3r

Thanks, that makes way more sense! Will need to find couple minutes to dive into the article :thumbsup:

So if I’m correct then the logger console backend is basically using IO.write :user, msg?

Besides that any ideas about the metadata or some articles that would explain how it works?

Best,
Leszek

Where Next?

Popular in Questions Top

_russellb
I want to try my hand at web scraping. What tools/libraries do I need to use. I’m hoping to turn this into something professional so don’...
New
tduccuong
Hi, is there any work on GUI with Elixir, that is similar to Electron/Javascript? My idea is to bundle Phoenix and BEAM into a single se...
New
jononomo
I am trying to figure out how Mix knows whether the environment is test, dev, or prod -- where is this set? Thanks.
New
Kagamiiiii
Student &amp; New to elixir. Nice language. I want to convert a english character, e.g. “a”, which is stored in a variable, to it’s asci...
New
rms.mrcs
Hi, I need to transform a list of numbers into a map where the keys are the indexes and the values are the original values of the list....
New
gonzofish
I’m currently trying to understand how to join three tables using Ecto. All the examples I’ve seen use 2, so maybe I’m just missing somet...
New
ovidiubadita
Hey all, I discovered Elixir and I love it. I always wanted to learn a functional programming and I intended to go for Haskell, but afte...
New
Mooodi
Given a string, how can I get access to its character by index? Enum.at("my_string", 2) doesn't work. Or rather, not char, but a substr...
New
Qqwy
Original source of discussion: This topic on the Pragmatic Programmers' Functional Web Development with Elixir, OTP, and Phoenix forum. ...
New
lanycrost
Hi everyone! I need implement if…else if…else condition from my elixir code, and anymore of this control flow structures not work proper...
New

Other popular topics Top

Qqwy
Update: How to use the Blogs &amp; Podcasts section You can post links to your blog posts or podcasts either in one of the Official Blog...
3268 119930 1237
New
openscript
Hello! Sorry for this astonishing simple question, but I’m really stuck. I try to set up the intellij-elixir plugin, but I don’t know ho...
New
script
If I have a string “1000 cfu/ml” . I want to remove the characters and / and space . So the string is like this "1000" What is the ...
New
freewebwithme
Using vs code and installed ElixirLS: support and debugger. And I got an error popped up on start up says Failed to run ‘elixir’ comma...
New
myronmarston
The Elixir Typespec docs show the following syntax for keyword lists in typespecs: # ... | [key: type] # keyword lis...
New
vonH
When I run the Plug and I recompile I wind up having to use Ctrl C to quit iex and start again. Witht the help of rlwrap I can use the cu...
New
stefanluptak
Hello everybody, usually, I use a 29" ultra-wide monitor for VSCode which can easily accomodate explorer (files panel) + file with code ...
New
chrisalley
ExUnit now has describe blocks which is a welcome addition coming from RSpec. In the docs, it states that nested hierarchies of describe ...
New
beno
I will often find my self writing things similar to: case some_value do nil -&gt; something() "" -&gt; something() _ -&gt; someth...
New
AstonJ
We’ve put together this wiki for Phoenix LiveView - please feel free to add any info you feel is worth including. What is Phoenix LiveV...
New

We're in Beta

About us Mission Statement