/xbmc/utils/log.cpp
http://github.com/xbmc/xbmc · C++ · 288 lines · 217 code · 47 blank · 24 comment · 34 complexity · f10288d6c66b2af5a5074f5119a58141 MD5 · raw file
- /*
- * Copyright (C) 2005-2018 Team Kodi
- * This file is part of Kodi - https://kodi.tv
- *
- * SPDX-License-Identifier: GPL-2.0-or-later
- * See LICENSES/README.md for more information.
- */
- #include "log.h"
- #include "CompileInfo.h"
- #include "ServiceBroker.h"
- #include "filesystem/File.h"
- #include "guilib/LocalizeStrings.h"
- #if defined(TARGET_ANDROID)
- #include "platform/android/utils/AndroidInterfaceForCLog.h"
- #elif defined(TARGET_DARWIN)
- #include "platform/darwin/utils/DarwinInterfaceForCLog.h"
- #elif defined(TARGET_WINDOWS) || defined(TARGET_WIN10)
- #include "platform/win32/utils/Win32InterfaceForCLog.h"
- #else
- #include "platform/posix/utils/PosixInterfaceForCLog.h"
- #endif
- #include "settings/SettingUtils.h"
- #include "settings/Settings.h"
- #include "settings/SettingsComponent.h"
- #include "settings/lib/Setting.h"
- #include "settings/lib/SettingsManager.h"
- #include "utils/URIUtils.h"
- #include <cstring>
- #include <set>
- #include <spdlog/sinks/basic_file_sink.h>
- #include <spdlog/sinks/dist_sink.h>
- static constexpr unsigned char Utf8Bom[3] = {0xEF, 0xBB, 0xBF};
- static const std::string LogFileExtension = ".log";
- static const std::string LogPattern = "%Y-%m-%d %T.%e T:%-5t %7l <%n>: %v";
- CLog::CLog()
- : m_platform(IPlatformLog::CreatePlatformLog()),
- m_sinks(std::make_shared<spdlog::sinks::dist_sink_mt>()),
- m_defaultLogger(CreateLogger("general")),
- m_logLevel(LOG_LEVEL_DEBUG),
- m_componentLogEnabled(false),
- m_componentLogLevels(0)
- {
- // add platform-specific debug sinks
- m_platform->AddSinks(m_sinks);
- // register the default logger with spdlog
- spdlog::set_default_logger(m_defaultLogger);
- // set the formatting pattern globally
- spdlog::set_pattern(LogPattern);
- // flush on debug logs
- spdlog::flush_on(spdlog::level::debug);
- // set the log level
- SetLogLevel(m_logLevel);
- }
- void CLog::OnSettingsLoaded()
- {
- const std::shared_ptr<CSettings> settings = CServiceBroker::GetSettingsComponent()->GetSettings();
- m_componentLogEnabled = settings->GetBool(CSettings::SETTING_DEBUG_EXTRALOGGING);
- SetComponentLogLevel(settings->GetList(CSettings::SETTING_DEBUG_SETEXTRALOGLEVEL));
- }
- void CLog::OnSettingChanged(std::shared_ptr<const CSetting> setting)
- {
- if (setting == NULL)
- return;
- const std::string& settingId = setting->GetId();
- if (settingId == CSettings::SETTING_DEBUG_EXTRALOGGING)
- m_componentLogEnabled = std::static_pointer_cast<const CSettingBool>(setting)->GetValue();
- else if (settingId == CSettings::SETTING_DEBUG_SETEXTRALOGLEVEL)
- SetComponentLogLevel(
- CSettingUtils::GetList(std::static_pointer_cast<const CSettingList>(setting)));
- }
- void CLog::Initialize(const std::string& path)
- {
- if (m_fileSink != nullptr)
- return;
- // register setting callbacks
- auto settingsManager =
- CServiceBroker::GetSettingsComponent()->GetSettings()->GetSettingsManager();
- settingsManager->RegisterSettingOptionsFiller("loggingcomponents",
- SettingOptionsLoggingComponentsFiller);
- settingsManager->RegisterSettingsHandler(this);
- std::set<std::string> settingSet;
- settingSet.insert(CSettings::SETTING_DEBUG_EXTRALOGGING);
- settingSet.insert(CSettings::SETTING_DEBUG_SETEXTRALOGLEVEL);
- settingsManager->RegisterCallback(this, settingSet);
- if (path.empty())
- return;
- // put together the path to the log file(s)
- std::string appName = CCompileInfo::GetAppName();
- StringUtils::ToLower(appName);
- const std::string filePathBase = URIUtils::AddFileToFolder(path, appName);
- const std::string filePath = filePathBase + LogFileExtension;
- const std::string oldFilePath = filePathBase + ".old" + LogFileExtension;
- // handle old.log by deleting an existing old.log and renaming the last log to old.log
- XFILE::CFile::Delete(oldFilePath);
- XFILE::CFile::Rename(filePath, oldFilePath);
- // write UTF-8 BOM
- {
- XFILE::CFile file;
- if (file.OpenForWrite(filePath, true))
- file.Write(Utf8Bom, sizeof(Utf8Bom));
- }
- // create the file sink
- m_fileSink = std::make_shared<spdlog::sinks::basic_file_sink_mt>(
- m_platform->GetLogFilename(filePath), false);
- m_fileSink->set_pattern(LogPattern);
- // add it to the existing sinks
- m_sinks->add_sink(m_fileSink);
- }
- void CLog::Uninitialize()
- {
- if (m_fileSink == nullptr)
- return;
- // unregister setting callbacks
- auto settingsManager =
- CServiceBroker::GetSettingsComponent()->GetSettings()->GetSettingsManager();
- settingsManager->UnregisterSettingOptionsFiller("loggingcomponents");
- settingsManager->UnregisterSettingsHandler(this);
- settingsManager->UnregisterCallback(this);
- // flush all loggers
- spdlog::apply_all([](std::shared_ptr<spdlog::logger> logger) { logger->flush(); });
- // flush the file sink
- m_fileSink->flush();
- // remove and destroy the file sink
- m_sinks->remove_sink(m_fileSink);
- m_fileSink.reset();
- }
- void CLog::SetLogLevel(int level)
- {
- if (level < LOG_LEVEL_NONE || level > LOG_LEVEL_MAX)
- return;
- m_logLevel = level;
- auto spdLevel = spdlog::level::info;
- if (level <= LOG_LEVEL_NONE)
- spdLevel = spdlog::level::off;
- else if (level >= LOG_LEVEL_DEBUG)
- spdLevel = spdlog::level::trace;
- if (m_defaultLogger != nullptr && m_defaultLogger->level() == spdLevel)
- return;
- spdlog::set_level(spdLevel);
- FormatAndLogInternal(spdlog::level::info, "Log level changed to \"{}\"",
- spdlog::level::to_string_view(spdLevel));
- }
- bool CLog::IsLogLevelLogged(int loglevel)
- {
- if (m_logLevel >= LOG_LEVEL_DEBUG)
- return true;
- if (m_logLevel <= LOG_LEVEL_NONE)
- return false;
- return (loglevel & LOGMASK) >= LOGNOTICE;
- }
- bool CLog::CanLogComponent(uint32_t component) const
- {
- if (!m_componentLogEnabled || component == 0)
- return false;
- return ((m_componentLogLevels & component) == component);
- }
- void CLog::SettingOptionsLoggingComponentsFiller(SettingConstPtr setting,
- std::vector<IntegerSettingOption>& list,
- int& current,
- void* data)
- {
- list.emplace_back(g_localizeStrings.Get(669), LOGSAMBA);
- list.emplace_back(g_localizeStrings.Get(670), LOGCURL);
- list.emplace_back(g_localizeStrings.Get(672), LOGFFMPEG);
- list.emplace_back(g_localizeStrings.Get(675), LOGJSONRPC);
- list.emplace_back(g_localizeStrings.Get(676), LOGAUDIO);
- list.emplace_back(g_localizeStrings.Get(680), LOGVIDEO);
- list.emplace_back(g_localizeStrings.Get(683), LOGAVTIMING);
- list.emplace_back(g_localizeStrings.Get(684), LOGWINDOWING);
- list.emplace_back(g_localizeStrings.Get(685), LOGPVR);
- list.emplace_back(g_localizeStrings.Get(686), LOGEPG);
- list.emplace_back(g_localizeStrings.Get(39117), LOGANNOUNCE);
- #ifdef HAS_DBUS
- list.emplace_back(g_localizeStrings.Get(674), LOGDBUS);
- #endif
- #ifdef HAS_WEB_SERVER
- list.emplace_back(g_localizeStrings.Get(681), LOGWEBSERVER);
- #endif
- #ifdef HAS_AIRTUNES
- list.emplace_back(g_localizeStrings.Get(677), LOGAIRTUNES);
- #endif
- #ifdef HAS_UPNP
- list.emplace_back(g_localizeStrings.Get(678), LOGUPNP);
- #endif
- #ifdef HAVE_LIBCEC
- list.emplace_back(g_localizeStrings.Get(679), LOGCEC);
- #endif
- list.emplace_back(g_localizeStrings.Get(682), LOGDATABASE);
- }
- Logger CLog::GetLogger(const std::string& loggerName)
- {
- auto logger = spdlog::get(loggerName);
- if (logger == nullptr)
- logger = CreateLogger(loggerName);
- return logger;
- }
- CLog& CLog::GetInstance()
- {
- return CServiceBroker::GetLogging();
- }
- spdlog::level::level_enum CLog::MapLogLevel(int level)
- {
- switch (level)
- {
- case LOGDEBUG:
- return spdlog::level::debug;
- case LOGINFO:
- case LOGNOTICE:
- return spdlog::level::info;
- case LOGWARNING:
- return spdlog::level::warn;
- case LOGERROR:
- return spdlog::level::err;
- case LOGSEVERE:
- case LOGFATAL:
- return spdlog::level::critical;
- case LOGNONE:
- return spdlog::level::off;
- default:
- break;
- }
- return spdlog::level::info;
- }
- Logger CLog::CreateLogger(const std::string& loggerName)
- {
- // create the logger
- auto logger = std::make_shared<spdlog::logger>(loggerName, m_sinks);
- // initialize the logger
- spdlog::initialize_logger(logger);
- return logger;
- }
- void CLog::SetComponentLogLevel(const std::vector<CVariant>& components)
- {
- m_componentLogLevels = 0;
- for (const auto& component : components)
- {
- if (!component.isInteger())
- continue;
- m_componentLogLevels |= static_cast<uint32_t>(component.asInteger());
- }
- }