


## Table of Contents
* [TL;DR](#tldr)
* [Installation](#installation)
* [Log Format](#log-format)
* [The Logger](#the-logger)
* [Controlling Terminal Output](#the-logger_controlling-terminal-output)
* [Custom Log Buffer](#the-logger_custom-log-buffer)
* [Log Filtering](#log-filtering)
* [File Logging](#file-logging)
* [Automatic Log File Flushing](#file-logging_automatic-log-buffer-flushing)
* [Locking the Log File](#file-logging_locking-the-log-file)
* [Logger Templates](#logger-templates)
<a name="tldr"></a>
## TL;DR
**Installing the library**:
```bash
cargo add libprettylogger
```
**Using the library in your project**:
```rust
// Include stuff from the library:
use prettylogger::Logger;
use prettylogger::config::Verbosity;
// A `Logger` struct with default configuration
let mut logger = Logger::default();
// Configure `Logger` to your liking
logger.set_verbosity(Verbosity::All); // Don't suppress any log messages
// Print logs:
logger.debug("A debug message!");
logger.info("Info message!");
logger.warning("A warning!");
logger.error("An error!");
logger.fatal("A fatal error!");
```
<a name="installation"></a>
## Installation
To install the library with `cargo`, run:
```bash
cargo add libprettylogger
```
Or add this to your `Cargo.toml`:
```toml
[dependencies]
libprettylogger = "2.0.0"
```
<a name="the-logger"></a>
## The Logger
The `Logger` struct is the **core** of the entire project.
This is what you are going to use when you want to print a log, set filtering
rules or modify log formatting. All of it's fields are private, only allowing for
modification via setters.
Creating a `Logger` struct with default configuration:
```rust
# use prettylogger::Logger;
let mut logger = Logger::default();
```
<a name="the-logger_controlling-terminal-output"></a>
### Controlling Terminal Output
By default, `Logger` streams all logs to `stdout` and `stderr`. If you only want
to write logs to a file or store them in a custom buffer, use:
```rust
# use prettylogger::Logger;
# let mut logger = Logger::default();
logger.toggle_console_output(false);
```
<a name="the-logger_custom-log-buffer"></a>
### Custom Log Buffer
`Logger` can store logs in a buffer instead of printing them or writing them
to a file. Later, you can reference that buffer and do whatever you want with it.
Enabling custom log buffer:
```rust
# use prettylogger::Logger;
# let mut logger = Logger::default();
logger.toggle_custom_log_buffer(true);
```
And when you need a reference to that buffer, call:
```rust
# use prettylogger::Logger;
# let mut logger = Logger::default();
let buffer = logger.log_buffer();
```
<a name="log-format"></a>
## Log Format
A basic log consists of several headers:
* **Log Type** **→** The type of the log (debug, info, warning etc.)
* **Timestamp** **→** Contains the date and time the log was created
* **Message** **→** The actual log message
Those headers can then be formatted using a log format string, similarly to how
you would format a datetime string.
Here is a log message with all it's headers marked:
```markup
[ DEBUG 21:52:37 An example debug message ]
^^^^^ ^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^
| timestamp
log type
```
This specific effect was achieved by setting the datetime format to `%H:%M:%S`,
log format to `[ %h %d %m ]` and the debug log type header to `DEBUG`.
Use this method to set the datetime format of a `Logger`:
```rust
# use prettylogger::Logger;
# let mut logger = Logger::default();
logger.set_datetime_format("%H:%M:%S");
```
You can set a custom log format like this:
```rust
# use prettylogger::Logger;
# let mut logger = Logger::default();
logger.set_log_format("[ %h %d %m ]");
```
**Note** that the `%m` (message) placeholder is mandatory and you will get an error
unless you include it in your format string.
Log type headers can be customized with their corresponding methods:
```rust
# use prettylogger::Logger;
# let mut logger = Logger::default();
logger.set_debug_header("DEBUG");
logger.set_info_header("INFO");
logger.set_warning_header("WARNING");
logger.set_error_header("ERROR");
logger.set_fatal_header("FATAL ERROR");
```
And you can also customize their colors:
```rust
# use prettylogger::{Logger, colors::Color};
# let mut logger = Logger::default();
logger.set_debug_color(Color::Blue);
logger.set_info_color(Color::Green);
logger.set_warning_color(Color::Yellow);
logger.set_error_color(Color::Red);
logger.set_fatal_color(Color::Magenta);
```
### Using the `LogStruct`
`LogStruct` is a type that represents a single log entry. You can create `LogStruct` instance using one of it's constructors:
* `debug(message: &str)`
* `info(message: &str)`
* `warning(message: &str)`
* `error(message: &str)`
* `fatal_error(message: &str)`
Using `LogStruct`'s `debug` constructor to create a debug log, and then formatting
with `logger.format_log(...)`:
```rust
# use prettylogger::{Logger, config::LogStruct};
# let mut logger = Logger::default();
let log_formatted = logger.format_log(&LogStruct::debug("A debug log!"));
```
<a name="log-filtering"></a>
## Log Filtering
Logs are filtered based on the current `LogLevel` and the `Logger`'s verbosity
setting. `config::Verbosity` enum can be used to set the verbosity of a `Logger`.
The `Verbosity` level determines which logs are filtered out:
- `All` **→** Disables log filtering, allowing all logs to pass through.
- `Standard` (default) **→** Filters out debug logs.
- `Quiet` **→** Only allows errors and warnings to be displayed.
- `ErrorsOnly` **→** Only allows errors to be shown.
To modify the verbosity of the `Logger`, use:
```rust
# use prettylogger::{Logger, config::Verbosity};
# let mut logger = Logger::default();
logger.set_verbosity(Verbosity::All);
```
To toggle log filtering, use:
```rust
# use prettylogger::{Logger, config::Verbosity};
# let mut logger = Logger::default();
logger.toggle_log_filtering(false);
```
<a name="file-logging"></a>
## File Logging
File logging is a feature that allows you to automatically save log output to a
file.
**Enabling file logging**:
```rust
# use prettylogger::Logger;
# let mut logger = Logger::default();
# let mut path = std::env::temp_dir();
# path.push("libprettylogger-tests/readme-doc1.log");
# let path = &path.to_str().unwrap().to_string();
// Set the log file path first:
logger.set_log_file_path(path);
// Then enable file logging:
logger.toggle_file_logging(true);
logger.info("Yay!"); // Yay!
logger.flush(); // Flush the log buffer to a file
```
It is **CRUCIAL** to set the log file path **FIRST**. If you try to enable file
logging before specifying a valid path, `Logger` will check the log file path, and
since the default path is an empty string, it will result in an error.
<a name="file-logging_locking-the-log-file"></a>
### Locking the Log File
The log file can be locked to prevent race conditions when there are multiple
threads accessing it at the same time. It prevents `Logger` from writing to
the log file until the lock has been released. The lock is only ignored when a
`Logger` is being dropped and the `OnDropPolicy` is set to `IgnoreLogFileLock`
(off by default).
Log file lock is not persistent (it's not saved when calling
`logger.save_template("path")`).
Toggling log file lock:
```rust
# use prettylogger::Logger;
# let mut logger = Logger::default();
logger.toggle_log_file_lock(true);
// Do some I/O operations on the log file here
logger.toggle_log_file_lock(false);
```
To set the on drop log file policy, use:
```rust
# use prettylogger::{Logger, config::OnDropPolicy};
# let mut logger = Logger::default();
logger.set_on_drop_file_policy(OnDropPolicy::IgnoreLogFileLock);
```
<a name="file-logging_automatic-log-buffer-flushing"></a>
### Automatic Log Buffer Flushing
You can either flush the log buffer automatically or set up automatic flushing
based on the log buffer size:
```rust
# use prettylogger::Logger;
# let mut logger = Logger::default();
# let mut path = std::env::temp_dir();
# path.push("libprettylogger-tests/readme-doc2.log");
# let path = &path.to_str().unwrap().to_string();
logger.set_log_file_path(path);
logger.toggle_file_logging(true);
// This will make `Logger` to flush the log buffer every 16 logs:
logger.set_max_log_buffer_size(16 as u32);
let mut i = 0;
loop {
logger.info("Yay!");
i += 1;
if i >= 16 {
break;
}
}
```
<a name="logger-templates"></a>
## Logger Templates
A **Logger template** is a JSON file that defines the configuration of a
`Logger` struct. This allows you to easily manage and store logging settings in a
file.
Here’s an example of what a `Logger` struct looks like in JSON format:
```json
{
"stdout_enabled": true,
"use_custom_log_buffer": false,
"verbosity": "Standard",
"filtering_enabled": true,
"log_header_color_enabled": true,
"debug_color": "Blue",
"info_color": "Green",
"warning_color": "Yellow",
"error_color": "Red",
"fatal_color": "Magenta",
"debug_header": "DBG",
"info_header": "INF",
"warning_header": "WAR",
"error_header": "ERR",
"fatal_header": "FATAL",
"log_format": "[%h] %m",
"datetime_format": "%Y-%m-%d %H:%M:%S",
"file_logging_enabled": false,
"log_file_path": "",
"file_log_buffer_max_size": 128,
"on_drop_policy": "DiscardLogBuffer"
}
```
Loading `Logger` from a template file:
```rust
# use prettylogger::Logger;
# let mut path = std::env::temp_dir();
# path.push("libprettylogger-tests/readme-doc3.log");
# let path = &path.to_str().unwrap().to_string();
# Logger::default().save_template(path);
let mut logger = Logger::from_template(path);
```
Saving `Logger` to a template file:
```rust
# use prettylogger::Logger;
let mut logger = Logger::default(); // Create a default `Logger`
# let mut path = std::env::temp_dir();
# path.push("libprettylogger-tests/readme-doc4.log");
# let path = &path.to_str().unwrap().to_string();
logger.save_template(path);
```