forked from quickshell/quickshell
		
	core/command: add log --follow
This commit is contained in:
		
							parent
							
								
									c78381f6d0
								
							
						
					
					
						commit
						a82fbf40c2
					
				
					 8 changed files with 262 additions and 63 deletions
				
			
		| 
						 | 
					@ -1,10 +1,14 @@
 | 
				
			||||||
#include "logging.hpp"
 | 
					#include "logging.hpp"
 | 
				
			||||||
#include <array>
 | 
					#include <array>
 | 
				
			||||||
 | 
					#include <cerrno>
 | 
				
			||||||
#include <cstdio>
 | 
					#include <cstdio>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <fcntl.h>
 | 
				
			||||||
#include <qbytearrayview.h>
 | 
					#include <qbytearrayview.h>
 | 
				
			||||||
 | 
					#include <qcoreapplication.h>
 | 
				
			||||||
#include <qdatetime.h>
 | 
					#include <qdatetime.h>
 | 
				
			||||||
#include <qendian.h>
 | 
					#include <qendian.h>
 | 
				
			||||||
 | 
					#include <qfilesystemwatcher.h>
 | 
				
			||||||
#include <qhash.h>
 | 
					#include <qhash.h>
 | 
				
			||||||
#include <qhashfunctions.h>
 | 
					#include <qhashfunctions.h>
 | 
				
			||||||
#include <qlist.h>
 | 
					#include <qlist.h>
 | 
				
			||||||
