Compare commits

..

No commits in common. "e019422dd199d744e04b9458eeaa6ad80f88253e" and "5dd910b683c701d3d3590de799996aef35d8558e" have entirely different histories.

8 changed files with 80 additions and 179 deletions

View File

@ -1,17 +1,5 @@
# Changelog # Changelog
## [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
### 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/))
## [v0.3.2](https://git.zhirov.kz/dlang/singlog/compare/v0.3.1...v0.3.2) (2023.06.01) ## [v0.3.2](https://git.zhirov.kz/dlang/singlog/compare/v0.3.1...v0.3.2) (2023.06.01)
- Printing information about the type of the logged message to the standard output stream and file - Printing information about the type of the logged message to the standard output stream and file

View File

@ -16,37 +16,25 @@ 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.SYSLOG | log.STDOUT | log.FILE) // write to syslog, standard output stream and file
.program(argv[0]) // program name as an identifier (for Windows OS) .name(argv[0]) // program name as an identifier (for Windows OS)
.level(log.DEBUGGING) // logging level .level(log.DEBUGGING) // logging level
.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.n("This is a notice message");
log.w("This is a warning message");
log.e("This is an error message"); log.e("This is an error message");
log.c("This is a critical message"); log.error("And this is also an error message");
log.a("This is an alert message"); log.w("This is a warning message");
log.d("This is a debug message"); log.i("This is an information message");
} }
``` ```
![output](tests/terminal.png) ![output](tests/output.png)
![output](tests/cmd.png)
## Examples ## Examples
Setting the name of the logged program (it matters for Windows OS): Setting the name of the logged program (it matters for Windows OS):
```d ```d
log.program("My program"); log.name("My program");
```
Setting the status of color text output (`false` by default):
```d
log.color(true);
``` ```
Setting the error output level: Setting the error output level:
@ -89,4 +77,4 @@ log.d("Debugging message") => log.debugging("Debugging message");
## DUB ## DUB
Add a dependency on `"singlog": "~>0.4.0"`. Add a dependency on `"singlog": "~>0.3.2"`.

View File

@ -18,7 +18,7 @@
"name": "test", "name": "test",
"targetType": "executable", "targetType": "executable",
"targetPath": "bin", "targetPath": "bin",
"targetName": "test", "targetName": "app",
"importPaths": ["source","tests"], "importPaths": ["source","tests"],
"sourcePaths": ["tests"] "sourcePaths": ["tests"]
} }

View File

