diff --git a/CMakeLists.txt b/CMakeLists.txt index 2fea275e62813..a437b912b051c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -54,6 +54,7 @@ option(BUILD_AUTOUPDATE "Build with autoupdate support" OFF) option(BUILD_TELEMETRY_MODULE "Build with telemetry module" ON) set(TELEMETRY_TRACK_ID "" CACHE STRING "Telemetry track id") set(CRASH_REPORT_URL "" CACHE STRING "URL where to send crash reports") +option(LOGGER_DEBUGLEVEL_ENABLED "Enable logging debug level" ON) option(BUILD_SHORTCUTS_MODULE "Build shortcuts module" ON) option(BUILD_SYSTEM_MODULE "Build system module" ON) diff --git a/build/config.h.in b/build/config.h.in index 8593743ba102b..174e4b5075770 100644 --- a/build/config.h.in +++ b/build/config.h.in @@ -46,6 +46,8 @@ #define YOUTUBE_API_KEY "${YOUTUBE_API_KEY}" +#cmakedefine LOGGER_DEBUGLEVEL_ENABLED + #cmakedefine BUILD_SHORTCUTS_MODULE #cmakedefine BUILD_SYSTEM_MODULE #cmakedefine BUILD_NETWORK_MODULE diff --git a/build/module.cmake b/build/module.cmake index 155b5c51318e1..20525f4d1f00e 100644 --- a/build/module.cmake +++ b/build/module.cmake @@ -106,6 +106,7 @@ target_include_directories(${MODULE} PUBLIC ${PROJECT_ROOT_DIR}/src/framework ${PROJECT_ROOT_DIR}/src/framework/global ${PROJECT_ROOT_DIR}/src/engraving + ${PROJECT_ROOT_DIR}/thirdparty/googletest/googletest/include ${MODULE_INCLUDE} ) diff --git a/ninja_build.sh b/ninja_build.sh index 4bfa0215d7d9d..cf4ae9ffe9c54 100755 --- a/ninja_build.sh +++ b/ninja_build.sh @@ -29,6 +29,7 @@ MUSESCORE_BUILD_NUMBER=${MUSESCORE_BUILD_NUMBER:-"12345678"} MUSESCORE_REVISION=${MUSESCORE_REVISION:-"abc123456"} MUSESCORE_TELEMETRY_ID=${MUSESCORE_TELEMETRY_ID:-""} MUSESCORE_CRASHREPORT_URL=${MUSESCORE_CRASHREPORT_URL:-""} +MUSESCORE_DEBUGLEVEL_ENABLED="OFF" MUSESCORE_BUILD_JACK=${MUSESCORE_BUILD_JACK:-"OFF"} MUSESCORE_BUILD_WEBENGINE=${MUSESCORE_BUILD_WEBENGINE:-"OFF"} MUSESCORE_BUILD_VST=${MUSESCORE_BUILD_VST:-"OFF"} @@ -71,6 +72,7 @@ function do_build() { -DMUSESCORE_REVISION="${MUSESCORE_REVISION}" \ -DTELEMETRY_TRACK_ID="${MUSESCORE_TELEMETRY_ID}" \ -DCRASH_REPORT_URL="${MUSESCORE_CRASHREPORT_URL}" \ + -DLOGGER_DEBUGLEVEL_ENABLED="${MUSESCORE_DEBUGLEVEL_ENABLED}" \ -DBUILD_JACK="${MUSESCORE_BUILD_JACK}" \ -DBUILD_VST="${MUSESCORE_BUILD_VST}" \ -DVST3_SDK_PATH="${MUSESCORE_VST3_SDK_PATH}" \ diff --git a/src/diagnostics/internal/engravingelementsprovider.cpp b/src/diagnostics/internal/engravingelementsprovider.cpp index a8d36c128e852..14679d7e8fd60 100644 --- a/src/diagnostics/internal/engravingelementsprovider.cpp +++ b/src/diagnostics/internal/engravingelementsprovider.cpp @@ -63,7 +63,7 @@ void EngravingElementsProvider::printStatistic(const std::string& title) stream << "-----------------------------------------------------\n"; stream << FORMAT("Total", 20) << VALUE(regCountTotal) << VALUE(unregCountTotal); - LOGI() << stream.str() << '\n'; + LOGD() << stream.str() << '\n'; } void EngravingElementsProvider::reg(const Ms::EngravingObject* e) @@ -110,11 +110,11 @@ mu::async::Channel EngravingElementsProvider:: void EngravingElementsProvider::checkTree(Ms::Score* score) { - LOGI() << "\n\n\n"; - LOGI() << "========================"; + LOGD() << "\n\n\n"; + LOGD() << "========================"; checkObjectTree(score->rootItem()); - LOGI() << "========================"; + LOGD() << "========================"; // LOGI() << "dumpTree:"; // int level = 0; // dumpTree(m_masterScore->rootItem(), level); @@ -136,10 +136,10 @@ void EngravingElementsProvider::dumpTree(const Ms::EngravingItem* item, int& lev ++level; QString gap; gap.fill(' ', level); - LOGI() << gap << item->name(); + LOGD() << gap << item->name(); for (const Ms::EngravingObject* ch : item->children()) { if (!ch->isEngravingItem()) { - LOGI() << "[" << item->name() << ": not item ch: " << ch->name(); + LOGD() << "[" << item->name() << ": not item ch: " << ch->name(); continue; } dumpTree(static_cast(ch), level); @@ -152,7 +152,7 @@ void EngravingElementsProvider::dumpTreeTree(const Ms::EngravingObject* obj, int ++level; QString gap; gap.fill(' ', level); - LOGI() << gap << obj->name(); + LOGD() << gap << obj->name(); for (int i = 0; i < obj->scanChildCount(); ++i) { const Ms::EngravingObject* ch = obj->scanChild(i); dumpTreeTree(ch, level); @@ -169,24 +169,24 @@ void EngravingElementsProvider::checkObjectTree(const Ms::EngravingObject* obj) Ms::EngravingObject* p1 = obj->parent(true); Ms::EngravingObject* p2 = obj->scanParent(); if (p1 && p2 && p1 != p2) { - LOGI() << "obj: " << obj->name(); - LOGE() << "parents is differens, p1: " << p1->name() << ", p2: " << p2->name(); + LOGD() << "obj: " << obj->name(); + LOGD() << "parents is differens, p1: " << p1->name() << ", p2: " << p2->name(); } size_t ch1 = obj->children().size(); size_t ch2 = obj->scanChildCount(); if (ch1 != ch2) { - LOGI() << "obj: " << obj->name(); - LOGE() << "chcount is differens, ch1: " << ch1 << ", ch2: " << ch2; + LOGD() << "obj: " << obj->name(); + LOGD() << "chcount is differens, ch1: " << ch1 << ", ch2: " << ch2; - LOGI() << "children1:"; + LOGD() << "children1:"; for (size_t i = 0; i < obj->children().size(); ++i) { - LOGI() << i << ": " << obj->children().at(i)->name(); + LOGD() << i << ": " << obj->children().at(i)->name(); } - LOGI() << "children2:"; + LOGD() << "children2:"; for (int i = 0; i < obj->scanChildCount(); ++i) { - LOGI() << i << ": " << obj->scanChild(i)->name(); + LOGD() << i << ": " << obj->scanChild(i)->name(); } } diff --git a/src/engraving/infrastructure/io/mscreader.cpp b/src/engraving/infrastructure/io/mscreader.cpp index f1854d67b62c3..44310e9f782c0 100644 --- a/src/engraving/infrastructure/io/mscreader.cpp +++ b/src/engraving/infrastructure/io/mscreader.cpp @@ -228,7 +228,7 @@ bool MscReader::ZipReader::open(QIODevice* device, const QString& filePath) if (!m_device->isOpen()) { if (!m_device->open(QIODevice::ReadOnly)) { - LOGE() << "failed open file: " << filePath; + LOGD() << "failed open file: " << filePath; return false; } } @@ -268,7 +268,7 @@ QStringList MscReader::ZipReader::fileList() const QStringList files; QVector fileInfoList = m_zip->fileInfoList(); if (m_zip->status() != MQZipReader::NoError) { - LOGE() << "failed read meta, status: " << m_zip->status(); + LOGD() << "failed read meta, status: " << m_zip->status(); } for (const MQZipReader::FileInfo& fi : fileInfoList) { @@ -288,7 +288,7 @@ QByteArray MscReader::ZipReader::fileData(const QString& fileName) const QByteArray data = m_zip->fileData(fileName); if (m_zip->status() != MQZipReader::NoError) { - LOGE() << "failed read data, status: " << m_zip->status(); + LOGD() << "failed read data, status: " << m_zip->status(); return QByteArray(); } return data; @@ -304,7 +304,7 @@ bool MscReader::DirReader::open(QIODevice* device, const QString& filePath) m_rootPath = QFileInfo(filePath).absolutePath(); if (!QFileInfo::exists(m_rootPath)) { - LOGE() << "not exists path: " << m_rootPath; + LOGD() << "not exists path: " << m_rootPath; return false; } @@ -347,7 +347,7 @@ QByteArray MscReader::DirReader::fileData(const QString& fileName) const QString filePath = m_rootPath + "/" + fileName; QFile file(filePath); if (!file.open(QIODevice::ReadOnly)) { - LOGE() << "failed open file: " << filePath; + LOGD() << "failed open file: " << filePath; return QByteArray(); } @@ -365,7 +365,7 @@ bool MscReader::XmlFileReader::open(QIODevice* device, const QString& filePath) if (!m_device->isOpen()) { if (!m_device->open(QIODevice::ReadOnly)) { - LOGE() << "failed open file: " << filePath; + LOGD() << "failed open file: " << filePath; return false; } } diff --git a/src/framework/audio/internal/synthesizers/fluidsynth/fluidsynth.cpp b/src/framework/audio/internal/synthesizers/fluidsynth/fluidsynth.cpp index 559db40242146..96d912a3ac761 100644 --- a/src/framework/audio/internal/synthesizers/fluidsynth/fluidsynth.cpp +++ b/src/framework/audio/internal/synthesizers/fluidsynth/fluidsynth.cpp @@ -298,7 +298,7 @@ bool FluidSynth::handleEvent(const Event& e) ret = fluid_synth_pitch_bend(m_fluid->synth, e.channel(), e.data()); } break; default: { - LOGW() << "not supported event type: " << e.opcodeString(); + LOGD() << "not supported event type: " << e.opcodeString(); ret = FLUID_FAILED; } } diff --git a/src/framework/global/CMakeLists.txt b/src/framework/global/CMakeLists.txt index bc74fa90fa13f..f9d0d76b87124 100644 --- a/src/framework/global/CMakeLists.txt +++ b/src/framework/global/CMakeLists.txt @@ -47,6 +47,8 @@ set(MODULE_SRC ${CMAKE_CURRENT_LIST_DIR}/io/device.h ${CMAKE_CURRENT_LIST_DIR}/log.h ${CMAKE_CURRENT_LIST_DIR}/logstream.h + ${CMAKE_CURRENT_LIST_DIR}/logremover.cpp + ${CMAKE_CURRENT_LIST_DIR}/logremover.h ${CMAKE_CURRENT_LIST_DIR}/dataformatter.cpp ${CMAKE_CURRENT_LIST_DIR}/dataformatter.h ${CMAKE_CURRENT_LIST_DIR}/id.cpp diff --git a/src/framework/global/globalmodule.cpp b/src/framework/global/globalmodule.cpp index 9cdf2d95c3c77..f3d0bb4c95713 100644 --- a/src/framework/global/globalmodule.cpp +++ b/src/framework/global/globalmodule.cpp @@ -28,6 +28,7 @@ #include "internal/globalconfiguration.h" #include "log.h" +#include "logremover.h" #include "thirdparty/haw_logger/logger/logdefdest.h" #include "version.h" @@ -80,6 +81,10 @@ void GlobalModule::onInit(const IApplication::RunMode&) io::path logPath = s_globalConf->userAppDataPath() + "/logs"; fileSystem()->makePath(logPath); + + //! Remove old logs + LogRemover::removeLogs(logPath, 7, "MuseScore_yyMMdd_HHmmss.log"); + //! File, this creates a file named "data/logs/MuseScore_yyMMdd_HHmmss.log" io::path logFilePath = logPath + "/MuseScore_" + QDateTime::currentDateTime().toString("yyMMdd_HHmmss") @@ -91,8 +96,10 @@ void GlobalModule::onInit(const IApplication::RunMode&) LOGI() << "log path: " << logFile->filePath(); logger->addDest(logFile); -#ifndef NDEBUG +#ifdef LOGGER_DEBUGLEVEL_ENABLED logger->setLevel(haw::logger::Debug); +#else + logger->setLevel(haw::logger::Normal); #endif LOGI() << "=== Started MuseScore " << framework::Version::fullVersion() << " ==="; diff --git a/src/framework/global/logremover.cpp b/src/framework/global/logremover.cpp new file mode 100644 index 0000000000000..a7753e351de99 --- /dev/null +++ b/src/framework/global/logremover.cpp @@ -0,0 +1,94 @@ +/* + * SPDX-License-Identifier: GPL-3.0-only + * MuseScore-CLA-applies + * + * MuseScore + * Music Composition & Notation + * + * Copyright (C) 2021 MuseScore BVBA and others + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include "logremover.h" + +#include +#include + +using namespace mu; + +void LogRemover::removeLogs(const io::path& logsDir, int olderThanDays, const QString& pattern) +{ + //! NOTE If the pattern changes, + //! then we need to change the implementation of `scanDir` and `parseDate` functions. + Q_ASSERT(pattern == "MuseScore_yyMMdd_HHmmss.log"); + if (pattern != "MuseScore_yyMMdd_HHmmss.log") { + return; + } + + QStringList files; + scanDir(logsDir, files); + + QDate currentDate = QDate::currentDate(); + + QStringList toRemoveFiles; + for (const QString& file : files) { + QDate date = parseDate(file); + if (!date.isValid()) { + continue; + } + + int days = date.daysTo(currentDate); + if (days >= olderThanDays) { + toRemoveFiles << file; + } + } + + removeFiles(toRemoveFiles); +} + +QDate LogRemover::parseDate(const QString& fileName) +{ + int endIdx = fileName.lastIndexOf('_'); + if (endIdx == -1) { + return QDate(); + } + + int startIdx = fileName.lastIndexOf('_', endIdx - 1); + if (startIdx == -1) { + return QDate(); + } + + QString dateStr = fileName.mid(startIdx + 1, (endIdx - startIdx - 1)); + QDate date = QDate::fromString(dateStr, "yyMMdd"); + + //! NOTE We get `1921`, but it should be `2021` + if (date.year() < 2000) { + date = date.addYears(100); + } + return date; +} + +void LogRemover::removeFiles(const QStringList& files) +{ + for (const QString& file : files) { + QFile::remove(file); + } +} + +void LogRemover::scanDir(const io::path& logsDir, QStringList& files) +{ + QDirIterator it(logsDir.toQString(), { "*.log" }, QDir::NoDotAndDotDot | QDir::NoSymLinks | QDir::Readable | QDir::Files); + while (it.hasNext()) { + files.push_back(it.next()); + } +} diff --git a/src/framework/global/logremover.h b/src/framework/global/logremover.h new file mode 100644 index 0000000000000..872e1dc9fcb62 --- /dev/null +++ b/src/framework/global/logremover.h @@ -0,0 +1,49 @@ +/* + * SPDX-License-Identifier: GPL-3.0-only + * MuseScore-CLA-applies + * + * MuseScore + * Music Composition & Notation + * + * Copyright (C) 2021 MuseScore BVBA and others + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#ifndef MU_LOGREMOVER_H +#define MU_LOGREMOVER_H + +#include +#include + +#include + +#include "io/path.h" + +namespace mu { +class LogRemover +{ +public: + + static void removeLogs(const io::path& logsDir, int olderThanDays, const QString& pattern); + +private: + + FRIEND_TEST(LogRemoverTests, ParseDate); + + static void scanDir(const io::path& logsDir, QStringList& files); + static QDate parseDate(const QString& fileName); + static void removeFiles(const QStringList& files); +}; +} + +#endif // MU_LOGREMOVER_H diff --git a/src/framework/global/tests/CMakeLists.txt b/src/framework/global/tests/CMakeLists.txt index 6861c5ec34442..a5016f08efb12 100644 --- a/src/framework/global/tests/CMakeLists.txt +++ b/src/framework/global/tests/CMakeLists.txt @@ -23,6 +23,7 @@ set(MODULE_TEST global_tests) set(MODULE_TEST_SRC ${CMAKE_CURRENT_LIST_DIR}/uri_tests.cpp ${CMAKE_CURRENT_LIST_DIR}/val_tests.cpp + ${CMAKE_CURRENT_LIST_DIR}/logremover_tests.cpp ) include(${PROJECT_SOURCE_DIR}/src/framework/testing/gtest.cmake) diff --git a/src/framework/global/tests/logremover_tests.cpp b/src/framework/global/tests/logremover_tests.cpp new file mode 100644 index 0000000000000..f52f6c4e7a857 --- /dev/null +++ b/src/framework/global/tests/logremover_tests.cpp @@ -0,0 +1,41 @@ +/* + * SPDX-License-Identifier: GPL-3.0-only + * MuseScore-CLA-applies + * + * MuseScore + * Music Composition & Notation + * + * Copyright (C) 2021 MuseScore BVBA and others + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include + +#include "logremover.h" + +namespace mu { +class LogRemoverTests : public ::testing::Test +{ +public: +}; + +TEST_F(LogRemoverTests, ParseDate) +{ + EXPECT_EQ(LogRemover::parseDate("path/to/logs/MuseScore_210629_154033.log"), QDate(2021, 6, 29)); + EXPECT_EQ(LogRemover::parseDate("path/to_to/logs/MuseScore_210709_154033.log"), QDate(2021, 7, 9)); + EXPECT_EQ(LogRemover::parseDate("path/to/logs/MuseScore_210709__154033.log"), QDate()); + EXPECT_EQ(LogRemover::parseDate("path/to/logs/MuseScore_210709_154033_.log"), QDate()); + EXPECT_EQ(LogRemover::parseDate("path/to/logs/MuseScore_210709_154033-.log"), QDate(2021, 7, 9)); +} +}