1 #include <QDateTime>
2 #include <QDir>
3 #include <QFileInfo>
4
5 #include "RollingFileAppender.h"
6
7
RollingFileAppender(const QString & fileName)8 RollingFileAppender::RollingFileAppender(const QString& fileName)
9 : FileAppender(fileName),
10 m_logFilesLimit(0)
11 {}
12
13
append(const QDateTime & timeStamp,Logger::LogLevel logLevel,const char * file,int line,const char * function,const QString & category,const QString & message)14 void RollingFileAppender::append(const QDateTime& timeStamp, Logger::LogLevel logLevel, const char* file, int line,
15 const char* function, const QString& category, const QString& message)
16 {
17 if (!m_rollOverTime.isNull() && QDateTime::currentDateTime() > m_rollOverTime)
18 rollOver();
19
20 FileAppender::append(timeStamp, logLevel, file, line, function, category, message);
21 }
22
23
datePattern() const24 RollingFileAppender::DatePattern RollingFileAppender::datePattern() const
25 {
26 QMutexLocker locker(&m_rollingMutex);
27 return m_frequency;
28 }
29
30
datePatternString() const31 QString RollingFileAppender::datePatternString() const
32 {
33 QMutexLocker locker(&m_rollingMutex);
34 return m_datePatternString;
35 }
36
37
setDatePattern(DatePattern datePattern)38 void RollingFileAppender::setDatePattern(DatePattern datePattern)
39 {
40 switch (datePattern)
41 {
42 case MinutelyRollover:
43 setDatePatternString(QLatin1String("'.'yyyy-MM-dd-hh-mm"));
44 break;
45 case HourlyRollover:
46 setDatePatternString(QLatin1String("'.'yyyy-MM-dd-hh"));
47 break;
48 case HalfDailyRollover:
49 setDatePatternString(QLatin1String("'.'yyyy-MM-dd-a"));
50 break;
51 case DailyRollover:
52 setDatePatternString(QLatin1String("'.'yyyy-MM-dd"));
53 break;
54 case WeeklyRollover:
55 setDatePatternString(QLatin1String("'.'yyyy-ww"));
56 break;
57 case MonthlyRollover:
58 setDatePatternString(QLatin1String("'.'yyyy-MM"));
59 break;
60 default:
61 Q_ASSERT_X(false, "DailyRollingFileAppender::setDatePattern()", "Invalid datePattern constant");
62 setDatePattern(DailyRollover);
63 };
64
65 QMutexLocker locker(&m_rollingMutex);
66 m_frequency = datePattern;
67
68 computeRollOverTime();
69 }
70
71
setDatePattern(const QString & datePattern)72 void RollingFileAppender::setDatePattern(const QString& datePattern)
73 {
74 setDatePatternString(datePattern);
75 computeFrequency();
76
77 computeRollOverTime();
78 }
79
80
setDatePatternString(const QString & datePatternString)81 void RollingFileAppender::setDatePatternString(const QString& datePatternString)
82 {
83 QMutexLocker locker(&m_rollingMutex);
84 m_datePatternString = datePatternString;
85 }
86
87
computeFrequency()88 void RollingFileAppender::computeFrequency()
89 {
90 QMutexLocker locker(&m_rollingMutex);
91
92 const QDateTime startTime(QDate(1999, 1, 1), QTime(0, 0));
93 const QString startString = startTime.toString(m_datePatternString);
94
95 if (startString != startTime.addSecs(60).toString(m_datePatternString))
96 m_frequency = MinutelyRollover;
97 else if (startString != startTime.addSecs(60 * 60).toString(m_datePatternString))
98 m_frequency = HourlyRollover;
99 else if (startString != startTime.addSecs(60 * 60 * 12).toString(m_datePatternString))
100 m_frequency = HalfDailyRollover;
101 else if (startString != startTime.addDays(1).toString(m_datePatternString))
102 m_frequency = DailyRollover;
103 else if (startString != startTime.addDays(7).toString(m_datePatternString))
104 m_frequency = WeeklyRollover;
105 else if (startString != startTime.addMonths(1).toString(m_datePatternString))
106 m_frequency = MonthlyRollover;
107 else
108 {
109 Q_ASSERT_X(false, "DailyRollingFileAppender::computeFrequency", "The pattern '%1' does not specify a frequency");
110 return;
111 }
112 }
113
114
removeOldFiles()115 void RollingFileAppender::removeOldFiles()
116 {
117 if (m_logFilesLimit <= 1)
118 return;
119
120 QFileInfo fileInfo(fileName());
121 QDir logDirectory(fileInfo.absoluteDir());
122 logDirectory.setFilter(QDir::Files);
123 logDirectory.setNameFilters(QStringList() << fileInfo.fileName() + "*");
124 QFileInfoList logFiles = logDirectory.entryInfoList();
125
126 QMap<QDateTime, QString> fileDates;
127 for (int i = 0; i < logFiles.length(); ++i)
128 {
129 QString name = logFiles[i].fileName();
130 QString suffix = name.mid(name.indexOf(fileInfo.fileName()) + fileInfo.fileName().length());
131 QDateTime fileDateTime = QDateTime::fromString(suffix, datePatternString());
132
133 if (fileDateTime.isValid())
134 fileDates.insert(fileDateTime, logFiles[i].absoluteFilePath());
135 }
136
137 QList<QString> fileDateNames = fileDates.values();
138 for (int i = 0; i < fileDateNames.length() - m_logFilesLimit + 1; ++i)
139 QFile::remove(fileDateNames[i]);
140 }
141
142
computeRollOverTime()143 void RollingFileAppender::computeRollOverTime()
144 {
145 Q_ASSERT_X(!m_datePatternString.isEmpty(), "DailyRollingFileAppender::computeRollOverTime()", "No active date pattern");
146
147 QDateTime now = QDateTime::currentDateTime();
148 QDate nowDate = now.date();
149 QTime nowTime = now.time();
150 QDateTime start;
151
152 switch (m_frequency)
153 {
154 case MinutelyRollover:
155 {
156 start = QDateTime(nowDate, QTime(nowTime.hour(), nowTime.minute(), 0, 0));
157 m_rollOverTime = start.addSecs(60);
158 }
159 break;
160 case HourlyRollover:
161 {
162 start = QDateTime(nowDate, QTime(nowTime.hour(), 0, 0, 0));
163 m_rollOverTime = start.addSecs(60*60);
164 }
165 break;
166 case HalfDailyRollover:
167 {
168 int hour = nowTime.hour();
169 if (hour >= 12)
170 hour = 12;
171 else
172 hour = 0;
173 start = QDateTime(nowDate, QTime(hour, 0, 0, 0));
174 m_rollOverTime = start.addSecs(60*60*12);
175 }
176 break;
177 case DailyRollover:
178 {
179 start = QDateTime(nowDate, QTime(0, 0, 0, 0));
180 m_rollOverTime = start.addDays(1);
181 }
182 break;
183 case WeeklyRollover:
184 {
185 // Qt numbers the week days 1..7. The week starts on Monday.
186 // Change it to being numbered 0..6, starting with Sunday.
187 int day = nowDate.dayOfWeek();
188 if (day == Qt::Sunday)
189 day = 0;
190 start = QDateTime(nowDate, QTime(0, 0, 0, 0)).addDays(-1 * day);
191 m_rollOverTime = start.addDays(7);
192 }
193 break;
194 case MonthlyRollover:
195 {
196 start = QDateTime(QDate(nowDate.year(), nowDate.month(), 1), QTime(0, 0, 0, 0));
197 m_rollOverTime = start.addMonths(1);
198 }
199 break;
200 default:
201 Q_ASSERT_X(false, "DailyRollingFileAppender::computeInterval()", "Invalid datePattern constant");
202 m_rollOverTime = QDateTime::fromTime_t(0);
203 }
204
205 m_rollOverSuffix = start.toString(m_datePatternString);
206 Q_ASSERT_X(now.toString(m_datePatternString) == m_rollOverSuffix,
207 "DailyRollingFileAppender::computeRollOverTime()", "File name changes within interval");
208 Q_ASSERT_X(m_rollOverSuffix != m_rollOverTime.toString(m_datePatternString),
209 "DailyRollingFileAppender::computeRollOverTime()", "File name does not change with rollover");
210 }
211
212
rollOver()213 void RollingFileAppender::rollOver()
214 {
215 Q_ASSERT_X(!m_datePatternString.isEmpty(), "DailyRollingFileAppender::rollOver()", "No active date pattern");
216
217 QString rollOverSuffix = m_rollOverSuffix;
218 computeRollOverTime();
219 if (rollOverSuffix == m_rollOverSuffix)
220 return;
221
222 closeFile();
223
224 QString targetFileName = fileName() + rollOverSuffix;
225 QFile f(targetFileName);
226 if (f.exists() && !f.remove())
227 return;
228 f.setFileName(fileName());
229 if (!f.rename(targetFileName))
230 return;
231
232 openFile();
233 removeOldFiles();
234 }
235
236
setLogFilesLimit(int limit)237 void RollingFileAppender::setLogFilesLimit(int limit)
238 {
239 QMutexLocker locker(&m_rollingMutex);
240 m_logFilesLimit = limit;
241 }
242
243
logFilesLimit() const244 int RollingFileAppender::logFilesLimit() const
245 {
246 QMutexLocker locker(&m_rollingMutex);
247 return m_logFilesLimit;
248 }
249