| /* | |
| * Licensed to the Apache Software Foundation (ASF) under one or more | |
| * contributor license agreements. See the NOTICE file distributed with | |
| * this work for additional information regarding copyright ownership. | |
| * The ASF licenses this file to You under the Apache License, Version 2.0 | |
| * (the "License"); you may not use this file except in compliance with | |
| * the License. You may obtain a copy of the License at | |
| * | |
| * http://www.apache.org/licenses/LICENSE-2.0 | |
| * | |
| * Unless required by applicable law or agreed to in writing, software | |
| * distributed under the License is distributed on an "AS IS" BASIS, | |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| * See the License for the specific language governing permissions and | |
| * limitations under the License. | |
| */ | |
| #include <log4cxx/logstring.h> | |
| #include <log4cxx/helpers/loglog.h> | |
| #include <log4cxx/logmanager.h> | |
| #include <log4cxx/helpers/transcoder.h> | |
| #include <iostream> | |
| #if !defined(LOG4CXX) | |
| #define LOG4CXX 1 | |
| #endif | |
| #include <log4cxx/private/log4cxx_private.h> | |
| #include <log4cxx/helpers/aprinitializer.h> | |
| #include <log4cxx/helpers/date.h> | |
| #include <log4cxx/helpers/stringhelper.h> | |
| #include <log4cxx/helpers/systemerrwriter.h> | |
| #include <log4cxx/helpers/optionconverter.h> | |
| #include <mutex> | |
| using namespace LOG4CXX_NS; | |
| using namespace LOG4CXX_NS::helpers; | |
| struct LogLog::LogLogPrivate | |
| { | |
| LogLogPrivate() | |
| : startTime{ APRInitializer::getStartTime() } | |
| {} | |
| ~LogLogPrivate() | |
| { | |
| quietMode = true; // Prevent output after deletion by onexit processing chain. | |
| } | |
| static LogLog* parent; | |
| static LogLogPrivate* getInstance() | |
| { | |
| if (!parent) | |
| return nullptr; | |
| return parent->m_priv.get(); | |
| } | |
| log4cxx_time_t startTime; | |
| bool debugEnabled{ false }; | |
| bool timeStampEnabled{ true }; | |
| /** | |
| In quietMode not even errors generate any output. | |
| */ | |
| bool quietMode{ false }; | |
| std::mutex mutex; | |
| LogString errorPrefix; | |
| LogString warnPrefix; | |
| LogString debugPrefix; | |
| LogString suffix; | |
| void setColorEnabled(bool newValue) | |
| { | |
| if (newValue) | |
| { | |
| this->errorPrefix = LOG4CXX_STR("\x1B[31m"); //red | |
| this->warnPrefix = LOG4CXX_STR("\x1B[33m"); //yellow | |
| this->debugPrefix = LOG4CXX_STR("\x1B[32m"); //green | |
| this->suffix = LOG4CXX_STR("\x1B[0m"); // none | |
| } | |
| else | |
| { | |
| this->errorPrefix.clear(); | |
| this->warnPrefix.clear(); | |
| this->debugPrefix.clear(); | |
| this->suffix.clear(); | |
| } | |
| } | |
| LogString elapsedMicroseconds() | |
| { | |
| LogString result; | |
| if (this->timeStampEnabled) | |
| { | |
| auto microsecondInterval = Date::currentTime() - this->startTime; | |
| StringHelper::toString(microsecondInterval, result); | |
| result += ' '; | |
| } | |
| return result; | |
| } | |
| void emit_log(const LogString& prefix, const LogString& msg, const LogString& suffix); | |
| void emit_log(const LogString& prefix, const LogString& msg, const std::exception& ex, const LogString& suffix); | |
| }; | |
| LogLog* LogLog::LogLogPrivate::parent{ nullptr }; | |
| LogLog::LogLog() : | |
| m_priv(std::make_unique<LogLogPrivate>()) | |
| { | |
| LogString log4cxxDebug = OptionConverter::getSystemProperty(LOG4CXX_STR("LOG4CXX_DEBUG"), LOG4CXX_STR("false")); | |
| m_priv->debugEnabled = OptionConverter::toBoolean(log4cxxDebug, false); | |
| auto logLogTimestamps = OptionConverter::getSystemProperty(LOG4CXX_STR("LOG4CXX_DEBUG_TIMESTAMPS"), LOG4CXX_STR("true")); | |
| m_priv->timeStampEnabled = OptionConverter::toBoolean(logLogTimestamps, true); | |
| auto color = OptionConverter::getSystemProperty(LOG4CXX_STR("LOG4CXX_COLOR"), LOG4CXX_STR("true")); | |
| m_priv->setColorEnabled(OptionConverter::toBoolean(color, true)); | |
| } | |
| LogLog::~LogLog() | |
| { | |
| LogLogPrivate::parent = nullptr; | |
| } | |
| ObjectPtr LogLog::_createInstance() | |
| { | |
| using LogLogHolder = SingletonHolder<LogLog>; | |
| auto pLogLog = std::make_shared<LogLogHolder>(); | |
| LogLogPrivate::parent = &pLogLog->value(); | |
| debug(LOG4CXX_STR("Started")); | |
| return pLogLog; | |
| } | |
| bool LogLog::isDebugEnabled() | |
| { | |
| auto p = LogLogPrivate::getInstance(); | |
| return p && !p->quietMode // Not deleted by onexit processing? | |
| && p->debugEnabled; | |
| } | |
| bool LogLog::isDebugEnabledFor(const LoggerPtr& category) | |
| { | |
| return isDebugEnabled() && category && category->isDebugEnabled(); | |
| } | |
| bool LogLog::isTraceEnabledFor(const LoggerPtr& category) | |
| { | |
| return isDebugEnabled() && category && category->isTraceEnabled(); | |
| } | |
| void LogLog::setInternalDebugging(bool debugEnabled1) | |
| { | |
| auto p = LogLogPrivate::getInstance(); | |
| if (p && !p->quietMode) // Not deleted by onexit processing? | |
| p->debugEnabled = debugEnabled1; | |
| } | |
| bool LogLog::isColorEnabled() | |
| { | |
| auto p = LogLogPrivate::getInstance(); | |
| return p && !p->errorPrefix.empty(); | |
| } | |
| void LogLog::setColorEnabled(bool newValue) | |
| { | |
| if (auto p = LogLogPrivate::getInstance()) | |
| p->setColorEnabled(newValue); | |
| } | |
| void LogLog::debug(const LogString& msg) | |
| { | |
| auto p = LogLogPrivate::getInstance(); | |
| if (p && !p->quietMode) // Not deleted by onexit processing? | |
| { | |
| if (!p->debugEnabled) | |
| { | |
| return; | |
| } | |
| std::lock_guard<std::mutex> lock(p->mutex); | |
| p->emit_log(p->debugPrefix, msg, p->suffix); | |
| } | |
| } | |
| void LogLog::debug(const LogString& msg, const std::exception& e) | |
| { | |
| auto p = LogLogPrivate::getInstance(); | |
| if (p && !p->quietMode) // Not deleted by onexit processing? | |
| { | |
| if (!p->debugEnabled) | |
| return; | |
| std::lock_guard<std::mutex> lock(p->mutex); | |
| p->emit_log(p->debugPrefix, msg, e, p->suffix); | |
| } | |
| } | |
| void LogLog::error(const LogString& msg) | |
| { | |
| auto p = LogLogPrivate::getInstance(); | |
| if (p && !p->quietMode) // Not deleted by onexit processing? | |
| { | |
| std::lock_guard<std::mutex> lock(p->mutex); | |
| p->emit_log(p->errorPrefix, msg, p->suffix); | |
| } | |
| } | |
| void LogLog::error(const LogString& msg, const std::exception& e) | |
| { | |
| auto p = LogLogPrivate::getInstance(); | |
| if (p && !p->quietMode) // Not deleted by onexit processing? | |
| { | |
| std::lock_guard<std::mutex> lock(p->mutex); | |
| p->emit_log(p->errorPrefix, msg, e, p->suffix); | |
| } | |
| } | |
| LoggerPtr LogLog::getLogger(const LogString& name) | |
| { | |
| return LogManager::getLoggerRepository()->getLogger(name); | |
| } | |
| #if !LOG4CXX_LOGCHAR_IS_UTF8 | |
| void LogLog::trace(const LoggerPtr& category, const std::string& msg) | |
| { | |
| LOG4CXX_DECODE_CHAR(lsMsg, msg); | |
| trace(category, lsMsg); | |
| } | |
| #endif | |
| void LogLog::trace(const LoggerPtr& category, const LogString& msg) | |
| { | |
| auto p = LogLogPrivate::getInstance(); | |
| if (p && !p->quietMode) // Not deleted by onexit processing? | |
| { | |
| if (!p->debugEnabled) | |
| { | |
| return; | |
| } | |
| std::lock_guard<std::mutex> lock(p->mutex); | |
| p->emit_log(p->debugPrefix, category->getName() + LOG4CXX_STR("::") + msg, p->suffix); | |
| } | |
| } | |
| void LogLog::setQuietMode(bool quietMode1) | |
| { | |
| auto p = LogLogPrivate::getInstance(); | |
| std::lock_guard<std::mutex> lock(p->mutex); | |
| p->quietMode = quietMode1; | |
| } | |
| void LogLog::warn(const LogString& msg) | |
| { | |
| auto p = LogLogPrivate::getInstance(); | |
| if (p && !p->quietMode) // Not deleted by onexit processing? | |
| { | |
| std::lock_guard<std::mutex> lock(p->mutex); | |
| p->emit_log(p->warnPrefix, msg, p->suffix); | |
| } | |
| } | |
| void LogLog::warn(const LogString& msg, const std::exception& e) | |
| { | |
| auto p = LogLogPrivate::getInstance(); | |
| if (p && !p->quietMode) // Not deleted by onexit processing? | |
| { | |
| std::lock_guard<std::mutex> lock(p->mutex); | |
| p->emit_log(p->warnPrefix, msg, e, p->suffix); | |
| } | |
| } | |
| void LogLog::LogLogPrivate::emit_log(const LogString& prefix, const LogString& msg, const LogString& suffix) | |
| { | |
| LogString out(elapsedMicroseconds() + LOG4CXX_STR("log4cxx: ")); | |
| out.append(prefix); | |
| out.append(msg); | |
| out.append(suffix); | |
| out.append(1, (logchar) 0x0A); | |
| SystemErrWriter().write(out); | |
| } | |
| void LogLog::LogLogPrivate::emit_log(const LogString& prefix, const LogString& msg, const std::exception& ex, const LogString& suffix) | |
| { | |
| LogString out(elapsedMicroseconds() + LOG4CXX_STR("log4cxx: ")); | |
| out.append(prefix); | |
| LogString exOut; | |
| if (auto raw = ex.what()) | |
| { | |
| exOut.append(out); | |
| Transcoder::decode(raw, exOut); | |
| } | |
| out.append(suffix); | |
| out.append(1, (logchar) 0x0A); | |
| SystemErrWriter errWriter; | |
| errWriter.write(out); | |
| if (!exOut.empty()) | |
| { | |
| exOut.append(suffix); | |
| exOut.append(1, (logchar) 0x0A); | |
| errWriter.write(exOut); | |
| } | |
| } |