1 /*
2     SPDX-FileCopyrightText: 2007 Nicolas Ternisien <nicolas.ternisien@gmail.com>
3 
4     SPDX-License-Identifier: GPL-2.0-or-later
5 */
6 
7 #include "syslogAnalyzer.h"
8 
9 #include <QDateTime>
10 #include <QStringList>
11 
12 #include <KLocalizedString>
13 
14 #include "globals.h"
15 #include "ksystemlog_debug.h"
16 
17 #include "localLogFileReader.h"
18 #include "logLevel.h"
19 #include "logLine.h"
20 #include "logMode.h"
21 #include "logViewWidget.h"
22 
23 #include "logViewModel.h"
24 
25 #include "parsingHelper.h"
26 
27 #include "ksystemlogConfig.h"
28 
SyslogAnalyzer(LogMode * logMode)29 SyslogAnalyzer::SyslogAnalyzer(LogMode *logMode)
30     : FileAnalyzer(logMode)
31 {
32 }
33 
~SyslogAnalyzer()34 SyslogAnalyzer::~SyslogAnalyzer()
35 {
36 }
37 
initColumns()38 LogViewColumns SyslogAnalyzer::initColumns()
39 {
40     LogViewColumns columns;
41     columns.addColumn(LogViewColumn(i18n("Date"), true, false));
42     columns.addColumn(LogViewColumn(i18n("Host"), true, true));
43     columns.addColumn(LogViewColumn(i18n("Process"), true, true));
44     columns.addColumn(LogViewColumn(i18n("Message"), true, false));
45 
46     return columns;
47 }
48 
createLogFileReader(const LogFile & logFile)49 LogFileReader *SyslogAnalyzer::createLogFileReader(const LogFile &logFile)
50 {
51     return new LocalLogFileReader(logFile);
52 }
53 
logFileSortMode()54 Analyzer::LogFileSortMode SyslogAnalyzer::logFileSortMode()
55 {
56     return Analyzer::AscendingSortedLogFile;
57 }
58 
59 /**
60  * TODO Improve speed of this method (with KRegExp class for example)
61  */
parseMessage(const QString & logLine,const LogFile & originalFile)62 LogLine *SyslogAnalyzer::parseMessage(const QString &logLine, const LogFile &originalFile)
63 {
64     // qCDebug(KSYSTEMLOG) << QTime::currentTime() << " : Reading line : " << logLine << " from " <<
65     // originalFile.url.path();
66 
67     // 15 is the default date size format
68     if (logLine.length() < 15) {
69         qCDebug(KSYSTEMLOG) << "Too short line";
70         return undefinedLogLine(logLine, originalFile);
71     }
72 
73     const int year = QDate::currentDate().year();
74 
75     // Month number
76     QString month(logLine.left(3));
77 
78     QString line(logLine);
79 
80     line.remove(0, 4);
81     const int monthNum = ParsingHelper::instance()->parseSyslogMonth(month);
82 
83     // Day number
84     QString day(line.left(2));
85     const int dayNum = day.toInt();
86 
87     line.remove(0, 3);
88 
89     // Time
90     QString stringTime(line.left(8));
91     const int h = stringTime.leftRef(2).toInt();
92     stringTime.remove(0, 3);
93     const int m = stringTime.leftRef(2).toInt();
94     stringTime.remove(0, 3);
95     const int s = stringTime.leftRef(2).toInt();
96     stringTime.remove(0, 3);
97 
98     const QDateTime dateTime(QDate(year, monthNum, dayNum), QTime(h, m, s));
99     if (!dateTime.isValid()) {
100         qCDebug(KSYSTEMLOG) << "Malformed date and time";
101         return undefinedLogLine(logLine, originalFile);
102     }
103 
104     line.remove(0, 9);
105 
106     QString hostname;
107 
108     const int nextSpace = line.indexOf(QLatin1Char(' '));
109     int nextDoubleDot = line.indexOf(QLatin1Char(':'));
110 
111     // Normal case or no process name
112     if (nextSpace < nextDoubleDot || nextDoubleDot == -1) {
113         // Host name
114         hostname = line.left(nextSpace);
115         line.remove(0, nextSpace + 1);
116     }
117     // No host name case (very rare)
118     else {
119         // Host name
120         hostname = undefinedHostName();
121     }
122 
123     // Refresh double dot once the line has been substr'ed
124     nextDoubleDot = line.indexOf(QLatin1Char(':'));
125 
126     QString process;
127     QString message;
128 
129     // Process name
130     if (nextDoubleDot != -1) {
131         process = line.left(nextDoubleDot);
132 
133         // If the delete process identifier option is enabled
134         if (KSystemLogConfig::deleteProcessIdentifier()) {
135             const int squareBracket = process.indexOf(QLatin1Char('['));
136 
137             // If we find a bracket, we remove the useless part
138             if (squareBracket != -1) {
139                 process.truncate(squareBracket);
140             }
141         }
142         line.remove(0, nextDoubleDot + 1);
143 
144         message = line.remove(0, 1);
145     }
146     // If we can't find any ':' character, it means that this line is a
147     // internal message of syslogd
148     else {
149         if (line.contains(QLatin1String("last message repeated")) || line.contains(QLatin1String("-- MARK --"))) {
150             process = QStringLiteral("syslog");
151         } else {
152             process = undefinedProcess();
153         }
154 
155         message = line;
156     }
157 
158     QStringList list;
159     list.append(hostname);
160     list.append(process);
161     list.append(message);
162 
163     return new LogLine(mLogLineInternalIdGenerator++, dateTime, list, originalFile.url().toLocalFile(), originalFile.defaultLogLevel(), mLogMode);
164 }
165 
undefinedLogLine(const QString & message,const LogFile & originalFile)166 inline LogLine *SyslogAnalyzer::undefinedLogLine(const QString &message, const LogFile &originalFile)
167 {
168     QStringList items;
169     items << undefinedHostName() << undefinedProcess() << message;
170     return new LogLine(mLogLineInternalIdGenerator++,
171                        QDateTime::currentDateTime(),
172                        items,
173                        originalFile.url().toLocalFile(),
174                        originalFile.defaultLogLevel(),
175                        mLogMode);
176 }
177 
undefinedHostName()178 inline QString SyslogAnalyzer::undefinedHostName()
179 {
180     // i18nc("Undefined host name", "undefined");
181     return QLatin1String("");
182 }
183 
undefinedProcess()184 inline QString SyslogAnalyzer::undefinedProcess()
185 {
186     // i18nc("Undefined process", "undefined");
187     return QLatin1String("");
188 }
189