diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 6c2dcb6d292..8b1a78d634f 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -195,7 +195,7 @@ jobs: run: >- cmake -G "${{ matrix.cmake_generator }}" - -DCMAKE_BUILD_TYPE=Release + -DCMAKE_BUILD_TYPE=RelWithDebInfo "-DCMAKE_PREFIX_PATH=${{ env.CMAKE_PREFIX_PATH }}" -DDEBUG_ASSERTIONS_FATAL=ON -DQt5_DIR=${{ env.QT_PATH }} ${{ matrix.cmake_args }} ${{ env.CMAKE_ARGS_EXTRA }} diff --git a/src/database/mixxxdb.cpp b/src/database/mixxxdb.cpp index c3f87d7a51a..a259411c011 100644 --- a/src/database/mixxxdb.cpp +++ b/src/database/mixxxdb.cpp @@ -1,5 +1,7 @@ #include "database/mixxxdb.h" +#include + #include "database/schemamanager.h" #include "moc_mixxxdb.cpp" #include "util/assert.h" diff --git a/src/mixxx.cpp b/src/mixxx.cpp index 3de77c1b8a0..f0ebcfc4349 100644 --- a/src/mixxx.cpp +++ b/src/mixxx.cpp @@ -178,11 +178,15 @@ MixxxMainWindow::MixxxMainWindow(QApplication* pApp, const CmdlineArgs& args) } #endif + mixxx::LogFlags logFlags = mixxx::LogFlag::LogToFile; + if (args.getDebugAssertBreak()) { + logFlags.setFlag(mixxx::LogFlag::DebugAssertBreak); + } mixxx::Logging::initialize( settingsPath, args.getLogLevel(), args.getLogFlushLevel(), - args.getDebugAssertBreak()); + logFlags); VERIFY_OR_DEBUG_ASSERT(SoundSourceProxy::registerProviders()) { qCritical() << "Failed to register any SoundSource providers"; diff --git a/src/sources/soundsourceopus.cpp b/src/sources/soundsourceopus.cpp index 9cf9eaad10d..50b25610eec 100644 --- a/src/sources/soundsourceopus.cpp +++ b/src/sources/soundsourceopus.cpp @@ -1,5 +1,7 @@ #include "sources/soundsourceopus.h" +#include + #include "audio/streaminfo.h" #include "util/logger.h" diff --git a/src/test/mixxxtest.cpp b/src/test/mixxxtest.cpp index 01af845f185..1dbcf900275 100644 --- a/src/test/mixxxtest.cpp +++ b/src/test/mixxxtest.cpp @@ -34,10 +34,10 @@ MixxxTest::ApplicationScope::ApplicationScope(int& argc, char** argv) { // Log level Debug would produce too many log messages that // might abort and fail the CI builds. mixxx::Logging::initialize( - QDir(), // No log file should be written during tests, only output to stderr + QString(), // No log file should be written during tests, only output to stderr logLevel, logLevel, - true); + mixxx::LogFlag::DebugAssertBreak); // All guessing of cover art should be done synchronously // in the same thread during tests to prevent test failures diff --git a/src/util/logging.cpp b/src/util/logging.cpp index 654ac119afc..46ea563185d 100644 --- a/src/util/logging.cpp +++ b/src/util/logging.cpp @@ -54,6 +54,45 @@ inline void writeToLog(const QByteArray& message, bool shouldPrint, } } +/// Rotate existing logfiles and get the file path of the log file to write to. +/// May return an invalid/empty QString if the log directory does not exist. +inline QString rotateLogFilesAndGetFilePath(const QString& logDirPath) { + if (logDirPath.isEmpty()) { + fprintf(stderr, "No log directory specified!\n"); + return QString(); + } + + QDir logDir(logDirPath); + if (!logDir.exists()) { + fprintf(stderr, + "Log directory %s does not exist!\n", + logDir.absolutePath().toLocal8Bit().constData()); + return QString(); + } + + QString logFilePath; + // Rotate old logfiles. + for (int i = 9; i >= 0; --i) { + const QString logFileName = (i == 0) ? QString("mixxx.log") + : QString("mixxx.log.%1").arg(i); + logFilePath = logDir.absoluteFilePath(logFileName); + if (QFileInfo::exists(logFilePath)) { + QString olderLogFilePath = + logDir.absoluteFilePath(QString("mixxx.log.%1").arg(i + 1)); + // This should only happen with number 10 + if (QFileInfo::exists(olderLogFilePath)) { + QFile::remove(olderLogFilePath); + } + if (!QFile::rename(logFilePath, olderLogFilePath)) { + fprintf(stderr, + "Error rolling over logfile %s\n", + logFilePath.toLocal8Bit().constData()); + } + } + } + return logFilePath; +} + // Debug message handler which outputs to stderr and a logfile, prepending the // thread name and log level. void MessageHandler(QtMsgType type, @@ -150,10 +189,10 @@ void MessageHandler(QtMsgType type, // static void Logging::initialize( - const QDir& logDir, + const QString& logDirPath, LogLevel logLevel, LogLevel logFlushLevel, - bool debugAssertBreak) { + LogFlags flags) { VERIFY_OR_DEBUG_ASSERT(!g_logfile.isOpen()) { // Somebody already called Logging::initialize. return; @@ -161,43 +200,23 @@ void Logging::initialize( setLogLevel(logLevel); - if (logDir.exists()) { - QString logFileName; + QString logFilePath; + if (flags.testFlag(LogFlag::LogToFile)) { + logFilePath = rotateLogFilesAndGetFilePath(logDirPath); + } - // Rotate old logfiles. - for (int i = 9; i >= 0; --i) { - if (i == 0) { - logFileName = logDir.filePath("mixxx.log"); - } else { - logFileName = logDir.filePath(QString("mixxx.log.%1").arg(i)); - } - QFileInfo logbackup(logFileName); - if (logbackup.exists()) { - QString olderlogname = - logDir.filePath(QString("mixxx.log.%1").arg(i + 1)); - // This should only happen with number 10 - if (QFileInfo::exists(olderlogname)) { - QFile::remove(olderlogname); - } - if (!QFile::rename(logFileName, olderlogname)) { - fprintf(stderr, - "Error rolling over logfile %s\n", - logFileName.toLocal8Bit().constData()); - } - } - } + if (logFilePath.isEmpty()) { + // No need to flush anything + g_logFlushLevel = LogLevel::Critical; + } else { // Since the message handler is not installed yet, we can touch s_logfile // without the lock. - g_logfile.setFileName(logFileName); + g_logfile.setFileName(logFilePath); g_logfile.open(QIODevice::WriteOnly | QIODevice::Text); g_logFlushLevel = logFlushLevel; - } else { - qInfo() << "No directory for writing a log file"; - // No need to flush anything - g_logFlushLevel = LogLevel::Critical; } - g_debugAssertBreak = debugAssertBreak; + g_debugAssertBreak = flags.testFlag(LogFlag::DebugAssertBreak); // Install the Qt message handler. qInstallMessageHandler(MessageHandler); diff --git a/src/util/logging.h b/src/util/logging.h index 98af667665f..03c9729d2ca 100644 --- a/src/util/logging.h +++ b/src/util/logging.h @@ -1,8 +1,7 @@ #ifndef MIXXX_UTIL_LOGGING_H #define MIXXX_UTIL_LOGGING_H -#include - +#include namespace mixxx { @@ -14,6 +13,14 @@ enum class LogLevel { Trace = 4, // for profiling etc. }; +enum class LogFlag { + None = 0, + LogToFile = 1, + DebugAssertBreak = 1 << 1, +}; +Q_DECLARE_FLAGS(LogFlags, LogFlag); +Q_DECLARE_OPERATORS_FOR_FLAGS(LogFlags); + constexpr LogLevel kLogLevelDefault = LogLevel::Warning; constexpr LogLevel kLogFlushLevelDefault = LogLevel::Critical; @@ -28,10 +35,10 @@ class Logging { public: // These are not thread safe. Only call them on Mixxx startup and shutdown. static void initialize( - const QDir& logDir, + const QString& logDirPath, LogLevel logLevel, LogLevel logFlushLevel, - bool debugAssertBreak); + LogFlags flags); // Sets only the loglevel without the on-disk settings. Used by mixxx-test. static void setLogLevel(LogLevel logLevel);