0.5.0-dev

This commit is contained in:
Alexander Zhirov 2023-07-18 21:01:43 +03:00 committed by Alexander Zhirov
parent f9b4718549
commit 067fc6acc6
6 changed files with 185 additions and 59 deletions

View File

@ -1,5 +1,18 @@
# Changelog # Changelog
## [v0.5.0](https://git.zhirov.kz/dlang/singlog/compare/v0.4.0...v0.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
## [v0.4.0](https://git.zhirov.kz/dlang/singlog/compare/v0.3.2...v0.4.0) (2023.06.07) ## [v0.4.0](https://git.zhirov.kz/dlang/singlog/compare/v0.3.2...v0.4.0) (2023.06.07)
- Part of the code has been changed/rewritten - Part of the code has been changed/rewritten

View File

@ -15,9 +15,9 @@ Singleton for simple logging
import singlog; import singlog;
void main(string[] argv) { void main(string[] argv) {
log.output(log.SYSLOG | log.STDOUT | log.FILE) // write to syslog, standard output stream and file log.output(log.output.syslog.stderr.stdout.file) // write to syslog, standard error/output streams and file
.program(argv[0]) // program name as an identifier (for Windows OS) .program(argv[0]) // program name as an identifier (for Windows OS)
.level(log.DEBUGGING) // logging level .level(log.level.debugging) // logging level
.color(true) // color text output .color(true) // color text output
.file("./test.log"); // the path to the log file .file("./test.log"); // the path to the log file
@ -28,6 +28,9 @@ void main(string[] argv) {
log.c("This is a critical message"); log.c("This is a critical message");
log.a("This is an alert message"); log.a("This is an alert message");
log.d("This is a debug message"); log.d("This is a debug message");
log.now(log.output.stdout).n("This error message will only be written to the standard output stream");
log.now(log.output.syslog.file).c("This error message will only be written to the syslog and file");
} }
``` ```
@ -52,30 +55,29 @@ log.color(true);
Setting the error output level: Setting the error output level:
```d ```d
log.level(log.DEBUGGING); log.level(log.level.debugging);
log.level(log.ALERT); log.level(log.level.alert);
log.level(log.CRITICAL); log.level(log.level.critical);
log.level(log.ERROR); log.level(log.level.error);
log.level(log.WARNING); log.level(log.level.warning);
log.level(log.NOTICE); log.level(log.level.notice);
log.level(log.INFORMATION); log.level(log.level.information);
``` ```
Assigning a target output: Assigning a target output:
```d ```d
log.output(log.SYSLOG); log.output(log.output.syslog.stderr.stdout);
log.output(log.STDOUT);
``` ```
Setup and allowing writing to a file: Setup and allowing writing to a file:
```d ```d
log.output(log.FILE); log.output(log.output.file);
log.file("./file.log"); log.file("./file.log");
``` ```
Output of messages to the log: Write messages to the log:
```d ```d
log.a("Alert message") => log.alert("Alert message"); log.a("Alert message") => log.alert("Alert message");
@ -87,6 +89,13 @@ log.i("Information message") => log.information("Information message");
log.d("Debugging message") => log.debugging("Debugging message"); log.d("Debugging message") => log.debugging("Debugging message");
``` ```
Write message to specific outputs:
```d
log.now(log.output.stdout).n("This error message will only be written to the standard output stream");
log.now(log.output.syslog.file).c("This error message will only be written to the syslog and file");
```
## DUB ## DUB
Add a dependency on `"singlog": "~>0.4.0"`. Add a dependency on `"singlog": "~>0.5.0"`.

View File

@ -1,8 +1,9 @@
module singlog; module singlog;
version(Windows) version(Windows) {
import core.sys.windows.windows; import core.sys.windows.windows;
else version(Posix) import std.utf : toUTF8, toUTF16z;
} else version(Posix)
import core.sys.posix.syslog; import core.sys.posix.syslog;
import std.string; import std.string;
@ -23,17 +24,15 @@ alias log = Log.msg;
// Setting the status of color text output // Setting the status of color text output
log.color(true); log.color(true);
// Setting the error output level // Setting the error output level
log.level(log.DEBUGGING); log.level(log.level.debugging);
log.level(log.ALERT); log.level(log.level.alert);
log.level(log.CRITICAL); log.level(log.level.critical);
log.level(log.ERROR); log.level(log.level.error);
log.level(log.WARNING); log.level(log.level.warning);
log.level(log.NOTICE); log.level(log.level.notice);
log.level(log.INFORMATION); log.level(log.level.information);
// Assigning a target output // Assigning a target output
log.output(log.SYSLOG); log.output(log.output.syslog.stderr.stdout.file);
log.output(log.STDOUT);
log.output(log.FILE);
// Setup and allowing writing to a file // Setup and allowing writing to a file
log.file("./file.log"); log.file("./file.log");
// Output of messages to the log // Output of messages to the log
@ -44,6 +43,8 @@ alias log = Log.msg;
log.warning("Warning message"); log.warning("Warning message");
log.notice("Notice message"); log.notice("Notice message");
log.informations("Information message"); log.informations("Information message");
// Write message to specific outputs
log.now(log.output.stdout.file).informations("Information message");
--- ---
+/ +/
class Log { class Log {
@ -67,7 +68,6 @@ version(Windows) {
]; ];
void writesyslog(string message, WORD priority) { void writesyslog(string message, WORD priority) {
import std.utf: toUTF16z;
auto wMessage = message.toUTF16z(); auto wMessage = message.toUTF16z();
HANDLE handleEventLog = RegisterEventSourceW(NULL, this._name.ptr); HANDLE handleEventLog = RegisterEventSourceW(NULL, this._name.ptr);
@ -88,30 +88,59 @@ version(Windows) {
FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_GREEN // white FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_GREEN // white
]; ];
void colorTextOutput(string time, wstring message, int priority) { void colorTextOutput(HANDLE handle, string time, string message, int priority) {
HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
CONSOLE_SCREEN_BUFFER_INFO defaultConsole; CONSOLE_SCREEN_BUFFER_INFO defaultConsole;
GetConsoleScreenBufferInfo(handle, &defaultConsole); GetConsoleScreenBufferInfo(handle, &defaultConsole);
writef("%s ", time); wstring wTime = "%s ".format(time).to!wstring;
wstring wType = this._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, this._color[priority] | FOREGROUND_INTENSITY); SetConsoleTextAttribute(handle, this._color[priority] | FOREGROUND_INTENSITY);
write(this._type[priority]); WriteConsoleW(handle, wType.ptr, cast(DWORD)wType.length, NULL, NULL);
SetConsoleTextAttribute(handle, this._color[priority]); SetConsoleTextAttribute(handle, this._color[priority]);
WriteConsoleW(handle, message.ptr, cast(DWORD)message.length, NULL, NULL); WriteConsoleW(handle, wMessage.ptr, cast(DWORD)wMessage.length, NULL, NULL);
SetConsoleTextAttribute(handle, defaultConsole.wAttributes); 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]]);
}
} }
void defaultTextOutput(string time, wstring message, int priority) { void defaultTextOutput(HANDLE handle, string time, string message, int priority) {
HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE); wstring wMessage = "%s %s %s\n".format(time, this._type[priority], message).to!wstring;
writef("%s %s", time, this._type[priority]); switch (GetFileType(handle)) {
WriteConsoleW(handle, message.ptr, cast(DWORD)message.length, NULL, NULL); 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 writestdout(string time, string message, int priority) { void writestdout(string time, string message, int priority) {
wstring wMessage = " %s\n".format(message).to!wstring; HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
this._ccolor ? this._ccolor ?
colorTextOutput(time, wMessage, priority) : colorTextOutput(handle, time, message, priority) :
defaultTextOutput(time, wMessage, priority); defaultTextOutput(handle, time, message, priority);
}
void writestderr(string time, string message, int priority) {
HANDLE handle = GetStdHandle(STD_ERROR_HANDLE);
this._ccolor ?
colorTextOutput(handle, time, message, priority) :
defaultTextOutput(handle, time, message, priority);
} }
} else version(Posix) { } else version(Posix) {
@ -144,6 +173,13 @@ version(Windows) {
); );
} }
void writestderr(string time, string message, int priority) {
stderr.writefln("%s %s",
time,
(this._ccolor ? this._color[priority] : "%s %s").format(this._type[priority], message)
);
}
void writesyslog(string message, int priority) { void writesyslog(string message, int priority) {
syslog(priority, message.toStringz()); syslog(priority, message.toStringz());
} }
@ -172,23 +208,29 @@ version(Windows) {
public enum { public enum {
SYSLOG = 1, SYSLOG = 1,
STDOUT = 2, STDOUT = 2,
FILE = 4 STDERR = 4,
FILE = 8
} }
int _nowoutput = 0;
int _output = STDOUT; int _output = STDOUT;
int _priority = INFORMATION; int _priority = INFORMATION;
void writelog(string message, int priority) { void writelog(string message, int priority) {
string time; string time;
int output = this._nowoutput ? this._nowoutput : this._output;
this._nowoutput = 0;
if (this._priority > priority) if (this._priority > priority)
return; return;
if (this._output & 1) if (output & 1)
writesyslog(message, _sysPriorityOS[_sysPriority[priority]]); writesyslog(message, _sysPriorityOS[_sysPriority[priority]]);
if (this._output & 6) if (output & 14)
time = Clock.currTime().format("%Y.%m.%d %H:%M:%S"); time = Clock.currTime().format("%Y.%m.%d %H:%M:%S");
if (this._output & 2) if (output & 2 && priority >= WARNING)
writestdout(time, message, priority); writestdout(time, message, priority);
if (this._output & 4) if (output & 4 && priority <= ERROR)
writestderr(time, message, priority);
if (output & 8)
writefile(time, message, priority); writefile(time, message, priority);
} }
@ -208,7 +250,7 @@ version(Windows) {
this._writeToFile = true; this._writeToFile = true;
} catch (Exception e) { } catch (Exception e) {
this._writeToFile = false; this._writeToFile = false;
this.error("Unable to open the log file " ~ this._path); this.now(output.stderr).error("Unable to open the log file " ~ this._path);
this.information(e); this.information(e);
return; return;
} }
@ -217,7 +259,7 @@ version(Windows) {
file.writefln("%s %s %s", time, this._type[priority], message); file.writefln("%s %s %s", time, this._type[priority], message);
} catch (Exception e) { } catch (Exception e) {
this._writeToFile = false; this._writeToFile = false;
this.error("Unable to write to the log file " ~ this._path); this.now(output.stderr).error("Unable to write to the log file " ~ this._path);
this.information(e); this.information(e);
return; return;
} }
@ -226,12 +268,65 @@ version(Windows) {
file.close(); file.close();
} catch (Exception e) { } catch (Exception e) {
this._writeToFile = false; this._writeToFile = false;
this.error("Unable to close the log file " ~ this._path); this.now(output.stderr).error("Unable to close the log file " ~ this._path);
this.information(e); this.information(e);
return; return;
} }
} }
struct Output {
int _output = STDOUT;
int _newoutput = 0;
int output() { return this._newoutput ? this._newoutput : this._output; }
public:
Output syslog() { this._newoutput |= SYSLOG; return this; }
Output stdout() { this._newoutput |= STDOUT; return this; }
Output stderr() { this._newoutput |= STDERR; return this; }
Output file() { this._newoutput |= FILE; return this; }
}
struct Level {
public:
int debugging() { return DEBUGGING; }
int alert() { return ALERT; }
int critical() { return CRITICAL; }
int error() { return ERROR; }
int warning() { return WARNING; }
int notice() { return NOTICE; }
int information() { return INFORMATION; }
alias d = debugging;
alias a = alert;
alias c = critical;
alias e = error;
alias w = warning;
alias n = notice;
alias i = information;
}
struct Now {
this(Output outs) {
_log._nowoutput = outs.output();
}
public:
void alert(T)(T message) { _log.alert(message); }
void critical(T)(T message) { _log.critical(message); }
void error(T)(T message) { _log.error(message); }
void warning(T)(T message) { _log.warning(message); }
void notice(T)(T message) { _log.notice(message); }
void information(T)(T message) { _log.information(message); }
void debugging(T)(T message) { _log.debugging(message); }
alias a = alert;
alias c = critical;
alias e = error;
alias w = warning;
alias n = notice;
alias i = information;
alias d = debugging;
}
public: public:
@property static Log msg() { @property static Log msg() {
if (this._log is null) if (this._log is null)
@ -240,6 +335,12 @@ public:
return this._log; return this._log;
} }
Output output() { return Output(); }
Level level() { return Level(); }
Now now(Output outs) { return Now(outs); }
Log output(Output outs) { this._output = outs.output(); return this._log; }
deprecated("Use passing the argument as a `log.output.<outs>` object")
Log output(int outs) { this._output = outs; return this._log; } Log output(int outs) { this._output = outs; return this._log; }
Log program(string name) { this._name = name.to!wstring; return this._log; } Log program(string name) { this._name = name.to!wstring; return this._log; }
Log file(string path) { this._path = path; return this._log; } Log file(string path) { this._path = path; return this._log; }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 51 KiB

After

Width:  |  Height:  |  Size: 50 KiB

View File

@ -1,9 +1,9 @@
import singlog; import singlog;
void main(string[] argv) { void main(string[] argv) {
log.output(log.SYSLOG | log.STDOUT | log.FILE) // write to syslog, standard output stream and file log.output(log.output.syslog.stderr.stdout.file) // write to syslog, standard error/output streams and file
.program(argv[0]) // program name as an identifier (for Windows OS) .program(argv[0]) // program name as an identifier (for Windows OS)
.level(log.DEBUGGING) // logging level .level(log.level.debugging) // logging level
.color(true) // color text output .color(true) // color text output
.file("./test.log"); // the path to the log file .file("./test.log"); // the path to the log file
@ -14,4 +14,7 @@ void main(string[] argv) {
log.c("This is a critical message"); log.c("This is a critical message");
log.a("This is an alert message"); log.a("This is an alert message");
log.d("This is a debug message"); log.d("This is a debug message");
log.now(log.output.stdout).n("This error message will only be written to the standard output stream");
log.now(log.output.syslog.file).c("This error message will only be written to the syslog and file");
} }