1 /**
2  * Модуль консольного логера, основанного на vibe.core.log и consoled
3  *
4  * Copyright: (c) 2015-2017, Milofon Project.
5  * License: Subject to the terms of the BSD license, as written in the included LICENSE.txt file.
6  * Authors: Maksim Galanin
7  */
8 module dango.system.logging.loggers.console;
9 
10 private
11 {
12     import std.typecons: Tuple, tuple;
13     import std.stdio: writeln, write, writef;
14     import std.format : format;
15 
16     import vibe.core.log;
17     import proped: Properties;
18 
19     import dango.system.logging.core;
20 }
21 
22 
23 enum AnsiColor
24 {
25     black = 30,
26     red = 31,
27     green = 32,
28     yellow = 33,
29     blue = 34,
30     magenta = 35,
31     cyan = 36,
32     white = 37,
33     defaultColor = 39
34 }
35 
36 
37 struct StringWithBoth(T)
38 {
39     string s;
40     T fg;
41     T bg;
42     this(string s, T fg, T bg)
43     {
44         this.s = s;
45         this.fg = fg;
46         this.bg = bg;
47     }
48 
49     string toString()
50     {
51         return "\033[%dm\033[%dm%s\033[0m".format(fg, bg + 10, s);
52     }
53 }
54 
55 
56 /**
57  * Фабрика создающая расширенный консольный логгер
58  */
59 class ConsoleLoggerFactory : LoggerFactory
60 {
61     shared(Logger) createLogger(Properties config)
62     {
63         LogLevel level = matchLogLevel(config.getOrElse("level", "info"));
64 
65         auto result = cast(shared)new ConsoleLogger(level);
66         return result;
67     }
68 }
69 
70 
71 /**
72  * Расширенный консольный логгер, с возможностью управления цветом
73  */
74 class ConsoleLogger : Logger
75 {
76     alias ColorTheme = Tuple!(AnsiColor, AnsiColor);
77 
78     enum themes = [
79         LogLevel.trace: ColorTheme(AnsiColor.cyan, AnsiColor.defaultColor),
80         LogLevel.debugV: ColorTheme(AnsiColor.green, AnsiColor.defaultColor),
81         LogLevel.debug_: ColorTheme(AnsiColor.green, AnsiColor.defaultColor),
82         LogLevel.diagnostic: ColorTheme(AnsiColor.green, AnsiColor.defaultColor),
83         LogLevel.info: ColorTheme(AnsiColor.defaultColor, AnsiColor.defaultColor),
84         LogLevel.warn: ColorTheme(AnsiColor.yellow, AnsiColor.defaultColor),
85         LogLevel.error: ColorTheme(AnsiColor.red, AnsiColor.defaultColor),
86         LogLevel.critical: ColorTheme(AnsiColor.white, AnsiColor.red),
87         LogLevel.fatal: ColorTheme(AnsiColor.white, AnsiColor.red),
88         LogLevel.none: ColorTheme(AnsiColor.defaultColor, AnsiColor.defaultColor),
89     ];
90 
91     this(LogLevel level) {
92         minLevel = level;
93     }
94 
95     override void beginLine(ref LogLine msg) @trusted
96     {
97         string pref;
98         final switch (msg.level) {
99             case LogLevel.trace: pref = "trc"; break;
100             case LogLevel.debugV: pref = "dbv"; break;
101             case LogLevel.debug_: pref = "dbg"; break;
102             case LogLevel.diagnostic: pref = "dia"; break;
103             case LogLevel.info: pref = "INF"; break;
104             case LogLevel.warn: pref = "WRN"; break;
105             case LogLevel.error: pref = "ERR"; break;
106             case LogLevel.critical: pref = "CRITICAL"; break;
107             case LogLevel.fatal: pref = "FATAL"; break;
108             case LogLevel.none: assert(false);
109         }
110         ColorTheme theme = themes[msg.level];
111         auto tm = msg.time;
112         static if (is(typeof(tm.fracSecs)))
113             auto msecs = tm.fracSecs.total!"msecs";
114         else auto msecs = tm.fracSec.msecs;
115 
116         writef("[%08X:%08X %d.%02d.%02d %02d:%02d:%02d.%03d ",
117                 msg.threadID, msg.fiberID,
118                 tm.year, tm.month, tm.day, tm.hour, tm.minute, tm.second, msecs);
119 
120         write(StringWithBoth!AnsiColor(pref, theme[0], theme[1]));
121         write("] ");
122     }
123 
124     override void put(scope const(char)[] text)
125     {
126         write(text);
127     }
128 
129     override void endLine()
130     {
131         writeln();
132     }
133 }
134