在线程中输出控制台打印方法

LogerThread.h

#ifndef LOGERTHREAD_H
#define LOGERTHREAD_H

#include <QThread>
#include <QFile>
#include <QStringList>
#include <QMutexLocker>

class LogerThread : public QThread
{
    Q_OBJECT
private:
    explicit LogerThread(QObject *parent = nullptr);
public:
    ~LogerThread();

    void log(QString msg);                    // 日志信息设置

    void run();
    // 创建单例
    static LogerThread* instance()
    {
        if(!_pInstance)
        {
            QMutexLocker mutexLocker(&_mutex);
//            if(!_pInstance)
//            {
                LogerThread *pInstance = new LogerThread();
                _pInstance = pInstance;
//            }
        }
        return _pInstance;
    }

private:
    static LogerThread *_pInstance;
    static QMutex _mutex;

    bool _isRun;                                     // 线程是否运行标志
    QFile *_pLogFile;                                // 日志文件
    QString _logPath;                                // 日志文件存储路径

    QStringList _msgList;                            // 日志缓冲的list
};

#endif // LOGERTHREAD_H

LogerThread.cpp

#include "LogerThread.h"
#include <QDir>
#include <QFileInfoList>
#include <QDateTime>
#include <QApplication>
#include <QString>

LogerThread * LogerThread::_pInstance = nullptr;
QMutex LogerThread::_mutex;
LogerThread::LogerThread(QObject *parent) :
    QThread(parent), _isRun(true), _pLogFile(nullptr)
{
    _logPath = QString("%1/log").arg(qApp->applicationDirPath());
    this->start();
}

LogerThread::~LogerThread()
{
    _isRun = false;
    this->terminate();
    this->wait();
}

void LogerThread::run()
{
    QDir logDir(_logPath);
    if (!logDir.exists())
    {
        logDir.mkpath(_logPath);
    }
    // 限制日志文件最大10M
    qint64 maxLogSize = 1024*1024*10;
    // 通过时间戳来对文件命名
    QString logPath = QString("%1/%2.log").arg(_logPath).arg(QDateTime::currentDateTime().toString("yyyy-MM-dd_hhmmss_zzz"));

    _pLogFile = new QFile(logPath);
    {
        while (_isRun)
        {
            // 超过最大限制则重新创建新文件
            if (_pLogFile->isOpen() && _pLogFile->size() >= maxLogSize)
            {
                _pLogFile->close();
            }
            if (!_pLogFile->isOpen())
            {
                _pLogFile->setFileName(logPath);
                // 注意写入时需要以追加形式打开文件
                if (!_pLogFile->open(QFile::WriteOnly | QFile::Append))
                    this->msleep(1000);
                continue;
            }
            QByteArray logText;
            while (_msgList.length() > 0 && _isRun)
            {
                logText = _msgList.first().toLocal8Bit();
                logText.append("\n");
                if (_pLogFile->write(logText) == -1)
                    break;
                _msgList.removeFirst();
            }
            this->msleep(500);
        }
        _pLogFile->close();
    }
}

void LogerThread::log(QString msg)
{
    if(msg.length() > 0)
    {
        _msgList.append(msg);
    }
}

 main.cpp

#include "LogerThread.h"


static void prepareLog()
{
    QDateTime time = QDateTime::currentDateTime();
    int curTime = int(time.toTime_t());
    // 设置日志多少天删除
    int deleteTime = 3 * 24 * 60 * 60;

    // 删除log文件夹里面超过7天的文件
    QDir dir(QApplication::applicationDirPath()+"/log");
    if (dir.exists())
    {
        qDebug()<<"delete log file-----------------------";
        dir.setFilter(QDir::AllEntries | QDir::NoDotAndDotDot);
        QFileInfoList fileList = dir.entryInfoList();
        foreach (QFileInfo file, fileList)
        {
            if(file.isFile())
            {
                int modifyTime = int(file.lastModified().toTime_t());
                if(curTime - modifyTime > deleteTime)
                {
                    file.dir().remove(file.fileName());
                }
            }
        }
    }
}

