
Erlang/OTP 21's new logger - signa11
https://ferd.ca/erlang-otp-21-s-new-logger.html
======
xutopia
I'm really impressed with all that is happening in the Erlang/Elixir world
nowadays. I didn't realize that this community was so actively introducing new
features and improvements to what is already a rock solid toolset.

~~~
dragosmocrii
I agree. Just starting myself with Elixir, and boy do I love the pipe
operator, pattern matching, and the wonderful OTP goodies. I've only practiced
with Elixir for a couple weeks, but for work when I write PHP code, I feel
sad, and look forward to work on the next Exercism task. Also joined the
Elixir slack, never seen such an awesome community. I hope Erlang/Elixir
continues to thrive

~~~
mrdoops
The worst part of Elixir is when you're working with other languages and you
know it'd be better in Elixir.

~~~
Thaxll
Other language that have strong typing for instance or good performance?

~~~
ramchip
I enjoy Elixir tremendously, but usually I’m forced to use another language
(Python) due to popularity, not technical merits.

It’s hard to sell anything that’s not in the TIOBE top 10.

To answer your comment more directly though, for many systems the benefits of
excellent concurrency, monitorability, and fault tolerance can outweigh those
of a strong type system or raw performance. It really depends what you’re
doing, and how your team likes to work. No such thing as a silver bullet and
all that.

------
qrybam
Erlang is great - we ended up settling on it as the basis of our platform. It
was between Erlang and C++ for our real time highly available system and in
hindsight Erlang was a no brainier. So far it hasn’t disappointed.

~~~
crocal
You won’t be disappointed. I have an Erlang/OTP system in operations since
nearly 10 years. Exactly zero downtime since first day of operation. And we
did upgrades and change of hardware. The customer is in love.

~~~
uxcolumbo
Zero downtime in 10 years - sounds impressive.

What is your system doing if you don't mind the question?

~~~
crocal
It is an automatic train supervision system for a metro line. It tracks and
displays the position of trains and automatically routes them depending on
schedule, delays and incidents. It also offer control and commands of the
traction power and the devices in station such as elevators, gates, doors,
passenger information display, etc. It also logs all commands and events on
the system. It’s the « command center « of a railway if you prefer. So it must
never stops.

------
davedx
Ahh, logging, a subject dear to my heart.

At the last project I worked on, we did a lot of work to optimize our logging,
as it was being done on low spec TV set-top-boxes, and we were burning a ton
of CPU cycles just doing formatting (lots of JSON serialization). What many
devs fail to realise is that, unless extra effort is made (as in the Erlang
system in the OP), every log operation you call is a synchronous, blocking
call that can actually be relatively expensive due to all the serialization
and I/O that goes on.

Async logging can help of course (necessary if you want to send logs over the
network). But you can still spend a lot of CPU just formatting the log lines
themselves.

The solution we decided on was similar to what you'd do in a C/C++ project:
for release/production, add a build step that removes all logging commands
below the logging level for the target. For example in C, you'd usually use
macros for this, and if your macro wasn't defined in release builds, none of
the logging code would be included in your executable.

This is great for performance but does have an operational trade off. Ops
people might want to be able to change the logging level of a system to
diagnose live issues. But if I think about all the CPU cycles and HDD storage
spent on logging (and often those wasted cycles have a very real impact on UX
or server latency), then I think in many cases it is worth stripping out
anything lower than Error level as standard.

