chulkilee

chulkilee

MetadataLogger: logging with metadata (+ tesla / plug middleware)

Hi all,

Here are several libraries I wrote to do structured logging with logger metadta.

(There were in different name - now renamed to metadata_logger_* and moved to own github org)

Highlights

  • Formatter, not backend; e.g. it doesn’t reimplement console logger backend. Choose your own backend! (or just console)
  • Minimal transformation: if you pass struct into metadata, it won’t convert it to map blindl; this is to prevent from leaking data into logs by accident. It uses Jason :slight_smile:
  • Return IO data (not building a large binary!)

See also

Most Liked

hauleth

hauleth

As you correctly pointed to my post on the forum with call for testers I need to make few statements:

  • In near future (when the new logger implementation stabilises) we will add proper structured logging to the Elixir’s Logger where metadata and “log message” (or, as called by Erlang, report) will be possible without any wrappers (#9465)
  • There is plan to deprecate “old” backends (and naturally formatters) in favour of using Erlang’s handlers and formatters API directly (#7928)

Additionally your metadata_logger_plug is currently more or less possible via Plug.Telemetry API, which I believe is currently more standardised and commonly supported (ex. Phoenix.Logger uses that).


However, nice work and I really appreciate idea of bringing structured logging to Elixir.

chulkilee

chulkilee

Thanks! I know there are lots of work going on logging and telemetry (which can be used for logging as well).

Here are my takes:

Log formatter will remain - just in different form: seems like new erlang logger (21.1) has log_formatter and Elixir is planning to use same mechanism so that elixir and erlang use same log event, and leverage same logging backend (via passing handler_config)

Metadata will be a map - I think this is the right way to go, as erlang already uses map ref (and it’s planned in #7928)

Passing map as a message is planned but it won’t invalidate use of metadata - passing a map as a message is planned in #9465. However, I see metadata is for scope-based while map message is for per message - and I found both are needed when I’m using them.

Note that this can be done even in the current Elixir if you use formatter taking a map message :wink: See this PR I just wrote…

instrumentation logging via :telemetry - I really like that idea! Plug.Telemetry was added after I wrote this middleware :wink: I created issues: for plug and for tesla

hauleth

hauleth

I am fully aware of the implementation and future plans, I made both of them :wink:

Yes, but the plan is to make it Erlang logger formatter, as you have noticed.

Internally, yes, from the user viewpoint, no. This is required for the compatibility. So in Elixir 1.10 it will be changed before returning in Logger.metadata/0.

Yes, as metadata is for something completely different. Using your example in metadata_logger_plug the status, body length, and response status should be part of the report, not metadata. Metadata is more about, well, meta data like: version, log position, module, function, application name, etc.

Well, partially. It will work for that particular formatter, but in general it will fail (also Dialyzer will complain) as you break contract about type of the accepted data. So that single formatter will work (because it relies on undefined behaviour), but any other will fail, and this will fail with parsing Erlang reports, as these are handled before these end in your translator.

hauleth

hauleth

No, because request id isn’t part of the log message, it is part of the context for the log message. This is huge difference that I am pointing there. Erlang logger also makes these difference as there are separate. If I would need to define in short the difference then I would say:

  • report/log message is about what happened (ex. Responded with OK 200 in 532ms (1 KiB) or %{http_response_code: 200, http_response_time: 532_000, http_body_size: 1024})
  • metadata is about when and where it happened (line: 42, mfa: {Foo.Controllers.Users, :show, 2}, time: 1573853293025234000, pid: #PID<0.108.0>), additionally it will contain all “meta” stuff, like mentioned report_cb

So you do not mix metadata and log data, and you do not need to pass some metadata to each execution. How it is presented later is completely different thing. Some tools make it even more distinct (for example Grafana’s Loki) as metadata are indexed, so these shouldn’t vary too much to not bloat indices, while data is not parsed at all.

And this is a little bit of the problem, as such data do not belong to the “metadata”, as this is data (without “meta” part). Fortunately in near future this will change.

Where Next?

Popular in Libraries Top

mathieuprog
Hello :wave: Allow me to introduce you to Tz, an alternative time zone database support to Tzdata. Why another library? First and fore...
New
Qqwy
Solution is a library to help you with working with ok/error-tuples in case and with-expressions by exposing special matching macros, as ...
New
MRdotB
I needed to reuse React components from my Chrome extension in my Phoenix/LiveView backend. I noticed that for Svelte/Vue, there are live...
New
martinthenth
Hello everybody :wave: Recently, some of my colleagues talked about database ids and uuids and their problems, and I remembered the pain...
New
Jskalc
Hi! Today, after a couple weeks of development I’ve released v0.1 of LiveVue. It’s a seamless integration of Vue and Phoenix LiveView, i...
New
zorbash
I created Kitto a framework for dashboards inspired by Dashing. [demo] The distributed characteristics of Elixir and the low memory foo...
New
handnot2
Samly can be used to enable SAML 2.0 Single Sign On in a Plug/Phoenix application. This library uses Erlang esaml to provide plug enabl...
New
KallDrexx
For a good number of months I've been working on creating a very basic RTMP live video streaming server. Now that I have a very, very ba...
New
mplatts
With HEEX released we decided to start a components library using Tailwind CSS - check it out here: Petal Components. We also have a boi...
New
New

Other popular topics Top

Brian
What is the proper way to load a module from a file in to IEX? In the python world, doing something like this pretty standard: from ....
New
shahryarjb
Hello, I get Persian date from my client and convert it to normal calendar like this: def jalali_string_to_miladi_english_number(persi...
New
sergio
In Ruby, I can go: User.find_by(email: "foobar@email.com").update(email: "hello@email.com") How can I do something similar in Elixir? ...
New
Tee
can someone please explain to me how Enum.reduce works with maps
New
pmjoe
I have a relationship of love and hate with Elixir. Lots of things are just absolutely right, but there are some things that are kind of ...
New
lessless
I believe there are people here who are dealing with CSV files import on the daily basis, and since Excel is a really popular tool there ...
New
yawaramin
In the Dialyzer docs ( http://erlang.org/doc/man/dialyzer.html#requesting-or-suppressing-warnings-in-source-files ), there is a way to tu...
New
jerry
Good day to you all. I have been struggling to get a query involving like and ilike to work. Can anyone assist me on this, please? pro...
New
stefanchrobot
What’s the safe way to decode a JSON string into a struct? I want to avoid calling String.to_atom. Jason.decode can give me a map with st...
New
WestKeys
Currently suffering from paralysis by [HTTP client] analysis. This is rather unusual in Elixirland as there tends to be consensus on the ...
New

Sub Categories:

We're in Beta

About us Mission Statement