From be933ef2241d79558f91796cc5b3a161f72ebf9c Mon Sep 17 00:00:00 2001 From: manuel Date: Mon, 19 Oct 2020 00:52:24 +0200 Subject: sync with upstream --- xbmc/utils/log.cpp | 288 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 288 insertions(+) create mode 100644 xbmc/utils/log.cpp (limited to 'xbmc/utils/log.cpp') 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 @@ +/* + * 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 +#include + +#include +#include + +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()), + 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 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 setting) +{ + if (setting == NULL) + return; + + const std::string& settingId = setting->GetId(); + if (settingId == CSettings::SETTING_DEBUG_EXTRALOGGING) + m_componentLogEnabled = std::static_pointer_cast(setting)->GetValue(); + else if (settingId == CSettings::SETTING_DEBUG_SETEXTRALOGLEVEL) + SetComponentLogLevel( + CSettingUtils::GetList(std::static_pointer_cast(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 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( + 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 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& 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(loggerName, m_sinks); + + // initialize the logger + spdlog::initialize_logger(logger); + + return logger; +} + +void CLog::SetComponentLogLevel(const std::vector& components) +{ + m_componentLogLevels = 0; + for (const auto& component : components) + { + if (!component.isInteger()) + continue; + + m_componentLogLevels |= static_cast(component.asInteger()); + } +} -- cgit v1.2.3