Compare commits
No commits in common. "master" and "v0.1.0" have entirely different histories.
|
|
@ -2,5 +2,3 @@
|
|||
.dub
|
||||
*.o
|
||||
lib
|
||||
bin
|
||||
test.log
|
||||
|
|
|
|||
121
CHANGELOG.md
121
CHANGELOG.md
|
|
@ -1,121 +0,0 @@
|
|||
# Changelog
|
||||
|
||||
## [1.0.1] - 2025-03-27
|
||||
### Fixed
|
||||
- Correct transfer of priority when writing to the system log.
|
||||
|
||||
## [1.0.0] - 2025-03-23
|
||||
|
||||
### Added
|
||||
- **Thread-safety**: Added a `Mutex` to ensure thread-safe logging operations across all methods (`_mutex` in `Log` class).
|
||||
- **Destructor**: Implemented `~this()` to properly close the log file when the `Log` instance is destroyed.
|
||||
- **File handle management**: Introduced `_file` (File handle) and `_fileOpen` (flag) for better file management, reducing repeated file opening/closing.
|
||||
- **Enhanced documentation**: Added detailed DDoc comments for the module, `Log` class, and all public/private methods, including examples.
|
||||
- **Immutable arrays**: Made `_sysPriority`, `_sysPriorityOS`, `_color` (Windows), `_colorCodes` (both platforms), and `_type` arrays immutable for better safety and performance.
|
||||
- **Singleton initialization**: Improved singleton pattern with double-checked locking in `@property static Log msg()` for thread-safe initialization.
|
||||
- **Fluent interface naming**: Renamed output-related enums (`SYSLOG`, `STD`, `FILE`) and methods (`std`, `syslog`, `file`) for consistency and clarity (e.g., `STDOUT` → `STD`).
|
||||
- **Error handling**: Enhanced error reporting in `writefile` by logging exception messages instead of the full exception object.
|
||||
|
||||
### Changed
|
||||
- **Output handling**:
|
||||
- Removed separate `writestdout` and `writestderr` methods; consolidated into a single `writestd` method that dynamically selects `stdout` or `stderr` based on log level (`ERROR` and above go to `stderr`, others to `stdout`).
|
||||
- Adjusted output enum values: `SYSLOG = 1`, `STD = 2`, `FILE = 8` (removed `STDERR = 4` as it's now handled by `STD`).
|
||||
- **Windows-specific**:
|
||||
- Renamed `_color` to `_colorCodes` for consistency with POSIX.
|
||||
- Updated `writesyslog` to use `toUTF16z()` for `_name` and added null checks.
|
||||
- **POSIX-specific**:
|
||||
- Renamed `_color` to `_colorCodes` and simplified console output logic in `writestd`.
|
||||
- Changed `writesyslog` to pass priority directly instead of mapping it.
|
||||
- **Log level filtering**: Moved priority check (`_priority > priority`) into `writelog` under the mutex for consistency.
|
||||
- **File logging**:
|
||||
- Simplified `writefile` by maintaining an open `File` handle (`_file`) instead of opening/closing on each write.
|
||||
- Removed redundant file existence check (`this._path.exists`) as `File` opening handles it implicitly.
|
||||
- **Configuration methods**: Made all setters (`program`, `file`, `level`, `color`, `output`) thread-safe with `synchronized (_mutex)`.
|
||||
- **Naming consistency**:
|
||||
- Renamed `Output.output()` to internal use; public access is via `Output` struct methods.
|
||||
|
||||
### Removed
|
||||
- **Deprecated method**: Removed the deprecated `Log output(int outs)` method; users must now use the fluent `Output` struct.
|
||||
- **Redundant output flags**: Removed `STDERR` from output enum as it's now handled dynamically by `STD`.
|
||||
- **Unnecessary struct fields**: Removed `_output` and `_newoutput` from `Output` struct; replaced with a single `value` field.
|
||||
- **Redundant methods**: Removed separate `writestdout` and `writestderr` in favor of `writestd`.
|
||||
|
||||
### Fixed
|
||||
- **Windows console output**: Added error checking in `colorTextOutput` and `defaultTextOutput` with `GetConsoleScreenBufferInfo`.
|
||||
- **File closing**: Ensured proper file closure in `file` method when changing the log file path.
|
||||
|
||||
### Breaking Changes
|
||||
- **Output enum changes**:
|
||||
- `STDOUT` renamed to `STD`, `STDERR` removed; code relying on `STDERR = 4` will need adjustment.
|
||||
- Users must update output configuration to use `STD` instead of separate `STDOUT`/`STDERR`.
|
||||
- **Method removal**: Code using the deprecated `Log output(int outs)` must switch to `Log.output(Output)`.
|
||||
- **Console output behavior**: Messages with priority `ERROR` and above now go to `stderr` by default when `STD` is enabled, which may change existing output redirection logic.
|
||||
|
||||
## [0.5.0] - 2023-07-21
|
||||
|
||||
### New
|
||||
|
||||
- Added the ability to output messages to the standard error stream. Now messages above the `WARNING` level will not be output to the `stdout`. To output them, need to use `stderr`
|
||||
- Write message to specific outputs via `log.now`
|
||||
- Now `log.output` allows to set the output as an argument
|
||||
- Now `log.level` allows to set the level as an argument
|
||||
|
||||
### Bug fixes
|
||||
|
||||
- Fixed streams redirection in Windows
|
||||
|
||||
## [0.4.0] - 2023-06-07
|
||||
|
||||
- Part of the code has been changed/rewritten
|
||||
|
||||
### New
|
||||
|
||||
- Color output of messages to the terminal and console
|
||||
|
||||
### Bug fixes
|
||||
|
||||
- In Windows, unicode messages are output without distortion to the system log and console (thanks [Adam D. Ruppe](https://arsdnet.net/))
|
||||
|
||||
## [0.3.2] - 2023-06-01
|
||||
|
||||
- Printing information about the type of the logged message to the standard output stream and file
|
||||
- Printing the date and time to the standard output stream
|
||||
|
||||
## [0.3.1] - 2023-05-30
|
||||
|
||||
### Bug fixes
|
||||
|
||||
- Log of debug messages
|
||||
|
||||
## [0.3.0] - 2023-04-28
|
||||
|
||||
- Minor changes
|
||||
|
||||
### New
|
||||
|
||||
- Windows OS Logging support
|
||||
|
||||
## [0.2.1] - 2023-03-29
|
||||
|
||||
### New
|
||||
|
||||
- Added aliases for the short form of function calls
|
||||
|
||||
### Bug fixes
|
||||
|
||||
- Calling the main object
|
||||
|
||||
## [0.2.0] - 2023-03-29
|
||||
|
||||
- Removed functions `fileOn()` and `fileOff()`
|
||||
|
||||
### New
|
||||
|
||||
- Simultaneous writing to the standard stream, syslog and file by binary setting the output flag
|
||||
|
||||
## [0.1.0] - 2023-03-23
|
||||
|
||||
### The first stable working release
|
||||
|
||||
- Output to the standard stream or syslog
|
||||
- Enable an entry in the file
|
||||
162
README.md
162
README.md
|
|
@ -1,152 +1,62 @@
|
|||

|
||||
# singlog
|
||||
|
||||
[](https://www.gnu.org/licenses/old-licenses/gpl-2.0.html)
|
||||
[](https://git.zhirov.kz/dlang/singlog)
|
||||
[](https://github.com/AlexanderZhirov/singlog)
|
||||
[](https://code.dlang.org/packages/singlog)
|
||||
[](https://www.linux.org/)
|
||||
[](https://support.microsoft.com/en-US/windows)
|
||||
Singleton for simple logging
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
# Singleton Logging Module
|
||||
|
||||
`singlog` is a singleton logging module written in the D programming language, designed to provide thread-safe, cross-platform logging with flexible output targets. It supports multiple log levels, configurable output destinations (syslog, console, file), and optional colored console output, making it a versatile tool for application logging.
|
||||
|
||||
## Features
|
||||
|
||||
- **Thread-Safety**: Utilizes a `Mutex` to ensure safe logging in multi-threaded applications.
|
||||
- **Cross-Platform**: Works on both Windows (Event Log, console) and POSIX (syslog, console) systems.
|
||||
- **Flexible Output Targets**: Supports logging to:
|
||||
- System logs (syslog on POSIX, Event Log on Windows).
|
||||
- Standard output (`stdout` for NOTICE and above, `stderr` for ERROR and below).
|
||||
- Files (with configurable file paths).
|
||||
- **Log Levels**: Seven configurable levels:
|
||||
- `DEBUGGING` (highest priority)
|
||||
- `ALERT`
|
||||
- `CRITICAL`
|
||||
- `ERROR`
|
||||
- `WARNING`
|
||||
- `NOTICE`
|
||||
- `INFORMATION` (lowest priority)
|
||||
- **Fluent Interface**: Provides a chaining API for easy configuration of output targets, log levels, and settings.
|
||||
- **Colored Output**: Optional ANSI color support for console messages (on POSIX) or Windows console colors.
|
||||
- **Singleton Design**: Ensures a single logger instance throughout the application, accessible via `Log.msg` or the `log` alias.
|
||||
- **Aliases**: Short aliases (e.g., `d` for `debugging`, `e` for `error`) for concise logging.
|
||||
|
||||
## Installation
|
||||
|
||||
To use `singlog`, include it in your D project:
|
||||
|
||||
1. **Via Source**: Copy the `singlog.d` file into your project’s source directory.
|
||||
2. **Via DUB** (if packaged):
|
||||
|
||||
Add it to your `dub.json`:
|
||||
```json
|
||||
"dependencies": {
|
||||
"singlog": "~>1.0.0"
|
||||
}
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
### Basic Configuration and Logging
|
||||
|
||||
The `singlog` module provides a singleton logger instance accessible via `Log.msg` or the global `log` alias. Here’s a basic example:
|
||||
## Basic Usage
|
||||
|
||||
```d
|
||||
import singlog;
|
||||
import simplog;
|
||||
|
||||
void main() {
|
||||
// Configure the logger
|
||||
log.program("MyApp") // Set program name for syslog/Event Log
|
||||
.color(true) // Enable colored console output
|
||||
.level(log.level.debugging) // Set minimum log level to DEBUGGING
|
||||
.output(log.output.std.file.syslog) // Output to console, file, and syslog
|
||||
.file("./myapp.log"); // Set log file path
|
||||
|
||||
// Log messages
|
||||
log.debugging("Starting application in debug mode");
|
||||
log.information("Initialization complete");
|
||||
log.error("Failed to load resource");
|
||||
void main()
|
||||
{
|
||||
Log.msg.level(Log.DEBUG);
|
||||
Log.msg.output(Log.SYSLOG);
|
||||
Log.msg.file("./file.log");
|
||||
Log.msg.warning("Hello, World!");
|
||||
}
|
||||
```
|
||||
|
||||
This configures the logger to:
|
||||
- Identify as "MyApp" in system logs.
|
||||
- Use colored output on the console.
|
||||
- Log all messages (from `DEBUGGING` up).
|
||||
- Write to the console, a file (`myapp.log`), and the system log.
|
||||
## Examples
|
||||
|
||||
### Log Levels and Aliases
|
||||
|
||||
The logger supports seven log levels with corresponding methods and aliases:
|
||||
|
||||
| Level | Method | Alias | Description |
|
||||
|---------------|-------------------|-------|------------------------------|
|
||||
| `DEBUGGING` | `debugging()` | `d()` | Debugging information |
|
||||
| `ALERT` | `alert()` | `a()` | High-priority alerts |
|
||||
| `CRITICAL` | `critical()` | `c()` | Critical errors |
|
||||
| `ERROR` | `error()` | `e()` | General errors |
|
||||
| `WARNING` | `warning()` | `w()` | Warnings |
|
||||
| `NOTICE` | `notice()` | `n()` | Notices |
|
||||
| `INFORMATION` | `information()` | `i()` | Informational messages |
|
||||
|
||||
Example using aliases:
|
||||
Setting the error output level:
|
||||
|
||||
```d
|
||||
log.d("Debug message");
|
||||
log.i("Info message");
|
||||
log.e("Error message");
|
||||
Log.msg.level(Log.DEBUG);
|
||||
Log.msg.level(Log.ALERT);
|
||||
Log.msg.level(Log.CRIT);
|
||||
Log.msg.level(Log.ERR);
|
||||
Log.msg.level(Log.WARNING);
|
||||
Log.msg.level(Log.NOTICE);
|
||||
Log.msg.level(Log.INFO);
|
||||
```
|
||||
|
||||
### Output Targets
|
||||
|
||||
Output targets can be configured using the `output()` method and its fluent interface:
|
||||
|
||||
- `syslog()`: Logs to the system log (Event Log on Windows, syslog on POSIX).
|
||||
- `std()`: Logs to the console (`stdout` or `stderr` based on log level).
|
||||
- `file()`: Logs to a file (requires `file()` to set the path).
|
||||
|
||||
Example:
|
||||
Assigning a target output:
|
||||
|
||||
```d
|
||||
log.output(log.output.std.file); // Console and file output
|
||||
log.i("This goes to console and file");
|
||||
Log.msg.output(Log.SYSLOG);
|
||||
Log.msg.output(Log.STDOUT);
|
||||
```
|
||||
|
||||
### Temporary Output Override
|
||||
|
||||
Use `now()` to temporarily override output targets for the next log call:
|
||||
Setup and allowing writing to a file:
|
||||
|
||||
```d
|
||||
log.now(log.output.std).n("This goes only to console");
|
||||
log.i("This uses default outputs again");
|
||||
Log.msg.file("./file.log");
|
||||
Log.msg.fileOn();
|
||||
Log.msg.fileOff();
|
||||
```
|
||||
|
||||
### Colored Output
|
||||
|
||||
Enable colored output with `color(true)`:
|
||||
Output of messages to the log:
|
||||
|
||||
```d
|
||||
log.color(true);
|
||||
log.w("This warning will be yellow on POSIX or Windows");
|
||||
log.c("This critical message will be magenta");
|
||||
Log.msg.alert("Alert message");
|
||||
Log.msg.critical("Critical message");
|
||||
Log.msg.error("Error message");
|
||||
Log.msg.warning("Warning message");
|
||||
Log.msg.notice("Notice message");
|
||||
Log.msg.informations("Information message");
|
||||
Log.msg.debugging("Debugging message");
|
||||
```
|
||||
|
||||
Colors differ by platform:
|
||||
- **POSIX**: Uses ANSI escape codes (e.g., green for `DEBUGGING`, red for `ERROR`).
|
||||
- **Windows**: Uses console color attributes (e.g., yellow for `WARNING`, white for `INFORMATION`).
|
||||
## Dub
|
||||
|
||||
### File Logging
|
||||
|
||||
Set a log file with `file()`:
|
||||
|
||||
```d
|
||||
log.file("app.log");
|
||||
log.e("This error goes to app.log");
|
||||
```
|
||||
|
||||
The file is opened in append mode (`"a+"`) and includes timestamps.
|
||||
Add a dependency on `"singlog": "~>0.1.0"`.
|
||||
|
|
|
|||
17
dub.json
17
dub.json
|
|
@ -7,22 +7,9 @@
|
|||
"license": "GPL-2.0",
|
||||
"copyright": "© Alexander Zhirov, 2023",
|
||||
"description": "Singleton for simple logging",
|
||||
"targetType": "library",
|
||||
"targetPath": "lib",
|
||||
"targetName": "singlog",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "library",
|
||||
"targetType": "library",
|
||||
"targetPath": "lib"
|
||||
},
|
||||
{
|
||||
"name": "test",
|
||||
"targetType": "executable",
|
||||
"targetPath": "bin",
|
||||
"targetName": "test",
|
||||
"importPaths": ["source","tests"],
|
||||
"sourcePaths": ["tests"]
|
||||
}
|
||||
],
|
||||
"dependencies": {
|
||||
"datefmt": "~>1.0.4"
|
||||
}
|
||||
|
|
|
|||
111
man/singlog.3
111
man/singlog.3
|
|
@ -1,111 +0,0 @@
|
|||
.\" Man page for the singlog library
|
||||
.TH SINGLOG 3 "March 23, 2025" "singlog" "Programmer's Manual"
|
||||
.SH NAME
|
||||
singlog \- Singleton logging library with thread-safety and flexible output targets
|
||||
|
||||
.SH SYNOPSIS
|
||||
.nf
|
||||
import singlog;
|
||||
|
||||
Log logger = Log.msg; // Access singleton instance
|
||||
log.<method>(<args>); // Use global alias
|
||||
.fi
|
||||
|
||||
.SH DESCRIPTION
|
||||
The \fBsinglog\fR library provides a thread-safe, singleton-based logging utility designed for cross-platform use on Windows and POSIX systems. It supports multiple output targets (syslog, stdout/stderr, file), configurable log levels, and optional colored console output. The library uses a fluent interface for easy configuration and provides short aliases for common log levels.
|
||||
|
||||
.SH FEATURES
|
||||
.TP
|
||||
.B Thread-safety
|
||||
Uses a \fBMutex\fR to ensure safe logging in multi-threaded applications.
|
||||
.TP
|
||||
.B Cross-platform
|
||||
Supports Windows (Event Log, console) and POSIX (syslog, console).
|
||||
.TP
|
||||
.B Flexible output
|
||||
Logs to syslog, stdout/stderr (based on log level), or files.
|
||||
.TP
|
||||
.B Log levels
|
||||
Seven levels: \fBDEBUGGING\fR, \fBALERT\fR, \fBCRITICAL\fR, \fBERROR\fR, \fBWARNING\fR, \fBNOTICE\fR, \fBINFORMATION\fR.
|
||||
.TP
|
||||
.B Fluent interface
|
||||
Chainable configuration for output targets, levels, and more.
|
||||
.TP
|
||||
.B Colored output
|
||||
Optional color support for console messages (STD output only).
|
||||
|
||||
.SH METHODS
|
||||
.TP
|
||||
.B Log.msg
|
||||
Returns the singleton instance of the \fBLog\fR class.
|
||||
.RS
|
||||
Example: \fBauto logger = Log.msg; logger.i("Logger retrieved");\fR
|
||||
.RE
|
||||
.TP
|
||||
.B program(string name)
|
||||
Sets the program name for syslog identification. Returns \fBLog\fR for chaining.
|
||||
.RS
|
||||
Example: \fBlog.program("MyApp").i("Name set");\fR
|
||||
.RE
|
||||
.TP
|
||||
.B file(string path)
|
||||
Sets the log file path. Returns \fBLog\fR for chaining.
|
||||
.RS
|
||||
Example: \fBlog.file("app.log").i("File configured");\fR
|
||||
.RE
|
||||
.TP
|
||||
.B level(int priority)
|
||||
Sets the minimum log level. Returns \fBLog\fR for chaining.
|
||||
.RS
|
||||
Example: \fBlog.level(log.level.warning).w("This shows");\fR
|
||||
.RE
|
||||
.TP
|
||||
.B color(bool condition)
|
||||
Enables/disables colored console output. Returns \fBLog\fR for chaining.
|
||||
.RS
|
||||
Example: \fBlog.color(true).i("Colored output");\fR
|
||||
.RE
|
||||
.TP
|
||||
.B output(Output outs)
|
||||
Sets default output targets. Returns \fBLog\fR for chaining.
|
||||
.RS
|
||||
Example: \fBlog.output(log.output.std.file).i("To console and file");\fR
|
||||
.RE
|
||||
.TP
|
||||
.B now(Output outs)
|
||||
Temporarily overrides output targets for the next log call. Returns \fBNow\fR for chaining.
|
||||
.RS
|
||||
Example: \fBlog.now(log.output.std).n("Temp console output");\fR
|
||||
.RE
|
||||
.TP
|
||||
.B Logging methods
|
||||
Log messages at different levels: \fBalert\fR, \fBcritical\fR, \fBerror\fR, \fBwarning\fR, \fBnotice\fR, \fBinformation\fR, \fBdebugging\fR (with aliases \fBa\fR, \fBc\fR, \fBe\fR, \fBw\fR, \fBn\fR, \fBi\fR, \fBd\fR).
|
||||
.RS
|
||||
Example: \fBlog.e("Error occurred"); log.i(42);\fR
|
||||
.RE
|
||||
|
||||
.SH EXAMPLES
|
||||
Configure and use the logger:
|
||||
.nf
|
||||
import singlog;
|
||||
|
||||
void main() {
|
||||
log.program("MyApp")
|
||||
.color(true)
|
||||
.level(log.level.debugging)
|
||||
.output(log.output.std.file.syslog)
|
||||
.file("myapp.log");
|
||||
|
||||
log.d("Starting in debug mode");
|
||||
log.i("App running");
|
||||
log.e("Error occurred");
|
||||
log.now(log.output.std).n("Temp console message");
|
||||
}
|
||||
.fi
|
||||
|
||||
.SH SEE ALSO
|
||||
.BR dmd (1),
|
||||
.BR syslog (3)
|
||||
|
||||
.SH AUTHOR
|
||||
Alexander Zhirov
|
||||
111
man/singlog.ru.3
111
man/singlog.ru.3
|
|
@ -1,111 +0,0 @@
|
|||
.\" Страница руководства для библиотеки singlog
|
||||
.TH SINGLOG 3 "23 марта 2025" "singlog" "Руководство программиста"
|
||||
.SH ИМЯ
|
||||
singlog \- Библиотека логирования с singleton-паттерном, потокобезопасностью и гибкими целями вывода
|
||||
|
||||
.SH СИНТАКСИС
|
||||
.nf
|
||||
import singlog;
|
||||
|
||||
Log logger = Log.msg; // Получение singleton-экземпляра
|
||||
log.<метод>(<аргументы>); // Использование глобального алиаса
|
||||
.fi
|
||||
|
||||
.SH ОПИСАНИЕ
|
||||
Библиотека \fBsinglog\fR предоставляет потокобезопасную утилиту логирования на основе singleton-паттерна, предназначенную для кроссплатформенного использования в системах Windows и POSIX. Поддерживает несколько целей вывода (syslog, stdout/stderr, файл), настраиваемые уровни логирования и опциональный цветной вывод в консоль. Библиотека использует плавный интерфейс для удобной настройки и предоставляет короткие алиасы для распространенных уровней логирования.
|
||||
|
||||
.SH ОСОБЕННОСТИ
|
||||
.TP
|
||||
.B Потокобезопасность
|
||||
Использует \fBMutex\fR для обеспечения безопасного логирования в многопоточных приложениях.
|
||||
.TP
|
||||
.B Кроссплатформенность
|
||||
Поддерживает Windows (журнал событий, консоль) и POSIX (syslog, консоль).
|
||||
.TP
|
||||
.B Гибкий вывод
|
||||
Вывод логов в syslog, stdout/stderr (в зависимости от уровня) или файлы.
|
||||
.TP
|
||||
.B Уровни логирования
|
||||
Семь уровней: \fBDEBUGGING\fR, \fBALERT\fR, \fBCRITICAL\fR, \fBERROR\fR, \fBWARNING\fR, \fBNOTICE\fR, \fBINFORMATION\fR.
|
||||
.TP
|
||||
.B Плавный интерфейс
|
||||
Цепочная настройка целей вывода, уровней и других параметров.
|
||||
.TP
|
||||
.B Цветной вывод
|
||||
Опциональная поддержка цветного вывода в консоль (только для STD).
|
||||
|
||||
.SH МЕТОДЫ
|
||||
.TP
|
||||
.B Log.msg
|
||||
Возвращает singleton-экземпляр класса \fBLog\fR.
|
||||
.RS
|
||||
Пример: \fBauto logger = Log.msg; logger.i("Логгер получен");\fR
|
||||
.RE
|
||||
.TP
|
||||
.B program(string name)
|
||||
Устанавливает имя программы для идентификации в syslog. Возвращает \fBLog\fR для цепочки.
|
||||
.RS
|
||||
Пример: \fBlog.program("МоеПриложение").i("Имя установлено");\fR
|
||||
.RE
|
||||
.TP
|
||||
.B file(string path)
|
||||
Устанавливает путь к лог-файлу. Возвращает \fBLog\fR для цепочки.
|
||||
.RS
|
||||
Пример: \fBlog.file("app.log").i("Файл настроен");\fR
|
||||
.RE
|
||||
.TP
|
||||
.B level(int priority)
|
||||
Устанавливает минимальный уровень логирования. Возвращает \fBLog\fR для цепочки.
|
||||
.RS
|
||||
Пример: \fBlog.level(log.level.warning).w("Это отобразится");\fR
|
||||
.RE
|
||||
.TP
|
||||
.B color(bool condition)
|
||||
Включает/выключает цветной вывод в консоль. Возвращает \fBLog\fR для цепочки.
|
||||
.RS
|
||||
Пример: \fBlog.color(true).i("Цветной вывод");\fR
|
||||
.RE
|
||||
.TP
|
||||
.B output(Output outs)
|
||||
Устанавливает цели вывода по умолчанию. Возвращает \fBLog\fR для цепочки.
|
||||
.RS
|
||||
Пример: \fBlog.output(log.output.std.file).i("В консоль и файл");\fR
|
||||
.RE
|
||||
.TP
|
||||
.B now(Output outs)
|
||||
Временно переопределяет цели вывода для следующего вызова. Возвращает \fBNow\fR для цепочки.
|
||||
.RS
|
||||
Пример: \fBlog.now(log.output.std).n("Временный вывод в консоль");\fR
|
||||
.RE
|
||||
.TP
|
||||
.B Методы логирования
|
||||
Запись сообщений на разных уровнях: \fBalert\fR, \fBcritical\fR, \fBerror\fR, \fBwarning\fR, \fBnotice\fR, \fBinformation\fR, \fBdebugging\fR (с алиасами \fBa\fR, \fBc\fR, \fBe\fR, \fBw\fR, \fBn\fR, \fBi\fR, \fBd\fR).
|
||||
.RS
|
||||
Пример: \fBlog.e("Произошла ошибка"); log.i(42);\fR
|
||||
.RE
|
||||
|
||||
.SH ПРИМЕРЫ
|
||||
Настройка и использование логгера:
|
||||
.nf
|
||||
import singlog;
|
||||
|
||||
void main() {
|
||||
log.program("МоеПриложение")
|
||||
.color(true)
|
||||
.level(log.level.debugging)
|
||||
.output(log.output.std.file.syslog)
|
||||
.file("myapp.log");
|
||||
|
||||
log.d("Запуск в режиме отладки");
|
||||
log.i("Приложение работает");
|
||||
log.e("Произошла ошибка");
|
||||
log.now(log.output.std).n("Временное сообщение в консоль");
|
||||
}
|
||||
.fi
|
||||
|
||||
.SH СМ. ТАКЖЕ
|
||||
.BR dmd (1),
|
||||
.BR syslog (3)
|
||||
|
||||
.SH АВТОР
|
||||
Александр Жиров
|
||||
BIN
singlog.png
BIN
singlog.png
Binary file not shown.
|
Before Width: | Height: | Size: 11 KiB |
974
source/singlog.d
974
source/singlog.d
|
|
@ -1,875 +1,147 @@
|
|||
/++
|
||||
Singleton logging module with thread-safety and flexible output targets.
|
||||
|
||||
This module provides a simple, thread-safe logging utility with support for multiple output targets
|
||||
(syslog, standard output/error, file), configurable log levels, and optional colored console output.
|
||||
It is designed to be cross-platform, working on both Windows and POSIX systems.
|
||||
|
||||
The logger is implemented as a singleton, ensuring a single instance throughout the application.
|
||||
It supports fluent configuration for ease of use and provides short aliases for common log levels.
|
||||
+/
|
||||
module singlog;
|
||||
|
||||
version(Windows) {
|
||||
import core.sys.windows.windows;
|
||||
import std.utf : toUTF8, toUTF16z;
|
||||
} else version(Posix) {
|
||||
import core.sys.posix.syslog;
|
||||
}
|
||||
|
||||
import core.sync.mutex : Mutex;
|
||||
import std.string;
|
||||
import core.sys.posix.syslog;
|
||||
import std.stdio;
|
||||
import std.conv;
|
||||
import std.meta;
|
||||
import std.file;
|
||||
import std.datetime;
|
||||
import datefmt;
|
||||
|
||||
/++
|
||||
Singleton logging class with thread-safe operations and flexible output.
|
||||
Singleton for simple logging
|
||||
|
||||
The `Log` class is the core of the `singlog` module, providing a robust logging system with the following features:
|
||||
- **Thread-safety**: Uses a `Mutex` to ensure safe logging in multi-threaded applications.
|
||||
- **Cross-platform**: Supports Windows (Event Log, console) and POSIX (syslog, console) systems.
|
||||
- **Flexible output**: Allows logging to syslog, stdout/stderr (based on log level), and files.
|
||||
- **Log levels**: Supports seven levels (`DEBUGGING`, `ALERT`, `CRITICAL`, `ERROR`, `WARNING`, `NOTICE`, `INFORMATION`).
|
||||
- **Fluent interface**: Enables easy configuration chaining for output targets, levels, and more.
|
||||
- **Colored output**: Optional color support for console messages (STD output only).
|
||||
|
||||
The class is a singleton, accessible via the static `msg` property or the global `log` alias.
|
||||
|
||||
Example:
|
||||
---
|
||||
import singlog;
|
||||
|
||||
void main() {
|
||||
// Configure the logger
|
||||
Log logger = Log.msg; // Get singleton instance
|
||||
logger.program("TestApp")
|
||||
.color(true)
|
||||
.level(Log.DEBUGGING)
|
||||
.output(Log.Output().std.file.syslog)
|
||||
.file("test.log");
|
||||
|
||||
// Log messages with full method names
|
||||
logger.debugging("Starting in debug mode");
|
||||
logger.information("App is running");
|
||||
logger.error("An error occurred");
|
||||
|
||||
// Log messages with aliases
|
||||
logger.d("Debug alias");
|
||||
logger.i("Info alias");
|
||||
logger.e("Error alias");
|
||||
|
||||
// Temporary output override
|
||||
logger.now(Log.Output().std).notice("Temporary console message");
|
||||
}
|
||||
// Setting the error output level
|
||||
Log.msg.level(Log.DEBUG);
|
||||
Log.msg.level(Log.ALERT);
|
||||
Log.msg.level(Log.CRIT);
|
||||
Log.msg.level(Log.ERR);
|
||||
Log.msg.level(Log.WARNING);
|
||||
Log.msg.level(Log.NOTICE);
|
||||
Log.msg.level(Log.INFO);
|
||||
// Assigning a target output
|
||||
Log.msg.output(Log.SYSLOG);
|
||||
Log.msg.output(Log.STDOUT);
|
||||
// Setup and allowing writing to a file
|
||||
Log.msg.file("./file.log");
|
||||
Log.msg.fileOn();
|
||||
Log.msg.fileOff();
|
||||
// Output of messages to the log
|
||||
Log.msg.alert("Alert message");
|
||||
Log.msg.critical("Critical message");
|
||||
Log.msg.error("Error message");
|
||||
Log.msg.warning("Warning message");
|
||||
Log.msg.notice("Notice message");
|
||||
Log.msg.informations("Information message");
|
||||
Log.msg.debugging("Debugging message");
|
||||
---
|
||||
+/
|
||||
class Log {
|
||||
private:
|
||||
static Log _log; /// Singleton instance of the logger
|
||||
Mutex _mutex; /// Mutex for thread-safety
|
||||
string _path; /// Path to the log file
|
||||
File _file; /// File handle for logging
|
||||
bool _fileOpen = false; /// Indicates if the log file is open
|
||||
wstring _name = "singlog"; /// Program name for syslog identification
|
||||
bool _writeToFile = true; /// Flag to enable/disable file logging
|
||||
bool _color = false; /// Flag to enable/disable colored console output
|
||||
int _output = STD; /// Default output flags (STD by default)
|
||||
int _priority = INFORMATION; /// Minimum log level for output
|
||||
int _nowOutput = 0; /// Temporary output override for the next log call
|
||||
class Log
|
||||
{
|
||||
private static Log log;
|
||||
private string path;
|
||||
private bool writeToFile = false;
|
||||
private bool fileExist = true;
|
||||
private static SysTime time;
|
||||
|
||||
/++ Private constructor to enforce singleton pattern +/
|
||||
this() {
|
||||
_mutex = new Mutex();
|
||||
// Target output
|
||||
enum {SYSLOG, STDOUT}
|
||||
|
||||
// Message output level
|
||||
enum {
|
||||
DEBUG = 0,
|
||||
CRIT = 1,
|
||||
ERR = 2,
|
||||
WARNING = 3,
|
||||
NOTICE = 4,
|
||||
INFO = 5,
|
||||
ALERT = 6
|
||||
}
|
||||
|
||||
int msgOutput = STDOUT;
|
||||
int msgLevel = INFO;
|
||||
|
||||
private this() {}
|
||||
|
||||
private void writeLog(string message, int msgLevel, int priority)
|
||||
{
|
||||
if (this.msgLevel > msgLevel)
|
||||
return;
|
||||
if (this.msgOutput == STDOUT)
|
||||
writeln(message);
|
||||
else if (this.msgOutput == SYSLOG)
|
||||
syslog(priority, (message ~ "\0").ptr);
|
||||
writeFile(message);
|
||||
}
|
||||
|
||||
/++ Destructor to ensure the log file is closed +/
|
||||
~this() {
|
||||
synchronized (_mutex) {
|
||||
if (_fileOpen) {
|
||||
_file.close();
|
||||
_fileOpen = false;
|
||||
}
|
||||
private void writeFile(string message)
|
||||
{
|
||||
if (!this.writeToFile || !this.fileExist)
|
||||
return;
|
||||
|
||||
if (this.path.exists)
|
||||
this.fileExist = true;
|
||||
else
|
||||
{
|
||||
this.fileExist = false;
|
||||
this.warning("The log file does not exist: " ~ this.path);
|
||||
this.fileExist = true;
|
||||
}
|
||||
|
||||
File file;
|
||||
|
||||
try {
|
||||
file = File(this.path, "a+");
|
||||
} catch (Exception e) {
|
||||
this.fileOff();
|
||||
this.error("Unable to open the log file " ~ this.path);
|
||||
this.critical(e);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
file.writeln(this.time.format("%Y.%m.%d %H:%M:%S: ") ~ message);
|
||||
} catch (Exception e) {
|
||||
this.fileOff();
|
||||
this.error("Unable to write to the log file " ~ this.path);
|
||||
this.critical(e);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
file.close();
|
||||
} catch (Exception e) {
|
||||
this.fileOff();
|
||||
this.error("Unable to close the log file " ~ this.path);
|
||||
this.critical(e);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
version(Windows) {
|
||||
immutable int[] _sysPriority = [0, 1, 1, 1, 2, 3, 3]; /// Mapping of log levels to syslog priorities
|
||||
immutable WORD[] _sysPriorityOS = [ /// Windows Event Log types
|
||||
EVENTLOG_SUCCESS, // DEBUGGING
|
||||
EVENTLOG_ERROR_TYPE, // ALERT, CRITICAL, ERROR
|
||||
EVENTLOG_WARNING_TYPE, // WARNING
|
||||
EVENTLOG_INFORMATION_TYPE // NOTICE, INFORMATION
|
||||
];
|
||||
|
||||
immutable WORD[] _colorCodes = [ /// Console color codes for each log level
|
||||
FOREGROUND_GREEN, // DEBUGGING (green)
|
||||
FOREGROUND_BLUE, // ALERT (blue)
|
||||
FOREGROUND_RED | FOREGROUND_BLUE, // CRITICAL (magenta)
|
||||
FOREGROUND_RED, // ERROR (red)
|
||||
FOREGROUND_RED | FOREGROUND_GREEN, // WARNING (yellow)
|
||||
FOREGROUND_BLUE | FOREGROUND_GREEN, // NOTICE (cyan)
|
||||
FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_GREEN // INFORMATION (white)
|
||||
];
|
||||
|
||||
/++
|
||||
Writes a message to the Windows Event Log.
|
||||
|
||||
Params:
|
||||
message = The message to log.
|
||||
priority = The Windows Event Log type (e.g., EVENTLOG_ERROR_TYPE).
|
||||
+/
|
||||
void writesyslog(string message, WORD priority) {
|
||||
auto wMessage = message.toUTF16z();
|
||||
HANDLE handleEventLog = RegisterEventSourceW(null, _name.toUTF16z());
|
||||
if (handleEventLog == null) return;
|
||||
ReportEventW(handleEventLog, priority, 0, 0, null, 1, 0, &wMessage, null);
|
||||
DeregisterEventSource(handleEventLog);
|
||||
}
|
||||
|
||||
/++
|
||||
Outputs a colored log message to the console on Windows.
|
||||
|
||||
Params:
|
||||
handle = The console handle (STD_OUTPUT_HANDLE or STD_ERROR_HANDLE).
|
||||
time = The timestamp of the message.
|
||||
message = The message to log.
|
||||
priority = The log level (used to select the color).
|
||||
+/
|
||||
void colorTextOutput(HANDLE handle, string time, string message, int priority) {
|
||||
CONSOLE_SCREEN_BUFFER_INFO defaultConsole;
|
||||
if (!GetConsoleScreenBufferInfo(handle, &defaultConsole)) return;
|
||||
|
||||
wstring wTime = "%s ".format(time).to!wstring;
|
||||
wstring wType = _type[priority].to!wstring;
|
||||
wstring wMessage = " %s\n".format(message).to!wstring;
|
||||
|
||||
switch (GetFileType(handle)) {
|
||||
case FILE_TYPE_CHAR:
|
||||
WriteConsoleW(handle, wTime.ptr, cast(DWORD)wTime.length, null, null);
|
||||
SetConsoleTextAttribute(handle, _colorCodes[priority] | FOREGROUND_INTENSITY);
|
||||
WriteConsoleW(handle, wType.ptr, cast(DWORD)wType.length, null, null);
|
||||
SetConsoleTextAttribute(handle, _colorCodes[priority]);
|
||||
WriteConsoleW(handle, wMessage.ptr, cast(DWORD)wMessage.length, null, null);
|
||||
SetConsoleTextAttribute(handle, defaultConsole.wAttributes);
|
||||
break;
|
||||
case FILE_TYPE_PIPE, FILE_TYPE_DISK:
|
||||
auto utf8Message = (wTime ~ wType ~ wMessage).toUTF8;
|
||||
WriteFile(handle, utf8Message.ptr, cast(DWORD)utf8Message.length, null, null);
|
||||
break;
|
||||
default:
|
||||
writesyslog("Unknown output file", _sysPriorityOS[_sysPriority[ERROR]]);
|
||||
|
||||
@property static Log msg()
|
||||
{
|
||||
if (this.log is null)
|
||||
{
|
||||
this.log = new Log;
|
||||
this.time = Clock.currTime();
|
||||
}
|
||||
|
||||
return this.log;
|
||||
}
|
||||
|
||||
/++
|
||||
Outputs a plain log message to the console on Windows.
|
||||
void output(int msgOutput) { this.msgOutput = msgOutput; }
|
||||
void level(int msgLevel) { this.msgLevel = msgLevel; }
|
||||
void file(string path) { this.path = path; }
|
||||
|
||||
Params:
|
||||
handle = The console handle (STD_OUTPUT_HANDLE or STD_ERROR_HANDLE).
|
||||
time = The timestamp of the message.
|
||||
message = The message to log.
|
||||
priority = The log level (used to format the message).
|
||||
+/
|
||||
void defaultTextOutput(HANDLE handle, string time, string message, int priority) {
|
||||
wstring wMessage = "%s %s %s\n".format(time, _type[priority], message).to!wstring;
|
||||
switch (GetFileType(handle)) {
|
||||
case FILE_TYPE_CHAR:
|
||||
WriteConsoleW(handle, wMessage.ptr, cast(DWORD)wMessage.length, null, null);
|
||||
break;
|
||||
case FILE_TYPE_PIPE, FILE_TYPE_DISK:
|
||||
auto utf8Message = wMessage.toUTF8;
|
||||
WriteFile(handle, utf8Message.ptr, cast(DWORD)utf8Message.length, null, null);
|
||||
break;
|
||||
default:
|
||||
writesyslog("Unknown output file", _sysPriorityOS[_sysPriority[ERROR]]);
|
||||
}
|
||||
}
|
||||
void fileOn() { this.writeToFile = true; }
|
||||
void fileOff() { this.writeToFile = false; }
|
||||
|
||||
/++
|
||||
Writes a message to the console on Windows, choosing stdout or stderr based on log level.
|
||||
|
||||
Params:
|
||||
time = The timestamp of the message.
|
||||
message = The message to log.
|
||||
priority = The log level (ERROR and above go to stderr, others to stdout).
|
||||
|
||||
Example:
|
||||
---
|
||||
log.writestd("2025.03.23 12:00:00", "Test error", ERROR); // Outputs to stderr
|
||||
log.writestd("2025.03.23 12:00:01", "Test info", INFORMATION); // Outputs to stdout
|
||||
---
|
||||
+/
|
||||
void writestd(string time, string message, int priority) {
|
||||
HANDLE handle = (priority <= ERROR) ?
|
||||
GetStdHandle(STD_ERROR_HANDLE) :
|
||||
GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
_color ? colorTextOutput(handle, time, message, priority) : defaultTextOutput(handle, time, message, priority);
|
||||
}
|
||||
} else version(Posix) {
|
||||
immutable int[] _sysPriority = [0, 1, 2, 3, 4, 5, 6]; /// Mapping of log levels to syslog priorities
|
||||
immutable int[] _sysPriorityOS = [ /// POSIX syslog priorities
|
||||
LOG_DEBUG, // DEBUGGING
|
||||
LOG_ALERT, // ALERT
|
||||
LOG_CRIT, // CRITICAL
|
||||
LOG_ERR, // ERROR
|
||||
LOG_WARNING, // WARNING
|
||||
LOG_NOTICE, // NOTICE
|
||||
LOG_INFO // INFORMATION
|
||||
];
|
||||
|
||||
immutable string[] _colorCodes = [ /// ANSI color codes for console output
|
||||
"\x1b[1;32m%s\x1b[0;32m %s\x1b[0;0m", // DEBUGGING (green)
|
||||
"\x1b[1;34m%s\x1b[0;34m %s\x1b[0;0m", // ALERT (blue)
|
||||
"\x1b[1;35m%s\x1b[0;35m %s\x1b[0;0m", // CRITICAL (magenta)
|
||||
"\x1b[1;31m%s\x1b[0;31m %s\x1b[0;0m", // ERROR (red)
|
||||
"\x1b[1;33m%s\x1b[0;33m %s\x1b[0;0m", // WARNING (yellow)
|
||||
"\x1b[1;36m%s\x1b[0;36m %s\x1b[0;0m", // NOTICE (cyan)
|
||||
"\x1b[1;97m%s\x1b[0;97m %s\x1b[0;0m" // INFORMATION (white)
|
||||
];
|
||||
|
||||
/++
|
||||
Writes a message to the console on POSIX, choosing stdout or stderr based on log level.
|
||||
|
||||
Params:
|
||||
time = The timestamp of the message.
|
||||
message = The message to log.
|
||||
priority = The log level (ERROR and above go to stderr, others to stdout).
|
||||
|
||||
Example:
|
||||
---
|
||||
log.writestd("2025.03.23 12:00:00", "Critical failure", CRITICAL); // Outputs to stderr
|
||||
log.writestd("2025.03.23 12:00:01", "System ready", NOTICE); // Outputs to stdout
|
||||
---
|
||||
+/
|
||||
void writestd(string time, string message, int priority) {
|
||||
if (priority <= ERROR) {
|
||||
stderr.writefln("%s %s", time, (_color ? _colorCodes[priority] : "%s %s").format(_type[priority], message));
|
||||
} else {
|
||||
writefln("%s %s", time, (_color ? _colorCodes[priority] : "%s %s").format(_type[priority], message));
|
||||
}
|
||||
}
|
||||
|
||||
/++
|
||||
Writes a message to the POSIX syslog.
|
||||
|
||||
Params:
|
||||
message = The message to log.
|
||||
priority = The syslog priority level (e.g., LOG_ERR).
|
||||
|
||||
Example:
|
||||
---
|
||||
log.writesyslog("System crash", ERROR); // Logs to syslog with LOG_ERR
|
||||
---
|
||||
+/
|
||||
void writesyslog(string message, int priority) {
|
||||
syslog(priority, message.toStringz());
|
||||
}
|
||||
void alert(T)(T message) { writeLog(message.to!string, ALERT, LOG_ALERT); }
|
||||
void critical(T)(T message) { writeLog(message.to!string, CRIT, LOG_CRIT); }
|
||||
void error(T)(T message) { writeLog(message.to!string, ERR, LOG_ERR); }
|
||||
void warning(T)(T message) { writeLog(message.to!string, WARNING, LOG_WARNING); }
|
||||
void notice(T)(T message) { writeLog(message.to!string, NOTICE, LOG_NOTICE); }
|
||||
void information(T)(T message) { writeLog(message.to!string, INFO, LOG_INFO); }
|
||||
void debugging(T)(T message) {writeLog(message.to!string, DEBUG, LOG_DEBUG); }
|
||||
}
|
||||
|
||||
/// Log level constants
|
||||
public enum : int {
|
||||
DEBUGGING = 0, /// Debugging messages (lowest priority)
|
||||
ALERT = 1, /// Alert messages (high priority)
|
||||
CRITICAL = 2, /// Critical errors
|
||||
ERROR = 3, /// General errors
|
||||
WARNING = 4, /// Warnings
|
||||
NOTICE = 5, /// Notices
|
||||
INFORMATION = 6 /// Informational messages (highest priority)
|
||||
}
|
||||
|
||||
/// Output target flags
|
||||
public enum : int {
|
||||
SYSLOG = 1, /// System log (Event Log on Windows, syslog on POSIX)
|
||||
STD = 2, /// Standard output (stdout for >= WARNING, stderr for <= ERROR)
|
||||
FILE = 8 /// File output
|
||||
}
|
||||
|
||||
immutable string[] _type = [ /// Log level prefixes for formatting
|
||||
"[DEBUG]:", "[ALERT]:", "[CRITICAL]:", "[ERROR]:", "[WARNING]:", "[NOTICE]:", "[INFO]:"
|
||||
];
|
||||
|
||||
/++
|
||||
Core logging function that writes a message to configured outputs.
|
||||
|
||||
Params:
|
||||
message = The message to log.
|
||||
priority = The log level of the message.
|
||||
|
||||
Example:
|
||||
---
|
||||
log.writelog("Application started", INFORMATION); // Logs to configured outputs
|
||||
log.writelog("Fatal error", CRITICAL); // Logs to stderr and other outputs
|
||||
---
|
||||
+/
|
||||
void writelog(string message, int priority) {
|
||||
synchronized (_mutex) {
|
||||
if (_priority > priority) return;
|
||||
int output = _nowOutput ? _nowOutput : _output;
|
||||
_nowOutput = 0;
|
||||
|
||||
string time;
|
||||
if (output & (STD | FILE)) {
|
||||
time = Clock.currTime().format("%Y.%m.%d %H:%M:%S");
|
||||
}
|
||||
|
||||
if (output & SYSLOG) writesyslog(message, _sysPriorityOS[_sysPriority[priority]]);
|
||||
if (output & STD) writestd(time, message, priority);
|
||||
if (output & FILE) writefile(time, message, priority);
|
||||
}
|
||||
}
|
||||
|
||||
/++
|
||||
Writes a message to the configured log file.
|
||||
|
||||
Params:
|
||||
time = The timestamp of the message.
|
||||
message = The message to log.
|
||||
priority = The log level of the message.
|
||||
|
||||
Example:
|
||||
---
|
||||
log.writefile("2025.03.23 12:00:00", "File operation failed", ERROR); // Writes to log file
|
||||
---
|
||||
+/
|
||||
void writefile(string time, string message, int priority) {
|
||||
if (!_writeToFile) return;
|
||||
|
||||
synchronized (_mutex) {
|
||||
if (!_fileOpen) {
|
||||
try {
|
||||
_file = File(_path, "a+");
|
||||
_fileOpen = true;
|
||||
} catch (Exception e) {
|
||||
_writeToFile = false;
|
||||
now(this.output.std).error("Unable to open the log file " ~ _path);
|
||||
information(e.msg);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
_file.writefln("%s %s %s", time, _type[priority], message);
|
||||
} catch (Exception e) {
|
||||
_writeToFile = false;
|
||||
now(this.output.std).error("Unable to write to the log file " ~ _path);
|
||||
information(e.msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
/++
|
||||
Property to access the singleton instance of the logger.
|
||||
|
||||
Returns:
|
||||
The single instance of the `Log` class.
|
||||
|
||||
Example:
|
||||
---
|
||||
auto logger = Log.msg; // Access the singleton logger
|
||||
logger.information("Logger retrieved");
|
||||
---
|
||||
+/
|
||||
@property static Log msg() {
|
||||
if (_log is null) {
|
||||
synchronized {
|
||||
if (_log is null) _log = new Log();
|
||||
}
|
||||
}
|
||||
return _log;
|
||||
}
|
||||
|
||||
/++
|
||||
Sets the program name for syslog identification.
|
||||
|
||||
Params:
|
||||
name = The name of the program.
|
||||
|
||||
Returns:
|
||||
This `Log` instance for chaining.
|
||||
|
||||
Example:
|
||||
---
|
||||
log.program("MyProgram"); // Sets syslog identifier to "MyProgram"
|
||||
log.i("Program name set");
|
||||
---
|
||||
+/
|
||||
Log program(string name) {
|
||||
synchronized (_mutex) { _name = name.to!wstring; }
|
||||
return this;
|
||||
}
|
||||
|
||||
/++
|
||||
Sets the file path for logging.
|
||||
|
||||
Params:
|
||||
path = The path to the log file.
|
||||
|
||||
Returns:
|
||||
This `Log` instance for chaining.
|
||||
|
||||
Example:
|
||||
---
|
||||
log.file("myapp.log"); // Sets log file to "myapp.log"
|
||||
log.i("Log file configured");
|
||||
---
|
||||
+/
|
||||
Log file(string path) {
|
||||
synchronized (_mutex) {
|
||||
if (_fileOpen) { _file.close(); _fileOpen = false; }
|
||||
_path = path;
|
||||
_writeToFile = true;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/++
|
||||
Sets the minimum log level.
|
||||
|
||||
Params:
|
||||
priority = The minimum log level (e.g., DEBUGGING, ERROR).
|
||||
|
||||
Returns:
|
||||
This `Log` instance for chaining.
|
||||
|
||||
Example:
|
||||
---
|
||||
log.level(log.level.warning); // Only WARNING and above will be logged
|
||||
log.d("This won't show"); // Ignored due to level
|
||||
log.w("This will show");
|
||||
---
|
||||
+/
|
||||
Log level(int priority) {
|
||||
synchronized (_mutex) { _priority = priority; }
|
||||
return this;
|
||||
}
|
||||
|
||||
/++
|
||||
Enables or disables colored console output.
|
||||
|
||||
Params:
|
||||
condition = `true` to enable colors, `false` to disable.
|
||||
|
||||
Returns:
|
||||
This `Log` instance for chaining.
|
||||
|
||||
Example:
|
||||
---
|
||||
log.color(true); // Enables colored output
|
||||
log.i("This will be colored");
|
||||
log.color(false); // Disables colored output
|
||||
log.i("This will be plain");
|
||||
---
|
||||
+/
|
||||
Log color(bool condition) {
|
||||
synchronized (_mutex) { _color = condition; }
|
||||
return this;
|
||||
}
|
||||
|
||||
/++
|
||||
Starts configuring output targets using a fluent interface.
|
||||
|
||||
Returns:
|
||||
An `Output` struct for chaining output target methods.
|
||||
|
||||
Example:
|
||||
---
|
||||
auto outs = log.output.std.file; // Configures std and file output
|
||||
log.output(outs);
|
||||
log.i("Logged to console and file");
|
||||
---
|
||||
+/
|
||||
Output output() {
|
||||
return Output();
|
||||
}
|
||||
|
||||
/++
|
||||
Sets the default output targets.
|
||||
|
||||
Params:
|
||||
outs = An `Output` struct with configured targets.
|
||||
|
||||
Returns:
|
||||
This `Log` instance for chaining.
|
||||
|
||||
Example:
|
||||
---
|
||||
log.output(log.output.syslog.std); // Sets output to syslog and console
|
||||
log.i("Logged to syslog and console");
|
||||
---
|
||||
+/
|
||||
Log output(Output outs) {
|
||||
synchronized (_mutex) { _output = outs.value; }
|
||||
return this;
|
||||
}
|
||||
|
||||
/++
|
||||
Temporarily overrides output targets for the next log call.
|
||||
|
||||
Params:
|
||||
outs = An `Output` struct with temporary targets.
|
||||
|
||||
Returns:
|
||||
A `Now` struct to chain the log call.
|
||||
|
||||
Example:
|
||||
---
|
||||
log.now(log.output.std).n("Temporary console output"); // Only to console
|
||||
log.i("Back to default outputs");
|
||||
---
|
||||
+/
|
||||
Now now(Output outs) {
|
||||
synchronized (_mutex) { _nowOutput = outs.value; }
|
||||
return Now(this);
|
||||
}
|
||||
|
||||
/++
|
||||
Logs an alert message (priority ALERT).
|
||||
|
||||
Params:
|
||||
message = The message to log (converted to string).
|
||||
|
||||
Example:
|
||||
---
|
||||
log.alert("System alert!"); // Logs with ALERT level
|
||||
log.a(42); // Logs "42" with ALERT level
|
||||
---
|
||||
+/
|
||||
void alert(T)(T message) { writelog(message.to!string, ALERT); }
|
||||
|
||||
/++
|
||||
Logs a critical error message (priority CRITICAL).
|
||||
|
||||
Params:
|
||||
message = The message to log (converted to string).
|
||||
|
||||
Example:
|
||||
---
|
||||
log.critical("Critical failure"); // Logs with CRITICAL level
|
||||
log.c("Out of memory"); // Alias usage
|
||||
---
|
||||
+/
|
||||
void critical(T)(T message) { writelog(message.to!string, CRITICAL); }
|
||||
|
||||
/++
|
||||
Logs an error message (priority ERROR).
|
||||
|
||||
Params:
|
||||
message = The message to log (converted to string).
|
||||
|
||||
Example:
|
||||
---
|
||||
log.error("File not found"); // Logs with ERROR level to stderr
|
||||
log.e("Error code: 404"); // Alias usage
|
||||
---
|
||||
+/
|
||||
void error(T)(T message) { writelog(message.to!string, ERROR); }
|
||||
|
||||
/++
|
||||
Logs a warning message (priority WARNING).
|
||||
|
||||
Params:
|
||||
message = The message to log (converted to string).
|
||||
|
||||
Example:
|
||||
---
|
||||
log.warning("Low disk space"); // Logs with WARNING level
|
||||
log.w("Check disk"); // Alias usage
|
||||
---
|
||||
+/
|
||||
void warning(T)(T message) { writelog(message.to!string, WARNING); }
|
||||
|
||||
/++
|
||||
Logs a notice message (priority NOTICE).
|
||||
|
||||
Params:
|
||||
message = The message to log (converted to string).
|
||||
|
||||
Example:
|
||||
---
|
||||
log.notice("User logged in"); // Logs with NOTICE level
|
||||
log.n("Session started"); // Alias usage
|
||||
---
|
||||
+/
|
||||
void notice(T)(T message) { writelog(message.to!string, NOTICE); }
|
||||
|
||||
/++
|
||||
Logs an informational message (priority INFORMATION).
|
||||
|
||||
Params:
|
||||
message = The message to log (converted to string).
|
||||
|
||||
Example:
|
||||
---
|
||||
log.information("App started"); // Logs with INFORMATION level
|
||||
log.i("Version 1.0"); // Alias usage
|
||||
---
|
||||
+/
|
||||
void information(T)(T message) { writelog(message.to!string, INFORMATION); }
|
||||
|
||||
/++
|
||||
Logs a debugging message (priority DEBUGGING).
|
||||
|
||||
Params:
|
||||
message = The message to log (converted to string).
|
||||
|
||||
Example:
|
||||
---
|
||||
log.debugging("Variable x = 5"); // Logs with DEBUGGING level
|
||||
log.d("Entering loop"); // Alias usage
|
||||
---
|
||||
+/
|
||||
void debugging(T)(T message) { writelog(message.to!string, DEBUGGING); }
|
||||
|
||||
/++ Alias for `alert` +/
|
||||
alias a = alert;
|
||||
/++ Alias for `critical` +/
|
||||
alias c = critical;
|
||||
/++ Alias for `error` +/
|
||||
alias e = error;
|
||||
/++ Alias for `warning` +/
|
||||
alias w = warning;
|
||||
/++ Alias for `notice` +/
|
||||
alias n = notice;
|
||||
/++ Alias for `information` +/
|
||||
alias i = information;
|
||||
/++ Alias for `debugging` +/
|
||||
alias d = debugging;
|
||||
|
||||
/++
|
||||
Struct for fluent configuration of output targets.
|
||||
|
||||
Provides methods to chain output targets, accumulating them into a bitmask.
|
||||
+/
|
||||
struct Output {
|
||||
private int value = 0;
|
||||
|
||||
/++
|
||||
Adds syslog to the output targets.
|
||||
|
||||
Example:
|
||||
---
|
||||
log.output(log.output.syslog); // Enables syslog output
|
||||
log.i("Logged to syslog");
|
||||
---
|
||||
+/
|
||||
Output syslog() { value |= SYSLOG; return this; }
|
||||
|
||||
/++
|
||||
Adds standard output (stdout/stderr) to the output targets.
|
||||
|
||||
Example:
|
||||
---
|
||||
log.output(log.output.std); // Enables console output
|
||||
log.w("Logged to console");
|
||||
---
|
||||
+/
|
||||
Output std() { value |= STD; return this; }
|
||||
|
||||
/++
|
||||
Adds file output to the output targets.
|
||||
|
||||
Example:
|
||||
---
|
||||
log.output(log.output.file); // Enables file output
|
||||
log.i("Logged to file");
|
||||
---
|
||||
+/
|
||||
Output file() { value |= FILE; return this; }
|
||||
}
|
||||
|
||||
/++
|
||||
Struct for fluent configuration of log levels.
|
||||
|
||||
Provides methods to specify log levels.
|
||||
+/
|
||||
struct Level {
|
||||
/++ Returns the DEBUGGING level +/
|
||||
int debugging() { return DEBUGGING; }
|
||||
/++ Returns the ALERT level +/
|
||||
int alert() { return ALERT; }
|
||||
/++ Returns the CRITICAL level +/
|
||||
int critical() { return CRITICAL; }
|
||||
/++ Returns the ERROR level +/
|
||||
int error() { return ERROR; }
|
||||
/++ Returns the WARNING level +/
|
||||
int warning() { return WARNING; }
|
||||
/++ Returns the NOTICE level +/
|
||||
int notice() { return NOTICE; }
|
||||
/++ Returns the INFORMATION level +/
|
||||
int information() { return INFORMATION; }
|
||||
|
||||
/++ Alias for `debugging` +/
|
||||
alias d = debugging;
|
||||
/++ Alias for `alert` +/
|
||||
alias a = alert;
|
||||
/++ Alias for `critical` +/
|
||||
alias c = critical;
|
||||
/++ Alias for `error` +/
|
||||
alias e = error;
|
||||
/++ Alias for `warning` +/
|
||||
alias w = warning;
|
||||
/++ Alias for `notice` +/
|
||||
alias n = notice;
|
||||
/++ Alias for `information` +/
|
||||
alias i = information;
|
||||
|
||||
/++
|
||||
Example:
|
||||
---
|
||||
log.level(log.level.d); // Sets level to DEBUGGING
|
||||
log.d("Debug message"); // Visible
|
||||
---
|
||||
+/
|
||||
}
|
||||
|
||||
/++
|
||||
Helper method to start level configuration.
|
||||
|
||||
Returns:
|
||||
A `Level` struct for chaining level methods.
|
||||
|
||||
Example:
|
||||
---
|
||||
log.level(log.level().warning); // Sets level to WARNING
|
||||
log.i("This won't show"); // Ignored due to level
|
||||
log.w("This will show");
|
||||
---
|
||||
+/
|
||||
Level level() { return Level(); }
|
||||
|
||||
/++
|
||||
Struct for temporary output override.
|
||||
|
||||
Provides methods to log messages with temporary output settings.
|
||||
+/
|
||||
struct Now {
|
||||
private Log _log;
|
||||
|
||||
this(Log log) { _log = log; }
|
||||
|
||||
/++
|
||||
Logs an alert message.
|
||||
|
||||
Example:
|
||||
---
|
||||
log.now(log.output.std).alert("Temp alert"); // Only to console
|
||||
---
|
||||
+/
|
||||
void alert(T)(T message) { _log.alert(message); }
|
||||
|
||||
/++
|
||||
Logs a critical error message.
|
||||
|
||||
Example:
|
||||
---
|
||||
log.now(log.output.file).c("Temp critical"); // Only to file
|
||||
---
|
||||
+/
|
||||
void critical(T)(T message) { _log.critical(message); }
|
||||
|
||||
/++
|
||||
Logs an error message.
|
||||
|
||||
Example:
|
||||
---
|
||||
log.now(log.output.std).e("Temp error"); // Only to stderr
|
||||
---
|
||||
+/
|
||||
void error(T)(T message) { _log.error(message); }
|
||||
|
||||
/++
|
||||
Logs a warning message.
|
||||
|
||||
Example:
|
||||
---
|
||||
log.now(log.output.syslog).w("Temp warning"); // Only to syslog
|
||||
---
|
||||
+/
|
||||
void warning(T)(T message) { _log.warning(message); }
|
||||
|
||||
/++
|
||||
Logs a notice message.
|
||||
|
||||
Example:
|
||||
---
|
||||
log.now(log.output.std).n("Temp notice"); // Only to stdout
|
||||
---
|
||||
+/
|
||||
void notice(T)(T message) { _log.notice(message); }
|
||||
|
||||
/++
|
||||
Logs an informational message.
|
||||
|
||||
Example:
|
||||
---
|
||||
log.now(log.output.file).i("Temp info"); // Only to file
|
||||
---
|
||||
+/
|
||||
void information(T)(T message) { _log.information(message); }
|
||||
|
||||
/++
|
||||
Logs a debugging message.
|
||||
|
||||
Example:
|
||||
---
|
||||
log.now(log.output.std).d("Temp debug"); // Only to stdout
|
||||
---
|
||||
+/
|
||||
void debugging(T)(T message) { _log.debugging(message); }
|
||||
|
||||
/++ Alias for `alert` +/
|
||||
alias a = alert;
|
||||
/++ Alias for `critical` +/
|
||||
alias c = critical;
|
||||
/++ Alias for `error` +/
|
||||
alias e = error;
|
||||
/++ Alias for `warning` +/
|
||||
alias w = warning;
|
||||
/++ Alias for `notice` +/
|
||||
alias n = notice;
|
||||
/++ Alias for `information` +/
|
||||
alias i = information;
|
||||
/++ Alias for `debugging` +/
|
||||
alias d = debugging;
|
||||
}
|
||||
}
|
||||
|
||||
/++
|
||||
Global alias for easy access to the logger instance.
|
||||
|
||||
The `log` alias provides a convenient shortcut to the singleton instance of the `Log` class,
|
||||
allowing direct access to all logging functionality without explicitly calling `Log.msg`.
|
||||
It supports the same methods, configuration options, and features as the `Log` class.
|
||||
|
||||
Example:
|
||||
---
|
||||
import singlog;
|
||||
|
||||
void main() {
|
||||
// Configure the logger using the alias
|
||||
log.program("MyApp")
|
||||
.color(true)
|
||||
.level(log.level.debugging) // Using log.level directly
|
||||
.output(log.output.std.file.syslog)
|
||||
.file("myapp.log");
|
||||
|
||||
// Log messages with full method names
|
||||
log.debugging("App starting in debug mode");
|
||||
log.information("Initialization complete");
|
||||
log.error("Failed to load resource");
|
||||
|
||||
// Log messages with aliases
|
||||
log.d("Debug message via alias");
|
||||
log.i("Info message via alias");
|
||||
log.e("Error message via alias");
|
||||
|
||||
// Temporary output override
|
||||
log.now(log.output.std).n("Temporary console-only message");
|
||||
}
|
||||
---
|
||||
+/
|
||||
alias log = Log.msg;
|
||||
|
|
|
|||
BIN
tests/cmd.png
BIN
tests/cmd.png
Binary file not shown.
|
Before Width: | Height: | Size: 35 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 153 KiB |
60
tests/test.d
60
tests/test.d
|
|
@ -1,60 +0,0 @@
|
|||
import singlog;
|
||||
import std.format : format;
|
||||
import std.exception : enforce;
|
||||
|
||||
/++
|
||||
Logging Levels Table:
|
||||
Level | Value | Description
|
||||
--------------|----------|---------
|
||||
DEBUGGING | 0 | Debugging information (highest)
|
||||
ALERT | 1 | Urgent alerts
|
||||
CRITICAL | 2 | Critical errors
|
||||
ERROR | 3 | Errors
|
||||
WARNING | 4 | Warnings
|
||||
NOTICE | 5 | Notices
|
||||
INFORMATION | 6 | Informational messages (lowest)
|
||||
+/
|
||||
void main(string[] argv) {
|
||||
// Logger configuration
|
||||
log.color(true) // Enable colored output
|
||||
.level(log.level.error) // Threshold ERROR (3): shows ERROR and less critical (≥3)
|
||||
.output(log.output.std.file.syslog) // Set all three output targets
|
||||
.file("./test.log") // Set log file
|
||||
.program(argv[0]); // Set program name (Windows only)
|
||||
|
||||
// Application start
|
||||
log.i("ChainDemo application started"); // INFO (6) >= 3
|
||||
log.e("Logging with ERROR level activated"); // ERROR (3) >= 3
|
||||
|
||||
// Level demonstration
|
||||
log.e("Error during operation"); // ERROR (3) >= 3
|
||||
log.w("Warning"); // WARNING (4) >= 3
|
||||
log.n("Important notice"); // NOTICE (5) >= 3
|
||||
log.d("Debugging not shown"); // DEBUGGING (0) < 3
|
||||
log.i("General information"); // INFO (6) >= 3
|
||||
log.a("Alert not shown"); // ALERT (1) < 3
|
||||
|
||||
// Example with data types
|
||||
int errorCode = 500;
|
||||
log.e("Server error %d".format(errorCode)); // ERROR (3) >= 3
|
||||
|
||||
// Temporary output redirection
|
||||
log.now(log.output.std).e("Error only to console"); // ERROR (3) >= 3
|
||||
|
||||
// Exception handling
|
||||
try {
|
||||
enforce(false, "Test exception");
|
||||
} catch (Exception e) {
|
||||
log.e("Exception: %s".format(e.msg)); // ERROR (3) >= 3
|
||||
}
|
||||
|
||||
// Configuration change
|
||||
log.color(true)
|
||||
.level(log.level.alert) // Threshold CRITICAL (2): shows CRITICAL and less critical (≥2)
|
||||
.output(log.output.std.file);
|
||||
log.e("This message will be shown (ERROR >= CRITICAL)"); // ERROR (3) >= 2
|
||||
log.a("Configuration changed, ALERT messages"); // ALERT (1) >= 2
|
||||
|
||||
// Finale
|
||||
log.c("Demonstration completed"); // CRITICAL (2) >= 2
|
||||
}
|
||||
Loading…
Reference in New Issue