1 /* 2 *Copyright (C) 2018 Laurent Tréguier 3 * 4 *This file is part of DLS. 5 * 6 *DLS is free software: you can redistribute it and/or modify 7 *it under the terms of the GNU General Public License as published by 8 *the Free Software Foundation, either version 3 of the License, or 9 *(at your option) any later version. 10 * 11 *DLS is distributed in the hope that it will be useful, 12 *but WITHOUT ANY WARRANTY; without even the implied warranty of 13 *MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 *GNU General Public License for more details. 15 * 16 *You should have received a copy of the GNU General Public License 17 *along with DLS. If not, see <http://www.gnu.org/licenses/>. 18 * 19 */ 20 21 module dls.protocol.logger; 22 23 import dls.protocol.interfaces : InitializeParams, MessageType; 24 25 private shared _logger = new shared LspLogger(); 26 private immutable int[InitializeParams.Trace] traceToType; 27 private immutable string[MessageType] messageSeverity; 28 private immutable logMessageFormat = "[%.24s] [%s] %s"; 29 30 shared static this() 31 { 32 import std.experimental.logger : LogLevel, globalLogLevel; 33 34 globalLogLevel = LogLevel.off; 35 36 //dfmt off 37 traceToType = [ 38 InitializeParams.Trace.off : 0, 39 InitializeParams.Trace.messages : MessageType.info, 40 InitializeParams.Trace.verbose : MessageType.log 41 ]; 42 43 messageSeverity = [ 44 MessageType.log : "D", 45 MessageType.info : "I", 46 MessageType.warning : "W", 47 MessageType.error : "E" 48 ]; 49 //dfmt on 50 } 51 52 @property shared(LspLogger) logger() 53 { 54 return _logger; 55 } 56 57 private shared class LspLogger 58 { 59 import dls.protocol.interfaces : MessageType; 60 import std.format : format; 61 62 private int _messageType; 63 64 @property void trace(const InitializeParams.Trace t) 65 { 66 _messageType = traceToType[t]; 67 } 68 69 void log(Args...)(const string message, const Args args) const 70 { 71 sendMessage(format(message, args), MessageType.log); 72 } 73 74 void info(Args...)(const string message, const Args args) const 75 { 76 sendMessage(format(message, args), MessageType.info); 77 } 78 79 void warning(Args...)(const string message, const Args args) const 80 { 81 sendMessage(format(message, args), MessageType.warning); 82 } 83 84 void error(Args...)(const string message, const Args args) const 85 { 86 sendMessage(format(message, args), MessageType.error); 87 } 88 89 private void sendMessage(const string message, const MessageType type) const 90 { 91 import dls.protocol.interfaces : LogMessageParams; 92 import dls.protocol.jsonrpc : send; 93 import dls.protocol.messages.methods : Window; 94 import dls.protocol.state : initOptions; 95 import std.datetime : Clock; 96 import std.file : mkdirRecurse; 97 import std.format : format; 98 import std.path : dirName; 99 import std.stdio : File; 100 101 if (type <= _messageType) 102 { 103 if (initOptions.logFile.length > 0) 104 { 105 static bool firstLog = true; 106 107 if (firstLog) 108 { 109 mkdirRecurse(dirName(initOptions.logFile)); 110 } 111 112 synchronized 113 { 114 auto log = File(initOptions.logFile, firstLog ? "w" : "a"); 115 log.writefln(logMessageFormat, Clock.currTime.toString(), 116 messageSeverity[type], message); 117 log.flush(); 118 } 119 120 if (firstLog) 121 { 122 firstLog = false; 123 } 124 } 125 126 if (type != MessageType.log) 127 { 128 send(Window.logMessage, new LogMessageParams(type, format(logMessageFormat, 129 Clock.currTime.toString(), messageSeverity[type], message))); 130 } 131 } 132 } 133 }