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: stdout, stderr, File; 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 string outStreamName = config.getOrElse("outStream", "stdout"); 35 return cast(shared)new ConsoleLogger(level, outStreamName, isSync); 36 } 37 } 38 39 40 /** 41 * Расширенный консольный логгер, с возможностью управления цветом 42 */ 43 class ConsoleLogger : Logger 44 { 45 private 46 { 47 immutable bool isSync; 48 File outStream; 49 } 50 51 52 this(LogLevel level, string outStreamName, bool isSync) @trusted 53 { 54 this.isSync = isSync; 55 if (outStreamName == "stderr") 56 this.outStream = stderr; 57 else 58 this.outStream = stdout; 59 minLevel = level; 60 } 61 62 alias ColorTheme = Tuple!(AnsiColor, AnsiColor); 63 64 enum themes = [ 65 LogLevel.trace: ColorTheme(AnsiColor.cyan, AnsiColor.reset), 66 LogLevel.debugV: ColorTheme(AnsiColor.green, AnsiColor.reset), 67 LogLevel.debug_: ColorTheme(AnsiColor.green, AnsiColor.reset), 68 LogLevel.diagnostic: ColorTheme(AnsiColor.green, AnsiColor.reset), 69 LogLevel.info: ColorTheme(AnsiColor.reset, AnsiColor.reset), 70 LogLevel.warn: ColorTheme(AnsiColor.yellow, AnsiColor.reset), 71 LogLevel.error: ColorTheme(AnsiColor.red, AnsiColor.reset), 72 LogLevel.critical: ColorTheme(AnsiColor.white, AnsiColor.red), 73 LogLevel.fatal: ColorTheme(AnsiColor.white, AnsiColor.red), 74 LogLevel.none: ColorTheme(AnsiColor.reset, AnsiColor.reset), 75 ]; 76 77 override void beginLine(ref LogLine msg) @trusted 78 { 79 string pref; 80 final switch (msg.level) 81 { 82 case LogLevel.trace: pref = "trc"; break; 83 case LogLevel.debugV: pref = "dbv"; break; 84 case LogLevel.debug_: pref = "dbg"; break; 85 case LogLevel.diagnostic: pref = "dia"; break; 86 case LogLevel.info: pref = "INF"; break; 87 case LogLevel.warn: pref = "WRN"; break; 88 case LogLevel.error: pref = "ERR"; break; 89 case LogLevel.critical: pref = "CRITICAL"; break; 90 case LogLevel.fatal: pref = "FATAL"; break; 91 case LogLevel.none: assert(false); 92 } 93 ColorTheme theme = themes[msg.level]; 94 95 auto tm = msg.time; 96 static if (is(typeof(tm.fracSecs))) 97 auto msecs = tm.fracSecs.total!"msecs"; 98 else auto msecs = tm.fracSec.msecs; 99 100 outStream.writef("[%08X:%08X %d.%02d.%02d %02d:%02d:%02d.%03d ", 101 msg.threadID, msg.fiberID, 102 tm.year, tm.month, tm.day, tm.hour, tm.minute, tm.second, msecs); 103 outStream.write(theme[0].fg, theme[1].bg, pref, resetColor); 104 outStream.write("] "); 105 } 106 107 override void put(scope const(char)[] text) 108 { 109 outStream.write(text); 110 } 111 112 override void endLine() @trusted 113 { 114 outStream.writeln(); 115 if (isSync) 116 outStream.flush(); 117 } 118 } 119