| 
						 | 
					@ -356,6 +360,18 @@ void ThreadLogging::initFs() {
 | 
				
			||||||
		delete detailedFile;
 | 
							delete detailedFile;
 | 
				
			||||||
		detailedFile = nullptr;
 | 
							detailedFile = nullptr;
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
 | 
							auto lock = flock {
 | 
				
			||||||
 | 
							    .l_type = F_WRLCK,
 | 
				
			||||||
 | 
							    .l_whence = SEEK_SET,
 | 
				
			||||||
 | 
							    .l_start = 0,
 | 
				
			||||||
 | 
							    .l_len = 0,
 | 
				
			||||||
 | 
							};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (fcntl(detailedFile->handle(), F_SETLK, &lock) != 0) { // NOLINT
 | 
				
			||||||
 | 
								qCWarning(logLogging) << "Unable to set lock marker on detailed log file. --follow from "
 | 
				
			||||||
 | 
								                         "other instances will not work.";
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		qCInfo(logLogging) << "Saving detailed logs to" << path;
 | 
							qCInfo(logLogging) << "Saving detailed logs to" << path;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -737,22 +753,13 @@ bool EncodedLogReader::registerCategory() {
 | 
				
			||||||
	return true;
 | 
						return true;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool readEncodedLogs(QIODevice* device, bool timestamps, int tail, const QString& rulespec) {
 | 
					bool LogReader::initialize() {
 | 
				
			||||||
	QList<QLoggingRule> rules;
 | 
						this->reader.setDevice(this->file);
 | 
				
			||||||
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		QLoggingSettingsParser parser;
 | 
					 | 
				
			||||||
		parser.setContent(rulespec);
 | 
					 | 
				
			||||||
		rules = parser.rules();
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	auto reader = EncodedLogReader();
 | 
					 | 
				
			||||||
	reader.setDevice(device);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	bool readable = false;
 | 
						bool readable = false;
 | 
				
			||||||
	quint8 logVersion = 0;
 | 
						quint8 logVersion = 0;
 | 
				
			||||||
	quint8 readerVersion = 0;
 | 
						quint8 readerVersion = 0;
 | 
				
			||||||
	if (!reader.readHeader(&readable, &logVersion, &readerVersion)) {
 | 
						if (!this->reader.readHeader(&readable, &logVersion, &readerVersion)) {
 | 
				
			||||||
		qCritical() << "Failed to read log header.";
 | 
							qCritical() << "Failed to read log header.";
 | 
				
			||||||
		return false;
 | 
							return false;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -765,29 +772,33 @@ bool readEncodedLogs(QIODevice* device, bool timestamps, int tail, const QString
 | 
				
			||||||
		return false;
 | 
							return false;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return true;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool LogReader::continueReading() {
 | 
				
			||||||
	auto color = LogManager::instance()->colorLogs;
 | 
						auto color = LogManager::instance()->colorLogs;
 | 
				
			||||||
 | 
						auto tailRing = RingBuffer<LogMessage>(this->remainingTail);
 | 
				
			||||||
	auto filters = QHash<quint16, CategoryFilter>();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	auto tailRing = RingBuffer<LogMessage>(tail);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	LogMessage message;
 | 
						LogMessage message;
 | 
				
			||||||
	auto stream = QTextStream(stdout);
 | 
						auto stream = QTextStream(stdout);
 | 
				
			||||||
	while (reader.read(&message)) {
 | 
						auto readCursor = this->file->pos();
 | 
				
			||||||
 | 
						while (this->reader.read(&message)) {
 | 
				
			||||||
 | 
							readCursor = this->file->pos();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		CategoryFilter filter;
 | 
							CategoryFilter filter;
 | 
				
			||||||
		if (filters.contains(message.readCategoryId)) {
 | 
							if (this->filters.contains(message.readCategoryId)) {
 | 
				
			||||||
			filter = filters.value(message.readCategoryId);
 | 
								filter = this->filters.value(message.readCategoryId);
 | 
				
			||||||
		} else {
 | 
							} else {
 | 
				
			||||||
			for (const auto& rule: rules) {
 | 
								for (const auto& rule: this->rules) {
 | 
				
			||||||
				filter.applyRule(message.category, rule);
 | 
									filter.applyRule(message.category, rule);
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			filters.insert(message.readCategoryId, filter);
 | 
								this->filters.insert(message.readCategoryId, filter);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (filter.shouldDisplay(message.type)) {
 | 
							if (filter.shouldDisplay(message.type)) {
 | 
				
			||||||
			if (tail == 0) {
 | 
								if (this->remainingTail == 0) {
 | 
				
			||||||
				LogMessage::formatMessage(stream, message, color, timestamps);
 | 
									LogMessage::formatMessage(stream, message, color, this->timestamps);
 | 
				
			||||||
				stream << '\n';
 | 
									stream << '\n';
 | 
				
			||||||
			} else {
 | 
								} else {
 | 
				
			||||||
				tailRing.emplace(message);
 | 
									tailRing.emplace(message);
 | 
				
			||||||
| 
						 | 
					@ -795,19 +806,97 @@ bool readEncodedLogs(QIODevice* device, bool timestamps, int tail, const QString
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (tail != 0) {
 | 
						if (this->remainingTail != 0) {
 | 
				
			||||||
		for (auto i = tailRing.size() - 1; i != -1; i--) {
 | 
							for (auto i = tailRing.size() - 1; i != -1; i--) {
 | 
				
			||||||
			auto& message = tailRing.at(i);
 | 
								auto& message = tailRing.at(i);
 | 
				
			||||||
			LogMessage::formatMessage(stream, message, color, timestamps);
 | 
								LogMessage::formatMessage(stream, message, color, this->timestamps);
 | 
				
			||||||
			stream << '\n';
 | 
								stream << '\n';
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	stream << Qt::flush;
 | 
						stream << Qt::flush;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!device->atEnd()) {
 | 
						if (this->file->pos() != readCursor) {
 | 
				
			||||||
		qCritical() << "An error occurred parsing the end of this log file.";
 | 
							qCritical() << "An error occurred parsing the end of this log file.";
 | 
				
			||||||
		qCritical() << "Remaining data:" << device->readAll();
 | 
							qCritical() << "Remaining data:" << this->file->readAll();
 | 
				
			||||||
 | 
							return false;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return true;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void LogFollower::FcntlWaitThread::run() {
 | 
				
			||||||
 | 
						auto lock = flock {
 | 
				
			||||||
 | 
						    .l_type = F_RDLCK, // won't block other read locks when we take it
 | 
				
			||||||
 | 
						    .l_whence = SEEK_SET,
 | 
				
			||||||
 | 
						    .l_start = 0,
 | 
				
			||||||
 | 
						    .l_len = 0,
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						auto r = fcntl(this->follower->reader->file->handle(), F_SETLKW, &lock); // NOLINT
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (r != 0) {
 | 
				
			||||||
 | 
							qCWarning(logLogging).nospace()
 | 
				
			||||||
 | 
							    << "Failed to wait for write locks to be removed from log file with error code " << errno
 | 
				
			||||||
 | 
							    << ": " << qt_error_string();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool LogFollower::follow() {
 | 
				
			||||||
 | 
						QObject::connect(&this->waitThread, &QThread::finished, this, &LogFollower::onFileLocked);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						QObject::connect(
 | 
				
			||||||
 | 
						    &this->fileWatcher,
 | 
				
			||||||
 | 
						    &QFileSystemWatcher::fileChanged,
 | 
				
			||||||
 | 
						    this,
 | 
				
			||||||
 | 
						    &LogFollower::onFileChanged
 | 
				
			||||||
 | 
						);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						this->fileWatcher.addPath(this->path);
 | 
				
			||||||
 | 
						this->waitThread.start();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						auto r = QCoreApplication::exec();
 | 
				
			||||||
 | 
						return r == 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void LogFollower::onFileChanged() {
 | 
				
			||||||
 | 
						if (!this->reader->continueReading()) {
 | 
				
			||||||
 | 
							QCoreApplication::exit(1);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void LogFollower::onFileLocked() {
 | 
				
			||||||
 | 
						if (!this->reader->continueReading()) {
 | 
				
			||||||
 | 
							QCoreApplication::exit(1);
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							QCoreApplication::exit(0);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool readEncodedLogs(
 | 
				
			||||||
 | 
					    QFile* file,
 | 
				
			||||||
 | 
					    const QString& path,
 | 
				
			||||||
 | 
					    bool timestamps,
 | 
				
			||||||
 | 
					    int tail,
 | 
				
			||||||
 | 
					    bool follow,
 | 
				
			||||||
 | 
					    const QString& rulespec
 | 
				
			||||||
 | 
					) {
 | 
				
			||||||
 | 
						QList<QLoggingRule> rules;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							QLoggingSettingsParser parser;
 | 
				
			||||||
 | 
							parser.setContent(rulespec);
 | 
				
			||||||
 | 
							rules = parser.rules();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						auto reader = LogReader(file, timestamps, tail, rules);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!reader.initialize()) return false;
 | 
				
			||||||
 | 
						if (!reader.continueReading()) return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (follow) {
 | 
				
			||||||
 | 
							auto follower = LogFollower(&reader, path);
 | 
				
			||||||
 | 
							return follower.follow();
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return true;
 | 
						return true;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -4,6 +4,7 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <qcontainerfwd.h>
 | 
					#include <qcontainerfwd.h>
 | 
				
			||||||
#include <qdatetime.h>
 | 
					#include <qdatetime.h>
 | 
				
			||||||
 | 
					#include <qfile.h>
 | 
				
			||||||
#include <qhash.h>
 | 
					#include <qhash.h>
 | 
				
			||||||
#include <qlatin1stringview.h>
 | 
					#include <qlatin1stringview.h>
 | 
				
			||||||
#include <qlogging.h>
 | 
					#include <qlogging.h>
 | 
				
			||||||
| 
						 | 
					@ -130,7 +131,14 @@ private:
 | 
				
			||||||
	LoggingThreadProxy threadProxy;
 | 
						LoggingThreadProxy threadProxy;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool readEncodedLogs(QIODevice* device, bool timestamps, int tail, const QString& rulespec);
 | 
					bool readEncodedLogs(
 | 
				
			||||||
 | 
					    QFile* file,
 | 
				
			||||||
 | 
					    const QString& path,
 | 
				
			||||||
 | 
					    bool timestamps,
 | 
				
			||||||
 | 
					    int tail,
 | 
				
			||||||
 | 
					    bool follow,
 | 
				
			||||||
 | 
					    const QString& rulespec
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
} // namespace qs::log
 | 
					} // namespace qs::log
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,12 +1,18 @@
 | 
				
			||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
 | 
					#include <utility>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <qbytearrayview.h>
 | 
					#include <qbytearrayview.h>
 | 
				
			||||||
#include <qcontainerfwd.h>
 | 
					#include <qcontainerfwd.h>
 | 
				
			||||||
#include <qfile.h>
 | 
					#include <qfile.h>
 | 
				
			||||||
 | 
					#include <qfilesystemwatcher.h>
 | 
				
			||||||
#include <qlogging.h>
 | 
					#include <qlogging.h>
 | 
				
			||||||
 | 
					#include <qobject.h>
 | 
				
			||||||
 | 
					#include <qthread.h>
 | 
				
			||||||
#include <qtmetamacros.h>
 | 
					#include <qtmetamacros.h>
 | 
				
			||||||
#include <qtypes.h>
 | 
					#include <qtypes.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "logging.hpp"
 | 
					#include "logging.hpp"
 | 
				
			||||||
 | 
					#include "logging_qtprivate.hpp"
 | 
				
			||||||
#include "ringbuf.hpp"
 | 
					#include "ringbuf.hpp"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace qs::log {
 | 
					namespace qs::log {
 | 
				
			||||||
| 
						 | 
					@ -120,4 +126,64 @@ private:
 | 
				
			||||||
	EncodedLogWriter detailedWriter;
 | 
						EncodedLogWriter detailedWriter;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class LogFollower;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class LogReader {
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
						explicit LogReader(
 | 
				
			||||||
 | 
						    QFile* file,
 | 
				
			||||||
 | 
						    bool timestamps,
 | 
				
			||||||
 | 
						    int tail,
 | 
				
			||||||
 | 
						    QList<qt_logging_registry::QLoggingRule> rules
 | 
				
			||||||
 | 
						)
 | 
				
			||||||
 | 
						    : file(file)
 | 
				
			||||||
 | 
						    , timestamps(timestamps)
 | 
				
			||||||
 | 
						    , remainingTail(tail)
 | 
				
			||||||
 | 
						    , rules(std::move(rules)) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						bool initialize();
 | 
				
			||||||
 | 
						bool continueReading();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					private:
 | 
				
			||||||
 | 
						QFile* file;
 | 
				
			||||||
 | 
						EncodedLogReader reader;
 | 
				
			||||||
 | 
						bool timestamps;
 | 
				
			||||||
 | 
						int remainingTail;
 | 
				
			||||||
 | 
						QHash<quint16, CategoryFilter> filters;
 | 
				
			||||||
 | 
						QList<qt_logging_registry::QLoggingRule> rules;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						friend class LogFollower;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class LogFollower: public QObject {
 | 
				
			||||||
 | 
						Q_OBJECT;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
						explicit LogFollower(LogReader* reader, QString path): reader(reader), path(std::move(path)) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						bool follow();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					private slots:
 | 
				
			||||||
 | 
						void onFileChanged();
 | 
				
			||||||
 | 
						void onFileLocked();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					private:
 | 
				
			||||||
 | 
						LogReader* reader;
 | 
				
			||||||
 | 
						QString path;
 | 
				
			||||||
 | 
						QFileSystemWatcher fileWatcher;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						class FcntlWaitThread: public QThread {
 | 
				
			||||||
 | 
						public:
 | 
				
			||||||
 | 
							explicit FcntlWaitThread(LogFollower* follower): follower(follower) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						protected:
 | 
				
			||||||
 | 
							void run() override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private:
 | 
				
			||||||
 | 
							LogFollower* follower;
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						FcntlWaitThread waitThread {this};
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
} // namespace qs::log
 | 
					} // namespace qs::log
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -16,34 +16,13 @@
 | 
				
			||||||
#include <qstringview.h>
 | 
					#include <qstringview.h>
 | 
				
			||||||
#include <qtypes.h>
 | 
					#include <qtypes.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "logging_qtprivate.hpp"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace qs::log {
 | 
					namespace qs::log {
 | 
				
			||||||
Q_DECLARE_LOGGING_CATEGORY(logLogging);
 | 
					Q_DECLARE_LOGGING_CATEGORY(logLogging);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace qt_logging_registry {
 | 
					namespace qt_logging_registry {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class QLoggingRule {
 | 
					 | 
				
			||||||
public:
 | 
					 | 
				
			||||||
	QLoggingRule();
 | 
					 | 
				
			||||||
	QLoggingRule(QStringView pattern, bool enabled);
 | 
					 | 
				
			||||||
	[[nodiscard]] int pass(QLatin1StringView categoryName, QtMsgType type) const;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	enum PatternFlag {
 | 
					 | 
				
			||||||
		FullText = 0x1,
 | 
					 | 
				
			||||||
		LeftFilter = 0x2,
 | 
					 | 
				
			||||||
		RightFilter = 0x4,
 | 
					 | 
				
			||||||
		MidFilter = LeftFilter | RightFilter
 | 
					 | 
				
			||||||
	};
 | 
					 | 
				
			||||||
	Q_DECLARE_FLAGS(PatternFlags, PatternFlag)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	QString category;
 | 
					 | 
				
			||||||
	int messageType;
 | 
					 | 
				
			||||||
	PatternFlags flags;
 | 
					 | 
				
			||||||
	bool enabled;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
private:
 | 
					 | 
				
			||||||
	void parse(QStringView pattern);
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class QLoggingSettingsParser {
 | 
					class QLoggingSettingsParser {
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
	void setContent(QStringView content);
 | 
						void setContent(QStringView content);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										44
									
								
								src/core/logging_qtprivate.hpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								src/core/logging_qtprivate.hpp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,44 @@
 | 
				
			||||||
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// The logging rule parser from qloggingregistry_p.h and qloggingregistry.cpp.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Was unable to properly link the functions when directly using the headers (which we depend
 | 
				
			||||||
 | 
					// on anyway), so below is a slightly stripped down copy. Making the originals link would
 | 
				
			||||||
 | 
					// be preferable.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <qflags.h>
 | 
				
			||||||
 | 
					#include <qlogging.h>
 | 
				
			||||||
 | 
					#include <qloggingcategory.h>
 | 
				
			||||||
 | 
					#include <qstringview.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace qs::log {
 | 
				
			||||||
 | 
					Q_DECLARE_LOGGING_CATEGORY(logLogging);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace qt_logging_registry {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class QLoggingRule {
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
						QLoggingRule();
 | 
				
			||||||
 | 
						QLoggingRule(QStringView pattern, bool enabled);
 | 
				
			||||||
 | 
						[[nodiscard]] int pass(QLatin1StringView categoryName, QtMsgType type) const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						enum PatternFlag {
 | 
				
			||||||
 | 
							FullText = 0x1,
 | 
				
			||||||
 | 
							LeftFilter = 0x2,
 | 
				
			||||||
 | 
							RightFilter = 0x4,
 | 
				
			||||||
 | 
							MidFilter = LeftFilter | RightFilter
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
						Q_DECLARE_FLAGS(PatternFlags, PatternFlag)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						QString category;
 | 
				
			||||||
 | 
						int messageType;
 | 
				
			||||||
 | 
						PatternFlags flags;
 | 
				
			||||||
 | 
						bool enabled;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					private:
 | 
				
			||||||
 | 
						void parse(QStringView pattern);
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					} // namespace qt_logging_registry
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					} // namespace qs::log
 | 
				
			||||||
| 
						 | 
					@ -96,6 +96,7 @@ struct CommandState {
 | 
				
			||||||
		bool sparse = false;
 | 
							bool sparse = false;
 | 
				
			||||||
		size_t verbosity = 0;
 | 
							size_t verbosity = 0;
 | 
				
			||||||
		int tail = 0;
 | 
							int tail = 0;
 | 
				
			||||||
 | 
							bool follow = false;
 | 
				
			||||||
		QStringOption rules;
 | 
							QStringOption rules;
 | 
				
			||||||
		QStringOption readoutRules;
 | 
							QStringOption readoutRules;
 | 
				
			||||||
		QStringOption file;
 | 
							QStringOption file;
 | 
				
			||||||
| 
						 | 
					@ -241,13 +242,10 @@ int runCommand(int argc, char** argv, QCoreApplication* coreApplication) {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		auto* sub = cli.add_subcommand(
 | 
							auto* sub = cli.add_subcommand("log", "Read quickshell logs.\n")
 | 
				
			||||||
		    "log",
 | 
							                ->description("If --file is specified, the given file will be read.\n"
 | 
				
			||||||
		    "Read quickshell logs.\n"
 | 
							                              "If not, the log of the first launched instance matching"
 | 
				
			||||||
		    "If --file is specified, the given file will be read.\n"
 | 
							                              "the instance selection flags will be read.");
 | 
				
			||||||
		    "If not, the log of the first launched instance matching"
 | 
					 | 
				
			||||||
		    "the instance selection flags will be read."
 | 
					 | 
				
			||||||
		);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		auto* file = sub->add_option("--file", state.log.file, "Log file to read.");
 | 
							auto* file = sub->add_option("--file", state.log.file, "Log file to read.");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -255,6 +253,9 @@ int runCommand(int argc, char** argv, QCoreApplication* coreApplication) {
 | 
				
			||||||
		    ->description("Maximum number of lines to print, starting from the bottom.")
 | 
							    ->description("Maximum number of lines to print, starting from the bottom.")
 | 
				
			||||||
		    ->check(CLI::Range(1, std::numeric_limits<int>::max(), "INT > 0"));
 | 
							    ->check(CLI::Range(1, std::numeric_limits<int>::max(), "INT > 0"));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							sub->add_flag("--follow", state.log.follow)
 | 
				
			||||||
 | 
							    ->description("Keep reading the log until the logging process terminates.");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		sub->add_option("-r,--rules", state.log.readoutRules, "Log file to read.")
 | 
							sub->add_option("-r,--rules", state.log.readoutRules, "Log file to read.")
 | 
				
			||||||
		    ->description("Rules to apply to the log being read, in the format of QT_LOGGING_RULES.");
 | 
							    ->description("Rules to apply to the log being read, in the format of QT_LOGGING_RULES.");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -267,6 +268,7 @@ int runCommand(int argc, char** argv, QCoreApplication* coreApplication) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		auto* sub = cli.add_subcommand("list", "List running quickshell instances.");
 | 
							auto* sub = cli.add_subcommand("list", "List running quickshell instances.");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		auto* all = sub->add_flag("-a,--all", state.instance.all)
 | 
							auto* all = sub->add_flag("-a,--all", state.instance.all)
 | 
				
			||||||
		                ->description("List all instances.\n"
 | 
							                ->description("List all instances.\n"
 | 
				
			||||||
		                              "If unspecified, only instances of"
 | 
							                              "If unspecified, only instances of"
 | 
				
			||||||
| 
						 | 
					@ -472,7 +474,14 @@ int readLogFile(CommandState& cmd) {
 | 
				
			||||||
		return -1;
 | 
							return -1;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return qs::log::readEncodedLogs(&file, cmd.log.timestamp, cmd.log.tail, *cmd.log.readoutRules)
 | 
						return qs::log::readEncodedLogs(
 | 
				
			||||||
 | 
						           &file,
 | 
				
			||||||
 | 
						           path,
 | 
				
			||||||
 | 
						           cmd.log.timestamp,
 | 
				
			||||||
 | 
						           cmd.log.tail,
 | 
				
			||||||
 | 
						           cmd.log.follow,
 | 
				
			||||||
 | 
						           *cmd.log.readoutRules
 | 
				
			||||||
 | 
						       )
 | 
				
			||||||
	         ? 0
 | 
						         ? 0
 | 
				
			||||||
	         : -1;
 | 
						         : -1;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -36,11 +36,14 @@ QDir QsPaths::crashDir(const QString& id) {
 | 
				
			||||||
	return dir;
 | 
						return dir;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					QString QsPaths::basePath(const QString& id) {
 | 
				
			||||||
 | 
						auto path = QsPaths::instance()->baseRunDir()->filePath("by-id");
 | 
				
			||||||
 | 
						path = QDir(path).filePath(id);
 | 
				
			||||||
 | 
						return path;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
QString QsPaths::ipcPath(const QString& id) {
 | 
					QString QsPaths::ipcPath(const QString& id) {
 | 
				
			||||||
	auto ipcPath = QsPaths::instance()->baseRunDir()->filePath("by-id");
 | 
						return QDir(QsPaths::basePath(id)).filePath("ipc.sock");
 | 
				
			||||||
	ipcPath = QDir(ipcPath).filePath(id);
 | 
					 | 
				
			||||||
	ipcPath = QDir(ipcPath).filePath("ipc.sock");
 | 
					 | 
				
			||||||
	return ipcPath;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
QDir* QsPaths::cacheDir() {
 | 
					QDir* QsPaths::cacheDir() {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -17,6 +17,7 @@ public:
 | 
				
			||||||
	static QsPaths* instance();
 | 
						static QsPaths* instance();
 | 
				
			||||||
	static void init(QString shellId, QString pathId);
 | 
						static void init(QString shellId, QString pathId);
 | 
				
			||||||
	static QDir crashDir(const QString& id);
 | 
						static QDir crashDir(const QString& id);
 | 
				
			||||||
 | 
						static QString basePath(const QString& id);
 | 
				
			||||||
	static QString ipcPath(const QString& id);
 | 
						static QString ipcPath(const QString& id);
 | 
				
			||||||
	static bool checkLock(const QString& path, InstanceLockInfo* info = nullptr);
 | 
						static bool checkLock(const QString& path, InstanceLockInfo* info = nullptr);
 | 
				
			||||||
	static QVector<InstanceLockInfo> collectInstances(const QString& path);
 | 
						static QVector<InstanceLockInfo> collectInstances(const QString& path);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue