1 /**
2 * Core module containing types pertaining to the base Logger
3 * class and base MessageTransform class (along with a default
4 * transform, DefaultTransform)
5 */
6 module dlog.core;
7 
8 import std.conv : to;
9 import dlog.defaults;
10 
11 /**
12 * DefaultTransform
13 *
14 * Provides a transformation of the kind
15 *
16 * [date+time] (srcFile:lineNumber): message `\n`
17 */
18 public final class DefaultTransform : MessageTransform
19 {
20 
21 	/**
22 	* Our transformation
23 	*/
24 	public override string transform(string text, string[] context)
25 	{
26 		string message;
27 
28 		/* Date and time */
29 		import std.datetime.systime : Clock, SysTime;
30 		SysTime currTime = Clock.currTime();
31 		import std.conv : to;
32 		string timestamp = to!(string)(currTime);
33 		message = "["~timestamp~"]";
34 
35 		/* Module information */
36 		message = message ~ "\t(";
37 		message = message ~ context[1]~":"~context[2];
38 		message = message ~ "): "~text;
39 
40 		/* Add trailing newline */
41 		message = message ~ '\n';
42 		
43 		return message;
44 	}
45 }
46 
47 /**
48 * Logger
49 *
50 * Represents a logger instance
51 */
52 public class Logger
53 {
54 	/* Starting transformation */
55 	private MessageTransform messageTransform;
56 	
57 	/**
58 	* Constructs a new Logger with the default
59 	* MessageTransform, see TODO (ref module)
60 	*/
61 	this()
62 	{
63 		this(new DefaultTransform());
64 	}
65 
66 	/**
67 	* Constructs a new Logger with the given
68 	* MessageTransform
69 	*/
70 	this(MessageTransform messageTransform)
71 	{
72 		this.messageTransform = messageTransform;
73 	}
74 
75 	/**
76 	* Log a message
77 	*/
78 	public final void log(TextType)(TextType message, string c1 = __FILE_FULL_PATH__,
79 									string c2 = __FILE__, ulong c3 = __LINE__,
80 									string c4 = __MODULE__, string c5 = __FUNCTION__,
81 									string c6 = __PRETTY_FUNCTION__, string[] contextExtras = null)
82 	{
83 		/* Construct context array */
84 		string[] context = [c1, c2, to!(string)(c3), c4, c5, c6]~contextExtras;
85 		
86 		/* Apply the transformation on the message */
87 		string transformedMesage = messageTransform.execute(to!(string)(message), context);
88 		
89 		/* Call the underlying logger implementation */
90 		logImpl(transformedMesage);
91 	}
92 
93 	/**
94 	* Logging implementation, this is where the fina
95 	* transformed text will be transferred to and finally
96 	* logged
97 	*/
98 	protected abstract void logImpl(string message);
99 }
100 
101 /**
102 * MessageTransform
103 *
104 * A message transform takes in text, applies
105 * a transformation to it and outputs said text
106 *
107 * Transforms may be chained
108 */
109 public abstract class MessageTransform
110 {
111 	/* Next transformation (if any) */
112 	private MessageTransform chainedTransform;
113 
114 	/**
115 	* The actual textual transformation.
116 	*
117 	* This is to be implemented by sub-classes
118 	*/
119 	public abstract string transform(string text, string[] context);
120 
121 	/**
122 	* Chain a transform
123 	*/
124 	public final void chain(MessageTransform transform)
125 	{
126 		chainedTransform = transform;
127 	}
128 
129 	/**
130 	* Perform the transformation
131 	*/
132 	public final string execute(string text, string[] context)
133 	{
134 		/* Perform the transformation */
135 		string transformedText = transform(text, context);
136 
137 		/* If there is a chained transformation */
138 		if(chainedTransform)
139 		{
140 			transformedText = chainedTransform.execute(transformedText, context);
141 		}
142 
143 		return transformedText;
144 	}
145 }
146 
147 /**
148 * Tests the DefaultLogger
149 */
150 unittest
151 {
152 	Logger logger = new DefaultLogger();
153 
154 	logger.log("This is a log message");
155 	logger.log(1);
156 	logger.log(1.1);
157 	logger.log(true);
158 	logger.log([1,2,3]);
159 	logger.log('f');
160 	logger.log(logger);
161 }