~~~
thibaut_barrere
There is a lot of care in Elixir Logger
([https://hexdocs.pm/logger/Logger.html](https://hexdocs.pm/logger/Logger.html))
with regard to this.

For instance, "arguments given to info/2 will only be evaluated if a message
is logged".

You can also trim out (at compile time, like you did with the build step) all
the logging commands below the selected level, with the
":compile_time_purge_matching" option.

~~~
davedx
That’s really awesome. All modern platforms should do this

------
blattimwind
Notably with good support for structured logging, which is usually badly
supported by log4j descendants (like e.g. Python's logging module).

------
sidkshatriya
Agree with the sentiment behind a lot of the comments above. Elixir/Erlang are
awesome and there is a lot of vitality in those communities at the moment
(more in Elixir perhaps).

Elixir is definitely a darling of HN but there are some areas where there are
some shortcomings in my point of view:

\- A lot of people seem to love Elixir macros but I actually think that they
result in a lot of compile time magic and make the code difficult to
debug/read. Macros make code easy to write but supremely difficult to behind-
the-scenes-understand and debug. The code that you write is transformed into
something very different when you run it! Also every major Elixir library
brings its own special macros which is a pain. Erlang OTOH does not use user
defined code transformations (i.e. macros) so much so the code there is easier
to comprehend. But the Erlang language is quite barebones and does not have
the expressive power of some of its functional cousins like OCaml/ML/Haskell.
Its seems that macros were an easy way to impart this expressive power to
Elixir but it comes with the above mentioned costs.

\- The Elixir (Erlang) runtime is stateful. This leads to many advantages but
I kinda love the PHP model of every request is isolated/new from the rest of
the system also. This may make PHP feel clunky/slowish but then its super easy
to debug. PHP works out fine for _most_ systems even at scale. If your system
does not have extreme requirements then PHP should work out fine.

\- Elixir is not statically typed. In 2018 for a new project its hard to
justify not using a typed system to make code more likely to "run" properly
out of the gate or increase your confidence while refactoring it. Even a
simple type system like golang's will do. No need for something complex like
C++/Java/Rust etc.

In summary there is a lot of good in the Erlang/Elixir ecosystem. I think it
makes sense to use this platform in many scenarios.

P.S. I've talked about PHP above. It continues to be fashionable to bash PHP
and I feel this is a meme that _must_ be combated. PHP 7.x is a much improved
platform. Once you look past some of its historical warts you'll find that it
can be very productive to work in. Of course it lacks static typing but if you
specify the types of the your function parameters and (comment) annotate the
type variables you can get some of the benefits of typing if you have the
correct IDE/code analysis tools. (Elixir/Erlang also have "soft" static typing
via dialyzer).

~~~
di4na
regarding point 3: In 2018, for an actor model on the BEAM, it is really easy
to justify not being statically type. For a single simple reason.

 _No one knows how to do it._ It is an open research problem and we are far
from a solution still.

~~~
erszcz
[https://github.com/josefs/Gradualizer](https://github.com/josefs/Gradualizer)
already introduced above by Zalastax is one project which shows how to do it.
It implements the gradual typing model, which merges static typing a'la
ML/Haskell, with dynamic typing of Erlang. Other real-world examples of
gradually typed languages are Facebook's Hack and TypeScript.

Erlang already has a dual nature:

\- the sequential part, which strives to be a pure and mostly side-effect free
functional language

\- the concurrent part, i.e. send, receive, process preemption, message
delivery semantics, etc, which is inherently stateful due to interactions
between stateful processes

Gradual typing fits this model well, because it provides soundness to the
sequential part of the language, while leaves the message passing parts which
_no one knows how to_ type dynamically typed.

BTW, I've spent a while to integrate Gradualizer with Vim -
[https://github.com/neomake/neomake/pull/2115](https://github.com/neomake/neomake/pull/2115)

~~~
di4na
So basically what i said. We do not know how to statically type it, just try
to provide some false safety.

------
davidw
Idle curiosity: I wonder if they fixed the 'bug' where if you had a big binary
in an error, it got translated to a string representation of a binary, which
absolutely blows up memory usage as it works its way through the logger.

In Erlang for instance, you might have a binary like <<"foo">>, which is the 3
bytes, 'f', 'o', 'o'. The display representation of it - <<"foo">> \- though,
as an Erlang string (which is a linked list of numbers) takes up 18 bytes
according to erts_debug:size, which is a huge multiplier.

As always, though, excellent writing by Fred.

~~~
mononcqc
This is mostly fixed. First, the loggers tend to use unicode-aware pretty-
printing, which lets you have rarer instances of a binary getting blown to its
integer bytes representation.

Then there's also ways to prevent just printing huge terms out. That's what
parameters like `term_depth` in many handlers do (I believe it's just `depth`
in the default handlers). They limit how deep you go into outputting some
data. So even if you have some very large strings or deeply nested structure,
they can get elided when they reach a certain threshold.

------
baby
I really like the help in the console of Elixir, but I prefer Erlang's syntax.
Is there similar tools for Erlang?

~~~
lelf
[https://github.com/erszcz/docsh](https://github.com/erszcz/docsh)

