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