v0.5.0
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
This commit is contained in:
parent
f9b4718549
commit
cf3fc66af8
13
CHANGELOG.md
13
CHANGELOG.md
|
@ -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
|
||||||
|
|
43
README.md
43
README.md
|
@ -15,11 +15,11 @@ 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
|
||||||
|
|
||||||
log.i("This is an information message");
|
log.i("This is an information message");
|
||||||
log.n("This is a notice message");
|
log.n("This is a notice message");
|
||||||
|
@ -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"`.
|
||||||
|
|
175
source/singlog.d
175
source/singlog.d
|
@ -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;
|
||||||
SetConsoleTextAttribute(handle, this._color[priority] | FOREGROUND_INTENSITY);
|
wstring wType = this._type[priority].to!wstring;
|
||||||
write(this._type[priority]);
|
wstring wMessage = " %s\n".format(message).to!wstring;
|
||||||
SetConsoleTextAttribute(handle, this._color[priority]);
|
|
||||||
WriteConsoleW(handle, message.ptr, cast(DWORD)message.length, NULL, NULL);
|
switch (GetFileType(handle)) {
|
||||||
SetConsoleTextAttribute(handle, defaultConsole.wAttributes);
|
case FILE_TYPE_CHAR:
|
||||||
|
WriteConsoleW(handle, wTime.ptr, cast(DWORD)wTime.length, NULL, NULL);
|
||||||
|
SetConsoleTextAttribute(handle, this._color[priority] | FOREGROUND_INTENSITY);
|
||||||
|
WriteConsoleW(handle, wType.ptr, cast(DWORD)wType.length, NULL, NULL);
|
||||||
|
SetConsoleTextAttribute(handle, this._color[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]]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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; }
|
||||||
|
|
BIN
tests/cmd.png
BIN
tests/cmd.png
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 |
13
tests/test.d
13
tests/test.d
|
@ -1,11 +1,11 @@
|
||||||
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
|
||||||
|
|
||||||
log.i("This is an information message");
|
log.i("This is an information message");
|
||||||
log.n("This is a notice message");
|
log.n("This is a notice message");
|
||||||
|
@ -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");
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue