From d07cab3560f34184ec96ce5b2734346acddab8c2 Mon Sep 17 00:00:00 2001 From: "Tristan B. Velloza Kildaire" Date: Tue, 9 Apr 2024 08:24:21 +0200 Subject: [PATCH 01/24] Core - Setting out new API --- source/dlog/nu/core.d | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 source/dlog/nu/core.d diff --git a/source/dlog/nu/core.d b/source/dlog/nu/core.d new file mode 100644 index 0000000..ddce1f6 --- /dev/null +++ b/source/dlog/nu/core.d @@ -0,0 +1,38 @@ +module dlog.nu.core; + +public class Message +{ + +} + +public interface Filter +{ + public bool filter(Message message); +} + +public interface MessageTransform +{ + public Message transform(Message message); +} + +public interface Handler +{ + public void handle(Message message); +} + +import std.container.slist : SList; +// import std.range : in; +import core.sync.mutex : Mutex; + +public abstract class Logger +{ + private SList!(MessageTransform) transforms; + private SList!(Filter) filters; + private SList!(Handler) handlers; + private Mutex lock; // Lock for attached handlers, filters and transforms + + this() + { + this.lock = new Mutex(); + } +} \ No newline at end of file From b6d002e7116f7813e1a9d77c0dc4542e3b413de6 Mon Sep 17 00:00:00 2001 From: "Tristan B. Velloza Kildaire" Date: Tue, 9 Apr 2024 08:24:34 +0200 Subject: [PATCH 02/24] Basic - Setting out use cases --- source/dlog/nu/basic.d | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 source/dlog/nu/basic.d diff --git a/source/dlog/nu/basic.d b/source/dlog/nu/basic.d new file mode 100644 index 0000000..e71962c --- /dev/null +++ b/source/dlog/nu/basic.d @@ -0,0 +1,39 @@ +module dlog.nu.basic; + +import dlog.nu.core; + +public class BasicMessage : Message +{ + private string text; + private Context ctx; + + public string getText() + { + return this.text; + } +} + +public class Context +{ + +} + +public class FileHandler : Handler +{ + import std.stdio : File; + private File file; + this(File file) + { + this.file = file; + } + + public void handle(Message message) + { + // Only handle BasicMessage(s) + BasicMessage bmesg = cast(BasicMessage)message; + if(bmesg) + { + file.writeln(bmesg.getText()); + } + } +} \ No newline at end of file From e35f6fba73ab72c9930934447cab8dd69e589d56 Mon Sep 17 00:00:00 2001 From: "Tristan B. Velloza Kildaire" Date: Tue, 9 Apr 2024 08:29:36 +0200 Subject: [PATCH 03/24] Core - Added methods for manipulating transforms --- source/dlog/nu/core.d | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/source/dlog/nu/core.d b/source/dlog/nu/core.d index ddce1f6..ef6f017 100644 --- a/source/dlog/nu/core.d +++ b/source/dlog/nu/core.d @@ -24,6 +24,16 @@ import std.container.slist : SList; // import std.range : in; import core.sync.mutex : Mutex; +// private mixin template Ting(Mutex lock) +// { +// scope(exit) +// { +// lock.unlock(); +// } + +// lock.lock(); +// } + public abstract class Logger { private SList!(MessageTransform) transforms; @@ -35,4 +45,30 @@ public abstract class Logger { this.lock = new Mutex(); } + + // TODO: Handle duplicate? + public final void addTransform(MessageTransform transform) + { + scope(exit) + { + this.lock.unlock(); + } + + this.lock.lock(); + + this.transforms.insertAfter(this.transforms[], transform); + } + + // TODO: Hanmdle not found explicitly? + public final void removeTransform(MessageTransform transform) + { + scope(exit) + { + this.lock.unlock(); + } + + this.lock.lock(); + + this.transforms.linearRemoveElement(transform); + } } \ No newline at end of file From f6ebb070ccd3ffb86a86399a5e48b6592332fe48 Mon Sep 17 00:00:00 2001 From: "Tristan B. Velloza Kildaire" Date: Tue, 9 Apr 2024 08:32:49 +0200 Subject: [PATCH 04/24] Logger - Implemented `log(Message message)` which does filtering, transformation and lastly handling --- source/dlog/nu/core.d | 42 ++++++++++++++++++++++++++++++++++++++---- 1 file changed, 38 insertions(+), 4 deletions(-) diff --git a/source/dlog/nu/core.d b/source/dlog/nu/core.d index ef6f017..5de7e90 100644 --- a/source/dlog/nu/core.d +++ b/source/dlog/nu/core.d @@ -10,7 +10,7 @@ public interface Filter public bool filter(Message message); } -public interface MessageTransform +public interface Transform { public Message transform(Message message); } @@ -36,7 +36,7 @@ import core.sync.mutex : Mutex; public abstract class Logger { - private SList!(MessageTransform) transforms; + private SList!(Transform) transforms; private SList!(Filter) filters; private SList!(Handler) handlers; private Mutex lock; // Lock for attached handlers, filters and transforms @@ -47,7 +47,7 @@ public abstract class Logger } // TODO: Handle duplicate? - public final void addTransform(MessageTransform transform) + public final void addTransform(Transform transform) { scope(exit) { @@ -60,7 +60,7 @@ public abstract class Logger } // TODO: Hanmdle not found explicitly? - public final void removeTransform(MessageTransform transform) + public final void removeTransform(Transform transform) { scope(exit) { @@ -71,4 +71,38 @@ public abstract class Logger this.transforms.linearRemoveElement(transform); } + + // Logs an actual message + // + // This first passes it over all filters + // then to a transform and then copies + // to each handler + public final void log(Message message) + { + scope(exit) + { + this.lock.unlock(); + } + + this.lock.lock(); + + foreach(Filter filter; this.filters) + { + if(!filter.filter(message)) + { + return; + } + } + + Message curMessage = message; + foreach(Transform transform; this.transforms) + { + curMessage = transform.transform(curMessage); + } + + foreach(Handler handler; this.handlers) + { + handler.handle(curMessage); + } + } } \ No newline at end of file From b13621fd82c437a27bbad60cb64d53a0a258e27a Mon Sep 17 00:00:00 2001 From: "Tristan B. Velloza Kildaire" Date: Tue, 9 Apr 2024 08:34:55 +0200 Subject: [PATCH 05/24] Logger - You can now add and remove filters and handlers --- source/dlog/nu/core.d | 52 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/source/dlog/nu/core.d b/source/dlog/nu/core.d index 5de7e90..e89f3bf 100644 --- a/source/dlog/nu/core.d +++ b/source/dlog/nu/core.d @@ -72,6 +72,58 @@ public abstract class Logger this.transforms.linearRemoveElement(transform); } + // TODO: Handle duplicate? + public final void addFilter(Filter filter) + { + scope(exit) + { + this.lock.unlock(); + } + + this.lock.lock(); + + this.filters.insertAfter(this.filters[], filter); + } + + // TODO: Hanmdle not found explicitly? + public final void removeFilter(Filter filter) + { + scope(exit) + { + this.lock.unlock(); + } + + this.lock.lock(); + + this.filters.linearRemoveElement(filter); + } + + // TODO: Handle duplicate? + public final void addHandler(Handler handler) + { + scope(exit) + { + this.lock.unlock(); + } + + this.lock.lock(); + + this.handlers.insertAfter(this.handlers[], handler); + } + + // TODO: Hanmdle not found explicitly? + public final void removeHandler(Handler handler) + { + scope(exit) + { + this.lock.unlock(); + } + + this.lock.lock(); + + this.handlers.linearRemoveElement(handler); + } + // Logs an actual message // // This first passes it over all filters From 2658ed20b54ada28be5b5990254fce94d2529466 Mon Sep 17 00:00:00 2001 From: "Tristan B. Velloza Kildaire" Date: Tue, 9 Apr 2024 08:41:08 +0200 Subject: [PATCH 06/24] BasicMessage - Now supports a `Level` setting Level - Added new enum type LevelFilter - Added implementation for level filtering --- source/dlog/nu/basic.d | 53 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 52 insertions(+), 1 deletion(-) diff --git a/source/dlog/nu/basic.d b/source/dlog/nu/basic.d index e71962c..92413a6 100644 --- a/source/dlog/nu/basic.d +++ b/source/dlog/nu/basic.d @@ -5,12 +5,23 @@ import dlog.nu.core; public class BasicMessage : Message { private string text; - private Context ctx; + private Level level; + + this(string text, Level level = Level.INFO) + { + this.text = text; + this.level = level; + } public string getText() { return this.text; } + + public Level getLevel() + { + return this.level; + } } public class Context @@ -36,4 +47,44 @@ public class FileHandler : Handler file.writeln(bmesg.getText()); } } +} + +public enum Level +{ + ERROR, + WARNING, + INFO, + DEBUG +} + +public class LevelFilter : Filter +{ + private Level curLevel; + + this() + { + + } + + public bool filter(Message message) + { + // Only handle BasicMessage(s) + BasicMessage bmesg = cast(BasicMessage)message; + if(bmesg) + { + return bmesg.getLevel() <= this.curLevel; + } + + return false; + } +} + +public class BasicLogger : Logger +{ + private Level level; + + this() + { + + } } \ No newline at end of file From 39c2fe78fd6d5a504ee86b438776b9f0621c1271 Mon Sep 17 00:00:00 2001 From: "Tristan B. Velloza Kildaire" Date: Tue, 9 Apr 2024 08:44:30 +0200 Subject: [PATCH 07/24] BasicLogger - Now stores current level in a filter of its own - The `LevelFilter` is attached to the `BasicLogger` on construction LevelFilter - Now use a `Level*` rather --- source/dlog/nu/basic.d | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/source/dlog/nu/basic.d b/source/dlog/nu/basic.d index 92413a6..df17d67 100644 --- a/source/dlog/nu/basic.d +++ b/source/dlog/nu/basic.d @@ -57,13 +57,13 @@ public enum Level DEBUG } -public class LevelFilter : Filter +private class LevelFilter : Filter { - private Level curLevel; + private Level* level; - this() + this(Level* level) { - + this.level = level; } public bool filter(Message message) @@ -72,7 +72,7 @@ public class LevelFilter : Filter BasicMessage bmesg = cast(BasicMessage)message; if(bmesg) { - return bmesg.getLevel() <= this.curLevel; + return bmesg.getLevel() <= *this.level; } return false; @@ -85,6 +85,14 @@ public class BasicLogger : Logger this() { + // Attach a new level-filter + // with access to our current + // level + addFilter(new LevelFilter(&level)); + } + public final void setLevel(Level level) + { + this.level = level; } } \ No newline at end of file From 5447f6dfbd36ba7c8c7c118c4bba861d45ae2353 Mon Sep 17 00:00:00 2001 From: "Tristan B. Velloza Kildaire" Date: Tue, 9 Apr 2024 08:46:29 +0200 Subject: [PATCH 08/24] ConsoleLogger - Added new logger --- source/dlog/nu/basic.d | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/source/dlog/nu/basic.d b/source/dlog/nu/basic.d index df17d67..e9314e9 100644 --- a/source/dlog/nu/basic.d +++ b/source/dlog/nu/basic.d @@ -95,4 +95,13 @@ public class BasicLogger : Logger { this.level = level; } +} + +public class ConsoleLogger : BasicLogger +{ + this() + { + import std.stdio; + addHandler(new FileHandler(stdout)); + } } \ No newline at end of file From fbada61e90729cb2a8f7818de4372de0aef55d22 Mon Sep 17 00:00:00 2001 From: "Tristan B. Velloza Kildaire" Date: Tue, 9 Apr 2024 08:47:43 +0200 Subject: [PATCH 09/24] BasicLogger - Added `getLevel()` --- source/dlog/nu/basic.d | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/source/dlog/nu/basic.d b/source/dlog/nu/basic.d index e9314e9..f9e167b 100644 --- a/source/dlog/nu/basic.d +++ b/source/dlog/nu/basic.d @@ -95,6 +95,11 @@ public class BasicLogger : Logger { this.level = level; } + + public final Level getLevel() + { + return this.level; + } } public class ConsoleLogger : BasicLogger From 6e48960022fb037009f6f7b3acafe39c4de04783 Mon Sep 17 00:00:00 2001 From: "Tristan B. Velloza Kildaire" Date: Tue, 9 Apr 2024 12:09:30 +0200 Subject: [PATCH 10/24] BasicMessage - Added `setText(string)` --- source/dlog/nu/basic.d | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/source/dlog/nu/basic.d b/source/dlog/nu/basic.d index f9e167b..1e92ade 100644 --- a/source/dlog/nu/basic.d +++ b/source/dlog/nu/basic.d @@ -13,6 +13,16 @@ public class BasicMessage : Message this.level = level; } + this() + { + + } + + public void setText(string text) + { + this.text = text; + } + public string getText() { return this.text; From 23d2b2ada91b077aa07d9ae8bba21d03f8107643 Mon Sep 17 00:00:00 2001 From: "Tristan B. Velloza Kildaire" Date: Tue, 9 Apr 2024 13:52:32 +0200 Subject: [PATCH 11/24] Core - Removed old code --- source/dlog/nu/core.d | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/source/dlog/nu/core.d b/source/dlog/nu/core.d index e89f3bf..c21b98d 100644 --- a/source/dlog/nu/core.d +++ b/source/dlog/nu/core.d @@ -24,16 +24,6 @@ import std.container.slist : SList; // import std.range : in; import core.sync.mutex : Mutex; -// private mixin template Ting(Mutex lock) -// { -// scope(exit) -// { -// lock.unlock(); -// } - -// lock.lock(); -// } - public abstract class Logger { private SList!(Transform) transforms; From 2f8b61fcf2f0289bde69a8f12e5b1fd7b3e71f88 Mon Sep 17 00:00:00 2001 From: "Tristan B. Velloza Kildaire" Date: Tue, 9 Apr 2024 14:28:33 +0200 Subject: [PATCH 12/24] BasicMessage - Added `setLevel(Level)` FileHandler - Only use `write(File, string)`, not `writeln(File, string)` --- source/dlog/nu/basic.d | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/source/dlog/nu/basic.d b/source/dlog/nu/basic.d index 1e92ade..77ab8e6 100644 --- a/source/dlog/nu/basic.d +++ b/source/dlog/nu/basic.d @@ -32,6 +32,11 @@ public class BasicMessage : Message { return this.level; } + + public void setLevel(Level level) + { + this.level = level; + } } public class Context @@ -54,7 +59,7 @@ public class FileHandler : Handler BasicMessage bmesg = cast(BasicMessage)message; if(bmesg) { - file.writeln(bmesg.getText()); + file.write(bmesg.getText()); } } } From 59ddf53efa7531a8c8d5230026455f0cb20f860a Mon Sep 17 00:00:00 2001 From: "Tristan B. Velloza Kildaire" Date: Tue, 9 Apr 2024 17:26:55 +0200 Subject: [PATCH 13/24] Major refactor - A lot of clean up --- source/dlog/{nu => }/basic.d | 24 +- source/dlog/context.d | 161 ----------- source/dlog/core.d | 535 ++++++++--------------------------- source/dlog/defaults.d | 212 ++++++++++++-- source/dlog/nu/core.d | 150 ---------- source/dlog/package.d | 4 +- source/dlog/transform.d | 52 ---- 7 files changed, 331 insertions(+), 807 deletions(-) rename source/dlog/{nu => }/basic.d (88%) delete mode 100644 source/dlog/context.d delete mode 100644 source/dlog/nu/core.d delete mode 100644 source/dlog/transform.d diff --git a/source/dlog/nu/basic.d b/source/dlog/basic.d similarity index 88% rename from source/dlog/nu/basic.d rename to source/dlog/basic.d index 77ab8e6..49fe6bc 100644 --- a/source/dlog/nu/basic.d +++ b/source/dlog/basic.d @@ -1,6 +1,6 @@ -module dlog.nu.basic; +module dlog.basic; -import dlog.nu.core; +import dlog.core; public class BasicMessage : Message { @@ -64,11 +64,29 @@ public class FileHandler : Handler } } +/** + * Logging level + */ public enum Level { + /** + * Error message + */ ERROR, - WARNING, + + /** + * Informative message + */ INFO, + + /** + * Warning message + */ + WARN, + + /** + * Debugging message + */ DEBUG } diff --git a/source/dlog/context.d b/source/dlog/context.d deleted file mode 100644 index 6e3a465..0000000 --- a/source/dlog/context.d +++ /dev/null @@ -1,161 +0,0 @@ -/** - * Context for logging - */ - -module dlog.context; - -import std.conv : to; - -/** - * Debugging trace level - */ -public enum Level -{ - /** - * Informative message - */ - INFO, - - /** - * Warning message - */ - WARN, - - /** - * Error message - */ - ERROR, - - /** - * Debugging message - */ - DEBUG -} - -/** - * Context that is passed in with the call to log - */ -public class Context -{ - private CompilationInfo lineInfo; - private Level level; - - /** - * Constructs a new Context - */ - this() - { - - } - - /** - * Set the line information - * - * Params: - * lineInfo = the CompilationInfo struct to use - */ - public final void setLineInfo(CompilationInfo lineInfo) - { - this.lineInfo = lineInfo; - } - - /** - * Obtain the line information generated at compilation - * time - * - * Returns: the CompilationInfo struct - */ - public final CompilationInfo getLineInfo() - { - return lineInfo; - } - - /** - * Returns the current tarce level - * - * Returns: the Level - */ - public final Level getLevel() - { - return level; - } - - /** - * Set the trace level - * - * Params: - * level = the Level to use - */ - public final void setLevel(Level level) - { - this.level = level; - } -} - -/** - * Information obtained during compilation time (if any) - */ -public struct CompilationInfo -{ - /** - * compile time usage file - */ - public string fullFilePath; - - /** - * compile time usage file (relative) - */ - public string file; - - /** - * compile time usage line number - */ - public ulong line; - - /** - * compile time usage module - */ - public string moduleName; - - /** - * compile time usage function - */ - public string functionName; - - /** - * compile time usage function (pretty) - */ - public string prettyFunctionName; - - /** - * Constructs the compilation information with the provided - * parameters - * - * Params: - * __FILE_FULL_PATH__ = compile time usage file - * __FILE__ = compile time usage file (relative) - * __LINE__ = compile time usage line number - * __MODULE__ = compile time usage module - * __FUNCTION__ = compile time usage function - * __PRETTY_FUNCTION__ = compile time usage function (pretty) - */ - this(string fullFilePath, string file, ulong line, string moduleName, string functionName, string prettyFunctionName) - { - this.fullFilePath = fullFilePath; - this.file = file; - this.line = line; - this.moduleName = moduleName; - this.functionName = functionName; - this.prettyFunctionName = prettyFunctionName; - } - - /** - * Flattens the known compile-time information into a string array - * - * Returns: a string[] - */ - public string[] toArray() - { - return [fullFilePath, file, to!(string)(line), moduleName, functionName, prettyFunctionName]; - } -} \ No newline at end of file diff --git a/source/dlog/core.d b/source/dlog/core.d index a00bb66..395d9aa 100644 --- a/source/dlog/core.d +++ b/source/dlog/core.d @@ -1,441 +1,150 @@ -/** - * Core logging services - */ module dlog.core; -import std.conv : to; -import std.range : join; -import dlog.transform : MessageTransform; -import dlog.defaults; -import dlog.context : Context, CompilationInfo, Level; -import dlog.utilities : flatten; - -/** -* Logger -* -* Represents a logger instance -*/ -public class Logger +public class Message { - /* Starting transformation */ - private MessageTransform messageTransform; - - /** - * The multiple argument joiner - */ - protected string multiArgJoiner; - /** - * Constructs a new Logger with the default - * MessageTransform - * - * Params: - * multiArgJoiner = optional joiner for segmented prints (default is " ") - */ - this(string multiArgJoiner = " ") - { - this(new DefaultTransform(), multiArgJoiner); - } - - /** - * Constructs a new Logger with the provided - * custom message transform - * Params: - * messageTransform = the message transform to use - * multiArgJoiner = optional joiner for segmented prints (default is " ") - */ - this(MessageTransform messageTransform, string multiArgJoiner = " ") - { - this.messageTransform = messageTransform; - this.multiArgJoiner = multiArgJoiner; - } - - /** - * Given an arbitrary amount of arguments, convert each to a string - * and return it as an array joined by the joiner - * - * Params: - * segments = alias sequence - * Returns: a string of the argumnets - */ - public string args(TextType...)(TextType segments) - { - /* The flattened components */ - string[] components = flatten(segments); - - /* Join all `components` into a single string */ - string joined = join(components, multiArgJoiner); - - return joined; - } - - - /** - * Logs the given string using the default context - * - * Params: - * text = the string to log - * __FILE_FULL_PATH__ = compile time usage file - * __FILE__ = compile time usage file (relative) - * __LINE__ = compile time usage line number - * __MODULE__ = compile time usage module - * __FUNCTION__ = compile time usage function - * __PRETTY_FUNCTION__ = compile time usage function (pretty) - */ - public final void log(string text, string c1 = __FILE_FULL_PATH__, - string c2 = __FILE__, ulong c3 = __LINE__, - string c4 = __MODULE__, string c5 = __FUNCTION__, - string c6 = __PRETTY_FUNCTION__) - { - /* Use the default context `Context` */ - Context defaultContext = new Context(); - - /* Build up the line information */ - CompilationInfo compilationInfo = CompilationInfo(c1, c2, c3, c4, c5, c6); - - /* Set the line information in the context */ - defaultContext.setLineInfo(compilationInfo); - - /* Call the log */ - logc(defaultContext, text, c1, c2, c3, c4, c5, c6); - } - - /** - * Logs using the default context an arbitrary amount of arguments - * - * Params: - * segments = the arbitrary argumnets (alias sequence) - * __FILE_FULL_PATH__ = compile time usage file - * __FILE__ = compile time usage file (relative) - * __LINE__ = compile time usage line number - * __MODULE__ = compile time usage module - * __FUNCTION__ = compile time usage function - * __PRETTY_FUNCTION__ = compile time usage function (pretty) - */ - public final void log(TextType...)(TextType segments, string c1 = __FILE_FULL_PATH__, - string c2 = __FILE__, ulong c3 = __LINE__, - string c4 = __MODULE__, string c5 = __FUNCTION__, - string c6 = __PRETTY_FUNCTION__) - { - /** - * Grab at compile-time all arguments and generate runtime code to add them to `components` - */ - string[] components = flatten(segments); - - /* Join all `components` into a single string */ - string messageOut = join(components, multiArgJoiner); - - /* Call the log (with text and default context) */ - log(messageOut, c1, c2, c3, c4, c5, c6); - } - - /** - * Logs the given string using the provided context - * - * Params: - * context = the custom context to use - * text = the string to log - * __FILE_FULL_PATH__ = compile time usage file - * __FILE__ = compile time usage file (relative) - * __LINE__ = compile time usage line number - * __MODULE__ = compile time usage module - * __FUNCTION__ = compile time usage function - * __PRETTY_FUNCTION__ = compile time usage function (pretty) - */ - public final void logc(Context context, string text, string c1 = __FILE_FULL_PATH__, - string c2 = __FILE__, ulong c3 = __LINE__, - string c4 = __MODULE__, string c5 = __FUNCTION__, - string c6 = __PRETTY_FUNCTION__) - { - /* Build up the line information */ - CompilationInfo compilationInfo = CompilationInfo(c1, c2, c3, c4, c5, c6); - - /* Set the line information in the context */ - context.setLineInfo(compilationInfo); - - /* Apply the transformation on the message */ - string transformedMesage = messageTransform.execute(text, context); - - /* Call the underlying logger implementation */ - logImpl(transformedMesage); - } - - /** - * Logs using the default context an arbitrary amount of arguments - * specifically setting the context's level to ERROR - * - * Params: - * segments = the arbitrary argumnets (alias sequence) - * __FILE_FULL_PATH__ = compile time usage file - * __FILE__ = compile time usage file (relative) - * __LINE__ = compile time usage line number - * __MODULE__ = compile time usage module - * __FUNCTION__ = compile time usage function - * __PRETTY_FUNCTION__ = compile time usage function (pretty) - */ - public void error(TextType...)(TextType segments, - string c1 = __FILE_FULL_PATH__, - string c2 = __FILE__, ulong c3 = __LINE__, - string c4 = __MODULE__, string c5 = __FUNCTION__, - string c6 = __PRETTY_FUNCTION__) - { - /* Use the default context `Context` */ - Context defaultContext = new Context(); - - /* Build up the line information */ - CompilationInfo compilationInfo = CompilationInfo(c1, c2, c3, c4, c5, c6); - - /* Set the line information in the context */ - defaultContext.setLineInfo(compilationInfo); - - /* Set the level to ERROR */ - defaultContext.setLevel(Level.ERROR); - - /** - * Grab at compile-time all arguments and generate runtime code to add them to `components` - */ - string[] components = flatten(segments); - - /* Join all `components` into a single string */ - string messageOut = join(components, multiArgJoiner); - - /* Call the log */ - logc(defaultContext, messageOut, c1, c2, c3, c4, c5, c6); - } - - /** - * Logs using the default context an arbitrary amount of arguments - * specifically setting the context's level to INFO - * - * Params: - * segments = the arbitrary argumnets (alias sequence) - * __FILE_FULL_PATH__ = compile time usage file - * __FILE__ = compile time usage file (relative) - * __LINE__ = compile time usage line number - * __MODULE__ = compile time usage module - * __FUNCTION__ = compile time usage function - * __PRETTY_FUNCTION__ = compile time usage function (pretty) - */ - public void info(TextType...)(TextType segments, - string c1 = __FILE_FULL_PATH__, - string c2 = __FILE__, ulong c3 = __LINE__, - string c4 = __MODULE__, string c5 = __FUNCTION__, - string c6 = __PRETTY_FUNCTION__) - { - /* Use the default context `Context` */ - Context defaultContext = new Context(); - - /* Build up the line information */ - CompilationInfo compilationInfo = CompilationInfo(c1, c2, c3, c4, c5, c6); - - /* Set the line information in the context */ - defaultContext.setLineInfo(compilationInfo); - - /* Set the level to INFO */ - defaultContext.setLevel(Level.INFO); - - /** - * Grab at compile-time all arguments and generate runtime code to add them to `components` - */ - string[] components = flatten(segments); - - /* Join all `components` into a single string */ - string messageOut = join(components, multiArgJoiner); - - /* Call the log */ - logc(defaultContext, messageOut, c1, c2, c3, c4, c5, c6); - } - - /** - * Logs using the default context an arbitrary amount of arguments - * specifically setting the context's level to WARN - * - * Params: - * segments = the arbitrary argumnets (alias sequence) - * __FILE_FULL_PATH__ = compile time usage file - * __FILE__ = compile time usage file (relative) - * __LINE__ = compile time usage line number - * __MODULE__ = compile time usage module - * __FUNCTION__ = compile time usage function - * __PRETTY_FUNCTION__ = compile time usage function (pretty) - */ - public void warn(TextType...)(TextType segments, - string c1 = __FILE_FULL_PATH__, - string c2 = __FILE__, ulong c3 = __LINE__, - string c4 = __MODULE__, string c5 = __FUNCTION__, - string c6 = __PRETTY_FUNCTION__) - { - /* Use the default context `Context` */ - Context defaultContext = new Context(); - - /* Build up the line information */ - CompilationInfo compilationInfo = CompilationInfo(c1, c2, c3, c4, c5, c6); - - /* Set the line information in the context */ - defaultContext.setLineInfo(compilationInfo); - - /* Set the level to WARN */ - defaultContext.setLevel(Level.WARN); - - /** - * Grab at compile-time all arguments and generate runtime code to add them to `components` - */ - string[] components = flatten(segments); - - /* Join all `components` into a single string */ - string messageOut = join(components, multiArgJoiner); - - /* Call the log */ - logc(defaultContext, messageOut, c1, c2, c3, c4, c5, c6); - } - - /** - * Logs using the default context an arbitrary amount of arguments - * specifically setting the context's level to DEBUG - * - * Params: - * segments = the arbitrary argumnets (alias sequence) - * __FILE_FULL_PATH__ = compile time usage file - * __FILE__ = compile time usage file (relative) - * __LINE__ = compile time usage line number - * __MODULE__ = compile time usage module - * __FUNCTION__ = compile time usage function - * __PRETTY_FUNCTION__ = compile time usage function (pretty) - */ - public void debug_(TextType...)(TextType segments, - string c1 = __FILE_FULL_PATH__, - string c2 = __FILE__, ulong c3 = __LINE__, - string c4 = __MODULE__, string c5 = __FUNCTION__, - string c6 = __PRETTY_FUNCTION__) - { - /* Use the default context `Context` */ - Context defaultContext = new Context(); - - /* Build up the line information */ - CompilationInfo compilationInfo = CompilationInfo(c1, c2, c3, c4, c5, c6); - - /* Set the line information in the context */ - defaultContext.setLineInfo(compilationInfo); - - /* Set the level to DEBUG */ - defaultContext.setLevel(Level.DEBUG); - - /** - * Grab at compile-time all arguments and generate runtime code to add them to `components` - */ - string[] components = flatten(segments); - - /* Join all `components` into a single string */ - string messageOut = join(components, multiArgJoiner); - - /* Call the log */ - logc(defaultContext, messageOut, c1, c2, c3, c4, c5, c6); - } - - /** - * Alias for debug_ - */ - public alias dbg = debug_; - - /** - * Logging implementation, this is where the final - * transformed text will be transferred to and finally - * logged - * - * Params: - * message = the message to log - */ - protected abstract void logImpl(string message); } - -version(unittest) +public interface Filter { - import std.meta : AliasSeq; - import std.stdio : writeln; + public bool filter(Message message); } -/** -* Tests the DefaultLogger -*/ -unittest +public interface Transform { - Logger logger = new DefaultLogger(); - - alias testParameters = AliasSeq!("This is a log message", 1.1, true, [1,2,3], 'f', logger); - - - // Test various types one-by-one - static foreach(testParameter; testParameters) - { - logger.log(testParameter); - } - - // Test various parameters (of various types) all at once - logger.log(testParameters); - - // Same as above but with a custom joiner set - logger = new DefaultLogger("(-)"); - logger.log(testParameters); - - writeln(); + public Message transform(Message message); } -/** - * Printing out some mixed data-types, also using a DEFAULT context - */ -unittest +public interface Handler { - Logger logger = new DefaultLogger(); - - // Create a default logger with the default joiner - logger = new DefaultLogger(); - logger.log(["a", "b", "c", "d"], [1, 2], true); - - writeln(); + public void handle(Message message); } -/** - * Printing out some mixed data-types, also using a CUSTOM context - */ -unittest +import std.container.slist : SList; +// import std.range : in; +import core.sync.mutex : Mutex; + +public abstract class Logger { - Logger logger = new DefaultLogger(); + private SList!(Transform) transforms; + private SList!(Filter) filters; + private SList!(Handler) handlers; + private Mutex lock; // Lock for attached handlers, filters and transforms - // Create a default logger with the default joiner - logger = new DefaultLogger(); + this() + { + this.lock = new Mutex(); + } - // Create a custom context - Context customContext = new Context(); + // TODO: Handle duplicate? + public final void addTransform(Transform transform) + { + scope(exit) + { + this.lock.unlock(); + } - // Log with the custom context - logger.logc(customContext, logger.args(["an", "array"], 1, "hello", true)); + this.lock.lock(); - writeln(); -} + this.transforms.insertAfter(this.transforms[], transform); + } -/** - * Printing out some mixed data-types, also using a DEFAULT context - * but also testing out the `error()`, `warn()`, `info()` and `debug()` - */ -unittest -{ - Logger logger = new DefaultLogger(); + // TODO: Hanmdle not found explicitly? + public final void removeTransform(Transform transform) + { + scope(exit) + { + this.lock.unlock(); + } - // Create a default logger with the default joiner - logger = new DefaultLogger(); + this.lock.lock(); - // Test out `error()` - logger.error(["woah", "LEVELS!"], 69.420); + this.transforms.linearRemoveElement(transform); + } - // Test out `info()` - logger.info(["woah", "LEVELS!"], 69.420); + // TODO: Handle duplicate? + public final void addFilter(Filter filter) + { + scope(exit) + { + this.lock.unlock(); + } - // Test out `warn()` - logger.warn(["woah", "LEVELS!"], 69.420); + this.lock.lock(); - // Test out `debug_()` - logger.debug_(["woah", "LEVELS!"], 69.420); + this.filters.insertAfter(this.filters[], filter); + } - writeln(); + // TODO: Hanmdle not found explicitly? + public final void removeFilter(Filter filter) + { + scope(exit) + { + this.lock.unlock(); + } + + this.lock.lock(); + + this.filters.linearRemoveElement(filter); + } + + // TODO: Handle duplicate? + public final void addHandler(Handler handler) + { + scope(exit) + { + this.lock.unlock(); + } + + this.lock.lock(); + + this.handlers.insertAfter(this.handlers[], handler); + } + + // TODO: Hanmdle not found explicitly? + public final void removeHandler(Handler handler) + { + scope(exit) + { + this.lock.unlock(); + } + + this.lock.lock(); + + this.handlers.linearRemoveElement(handler); + } + + // Logs an actual message + // + // This first passes it over all filters + // then to a transform and then copies + // to each handler + public final void log(Message message) + { + scope(exit) + { + this.lock.unlock(); + } + + this.lock.lock(); + + foreach(Filter filter; this.filters) + { + if(!filter.filter(message)) + { + return; + } + } + + Message curMessage = message; + foreach(Transform transform; this.transforms) + { + curMessage = transform.transform(curMessage); + } + + foreach(Handler handler; this.handlers) + { + handler.handle(curMessage); + } + } } \ No newline at end of file diff --git a/source/dlog/defaults.d b/source/dlog/defaults.d index f11d5b9..2e41b13 100644 --- a/source/dlog/defaults.d +++ b/source/dlog/defaults.d @@ -3,10 +3,12 @@ */ module dlog.defaults; -import dlog.core : Logger; -import dlog.transform : MessageTransform; -import dlog.context : Context, CompilationInfo; +import dlog.core; +import dlog.basic : BasicMessage, FileHandler, Level; +import std.stdio : stdout; import std.conv : to; +import dlog.utilities : flatten; +import std.array :join; /** * DefaultLogger @@ -15,6 +17,12 @@ import std.conv : to; */ public final class DefaultLogger : Logger { + /** + * The joiner for multi-argument + * log messages + */ + private string multiArgJoiner; + /** * Constructs a new default logger * @@ -23,18 +31,93 @@ public final class DefaultLogger : Logger */ this(string multiArgJoiner = " ") { - /* Use the DefaultTransform */ - super(multiArgJoiner); + this.multiArgJoiner = multiArgJoiner; + + addTransform(new DefaultTransform()); + addHandler(new FileHandler(stdout)); } /** - * Our logging implementation + * Logs the given message of an arbitrary amount of + * arguments and specifically sets the level to ERROR + * + * Params: + * segments = the arbitrary argumnets (alias sequence) */ - protected override void logImpl(string message) + public void error(TextType...)(TextType segments) { - import std.stdio : write; - write(message); + doLog(segments, Level.ERROR); } + + /** + * Logs the given message of an arbitrary amount of + * arguments and specifically sets the level to INFO + * + * Params: + * segments = the arbitrary argumnets (alias sequence) + */ + public void info(TextType...)(TextType segments) + { + doLog(segments, Level.INFO); + } + + /** + * Logs the given message of an arbitrary amount of + * arguments and specifically sets the level to WARN + * + * Params: + * segments = the arbitrary argumnets (alias sequence) + */ + public void warn(TextType...)(TextType segments) + { + doLog(segments, Level.WARN); + } + + /** + * Logs the given message of an arbitrary amount of + * arguments and specifically sets the level to DEBUG + * + * Params: + * segments = the arbitrary argumnets (alias sequence) + */ + public void debug_(TextType...)(TextType segments) + { + doLog(segments, Level.DEBUG); + } + + /** + * Performs the actual logging + * by packing up everything before + * sending it to the `log(Message)` + * method + * + * Params: + * segments = the compile-time segments + * level = the log level to use + */ + private void doLog(TextType...)(TextType segments, Level level) + { + /* Create a new basic message */ + BasicMessage message = new BasicMessage(); + + /* Set the level */ + message.setLevel(level); + + /** + * Grab all compile-time arguments and make them + * into an array, then join them together and + * set that text as the message's text + */ + message.setText(join(flatten(segments), multiArgJoiner)); + + /* Log this message */ + log(message); + } + + /** + * Alias for debug_ + */ + public alias dbg = debug_; } /** @@ -44,38 +127,115 @@ public final class DefaultLogger : Logger * * [date+time] (srcFile:lineNumber): message `\n` */ -public final class DefaultTransform : MessageTransform +public final class DefaultTransform : Transform { /** * Performs the default transformation - * - * Params: - * text = text input to transform - * context = the context (if any) - * Returns: the transformed text */ - public override string transform(string text, Context ctx) - { - /* Extract the context */ - string[] context = ctx.getLineInfo().toArray(); - string message; + + + public Message transform(Message message) + { + // Only handle BasicMessage(s) + BasicMessage bmesg = cast(BasicMessage)message; + if(bmesg is null) + { + return message; + } + + string text; /* Date and time */ import std.datetime.systime : Clock, SysTime; SysTime currTime = Clock.currTime(); import std.conv : to; string timestamp = to!(string)(currTime); - message = "["~timestamp~"]"; + text = "["~timestamp~"]"; - /* Module information */ - message = message ~ "\t("; - message = message ~ context[1]~":"~context[2]; - message = message ~ "): "~text; + /* Level */ + text = text ~ "\t("; + text = text ~ to!(string)(bmesg.getLevel()); + text = text ~ "): "~bmesg.getText(); /* Add trailing newline */ - message = message ~ '\n'; + text = text ~ '\n'; + /* Store the updated text */ + bmesg.setText(text); + return message; } +} + +version(unittest) +{ + import std.meta : AliasSeq; + import std.stdio : writeln; +} + +/** +* Tests the DefaultLogger +*/ +unittest +{ + DefaultLogger logger = new DefaultLogger(); + + alias testParameters = AliasSeq!("This is a log message", 1.1, true, [1,2,3], 'f', logger); + + + // Test various types one-by-one + static foreach(testParameter; testParameters) + { + logger.info(testParameter); + } + + // Test various parameters (of various types) all at once + logger.info(testParameters); + + // Same as above but with a custom joiner set + logger = new DefaultLogger("(-)"); + logger.info(testParameters); + + writeln(); +} + +/** + * Printing out some mixed data-types, also using a DEFAULT context + */ +unittest +{ + DefaultLogger logger = new DefaultLogger(); + + // Create a default logger with the default joiner + logger = new DefaultLogger(); + logger.info(["a", "b", "c", "d"], [1, 2], true); + + writeln(); +} + +/** + * Printing out some mixed data-types, also using a DEFAULT context + * but also testing out the `error()`, `warn()`, `info()` and `debug()` + */ +unittest +{ + DefaultLogger logger = new DefaultLogger(); + + // Create a default logger with the default joiner + logger = new DefaultLogger(); + + // Test out `error()` + logger.error(["woah", "LEVELS!"], 69.420); + + // Test out `info()` + logger.info(["woah", "LEVELS!"], 69.420); + + // Test out `warn()` + logger.warn(["woah", "LEVELS!"], 69.420); + + // Test out `debug_()` + logger.debug_(["woah", "LEVELS!"], 69.420); + + writeln(); } \ No newline at end of file diff --git a/source/dlog/nu/core.d b/source/dlog/nu/core.d deleted file mode 100644 index c21b98d..0000000 --- a/source/dlog/nu/core.d +++ /dev/null @@ -1,150 +0,0 @@ -module dlog.nu.core; - -public class Message -{ - -} - -public interface Filter -{ - public bool filter(Message message); -} - -public interface Transform -{ - public Message transform(Message message); -} - -public interface Handler -{ - public void handle(Message message); -} - -import std.container.slist : SList; -// import std.range : in; -import core.sync.mutex : Mutex; - -public abstract class Logger -{ - private SList!(Transform) transforms; - private SList!(Filter) filters; - private SList!(Handler) handlers; - private Mutex lock; // Lock for attached handlers, filters and transforms - - this() - { - this.lock = new Mutex(); - } - - // TODO: Handle duplicate? - public final void addTransform(Transform transform) - { - scope(exit) - { - this.lock.unlock(); - } - - this.lock.lock(); - - this.transforms.insertAfter(this.transforms[], transform); - } - - // TODO: Hanmdle not found explicitly? - public final void removeTransform(Transform transform) - { - scope(exit) - { - this.lock.unlock(); - } - - this.lock.lock(); - - this.transforms.linearRemoveElement(transform); - } - - // TODO: Handle duplicate? - public final void addFilter(Filter filter) - { - scope(exit) - { - this.lock.unlock(); - } - - this.lock.lock(); - - this.filters.insertAfter(this.filters[], filter); - } - - // TODO: Hanmdle not found explicitly? - public final void removeFilter(Filter filter) - { - scope(exit) - { - this.lock.unlock(); - } - - this.lock.lock(); - - this.filters.linearRemoveElement(filter); - } - - // TODO: Handle duplicate? - public final void addHandler(Handler handler) - { - scope(exit) - { - this.lock.unlock(); - } - - this.lock.lock(); - - this.handlers.insertAfter(this.handlers[], handler); - } - - // TODO: Hanmdle not found explicitly? - public final void removeHandler(Handler handler) - { - scope(exit) - { - this.lock.unlock(); - } - - this.lock.lock(); - - this.handlers.linearRemoveElement(handler); - } - - // Logs an actual message - // - // This first passes it over all filters - // then to a transform and then copies - // to each handler - public final void log(Message message) - { - scope(exit) - { - this.lock.unlock(); - } - - this.lock.lock(); - - foreach(Filter filter; this.filters) - { - if(!filter.filter(message)) - { - return; - } - } - - Message curMessage = message; - foreach(Transform transform; this.transforms) - { - curMessage = transform.transform(curMessage); - } - - foreach(Handler handler; this.handlers) - { - handler.handle(curMessage); - } - } -} \ No newline at end of file diff --git a/source/dlog/package.d b/source/dlog/package.d index e15ebf8..6dc05fb 100644 --- a/source/dlog/package.d +++ b/source/dlog/package.d @@ -11,12 +11,12 @@ public import dlog.core; /** * Transformations */ -public import dlog.transform; +// public import dlog.transform; /** * Context for logging */ -public import dlog.context; +// public import dlog.context; /** * Default logger diff --git a/source/dlog/transform.d b/source/dlog/transform.d deleted file mode 100644 index 3e24c62..0000000 --- a/source/dlog/transform.d +++ /dev/null @@ -1,52 +0,0 @@ -/** - * Transformations - */ -module dlog.transform; - -import dlog.context : Context; - -/** -* MessageTransform -* -* A message transform takes in text, applies -* a transformation to it and outputs said text -* -* Transforms may be chained -*/ -public abstract class MessageTransform -{ - /* Next transformation (if any) */ - private MessageTransform chainedTransform; - - /** - * The actual textual transformation. - * - * This is to be implemented by sub-classes - */ - public abstract string transform(string text, Context context); - - /** - * Chain a transform - */ - public final void chain(MessageTransform transform) - { - chainedTransform = transform; - } - - /** - * Perform the transformation - */ - public final string execute(string text, Context context) - { - /* Perform the transformation */ - string transformedText = transform(text, context); - - /* If there is a chained transformation */ - if(chainedTransform) - { - transformedText = chainedTransform.execute(transformedText, context); - } - - return transformedText; - } -} \ No newline at end of file From e93501457326bdbb08167b6a90caf1ad2b7ca2e1 Mon Sep 17 00:00:00 2001 From: "Tristan B. Velloza Kildaire" Date: Tue, 9 Apr 2024 18:53:32 +0200 Subject: [PATCH 14/24] Defaults - Cleaned up --- source/dlog/defaults.d | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/source/dlog/defaults.d b/source/dlog/defaults.d index 2e41b13..13c5df4 100644 --- a/source/dlog/defaults.d +++ b/source/dlog/defaults.d @@ -9,11 +9,15 @@ import std.stdio : stdout; import std.conv : to; import dlog.utilities : flatten; import std.array :join; +import std.datetime.systime : Clock, SysTime; /** * DefaultLogger * -* The default logger logs to standard output (fd 0) +* The default logger logs using +* a pretty stock-standard (non-colored) +* message transformation and supports +* the basic levels of logging. */ public final class DefaultLogger : Logger { @@ -125,16 +129,19 @@ public final class DefaultLogger : Logger * * Provides a transformation of the kind * - * [date+time] (srcFile:lineNumber): message `\n` + * [date+time] (level): message `\n` */ -public final class DefaultTransform : Transform +private final class DefaultTransform : Transform { /** - * Performs the default transformation + * Performs the default transformation. + * If the message is not a `BasicMessage` + * then no transformation occurs. + * + * Params: + * message = the message to transform + * Returns: the transformed message */ - - - public Message transform(Message message) { // Only handle BasicMessage(s) @@ -147,9 +154,7 @@ public final class DefaultTransform : Transform string text; /* Date and time */ - import std.datetime.systime : Clock, SysTime; SysTime currTime = Clock.currTime(); - import std.conv : to; string timestamp = to!(string)(currTime); text = "["~timestamp~"]"; From c53558f8479b35bc3a32b2dba0a58c31435d3e40 Mon Sep 17 00:00:00 2001 From: "Tristan B. Velloza Kildaire" Date: Tue, 9 Apr 2024 18:56:33 +0200 Subject: [PATCH 15/24] Refactored - Cleaned up --- source/dlog/basic.d | 14 +++++++++----- source/dlog/core.d | 5 +++++ source/dlog/defaults.d | 6 ++++-- source/dlog/package.d | 24 ++++++++---------------- source/dlog/utilities.d | 2 ++ 5 files changed, 28 insertions(+), 23 deletions(-) diff --git a/source/dlog/basic.d b/source/dlog/basic.d index 49fe6bc..6c42443 100644 --- a/source/dlog/basic.d +++ b/source/dlog/basic.d @@ -1,3 +1,12 @@ +/** + * Defines some basic message + * types, filters and handlers + * that may be of use in + * some combination or + * seperate + * + * Authors: Tristan Brice Velloza Kildaire (deavmi) + */ module dlog.basic; import dlog.core; @@ -39,11 +48,6 @@ public class BasicMessage : Message } } -public class Context -{ - -} - public class FileHandler : Handler { import std.stdio : File; diff --git a/source/dlog/core.d b/source/dlog/core.d index 395d9aa..58991ca 100644 --- a/source/dlog/core.d +++ b/source/dlog/core.d @@ -1,3 +1,8 @@ +/** + * Core logging services + * + * Authors: Tristan Brice Velloza Kildaire (deavmi) + */ module dlog.core; public class Message diff --git a/source/dlog/defaults.d b/source/dlog/defaults.d index 13c5df4..a6aaf70 100644 --- a/source/dlog/defaults.d +++ b/source/dlog/defaults.d @@ -1,6 +1,8 @@ /** -* Default logger -*/ + * Default logger + * + * Authors: Tristan Brice Velloza Kildaire (deavmi) + */ module dlog.defaults; import dlog.core; diff --git a/source/dlog/package.d b/source/dlog/package.d index 6dc05fb..616d6ee 100644 --- a/source/dlog/package.d +++ b/source/dlog/package.d @@ -1,24 +1,16 @@ /** -* DLog logging facilities -*/ + * The DLog logging framework + * + * Authors: Tristan Brice Velloza Kildaire (deavmi) + */ module dlog; /** -* Core logging services -*/ + * Core logging services + */ public import dlog.core; /** -* Transformations -*/ -// public import dlog.transform; - -/** -* Context for logging -*/ -// public import dlog.context; - -/** -* Default logger -*/ + * Default logger + */ public import dlog.defaults; \ No newline at end of file diff --git a/source/dlog/utilities.d b/source/dlog/utilities.d index cea892e..ebee2d6 100644 --- a/source/dlog/utilities.d +++ b/source/dlog/utilities.d @@ -1,5 +1,7 @@ /** * Helper functions + * + * Authors: Tristan Brice Velloza Kildaire (deavmi) */ module dlog.utilities; From 66adb8f70065a4e2c232c0ff6af5aa1dacc16887 Mon Sep 17 00:00:00 2001 From: "Tristan B. Velloza Kildaire" Date: Tue, 9 Apr 2024 18:59:25 +0200 Subject: [PATCH 16/24] Core - Added more docs --- source/dlog/core.d | 48 +++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 43 insertions(+), 5 deletions(-) diff --git a/source/dlog/core.d b/source/dlog/core.d index 58991ca..0055b59 100644 --- a/source/dlog/core.d +++ b/source/dlog/core.d @@ -5,30 +5,68 @@ */ module dlog.core; -public class Message +import std.container.slist : SList; +import core.sync.mutex : Mutex; + +/** + * The base message type + */ +public abstract class Message { } +/** + * Defines the filtering + * interface + */ public interface Filter { + /** + * Filters the given message + * returning a verdict + * based on it + * + * Params: + * message = the message + * Returns: the verdct + */ public bool filter(Message message); } +/** + * Defines the message + * transformation interface + */ public interface Transform { + /** + * Transforms the given message + * + * Params: + * message = the message input + * Returns: the transformed + * message + */ public Message transform(Message message); } +/** + * Defines the interface + * for handling messages + */ public interface Handler { + /** + * Handles the given message + * + * Params: + * message = the message to + * handle + */ public void handle(Message message); } -import std.container.slist : SList; -// import std.range : in; -import core.sync.mutex : Mutex; - public abstract class Logger { private SList!(Transform) transforms; From 9d8f7af4a3ab1999bfda8bbea2d3197480f1374c Mon Sep 17 00:00:00 2001 From: "Tristan B. Velloza Kildaire" Date: Tue, 9 Apr 2024 19:04:31 +0200 Subject: [PATCH 17/24] Core - Last few docs added --- source/dlog/core.d | 70 ++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 65 insertions(+), 5 deletions(-) diff --git a/source/dlog/core.d b/source/dlog/core.d index 0055b59..89cfcd2 100644 --- a/source/dlog/core.d +++ b/source/dlog/core.d @@ -67,6 +67,11 @@ public interface Handler public void handle(Message message); } +/** + * Defines the base logger + * and functionality associated + * with it + */ public abstract class Logger { private SList!(Transform) transforms; @@ -74,12 +79,22 @@ public abstract class Logger private SList!(Handler) handlers; private Mutex lock; // Lock for attached handlers, filters and transforms + /** + * Constructs a new logger + */ this() { this.lock = new Mutex(); } // TODO: Handle duplicate? + /** + * Adds the given transform + * + * Params: + * transform = the transform + * to add + */ public final void addTransform(Transform transform) { scope(exit) @@ -93,6 +108,13 @@ public abstract class Logger } // TODO: Hanmdle not found explicitly? + /** + * Removes the given transform + * + * Params: + * transform = the transform + * to remove + */ public final void removeTransform(Transform transform) { scope(exit) @@ -106,6 +128,14 @@ public abstract class Logger } // TODO: Handle duplicate? + + /** + * Adds the given filter + * + * Params: + * filter = the filter + * to add + */ public final void addFilter(Filter filter) { scope(exit) @@ -119,6 +149,14 @@ public abstract class Logger } // TODO: Hanmdle not found explicitly? + + /** + * Removes the given filter + * + * Params: + * filter = the filter + * to remove + */ public final void removeFilter(Filter filter) { scope(exit) @@ -132,6 +170,14 @@ public abstract class Logger } // TODO: Handle duplicate? + + /** + * Adds the given handler + * + * Params: + * handler = the handler + * to add + */ public final void addHandler(Handler handler) { scope(exit) @@ -145,6 +191,14 @@ public abstract class Logger } // TODO: Hanmdle not found explicitly? + + /** + * Removes the given handler + * + * Params: + * handler = the handler + * to remove + */ public final void removeHandler(Handler handler) { scope(exit) @@ -157,11 +211,17 @@ public abstract class Logger this.handlers.linearRemoveElement(handler); } - // Logs an actual message - // - // This first passes it over all filters - // then to a transform and then copies - // to each handler + /** + * Logs the provided message by processing + * it through all the filters, and if + * the verdict is `true` then transforms + * the message via all transformers + * and finally dispatches said message + * to all attached handlers + * + * Params: + * message = the message + */ public final void log(Message message) { scope(exit) From 8bb28de027aeffa07c5a8fd608f3ae529b09dbd8 Mon Sep 17 00:00:00 2001 From: "Tristan B. Velloza Kildaire" Date: Tue, 9 Apr 2024 19:14:18 +0200 Subject: [PATCH 18/24] DefaultLogger - Now is a kind-of `BasicLogger` (gives us log-level support Defaults (unittests) - Updated --- source/dlog/defaults.d | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/source/dlog/defaults.d b/source/dlog/defaults.d index a6aaf70..5ae9138 100644 --- a/source/dlog/defaults.d +++ b/source/dlog/defaults.d @@ -6,7 +6,7 @@ module dlog.defaults; import dlog.core; -import dlog.basic : BasicMessage, FileHandler, Level; +import dlog.basic : BasicMessage, FileHandler, Level, BasicLogger; import std.stdio : stdout; import std.conv : to; import dlog.utilities : flatten; @@ -21,7 +21,7 @@ import std.datetime.systime : Clock, SysTime; * message transformation and supports * the basic levels of logging. */ -public final class DefaultLogger : Logger +public final class DefaultLogger : BasicLogger { /** * The joiner for multi-argument @@ -188,6 +188,9 @@ unittest { DefaultLogger logger = new DefaultLogger(); + // Set logging level to at least INFO + logger.setLevel(Level.INFO); + alias testParameters = AliasSeq!("This is a log message", 1.1, true, [1,2,3], 'f', logger); @@ -202,6 +205,10 @@ unittest // Same as above but with a custom joiner set logger = new DefaultLogger("(-)"); + + // Set logging level to at least INFO + logger.setLevel(Level.INFO); + logger.info(testParameters); writeln(); @@ -212,10 +219,13 @@ unittest */ unittest { + // Create a default logger with the default joiner DefaultLogger logger = new DefaultLogger(); - // Create a default logger with the default joiner - logger = new DefaultLogger(); + // Set logging level to at least INFO + logger.setLevel(Level.INFO); + + // Log some stuff logger.info(["a", "b", "c", "d"], [1, 2], true); writeln(); @@ -227,10 +237,11 @@ unittest */ unittest { + // Create a default logger with the default joiner DefaultLogger logger = new DefaultLogger(); - // Create a default logger with the default joiner - logger = new DefaultLogger(); + // Set logging level to at least DEBUG + logger.setLevel(Level.DEBUG); // Test out `error()` logger.error(["woah", "LEVELS!"], 69.420); @@ -244,5 +255,9 @@ unittest // Test out `debug_()` logger.debug_(["woah", "LEVELS!"], 69.420); + // Should not be able to see this + logger.setLevel(Level.INFO); + logger.debug_("Can't see me!"); + writeln(); } \ No newline at end of file From 986a3d3bdf48392523b214aa1382342ff549d03e Mon Sep 17 00:00:00 2001 From: "Tristan B. Velloza Kildaire" Date: Tue, 9 Apr 2024 19:20:25 +0200 Subject: [PATCH 19/24] RWADME - Fixed up --- README.md | 129 +++++++++++++++--------------------------------------- 1 file changed, 36 insertions(+), 93 deletions(-) diff --git a/README.md b/README.md index 4bc6280..7769e0b 100644 --- a/README.md +++ b/README.md @@ -35,9 +35,15 @@ dlog is formed out of two main components: 1. `Logger` * The logger contains the needed barebones for facilitating the actual logging of text -2. `MessageTransform` - * A MessageTransform is attached to a logger and performs manipulation on the text input into the logger for logging + * The _base logger_ (i.e. `Logger`) maintains a list of attaches _filters_, _message transformers_ and _handlers_ +2. `Filter` + * Acts as a predicate on the incoming _message_ and determines whether it should be logged or not + * This is used by the `BasicLogger` to implement log levels +3. `Transform` + * A _message transform_ is attached to a logger and performs manipulation on the message logged * They may be chained as to perform multiple transformations in a stream-like fashion +4. `Handler` + * A _handler_ handles the final transformed message, for some this means outputting to standard out, or a file ### Quick start @@ -47,60 +53,29 @@ simply use the default logger as follows: ```d import dlog; -Logger logger = new DefaultLogger(); +DefaultLogger logger = new DefaultLogger(); +logger.setLevel(Level.DEBUG); +logger.error(["woah", "LEVELS!"], 69.420); +logger.info(["woah", "LEVELS!"], 69.420); +logger.warn(["woah", "LEVELS!"], 69.420); +logger.debug_(["woah", "LEVELS!"], 69.420); -logger.log("This is a log message"); -logger.log(1); -logger.log(1==1); -logger.log([1,2,3]); +// Should not be able to see this +logger.setLevel(Level.INFO); +logger.debug_("Can't see me!"); ``` This will output the following: ``` -[2021-Dec-23 11:17:35.3527637] (source/dlog/testing/thing.d:12): This is a log message -[2021-Dec-23 11:17:35.3527717] (source/dlog/testing/thing.d:13): 1 -[2021-Dec-23 11:17:35.3527789] (source/dlog/testing/thing.d:14): true -[2021-Dec-23 11:17:35.3527871] (source/dlog/testing/thing.d:15): [1, 2, 3] +[2024-Apr-09 19:14:38.3077171] (ERROR): ["woah", "LEVELS!"] 69.42 +[2024-Apr-09 19:14:38.3077346] (INFO): ["woah", "LEVELS!"] 69.42 +[2024-Apr-09 19:14:38.3077559] (WARN): ["woah", "LEVELS!"] 69.42 +[2024-Apr-09 19:14:38.3077759] (DEBUG): ["woah", "LEVELS!"] 69.42 ``` -As you can see file and line numbering of where the `log()` function is called appears in the log message which can be quite helpful -for debugging. - ---- - -We also support many different logging levels which can be accomplished using the `error`, `debug_` (or the `dbg` alias), `info `(the default) and `warn`: - -```d -Logger logger = new DefaultLogger(); - -// Create a default logger with the default joiner -logger = new DefaultLogger(); - -// Test out `error()` -logger.error(["woah", "LEVELS!"], 69.420); - -// Test out `info()` -logger.info(["woah", "LEVELS!"], 69.420); - -// Test out `warn()` -logger.warn(["woah", "LEVELS!"], 69.420); - -// Test out `debug_()` -logger.debug_(["woah", "LEVELS!"], 69.420); -``` - -This outputs the following: - -``` -[2023-Mar-03 11:33:49.2617904] (source/dlog/core.d:427): ["woah", "LEVELS!"] 69.42 -[2023-Mar-03 11:33:49.2618091] (source/dlog/core.d:430): ["woah", "LEVELS!"] 69.42 -[2023-Mar-03 11:33:49.2618273] (source/dlog/core.d:433): ["woah", "LEVELS!"] 69.42 -[2023-Mar-03 11:33:49.2618457] (source/dlog/core.d:436): ["woah", "LEVELS!"] 69.42 -``` - -You can also look into `logc(Context, string)` which allows you to use a `Context` object when logging, more information available in the [full API](https://dlog.dpldocs.info/v0.3.19/dlog.context.html). +You can see the [full API](https://dlog.dpldocs.info/v0.3.19/dlog.context.html) for more information. ### Custom loggers @@ -110,64 +85,32 @@ Perhaps the default transformation, `DefaultTransform`, may not be what you want messages or perhaps don't want the date-and-timestamp included at all. All of this can be up to you if you choose to implement your own message transform. -You will need to start off with a class that inherits from the `MessageTransform` class and then which overrides the `transform` method as shown below: +You will need to start off with a class that inherits from the `Transform` class and then which overrides the `transform` method as shown below: ```d import dlog; -public class CustomTranform : MessageTransform +public class CustomTranform : Transform { - public override string transform(string text, Context context) + public override Message transform(Message message) { + BasicMessage bmesg = cast(BasicMessage)message; + + // Only handle BasicMessage(s) - ones which have `setText(string)` + if(bmesg is null) + { + return message; + } + string transformed; + /* Insert transformation code here */ + bmesg.setText(transformed); - /* Insert code to transform `text` and return the `transformed` text */ - - return transformed; + return message; } } ``` -Additional information, besides the text being logged itself (this is the `string text` argument), comes in the form of a `Context` object `context`. What one can get from this is a `CompilationInfo` struct which contains the following fields below if one calls `toArray()` on -it which will return a string array shown below (we refer to this array as `lineInfo`): - -1. `lineInfo[0]` - * This contains `__FILE_FULL_PATH__` which is the full path (absolute) to the source file where `log()` was called -2. `lineInfo[1]` - * This contains `__FILE__` which is the path (starting at `source/` to the source file where `log()` was called -3. `lineInfo[2]` - * This contains a stringified version of `__LINE__` which is the line number of the call to `log()` -4. `lineInfo[3]` - * This contains `__MODULE__` which is the name of the module the call to `log()` appeared in -5. `lineInfo[4]` - * This contains `__FUNCTION__` which is the name of the function `log()` was called in -6. `lineInfo[5]` - * This contains `__PRETTY_FUNCTION__` which is the same as above but with type information - -The point of a `Context` object is also such that a custom transformer may expect a kind-of `Context` like a custom one (i.e. `CustomContext`) -which perhaps a custom logger (kind-of `Logger`) can then have set certain fields in it. - -## Creating a Logger - -We now need to create a logger that makes use of our message transform, we can do so by creating an instance -of the `Logger` class and passing in our `MessageTransform` as so: - -```d -Logger customLogger = new DefaultLogger(new CustomTranform()); -``` - -The above is all one needs to be able to pull off a custom transformation. - -### Custom Logger - -Custom loggers can also be created by sub-classing the `Logger` class and overriding the `logImpl(string)` method. -The reason someone may want to do this is up to them. One easy to think of reason is to perhaps applying filtering -of messages to be logged and skip them (as this method is where the I/O of printing out the logs normally happens). -Another reason may be to log to a different data resource, the `DefaultLogger` writes to the file descriptor `0` (stdout), -but you may want to log over a socket connection to a remote machine for example, or perhaps do several pieces of -I/O for your logging. One can do that with a custom logger, you shoudl see `source/dlog/defaults.d` for the implementation -of a custom logger, such as `DefaultLogger`. - ## License LGPL v3 \ No newline at end of file From 49f1f70f28ed4eb4c56763a8beeeca94590c0433 Mon Sep 17 00:00:00 2001 From: "Tristan B. Velloza Kildaire" Date: Tue, 9 Apr 2024 19:27:15 +0200 Subject: [PATCH 20/24] Basics - Added some missing docs --- source/dlog/basic.d | 53 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 52 insertions(+), 1 deletion(-) diff --git a/source/dlog/basic.d b/source/dlog/basic.d index 6c42443..32d6ecc 100644 --- a/source/dlog/basic.d +++ b/source/dlog/basic.d @@ -10,38 +10,89 @@ module dlog.basic; import dlog.core; +import std.stdio : File; +/** + * Represents a basic message + * with log level information + * associated with it as well + * as text + */ public class BasicMessage : Message { + /** + * The text message + */ private string text; + + /** + * Log level + */ private Level level; + /** + * Constructs a new `BasicMessage` + * with the given text and log level + * + * Params: + * text = the message text + * level = the log level (default + * is `Level.INFO`) + */ this(string text, Level level = Level.INFO) { this.text = text; this.level = level; } + /** + * Constructs an empty message + * with the highest log level + * (least verbose) + */ this() { } + /** + * Sets the text + * + * Params: + * text = the message's + * text + */ public void setText(string text) { this.text = text; } + /** + * Returns the text + * + * Returns: the text + */ public string getText() { return this.text; } + /** + * Returns the log level + * + * Returns: the level + */ public Level getLevel() { return this.level; } + /** + * Sets the log level + * + * Params: + * level = the level + */ public void setLevel(Level level) { this.level = level; @@ -50,7 +101,7 @@ public class BasicMessage : Message public class FileHandler : Handler { - import std.stdio : File; + private File file; this(File file) { From 6be4be3534ca29da07cce42e44783c308b68e024 Mon Sep 17 00:00:00 2001 From: "Tristan B. Velloza Kildaire" Date: Tue, 9 Apr 2024 19:30:56 +0200 Subject: [PATCH 21/24] Basics - More docs --- source/dlog/basic.d | 52 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 51 insertions(+), 1 deletion(-) diff --git a/source/dlog/basic.d b/source/dlog/basic.d index 32d6ecc..9fa4dda 100644 --- a/source/dlog/basic.d +++ b/source/dlog/basic.d @@ -99,15 +99,39 @@ public class BasicMessage : Message } } +/** + * A file-based handler which + * writes `BasicMessage`(s) + * to a provided file + */ public class FileHandler : Handler { - + /** + * File to write to + */ private File file; + + /** + * Constrtucts a new + * `FileHandler` with + * the given file + * + * Params: + * file = the file + */ this(File file) { this.file = file; } + /** + * Handles the message, does a + * no-op if the message is + * not a kind-of `BasicMessage` + * + * Params: + * message = the message + */ public void handle(Message message) { // Only handle BasicMessage(s) @@ -145,15 +169,41 @@ public enum Level DEBUG } +/** + * A level-based filter which + * has a predicate which operates + * on the value of a pointed-to + * `Level` variable + */ private class LevelFilter : Filter { + /** + * Address of the level var + */ private Level* level; + /** + * Constructs a new `LevelFilter` + * with the given `Level*` + * + * Params: + * level = the level address + */ this(Level* level) { this.level = level; } + /** + * Filters the given message according + * to the current level. This will no-op + * and always return `true` if the message + * is not a kind-of `BasicMessage` + * + * Params: + * message = the message + * Returns: the verdict + */ public bool filter(Message message) { // Only handle BasicMessage(s) From b29e2eb1c714ff7410f4db8ed7f8e8d9e4a58aa2 Mon Sep 17 00:00:00 2001 From: "Tristan B. Velloza Kildaire" Date: Tue, 9 Apr 2024 19:31:22 +0200 Subject: [PATCH 22/24] LevelFilter - Now returns a `true` verdict if the incoming `Message` is NOT a kind-of `BasicMessage` --- source/dlog/basic.d | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/dlog/basic.d b/source/dlog/basic.d index 9fa4dda..667582c 100644 --- a/source/dlog/basic.d +++ b/source/dlog/basic.d @@ -213,7 +213,7 @@ private class LevelFilter : Filter return bmesg.getLevel() <= *this.level; } - return false; + return true; } } From 1d57ab1529c290b7a5a1dbcaaac2e8379781b08e Mon Sep 17 00:00:00 2001 From: "Tristan B. Velloza Kildaire" Date: Tue, 9 Apr 2024 19:31:52 +0200 Subject: [PATCH 23/24] ConsoleLogger - Removed --- source/dlog/basic.d | 9 --------- 1 file changed, 9 deletions(-) diff --git a/source/dlog/basic.d b/source/dlog/basic.d index 667582c..88ceb2f 100644 --- a/source/dlog/basic.d +++ b/source/dlog/basic.d @@ -238,13 +238,4 @@ public class BasicLogger : Logger { return this.level; } -} - -public class ConsoleLogger : BasicLogger -{ - this() - { - import std.stdio; - addHandler(new FileHandler(stdout)); - } } \ No newline at end of file From dac231866eaad4a47ba740c9429bb4282ea53f05 Mon Sep 17 00:00:00 2001 From: "Tristan B. Velloza Kildaire" Date: Wed, 10 Apr 2024 13:52:37 +0200 Subject: [PATCH 24/24] BasicLogger - Documented --- source/dlog/basic.d | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/source/dlog/basic.d b/source/dlog/basic.d index 88ceb2f..ed7753f 100644 --- a/source/dlog/basic.d +++ b/source/dlog/basic.d @@ -217,10 +217,20 @@ private class LevelFilter : Filter } } +/** + * A basic logger which has support + * for log levels + */ public class BasicLogger : Logger { + /** + * The current log level + */ private Level level; + /** + * Constructs a new `BasicLogger` + */ this() { // Attach a new level-filter @@ -229,11 +239,24 @@ public class BasicLogger : Logger addFilter(new LevelFilter(&level)); } + /** + * Sets the log level + * + * Params: + * level = the new + * level + */ public final void setLevel(Level level) { this.level = level; } + /** + * Obtains the current log + * level + * + * Returns: the current level + */ public final Level getLevel() { return this.level;