# Log API

## Introduction

The logging API is one of the most important of the entire kernel: it allow it to output informations with various level of importance and various sources.

## Output methods

The logging API can log informations with two differents methods:
- serial output: use the serial API to output in real time all the provided informations. Can be disabled by setting it to true using the `sh_log_load_serial_setting(sh_bool is_disabled)` function. The serial API being disabled, this method can also be disabled by that.
- ring buffer output: use the ring buffer API to store all the provided informations into a ring buffer, mapped by the bootloader. Can be disabled by setting the `logging_ring_size` boot configuration key to 0

The following functions provide way to set and get those settings:
- `void sh_log_load_serial_setting(sh_bool is_disabled)`: specify if serial log outputting should be disabled
- `sh_bool sh_log_get_serial_setting()` return the activation status of serial log outputting (`SH_TRUE` mean disabled)
- `void sh_log_load_logging_ring_size(sh_uint16 pages_count)`: set logging ring size
- `sh_uint32 sh_log_get_logging_ring_size()`: return logging ring size
- `sh_uint64 sh_log_get_total_bytes_written()`: return total amount of bytes written inside logging ring

## Output primitives

The following functions doesn't care about log level or log source and are specialized into specific data type:
- `void sh_log_byte(sh_uint8 byte)`: log a byte, basic entry point of the entire logging system
- `SH_STATUS sh_log_string(const char* str)`: log a table of characters
Here are the numbers logging functions under their naming scheme:
```
sh_log_(u)int[8/16/32/64](_hex)
```

Basically, there is 12 functions that can output numbers, in various sizes (8 to 64 bits), signed or unsigned, in decimal or hexadecimal. The hexadecimal variant doesn't exist for signed integers. Examples: `sh_log_uint8`, `sh_log_int16`, `sh_log_uint64_hex`...

There are two mores functions:
- `SH_STATUS sh_log_uint64_hex_fixed(sh_uint64 n)`: log a `sh_uint64` in hexadecimal without removing useless zeros, useful for logging pointers and address
- `SH_STATUS sh_log_double(double value)`: log a double encoded in decimal

## Output channels and log level

The Shelter logging API provide higher level functions to output on specific log channels. Here are all the log channels:
- `SH_LOG_DEBUG`: log level 0
- `SH_LOG_LOG`: log level 1
- `SH_LOG_WARNING`: log level 2
- `SH_LOG_ERROR`: log level 3
- `SH_LOG_CRITICAL`: log level 4
- `SH_LOG_FATAL`: log level 5
- `SH_LOG_TEST`: log level 6

Each log channel has a log level. The log level is set by the `log_level` boot configuration key. The log API will only output log messages with log level equal or higher to current log level. This restriction doesn't apply to log channel `SH_LOG_TEST`.

The `sh_log_OUTPUT_TYPE` type is used to store output type by log level. It's a wrapper of `sh_uint8`. The `sh_log_output_type_valid(sh_log_OUTPUT_TYPE t)` can be used to check if a log level is valid.

Two functions allow to set and get the current log level:
- `SH_STATUS sh_log_load_log_level(sh_uint8 log_level)`
- `sh_uint8 sh_log_get_log_level()`

## Output sources

The Shelter logging API also require a source in order to log informations. Here are all the possible sources:
- `SH_LOG_SOURCE_MAIN`
- `SH_LOG_SOURCE_CONF`
- `SH_LOG_SOURCE_PAGE`
- `SH_LOG_SOURCE_SLAB`
- `SH_LOG_SOURCE_TEST`
- `SH_LOG_SOURCE_PEZ`
- `SH_LOG_SOURCE_PBA`
- `SH_LOG_SOURCE_HEAP`
- `SH_LOG_SOURCE_STD`

The `sh_log_OUTPUT_SOURCE` type is used to store log source. It's a wrapper of `sh_uint16`. The `sh_log_output_source_valid(sh_log_OUTPUT_SOURCE s)` can be used to check if a log level is valid.

## Output payloads

In order to compile all of those informations into one payload, the logging API provide this structure :
``` C
typedef struct {
  sh_log_OUTPUT_TYPE output_type;
  sh_log_OUTPUT_SOURCE output_source;
  sh_tsc_TSC_VALUE tsc_value;
  const char* message_pointer;
} sh_log_OUTPUT_PAYLOAD;
```

This allow to contain the message content, the output channel, the output source and the TSC value of any log message.

There is two functions that can manipulate output payloads:
- `SH_STATUS sh_log_payload(sh_log_OUTPUT_PAYLOAD *payload)`: output a payload
- `SH_STATUS sh_log_payload_format(sh_log_OUTPUT_PAYLOAD *payload,va_list args)`: format then output a payload, not directly callable, see below for more informations

## Higher levels logging functions

The following functions will automatically create the payload depending on the parameters they receive.

### Logging with automatic line break

These functions are named like this:
```
sh_log_[test/debug/log/warning/error/critical/fatal]
```

They all need two arguments in the following order (except `sh_log_test` which only need the first one):
- `const char* str`: the text to log
- `sh_log_OUTPUT_SOURCE source`: the source of the log message

These functions will automatically add the `\n` characters at the end of each log message.

### Logging without automatic line break

These functions are named like this:
```
sh_log_l[test/debug/log/warning/error/critical/fatal]
```

They all need two arguments in the following order (except `sh_log_ltest` which only need the first one):
- `const char* str`: the text to log
- `sh_log_OUTPUT_SOURCE source`: the source of the log message

### Logging with formating

In order to allow for formatting log messages, the log API provide functions named like this:
```
sh_log_f[test/debug/log/warning/error/critical/fatal]
```

They all need at least two arguments in the following order (except `sh_log_ltest` which only need the second one):
- `sh_log_OUTPUT_SOURCE source`: the source of the log message
- `const char* format`: the format text
- all the others argument after that are used as content for formatting the log message

All of these functions use `sh_log_payload_format()` under the hood which itself use `SH_STATUS sh_log_format(const char* format,va_list args)` to format log messages.

The format syntax is as follow:
- `%s`: insert a string made of `char`, passed as `char*`
- `%d`: insert a double
- `%x`: insert a integer that need to be provided as a `sh_uint64`, format it as hexadecimal without removing useless zeros. Used to log addresses
- `%c`: insert a `char`
- `%%`: insert a `%`

There is also a specific syntax for formatting integers. It's start with the `%` symbol, then need a amount of bytes (can be 1, 2, 4 or 8) and a output format: `u` for unsigned decimal, `s` for signed decimal, `U` for unsigned decimal. Example: `%1s` output a `sh_int8` in decimal, `%2u` output a `sh_uint16` in decimal, `%4U` output a unsigned `sh_uint32` in hexadecimal.
