summaryrefslogtreecommitdiffstats
path: root/xbmc/utils/log.cpp
diff options
context:
space:
mode:
authormanuel <manuel@mausz.at>2020-10-19 00:52:24 +0200
committermanuel <manuel@mausz.at>2020-10-19 00:52:24 +0200
commitbe933ef2241d79558f91796cc5b3a161f72ebf9c (patch)
treefe3ab2f130e20c99001f2d7a81d610c78c96a3f4 /xbmc/utils/log.cpp
parent5f8335c1e49ce108ef3481863833c98efa00411b (diff)
downloadkodi-pvr-build-be933ef2241d79558f91796cc5b3a161f72ebf9c.tar.gz
kodi-pvr-build-be933ef2241d79558f91796cc5b3a161f72ebf9c.tar.bz2
kodi-pvr-build-be933ef2241d79558f91796cc5b3a161f72ebf9c.zip
sync with upstream
Diffstat (limited to 'xbmc/utils/log.cpp')
-rw-r--r--xbmc/utils/log.cpp288
1 files changed, 288 insertions, 0 deletions
diff --git a/xbmc/utils/log.cpp b/xbmc/utils/log.cpp
new file mode 100644
index 0000000..7fb87fe
--- /dev/null
+++ b/xbmc/utils/log.cpp
@@ -0,0 +1,288 @@
1/*
2 * Copyright (C) 2005-2018 Team Kodi
3 * This file is part of Kodi - https://kodi.tv
4 *
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 * See LICENSES/README.md for more information.
7 */
8
9#include "log.h"
10
11#include "CompileInfo.h"
12#include "ServiceBroker.h"
13#include "filesystem/File.h"
14#include "guilib/LocalizeStrings.h"
15#if defined(TARGET_ANDROID)
16#include "platform/android/utils/AndroidInterfaceForCLog.h"
17#elif defined(TARGET_DARWIN)
18#include "platform/darwin/utils/DarwinInterfaceForCLog.h"
19#elif defined(TARGET_WINDOWS) || defined(TARGET_WIN10)
20#include "platform/win32/utils/Win32InterfaceForCLog.h"
21#else
22#include "platform/posix/utils/PosixInterfaceForCLog.h"
23#endif
24#include "settings/SettingUtils.h"
25#include "settings/Settings.h"
26#include "settings/SettingsComponent.h"
27#include "settings/lib/Setting.h"
28#include "settings/lib/SettingsManager.h"
29#include "utils/URIUtils.h"
30
31#include <cstring>
32#include <set>
33
34#include <spdlog/sinks/basic_file_sink.h>
35#include <spdlog/sinks/dist_sink.h>
36
37static constexpr unsigned char Utf8Bom[3] = {0xEF, 0xBB, 0xBF};
38static const std::string LogFileExtension = ".log";
39static const std::string LogPattern = "%Y-%m-%d %T.%e T:%-5t %7l <%n>: %v";
40
41CLog::CLog()
42 : m_platform(IPlatformLog::CreatePlatformLog()),
43 m_sinks(std::make_shared<spdlog::sinks::dist_sink_mt>()),
44 m_defaultLogger(CreateLogger("general")),
45 m_logLevel(LOG_LEVEL_DEBUG),
46 m_componentLogEnabled(false),
47 m_componentLogLevels(0)
48{
49 // add platform-specific debug sinks
50 m_platform->AddSinks(m_sinks);
51
52 // register the default logger with spdlog
53 spdlog::set_default_logger(m_defaultLogger);
54
55 // set the formatting pattern globally
56 spdlog::set_pattern(LogPattern);
57
58 // flush on debug logs
59 spdlog::flush_on(spdlog::level::debug);
60
61 // set the log level
62 SetLogLevel(m_logLevel);
63}
64
65void CLog::OnSettingsLoaded()
66{
67 const std::shared_ptr<CSettings> settings = CServiceBroker::GetSettingsComponent()->GetSettings();
68 m_componentLogEnabled = settings->GetBool(CSettings::SETTING_DEBUG_EXTRALOGGING);
69 SetComponentLogLevel(settings->GetList(CSettings::SETTING_DEBUG_SETEXTRALOGLEVEL));
70}
71
72void CLog::OnSettingChanged(std::shared_ptr<const CSetting> setting)
73{
74 if (setting == NULL)
75 return;
76
77 const std::string& settingId = setting->GetId();
78 if (settingId == CSettings::SETTING_DEBUG_EXTRALOGGING)
79 m_componentLogEnabled = std::static_pointer_cast<const CSettingBool>(setting)->GetValue();
80 else if (settingId == CSettings::SETTING_DEBUG_SETEXTRALOGLEVEL)
81 SetComponentLogLevel(
82 CSettingUtils::GetList(std::static_pointer_cast<const CSettingList>(setting)));
83}
84
85void CLog::Initialize(const std::string& path)
86{
87 if (m_fileSink != nullptr)
88 return;
89
90 // register setting callbacks
91 auto settingsManager =
92 CServiceBroker::GetSettingsComponent()->GetSettings()->GetSettingsManager();
93 settingsManager->RegisterSettingOptionsFiller("loggingcomponents",
94 SettingOptionsLoggingComponentsFiller);
95 settingsManager->RegisterSettingsHandler(this);
96 std::set<std::string> settingSet;
97 settingSet.insert(CSettings::SETTING_DEBUG_EXTRALOGGING);
98 settingSet.insert(CSettings::SETTING_DEBUG_SETEXTRALOGLEVEL);
99 settingsManager->RegisterCallback(this, settingSet);
100
101 if (path.empty())
102 return;
103
104 // put together the path to the log file(s)
105 std::string appName = CCompileInfo::GetAppName();
106 StringUtils::ToLower(appName);
107 const std::string filePathBase = URIUtils::AddFileToFolder(path, appName);
108 const std::string filePath = filePathBase + LogFileExtension;
109 const std::string oldFilePath = filePathBase + ".old" + LogFileExtension;
110
111 // handle old.log by deleting an existing old.log and renaming the last log to old.log
112 XFILE::CFile::Delete(oldFilePath);
113 XFILE::CFile::Rename(filePath, oldFilePath);
114
115 // write UTF-8 BOM
116 {
117 XFILE::CFile file;
118 if (file.OpenForWrite(filePath, true))
119 file.Write(Utf8Bom, sizeof(Utf8Bom));
120 }
121
122 // create the file sink
123 m_fileSink = std::make_shared<spdlog::sinks::basic_file_sink_mt>(
124 m_platform->GetLogFilename(filePath), false);
125 m_fileSink->set_pattern(LogPattern);
126
127 // add it to the existing sinks
128 m_sinks->add_sink(m_fileSink);
129}
130
131void CLog::Uninitialize()
132{
133 if (m_fileSink == nullptr)
134 return;
135
136 // unregister setting callbacks
137 auto settingsManager =
138 CServiceBroker::GetSettingsComponent()->GetSettings()->GetSettingsManager();
139 settingsManager->UnregisterSettingOptionsFiller("loggingcomponents");
140 settingsManager->UnregisterSettingsHandler(this);
141 settingsManager->UnregisterCallback(this);
142
143 // flush all loggers
144 spdlog::apply_all([](std::shared_ptr<spdlog::logger> logger) { logger->flush(); });
145
146 // flush the file sink
147 m_fileSink->flush();
148
149 // remove and destroy the file sink
150 m_sinks->remove_sink(m_fileSink);
151 m_fileSink.reset();
152}
153
154void CLog::SetLogLevel(int level)
155{
156 if (level < LOG_LEVEL_NONE || level > LOG_LEVEL_MAX)
157 return;
158
159 m_logLevel = level;
160
161 auto spdLevel = spdlog::level::info;
162 if (level <= LOG_LEVEL_NONE)
163 spdLevel = spdlog::level::off;
164 else if (level >= LOG_LEVEL_DEBUG)
165 spdLevel = spdlog::level::trace;
166
167 if (m_defaultLogger != nullptr && m_defaultLogger->level() == spdLevel)
168 return;
169
170 spdlog::set_level(spdLevel);
171 FormatAndLogInternal(spdlog::level::info, "Log level changed to \"{}\"",
172 spdlog::level::to_string_view(spdLevel));
173}
174
175bool CLog::IsLogLevelLogged(int loglevel)
176{
177 if (m_logLevel >= LOG_LEVEL_DEBUG)
178 return true;
179 if (m_logLevel <= LOG_LEVEL_NONE)
180 return false;
181
182 return (loglevel & LOGMASK) >= LOGNOTICE;
183}
184
185bool CLog::CanLogComponent(uint32_t component) const
186{
187 if (!m_componentLogEnabled || component == 0)
188 return false;
189
190 return ((m_componentLogLevels & component) == component);
191}
192
193void CLog::SettingOptionsLoggingComponentsFiller(SettingConstPtr setting,
194 std::vector<IntegerSettingOption>& list,
195 int& current,
196 void* data)
197{
198 list.emplace_back(g_localizeStrings.Get(669), LOGSAMBA);
199 list.emplace_back(g_localizeStrings.Get(670), LOGCURL);
200 list.emplace_back(g_localizeStrings.Get(672), LOGFFMPEG);
201 list.emplace_back(g_localizeStrings.Get(675), LOGJSONRPC);
202 list.emplace_back(g_localizeStrings.Get(676), LOGAUDIO);
203 list.emplace_back(g_localizeStrings.Get(680), LOGVIDEO);
204 list.emplace_back(g_localizeStrings.Get(683), LOGAVTIMING);
205 list.emplace_back(g_localizeStrings.Get(684), LOGWINDOWING);
206 list.emplace_back(g_localizeStrings.Get(685), LOGPVR);
207 list.emplace_back(g_localizeStrings.Get(686), LOGEPG);
208 list.emplace_back(g_localizeStrings.Get(39117), LOGANNOUNCE);
209#ifdef HAS_DBUS
210 list.emplace_back(g_localizeStrings.Get(674), LOGDBUS);
211#endif
212#ifdef HAS_WEB_SERVER
213 list.emplace_back(g_localizeStrings.Get(681), LOGWEBSERVER);
214#endif
215#ifdef HAS_AIRTUNES
216 list.emplace_back(g_localizeStrings.Get(677), LOGAIRTUNES);
217#endif
218#ifdef HAS_UPNP
219 list.emplace_back(g_localizeStrings.Get(678), LOGUPNP);
220#endif
221#ifdef HAVE_LIBCEC
222 list.emplace_back(g_localizeStrings.Get(679), LOGCEC);
223#endif
224 list.emplace_back(g_localizeStrings.Get(682), LOGDATABASE);
225}
226
227Logger CLog::GetLogger(const std::string& loggerName)
228{
229 auto logger = spdlog::get(loggerName);
230 if (logger == nullptr)
231 logger = CreateLogger(loggerName);
232
233 return logger;
234}
235
236CLog& CLog::GetInstance()
237{
238 return CServiceBroker::GetLogging();
239}
240
241spdlog::level::level_enum CLog::MapLogLevel(int level)
242{
243 switch (level)
244 {
245 case LOGDEBUG:
246 return spdlog::level::debug;
247 case LOGINFO:
248 case LOGNOTICE:
249 return spdlog::level::info;
250 case LOGWARNING:
251 return spdlog::level::warn;
252 case LOGERROR:
253 return spdlog::level::err;
254 case LOGSEVERE:
255 case LOGFATAL:
256 return spdlog::level::critical;
257 case LOGNONE:
258 return spdlog::level::off;
259
260 default:
261 break;
262 }
263
264 return spdlog::level::info;
265}
266
267Logger CLog::CreateLogger(const std::string& loggerName)
268{
269 // create the logger
270 auto logger = std::make_shared<spdlog::logger>(loggerName, m_sinks);
271
272 // initialize the logger
273 spdlog::initialize_logger(logger);
274
275 return logger;
276}
277
278void CLog::SetComponentLogLevel(const std::vector<CVariant>& components)
279{
280 m_componentLogLevels = 0;
281 for (const auto& component : components)
282 {
283 if (!component.isInteger())
284 continue;
285
286 m_componentLogLevels |= static_cast<uint32_t>(component.asInteger());
287 }
288}