1// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd.
2//
3// SPDX-License-Identifier: GPL-3.0-or-later
4
5#include "frameworklog.h"
6#include "logutils.h"
7#include "common/util/commandparser.h"
8
9#include <QDir>
10#include <QFile>
11#include <QFileInfo>
12#include <QCoreApplication>
13#include <QtConcurrent>
14
15#ifdef DTK_LOG
16#include <DLog>
17#endif
18
19Q_LOGGING_CATEGORY(Framework, "Framework")
20
21DPF_BEGIN_NAMESPACE
22
23namespace GlobalPrivate
24{
25 static QFile file;
26 static uint dayCount = 7;
27 static QMutex mutex;
28
29 QString formatFrameworkLogOut(QtMsgType type, const QMessageLogContext &context, const QString &msg)
30 {
31 auto fileNameList = QString(context.file).split(QDir::separator());
32 auto currentName = fileNameList[fileNameList.size() - 1];
33
34 if (type == QtMsgType::QtDebugMsg)
35 return "[" + QString(context.category) + "]["
36 + LogUtils::localDateTime() + "][Debug]["
37 + currentName + " "
38 + context.function + " "
39 + QString::number(context.line) + "]"
40 + msg;
41 if (type == QtMsgType::QtInfoMsg)
42 return "[" + QString(context.category) + "]["
43 + LogUtils::localDateTime() + "][Info]["
44 + currentName + " "
45 + context.function + " "
46 + QString::number(context.line) + "]"
47 + msg;
48 if (type == QtMsgType::QtCriticalMsg)
49 return "[" + QString(context.category) + "]["
50 + LogUtils::localDateTime() + "][Critical]["
51 + currentName + " "
52 + context.function + " "
53 + QString::number(context.line) + "]"
54 + msg;
55 if (type == QtMsgType::QtWarningMsg)
56 return "[" + QString(context.category) + "]["
57 + LogUtils::localDateTime() + "][Warning]["
58 + currentName + " "
59 + context.function + " "
60 + QString::number(context.line) + "]"
61 + msg;
62 if (type == QtMsgType::QtSystemMsg)
63 return "[" + QString(context.category) + "]["
64 + LogUtils::localDateTime() + "][System]["
65 + currentName + " "
66 + context.function + " "
67 + QString::number(context.line) + "]"
68 + msg;
69 if (type == QtMsgType::QtFatalMsg)
70 return "[" + QString(context.category) + "]["
71 + LogUtils::localDateTime() + "][Fatal]["
72 + currentName + " "
73 + context.function + " "
74 + QString::number(context.line) + "]"
75 + msg;
76 return msg;
77 }
78
79 static void rmExpiredLogs()
80 {
81 QtConcurrent::run([=](){
82 QDirIterator itera(LogUtils::appCacheLogPath(),QDir::Files);
83 while(itera.hasNext()) {
84 itera.next();
85 auto list = itera.fileName().split("_");
86 if (itera.fileInfo().suffix() == "log"
87 && list.count() == 2
88 && !LogUtils::containLastDay(
89 QDateTime(QDate::fromString(list[0],"yyyy-MM-dd"),
90 QTime(0,0,0,0)),
91 LogUtils::toDayZero(),
92 GlobalPrivate::dayCount))
93 {
94
95 auto outMsg = formatFrameworkLogOut(QtMsgType::QtInfoMsg,
96 QMessageLogContext{
97 __FILE__,
98 __LINE__,
99 __FUNCTION__,
100 Framework().categoryName()
101 },
102 QString("remove true(%0) not last week log: %1")
103 .arg(QDir().remove(itera.path() + QDir::separator() + itera.fileName()))
104 .arg(itera.fileName().toLocal8Bit().data())
105 );
106
107 fprintf(stderr, "%s\n", outMsg.toUtf8().data());
108 }
109 }
110 });
111 }
112
113 void redirectGlobalDebug(QtMsgType type,
114 const QMessageLogContext &context,
115 const QString &msg)
116 {
117 QMutexLocker locker(&mutex);
118 QString logMsg = GlobalPrivate::formatFrameworkLogOut(type,context,msg);
119 if (type == QtMsgType::QtDebugMsg)
120 fprintf(stdin,"%s\n",logMsg.toUtf8().data());
121 if (type == QtMsgType::QtInfoMsg)
122 fprintf(stderr,"%s\n",logMsg.toUtf8().data());
123 if (type == QtMsgType::QtSystemMsg)
124 fprintf(stdin,"%s\n",logMsg.toUtf8().data());
125 if (type == QtMsgType::QtCriticalMsg)
126 fprintf(stderr,"%s\n",logMsg.toUtf8().data());
127 if (type == QtMsgType::QtWarningMsg)
128 fprintf(stderr,"%s\n",logMsg.toUtf8().data());
129 if (type == QtMsgType::QtFatalMsg)
130 fprintf(stderr,"%s\n",logMsg.toUtf8().data());
131
132 // cache/deepin/qApp->applicationName()
133 LogUtils::checkAppCacheLogDir();
134
135 if (GlobalPrivate::file.fileName().isEmpty()) {
136 GlobalPrivate::file.setFileName(LogUtils::appCacheLogPath()
137 + QDir::separator()
138 + LogUtils::localDate()
139 + "_" + QCoreApplication::applicationName()
140 + ".log");
141
142 auto outMsg = GlobalPrivate::formatFrameworkLogOut(QtMsgType::QtInfoMsg,
143 QMessageLogContext{
144 __FILE__,
145 __LINE__,
146 __FUNCTION__,
147 Framework().categoryName()
148 },
149 "Current redirect log file path: "
150 + GlobalPrivate::file.fileName()
151 );
152
153 fprintf(stderr, "%s\n", outMsg.toUtf8().data());
154
155 //清除超出时间段的日志
156 GlobalPrivate::rmExpiredLogs();
157 }
158
159 if (!GlobalPrivate::file.open(QFile::Append|QFile::ReadOnly)) {
160
161 auto outMsg = GlobalPrivate::formatFrameworkLogOut(QtMsgType::QtInfoMsg,
162 QMessageLogContext{
163 __FILE__,
164 __LINE__,
165 __FUNCTION__,
166 Framework().categoryName()
167 },
168 "Failed, open redirect log file"
169 + GlobalPrivate::file.fileName()
170 + " "
171 + GlobalPrivate::file.errorString()
172 );
173
174 fprintf(stderr, "%s\n", outMsg.toUtf8().data());
175
176 return;
177 }
178
179 GlobalPrivate::file.write((logMsg + ("\n")).toLocal8Bit().data());
180 GlobalPrivate::file.flush();
181 GlobalPrivate::file.close();
182 }
183
184} // namespace GlobalPrivate
185
186/**
187 * @brief enableFrameworkLog 开启框架日志打印
188 * @param enabled true为开启,false则关闭
189 */
190void FrameworkLog::enableFrameworkLog(bool enabled){
191 if (enabled) {
192 QLoggingCategory::setFilterRules(QLatin1String("FrameworkLog.warning=true"));
193 QLoggingCategory::setFilterRules(QLatin1String("FrameworkLog.debug=true"));
194 QLoggingCategory::setFilterRules(QLatin1String("FrameworkLog.info=true"));
195 QLoggingCategory::setFilterRules(QLatin1String("FrameworkLog.critical=true"));
196
197 } else {
198 QLoggingCategory::setFilterRules(QLatin1String("FrameworkLog.warning=false"));
199 QLoggingCategory::setFilterRules(QLatin1String("FrameworkLog.debug=false"));
200 QLoggingCategory::setFilterRules(QLatin1String("FrameworkLog.info=false"));
201 QLoggingCategory::setFilterRules(QLatin1String("FrameworkLog.critical=false"));
202 }
203}
204
205/**
206 * @brief setLogCacheDayCount 设置日志缓存时间,
207 * 需要在调用其他函数之前调用
208 * @param uint 缓存的天数
209 */
210void FrameworkLog::setLogCacheDayCount(uint dayCount)
211{
212 static QMutex mutex;
213 mutex.lock();
214 GlobalPrivate::dayCount = dayCount;
215 mutex.unlock();
216}
217
218/**
219 * @brief logCacheDayCount 获取设置的日志缓存时间
220 * @return uint 缓存的天数,默认缓存7天
221 */
222uint FrameworkLog::logCacheDayCount()
223{
224 return GlobalPrivate::dayCount;
225}
226
227/**
228 * @brief initialize 初始化框架日志打印模块
229 */
230void FrameworkLog::initialize()
231{
232#ifdef DTK_LOG
233
234 QString tempPath = DTK_CORE_NAMESPACE::DLogManager::getlogFilePath();
235 QString appName = QDir::separator() + qApp->applicationName() + QDir::separator();
236 QString result = QDir::separator() + "deepin" + appName;
237 DTK_CORE_NAMESPACE::DLogManager::setlogFilePath(tempPath.replace(appName,result));
238 qInfo() << "redirect output info to log: " << DTK_CORE_NAMESPACE::DLogManager::getlogFilePath();
239 DTK_CORE_NAMESPACE::DLogManager::registerConsoleAppender();
240 DTK_CORE_NAMESPACE::DLogManager::registerFileAppender();
241#else
242 qInstallMessageHandler(&GlobalPrivate::redirectGlobalDebug);
243#endif
244}
245
246DPF_END_NAMESPACE
247