1 /**
2 Copyright: Copyright (c) 2018, Joakim Brännström. All rights reserved.
3 License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0)
4 Author: Joakim Brännström (joakim.brannstrom@gmx.com)
5 
6 Handles console logging in pretty colors.
7 
8 The module disables colors when stdout and stderr isn't a TTY that support
9 colors. This is to avoid ASCII escape sequences in piped output.
10 */
11 module colorlog;
12 
13 import std.stdio : writefln, stderr, stdout;
14 import logger = std.experimental.logger;
15 import std.experimental.logger : LogLevel;
16 
17 public import my.term_color;
18 
19 /// The verbosity level of the logging to use.
20 enum VerboseMode {
21     /// Info+
22     info,
23     /// Trace+
24     trace,
25     /// Warnings+
26     warning,
27 }
28 
29 /** Configure `std.experimental.logger` with a colorlog instance.
30  */
31 void confLogger(VerboseMode mode) @safe {
32     final switch (mode) {
33     case VerboseMode.info:
34         logger.globalLogLevel = logger.LogLevel.info;
35         logger.sharedLog = new SimpleLogger(logger.LogLevel.info);
36         break;
37     case VerboseMode.trace:
38         logger.globalLogLevel = logger.LogLevel.all;
39         logger.sharedLog = new DebugLogger(logger.LogLevel.all);
40         break;
41     case VerboseMode.warning:
42         logger.globalLogLevel = logger.LogLevel.warning;
43         logger.sharedLog = new SimpleLogger(logger.LogLevel.info);
44         break;
45     }
46 }
47 
48 // The width of the prefix.
49 private immutable _prefixWidth = 8;
50 
51 class SimpleLogger : logger.Logger {
52     this(const LogLevel lvl = LogLevel.warning) @safe {
53         super(lvl);
54         initColors;
55     }
56 
57     override void writeLogMsg(ref LogEntry payload) @trusted {
58         auto out_ = stderr;
59         auto use_color = Color.red;
60         auto use_mode = Mode.bold;
61         const use_bg = Background.black;
62 
63         switch (payload.logLevel) {
64         case LogLevel.trace:
65             out_ = stdout;
66             use_color = Color.white;
67             use_mode = Mode.init;
68             break;
69         case LogLevel.info:
70             out_ = stdout;
71             use_color = Color.white;
72             break;
73         default:
74         }
75 
76         import std.conv : to;
77 
78         out_.writefln("%s: %s", payload.logLevel.to!string.color(use_color)
79                 .bg(use_bg).mode(use_mode), payload.msg);
80     }
81 }
82 
83 class DebugLogger : logger.Logger {
84     this(const logger.LogLevel lvl = LogLevel.trace) @safe {
85         super(lvl);
86         initColors;
87     }
88 
89     override void writeLogMsg(ref LogEntry payload) @trusted {
90         auto out_ = stderr;
91         auto use_color = Color.red;
92         auto use_mode = Mode.bold;
93         const use_bg = Background.black;
94 
95         switch (payload.logLevel) {
96         case LogLevel.trace:
97             out_ = stdout;
98             use_color = Color.white;
99             use_mode = Mode.init;
100             break;
101         case LogLevel.info:
102             out_ = stdout;
103             use_color = Color.white;
104             break;
105         default:
106         }
107 
108         import std.conv : to;
109 
110         out_.writefln("%s: %s [%s:%d]", payload.logLevel.to!string.color(use_color)
111                 .bg(use_bg).mode(use_mode), payload.msg, payload.funcName, payload.line);
112     }
113 }