Logging in Erlang

Our first program will demonstrate basic logging functionality in Erlang. Here’s the full source code:

-module(logging_example).
-export([main/0]).

main() ->
    % Simple logging using io:format
    io:format("standard logger~n"),

    % Logging with timestamp
    io:format("~s: with timestamp~n", [timestamp()]),

    % Logging with custom prefix
    log_with_prefix("my:", "from mylog"),

    % Logging to a file
    {ok, File} = file:open("log.txt", [write]),
    io:format(File, "hello~n", []),
    file:close(File),

    % Reading from the file and printing
    {ok, Content} = file:read_file("log.txt"),
    io:format("from file: ~s", [Content]),

    % Structured logging using lager
    application:ensure_all_started(lager),
    lager:info("hi there"),
    lager:info("hello again", [{key, "val"}, {age, 25}]).

% Helper function to get timestamp
timestamp() ->
    {{Year, Month, Day}, {Hour, Minute, Second}} = calendar:local_time(),
    io_lib:format("~4..0B/~2..0B/~2..0B ~2..0B:~2..0B:~2..0B",
                  [Year, Month, Day, Hour, Minute, Second]).

% Helper function to log with prefix
log_with_prefix(Prefix, Message) ->
    io:format("~s~s: ~s~n", [Prefix, timestamp(), Message]).

To run the program, save it as logging_example.erl and use the Erlang shell:

$ erl
1> c(logging_example).
{ok,logging_example}
2> logging_example:main().
standard logger
2023/08/22 10:45:16: with timestamp
my:2023/08/22 10:45:16: from mylog
from file: hello
10:45:16.904 [info] hi there
10:45:16.904 [info] hello again key=val age=25
ok

Let’s break down the example:

  1. We start with simple logging using io:format/1, which is similar to Println in the original example.

  2. We then demonstrate logging with a timestamp. In Erlang, we need to create our own timestamp function.

  3. Custom prefixes are implemented using a helper function log_with_prefix/2.

  4. For logging to a file, we use Erlang’s built-in file operations.

  5. To demonstrate structured logging, we use the lager library, which is commonly used for logging in Erlang applications. Note that you’ll need to add lager as a dependency to your project to use it.

  6. The lager:info/2 function allows us to log both a message and a list of key-value pairs, similar to the structured logging in the original example.

Erlang doesn’t have a direct equivalent to Go’s log package with flags and prefixes. However, we can achieve similar functionality using a combination of io:format/2 and custom functions.

For more advanced logging needs, consider using established Erlang logging frameworks like lager or logger (OTP 21+), which provide more sophisticated features for production environments.