1 /***************************************************************************
2 * Copyright (C) 2005-2019 by the Quassel Project *
3 * devel@quassel-irc.org *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) version 3. *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program; if not, write to the *
17 * Free Software Foundation, Inc., *
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
19 ***************************************************************************/
38 QByteArray msgWithTime(const Logger::LogEntry& msg)
42 switch (msg.logLevel) {
43 case Logger::LogLevel::Debug:
44 levelString = "[Debug] ";
46 case Logger::LogLevel::Info:
47 levelString = "[Info ] ";
49 case Logger::LogLevel::Warning:
50 levelString = "[Warn ] ";
52 case Logger::LogLevel::Error:
53 levelString = "[Error] ";
55 case Logger::LogLevel::Fatal:
56 levelString = "[FATAL] ";
60 return (msg.timeStamp.toString("yyyy-MM-dd hh:mm:ss ") + levelString + msg.message + "\n").toUtf8();
65 Logger::Logger(QObject* parent)
68 static bool registered = []() {
69 qRegisterMetaType<LogEntry>();
74 connect(this, &Logger::messageLogged, this, &Logger::onMessageLogged);
76 qInstallMessageHandler(Logger::messageHandler);
81 // If we're not initialized yet, output pending messages so they don't get lost
83 for (auto&& message : _messages) {
84 std::cerr << msgWithTime(message).constData();
89 std::vector<Logger::LogEntry> Logger::messages() const
94 void Logger::setup(bool keepMessages)
96 _keepMessages = keepMessages;
98 // Set maximum level for output (we still store/announce all messages for client-side filtering)
99 if (Quassel::isOptionSet("loglevel")) {
100 QString level = Quassel::optionValue("loglevel").toLower();
101 if (level == "debug")
102 _outputLevel = LogLevel::Debug;
103 else if (level == "info")
104 _outputLevel = LogLevel::Info;
105 else if (level == "warning")
106 _outputLevel = LogLevel::Warning;
107 else if (level == "error")
108 _outputLevel = LogLevel::Error;
110 throw ExitException{EXIT_FAILURE, qPrintable(tr("Invalid log level %1; supported are Debug|Info|Warning|Error").arg(level))};
114 QString logfilename = Quassel::optionValue("logfile");
115 if (!logfilename.isEmpty()) {
116 _logFile.setFileName(logfilename);
117 if (!_logFile.open(QFile::Append | QFile::Unbuffered | QFile::Text)) {
118 qCritical() << qPrintable(tr("Could not open log file \"%1\": %2").arg(logfilename, _logFile.errorString()));
121 if (!_logFile.isOpen()) {
122 if (!_logFile.open(stderr, QFile::WriteOnly | QFile::Unbuffered | QFile::Text)) {
123 qCritical() << qPrintable(tr("Cannot write to stderr: %1").arg(_logFile.errorString()));
128 _syslogEnabled = Quassel::isOptionSet("syslog");
130 // set up options, program name, and facility for later calls to syslog(3)
132 openlog("quasselcore", LOG_PID, LOG_USER);
137 // Now that we've setup our logging backends, output pending messages
138 for (auto&& message : _messages) {
139 outputMessage(message);
141 if (!_keepMessages) {
146 void Logger::messageHandler(QtMsgType type, const QMessageLogContext&, const QString& message)
148 Quassel::instance()->logger()->handleMessage(type, message);
151 void Logger::handleMessage(QtMsgType type, const QString& msg)
155 handleMessage(LogLevel::Debug, msg);
158 handleMessage(LogLevel::Info, msg);
161 handleMessage(LogLevel::Warning, msg);
164 handleMessage(LogLevel::Error, msg);
167 handleMessage(LogLevel::Fatal, msg);
172 void Logger::handleMessage(LogLevel level, const QString& msg)
174 // Use signal connection to make this method thread-safe
175 emit messageLogged({QDateTime::currentDateTime(), level, msg});
178 void Logger::onMessageLogged(const LogEntry& message)
181 _messages.push_back(message);
184 // If setup() wasn't called yet, just store the message - will be output later
186 outputMessage(message);
190 void Logger::outputMessage(const LogEntry& message)
192 if (message.logLevel < _outputLevel) {
197 if (_syslogEnabled) {
199 switch (message.logLevel) {
200 case LogLevel::Debug:
206 case LogLevel::Warning:
209 case LogLevel::Error:
212 case LogLevel::Fatal:
215 syslog(prio, "%s", qPrintable(message.message));
219 if (!_logFile.fileName().isEmpty() || !_syslogEnabled) {
220 _logFile.write(msgWithTime(message));
224 // For fatal messages, write log to dump file
225 if (message.logLevel == LogLevel::Fatal) {
226 QFile dumpFile{Quassel::instance()->coreDumpFileName()};
227 if (dumpFile.open(QIODevice::Append)) {
228 dumpFile.write(msgWithTime(message));