25#include "core/LogEntry.h"
34 LogLevel level = LogLevel::Info;
39inline LogLevel levelFromString(
const QString &level) {
40 const QString lower = level.toLower();
41 if (lower ==
"info") {
42 return LogLevel::Info;
44 if (lower ==
"fatal" || lower ==
"error") {
45 return LogLevel::Error;
47 if (lower ==
"warning" || lower ==
"warn") {
48 return LogLevel::Warning;
50 if (lower ==
"debug" || lower ==
"note" || lower ==
"remark") {
51 return LogLevel::Debug;
53 return LogLevel::Info;
56inline ParsedLogLine parseDiagnosticLine(
const QString &line) {
58 if (!line.startsWith(
"@diag\t")) {
62 QString payload = line.mid(6);
63 const QStringList parts = payload.split(
'\t');
64 if (parts.size() < 2) {
68 parsed.level = levelFromString(parts[0]);
69 if (parts.size() >= 5) {
70 const QString file = parts[1];
71 const QString lineNo = parts[2];
72 const QString colNo = parts[3];
73 const QString message = parts.mid(4).join(
"\t");
74 QString location = file;
75 if (!lineNo.isEmpty()) {
76 location +=
":" + lineNo;
78 if (!colNo.isEmpty()) {
79 location +=
":" + colNo;
81 parsed.message = location.isEmpty() ? message
82 : QString(
"%1: %2").arg(location, message);
84 parsed.message = parts.mid(1).join(
"\t");
91inline bool isWordChar(QChar ch) {
92 return ch.isLetterOrNumber() || ch ==
'_';
95inline bool containsSeverityToken(
const QString &lower,
96 const QString &token) {
98 while ((index = lower.indexOf(token, index)) != -1) {
99 const int before = index - 1;
100 const int after = index + token.size();
101 const bool beforeOk =
102 before < 0 || !isWordChar(lower.at(before));
108 if (after >= lower.size()) {
112 const QChar afterChar = lower.at(after);
113 if (afterChar.isSpace() || afterChar ==
':' || afterChar ==
']' ||
114 afterChar ==
')' || afterChar ==
',' || afterChar ==
';') {
118 if (afterChar ==
'.' && after + 1 >= lower.size()) {
128inline LogLevel guessLevelFromText(
const QString &line,
bool isStdErr) {
129 const QString lower = line.toLower();
130 if (containsSeverityToken(lower,
"fatal") ||
131 containsSeverityToken(lower,
"error")) {
132 return LogLevel::Error;
134 if (containsSeverityToken(lower,
"warning") ||
135 containsSeverityToken(lower,
"warn")) {
136 return LogLevel::Warning;
138 if (containsSeverityToken(lower,
"note") ||
139 containsSeverityToken(lower,
"remark") ||
140 containsSeverityToken(lower,
"debug")) {
141 return LogLevel::Debug;
143 return isStdErr ? LogLevel::Warning : LogLevel::Info;
146inline QVector<LogEntry> parseProcessOutput(QString &buffer,
147 const QString &chunk,
148 const QString &source,
150 QVector<LogEntry> entries;
151 if (chunk.isEmpty()) {
155 constexpr int kMaxBufferSize = 64 * 1024;
157 if (buffer.size() > kMaxBufferSize) {
158 buffer = buffer.right(kMaxBufferSize);
160 const QStringList lines = buffer.split(
'\n');
161 buffer = lines.isEmpty() ? QString() : lines.last();
163 if (lines.size() <= 1) {
167 const QDateTime now = QDateTime::currentDateTime();
168 entries.reserve(lines.size() - 1);
169 for (
int i = 0; i < lines.size() - 1; ++i) {
170 const QString line = lines.at(i).trimmed();
171 if (line.isEmpty()) {
178 parsed.parsed ? parsed.level : guessLevelFromText(line, isStdErr);
179 entry.source = source;
180 entry.message = parsed.parsed ? parsed.message : line;
181 entry.timestamp = now;
182 entries.append(entry);