#include "journalwork.h"
#include "utils.h"
#include "qtcompat.h"
#include <DApplication>
#include <QDateTime>
#include <QDebug>
#include <QFile>
#include <QJsonDocument>
#include <QJsonObject>
#include <QProcess>
#include <QLoggingCategory>
Q_DECLARE_LOGGING_CATEGORY(logApp)
DWIDGET_USE_NAMESPACE
std::atomic<journalWork *> journalWork::m_instance;
std::mutex journalWork::m_mutex;
* @brief journalWork::journalWork 线程构造函数
* @param arg 筛选参数
* @param parent 父对象
*/
journalWork::journalWork(QStringList arg, QObject *parent)
: QObject(parent),
QRunnable()
{
qCDebug(logApp) << "journalWork constructor called with args:" << arg;
qRegisterMetaType<QList<LOG_MSG_JOURNAL> >("QList<LOG_MSG_JOURNAL>");
setAutoDelete(true);
initMap();
m_arg.append("-o");
m_arg.append("json");
if (!arg.isEmpty()) {
m_arg.append(arg);
qCDebug(logApp) << "Added journal filter args:" << arg;
}
thread_index++;
m_threadIndex = thread_index;
qCDebug(logApp) << "Thread index set to:" << m_threadIndex;
}
* @brief journalWork::journalWork 线程构造函数
* @param parent 父对象
*/
journalWork::journalWork(QObject *parent)
: QObject(parent),
QRunnable()
{
qCDebug(logApp) << "journalWork default constructor called";
qRegisterMetaType<QList<LOG_MSG_JOURNAL> >("QList<LOG_MSG_JOURNAL>");
initMap();
setAutoDelete(true);
thread_index++;
m_threadIndex = thread_index;
qCDebug(logApp) << "Thread index set to:" << m_threadIndex;
}
* @brief journalWork::~journalWork 析构时清空数据结构
*/
journalWork::~journalWork()
{
qCDebug(logApp) << "journalWork destructor called";
logList.clear();
m_map.clear();
qCDebug(logApp) << "Cleaned up journalWork resources";
}
* @brief journalWork::stopWork 停止该线程
*/
void journalWork::stopWork()
{
qCDebug(logApp) << "journalWork::stopWork called";
m_canRun = false;
}
* @brief journalWork::getIndex 获取当前对象的计数
* @return 当前对象的计数标号
*/
int journalWork::getIndex()
{
qCDebug(logApp) << "journalWork::getIndex called, returning:" << m_threadIndex;
return m_threadIndex;
}
* @brief journalWork::getPublicIndex 获取现在此类产生对象的个数
* @return 此类产生对象的个数,静态成员变量
*/
int journalWork::getPublicIndex()
{
qCDebug(logApp) << "journalWork::getPublicIndex called, returning:" << thread_index;
return thread_index;
}
* @brief journalWork::setArg 设置筛选参数
* @param arg 筛选参数
*/
void journalWork::setArg(QStringList arg)
{
qCDebug(logApp) << "journalWork::setArg called with:" << arg;
m_arg.clear();
if (!arg.isEmpty()) {
m_arg.append(arg);
qCDebug(logApp) << "Arguments set successfully";
}
}
* @brief journalWork::run 线程执行函数
*/
void journalWork::run()
{
qCDebug(logApp) << "journalWork::run thread started";
doWork();
qCDebug(logApp) << "journalWork::run thread finished";
}
* @brief journalWork::doWork 实际的获取数据逻辑
*/
void journalWork::doWork()
{
qCDebug(logApp) << "journalWork::doWork started";
m_canRun = true;
mutex.lock();
logList.clear();
mutex.unlock();
if ((!m_canRun)) {
qCDebug(logApp) << "Work stopped before starting";
return;
}
int r;
sd_journal *j ;
if ((!m_canRun)) {
return;
}
r = sd_journal_open(&j, SD_JOURNAL_LOCAL_ONLY);
if ((!m_canRun)) {
sd_journal_close(j);
return;
}
if (r < 0) {
fprintf(stderr, "Failed to open journal: %s\n", strerror(-r));
return;
}
sd_journal_seek_tail(j);
if ((!m_canRun)) {
sd_journal_close(j);
return;
}
if (!m_arg.isEmpty()) {
QString _priority = m_arg.at(0);
if (_priority != "all")
sd_journal_add_match(j, m_arg.at(0).toStdString().c_str(), 0);
}
if ((!m_canRun)) {
sd_journal_close(j);
return;
}
int cnt = 0;
SD_JOURNAL_FOREACH_BACKWARDS(j) {
if ((!m_canRun)) {
sd_journal_close(j);
return;
}
const char *d;
size_t l;
LOG_MSG_JOURNAL logMsg;
r = sd_journal_get_data(j, "_SOURCE_REALTIME_TIMESTAMP", reinterpret_cast<const void **>(&d), &l);
if (r < 0) {
r = sd_journal_get_data(j, "__REALTIME_TIMESTAMP", reinterpret_cast<const void **>(&d), &l);
if (r < 0) {
continue;
}
}
uint64_t t;
sd_journal_get_realtime_usec(j, &t);
QString dt = getReplaceColorStr(d).split("=").value(1);
if (m_arg.size() == 3) {
if (t < static_cast<uint64_t>(m_arg.at(1).toLongLong()) || t > static_cast<uint64_t>(m_arg.at(2).toLongLong()))
continue;
}
logMsg.dateTime = getDateTimeFromStamp(dt);
r = sd_journal_get_data(j, "_HOSTNAME", reinterpret_cast<const void **>(&d), &l);
if (r < 0)
logMsg.hostName = "";
else {
QStringList strList = getReplaceColorStr(d).split("=");
strList.removeFirst();
logMsg.hostName = strList.join("=");
}
r = sd_journal_get_data(j, "_PID", reinterpret_cast<const void **>(&d), &l);
if (r < 0)
logMsg.daemonId = "";
else {
QStringList strList = getReplaceColorStr(d).split("=");
strList.removeFirst();
logMsg.daemonId = strList.join("=");
}
r = sd_journal_get_data(j, "SYSLOG_IDENTIFIER", reinterpret_cast<const void **>(&d), &l);
if (r < 0) {
r = sd_journal_get_data(j, "_EXE", reinterpret_cast<const void **>(&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(logApp) << "unknown progressname, exe path: " << strList.first();
logMsg.daemonName = "unknown";
}
} else {
qCWarning(logApp) << logMsg.daemonId << "error code" << r;
logMsg.daemonName = "unknown";
}
} else {
QStringList strList = getReplaceColorStr(d).split("=");
strList.removeFirst();
logMsg.daemonName = strList.join("=");
}
r = sd_journal_get_data(j, "MESSAGE", reinterpret_cast<const void **>(&d), &l);
if (r < 0) {
logMsg.msg = "";
} else {
QStringList strList = getReplaceColorStr(d).split("=");
strList.removeFirst();
logMsg.msg = strList.join("=");
}
r = sd_journal_get_data(j, "PRIORITY", reinterpret_cast<const void **>(&d), &l);
if (r < 0) {
logMsg.level = i2str(7);
} else {
logMsg.level = i2str(getReplaceColorStr(d).split("=").value(1).toInt());
}
cnt++;
mutex.lock();
logList.append(logMsg);
mutex.unlock();
if (cnt % 500 == 0) {
mutex.lock();
emit journalData(m_threadIndex, logList);
logList.clear();
mutex.unlock();
}
}
if (logList.count() >= 0) {
emit journalData(m_threadIndex, logList);
}
emit journalFinished(m_threadIndex);
sd_journal_close(j);
}
* @brief JournalBootWork::getReplaceColorStr 替换掉获取字符的颜色字符和特殊符号
* @param d 原字符
* @return 替换后的字符
*/
QString journalWork::getReplaceColorStr(const char *d)
{
qCDebug(logApp) << "journalWork::getReplaceColorStr processing string";
QByteArray byteChar(d);
byteChar = Utils::replaceEmptyByteArray(byteChar);
QString d_str = QString(byteChar);
d_str.replace(REG_EXP("\\x1B\\[\\d+(;\\d+){0,2}m"), "");
d_str.replace(REG_EXP("\\002"), "");
return d_str;
}
* @brief JournalBootWork::getDateTimeFromStamp 通过获取的时间戳转换为格式化的时间显示文本
* @param str 接口获取的原始时间字符
* @return 格式化的时间显示文本
*/
QString journalWork::getDateTimeFromStamp(const QString &str)
{
qCDebug(logApp) << "journalWork::getDateTimeFromStamp converting timestamp:" << str;
QString ret = "";
QString dtstr = str.left(str.length() - 6);
QDateTime dt = DATE_FOTIME(dtstr.toUInt());
ret = dt.toString("yyyy-MM-dd hh:mm:ss");
return ret;
}
* @brief JournalBootWork::initMap 初始化等级数字和等级显示文本的map
*/
void journalWork::initMap()
{
qCDebug(logApp) << "journalWork::initMap initializing level map";
m_map.clear();
m_map.insert(0, DApplication::translate("Level", "Emergency"));
m_map.insert(1, DApplication::translate("Level", "Alert"));
m_map.insert(2, DApplication::translate("Level", "Critical"));
m_map.insert(3, DApplication::translate("Level", "Error"));
m_map.insert(4, DApplication::translate("Level", "Warning"));
m_map.insert(5, DApplication::translate("Level", "Notice"));
m_map.insert(6, DApplication::translate("Level", "Info"));
m_map.insert(7, DApplication::translate("Level", "Debug"));
qCDebug(logApp) << "Level map initialized with" << m_map.size() << "entries";
}
* @brief JournalBootWork::i2str 日志等级到等级显示文本的转换
* @param prio 日志等级数字
* @return 等级显示文
*/
QString journalWork::i2str(int prio)
{
qCDebug(logApp) << "journalWork::i2str converting priority:" << prio;
return m_map.value(prio);
}