1 module minlog.logger;
2 
3 import std.stdio;
4 import std.format;
5 import std.conv;
6 import std.datetime;
7 import colorize;
8 
9 /// how verbose the messages are
10 enum Verbosity {
11     trace = 4,
12     info = 3,
13     warn = 2,
14     error = 1,
15     crit = 0
16 }
17 
18 /// a utility class for displaying diagnostic messages
19 class Logger {
20     /// maximum message verbosity
21     public Verbosity verbosity;
22     /// message output targets
23     public ILogSink[] sinks;
24 
25     /**
26     initialize a logger with a given verbosity
27     */
28     this(Verbosity verbosity) {
29         this.verbosity = verbosity;
30     }
31 
32     /// writes a message
33     public void write_line(string log, Verbosity level) {
34         if (level <= verbosity) {
35             foreach (sink; sinks) {
36                 sink.write_line(log, level);
37             }
38         }
39     }
40 
41     /// writes a message at trace verbosity
42     public void trace(string log) {
43         write_line(log, Verbosity.trace);
44     }
45 
46     /// writes a message at INFO verbosity
47     public void info(string log) {
48         write_line(log, Verbosity.info);
49     }
50 
51     /// writes a message at warn verbosity
52     public void warn(string log) {
53         write_line(log, Verbosity.warn);
54     }
55 
56     /// writes a message at error verbosity
57     public void err(string log) {
58         write_line(log, Verbosity.error);
59     }
60 
61     /// writes a message at crit verbosity
62     public void crit(string log) {
63         write_line(log, Verbosity.crit);
64     }
65 
66     private static string shortVerbosity(Verbosity level) {
67         switch (level) {
68         case Verbosity.trace:
69             return "trce";
70         case Verbosity.info:
71             return "info";
72         case Verbosity.warn:
73             return "warn";
74         case Verbosity.error:
75             return "err!";
76         case Verbosity.crit:
77             return "crit";
78         default:
79             return to!string(level);
80         }
81     }
82 
83     private static string formatMeta(Verbosity level) {
84         auto time = cast(TimeOfDay) Clock.currTime();
85         return format("[%s/%s]", shortVerbosity(level), time.toISOExtString());
86     }
87 
88     /// a sink that accepts log messages
89     public interface ILogSink {
90         /// writes a message to the sink
91         void write_line(string log, Verbosity level);
92     }
93 
94     /// a sink that outputs to the console
95     public static class ConsoleSink : ILogSink {
96         public void write_line(string log, Verbosity level) {
97             auto col = colorFor(level);
98             colorize.cwritef(formatMeta(level).color(col, colorize.bg.black));
99             colorize.cwritefln(" %s", log);
100         }
101 
102         private colorize.fg colorFor(Verbosity level) {
103             switch (level) {
104             case Verbosity.trace:
105                 return colorize.fg.light_black;
106             case Verbosity.info:
107                 return colorize.fg.green;
108             case Verbosity.warn:
109                 return colorize.fg.yellow;
110             case Verbosity.error:
111                 return colorize.fg.light_red;
112             case Verbosity.crit:
113                 return colorize.fg.red;
114             default:
115                 return colorize.fg.white;
116             }
117         }
118     }
119 
120     /// a sink that outputs to a file
121     public static class FileSink : ILogSink {
122         public string path;
123         private File of;
124 
125         this(string path) {
126             this.path = path;
127             this.of = File(path, "a");
128         }
129 
130         public void write_line(string log, Verbosity level) {
131             of.write(formatMeta(level));
132             of.writeln(" {log}");
133             of.flush();
134         }
135     }
136 }
137 
138 unittest {
139     auto log = new Logger(Verbosity.info);
140     log.sinks ~= new Logger.ConsoleSink();
141     log.verbosity = Verbosity.trace;
142 
143     log.info("hello world");
144 }