From 516df202d4aa1ae620907fed0cbf395731716e5c Mon Sep 17 00:00:00 2001 From: houchengqiu Date: Wed, 25 Oct 2023 17:48:05 +0800 Subject: [PATCH] feat: Command line export by condition Command line export by condition Log: Command line export by condition --- application/cliapplicationhelper.cpp | 3 - application/dbusproxy/dldbushandler.cpp | 2 +- application/displaycontent.cpp | 17 +- application/journalwork.cpp | 19 +- application/logauththread.cpp | 181 ++-- application/logbackend.cpp | 1153 ++++++++++++++++++++++- application/logbackend.h | 195 +++- application/logfileparser.cpp | 1 + application/main.cpp | 106 ++- application/structdef.h | 14 + application/utils.cpp | 77 +- application/utils.h | 5 +- logViewerService/logviewerservice.cpp | 48 +- translations/deepin-log-viewer.ts | 24 + 14 files changed, 1672 insertions(+), 173 deletions(-) diff --git a/application/cliapplicationhelper.cpp b/application/cliapplicationhelper.cpp index e59b898f..0b05d775 100644 --- a/application/cliapplicationhelper.cpp +++ b/application/cliapplicationhelper.cpp @@ -142,12 +142,9 @@ bool CliApplicationHelper::setSingleInstance(const QString &key, CliApplicationH if (!_d_singleServer->listen(socket_key)) { qCWarning(dgAppHelper) << "listen failed:" << _d_singleServer->errorString(); return false; - } else { - qCDebug(dgAppHelper) << "===> listen <===" << _d_singleServer->serverName() << getpid(); } if (new_server) { - qCDebug(dgAppHelper) << "===> new server <===" << _d_singleServer->serverName() << getpid(); QObject::connect(_d_singleServer, &QLocalServer::newConnection, qApp, [] { QLocalSocket *instance = _d_singleServer->nextPendingConnection(); // 先发送数据告诉新的实例自己收到了它的请求 diff --git a/application/dbusproxy/dldbushandler.cpp b/application/dbusproxy/dldbushandler.cpp index bc712503..74b25881 100644 --- a/application/dbusproxy/dldbushandler.cpp +++ b/application/dbusproxy/dldbushandler.cpp @@ -39,7 +39,7 @@ DLDBusHandler::DLDBusHandler(QObject *parent) if (!m_dbus->isValid() && !m_dbus->lastError().message().isEmpty()) { qCCritical(logDBusHandler) << "dbus com.deepin.logviewer isValid false error:" << m_dbus->lastError() << m_dbus->lastError().message(); } - qCInfo(logDBusHandler) << "dbus com.deepin.logviewer isValid true"; + qCDebug(logDBusHandler) << "dbus com.deepin.logviewer isValid true"; } /*! diff --git a/application/displaycontent.cpp b/application/displaycontent.cpp index 6ab5f2cc..b6d7c561 100644 --- a/application/displaycontent.cpp +++ b/application/displaycontent.cpp @@ -1157,22 +1157,11 @@ void DisplayContent::insertJournalTable(QList logList, int star */ QString DisplayContent::getAppName(const QString &filePath) { - QString ret; - if (filePath.isEmpty()) - return ret; - QStringList strList = filePath.split("/"); - if (strList.count() < 2) { - if (filePath.contains(".")) - ret = filePath.section(".", 0, 0); - else { - ret = filePath; - } - return LogApplicationHelper::instance()->transName(ret); - } + QString ret = Utils::appName(filePath); + if (ret.isEmpty()) + return ret; - QString desStr = filePath.section("/", -1); - ret = desStr.mid(0, desStr.lastIndexOf(".")); return LogApplicationHelper::instance()->transName(ret); } diff --git a/application/journalwork.cpp b/application/journalwork.cpp index 83ac5d10..fa7f5902 100644 --- a/application/journalwork.cpp +++ b/application/journalwork.cpp @@ -231,10 +231,23 @@ void journalWork::doWork() //获取进程名 r = sd_journal_get_data(j, "SYSLOG_IDENTIFIER", reinterpret_cast(&d), &l); if (r < 0) { - logMsg.daemonName = "unknown"; - qCWarning(logJournal) << logMsg.daemonId << "error code" << r; + r = sd_journal_get_data(j, "_EXE", reinterpret_cast(&d), &l); + if (r >= 0) { + QStringList strList = getReplaceColorStr(d).split("="); + strList.removeFirst(); + QFileInfo fi(strList.first()); + if (fi.exists()) + logMsg.daemonName = fi.fileName(); + else { + qCWarning(logJournal) << "unknown progressname, exe path: " << strList.first(); + logMsg.daemonName = "unknown"; + } + } else { + qCWarning(logJournal) << logMsg.daemonId << "error code" << r; + logMsg.daemonName = "unknown"; + } } else { - QStringList strList = getReplaceColorStr(d).split("="); + QStringList strList = getReplaceColorStr(d).split("="); strList.removeFirst(); logMsg.daemonName = strList.join("="); } diff --git a/application/logauththread.cpp b/application/logauththread.cpp index 2d760615..68268e74 100644 --- a/application/logauththread.cpp +++ b/application/logauththread.cpp @@ -103,15 +103,17 @@ void LogAuthThread::stopProccess() m_isStopProccess = true; //停止获取线程执行,标记量置false m_canRun = false; - //共享内存数据结构,用于和获取进程共享内存,数据为是否可执行进程,用于控制数据获取进程停止,因为这里会出现需要提权执行的进程,主进程没有权限停止提权进程,所以使用共享内存变量标记量控制提权进程停止 - ShareMemoryInfo shareInfo ; - //设置进程为不可执行 - shareInfo.isStart = false; - //把数据付给共享内存中对应的变量 - SharedMemoryManager::instance()->setRunnableTag(shareInfo); + if (!Utils::runInCmd) { + //共享内存数据结构,用于和获取进程共享内存,数据为是否可执行进程,用于控制数据获取进程停止,因为这里会出现需要提权执行的进程,主进程没有权限停止提权进程,所以使用共享内存变量标记量控制提权进程停止 + ShareMemoryInfo shareInfo ; + //设置进程为不可执行 + shareInfo.isStart = false; + //把数据付给共享内存中对应的变量 + SharedMemoryManager::instance()->setRunnableTag(shareInfo); + } if (m_process) { m_process->kill(); - } + } } void LogAuthThread::setFilePath(const QStringList &filePath) @@ -206,20 +208,24 @@ void LogAuthThread::handleBoot() if (!m_canRun) { return; } - initProccess(); - m_process->setProcessChannelMode(QProcess::MergedChannels); - //共享内存对应变量置true,允许进程内部逻辑运行 - ShareMemoryInfo shareInfo; - shareInfo.isStart = true; - SharedMemoryManager::instance()->setRunnableTag(shareInfo); - //启动日志需要提权获取,运行的时候把对应共享内存的名称传进去,方便获取进程拿标记量判断是否继续运行 - m_process->start("pkexec", QStringList() << "logViewerAuth" - << m_FilePath.at(i) << SharedMemoryManager::instance()->getRunnableKey()); - m_process->waitForFinished(-1); - if (m_process->exitCode() != 0) { - emit bootFinished(m_threadCount); - return; + + if (!Utils::runInCmd) { + initProccess(); + m_process->setProcessChannelMode(QProcess::MergedChannels); + //共享内存对应变量置true,允许进程内部逻辑运行 + ShareMemoryInfo shareInfo; + shareInfo.isStart = true; + SharedMemoryManager::instance()->setRunnableTag(shareInfo); + //启动日志需要提权获取,运行的时候把对应共享内存的名称传进去,方便获取进程拿标记量判断是否继续运行 + m_process->start("pkexec", QStringList() << "logViewerAuth" + << m_FilePath.at(i) << SharedMemoryManager::instance()->getRunnableKey()); + m_process->waitForFinished(-1); + if (m_process->exitCode() != 0) { + emit bootFinished(m_threadCount); + return; + } } + QString byte = DLDBusHandler::instance(this)->readLog(m_FilePath.at(i)); byte.replace('\u0000', "").replace("\x01", ""); QStringList strList = byte.split('\n', QString::SkipEmptyParts); @@ -284,27 +290,31 @@ void LogAuthThread::handleKern() if (!m_canRun) { return; } - initProccess(); - if (!m_canRun) { - return; - } - m_process->setProcessChannelMode(QProcess::MergedChannels); - if (!m_canRun) { - return; - } - //共享内存对应变量置true,允许进程内部逻辑运行 - ShareMemoryInfo shareInfo; - shareInfo.isStart = true; - SharedMemoryManager::instance()->setRunnableTag(shareInfo); - //启动日志需要提权获取,运行的时候把对应共享内存的名称传进去,方便获取进程拿标记量判断是否继续运行 - m_process->start("pkexec", QStringList() << "logViewerAuth" - << m_FilePath.at(i) << SharedMemoryManager::instance()->getRunnableKey()); - m_process->waitForFinished(-1); - //有错则传出空数据 - if (m_process->exitCode() != 0) { - emit kernFinished(m_threadCount); - return; + + if (!Utils::runInCmd) { + initProccess(); + if (!m_canRun) { + return; + } + m_process->setProcessChannelMode(QProcess::MergedChannels); + if (!m_canRun) { + return; + } + //共享内存对应变量置true,允许进程内部逻辑运行 + ShareMemoryInfo shareInfo; + shareInfo.isStart = true; + SharedMemoryManager::instance()->setRunnableTag(shareInfo); + //启动日志需要提权获取,运行的时候把对应共享内存的名称传进去,方便获取进程拿标记量判断是否继续运行 + m_process->start("pkexec", QStringList() << "logViewerAuth" + << m_FilePath.at(i) << SharedMemoryManager::instance()->getRunnableKey()); + m_process->waitForFinished(-1); + //有错则传出空数据 + if (m_process->exitCode() != 0) { + emit kernFinished(m_threadCount); + return; + } } + if (!m_canRun) { return; } @@ -924,40 +934,43 @@ void LogAuthThread::handleAudit() if (!m_canRun) { return; } - initProccess(); - if (!m_canRun) { - return; - } - m_process->setProcessChannelMode(QProcess::MergedChannels); - if (!m_canRun) { - return; - } - if (DBusManager::isSEOepn()) { - if (DBusManager::isAuditAdmin()) { - // 是审计管理员,需要鉴权,有错则传出空数据 - if (!Utils::checkAuthorization("com.deepin.pkexec.logViewerAuth.self", QCoreApplication::instance()->applicationPid())) { - emit auditFinished(m_threadCount); - return; - } - } else { - // 不是审计管理员,给出提示 - emit auditFinished(m_threadCount, true); + if (!Utils::runInCmd) { + initProccess(); + if (!m_canRun) { return; } - } else { - // 未开启等保四,鉴权逻辑同内核日志 - ShareMemoryInfo shareInfo; - shareInfo.isStart = true; - SharedMemoryManager::instance()->setRunnableTag(shareInfo); - //启动日志需要提权获取,运行的时候把对应共享内存的名称传进去,方便获取进程拿标记量判断是否继续运行 - m_process->start("pkexec", QStringList() << "logViewerAuth" - << m_FilePath.at(i) << SharedMemoryManager::instance()->getRunnableKey()); - m_process->waitForFinished(-1); - if (m_process->exitCode() != 0) { - emit auditFinished(m_threadCount); + m_process->setProcessChannelMode(QProcess::MergedChannels); + if (!m_canRun) { return; } + + if (DBusManager::isSEOepn()) { + if (DBusManager::isAuditAdmin()) { + // 是审计管理员,需要鉴权,有错则传出空数据 + if (!Utils::checkAuthorization("com.deepin.pkexec.logViewerAuth.self", QCoreApplication::instance()->applicationPid())) { + emit auditFinished(m_threadCount); + return; + } + } else { + // 不是审计管理员,给出提示 + emit auditFinished(m_threadCount, true); + return; + } + } else { + // 未开启等保四,鉴权逻辑同内核日志 + ShareMemoryInfo shareInfo; + shareInfo.isStart = true; + SharedMemoryManager::instance()->setRunnableTag(shareInfo); + //启动日志需要提权获取,运行的时候把对应共享内存的名称传进去,方便获取进程拿标记量判断是否继续运行 + m_process->start("pkexec", QStringList() << "logViewerAuth" + << m_FilePath.at(i) << SharedMemoryManager::instance()->getRunnableKey()); + m_process->waitForFinished(-1); + if (m_process->exitCode() != 0) { + emit auditFinished(m_threadCount); + return; + } + } } if (!m_canRun) { @@ -1149,13 +1162,20 @@ void LogAuthThread::handleCoredump() } QList coredumpList; + QString byte; initProccess(); - m_process->start("pkexec", QStringList() << "logViewerAuth" << - QStringList() << "coredumpctl-list" << SharedMemoryManager::instance()->getRunnableKey()); - m_process->waitForFinished(-1); + if (Utils::runInCmd) { + byte = DLDBusHandler::instance()->readLog("coredump"); + byte = byte.replace('\u0000', "").replace("\x01", ""); + } else { + m_process->start("pkexec", QStringList() << "logViewerAuth" << + QStringList() << "coredumpctl-list" << SharedMemoryManager::instance()->getRunnableKey()); + m_process->waitForFinished(-1); + QByteArray outByte = m_process->readAllStandardOutput(); + byte = Utils::replaceEmptyByteArray(outByte); + } - QByteArray outByte = m_process->readAllStandardOutput(); - QStringList strList = QString(Utils::replaceEmptyByteArray(outByte)).split('\n', QString::SkipEmptyParts); + QStringList strList = QString(byte).split('\n', QString::SkipEmptyParts); QRegExp re("(Storage: )\\S+"); for (int i = strList.size() - 1; i >= 0 ; --i) { @@ -1194,10 +1214,15 @@ void LogAuthThread::handleCoredump() // 解析coredump文件保存位置 if (coredumpMsg.coreFile != "missing") { // 若coreFile状态为missing,表示文件已丢失,不继续解析文件位置 - m_process->start("pkexec", QStringList() << "logViewerAuth" << QStringList() << "coredumpctl-info" - << coredumpMsg.pid <getRunnableKey()); - m_process->waitForFinished(-1); - QByteArray outInfoByte = m_process->readAllStandardOutput(); + QString outInfoByte; + if (Utils::runInCmd) { + outInfoByte = DLDBusHandler::instance()->readLog(QString("coredumpctl info %1").arg(coredumpMsg.pid)); + } else { + m_process->start("pkexec", QStringList() << "logViewerAuth" << QStringList() << "coredumpctl-info" + << coredumpMsg.pid <getRunnableKey()); + m_process->waitForFinished(-1); + outInfoByte = m_process->readAllStandardOutput(); + } re.indexIn(outInfoByte); coredumpMsg.storagePath = re.cap(0).replace("Storage: ", ""); } else { diff --git a/application/logbackend.cpp b/application/logbackend.cpp index 2e9f3d9b..00c354de 100644 --- a/application/logbackend.cpp +++ b/application/logbackend.cpp @@ -4,12 +4,13 @@ #include "logbackend.h" #include "logallexportthread.h" +#include "logfileparser.h" +#include "logexportthread.h" #include "utils.h" #include "dbusmanager.h" #include "dbusproxy/dldbushandler.h" #include "logapplicationhelper.h" #include "DebugTimeManager.h" - #include #include @@ -18,6 +19,7 @@ #include #include #include +#include #ifdef QT_DEBUG Q_LOGGING_CATEGORY(logBackend, "org.deepin.log.viewer.backend") @@ -97,7 +99,7 @@ void LogBackend::exportAllLogs(const QString &outDir) }); QThreadPool::globalInstance()->start(thread); - resetToNormalAuth(m_outPath); + Utils::resetToNormalAuth(m_outPath); } void LogBackend::exportTypeLogs(const QString &outDir, const QString &type) @@ -339,10 +341,35 @@ void LogBackend::exportTypeLogs(const QString &outDir, const QString &type) break; } - resetToNormalAuth(tmpCategoryOutPath); + Utils::resetToNormalAuth(tmpCategoryOutPath); +} + +bool LogBackend::LogBackend::exportTypeLogsByCondition(const QString &outDir, const QString &type, const QString &period, const QString &condition, const QString &keyword) +{ + if (!getOutDirPath(outDir)) + return false; + + // 日志种类有效性验证 + QString error; + m_flag = type2Flag(type, error); + if (NONE == m_flag) { + qCInfo(logBackend) << error; + return false; + } + + m_currentSearchStr = keyword; + + // 解析数据 + if (!parseData(m_flag, period, condition)) { + qCWarning(logBackend) << QString("parse data failed."); + return false; + } + + m_bNeedExport = true; + return true; } -void LogBackend::exportLogsByApp(const QString &outDir, const QString &appName) +void LogBackend::exportAppLogs(const QString &outDir, const QString &appName) { if(!getOutDirPath(outDir)) return; @@ -400,7 +427,64 @@ void LogBackend::exportLogsByApp(const QString &outDir, const QString &appName) DLDBusHandler::instance()->exportLog(tmpCategoryOutPath, "journalctl_app", false); } - resetToNormalAuth(tmpCategoryOutPath); + Utils::resetToNormalAuth(tmpCategoryOutPath); +} + +bool LogBackend::exportAppLogsByCondition(const QString &outDir, const QString &appName, const QString &period, const QString &level, const QString &keyword) +{ + if(!getOutDirPath(outDir)) + return false; + + if (appName.isEmpty()) + return false; + + // 周期类型有效性验证 + BUTTONID periodId = ALL; + if (!period.isEmpty()) { + periodId = period2Enum(period); + if (INVALID == periodId) { + qCWarning(logBackend) << "invalid period parameter: " << period; + return false; + } + } + + qCInfo(logBackend) << "period:" << period << "level:" << level << "keyword:" << keyword; + + TIME_RANGE timeRange = getTimeRange(periodId); + + // 先查找是否有该应用相关日志 + QString logPath; + QMap appData = LogApplicationHelper::instance()->getMap(); + for (auto &it2 : appData.toStdMap()) { + if (it2.second.contains(appName)) { + logPath = it2.second; + break; + } + } + + if (logPath.isEmpty()) { + qCInfo(logBackend) << QString("unknown app:%1 is invalid.").arg(appName); + return false; + } + + // 解析器准备工作 + initParser(); + if (!m_pParser) + return false; + + m_flag = APP; + m_curAppLog = logPath; + m_bNeedExport = true; + m_currentSearchStr = keyword; + + APP_FILTERS appFilter; + appFilter.path = logPath; + appFilter.lvlFilter = level2Id(level); + appFilter.timeFilterBegin = timeRange.begin; + appFilter.timeFilterEnd = timeRange.end; + m_appCurrentIndex = m_pParser->parseByApp(appFilter); + + return true; } QStringList LogBackend::getLogTypes() @@ -466,6 +550,864 @@ QStringList LogBackend::getLogTypes() return m_logTypes; } +void LogBackend::slot_dpkgFinished(int index) +{ + if (m_flag != DPKG || index != m_dpkgCurrentIndex) + return; + m_isDataLoadComplete = true; + + if (m_bNeedExport) { + exportData(); + } +} + +void LogBackend::slot_dpkgData(int index, QList list) +{ + if (m_flag != DPKG || index != m_dpkgCurrentIndex) + return; + + dListOrigin.append(list); + dList.append(filterDpkg(m_currentSearchStr, list)); +} + +void LogBackend::slot_XorgFinished(int index) +{ + if (m_flag != XORG || index != m_xorgCurrentIndex) + return; + m_isDataLoadComplete = true; + + if (m_bNeedExport) { + exportData(); + } +} + +void LogBackend::slot_xorgData(int index, QList list) +{ + if (m_flag != XORG || index != m_xorgCurrentIndex) + return; + + xListOrigin.append(list); + xList.append(filterXorg(m_currentSearchStr, list)); +} + +void LogBackend::slot_bootFinished(int index) +{ + if (m_flag != BOOT || index != m_bootCurrentIndex) + return; + m_isDataLoadComplete = true; + + if (m_bNeedExport) { + exportData(); + } +} + +void LogBackend::slot_bootData(int index, QList list) +{ + if (m_flag != BOOT || index != m_bootCurrentIndex) + return; + + bList.append(list); + currentBootList.append(filterBoot(m_bootFilter, list)); +} + +void LogBackend::slot_kernFinished(int index) +{ + if (m_flag != KERN || index != m_kernCurrentIndex) + return; + m_isDataLoadComplete = true; + + if (m_bNeedExport) { + exportData(); + } +} + +void LogBackend::slot_kernData(int index, QList list) +{ + if (m_flag != KERN || index != m_kernCurrentIndex) + return; + + kListOrigin.append(list); + kList.append(filterKern(m_currentSearchStr, list)); +} + +void LogBackend::slot_kwinFinished(int index) +{ + if (m_flag != Kwin || index != m_kwinCurrentIndex) + return; + m_isDataLoadComplete = true; + + if (m_bNeedExport) { + exportData(); + } +} + +void LogBackend::slot_kwinData(int index, QList list) +{ + if (m_flag != Kwin || index != m_kwinCurrentIndex) + return; + m_kwinList.append(list); + m_currentKwinList.append(filterKwin(m_currentSearchStr, list)); +} + +void LogBackend::slot_dnfFinished(const QList &list) +{ + if (m_flag != Dnf) + return; + dnfList = filterDnf(m_currentSearchStr, list); + dnfListOrigin = list; + + m_isDataLoadComplete = true; + + if (m_bNeedExport) { + exportData(); + } +} + +void LogBackend::slot_dmesgFinished(const QList &list) +{ + if (m_flag != Dmesg) + return; + + dmesgList = filterDmesg(m_currentSearchStr,list); + dmesgListOrigin = list; + + m_isDataLoadComplete = true; + + if (m_bNeedExport) { + exportData(); + } +} + +void LogBackend::slot_journalFinished(int index) +{ + if (m_flag != JOURNAL || index != m_journalCurrentIndex) + return; + m_isDataLoadComplete = true; + + if (m_bNeedExport) { + exportData(); + } +} + +void LogBackend::slot_journalBootFinished(int index) +{ + if (m_flag != BOOT_KLU || index != m_journalBootCurrentIndex) + return; + m_isDataLoadComplete = true; + + if (m_bNeedExport) { + exportData(); + } +} + +void LogBackend::slot_journalBootData(int index, QList list) +{ + if (m_flag != BOOT_KLU || index != m_journalBootCurrentIndex) + return; + + jBootListOrigin.append(list); + jBootList.append(filterJournalBoot(m_currentSearchStr, list)); +} + +void LogBackend::slot_journalData(int index, QList list) +{ + //判断最近一次获取数据线程的标记量,和信号曹发来的sender的标记量作对比,如果相同才可以刷新,因为会出现上次的获取线程就算停下信号也发出来了 + if (m_flag != JOURNAL || index != m_journalCurrentIndex) + return; + + jListOrigin.append(list); + jList.append(filterJournal(m_currentSearchStr, list)); +} + +void LogBackend::slot_applicationFinished(int index) +{ + if (m_flag != APP || index != m_appCurrentIndex) + return; + m_isDataLoadComplete = true; + + if (m_bNeedExport) { + exportData(); + } +} + +void LogBackend::slot_applicationData(int index, QList list) +{ + if (m_flag != APP || index != m_appCurrentIndex) + return; + + appListOrigin.append(list); + appList.append(filterApp(m_currentSearchStr, list)); +} + +void LogBackend::slot_normalFinished(int index) +{ + if (m_flag != Normal || index != m_normalCurrentIndex) + return; + m_isDataLoadComplete = true; + + if (m_bNeedExport) { + exportData(); + } +} + +void LogBackend::slot_normalData(int index, QList list) +{ + if (m_flag != Normal || index != m_normalCurrentIndex) + return; + norList.append(list); + nortempList.append(filterNomal(m_normalFilter, list)); +} + +void LogBackend::slot_auditFinished(int index, bool bShowTip) +{ + Q_UNUSED(bShowTip); + + if (m_flag != Audit || index != m_auditCurrentIndex) + return; + m_isDataLoadComplete = true; + + + if (m_bNeedExport) { + exportData(); + } +} + +void LogBackend::slot_auditData(int index, QList list) +{ + if (m_flag != Audit || index != m_auditCurrentIndex) + return; + + aListOrigin.append(list); + aList.append(filterAudit(m_auditFilter, list)); +} + +void LogBackend::slot_coredumpFinished(int index) +{ + if (m_flag != COREDUMP || index != m_coredumpCurrentIndex) + return; + + m_isDataLoadComplete = true; + + if (m_bNeedExport) { + exportData(); + } +} + +void LogBackend::slot_coredumpData(int index, QList list) +{ + if (m_flag != COREDUMP || index != m_coredumpCurrentIndex) + return; + + m_coredumpList.append(list); + m_currentCoredumpList.append(filterCoredump(m_currentSearchStr, list)); +} + +void LogBackend::slot_logLoadFailed(const QString &iError) +{ + qCWarning(logBackend) << "parse data failed. error: " << iError; + qApp->exit(-1); +} + +void LogBackend::onExportProgress(int nCur, int nTotal) +{ + Q_UNUSED(nCur); + Q_UNUSED(nTotal); +} + +void LogBackend::onExportResult(bool isSuccess) +{ + if (isSuccess) { + qCInfo(logBackend) << "export success."; + + } else { + qCWarning(logBackend) << "export failed."; + } + + Utils::resetToNormalAuth(m_outPath); + + qApp->exit(-1); +} + +QList LogBackend::filterBoot(BOOT_FILTERS ibootFilter, const QList &iList) +{ + QList rsList; + bool isStatusFilterEmpty = ibootFilter.statusFilter.isEmpty(); + if (isStatusFilterEmpty && ibootFilter.searchstr.isEmpty()) { + return iList; + } else { + for (int i = 0; i < iList.size(); i++) { + LOG_MSG_BOOT msg = iList.at(i); + QString _statusStr = msg.status; + if ((_statusStr.compare(ibootFilter.statusFilter, Qt::CaseInsensitive) != 0) && !isStatusFilterEmpty) + continue; + if ((msg.status.contains(ibootFilter.searchstr, Qt::CaseInsensitive)) || (msg.msg.contains(ibootFilter.searchstr, Qt::CaseInsensitive))) { + rsList.append(iList[i]); + } + } + } + return rsList; +} + +QList LogBackend::filterNomal(NORMAL_FILTERS inormalFilter, QList &iList) +{ + QList rsList; + if (inormalFilter.searchstr.isEmpty() && inormalFilter.eventTypeFilter < 0) { + return iList; + } + int tcbx = inormalFilter.eventTypeFilter; + if (0 == tcbx) { + for (auto i = 0; i < iList.size(); i++) { + LOG_MSG_NORMAL msg = iList.at(i); + if (msg.eventType.contains(inormalFilter.searchstr, Qt::CaseInsensitive) || msg.userName.contains(inormalFilter.searchstr, Qt::CaseInsensitive) || msg.dateTime.contains(inormalFilter.searchstr, Qt::CaseInsensitive) || msg.msg.contains(inormalFilter.searchstr, Qt::CaseInsensitive)) { + rsList.append(msg); + } + } + } else if (1 == tcbx) { + for (auto i = 0; i < iList.size(); i++) { + LOG_MSG_NORMAL msg = iList.at(i); + if (msg.eventType.contains(inormalFilter.searchstr, Qt::CaseInsensitive) || msg.userName.contains(inormalFilter.searchstr, Qt::CaseInsensitive) || msg.dateTime.contains(inormalFilter.searchstr, Qt::CaseInsensitive) || msg.msg.contains(inormalFilter.searchstr, Qt::CaseInsensitive)) { + if (msg.eventType.compare("Boot", Qt::CaseInsensitive) != 0 && msg.eventType.compare("shutdown", Qt::CaseInsensitive) != 0 && msg.eventType.compare("runlevel", Qt::CaseInsensitive) != 0) + rsList.append(msg); + } + } + } else if (2 == tcbx) { + for (auto i = 0; i < iList.size(); i++) { + LOG_MSG_NORMAL msg = iList.at(i); + if (msg.eventType.contains(inormalFilter.searchstr, Qt::CaseInsensitive) || msg.userName.contains(inormalFilter.searchstr, Qt::CaseInsensitive) || msg.dateTime.contains(inormalFilter.searchstr, Qt::CaseInsensitive) || msg.msg.contains(inormalFilter.searchstr, Qt::CaseInsensitive)) { + if (iList[i].eventType.compare("Boot", Qt::CaseInsensitive) == 0) + rsList.append(iList[i]); + } + } + } else if (3 == tcbx) { + for (auto i = 0; i < iList.size(); i++) { + LOG_MSG_NORMAL msg = iList.at(i); + if (msg.eventType.contains(inormalFilter.searchstr, Qt::CaseInsensitive) || msg.userName.contains(inormalFilter.searchstr, Qt::CaseInsensitive) || msg.dateTime.contains(inormalFilter.searchstr, Qt::CaseInsensitive) || msg.msg.contains(inormalFilter.searchstr, Qt::CaseInsensitive)) { + if (iList[i].eventType.compare("shutdown", Qt::CaseInsensitive) == 0) + rsList.append(iList[i]); + } + } + } + return rsList; +} + +QList LogBackend::filterDpkg(const QString &iSearchStr, const QList &iList) +{ + QList rsList; + if (iSearchStr.isEmpty()) { + return iList; + } + + for (int i = 0; i < iList.size(); i++) { + LOG_MSG_DPKG msg = iList.at(i); + if (msg.dateTime.contains(iSearchStr, Qt::CaseInsensitive) || msg.msg.contains(iSearchStr, Qt::CaseInsensitive)) { + rsList.append(msg); + } + } + return rsList; +} + +QList LogBackend::filterKern(const QString &iSearchStr, const QList &iList) +{ + QList rsList; + if (iSearchStr.isEmpty()) { + return iList; + } + for (int i = 0; i < iList.size(); i++) { + LOG_MSG_JOURNAL msg = iList.at(i); + if (msg.dateTime.contains(iSearchStr, Qt::CaseInsensitive) || msg.hostName.contains(iSearchStr, Qt::CaseInsensitive) || msg.daemonName.contains(iSearchStr, Qt::CaseInsensitive) || msg.msg.contains(iSearchStr, Qt::CaseInsensitive)) { + rsList.append(msg); + } + } + return rsList; +} + +QList LogBackend::filterXorg(const QString &iSearchStr, const QList &iList) +{ + QList rsList; + if (iSearchStr.isEmpty()) { + return iList; + } + for (int i = 0; i < iList.size(); i++) { + LOG_MSG_XORG msg = iList.at(i); + if (msg.offset.contains(iSearchStr, Qt::CaseInsensitive) || msg.msg.contains(iSearchStr, Qt::CaseInsensitive)) + rsList.append(msg); + } + return rsList; +} + +QList LogBackend::filterKwin(const QString &iSearchStr, const QList &iList) +{ + QList rsList; + if (iSearchStr.isEmpty()) { + return iList; + } + for (int i = 0; i < iList.size(); i++) { + LOG_MSG_KWIN msg = iList.at(i); + if (msg.msg.contains(iSearchStr, Qt::CaseInsensitive)) + rsList.append(msg); + } + return rsList; +} + +QList LogBackend::filterApp(const QString &iSearchStr, const QList &iList) +{ + QList rsList; + if (iSearchStr.isEmpty()) { + return iList; + } + for (int i = 0; i < iList.size(); i++) { + LOG_MSG_APPLICATOIN msg = iList.at(i); + if (msg.dateTime.contains(iSearchStr, Qt::CaseInsensitive) || msg.level.contains(iSearchStr, Qt::CaseInsensitive) || msg.src.contains(iSearchStr, Qt::CaseInsensitive) || msg.msg.contains(iSearchStr, Qt::CaseInsensitive)) + rsList.append(msg); + } + return rsList; +} + +QList LogBackend::filterDnf(const QString &iSearchStr, const QList &iList) +{ + QList rsList; + if (iSearchStr.isEmpty()) { + return iList; + } + for (int i = 0; i < iList.size(); i++) { + LOG_MSG_DNF msg = iList.at(i); + if (msg.dateTime.contains(m_currentSearchStr, Qt::CaseInsensitive) + || msg.msg.contains(m_currentSearchStr, Qt::CaseInsensitive) + || msg.level.contains(m_currentSearchStr, Qt::CaseInsensitive)) + rsList.append(msg); + } + return rsList; +} + +QList LogBackend::filterDmesg(const QString &iSearchStr, const QList &iList) +{ + QList rsList; + if (iSearchStr.isEmpty()) { + return iList; + } + + for (int i = 0; i < iList.size(); i++) { + LOG_MSG_DMESG msg = iList.at(i); + if (msg.dateTime.contains(m_currentSearchStr, Qt::CaseInsensitive) || msg.msg.contains(m_currentSearchStr, Qt::CaseInsensitive)) + rsList.append(msg); + } + + return rsList; +} + +QList LogBackend::filterJournal(const QString &iSearchStr, const QList &iList) +{ + QList rsList; + if (iSearchStr.isEmpty()) { + return iList; + } + for (int i = 0; i < iList.size(); i++) { + LOG_MSG_JOURNAL msg = iList.at(i); + if (msg.dateTime.contains(iSearchStr, Qt::CaseInsensitive) || msg.hostName.contains(iSearchStr, Qt::CaseInsensitive) || msg.daemonName.contains(iSearchStr, Qt::CaseInsensitive) || msg.daemonId.contains(iSearchStr, Qt::CaseInsensitive) || msg.level.contains(iSearchStr, Qt::CaseInsensitive) || msg.msg.contains(iSearchStr, Qt::CaseInsensitive)) + rsList.append(msg); + } + return rsList; +} + +QList LogBackend::filterJournalBoot(const QString &iSearchStr, const QList &iList) +{ + QList rsList; + if (iSearchStr.isEmpty()) { + return iList; + } + for (int i = 0; i < iList.size(); i++) { + LOG_MSG_JOURNAL msg = iList.at(i); + if (msg.dateTime.contains(iSearchStr, Qt::CaseInsensitive) || msg.hostName.contains(iSearchStr, Qt::CaseInsensitive) || msg.daemonName.contains(iSearchStr, Qt::CaseInsensitive) || msg.daemonId.contains(iSearchStr, Qt::CaseInsensitive) || msg.level.contains(iSearchStr, Qt::CaseInsensitive) || msg.msg.contains(iSearchStr, Qt::CaseInsensitive)) + rsList.append(msg); + } + return rsList; +} + +QList LogBackend::filterAudit(AUDIT_FILTERS auditFilter, const QList &iList) +{ + QList rsList; + if (auditFilter.searchstr.isEmpty() && auditFilter.auditTypeFilter < -1) { + return iList; + } + int nAuditType = auditFilter.auditTypeFilter - 1; + for (int i = 0; i < iList.size(); i++) { + LOG_MSG_AUDIT msg = iList.at(i); + if (msg.contains(auditFilter.searchstr) && (nAuditType == -1 || msg.filterAuditType(nAuditType))) { + rsList.append(msg); + } + } + + return rsList; +} +QList LogBackend::filterCoredump(const QString &iSearchStr, const QList &iList) +{ + QList rsList; + if (iSearchStr.isEmpty()) { + return iList; + } + for (int i = 0; i < iList.size(); i++) { + LOG_MSG_COREDUMP msg = iList.at(i); + if (msg.sig.contains(iSearchStr, Qt::CaseInsensitive) + || msg.dateTime.contains(iSearchStr, Qt::CaseInsensitive) + || msg.coreFile.contains(iSearchStr, Qt::CaseInsensitive) + || msg.uid.contains(iSearchStr, Qt::CaseInsensitive) + || msg.exe.contains(iSearchStr, Qt::CaseInsensitive)) { + rsList.append(msg); + } + } + + return rsList; +} + +bool LogBackend::parseData(const LOG_FLAG &flag, const QString &period, const QString &condition) +{ + // 周期类型有效性验证 + BUTTONID periodId = ALL; + if (!period.isEmpty()) { + periodId = period2Enum(period); + if (INVALID == periodId) { + qCWarning(logBackend) << "invalid period parameter: " << period; + return false; + } + } + + qCInfo(logBackend) << "period:" << period << "condition:" << condition << "keyword:" << m_currentSearchStr; + + TIME_RANGE timeRange = getTimeRange(periodId); + int lId = level2Id(condition); + + // 解析器准备工作 + initParser(); + if (!m_pParser) + return false; + + // 设置筛选条件,解析数据 + switch (flag) { + case JOURNAL: { + QStringList arg; + if (lId != LVALL) { + QString prio = QString("PRIORITY=%1").arg(lId); + arg.append(prio); + } else { + arg.append("all"); + } + + if (timeRange.begin != -1 && timeRange.end != -1) { + arg << QString::number(timeRange.begin * 1000) << QString::number(timeRange.end *1000); + } + + m_journalCurrentIndex = m_pParser->parseByJournal(arg); + } + break; + case Dmesg: { + DMESG_FILTERS dmesgfilter; + dmesgfilter.levelFilter = static_cast(lId); + dmesgfilter.timeFilter = timeRange.begin; + if (periodId == ALL) + dmesgfilter.timeFilter = 0; + + m_pParser->parseByDmesg(dmesgfilter); + } + break; + case KERN: { + KERN_FILTERS kernFilter; + kernFilter.timeFilterBegin = timeRange.begin; + kernFilter.timeFilterEnd = timeRange.end; + + m_kernCurrentIndex = m_pParser->parseByKern(kernFilter); + } + break; + case BOOT_KLU: { + QStringList arg; + if (lId != LVALL) { + QString prio = QString("PRIORITY=%1").arg(lId); + arg.append(prio); + } else { + arg.append("all"); + } + + m_journalBootCurrentIndex = m_pParser->parseByJournalBoot(arg); + } + break; + case BOOT: { + m_bootFilter.searchstr = m_currentSearchStr; + if (condition.isEmpty()) + m_bootFilter.statusFilter = ""; + else if (condition == "ok" || condition == "1") + m_bootFilter.statusFilter = "OK"; + else if (condition == "failed" || condition == "0") + m_bootFilter.statusFilter = "Failed"; + else { + qCWarning(logBackend) << "unknown status: " << condition; + m_bootFilter.statusFilter = ""; + } + + m_bootCurrentIndex = m_pParser->parseByBoot(); + } + break; + case DPKG: { + DKPG_FILTERS dpkgFilter; + dpkgFilter.timeFilterBegin = timeRange.begin; + dpkgFilter.timeFilterEnd = timeRange.end; + m_dpkgCurrentIndex = m_pParser->parseByDpkg(dpkgFilter); + } + break; + case Dnf: { + DNF_FILTERS dnffilter; + dnffilter.levelfilter = dnfLevel2Id(condition); + dnffilter.timeFilter = timeRange.begin; + if (periodId == ALL) + dnffilter.timeFilter = 0; + + m_pParser->parseByDnf(dnffilter); + } + break; + case Kwin: { + KWIN_FILTERS filter; + filter.msg = ""; + m_kwinCurrentIndex = m_pParser->parseByKwin(filter); + } + break; + case XORG: { + XORG_FILTERS xorgFilter; + m_xorgCurrentIndex = m_pParser->parseByXlog(xorgFilter); + } + break; + case APP: { + // TODO 待实现 + } + break; + case COREDUMP: { + COREDUMP_FILTERS coreFilter; + coreFilter.timeFilterBegin = timeRange.begin; + coreFilter.timeFilterEnd = timeRange.end; + m_coredumpCurrentIndex = m_pParser->parseByCoredump(coreFilter); + } + break; + case Normal: { + m_normalFilter.searchstr = m_currentSearchStr; + m_normalFilter.timeFilterBegin = timeRange.begin; + m_normalFilter.timeFilterEnd = timeRange.end; + m_normalFilter.eventTypeFilter = normal2eventType(condition); + m_normalCurrentIndex = m_pParser->parseByNormal(m_normalFilter); + } + break; + case Audit: { + AUDIT_FILTERS auditFilter; + auditFilter.timeFilterBegin = timeRange.begin; + auditFilter.timeFilterEnd = timeRange.end; + auditFilter.auditTypeFilter = audit2eventType(condition); + m_auditCurrentIndex = m_pParser->parseByAudit(auditFilter); + } + break; + default: + break; + } + + return true; +} + +void LogBackend::exportData() +{ + if (!m_isDataLoadComplete) + return; + + QString outPath = m_outPath; + + LogExportThread *exportThread = new LogExportThread(m_isDataLoadComplete, this); + connect(exportThread, &LogExportThread::sigResult, this, &LogBackend::onExportResult); + connect(exportThread, &LogExportThread::sigProgress, this, &LogBackend::onExportProgress); + + QString fileName = ""; + QStringList labels; + switch (m_flag) { + case JOURNAL: { + fileName = outPath + "/system.txt"; + labels << QCoreApplication::translate("Table", "Level") + << QCoreApplication::translate("Table", "Process") // modified by Airy + << QCoreApplication::translate("Table", "Date and Time") + << QCoreApplication::translate("Table", "Info") + << QCoreApplication::translate("Table", "User") + << QCoreApplication::translate("Table", "PID"); + exportThread->exportToTxtPublic(fileName, jList, labels, m_flag); + } + break; + case Dmesg: { + fileName = outPath + "/dmesg.txt"; + labels << QCoreApplication::translate("Table", "Level") + << QCoreApplication::translate("Table", "Date and Time") + << QCoreApplication::translate("Table", "Info"); + exportThread->exportToTxtPublic(fileName, dmesgList, labels); + } + break; + case KERN: { + fileName = outPath + "/kernel.txt"; + labels << QCoreApplication::translate("Table", "Date and Time") + << QCoreApplication::translate("Table", "User") + << QCoreApplication::translate("Table", "Process") + << QCoreApplication::translate("Table", "Info"); + exportThread->exportToTxtPublic(fileName, kList, labels, m_flag); + } + break; + case BOOT_KLU: { + fileName = outPath + "/boot_klu.txt"; + labels << QCoreApplication::translate("Table", "Level") + << QCoreApplication::translate("Table", "Process") + << QCoreApplication::translate("Table", "Date and Time") + << QCoreApplication::translate("Table", "Info") + << QCoreApplication::translate("Table", "User") + << QCoreApplication::translate("Table", "PID"); + exportThread->exportToTxtPublic(fileName, jBootList, labels, JOURNAL); + } + break; + case BOOT: { + fileName = outPath + "/boot.txt"; + labels << QCoreApplication::translate("Table", "Status") + << QCoreApplication::translate("Table", "Info"); + exportThread->exportToTxtPublic(fileName, currentBootList, labels); + } + break; + case DPKG: { + fileName = outPath + "/dpkg.txt"; + labels << QCoreApplication::translate("Table", "Date and Time") + << QCoreApplication::translate("Table", "Info") + << QCoreApplication::translate("Table", "Action"); + exportThread->exportToTxtPublic(fileName, dList, labels); + } + break; + case Dnf: { + fileName = outPath + "/dnf.txt"; + labels << QCoreApplication::translate("Table", "Level") + << QCoreApplication::translate("Table", "Date and Time") + << QCoreApplication::translate("Table", "Info"); + exportThread->exportToTxtPublic(fileName, dnfList, labels); + } + break; + case Kwin: { + fileName = outPath + "/kwin.txt"; + labels << QCoreApplication::translate("Table", "Info"); + exportThread->exportToTxtPublic(fileName, m_currentKwinList, labels); + } + break; + case XORG: { + fileName = outPath + "/xorg.txt"; + labels << QCoreApplication::translate("Table", "Offset") + << QCoreApplication::translate("Table", "Info"); + exportThread->exportToTxtPublic(fileName, xList, labels); + } + break; + case APP: { + QString appName = Utils::appName(m_curAppLog); + QString transAppName = LogApplicationHelper::instance()->transName(appName); + fileName = outPath + QString("/%1.txt").arg(appName); + labels << QCoreApplication::translate("Table", "Level") + << QCoreApplication::translate("Table", "Date and Time") + << QCoreApplication::translate("Table", "Source") + << QCoreApplication::translate("Table", "Info"); + exportThread->exportToTxtPublic(fileName, appList, labels, transAppName); + } + break; + case COREDUMP: { + fileName = outPath + "/coredump.zip"; + labels << QCoreApplication::translate("Table", "SIG") + << QCoreApplication::translate("Table", "Date and Time") + << QCoreApplication::translate("Table", "Core File") + << QCoreApplication::translate("Table", "User Name ") + << QCoreApplication::translate("Table", "EXE"); + exportThread->exportToZipPublic(fileName, m_currentCoredumpList, labels); + } + break; + case Normal: { + fileName = outPath + "/boot-shutdown-event.txt"; + labels << QCoreApplication::translate("Table", "Event Type") + << QCoreApplication::translate("Table", "Username") + << QCoreApplication::translate("Tbble", "Date and Time") + << QCoreApplication::translate("Table", "Info"); + exportThread->exportToTxtPublic(fileName, nortempList, labels); + } + break; + case Audit: { + fileName = outPath + "/audit.txt"; + labels << QCoreApplication::translate("Table", "Event Type") + << QCoreApplication::translate("Table", "Date and Time") + << QCoreApplication::translate("Table", "Process") + << QCoreApplication::translate("Table", "Status") + << QCoreApplication::translate("Table", "Info"); + exportThread->exportToTxtPublic(fileName, aList, labels); + } + break; + default: + break; + } + QThreadPool::globalInstance()->start(exportThread); + qCInfo(logBackend) << "exporting ..."; +} + +void LogBackend::initParser() +{ + if (m_pParser) + return; + + m_pParser = new LogFileParser(); + + connect(m_pParser, &LogFileParser::dpkgFinished, this, &LogBackend::slot_dpkgFinished, + Qt::QueuedConnection); + connect(m_pParser, &LogFileParser::dpkgData, this, &LogBackend::slot_dpkgData, + Qt::QueuedConnection); + connect(m_pParser, &LogFileParser::xlogFinished, this, &LogBackend::slot_XorgFinished, + Qt::QueuedConnection); + connect(m_pParser, &LogFileParser::xlogData, this, &LogBackend::slot_xorgData, + Qt::QueuedConnection); + + connect(m_pParser, &LogFileParser::bootFinished, this, &LogBackend::slot_bootFinished, + Qt::QueuedConnection); + connect(m_pParser, &LogFileParser::bootData, this, &LogBackend::slot_bootData, + Qt::QueuedConnection); + + connect(m_pParser, &LogFileParser::kernFinished, this, &LogBackend::slot_kernFinished, + Qt::QueuedConnection); + connect(m_pParser, &LogFileParser::kernData, this, &LogBackend::slot_kernData, + Qt::QueuedConnection); + + connect(m_pParser, &LogFileParser::journalFinished, this, &LogBackend::slot_journalFinished, + Qt::QueuedConnection); + connect(m_pParser, &LogFileParser::journalData, this, &LogBackend::slot_journalData, + Qt::QueuedConnection); + connect(m_pParser, &LogFileParser::journaBootlData, this, &LogBackend::slot_journalBootData, + Qt::QueuedConnection); + connect(m_pParser, &LogFileParser::appFinished, this, + &LogBackend::slot_applicationFinished); + connect(m_pParser, &LogFileParser::appData, this, + &LogBackend::slot_applicationData); + + connect(m_pParser, &LogFileParser::kwinFinished, this, &LogBackend::slot_kwinFinished, + Qt::QueuedConnection); + connect(m_pParser, &LogFileParser::kwinData, this, &LogBackend::slot_kwinData, + Qt::QueuedConnection); + + connect(m_pParser, &LogFileParser::normalData, this, &LogBackend::slot_normalData, + Qt::QueuedConnection); + connect(m_pParser, &LogFileParser::normalFinished, this, &LogBackend::slot_normalFinished, + Qt::QueuedConnection); + connect(m_pParser, &LogFileParser::journalBootFinished, this, &LogBackend::slot_journalBootFinished); + + connect(m_pParser, &LogFileParser::proccessError, this, &LogBackend::slot_logLoadFailed, + Qt::QueuedConnection); + connect(m_pParser, SIGNAL(dnfFinished(QList)), this, SLOT(slot_dnfFinished(QList))); + connect(m_pParser, &LogFileParser::dmesgFinished, this, &LogBackend::slot_dmesgFinished, + Qt::QueuedConnection); + + connect(m_pParser, &LogFileParser::auditData, this, &LogBackend::slot_auditData, + Qt::QueuedConnection); + connect(m_pParser, &LogFileParser::auditFinished, this, &LogBackend::slot_auditFinished, + Qt::QueuedConnection); + + connect(m_pParser, &LogFileParser::coredumpData, this, &LogBackend::slot_coredumpData, + Qt::QueuedConnection); + connect(m_pParser, &LogFileParser::coredumpFinished, this, &LogBackend::slot_coredumpFinished, + Qt::QueuedConnection); +} + QString LogBackend::getOutDirPath() const { return m_outPath; @@ -489,8 +1431,14 @@ bool LogBackend::getOutDirPath(const QString &path) } if (dir.exists()) { + QFileInfo fi(tmpPath); + if (!fi.isWritable()) { + qCWarning(logBackend) << "outPath: isnot writable." << m_outPath; + return false; + } + m_outPath = tmpPath; - qCDebug(logBackend) << "outPath:" << m_outPath; + qCInfo(logBackend) << "outPath:" << m_outPath; return true; } else { @@ -501,71 +1449,55 @@ bool LogBackend::getOutDirPath(const QString &path) return false; } -void LogBackend::resetToNormalAuth(const QString &path) -{ - QDir dir(path); - if (!path.isEmpty() && dir.exists()) { - QDir dir(path); - if (dir.exists()) { - QProcess procss; - procss.setWorkingDirectory(path); - QStringList arg = {"-c"}; - arg.append(QString("chmod -R 777 '%1'").arg(path)); - procss.start("/bin/bash", arg); - procss.waitForFinished(-1); - } - } -} - LOG_FLAG LogBackend::type2Flag(const QString &type, QString& error) { Dtk::Core::DSysInfo::UosEdition edition = Dtk::Core::DSysInfo::uosEditionType(); bool isCentos = Dtk::Core::DSysInfo::UosEuler == edition || Dtk::Core::DSysInfo::UosEnterpriseC == edition || Dtk::Core::DSysInfo::UosMilitaryS == edition; LOG_FLAG flag = NONE; - if (type == "system") + if (type == TYPE_SYSTEM) flag = JOURNAL; - else if (type == "kernel") { + else if (type == TYPE_KERNEL) { if (isCentos) flag = Dmesg; else flag = KERN; - } else if (type == "boot") { + } else if (type == TYPE_BOOT) { if (DBusManager::isSpecialComType()) flag = BOOT_KLU; else flag = BOOT; - } else if (type == "dpkg") { + } else if (type == TYPE_DPKG) { if (!isCentos) flag = DPKG; else error = "Server industry edition has no dpkg.log"; - } else if (type == "dnf") { + } else if (type == TYPE_DNF) { if (isCentos) flag = Dnf; else error = "Only server industry edition has dnf.log"; - } else if (type == "kwin") { + } else if (type == TYPE_KWIN) { if (DBusManager::isSpecialComType()) flag = Kwin; else error = "Only wayland platform has kwin.log"; - } else if (type == "xorg") { + } else if (type == TYPE_XORG) { if (!DBusManager::isSpecialComType()) flag = XORG; else error = "Wayland platform has no Xorg.log"; - } else if (type == "app") { + } else if (type == TYPE_APP) { flag = APP; - } else if (type == "coredump") { + } else if (type == TYPE_COREDUMP) { flag = COREDUMP; - } else if (type == "boot-shutdown-event") { + } else if (type == TYPE_BSE) { flag = Normal; - } else if (type == "other") { + } else if (type == TYPE_OTHER) { flag = OtherLog; - } else if (type == "custom") { + } else if (type == TYPE_CUSTOM) { flag = CustomLog; - } else if (type == "audit") { + } else if (type == TYPE_AUDIT) { flag = Audit; } else { flag = NONE; @@ -574,3 +1506,154 @@ LOG_FLAG LogBackend::type2Flag(const QString &type, QString& error) return flag; } + +BUTTONID LogBackend::period2Enum(const QString &period) +{ + BUTTONID id = INVALID; + if (period == "all") + id = ALL; + else if (period == "today" || period == "1d") + id = ONE_DAY; + else if (period == "3d") + id = THREE_DAYS; + else if (period == "1w") + id = ONE_WEEK; + else if (period == "1m") + id = ONE_MONTH; + else if (period == "3m") + id = THREE_MONTHS; + + return id; +} + +int LogBackend::level2Id(const QString &level) +{ + int lId = -1; + if (level == "debug" || level == "7") + lId = 7; + if (level == "info" || level == "6") + lId = 6; + else if (level == "notice" || level == "5") + lId = 5; + else if (level == "warning" || level == "4") + lId = 4; + else if (level == "err" || level == "error" || level == "3") + lId = 3; + else if (level == "critical" || level == "crit" || level == "2") + lId = 2; + else if (level == "alert" || level == "1") + lId = 1; + else if (level == "emerg" || level == "0") + lId = 0; + + return lId; +} + +DNFPRIORITY LogBackend::dnfLevel2Id(const QString &level) +{ + DNFPRIORITY eId = DNFLVALL; + if (level == "trace" || level == "6") + eId = TRACE; + else if (level == "debug" || level == "5") + eId = DEBUG; + else if (level == "info" || level == "4") + eId = INFO; + else if (level == "warning" || level == "3") + eId = WARNING; + else if (level == "error" || level == "err" || level == "2") + eId = ERROR; + else if (level == "critical" || level == "crit" || level == "1") + eId = CRITICAL; + else if (level == "supercritical" || level == "supercrit" || level == "0") + eId = SUPERCRITICAL; + + return eId; +} + +int LogBackend::normal2eventType(const QString &eventType) +{ + int type = 0; + if (eventType == "all" || eventType == "0") + type = 0; + else if (eventType == "login" || eventType == "1") + type = 1; + else if (eventType == "boot" || eventType == "2") + type = 2; + else if (eventType == "shutdown" || eventType == "3") + type = 3; + + return type; +} + +int LogBackend::audit2eventType(const QString &eventType) +{ + int type = 0; + if (eventType == "all" || eventType == "0") + type = 0; + else if (eventType == "identauth" || eventType == "1") + type = 1; + else if (eventType == "dac" || eventType == "2") + type = 2; + else if (eventType == "mac" || eventType == "3") + type = 3; + else if (eventType == "remote" || eventType == "4") + type = 4; + else if (eventType == "docaudit" || eventType == "5") + type = 5; + else if (eventType == "other" || eventType == "6") + type = 6; + + return type; +} + +TIME_RANGE LogBackend::getTimeRange(const BUTTONID &periodId) +{ + TIME_RANGE tr; + + QDateTime dtStart = QDateTime::currentDateTime(); + QDateTime dtEnd = dtStart; + dtStart.setTime(QTime()); + dtEnd.setTime(QTime(23, 59, 59, 999)); + tr.end = dtEnd.toMSecsSinceEpoch(); + + switch (periodId) { + case ALL: { + tr.begin = -1; + tr.end = -1; + } + break; + case ONE_DAY: { + tr.begin = dtStart.toMSecsSinceEpoch(); + } + break; + case THREE_DAYS: { + tr.begin = dtStart.addDays(-2).toMSecsSinceEpoch(); + } + break; + case ONE_WEEK: { + tr.begin = dtStart.addDays(-6).toMSecsSinceEpoch(); + } + break; + case ONE_MONTH: { + tr.begin = dtStart.addMonths(-1).toMSecsSinceEpoch(); + if (m_flag == Dmesg || m_flag == Dnf) { + tr.begin = dtStart.addDays(-29).toMSecsSinceEpoch(); + } + } + break; + case THREE_MONTHS: { + tr.begin = dtStart.addMonths(-3).toMSecsSinceEpoch(); + if (m_flag == Dmesg || m_flag == Dnf) { + tr.begin = dtStart.addDays(-89).toMSecsSinceEpoch(); + } + } + break; + default: { + tr.begin = -1; + tr.end = -1; + } + break; + } + + return tr; +} diff --git a/application/logbackend.h b/application/logbackend.h index c4c41ccb..c25f7d71 100644 --- a/application/logbackend.h +++ b/application/logbackend.h @@ -13,6 +13,7 @@ class LogFileParser; class LogBackend : public QObject { Q_OBJECT + public: static LogBackend *instance(QObject *parent = nullptr); ~LogBackend(); @@ -27,21 +28,85 @@ class LogBackend : public QObject // 按类型导出日志 void exportTypeLogs(const QString &outDir, const QString &type = ""); + // 按条件导出日志 + // condition 可能为级别、事件类型、状态、审计类型等条件 + bool exportTypeLogsByCondition(const QString &outDir, const QString &type, const QString &period, const QString &condition = "", const QString &keyword = ""); + // 按应用导出日志 - void exportLogsByApp(const QString &outDir, const QString &appName = ""); + void exportAppLogs(const QString &outDir, const QString &appName = ""); + + // 按条件导出应用日志 + bool exportAppLogsByCondition(const QString &outDir, const QString& appName, const QString &period, const QString &level = "", const QString &keyword = ""); // 获取当前系统支持的日志种类 QStringList getLogTypes(); QString getOutDirPath() const; - void resetToNormalAuth(const QString &path); + + static LOG_FLAG type2Flag(const QString &type, QString &error); private: static LogBackend *m_staticbackend; +private slots: + void slot_dpkgFinished(int index); + void slot_dpkgData(int index, QList list); + void slot_XorgFinished(int index); + void slot_xorgData(int index, QList list); + void slot_bootFinished(int index); + void slot_bootData(int index, QList list); + void slot_kernFinished(int index); + void slot_kernData(int index, QList list); + void slot_kwinFinished(int index); + void slot_kwinData(int index, QList list); + void slot_dnfFinished(const QList &list); + void slot_dmesgFinished(const QList &list); + void slot_journalFinished(int index); + void slot_journalBootFinished(int index); + void slot_journalBootData(int index, QList list); + void slot_journalData(int index, QList list); + void slot_applicationFinished(int index); + void slot_applicationData(int index, QList list); + void slot_normalFinished(int index); + void slot_normalData(int index, QList list); + void slot_auditFinished(int index, bool bShowTip = false); + void slot_auditData(int index, QList list); + void slot_coredumpFinished(int index); + void slot_coredumpData(int index, QList list); + + void slot_logLoadFailed(const QString &iError); + + void onExportProgress(int nCur, int nTotal); + void onExportResult(bool isSuccess); + + QList filterBoot(BOOT_FILTERS ibootFilter, const QList &iList); + QList filterNomal(NORMAL_FILTERS inormalFilter, QList &iList); + QList filterDpkg(const QString &iSearchStr, const QList &iList); + QList filterKern(const QString &iSearchStr, const QList &iList); + QList filterXorg(const QString &iSearchStr, const QList &iList); + QList filterKwin(const QString &iSearchStr, const QList &iList); + QList filterApp(const QString &iSearchStr, const QList &iList); + QList filterDnf(const QString &iSearchStr, const QList &iList); + QList filterDmesg(const QString &iSearchStr, const QList &iList); + QList filterJournal(const QString &iSearchStr, const QList &iList); + QList filterJournalBoot(const QString &iSearchStr, const QList &iList); + QList filterAudit(AUDIT_FILTERS auditFilter, const QList &iList); + QList filterCoredump(const QString &iSearchStr, const QList &iList); + private: + void initParser(); + + bool parseData(const LOG_FLAG &flag, const QString &period, const QString &condition); + + void exportData(); + bool getOutDirPath(const QString &path); - LOG_FLAG type2Flag(const QString &type, QString &error); + BUTTONID period2Enum(const QString &period); + int level2Id(const QString &level); + DNFPRIORITY dnfLevel2Id(const QString &level); + int normal2eventType(const QString &eventType); + int audit2eventType(const QString &eventType); + TIME_RANGE getTimeRange(const BUTTONID& periodId); private: QStringList m_logTypes; @@ -49,8 +114,132 @@ class LogBackend : public QObject QString m_outPath {""}; QString m_cmdWorkDir {""}; +private: + + /** + * @brief m_curAppLog 当前选中的应用的日志文件路径 + */ + QString m_curAppLog {""}; + //当前解析的日志类型 LOG_FLAG m_flag {NONE}; + + /** + * @brief jBootList 经过筛选完成的启动日志列表 + */ + /** + * @brief jBootListOrigin 未经过筛选的启动日志数据 journalctl --boot cmd. + */ + QList jBootList, jBootListOrigin; + + // System log data + QList jList, jListOrigin; + // Dmesg log data + QList dmesgList, dmesgListOrigin; + + QList dnfList, dnfListOrigin; //dnf.log + /** + * @brief dList 经过筛选完成的dpkg日志数据 + */ + /** + * @brief dListOrigin 未经过筛选的dpkg日志数据 dpkg.log + */ + QList dList, dListOrigin; + /** + * @brief xList 经过筛选完成的xorg日志数据 + */ + /** + * @brief xListOrigin 未经过筛选的xorg日志数据 Xorg.0.log + */ + QList xList, xListOrigin; + /** + * @brief currentBootList 经过筛选完成的启动日志数据 + */ + /** + * @brief bList 未经过筛选的启动日志数据 boot.log + */ + QList bList, currentBootList; + /** + * @brief kList 经过筛选完成的内核日志数据 + */ + /** + * @brief kListOrigin 未经过筛选的内核日志数据 kern.log + */ + QList kList, kListOrigin; + + /** + * @brief aListOrigin 未经过筛选的审计日志数据 audit/audit.log + */ + QList aList, aListOrigin; + + /** + * @brief appListOrigin 未经过筛选的内核日志数据 ~/.cache/deepin/xxx.log(.xxx) + */ + QList appList, appListOrigin; + /** + * @brief norList add 未经过筛选完成的开关机日志数据 by Airy + */ + QList norList; + /** + * @brief nortempList 经过筛选的开关机日志数据 add by Airy + */ + QList nortempList; + /** + * @brief m_currentKwinList add 经过筛选完成的kwin日志数据 by Airy /$HOME/.kwin.log + */ + QList m_currentKwinList; + /** + * @brief m_kwinList 未经过筛选的开关机日志数据 + */ + QList m_kwinList; + + + QList m_coredumpList; + QList m_currentCoredumpList; + + //当前搜索关键字 + QString m_currentSearchStr {""}; + + /** + * @brief m_journalFilter 当前系统日志筛选条件 + */ + JOURNAL_FILTERS m_journalFilter; + /** + * @brief m_currentKwinFilter kwin日志当前筛选条件 + */ + KWIN_FILTERS m_currentKwinFilter; + /** + * @brief m_normalFilter 开关机日志当前筛选条件 + */ + NORMAL_FILTERS m_normalFilter; + //启动日志当前筛选条件 + BOOT_FILTERS m_bootFilter = {"", ""}; + /** + * @brief m_auditFilter 当前审计日志筛选条件 + */ + AUDIT_FILTERS m_auditFilter; + + //当前系统日志获取进程标记量 + int m_journalCurrentIndex {-1}; + //当前klu启动日志获取进程标记量 + int m_journalBootCurrentIndex {-1}; + //当前启动日志获取进程标记量 + int m_bootCurrentIndex {-1}; + int m_dpkgCurrentIndex {-1}; + int m_kernCurrentIndex {-1}; + int m_normalCurrentIndex {-1}; + int m_xorgCurrentIndex {-1}; + int m_kwinCurrentIndex {-1}; + int m_appCurrentIndex {-1}; + int m_OOCCurrentIndex {-1}; + int m_auditCurrentIndex {-1}; + int m_coredumpCurrentIndex {-1}; + + bool m_isDataLoadComplete {false}; + bool m_bNeedExport {false}; + +private: + LogFileParser *m_pParser {nullptr}; }; #endif // LOGBACKEND_H diff --git a/application/logfileparser.cpp b/application/logfileparser.cpp index 73a54b24..a72974ed 100644 --- a/application/logfileparser.cpp +++ b/application/logfileparser.cpp @@ -68,6 +68,7 @@ LogFileParser::LogFileParser(QWidget *parent) qRegisterMetaType>("QList"); qRegisterMetaType>("QList"); qRegisterMetaType>("QList"); + qRegisterMetaType>("QList"); qRegisterMetaType ("LOG_FLAG"); } diff --git a/application/main.cpp b/application/main.cpp index 804ab5e6..6926a5e0 100644 --- a/application/main.cpp +++ b/application/main.cpp @@ -58,6 +58,11 @@ int main(int argc, char *argv[]) QCommandLineOption exportOption(QStringList() << "e" << "export", DApplication::translate("main", "Export logs to the specified path"), DApplication::translate("main", "PATH")); QCommandLineOption typeOption(QStringList() << "t" << "type", DApplication::translate("main", "Export logs of specified types"), DApplication::translate("main", "TYPE")); QCommandLineOption appOption(QStringList() << "d" << "deepin-application", DApplication::translate("main", "Export logs of specified self-developed applications"), DApplication::translate("main", "SELF APPNAME")); + QCommandLineOption periodOption(QStringList() << "p" << "period", DApplication::translate("main", "Export logs within a specified time period"), DApplication::translate("main", "PERIOD")); + QCommandLineOption levelOption(QStringList() << "l" << "level", DApplication::translate("main", "Export logs within a specified debug level"), DApplication::translate("main", "LEVEL")); + QCommandLineOption statusOption(QStringList() << "s" << "status", DApplication::translate("main", "Export boot(no-klu) logs within a specified status"), DApplication::translate("main", "BOOT STATUS")); + QCommandLineOption eventOption(QStringList() << "E" << "event", DApplication::translate("main", "Export boot-shutdown-event or audit logs within a specified event type"), DApplication::translate("main", "EVENT TYPE")); + QCommandLineOption keywordOption(QStringList() << "k" << "search", DApplication::translate("main", "Export logs based on keywords search results"), DApplication::translate("main", "KEY WORD")); QCommandLineParser cmdParser; cmdParser.setApplicationDescription("deepin-log-viewer"); @@ -66,6 +71,11 @@ int main(int argc, char *argv[]) cmdParser.addOption(exportOption); cmdParser.addOption(typeOption); cmdParser.addOption(appOption); + cmdParser.addOption(periodOption); + cmdParser.addOption(levelOption); + cmdParser.addOption(statusOption); + cmdParser.addOption(eventOption); + cmdParser.addOption(keywordOption); if (!cmdParser.parse(qApp->arguments())) { cmdParser.showHelp(); @@ -82,12 +92,13 @@ int main(int argc, char *argv[]) return 0; } + Utils::runInCmd = true; + // 根据当前用户名获取正确家目录路径 Utils::homePath = Utils::getHomePath(argv[argc - 1]); // 设置命令行工作目录 LogBackend::instance(&a)->setCmdWorkDir(argv[argc - 2]); - // 若指定有导出目录,按指定目录导出 QString outDir = cmdParser.value(exportOption); if (outDir.isEmpty()) { @@ -97,18 +108,101 @@ int main(int argc, char *argv[]) QString type = ""; QString appName = ""; + QString period = ""; + QString level = ""; + QString status = ""; + QString event = ""; + QString keyword = ""; if (cmdParser.isSet(typeOption)) type = cmdParser.value(typeOption); if (cmdParser.isSet(appOption)) appName = cmdParser.value(appOption); + if (cmdParser.isSet(periodOption)) + period = cmdParser.value(periodOption); + if (cmdParser.isSet(levelOption)) + level = cmdParser.value(levelOption); + if (cmdParser.isSet(statusOption)) + status = cmdParser.value(statusOption); + if (cmdParser.isSet(eventOption)) + event = cmdParser.value(eventOption); + if (cmdParser.isSet(keywordOption)) + keyword = cmdParser.value(keywordOption); if (!type.isEmpty()) { - // 按种类导出日志 - LogBackend::instance(&a)->exportTypeLogs(outDir, type); - return 0; + // 按类型导出日志 + if (period.isEmpty() && + level.isEmpty() && + status.isEmpty() && + event.isEmpty() && + appName.isEmpty() && + keyword.isEmpty()) { + LogBackend::instance(&a)->exportTypeLogs(outDir, type); + return 0; + } else { + // 按筛选条件导出指定类型的日志 + bool bRet = false; + QString error(""); + LOG_FLAG flag = LogBackend::type2Flag(type, error); + if (TYPE_SYSTEM == type || Dmesg == flag || BOOT_KLU == flag || TYPE_DNF == type){ + // system、dmesg(centos下内核日志)、boot_klu、dnf 可按周期或级别导出 + if (!status.isEmpty() || !event.isEmpty()) + qCWarning(logAppMain) << QString("Export logs by %1, can only be filtered using 'period' or 'level' parameter.").arg(type); + else + bRet = LogBackend::instance(&a)->exportTypeLogsByCondition(outDir, type, period, level, keyword); + } else if (KERN == flag || TYPE_DPKG == type || TYPE_COREDUMP == type) { + // 内核、dpkg、崩溃日志 可按周期导出 + if (!level.isEmpty() || !status.isEmpty() || !event.isEmpty()) + qCWarning(logAppMain) << QString("Export logs by %1, can only be filtered using 'period' condition.").arg(type); + else + bRet = LogBackend::instance(&a)->exportTypeLogsByCondition(outDir, type, period, "", keyword); + } else if (BOOT == flag) { + // 启动日志 可按状态导出 + if (!period.isEmpty() || !level.isEmpty() || !event.isEmpty()) + qCWarning(logAppMain) << QString("Export logs by %1, can only be filtered using 'status' parameter.").arg(type); + else + bRet = LogBackend::instance(&a)->exportTypeLogsByCondition(outDir, type, "", status, keyword); + } else if (TYPE_APP == type) { + if (!status.isEmpty() || !event.isEmpty()) { + qCWarning(logAppMain) << QString("Export logs by %1, can only be filtered using 'period' or 'level' parameter.").arg(type); + } else if (!appName.isEmpty()) { + bRet = LogBackend::instance(&a)->exportAppLogsByCondition(outDir, appName, period, level, keyword); + } else { + qCWarning(logAppMain) << QString("Export logs by %1, filterd by 'period' or 'level', currently not supported.").arg(type).arg(appName); + } + } else if (TYPE_BSE == type || TYPE_AUDIT == type) { + // 开关机事件、审计日志 可按周期和事件类型导出 + if (!level.isEmpty() || !status.isEmpty()) + qCWarning(logAppMain) << QString("Export logs by %1, can only be filtered using 'period' or 'event' parameter.").arg(type); + else + bRet = LogBackend::instance(&a)->exportTypeLogsByCondition(outDir, type, period, event, keyword); + } else if (TYPE_XORG == type || TYPE_OTHER == type || TYPE_CUSTOM == type || TYPE_KWIN == type) { + // Xorg、其他、自定义日志 不能按条件导出 + if (!period.isEmpty() || !level.isEmpty() || !status.isEmpty() || !event.isEmpty()) + qCWarning(logAppMain) << QString("Export logs by %1, cannot be filtered by any parameters.").arg(type); + } else { + qCWarning(logAppMain) << error; + } + + if (!bRet) + return 0; + } } else if (!appName.isEmpty()) { - LogBackend::instance(&a)->exportLogsByApp(outDir, appName); - return 0; + if (period.isEmpty() && + level.isEmpty() && + status.isEmpty() && + event.isEmpty() && + keyword.isEmpty()) { + LogBackend::instance(&a)->exportAppLogs(outDir, appName); + return 0; + } else { + bool bRet = false; + if (!status.isEmpty() || !event.isEmpty()) + qCWarning(logAppMain) << QString("Export app logs, can only be filtered using 'period' or 'level' parameter."); + else if (!period.isEmpty() || !level.isEmpty()) + bRet = LogBackend::instance(&a)->exportAppLogsByCondition(outDir, appName, period, level, keyword); + if (!bRet) + return 0; + } } else { // 未指定类型,默认导出所有日志 LogBackend::instance(&a)->exportAllLogs(outDir); diff --git a/application/structdef.h b/application/structdef.h index d6c52094..e5178f25 100644 --- a/application/structdef.h +++ b/application/structdef.h @@ -45,6 +45,20 @@ #define ICONDARKPREFIX "://images/dark/" #define DOCTEMPLATE "://doc_template/template.doc" +#define TYPE_SYSTEM "system" +#define TYPE_KERNEL "kernel" +#define TYPE_BOOT "boot" +#define TYPE_DPKG "dpkg" +#define TYPE_DNF "dnf" +#define TYPE_KWIN "kwin" +#define TYPE_XORG "xorg" +#define TYPE_APP "app" +#define TYPE_COREDUMP "coredump" +#define TYPE_BSE "boot-shutdown-event" +#define TYPE_OTHER "other" +#define TYPE_CUSTOM "custom" +#define TYPE_AUDIT "audit" + #define AUDIT_ORIGIN_DATAROLE Qt::UserRole + 3 enum PRIORITY { LVALL = -1, diff --git a/application/utils.cpp b/application/utils.cpp index 06841518..a39e0d8d 100644 --- a/application/utils.cpp +++ b/application/utils.cpp @@ -25,6 +25,8 @@ #include #include #include +#include + #include using namespace PolkitQt1; @@ -39,7 +41,7 @@ QHash Utils::m_fontNameCache; QMap Utils::m_mapAuditType2EventType; int Utils::specialComType = -1; QString Utils::homePath = QDir::homePath(); - +bool Utils::runInCmd = false; Utils::Utils(QObject *parent) : QObject(parent) { @@ -343,6 +345,23 @@ QString Utils::getCurrentUserName() return pwd->pw_name; } +bool Utils::isValidUserName(const QString &userName) +{ + bool bValidUserName = false; + QDBusInterface interface("com.deepin.daemon.Accounts", "/com/deepin/daemon/Accounts", "com.deepin.daemon.Accounts", QDBusConnection::systemBus()); + QStringList userList = qvariant_cast< QStringList >(interface.property("UserList")); + for (auto strUser : userList) { + uint uid = strUser.mid(strUser.lastIndexOf("User") + 4).toUInt(); + QString tempUserName = getUserNamebyUID(uid); + if(tempUserName == userName) { + bValidUserName = true; + break; + } + } + + return bValidUserName; +} + bool Utils::isCoredumpctlExist() { bool isCoredumpctlExist = false; @@ -365,28 +384,60 @@ QString Utils::getHomePath(const QString &userName) else uName = getCurrentUserName(); - - QProcess *unlock = new QProcess; - unlock->start("sh", QStringList() << "-c" << QString("cat /etc/passwd | grep %1").arg(uName)); - unlock->waitForFinished(); - auto output = unlock->readAllStandardOutput(); - auto str = QString::fromUtf8(output); - QString homePath = str.mid(str.indexOf("::") + 2).split(":").first(); + QString homePath = ""; + if (isValidUserName(uName)) { + QProcess *unlock = new QProcess; + unlock->start("sh", QStringList() << "-c" << QString("cat /etc/passwd | grep %1").arg(uName)); + unlock->waitForFinished(); + auto output = unlock->readAllStandardOutput(); + auto str = QString::fromUtf8(output); + homePath = str.mid(str.indexOf("::") + 2).split(":").first(); + } // 根据用户名获取家目录失败,默认采用QDir::homePath()作为homePath QDir dir(homePath); if (!dir.exists() || homePath.isEmpty()) homePath = QDir::homePath(); - qCInfo(logUtils) << "userName: " << uName << "homePath:" << homePath; + qCDebug(logUtils) << "userName: " << uName << "homePath:" << homePath; return homePath; } -QString Utils::appName(const QString &path) +QString Utils::appName(const QString &filePath) { - if (path.indexOf('/') == -1) - return path; + QString ret; + if (filePath.isEmpty()) + return ret; + + QStringList strList = filePath.split("/"); + if (strList.count() < 2) { + if (filePath.contains(".")) + ret = filePath.section(".", 0, 0); + else { + ret = filePath; + } + return ret; + } + + QString tmpPath = filePath; + if (tmpPath.endsWith('/')) + tmpPath = tmpPath.remove(tmpPath.size() - 1, 1); + QString desStr = tmpPath.section("/", -1); + ret = desStr.mid(0, desStr.lastIndexOf(".")); + return ret; +} - return path.mid(path.lastIndexOf("/") + 1, path.size() - 1).split(".").first(); +void Utils::resetToNormalAuth(const QString &path) +{ + QFileInfo fi(path); + if (!path.isEmpty() && fi.exists()) { + qCDebug(logUtils) << "resetToNormalAuth path:" << path; + QProcess procss; + procss.setWorkingDirectory(path); + QStringList arg = {"-c"}; + arg.append(QString("chmod -R 777 '%1'").arg(path)); + procss.start("/bin/bash", arg); + procss.waitForFinished(-1); + } } diff --git a/application/utils.h b/application/utils.h index 995a6693..c1a4a26f 100644 --- a/application/utils.h +++ b/application/utils.h @@ -55,15 +55,18 @@ class Utils : public QObject static double convertToMB(quint64 cap, const int size = 1024); static QString getUserNamebyUID(uint uid); //根据uid获取用户名 static QString getCurrentUserName(); + static bool isValidUserName(const QString &userName); static bool isCoredumpctlExist(); // is coredumpctl installed static QString getHomePath(const QString &userName = ""); - static QString appName(const QString &path); + static QString appName(const QString &filePath); + static void resetToNormalAuth(const QString &path); /** * @brief specialComType 是否是特殊机型,like huawei * 取值有3种(-1,0,>0),默认为-1(未知),0(不是特殊机型),>0(特殊机型) */ static int specialComType; static QString homePath; + static bool runInCmd; }; #endif diff --git a/logViewerService/logviewerservice.cpp b/logViewerService/logviewerservice.cpp index 46d3aacf..10d263b3 100644 --- a/logViewerService/logviewerservice.cpp +++ b/logViewerService/logviewerservice.cpp @@ -56,28 +56,44 @@ QString LogViewerService::readLog(const QString &filePath) if ((!filePath.startsWith("/var/log/") && !filePath.startsWith("/tmp") && !filePath.startsWith("/home") && - !filePath.startsWith("/root")) || + !filePath.startsWith("/root") && + !filePath.startsWith("coredumpctl info") && + filePath != "coredump") || filePath.contains("..")) { return " "; } - m_process.start("cat", QStringList() << filePath); - m_process.waitForFinished(-1); - QByteArray byte = m_process.readAllStandardOutput(); - - //QByteArray -> QString 如果遇到0x00,会导致转换终止 - //replace("\x00", "")和replace("\u0000", "")无效 - //使用remove操作,性能损耗过大,因此遇到0x00 替换为 0x20(空格符) - qCInfo(logService) << "replace 0x00 to 0x20 begin"; - int replaceTimes = 0; - for (int i = 0; i != byte.size(); ++i) { - if (byte.at(i) == 0x00) { - byte[i] = 0x20; - replaceTimes++; + if (filePath == "coredump") { + // 通过后端服务,读取系统下所有账户的崩溃日志信息 + m_process.start("/bin/bash", QStringList() << "-c" << "coredumpctl list --no-pager"); + m_process.waitForFinished(-1); + + return m_process.readAllStandardOutput(); + } else if (filePath.startsWith("coredumpctl info")) { + // 通过后端服务,按进程号获取崩溃信息 + m_process.start("/bin/bash", QStringList() << "-c" << filePath); + m_process.waitForFinished(-1); + + return m_process.readAllStandardOutput(); + } else { + m_process.start("cat", QStringList() << filePath); + m_process.waitForFinished(-1); + QByteArray byte = m_process.readAllStandardOutput(); + + //QByteArray -> QString 如果遇到0x00,会导致转换终止 + //replace("\x00", "")和replace("\u0000", "")无效 + //使用remove操作,性能损耗过大,因此遇到0x00 替换为 0x20(空格符) + qCInfo(logService) << "replace 0x00 to 0x20 begin"; + int replaceTimes = 0; + for (int i = 0; i != byte.size(); ++i) { + if (byte.at(i) == 0x00) { + byte[i] = 0x20; + replaceTimes++; + } } + qCInfo(logService) << "replace 0x00 to 0x20 end. replaceTimes:" << replaceTimes; + return QString::fromUtf8(byte); } - qCInfo(logService) << "replace 0x00 to 0x20 end. replaceTimes:" << replaceTimes; - return QString::fromUtf8(byte); } /*! diff --git a/translations/deepin-log-viewer.ts b/translations/deepin-log-viewer.ts index 1205693e..703e180a 100644 --- a/translations/deepin-log-viewer.ts +++ b/translations/deepin-log-viewer.ts @@ -520,6 +520,30 @@ SELF APPNAME + + Export logs within a specified time period + + + + PERIOD + + + + Export logs within a specified debug level + + + + LEVEL + + + + Export boot logs within a specified status + + + + BOOT STATUS + + titlebar