## 9 Error Logging

There is a system process with the registered name `error_logger`. This process receives all error messages from the Erlang runtime system and error messages sent by the error reporting functions in the module `error_logger`.

This section describes the following topics:

- error types
- error message handling
- the standard error logger
- customized error report handlers.

### 9.1 Types of Errors

Errors are divided into the following three categories:

- predicted, recoverable errors
- predicted, unrecoverable errors
- unpredicted errors.

The system designer has to decide if a process can recover from predicted errors.

The last two categories of errors cause an abnormal termination of the process.

### 9.2 Error Message Handling

Errors can be reported by propagating an EXIT signal, by producing an error report, or both of these methods. The following table summarizes how the three categories of errors can be reported.

Error Message Reporting
Category | EXIT reason | Error report
Predicted and recoverable | - | yes
Predicted and unrecoverable | yes | yes
Not predicted | yes | -

Recoverable errors are not reported by EXIT signals because the process does not terminate. Unpredicted errors are only reported by EXIT signals because the program does not take care of these errors.

| The recovery from predicted errors is interpreted as an internal process error recovery. A process restart, issued by the layer above in the supervision tree, can also be used to recover from errors.

An unrecoverable, but predicted error can provide meaningful error descriptions, not only in an error report but also through an informative EXIT reason. It is recommended that the EXIT reason is composed as `{Reason,{Mod,Fun,Args}}` where:

- `Reason` is an informative error descriptor, for example an atom or `{atom, Value}`.
- `{Mod,Fun,Args}` is the `Mod`:`Fun`(`Args`) function where the error is detected.

### 9.3 The Standard Error Logger

The `error_logger` process receives and handles the following types of errors:

- all errors generated by the Erlang runtime system (the `emulator`)
- errors reported through the `error_logger` module interface functions `error_msg/1`, `error_msg/2`, `info_msg/1`, `info_msg/2`, `format/2`, `error_report/1`, and `info_report/1`.

When the `error_logger` process receives an error, it is sent to the the `error_logger` on the node which is the group leader process for the process which caused the error.

During system start-up, errors are kept in a buffer and they are also written unformatted to `standard out`, because error message handling is determined by the start-up process. The standard `error_logger` provides two possibilities:

- write to `standard_out`
- write to a specified file.

All buffered errors are written again when the intended handler is installed. Initially errors are written in the format `{error_logger,Time,Arg1,Arg2}`, where:

- `Time` is a tuple which contains date and time information
- `Arg1` and `Arg2` are the arguments given to a report function.

When a standard handler is installed, errors are written in the following format:

        =ERROR REPORT=== Time ====
         Formatted error

`Formatted error` error messages, which are reported through the `format` or `error_msg` functions calls, are produced from `Format` and `Args` in the same way as in the function `io:format/2`. If the error was reported through the supplied `error_report(Report)` function, the `Report` argument is interpreted and written as follows:

- `[{Tag,Info}]`, where `Tag` and `Info` is any term. Each `{Tag,Info}` tuple is written on a separate line:

               Tag: Info

- `Other` is written as `io_lib:format("~p~n",[Other])`.

It is also possible to use the `info_report(Report)` function to format `Report` as `error_report/1` in the above example, but with the heading:

        =INFO REPORT=== Time ====

### 9.4 Adding A Customized Report Handler

It is possible to add customized error report handlers to the `error_logger` process. This may be desirable in order to satisfy one of the following purposes:

- to perform additional processing of standard error messages
- to override the standard behaviour (the standard handlers must be deleted)
- to handle new types of error messages.

The following two functions are used to add and delete handlers:

- `add_report_handler` to add a handler
- `delete_report_handler` to delete a handler.

| It is strongly recommended that the standard error reporting functions be used. Customized handlers should only be added if they are really needed.

The `error_logger` is implemented with the `gen_event` behaviour. This means that an event callback module has to be implemented in order to add an associated error logger handler .

All handlers installed within the `error_logger` are notified about errors that are received by the `error_logger`. This notification is done by calling `handle_event/2` in each callback module. This means that several actions can be performed when specific events occur. For example, the standard `error_logger` behaviour can be accompanied by an SNMP trap which is triggered when a pre-determined level of error messages have been received.

New types of error message can be reported with the `error_report/2` and `info_report/2` functions. Errors which are reported this way are ignored by the standard error logger handlers and would be lost unless an associated handler has been installed.

The event generated by calling `error_logger:error_report(Type, Report)`, and which has to be handled by the added error report handler, is the term:

- `{error_report, Gleader, {Type, Pid, Report}}` where:
  - `Gleader` is the group leader process of the process which executes the function call.
  - `Type` is a term which identifies the type of the error report.
  - `Pid` is the process identity of the process that issued the error report. The `Pid` can be used to determine at which node the report was generated.
  - `Report` is a term which describes the error. This term must be recognized by the customized error report handler.

Substitute `info_report` in place of `error_report` when calling the `error_logger:info_report(Type, Report)` function.

| No standard error_logger messages are described here.

The following example illustrates how an error report handler for `my_error` type of error messages can be implemented:

    -module(my_error_logger_h).
    -copyright('Copyright (c) 1991-97 Ericsson Telecom AB').
    -vsn('$Revision: /main/release/2 $').
    -behaviour(gen_event).

    -export([start/0, stop/0, init/1, handle_event/2, handle_info/2,
             handle_call/2, terminate/2, report/1]).

    start() -> error_logger:add_report_handler(my_error_logger_h).

    stop() -> error_logger:delete_report_handler(my_error_logger_h).

    report(My_error) ->
        error_logger:error_report(my_error, My_error).

    init(_) -> {ok, []}.

    handle_event({error_report, Gleader, {my_error, Pid, My_error}}, State) ->
        handle_my_error(Gleader, Pid, My_error),
        {ok, State};
    handle_event(_, State) ->  % Ignore all other error messages.
        {ok, State}.

    handle_info(_, State) ->
        {ok, State}.

    handle_call(_, State) ->
        {error, bad_query}.

    terminate(_, _) ->
        ok.

    handle_my_error(Gleader, Pid, My_error) when node(Gleader) == node() ->
        %% do handle the error
        ok;
    handle_my_error(_, _, _) -> % Ignore error if Gleader at another node.
        ok.

The purpose of the `error_logger` is to log or write errors. If some other type of event handler is needed it must be implemented as a customized process with another registered name. Refer to the section Events for further information.

Copyright © 1991-2002 Ericsson Utvecklings AB