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