mirror of https://github.com/deavmi/dlog.git
parent
2f8b61fcf2
commit
59ddf53efa
|
@ -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
|
||||
}
|
||||
|
|
@ -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];
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue