[PVR][Estuary] Timer settings dialog: Show client name in timer type selection dialog...
[xbmc.git] / xbmc / utils / log.cpp
blobb0eb2bb8f9d5478ba26d6c7a01c7c2b3268eb694
1 /*
2 * Copyright (C) 2005-2018 Team Kodi
3 * This file is part of Kodi - https://kodi.tv
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 * See LICENSES/README.md for more information.
7 */
9 #include "log.h"
11 #include "CompileInfo.h"
12 #include "ServiceBroker.h"
13 #include "filesystem/File.h"
14 #include "guilib/LocalizeStrings.h"
15 #include "settings/SettingUtils.h"
16 #include "settings/Settings.h"
17 #include "settings/SettingsComponent.h"
18 #include "settings/lib/Setting.h"
19 #include "settings/lib/SettingsManager.h"
20 #include "utils/StringUtils.h"
21 #include "utils/URIUtils.h"
23 #include <cstring>
24 #include <set>
26 #include <spdlog/sinks/basic_file_sink.h>
27 #include <spdlog/sinks/dist_sink.h>
28 #include <spdlog/sinks/dup_filter_sink.h>
30 namespace
32 static constexpr unsigned char Utf8Bom[3] = {0xEF, 0xBB, 0xBF};
33 static const std::string LogFileExtension = ".log";
34 static const std::string LogPattern = "%Y-%m-%d %T.%e T:%-5t %7l <%n>: %v";
35 } // namespace
37 CLog::CLog()
38 : m_platform(IPlatformLog::CreatePlatformLog()),
39 m_sinks(std::make_shared<spdlog::sinks::dist_sink_mt>()),
40 m_defaultLogger(CreateLogger("general")),
41 m_logLevel(LOG_LEVEL_DEBUG),
42 m_componentLogEnabled(false),
43 m_componentLogLevels(0)
45 // add platform-specific debug sinks
46 m_platform->AddSinks(m_sinks);
48 // register the default logger with spdlog
49 spdlog::set_default_logger(m_defaultLogger);
51 // set the formatting pattern globally
52 spdlog::set_pattern(LogPattern);
54 // flush on debug logs
55 spdlog::flush_on(spdlog::level::debug);
57 // set the log level
58 SetLogLevel(m_logLevel);
61 CLog::~CLog()
63 spdlog::drop("general");
66 void CLog::OnSettingsLoaded()
68 const std::shared_ptr<CSettings> settings = CServiceBroker::GetSettingsComponent()->GetSettings();
69 m_componentLogEnabled = settings->GetBool(CSettings::SETTING_DEBUG_EXTRALOGGING);
70 SetComponentLogLevel(settings->GetList(CSettings::SETTING_DEBUG_SETEXTRALOGLEVEL));
73 void CLog::OnSettingChanged(const std::shared_ptr<const CSetting>& setting)
75 if (setting == NULL)
76 return;
78 const std::string& settingId = setting->GetId();
79 if (settingId == CSettings::SETTING_DEBUG_EXTRALOGGING)
80 m_componentLogEnabled = std::static_pointer_cast<const CSettingBool>(setting)->GetValue();
81 else if (settingId == CSettings::SETTING_DEBUG_SETEXTRALOGLEVEL)
82 SetComponentLogLevel(
83 CSettingUtils::GetList(std::static_pointer_cast<const CSettingList>(setting)));
86 void CLog::Initialize(const std::string& path)
88 if (m_fileSink != nullptr)
89 return;
91 // register setting callbacks
92 auto settingsManager =
93 CServiceBroker::GetSettingsComponent()->GetSettings()->GetSettingsManager();
94 settingsManager->RegisterSettingOptionsFiller("loggingcomponents",
95 SettingOptionsLoggingComponentsFiller);
96 settingsManager->RegisterSettingsHandler(this);
97 std::set<std::string> settingSet;
98 settingSet.insert(CSettings::SETTING_DEBUG_EXTRALOGGING);
99 settingSet.insert(CSettings::SETTING_DEBUG_SETEXTRALOGLEVEL);
100 settingsManager->RegisterCallback(this, settingSet);
102 if (path.empty())
103 return;
105 // put together the path to the log file(s)
106 std::string appName = CCompileInfo::GetAppName();
107 StringUtils::ToLower(appName);
108 const std::string filePathBase = URIUtils::AddFileToFolder(path, appName);
109 const std::string filePath = filePathBase + LogFileExtension;
110 const std::string oldFilePath = filePathBase + ".old" + LogFileExtension;
112 // handle old.log by deleting an existing old.log and renaming the last log to old.log
113 XFILE::CFile::Delete(oldFilePath);
114 XFILE::CFile::Rename(filePath, oldFilePath);
116 // write UTF-8 BOM
118 XFILE::CFile file;
119 if (file.OpenForWrite(filePath, true))
120 file.Write(Utf8Bom, sizeof(Utf8Bom));
123 // create the file sink within a duplicate filter sink
124 auto duplicateFilterSink =
125 std::make_shared<spdlog::sinks::dup_filter_sink_st>(std::chrono::seconds(10));
126 auto basicFileSink = std::make_shared<spdlog::sinks::basic_file_sink_st>(
127 m_platform->GetLogFilename(filePath), false);
128 basicFileSink->set_pattern(LogPattern);
129 duplicateFilterSink->add_sink(basicFileSink);
130 m_fileSink = duplicateFilterSink;
132 // add it to the existing sinks
133 m_sinks->add_sink(m_fileSink);
136 void CLog::UnregisterFromSettings()
138 // unregister setting callbacks
139 auto settingsManager =
140 CServiceBroker::GetSettingsComponent()->GetSettings()->GetSettingsManager();
141 settingsManager->UnregisterSettingOptionsFiller("loggingcomponents");
142 settingsManager->UnregisterSettingsHandler(this);
143 settingsManager->UnregisterCallback(this);
146 void CLog::Deinitialize()
148 if (m_fileSink == nullptr)
149 return;
151 // flush all loggers
152 spdlog::apply_all([](const std::shared_ptr<spdlog::logger>& logger) { logger->flush(); });
154 // flush the file sink
155 m_fileSink->flush();
157 // remove and destroy the file sink
158 m_sinks->remove_sink(m_fileSink);
159 m_fileSink.reset();
162 void CLog::SetLogLevel(int level)
164 if (level < LOG_LEVEL_NONE || level > LOG_LEVEL_MAX)
165 return;
167 m_logLevel = level;
169 auto spdLevel = spdlog::level::info;
170 if (level <= LOG_LEVEL_NONE)
171 spdLevel = spdlog::level::off;
172 else if (level >= LOG_LEVEL_DEBUG)
173 spdLevel = spdlog::level::trace;
175 if (m_defaultLogger != nullptr && m_defaultLogger->level() == spdLevel)
176 return;
178 spdlog::set_level(spdLevel);
179 FormatAndLogInternal(spdlog::level::info, "Log level changed to \"{}\"",
180 spdlog::level::to_string_view(spdLevel));
183 bool CLog::IsLogLevelLogged(int loglevel)
185 if (m_logLevel >= LOG_LEVEL_DEBUG)
186 return true;
187 if (m_logLevel <= LOG_LEVEL_NONE)
188 return false;
190 return (loglevel & LOGMASK) >= LOGINFO;
193 bool CLog::CanLogComponent(uint32_t component) const
195 if (!m_componentLogEnabled || component == 0)
196 return false;
198 return ((m_componentLogLevels & component) == component);
201 void CLog::SettingOptionsLoggingComponentsFiller(const SettingConstPtr& setting,
202 std::vector<IntegerSettingOption>& list,
203 int& current,
204 void* data)
206 list.emplace_back(g_localizeStrings.Get(669), LOGSAMBA);
207 list.emplace_back(g_localizeStrings.Get(670), LOGCURL);
208 list.emplace_back(g_localizeStrings.Get(672), LOGFFMPEG);
209 list.emplace_back(g_localizeStrings.Get(675), LOGJSONRPC);
210 list.emplace_back(g_localizeStrings.Get(676), LOGAUDIO);
211 list.emplace_back(g_localizeStrings.Get(680), LOGVIDEO);
212 list.emplace_back(g_localizeStrings.Get(683), LOGAVTIMING);
213 list.emplace_back(g_localizeStrings.Get(684), LOGWINDOWING);
214 list.emplace_back(g_localizeStrings.Get(685), LOGPVR);
215 list.emplace_back(g_localizeStrings.Get(686), LOGEPG);
216 list.emplace_back(g_localizeStrings.Get(39117), LOGANNOUNCE);
217 list.emplace_back(g_localizeStrings.Get(39124), LOGADDONS);
218 #ifdef HAS_DBUS
219 list.emplace_back(g_localizeStrings.Get(674), LOGDBUS);
220 #endif
221 #ifdef HAS_WEB_SERVER
222 list.emplace_back(g_localizeStrings.Get(681), LOGWEBSERVER);
223 #endif
224 #ifdef HAS_AIRTUNES
225 list.emplace_back(g_localizeStrings.Get(677), LOGAIRTUNES);
226 #endif
227 #ifdef HAS_UPNP
228 list.emplace_back(g_localizeStrings.Get(678), LOGUPNP);
229 #endif
230 #ifdef HAVE_LIBCEC
231 list.emplace_back(g_localizeStrings.Get(679), LOGCEC);
232 #endif
233 list.emplace_back(g_localizeStrings.Get(682), LOGDATABASE);
234 #if defined(HAS_FILESYSTEM_SMB)
235 list.emplace_back(g_localizeStrings.Get(37050), LOGWSDISCOVERY);
236 #endif
239 Logger CLog::GetLogger(const std::string& loggerName)
241 auto logger = spdlog::get(loggerName);
242 if (logger == nullptr)
243 logger = CreateLogger(loggerName);
245 return logger;
248 CLog& CLog::GetInstance()
250 return CServiceBroker::GetLogging();
253 spdlog::level::level_enum CLog::MapLogLevel(int level)
255 switch (level)
257 case LOGDEBUG:
258 return spdlog::level::debug;
259 case LOGINFO:
260 return spdlog::level::info;
261 case LOGWARNING:
262 return spdlog::level::warn;
263 case LOGERROR:
264 return spdlog::level::err;
265 case LOGFATAL:
266 return spdlog::level::critical;
267 case LOGNONE:
268 return spdlog::level::off;
270 default:
271 break;
274 return spdlog::level::info;
277 Logger CLog::CreateLogger(const std::string& loggerName)
279 // create the logger
280 auto logger = std::make_shared<spdlog::logger>(loggerName, m_sinks);
282 // initialize the logger
283 spdlog::initialize_logger(logger);
285 return logger;
288 void CLog::SetComponentLogLevel(const std::vector<CVariant>& components)
290 m_componentLogLevels = 0;
291 for (const auto& component : components)
293 if (!component.isInteger())
294 continue;
296 m_componentLogLevels |= static_cast<uint32_t>(component.asInteger());
300 void CLog::FormatLineBreaks(std::string& message)
302 StringUtils::Replace(message, "\n", "\n ");