void logOutput(QtMsgType type, const QMessageLogContext &context, const QString &msg)
{
    static QMutex mutex;
    mutex.lock();

    QString text;
    text.append(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss:zzz"));
    QFileInfo fileName(QString(context.file));

    switch(int(type))
    {
    case QtDebugMsg:
        text.append("[D] ");
        break;

    case QtWarningMsg:
        text.append("[W] ");
        break;

    case QtCriticalMsg:
        text.append("[C] ");
        break;

    case QtFatalMsg:
        text.append("[F] ");
        break;
    }
    text.append(fileName.fileName() + "-");
    text.append(msg);

    mutex.unlock();

    // 是否输出日志到日志文件
    // 创建单例线程来实时获取记录程序输出的各种日志信息
    LogerThread::instance()->log(text);
}


int main(int argc, char *argv[])
{
    // 删除超时的日志文件
    prepareLog();

#define CONSOLE_ENABLE
#if defined (CONSOLE_ENABLE)
    qInstallMessageHandler(logOutput);
#endif

    QApplication a(argc, argv);
    static QTranslator translator;
    a.installTranslator(&translator);

    Widget *w = new Widget;

    w->setMinimumHeight(520);
    w->setMinimumWidth(1020);
    w->show();
    return a.exec();
}
目前不知道为啥QString::fromUtf8(context.function) 和 QString(context.line)的打印信息有问题

限制在qml界面显示100条日志信息,支持日志信息的增删

LogMessages.h

#pragma once

#ifndef LOGMESSAGES_H
#define LOGMESSAGES_H

#include <QObject>
#include <QAbstractListModel>

class LogData;
class LogMessages : public QAbstractListModel
{
    Q_OBJECT
public:
    /** 条目中的角色类型
    *  @param[TypeRole]对应LogData的(QString)type;[SizeRole1]对应LogData的(QString)size
    *  @return null
    */
    enum AnimalRoles {
        TypeRole = Qt::UserRole + 1,
        SizeRole1
    };
    explicit LogMessages(QObject *parent = nullptr);
    ~LogMessages();

public: // QAbstractItemModel interface
    int rowCount(const QModelIndex &parent = QModelIndex()) const override;
    /** 根据索引和角色获取条目的数据
    *  @param[index]索引;[role]数据角色
    *  @return null
    */
    QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
    /** 根据索引和角色获取条目的数据
    *  @param[index]索引;[role]数据角色
    *  @return null
    */
    Q_INVOKABLE void append(const LogData &data);
    /** 增加条目
    *  @param[index]索引
    *  @return null
    */
    Q_INVOKABLE void insert(int index, const LogData &data);
    /** 根据索引删除条目
    *  @param[index]索引
    *  @return null
    */
    Q_INVOKABLE void remove(int index);
    /** 增加条目
    *  @param[map]数据
    *  @return null
    */
    Q_INVOKABLE void append(const QVariantMap map);

    bool modelData(int index, LogData &modelData);

signals:
    void countChanged(int arg);

private:
    int count() const;

protected:
    QHash<int, QByteArray> roleNames() const override;

private:
    QList<LogData> m_data;
};

class LogData
{
public:
    LogData(const QString &type, const QString &size):
        m_type(type), m_size(size)
    {

    }

    QString type() const {return m_type;}
    QString size() const {return m_size;}

private:
    QString m_type;
    QString m_size;
};
#endif // LOGMESSAGES_H

LogMessages.cpp

#include "LogMessages.h"
#include <QDebug>

LogMessages::LogMessages(QObject *parent):
    QAbstractListModel(parent)
{

}

LogMessages::~LogMessages()
{

}

int LogMessages::rowCount(const QModelIndex &parent) const
{
    Q_UNUSED(parent)
    return m_data.count();
}

QVariant LogMessages::data(const QModelIndex &index, int role) const
{
    if (index.row() < 0 || index.row() >= m_data.count())
        return QVariant();

    const LogData &data = m_data[index.row()];

    if (role == TypeRole)
        return data.type();
    else if (role == SizeRole1)
        return data.size();

    return QVariant();
}

void LogMessages::insert(int index, const LogData &data)
{
    if(index < 0 || index > m_data.count()) {
        return;
    }

    beginInsertRows(QModelIndex(), index, index);
    m_data.insert(index, data);
    endInsertRows();
    emit countChanged(m_data.count());
}

void LogMessages::append(const LogData &data)
{
    m_data.insert(count(), data);
    emit countChanged(m_data.count());
}

void LogMessages::remove(int index)
{
    if(index < 0 || index >= m_data.count()) {
        return;
    }

    beginRemoveRows(QModelIndex(), index, index);
    m_data.removeAt( index );
    endRemoveRows();
    emit countChanged(m_data.count());
}

void LogMessages::append(const QVariantMap map)
{
    QString type = map["type"].toString();
    QString size = map["size"].toString();

    LogData data(type, size);

    insert(count(), data);
}

bool LogMessages::modelData(int index, LogData &modelData)
{
    if(index < 0 || index >= m_data.count()) {
        return false;
    }

    modelData = m_data.at(index);
    return true;
}

int LogMessages::count() const
{
    return rowCount(QModelIndex());
}

QHash<int, QByteArray> LogMessages::roleNames() const
{
    QHash<int, QByteArray> roles;
    roles[TypeRole] = "type";
    roles[SizeRole1] = "size";
    return roles;
}

在创建以上类的基础上执行以下操作:

1.创建main中全局静态对象:

static LogMessages logModel;

2.同时创建上下文属性modelManager用于qml显示:

_qmlAppEngine->rootContext()->setContextProperty("modelManager", &logModel);

3.在main文件的logoutput函数增加对text文本的append

  if(logModel.rowCount() >= 100)// 限制最多显示100条 多的在log文件夹下通过日志看
    {
        logModel.remove(logModel.rowCount()-1);
    }
    logModel.append(LogData(text,""));
    QModelIndex modelIndex;
    modelIndex = logModel.index(logModel.rowCount()-1,0,QModelIndex());
    qDebug()<<logModel.rowCount()<<logModel.data(modelIndex,LogMessages::TypeRole);

4.qml中调用

//import 包

Rectangle {
    id: logView

    color: "transparent"
    ScrollView
    {
        id: myLessFlow
        anchors.fill: parent
        anchors.topMargin: 40
        anchors.leftMargin: 24
        anchors.bottomMargin: 40
        anchors.rightMargin: 24
        ScrollBar.vertical.policy: ScrollBar.AlwaysOn
        ScrollBar.horizontal.policy: ScrollBar.AlwaysOff
        clip: true
        ListView
        {
            id: appInformationView
            anchors.fill: parent
            currentIndex: 0
            highlightMoveDuration: 50
            model: modelManager
            delegate: gridLessDelegate
        }
    }

    Component
    {
        id: gridLessDelegate
        Rectangle
        {
            width: logView.width
            height: innerText.contentHeight+20
            color: (index%2 === 0) ? "#333333" :"#222222"
            Text
            {
                id: innerText
                anchors.fill: parent
                verticalAlignment: Text.AlignVCenter
                text: type
                wrapMode: Text.WrapAnywhere
                font.pixelSize: 14
                color: "#FFFFFF"
            }
        }
    }
}

猜你喜欢

转载自blog.csdn.net/caicai_xiaobai/article/details/132086598