diff --git a/docs/mkdocs.yml b/docs/mkdocs.yml index 102ec2b..6ca6216 100644 --- a/docs/mkdocs.yml +++ b/docs/mkdocs.yml @@ -141,10 +141,10 @@ markdown_extensions: nav: - Welcome: index.md - Getting started: - - getting-started/index.md - - Installation: getting-started/installation.md + - Introduction: getting-started/introduction.md + - Install: getting-started/install.md - Basic usages: getting-started/basic-usages.md - - Creating your logger: getting-started/creating-your-logger.md + - Creating your logger: getting-started/creating-custom-logger.md - Under the hood: - under-the-hood/index.md - Log severity levels: under-the-hood/log-severity-levels.md diff --git a/docs/overrides/welcome.html b/docs/overrides/welcome.html index 934983f..726a437 100644 --- a/docs/overrides/welcome.html +++ b/docs/overrides/welcome.html @@ -79,7 +79,7 @@ } .custom-hero { - margin-top:10%; + margin-top:3%; margin-left:6%; margin-right:6%; } @@ -116,7 +116,7 @@

Log smarter, debug faster in VBA

{{ config.site_description }} Set up in two minutes.

- + Get started diff --git a/docs/src/getting-started/VBAMonologger-multiples-handlers.png b/docs/src/getting-started/VBAMonologger-multiples-handlers.png new file mode 100644 index 0000000..8e18a91 Binary files /dev/null and b/docs/src/getting-started/VBAMonologger-multiples-handlers.png differ diff --git a/docs/src/getting-started/basic-usages.md b/docs/src/getting-started/basic-usages.md index c9755b6..d5a7613 100644 --- a/docs/src/getting-started/basic-usages.md +++ b/docs/src/getting-started/basic-usages.md @@ -1,44 +1,11 @@ -## Severity levels -The severity levels indicate the severity of each event, from the most trivial to the most catastrophic, and allow administrators or developers to filter messages based on their importance. -**VBA Monologger** manages 8 standard severity levels to classify the importance of log messages, following the [PSR-3](https://www.php-fig.org/psr/psr-3/) standard, which is itself based on RFC 5424, the standard defined by the IETF (*Internet Engineering Task Force*) to specify the format of messages for the Syslog protocol, which is used for transmitting logs over IP networks. - -| Log level | Description | -|-------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| `EMERGENCY` | Indicates a very critical situation that requires immediate attention. (System crash, data corruption) | -| `ALERT` | Signals an alert condition. (Critical disk space running out) | -| `CRITICAL` | Indicates a serious error. (Database connection failure, server downtime) | -| `ERROR` | Represents an error in the system. (Failed to save user data, unexpected exception) | -| `WARNING` | A warning about a potential problem. (Use a deprecated function used, low memory warning) | -| `NOTICE` | Important notifications that are not urgent. (User login successful, configuration change detected) | -| `INFO` | General information about the normal operation. (System startup, data processed successfully) | -| `DEBUG` | Detailed information for debugging. (Variable values during loop iteration, query execution details). Notes, that the '**debug**' method exposes presents in PSR-3 is rename into '**trace**' in order to be compatible in VBA ecosystem. | - -Each logger must implement hte interface `LoggerInterface`. ' This interface is (*supposed to be*) designed according to the PSR-3 standard (see: https://www.php-fig.org/psr/psr-3/), and exposed this methods: - -```vbscript -' Logs message for each severity levels -Logger.trace "Authentication function call for user 'Bob Morane'." -Logger.info "User 'UltraVomit' has logged in successfully." -Logger.notice "Process completed successfully with minor issues." -Logger.warning "'Beetlejuice' should not be called more than 3 times." -Logger.error "An error occurred with the user 'DRZCFOS2'." -Logger.critical "System is in an unstable state." -Logger.alert "Action required: unable to generate the dashboard." -Logger.emergency "A critical failure occurred in the application." -``` - - - -## Create default logger with factory +## Create default loggers with factory ### Log output to VBA Console To create a logger that output logs into the VBA console, we use the factory `VBAMonologger.Factory`, as shown below. -This logger is configured by default with the handler `VBAMonologger.Handler.HandlerConsoleVBA`, which uses the default line formatter: `VBAMonologger.Formatter.FormatterLine`. By default, this logger also loads the pre-processors placeholders: `VBAMonologger.Processor.ProcessorPlaceholders`, allowing the use of placeholders in log messages that will be replaced with values provided in the log record context. - ```vbscript Public Sub howto_use_loggerConsoleVBA() ' Create a logger instance for output log into VBA console @@ -61,14 +28,14 @@ You can see result in the **VBA console** (a.k.a. **Excel's Immediate Windows**) ![VBAMonologger-output-VBAConsole.png](VBAMonologger-output-VBAConsole.png) -> Note: If the console is not visible in Excel Visual basidc IDE, go to the menu and select *View > Immediate Window*. Alternatively, you can press Ctrl + G to quickly open it. +> Note: If the console is not visible in Excel Visual basic IDE, go to the menu and select *View > Immediate Window*. Alternatively, you can press Ctrl + G to quickly open it. +This logger is configured by default with the handler `VBAMonologger.Handler.HandlerConsoleVBA`, which uses the default line formatter: `VBAMonologger.Formatter.FormatterLine`. This logger also loads the pre-processors placeholders: `VBAMonologger.Processor.ProcessorPlaceholders`, allowing the use of placeholders in log messages that will be replaced with values provided in the log record context. -### Log output to Windows Console -The factory also provides a logger for Windows console (*cmd.exe*). +### Log output to Windows Console -This logger handles log messages by streaming them to the Windows console using an HTTP-based client/server architecture. The client sends log entries as HTTP requests to the server, and the server processes these requests, displaying the log messages directly in the console output. By default, this logger features a formatter that supports ANSI colors (`VBAMonologger.Formatter.FormatterANSIcoloredLine`). It also includes the *placeholders* pre-processors. +The factory also provides a logger for Windows console (*cmd.exe*). It handles log messages by streaming them to the Windows console using an HTTP-based client/server architecture. The client sends log records as HTTP requests to the server, and the server processes these requests, displaying the log messages directly in the console output. This logger features a formatter that supports ANSI colors (`VBAMonologger.Formatter.FormatterANSIcoloredLine`), and like the VBA console logger, it also includes the *placeholders* pre-processors. ```vbscript Public Sub howto_use_loggerConsole() @@ -80,7 +47,7 @@ Public Sub howto_use_loggerConsole() End Sub ``` -When you execute this code, it launches a `cmd.exe`, and you can view the results in it. +When you execute this code, it launches a `cmd.exe`, and you can view the results in it. The formatter's configuration allows you to customize the color scheme. ![VBAMonologger-output-WindowsConsole.png](VBAMonologger-output-WindowsConsole.png) diff --git a/docs/src/getting-started/creating-custom-logger.md b/docs/src/getting-started/creating-custom-logger.md index e69de29..0974ea2 100644 --- a/docs/src/getting-started/creating-custom-logger.md +++ b/docs/src/getting-started/creating-custom-logger.md @@ -0,0 +1,82 @@ + + +### Create a custom logger from scratch + +In this example, we create an empty logger, and we push into multiples handlers with differnts formatters. + - a handler for ouptut log into console VBA + - a handler for ouptut log into console + - a handler for ouptut log into file only for error log records (level >= error) + +```vbscript +Public Sub howto_create_a_custom_Logger_from_scratch() + Dim customLogger As VBAMonologger.Logger + Set customLogger = VBAMonologger.Factory.createLogger + + ' Create a custom line formatter + Dim customFormatterLine As VBAMonologger.FormatterLine + Set customFormatterLine = VBAMonologger.Factory.createFormatterLine + customFormatterLine.showContext = True + customFormatterLine.showExtra = True + customFormatterLine.withAllowingInlineLineBreaks = False + customFormatterLine.templateLine = ":: {{ channel }}{{ level_name }} - {{ message }}" + + ' Add a custom console VBA handler (use custom formatter) + Dim customHandlerConsoleVBA As VBAMonologger.HandlerConsoleVBA + Set customHandlerConsoleVBA = VBAMonologger.Factory.createHandlerConsoleVBA + Set customHandlerConsoleVBA.formatter = customFormatterLine + customLogger.pushHandler customHandlerConsoleVBA + + ' Add a custom console handler (use default formatter with ANSI support) + Dim customHandlerConsole As VBAMonologger.HandlerConsole + Set customHandlerConsole = VBAMonologger.Factory.createHandlerConsole + customHandlerConsole.portServer = 20101 + customHandlerConsole.hostnameServer = "127.0.0.1" + customHandlerConsole.withANSIColorSupport = True + customHandlerConsole.withDebug = False + customHandlerConsole.withNewlineForContextAndExtra = True + customHandlerConsole.startServerLogsViewer + customLogger.pushHandler customHandlerConsole + + ' Add a custom file handler (use a custom formatter and capture only error log records, i.e. with level >= LEVEL_ERROR) + Dim customHandlerFile As VBAMonologger.handlerFile + Set customHandlerFile = VBAMonologger.Factory.createHandlerFile + customHandlerFile.logFileName = "error_" & Format(Now, "yyyy-mm-dd") & ".log" + customHandlerFile.logFileFolder = ThisWorkbook.Path & "\logs" + customHandlerFile.Level = LEVEL_ERROR + Dim formatter As VBAMonologger.FormatterLine + Set formatter = customHandlerFile.formatter + formatter.setTemplateLineWithNewlineForContextAndExtra + formatter.withWhitespace = True + formatter.withAllowingInlineLineBreaks = True + customLogger.pushHandler customHandlerFile + + ' Add pre-processors + VBAMonologger.Factory.pushProcessorPlaceholders customLogger + VBAMonologger.Factory.pushProcessorUID customLogger, 8 + VBAMonologger.Factory.pushProcessorUsageCPU customLogger + VBAMonologger.Factory.pushProcessorUsageMemory customLogger + Dim tags As Object + Set tags = CreateObject("Scripting.Dictionary") + tags.Add "environment", "production" + VBAMonologger.Factory.pushProcessorTags customLogger, tags, TAGS_DESTINATION.LOG_EXTRA + + ' Use the custom logger + customLogger.trace "Authentication function call for user 'Bob Morane'." ' The 'debug' method exposes presents in PSR-3 is rename into 'trace' in order to be compatible in VBA ecosystem + customLogger.info "User 'Ultra Vomit' has logged in successfully." + customLogger.notice "Process completed successfully with minor issues." + customLogger.warning "The user 'Beetlejuice' should not be called more than 3 times." + customLogger.Error "An error occurred when the user 'DeadRobotZombieCopFromOuterspace' tried to read the dashboard file." + customLogger.critical "System is in an unstable state. Unable to authenticate the user 'Skjalg Skagen'." + customLogger.alert "Action required: unable to generate the dashboard." + customLogger.emergency "A critical failure occurred in the application for moving files." + + Dim context As Object: Set context = CreateObject("Scripting.Dictionary") + context.Add "UserName", "Bob Morane" + context.Add "UserID", 342527 + customLogger.trace "Authentication function call for user '{UserName}' with id '{UserID}'.", context + customLogger.Error "User id '{UserID}' does not exist. Unable to create dashboard file.", context +End Sub +``` + +![VBAMonologger-multiples-handlers.png](VBAMonologger-multiples-handlers.png) + diff --git a/docs/src/getting-started/index.md b/docs/src/getting-started/index.md index 33e7770..f225dd1 100644 --- a/docs/src/getting-started/index.md +++ b/docs/src/getting-started/index.md @@ -4,11 +4,3 @@ hide: --- # Getting started - -## Preamble - -VBA provides developers with the ability to automate tasks, interact with the features of -Microsoft Office applications, and even create applications with a graphical user interface (`Userform`). However, compared to other development ecosystems, VBA only offers a rudimentary logging solution, limited to the `Debug.Print` function, which writes to the Excel console (a.k.a. the Excel immediate window). - -The *VBA Monologger* library project was born out of the need for a more advanced and flexible logging solution in the VBA ecosystem. It is (heavily) inspired by the PSR-3 standard in the PHP ecosystem and its most recognized implementation, the Monolog library. The goal of this library is to provide similar features and capabilities, particularly by offering a modular architecture that can easily adapt to different use cases. The main idea is for each developer to easily configure and customize their own logging system according to their needs. - diff --git a/docs/src/getting-started/installation.md b/docs/src/getting-started/install.md similarity index 65% rename from docs/src/getting-started/installation.md rename to docs/src/getting-started/install.md index 80918a3..6e995da 100644 --- a/docs/src/getting-started/installation.md +++ b/docs/src/getting-started/install.md @@ -1,4 +1,4 @@ -## Installation +## Manual installation 1. Download the VBA Monologger Excel Add-in (.xlam file) to your computer. @@ -18,4 +18,15 @@
![excel_reference_vbamonologger.png](excel_reference_vbamonologger.png) -That's it. Time to code with it! +That's it. + + + +## Setup wizard installation (*as soon as possible*) + +In the future, we plan to introduce a setup wizard to simplify the deployment of VBA add-ins using [InnoSetup](https://jrsoftware.org/isinfo.php). + +This setup will place the VBA Monologger `.xlam` file into the standard folder for Excel add-ins: `C:\Users\[name]\AppData\Roaming\Microsoft\AddIns\`. And after, it will automatically activate in Excel by updating the Windows Registry. + +> See : https://github.com/6i-software/deploy-microsoft-office-extensions + diff --git a/docs/src/getting-started/introduction.md b/docs/src/getting-started/introduction.md new file mode 100644 index 0000000..1dbe22f --- /dev/null +++ b/docs/src/getting-started/introduction.md @@ -0,0 +1,271 @@ +## Preamble + +### Logging system? + +Logging is a process that involves recording and storing traces of events, activities, or errors that occur during the use of an application. Useful for both developers for debugging and administrators for diagnosing and resolving incidents, logs provide traceability and visibility into the behavior of an application throughout its operation. + +In its simplest form, log entries are recorded in text format, with each line representing an event that occurred during the application's lifecycle. + +```bash +[2024-11-05 09:15:34] app.INFO: Application started + | ctx: {"version": "2.3.1", "user_id": 101} +[2024-11-05 09:16:01] app.INFO: Workbook loaded successfully + | ctx: {"workbook_id": 789, "workbook_name": "Q4 Marketing"} +[2024-11-05 09:17:15] app.DEBUG: Task modified + | ctx: {"task_id": 456, "task_name": "Strategy Review", "user_id": 101} +[2024-11-05 09:18:45] app.WARNING: Low disk space - risky save + | ctx: {"available": "100 MB", "required": "200 MB"} +[2024-11-05 09:19:03] app.ERROR: Project save failed + | ctx: {"project_id": 789, "error": "Insufficient disk space", "user_id": 101} +[2024-11-05 09:20:00] app.INFO: Application closed + | ctx: {"user_id": 101} +``` + +According to the *twelve-factor app* manifest, you should "*[treat logs as event streams](https://12factor.net/logs)*". Logs are not just recorded in a file for later consultation. They can also be monitored in real-time in a terminal, sent to a database, or redirected to external log aggregation and analysis tools (such as the ELK stack, Graylog, BetterStack, Splunk...). + +A logging system should offer flexible management, allowing different severity levels of events to be distinguished, so messages can be filtered according to their importance, from simple information to critical errors. It should also be capable of sending logs to multiple destinations simultaneously, such as a terminal, file, database, or monitoring service. Additionally, the log format must be customizable to meet the specific needs of the application and the tools used for analysis, making it easier to manage and interpret the collected data. + + +### Motivations of VBA Monologger + +VBA provides developers with the ability to automate tasks, interact with the features of +Microsoft Office applications, and even create applications with a graphical user interface (`Userform`). However, compared to other development ecosystems, VBA only offers a rudimentary logging solution, limited to the `Debug.Print` function, which writes to the Excel console (a.k.a. the Excel immediate window). + +The *VBA Monologger* library project was born out of the need for a more advanced and flexible logging solution in the VBA ecosystem. It is (heavily) inspired by the PSR-3 standard in the PHP ecosystem and its most recognized implementation, the Monolog library. The goal of this library is to provide similar features and capabilities, particularly by offering a modular architecture that can easily adapt to different use cases. + +The main idea is for each developer to easily configure and customize their own logging system according to their needs. + + +## Concepts + +### Severity levels + +The severity levels indicate the severity of each event, from the most trivial to the most catastrophic, and allow administrators or developers to filter messages based on their importance. + +**VBA Monologger** manages 8 standard severity levels to classify the importance of log messages, following the [PSR-3](https://www.php-fig.org/psr/psr-3/) standard, which is itself based on RFC 5424, the standard defined by the IETF (*Internet Engineering Task Force*) to specify the format of messages for the Syslog protocol, which is used for transmitting logs over IP networks. + +| Log level | Description | +|-------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `EMERGENCY` | Indicates a very critical situation that requires immediate attention. (System crash, data corruption) | +| `ALERT` | Signals an alert condition. (Critical disk space running out) | +| `CRITICAL` | Indicates a serious error. (Database connection failure, server downtime) | +| `ERROR` | Represents an error in the system. (Failed to save user data, unexpected exception) | +| `WARNING` | A warning about a potential problem. (Use a deprecated function used, low memory warning) | +| `NOTICE` | Important notifications that are not urgent. (User login successful, configuration change detected) | +| `INFO` | General information about the normal operation. (System startup, data processed successfully) | +| `DEBUG` | Detailed information for debugging. (Variable values during loop iteration, query execution details). Notes, that the '**debug**' method exposes presents in PSR-3 is rename into '**trace**' in order to be compatible in VBA ecosystem. | + + + +### Logger + +The `Logger` is the central component of this library, acting as the primary interface for recording, categorizing, and managing log messages throughout an application. It implements the `LoggerInterface`, also describes in the PSR-3. It provides developers with a highly configurable and flexible tool for implementing custom logging logic tailored to their specific needs. By using a logger, applications can systematically capture events and system states, facilitating both real-time monitoring and historical analysis of system behavior. + +The Logger is designed to handle multiple logging levels, directing each log entry to the appropriate handlers (i.e. appropriate destinations) and applying the correct formatting to messages. It also supports the use of various pre-processors, which can enrich log messages with extra contextual information, allowing for complex logging logic while keeping code readable and straightforward. + +```mermaid +mindmap + root((Logger)) + Handlers + HandlerConsoleVBA
*for all levels* + FormatterLine + HandlerConsole
*for all levels* + FormatterANSIColoredLine + HandlerFile
*exclude debug level* + FormatterJSON + HandlerEmail
*for level >= error* + FormatterHTML + Processors + ProcessorPlaceholders + ProcessorUID + Name of loger, a.k.a. log channel +``` + +Additionally, the Logger standardizes and simplifies the use of logging methods (such as mehtods : `logger.info`, `logger.debug` ...). It offers a consistent and intuitive approach to logging at different levels of severity, letting developers effortlessly call the appropriate logging level without dealing with the underlying technical details. Each log level can be invoked through a simple, clear method, making logging an integral yet unobtrusive part of the development process. + +Every logger must implement the `LoggerInterface`, which provides the following methods: + +```vbscript +Logger.trace "Authentication function call for user 'Bob Morane'." +Logger.info "User 'UltraVomit' has logged in successfully." +Logger.notice "Process completed successfully with minor issues." +Logger.warning "'Beetlejuice' should not be called more than 3 times." +Logger.error "An error occurred with the user 'DRZCFOS2'." +Logger.critical "System is in an unstable state." +Logger.alert "Action required: unable to generate the dashboard." +Logger.emergency "A critical failure occurred in the application." +``` + + +### Identifying a logger with a channel name + +**Log channels** are a powerful way to identify which part of an application a log entry is associated with. This is especially useful in large applications with multiple components and multiple loggers. The idea is to have several logging systems sharing the same handler, all writing into a single log file. Channels help identify the source of the log, making filtering and searching more manageable. + +Here’s an example with three distinct logging channels to demonstrate how they help differentiate logs by application component: one channel for the main application (`app`), another for authentication (`auth`), and a third for data processing (`data`). + +``` +[2024-11-05 09:15:34] auth.INFO: User login successful +[2024-11-05 09:16:01] app.INFO: Dashboard loaded successfully +[2024-11-05 09:16:20] data.DEBUG: Data import started +[2024-11-05 09:17:30] auth.WARNING: Suspicious login attempt detected +[2024-11-05 09:18:45] data.ERROR: Data import failed +[2024-11-05 09:19:03] app.INFO: User preferences saved +[2024-11-05 09:20:00] app.INFO: Application shutdown initiated +``` + + +### Processing log records with a handler + +A **log handler** is a key component responsible for processing each log entry. When a log message is generated, it is not simply recorded; it must be directed to a location where it can be viewed and used. This is where the handler comes in, determining where and how each log entry will be sent or saved. Here are some examples of *built-in* log handlers provided in VBAMonologger: + +| Handler | Description | +|------------------|--------------------------------------------------------------------------------------------------------| +| `HandlerConsoleVBA` | Sends log messages to the console of VBA Project IDE (*Excel's Immediate Window*). | +| `HandlerConsole` | Sends log messages to the Windows console (*cmd.exe*). | +| `HandlerFile` | Write log messages into a text file. | +| `HandlerEmail` | Sends messages by email, typically used to alert an administrator in case of critical errors. (*asap*) | + +The benefit of using different handlers lies not only in applying specific treatments to logs but also in filtering messages based on their severity level. A handler can be configured to handle only certain severity levels. For example, one handler could be set to log only critical errors to a dedicated file, while another handler records all events in a general log file. + + +### Formatting log records, the serialization of logs record + +Each *handler* is associated with a unique *formatter*. This is a specific component whose role is to define the format of log message. It transforms and structures each log entry, changing it from its raw form to a readable format tailored to a specific type (text, HTML, JSON, etc.). + +VBAMonologger provides the following formatters: + +| Log Formatter | Description | +|----------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `FormatterLine` | The default formatter that represents each log entry on a single line of text. | +| `FormatterANSIColoredLine` | A version derived from *FormatterLine* that supports color coding each log entry line using ANSI escape sequences. | +| `FormatterJSON` | Formats the logs in JSON. This is the most interoperable format, facilitating integration with external log aggregation and analysis tools (e.g., *ELK stack*). | +| `FormatterHTML` | Produces messages in HTML format, typically used when sending logs via email. (*asap*) | + +### Redirection and chaining handlers (*stack handlers*) + +In the log processing, there's no limitation to having multiple *handlers* into logger, so that the same log entry can be sent to multiple destinations in the same time with different formatter: console, writing to a file, or sending via email. Each *handler* acts sequentially, one after the other, in the order they were added to the *logger*'s stack. When a log event occurs, it passes through all handlers, each performing its own processing. + +This mechanism provides great flexibility in log processing because each handler can be independently configured to perform specific actions without interfering with the others. + + +### Propagation control of logs (*bubbling*) + +In case of multiples handlers references in logger, each *handler* can decide to block the **propagation** of a log message (*a.k.a.* bubbling) in the processing chain, or allow it to continue to other *handlers* referenced in the stack. The control of this propagation is managed by setting the `bubble` boolean property attached to each *handler*. When a *handler* blocks propagation (`bubble = false`), it means the log message will not be passed to the *handlers* below it in the stack. Otherwise, the message will continue to propagate until every *handler* in the stack has had a chance to process it. + +Let's imagine a logging system with three *handlers*: + +- First, a `HandlerEmail` to send error-level logs (`level >= ERROR`) via email, without propagation (`bubble = false`). +- Next, a `HandlerFile` to log other messages in a file, excluding the debug level (`DEBUG < level < ERROR`). +- Finally, a `HandlerConsole` to display the remaining logs in the console (`level < ERROR`). + +When an error-level log is captured by `HandlerEmail`, the first handler in the stack, it will not propagate to the other *handlers*. An `ERROR` level log will only be sent via email. It will not be recorded in the log file (`HandlerFile`), nor displayed in the console (`HandlerConsole`). + +```mermaid +sequenceDiagram + participant Logger as Logger + participant HandlerEmail as HandlerEmail
($bubble = false, level = ERROR) + participant HandlerFile as HandlerFile
(level = NOTICE) + participant HandlerConsole as HandlerConsole
(level = DEBUG) + + %% ERROR level log + Logger->>HandlerEmail: ERROR level log + HandlerEmail-->>HandlerEmail: Send log via email + HandlerEmail--xHandlerFile: Propagation blocked
($bubble = false) + Note right of HandlerEmail: The error message is handled
only by HandlerEmail
and is not processed elsewhere. +``` + +When a log of level `INFO` is recorded, it is not captured by the first `HandlerEmail`. Its processing starts with the `HandlerFile`, which allows the propagation of the messages. The log is then sent to the `HandlerConsole` for processing. Therefore, this log will be recorded in a log file and displayed in the console. + +```mermaid +sequenceDiagram + participant Logger as Logger + participant HandlerEmail as HandlerEmail
($bubble = false, level = ERROR) + participant HandlerFile as HandlerFile
(level = NOTICE) + participant HandlerConsole as HandlerConsole
(level = DEBUG) + + %% INFO level log + Logger->>HandlerEmail: INFO level log + HandlerEmail--xHandlerEmail: Ignored (insufficient level) + HandlerEmail->>HandlerFile: INFO level log + HandlerFile-->>HandlerFile: Log saved to file + HandlerFile-->>HandlerConsole: Propagation (bubble = true) + HandlerConsole-->>HandlerConsole: Displayed in console + Note right of HandlerFile: INFO level log is processed
by HandlerFile and HandlerConsole. +``` + + +### Adding metadatas in log records + +In addition to the basic log message, you may sometimes want to include extra information that helps to provide more context for the event being logged. This could include things like the username of the person triggering the event, a session ID, or any other piece of data that can assist in understanding the log entry better. This can be easily done by adding a *`context`* or `extra` to your log messages. + + - The `context` is used to add information directly related to the logged event, such as details about an error or an ongoing operation. + - On the other hand, `extra` is reserved for additional metadata, often generated automatically or added by pre-processors, providing global context and supplementary technical details. + +The `context` (or `extra`) is essentially a VBA dictionary where you can store key-value pairs that hold relevant information. When you create a log entry, this context can be attached and will be incorporated into the log output, providing deeper insights into the logged event. + +Regardless of which log handler is used and which formatter is applied, the fields within the context can be accessed as template variables within the log message. These template variables are enclosed in `{}` brackets. If a particular key doesn’t exist in the context, it will be replaced by an empty string. + +```vbscript +' Set context +Dim context As Object: Set context = CreateObject("Scripting.Dictionary") +context.Add "Username", "v20100v" + +' Set extra +Dim extra As Object: Set extra = CreateObject("Scripting.Dictionary") +extra.Add "CPU-Usage", "51%" + +Logger.info "Adding a new user", context +Logger.info "Adding the new user: '{username}'", context +Logger.info "Adding the new user: '{username}'", context, extra +``` + +Result: + +``` +[2024-11-05 09:15:34] app.INFO: Adding a new user | {"Username": "v20100v"} +[2024-11-05 09:15:34] app.INFO: Adding the new user: 'v20100v' | {"Username": "v20100v"} +[2024-11-05 09:15:34] app.INFO: Adding the new user: 'v20100v' | {"Username": "v20100v"} | extra: {"CPU-Usage":"51%"} +``` + +This feature is a great way to enrich your log entries with important details and provide better traceability and understanding of your application's behavior. + +In this example, the templating engine with placeholders is provided by the `ProcessorPlaceholders` pre-processor, which uses context data to replace variables in log messages. It allows to embed context values directly into log message text with placeholders. The engine automatically replaces the placeholder `{username}` with its corresponding value from the context dictionary, in this case, `v20100v`. + + +### Pre-processor of log records + +Pre-processors are a powerful feature, allowing for additional metadatas to be added to log messages before they are recorded. These functions can be used to enrich log messages with extra information that might not be directly part of the log entry itself, but is still relevant for better understanding and tracking. Pre-processors can modify, format, or even generate additional metadata that can be attached to each log message into the `extra` property. A logger can reference one or more pre-processors. + +In VBA Monologger, several built-in processors offer specific functionalities to enhance the log entry by adding additional context or modifying it in various ways before it is passed to the handlers. Here are some examples of the available pre-processors: + +| Log processor | Description | +|-------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `ProcessorPlaceholders` | Allows to replace specific variables or placeholders in log messages with their corresponding values, adding dynamic context to the logs. The `context` variable must be a VBA `Scripting.Dictionary`. (*e.g.* `logger.info("Authentication failed for user '{UserName}' with id '{UserID}'.", context)`. | +| `ProcessorTags` | Adds one or more tags to a log entry. | +| `ProcessorUID` | Adds a unique identifier (UID) to each session . The generated UID consists of hexadecimal characters, and its size can be configured. | +| `ProcessorUsageUsage` | Adds the computer's memory usage to each log entry. The system's current memory status is retrieved using the `GlobalMemoryStatusEx` API in Windows. | +| `ProcessorUsageCPU` | Adds the computer's cpu usage to each log entry. | + +Result of a logger with pre-processors : placeholders, tags (`environment, user_role`), UID, usage memory and usage CPU. + +``` +[2024/12/13 18:59:30] App.INFO: User '35353' has logged in successfully. + | context: + | { + | "UserName": "Bob", + | "UserID": 35353, + | "Operation": "create", + | "environment": "production", + | "user_role": "admin" + | } + | extra: + | { + | "session-UID": "A09A248CF0", + | "memory": { + | "memory-used": "65%", + | "memory-total": "15,23", + | "memory-available": "5,30" + | }, + | "CPU-used": "21,4%" + | } +``` \ No newline at end of file diff --git a/examples/example.xlsm b/examples/example.xlsm index ba7557c..70e14b7 100644 Binary files a/examples/example.xlsm and b/examples/example.xlsm differ