@ -2,7 +2,7 @@ module singlog;
version(Windows) version(Windows)
import core.sys.windows.windows; import core.sys.windows.windows;
else version(Posix) else
import core.sys.posix.syslog; import core.sys.posix.syslog;
import std.string; import std.string;
@ -19,9 +19,7 @@ alias log = Log.msg;
--- ---
// Setting the name of the logged program // Setting the name of the logged program
log.program("My program"); log.name("My program");
// Setting the status of color text output
log.color(true);
// Setting the error output level // Setting the error output level
log.level(log.DEBUGGING); log.level(log.DEBUGGING);
log.level(log.ALERT); log.level(log.ALERT);
@ -48,107 +46,40 @@ alias log = Log.msg;
+/ +/
class Log { class Log {
private: private:
static Log _log; static Log log;
string _path; string path;
wstring _name = "singlog"; string nameProgram = "singlog";
bool _writeToFile = true; bool writeToFile = true;
bool _ccolor = false;
this() {} this() {}
version(Windows) { version(Windows) {
int[] _sysPriority = [0, 1, 1, 1, 2, 3, 3]; public enum {
DEBUGGING = 0,
WORD[] _sysPriorityOS = [ ALERT = 1,
CRITICAL = 1,
ERROR = 1,
WARNING = 2,
NOTICE = 3,
INFORMATION = 3,
}
WORD[] sysLevel = [
EVENTLOG_SUCCESS, EVENTLOG_SUCCESS,
EVENTLOG_ERROR_TYPE, EVENTLOG_ERROR_TYPE,
EVENTLOG_WARNING_TYPE, EVENTLOG_WARNING_TYPE,
EVENTLOG_INFORMATION_TYPE EVENTLOG_INFORMATION_TYPE
]; ];
void writesyslog(string message, WORD priority) { void syslog(WORD priority, LPCSTR message) {
import std.utf: toUTF16z; HANDLE handleEventLog = RegisterEventSourceA(NULL, this.nameProgram.toStringz());
auto wMessage = message.toUTF16z();
HANDLE handleEventLog = RegisterEventSourceW(NULL, this._name.ptr);
if (handleEventLog == NULL) if (handleEventLog == NULL)
return; return;
ReportEventW(handleEventLog, priority, 0, 0, NULL, 1, 0, &wMessage, NULL); ReportEventA(handleEventLog, priority, 0, 0, NULL, 1, 0, &message, NULL);
DeregisterEventSource(handleEventLog); DeregisterEventSource(handleEventLog);
} }
WORD[] _color = [
FOREGROUND_GREEN, // green
FOREGROUND_BLUE, // blue
FOREGROUND_RED | FOREGROUND_BLUE, // magenta
FOREGROUND_RED, // red
FOREGROUND_RED | FOREGROUND_GREEN, // yellow
FOREGROUND_BLUE | FOREGROUND_GREEN, // cyan
FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_GREEN // white
];
void colorTextOutput(string time, wstring message, int priority) {
HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
CONSOLE_SCREEN_BUFFER_INFO defaultConsole;
GetConsoleScreenBufferInfo(handle, &defaultConsole);
writef("%s ", time);
SetConsoleTextAttribute(handle, this._color[priority] | FOREGROUND_INTENSITY);
write(this._type[priority]);
SetConsoleTextAttribute(handle, this._color[priority]);
WriteConsoleW(handle, message.ptr, cast(DWORD)message.length, NULL, NULL);
SetConsoleTextAttribute(handle, defaultConsole.wAttributes);
}
void defaultTextOutput(string time, wstring message, int priority) {
HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
writef("%s %s", time, this._type[priority]);
WriteConsoleW(handle, message.ptr, cast(DWORD)message.length, NULL, NULL);
}
void writestdout(string time, string message, int priority) {
wstring wMessage = " %s\n".format(message).to!wstring;
this._ccolor ?
colorTextOutput(time, wMessage, priority) :
defaultTextOutput(time, wMessage, priority);
}
} else version(Posix) { } else version(Posix) {
int[] _sysPriority = [0, 1, 2, 3, 4, 5, 6];
int[] _sysPriorityOS = [
LOG_DEBUG,
LOG_ALERT,
LOG_CRIT,
LOG_ERR,
LOG_WARNING,
LOG_NOTICE,
LOG_INFO
];
string[] _color = [
"\x1b[1;32m%s\x1b[0;32m %s\x1b[0;0m", // green
"\x1b[1;34m%s\x1b[0;34m %s\x1b[0;0m", // blue
"\x1b[1;35m%s\x1b[0;35m %s\x1b[0;0m", // magenta
"\x1b[1;31m%s\x1b[0;31m %s\x1b[0;0m", // red
"\x1b[1;33m%s\x1b[0;33m %s\x1b[0;0m", // yellow
"\x1b[1;36m%s\x1b[0;36m %s\x1b[0;0m", // cyan
"\x1b[1;97m%s\x1b[0;97m %s\x1b[0;0m", // white
];
void writestdout(string time, string message, int priority) {
writefln("%s %s",
time,
(this._ccolor ? this._color[priority] : "%s %s").format(this._type[priority], message)
);
}
void writesyslog(string message, int priority) {
syslog(priority, message.toStringz());
}
}
public enum { public enum {
DEBUGGING = 0, DEBUGGING = 0,
ALERT = 1, ALERT = 1,
@ -158,16 +89,16 @@ version(Windows) {
NOTICE = 5, NOTICE = 5,
INFORMATION = 6 INFORMATION = 6
} }
int[] sysLevel = [
string[] _type = [ LOG_DEBUG,
"[DEBUG]:", LOG_ALERT,
"[ALERT]:", LOG_CRIT,
"[CRITICAL]:", LOG_ERR,
"[ERROR]:", LOG_WARNING,
"[WARNING]:", LOG_NOTICE,
"[NOTICE]:", LOG_INFO
"[INFO]:"
]; ];
}
public enum { public enum {
SYSLOG = 1, SYSLOG = 1,
@ -175,49 +106,48 @@ version(Windows) {
FILE = 4 FILE = 4
} }
int _output = STDOUT; int msgOutput = STDOUT;
int _priority = INFORMATION; int msgLevel = INFORMATION;
void writelog(string message, int priority) { void writeLog(string message, string type, int msgLevel) {
string time; if (this.msgLevel > msgLevel)
if (this._priority > priority)
return; return;
if (this._output & 1) if (this.msgOutput & 1)
writesyslog(message, _sysPriorityOS[_sysPriority[priority]]); syslog(sysLevel[msgLevel], message.toStringz());
if (this._output & 6) if (this.msgOutput & 6)
time = Clock.currTime().format("%Y.%m.%d %H:%M:%S"); message = format("%s [%s]: %s", Clock.currTime().format("%Y.%m.%d %H:%M:%S"), type, message);
if (this._output & 2) if (this.msgOutput & 2)
writestdout(time, message, priority); writeln(message);
if (this._output & 4) if (this.msgOutput & 4)
writefile(time, message, priority); writeFile(message);
} }
void writefile(string time, string message, int priority) { void writeFile(string message) {
if (!this._writeToFile) if (!this.writeToFile)
return; return;
if (!this._path.exists) { if (!this.path.exists) {
this._writeToFile = false; this.writeToFile = false;
this.warning("The log file does not exist: " ~ this._path); this.warning("The log file does not exist: " ~ this.path);
} }
File file; File file;
try { try {
file = File(this._path, "a+"); file = File(this.path, "a+");
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.error("Unable to open the log file " ~ this.path);
this.information(e); this.information(e);
return; return;
} }
try { try {
file.writefln("%s %s %s", time, this._type[priority], message); file.writeln(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.error("Unable to write to the log file " ~ this.path);
this.information(e); this.information(e);
return; return;
} }
@ -225,8 +155,8 @@ version(Windows) {
try { try {
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.error("Unable to close the log file " ~ this.path);
this.information(e); this.information(e);
return; return;
} }
@ -234,25 +164,24 @@ version(Windows) {
public: public:
@property static Log msg() { @property static Log msg() {
if (this._log is null) if (this.log is null)
this._log = new Log; this.log = new Log;
return this._log; return this.log;
} }
Log output(int outs) { this._output = outs; return this._log; } Log output(int msgOutput) { this.msgOutput = msgOutput; return this.log; }
Log program(string name) { this._name = name.to!wstring; return this._log; } Log name(string nameProgram) { this.nameProgram = nameProgram; return this.log; }
Log file(string path) { this._path = path; return this._log; } Log file(string path) { this.path = path; return this.log; }
Log level(int priority) { this._priority = priority; return this._log; } Log level(int msgLevel) { this.msgLevel = msgLevel; return this.log; }
Log color(bool condition) { this._ccolor = condition; return this._log; }
void alert(T)(T message) { writelog(message.to!string, ALERT); } void alert(T)(T message) { writeLog(message.to!string, "ALERT", ALERT); }
void critical(T)(T message) { writelog(message.to!string, CRITICAL); } void critical(T)(T message) { writeLog(message.to!string, "CRITICAL", CRITICAL); }
void error(T)(T message) { writelog(message.to!string, ERROR); } void error(T)(T message) { writeLog(message.to!string, "ERROR", ERROR); }
void warning(T)(T message) { writelog(message.to!string, WARNING); } void warning(T)(T message) { writeLog(message.to!string, "WARNING", WARNING); }
void notice(T)(T message) { writelog(message.to!string, NOTICE); } void notice(T)(T message) { writeLog(message.to!string, "NOTICE", NOTICE); }
void information(T)(T message) { writelog(message.to!string, INFORMATION); } void information(T)(T message) { writeLog(message.to!string, "INFORMATION", INFORMATION); }
void debugging(T)(T message) { writelog(message.to!string, DEBUGGING); } void debugging(T)(T message) { writeLog(message.to!string, "DEBUGGING", DEBUGGING); }
alias a = alert; alias a = alert;
alias c = critical; alias c = critical;

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

BIN
tests/output.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 51 KiB

View File

@ -2,16 +2,12 @@ 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.SYSLOG | log.STDOUT | log.FILE) // write to syslog, standard output stream and file
.program(argv[0]) // program name as an identifier (for Windows OS) .name(argv[0]) // program name as an identifier (for Windows OS)
.level(log.DEBUGGING) // logging level .level(log.DEBUGGING) // logging level
.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.n("This is a notice message");
log.w("This is a warning message");
log.e("This is an error message"); log.e("This is an error message");
log.c("This is a critical message"); log.error("And this is also an error message");
log.a("This is an alert message"); log.w("This is a warning message");
log.d("This is a debug message"); log.i("This is an information message");
} }