From a6486f7cbcc07bff119b16a0b277e3e3bbbce1ea Mon Sep 17 00:00:00 2001 From: Matteo Merli Date: Sun, 20 May 2018 07:00:16 -0700 Subject: [PATCH] Added option for custom loggers in C++ and C APIs --- pulsar-client-cpp/CMakeLists.txt | 38 ++++--- .../include/pulsar/ClientConfiguration.h | 13 +++ pulsar-client-cpp/include/pulsar/Logger.h | 51 +++++++++ .../include/pulsar/c/client_configuration.h | 17 +-- pulsar-client-cpp/lib/ClientConfiguration.cc | 7 ++ .../lib/ClientConfigurationImpl.h | 2 + pulsar-client-cpp/lib/ClientImpl.cc | 21 +++- pulsar-client-cpp/lib/Log4CxxLogger.h | 41 +++++++ pulsar-client-cpp/lib/Log4cxxLogger.cc | 96 +++++++++++++++++ pulsar-client-cpp/lib/LogUtils.cc | 55 +++++----- pulsar-client-cpp/lib/LogUtils.h | 101 +++++++++--------- pulsar-client-cpp/lib/MessageBuilder.cc | 2 +- pulsar-client-cpp/lib/MessageCrypto.cc | 14 +-- pulsar-client-cpp/lib/SimpleLoggerImpl.cc | 90 ++++++++++++++++ pulsar-client-cpp/lib/SimpleLoggerImpl.h | 33 ++++++ .../lib/c/c_ClientConfiguration.cc | 30 ++++-- pulsar-client-cpp/perf/CMakeLists.txt | 4 +- pulsar-client-cpp/perf/PerfConsumer.cc | 2 - pulsar-client-cpp/perf/PerfProducer.cc | 10 +- pulsar-client-cpp/tests/main.cc | 1 - 20 files changed, 500 insertions(+), 128 deletions(-) create mode 100644 pulsar-client-cpp/include/pulsar/Logger.h create mode 100644 pulsar-client-cpp/lib/Log4CxxLogger.h create mode 100644 pulsar-client-cpp/lib/Log4cxxLogger.cc create mode 100644 pulsar-client-cpp/lib/SimpleLoggerImpl.cc create mode 100644 pulsar-client-cpp/lib/SimpleLoggerImpl.h diff --git a/pulsar-client-cpp/CMakeLists.txt b/pulsar-client-cpp/CMakeLists.txt index e5fd716d8ecd2..38a47742eff66 100644 --- a/pulsar-client-cpp/CMakeLists.txt +++ b/pulsar-client-cpp/CMakeLists.txt @@ -27,6 +27,9 @@ MESSAGE(STATUS "BUILD_TESTS: " ${BUILD_TESTS}) option(LINK_STATIC "Link against static libraries" OFF) MESSAGE(STATUS "LINK_STATIC: " ${LINK_STATIC}) +option(USE_LOG4CXX "Build with Log4cxx support" OFF) +MESSAGE(STATUS "USE_LOG4CXX: " ${USE_LOG4CXX}) + IF (CMAKE_BUILD_TYPE STREQUAL "") set(CMAKE_BUILD_TYPE RelWithDebInfo) ENDIF () @@ -65,17 +68,20 @@ if (LINK_STATIC) find_library(PROTOBUF_LIBRARIES NAMES libprotobuf.a) find_library(CURL_LIBRARY_PATH NAMES libcurl.a curl) find_library(LIB_JSON NAMES libjsoncpp.a libjsoncpp_static.a) - find_library(LOG4CXX_LIBRARY_PATH NAMES liblog4cxx.a) - - # Libraries needed by log4cxx to link statically with - find_library(APR_LIBRARY_PATH NAMES libapr-1.a PATHS /usr/lib /usr/local/apr/lib /usr/local/opt/apr/libexec/lib/) - find_library(APR_UTIL_LIBRARY_PATH NAMES libaprutil-1.a PATHS /usr/lib /usr/local/apr/lib /usr/local/opt/apr-util/libexec/lib/) - find_library(EXPAT_LIBRARY_PATH NAMES libexpat.a expat) - if (APPLE) - find_library(ICONV_LIBRARY_PATH NAMES libiconv.a iconv) - else () - set(ICONV_LIBRARY_PATH ) - endif () + + if (USE_LOG4CXX) + find_library(LOG4CXX_LIBRARY_PATH NAMES liblog4cxx.a) + + # Libraries needed by log4cxx to link statically with + find_library(APR_LIBRARY_PATH NAMES libapr-1.a PATHS /usr/lib /usr/local/apr/lib /usr/local/opt/apr/libexec/lib/) + find_library(APR_UTIL_LIBRARY_PATH NAMES libaprutil-1.a PATHS /usr/lib /usr/local/apr/lib /usr/local/opt/apr-util/libexec/lib/) + find_library(EXPAT_LIBRARY_PATH NAMES libexpat.a expat) + if (APPLE) + find_library(ICONV_LIBRARY_PATH NAMES libiconv.a iconv) + else () + set(ICONV_LIBRARY_PATH ) + endif (APPLE) + endif (USE_LOG4CXX) else() # Link to shared libraries find_package(ZLIB REQUIRED) @@ -90,7 +96,9 @@ else() find_library(LIB_JSON jsoncpp) find_library(LOG4CXX_LIBRARY_PATH log4cxx) find_library(CURL_LIBRARY_PATH curl) - find_path(LOG4CXX_INCLUDE_PATH log4cxx/logger.h) + if (USE_LOG4CXX) + find_path(LOG4CXX_INCLUDE_PATH log4cxx/logger.h) + endif (USE_LOG4CXX) endif (LINK_STATIC) @@ -140,7 +148,11 @@ if (BUILD_TESTS) endif () find_path(JSON_INCLUDE_PATH jsoncpp) -find_path(LOG4CXX_INCLUDE_PATH log4cxx/logger.h) + +if (USE_LOG4CXX) + set(CMAKE_CXX_FLAGS " -DUSE_LOG4CXX ${CMAKE_CXX_FLAGS}") + find_path(LOG4CXX_INCLUDE_PATH log4cxx/logger.h) +endif (USE_LOG4CXX) if (NOT LIB_JSON) find_library(LIB_JSON json_cpp) diff --git a/pulsar-client-cpp/include/pulsar/ClientConfiguration.h b/pulsar-client-cpp/include/pulsar/ClientConfiguration.h index 137d528ca2d4e..eedf716240d34 100644 --- a/pulsar-client-cpp/include/pulsar/ClientConfiguration.h +++ b/pulsar-client-cpp/include/pulsar/ClientConfiguration.h @@ -20,6 +20,8 @@ #define PULSAR_CLIENTCONFIGURATION_H_ #include +#include + #pragma GCC visibility push(default) namespace pulsar { class PulsarWrapper; @@ -105,6 +107,7 @@ class ClientConfiguration { * Initialize the log configuration * * @param logConfFilePath path of the configuration file + * @deprecated */ ClientConfiguration& setLogConfFilePath(const std::string& logConfFilePath); @@ -113,6 +116,16 @@ class ClientConfiguration { */ const std::string& getLogConfFilePath() const; + /** + * Configure a custom logger backend to route of Pulsar client library + * to a different logger implementation. + * + * By default, log messages are printed on standard output. + */ + ClientConfiguration& setLogger(LoggerFactoryPtr loggerFactory); + + LoggerFactoryPtr getLogger() const; + ClientConfiguration& setUseTls(bool useTls); bool isUseTls() const; diff --git a/pulsar-client-cpp/include/pulsar/Logger.h b/pulsar-client-cpp/include/pulsar/Logger.h new file mode 100644 index 0000000000000..e319a04f0b837 --- /dev/null +++ b/pulsar-client-cpp/include/pulsar/Logger.h @@ -0,0 +1,51 @@ +/** + * 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. + */ +#pragma once + +#include + +#pragma GCC visibility push(default) + +namespace pulsar { + +class Logger { + public: + enum Level + { + DEBUG = 0, + INFO = 1, + WARN = 2, + ERROR = 3 + }; + + virtual bool isEnabled(Level level) = 0; + + virtual void log(Level level, int line, const std::string& message) = 0; +}; + +class LoggerFactory { + public: + virtual ~LoggerFactory() {} + + virtual Logger* getLogger(const std::string& fileName) = 0; +}; + +typedef boost::shared_ptr LoggerFactoryPtr; +} // namespace pulsar +#pragma GCC visibility pop diff --git a/pulsar-client-cpp/include/pulsar/c/client_configuration.h b/pulsar-client-cpp/include/pulsar/c/client_configuration.h index 7725e7cca8d81..b04c21d03a111 100644 --- a/pulsar-client-cpp/include/pulsar/c/client_configuration.h +++ b/pulsar-client-cpp/include/pulsar/c/client_configuration.h @@ -25,6 +25,10 @@ extern "C" { #pragma GCC visibility push(default) +typedef enum { pulsar_DEBUG = 0, pulsar_INFO = 1, pulsar_WARN = 2, pulsar_ERROR = 3 } pulsar_logger_level_t; + +typedef void (*pulsar_logger)(pulsar_logger_level_t level, const char *file, int line, const char *message); + typedef struct _pulsar_client_configuration pulsar_client_configuration_t; typedef struct _pulsar_authentication pulsar_authentication_t; @@ -101,18 +105,7 @@ void pulsar_client_configuration_set_concurrent_lookup_request(pulsar_client_con */ int pulsar_client_configuration_get_concurrent_lookup_request(pulsar_client_configuration_t *conf); -/** - * Initialize the log configuration - * - * @param logConfFilePath path of the configuration file - */ -void pulsar_client_configuration_set_log_conf_file_path(pulsar_client_configuration_t *conf, - const char *logConfFilePath); - -/** - * Get the path of log configuration file (log4cpp) - */ -const char *pulsar_client_configuration_get_log_conf_file_path(pulsar_client_configuration_t *conf); +void pulsar_client_configuration_logger(pulsar_client_configuration_t *conf, pulsar_logger logger); void pulsar_client_configuration_set_use_tls(pulsar_client_configuration_t *conf, int useTls); diff --git a/pulsar-client-cpp/lib/ClientConfiguration.cc b/pulsar-client-cpp/lib/ClientConfiguration.cc index 6f011e3b6de37..246c7af932a59 100644 --- a/pulsar-client-cpp/lib/ClientConfiguration.cc +++ b/pulsar-client-cpp/lib/ClientConfiguration.cc @@ -96,6 +96,13 @@ ClientConfiguration& ClientConfiguration::setLogConfFilePath(const std::string& const std::string& ClientConfiguration::getLogConfFilePath() const { return impl_->logConfFilePath; } +ClientConfiguration& ClientConfiguration::setLogger(LoggerFactoryPtr loggerFactory) { + impl_->loggerFactory = loggerFactory; + return *this; +} + +LoggerFactoryPtr ClientConfiguration::getLogger() const { return impl_->loggerFactory; } + ClientConfiguration& ClientConfiguration::setStatsIntervalInSeconds( const unsigned int& statsIntervalInSeconds) { impl_->statsIntervalInSeconds = statsIntervalInSeconds; diff --git a/pulsar-client-cpp/lib/ClientConfigurationImpl.h b/pulsar-client-cpp/lib/ClientConfigurationImpl.h index 4ea77cf92e1bb..b5da7908ed0da 100644 --- a/pulsar-client-cpp/lib/ClientConfigurationImpl.h +++ b/pulsar-client-cpp/lib/ClientConfigurationImpl.h @@ -34,6 +34,8 @@ struct ClientConfigurationImpl { std::string tlsTrustCertsFilePath; bool tlsAllowInsecureConnection; unsigned int statsIntervalInSeconds; + LoggerFactoryPtr loggerFactory; + ClientConfigurationImpl() : authenticationPtr(AuthFactory::Disabled()), ioThreads(1), diff --git a/pulsar-client-cpp/lib/ClientImpl.cc b/pulsar-client-cpp/lib/ClientImpl.cc index 1390336cd7002..80f947b6071d1 100644 --- a/pulsar-client-cpp/lib/ClientImpl.cc +++ b/pulsar-client-cpp/lib/ClientImpl.cc @@ -24,6 +24,8 @@ #include "ReaderImpl.h" #include "PartitionedProducerImpl.h" #include "PartitionedConsumerImpl.h" +#include "SimpleLoggerImpl.h" +#include "Log4CxxLogger.h" #include #include #include @@ -73,7 +75,24 @@ ClientImpl::ClientImpl(const std::string& serviceUrl, const ClientConfiguration& producerIdGenerator_(0), consumerIdGenerator_(0), requestIdGenerator_(0) { - LogUtils::init(clientConfiguration.getLogConfFilePath()); + if (clientConfiguration.getLogger()) { + // A logger factory was explicitely configured. Let's just use that + LogUtils::setLoggerFactory(clientConfiguration.getLogger()); + } else { +#ifdef USE_LOG4CXX + if (!clientConfiguration.getLogConfFilePath().empty()) { + // A log4cxx log file was passed through deprecated parameter. Use that to configure Log4CXX + LogUtils::setLoggerFactory(Log4CxxLogger::create(clientConfiguration.getLogConfFilePath())); + } else { + // Use default simple console logger + LogUtils::setLoggerFactory(SimpleLoggerFactory::create()); + } +#else + // Use default simple console logger + LogUtils::setLoggerFactory(SimpleLoggerFactory::create()); +#endif + } + if (serviceUrl_.compare(0, 4, "http") == 0) { LOG_DEBUG("Using HTTP Lookup"); lookupServicePtr_ = diff --git a/pulsar-client-cpp/lib/Log4CxxLogger.h b/pulsar-client-cpp/lib/Log4CxxLogger.h new file mode 100644 index 0000000000000..184c33652fb02 --- /dev/null +++ b/pulsar-client-cpp/lib/Log4CxxLogger.h @@ -0,0 +1,41 @@ +/** + * 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. + */ + +#pragma once + +#include + +#ifdef USE_LOG4CXX + +#pragma GCC visibility push(default) + +namespace pulsar { + +class Log4CxxLoggerFactory : public LoggerFactory { + public: + static LoggerFactoryPtr create(); + static LoggerFactoryPtr create(const std::string& log4cxxConfFile); + + Logger* getLogger(const std::string& fileName); +}; +} // namespace pulsar + +#pragma GCC visibility pop + +#endif diff --git a/pulsar-client-cpp/lib/Log4cxxLogger.cc b/pulsar-client-cpp/lib/Log4cxxLogger.cc new file mode 100644 index 0000000000000..99cc6144ca9aa --- /dev/null +++ b/pulsar-client-cpp/lib/Log4cxxLogger.cc @@ -0,0 +1,96 @@ +/** + * 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 "Log4CxxLogger.h" +#include + +#ifdef USE_LOG4CXX + +#include +#include +#include +#include +#include + +using namespace log4cxx; + +namespace pulsar { + +class Log4CxxLogger : public Logger { + std::string _fileName; + LoggerPtr _logger; + + public: + Log4CxxLogger(const std::string &fileName) + : _fileName(fileName), _logger(log4cxx::Logger::getLogger(LOG_CATEGORY_NAME + fileName)) {} + + bool isEnabled(Level level) { return _logger->isEnabledFor(getLevel(level)); } + + void log(Level level, int line, const std::string &message) { + spi::LocationInfo location(_fileName.c_str(), "", line); + _logger->forcedLogLS(getLevel(level), message, location); + } + + private: + static log4cxx::LevelPtr getLevel(Level level) { + switch (level) { + case DEBUG: + return log4cxx::Level::getDebug(); + case INFO: + return log4cxx::Level::getInfo(); + case WARN: + return log4cxx::Level::getWarn(); + case ERROR: + return log4cxx::Level::getError(); + } + } +}; + +LoggerFactoryPtr Log4CxxLoggerFactory::create() { + if (!LogManager::getLoggerRepository()->isConfigured()) { + LogManager::getLoggerRepository()->setConfigured(true); + LoggerPtr root = log4cxx::Logger::getRootLogger(); + static const LogString TTCC_CONVERSION_PATTERN(LOG4CXX_STR("%d{HH:mm:ss.SSS} [%t] %-5p %l - %m%n")); + LayoutPtr layout(new PatternLayout(TTCC_CONVERSION_PATTERN)); + AppenderPtr appender(new ConsoleAppender(layout)); + root->setLevel(log4cxx::Level::getInfo()); + root->addAppender(appender); + } + + return LoggerFactoryPtr(new Log4CxxLoggerFactory()); +} + +LoggerFactoryPtr Log4CxxLoggerFactory::create(const std::string &log4cxxConfFile) { + try { + log4cxx::PropertyConfigurator::configure(log4cxxConfFile); + } catch (const std::exception &e) { + std::cerr << "exception caught while configuring log4cpp via '" << log4cxxConfFile + << "': " << e.what() << std::endl; + } catch (...) { + std::cerr << "unknown exception while configuring log4cpp via '" << log4cxxConfFile << "'." + << std::endl; + } + + return LoggerFactoryPtr(new Log4CxxLoggerFactory()); +} + +Logger *Log4CxxLoggerFactory::getLogger(const std::string &fileName) { return new Log4CxxLogger(fileName); } +} // namespace pulsar + +#endif // USE_LOG4CXX diff --git a/pulsar-client-cpp/lib/LogUtils.cc b/pulsar-client-cpp/lib/LogUtils.cc index 70507d94fcf09..219232702dc99 100644 --- a/pulsar-client-cpp/lib/LogUtils.cc +++ b/pulsar-client-cpp/lib/LogUtils.cc @@ -18,35 +18,34 @@ */ #include "LogUtils.h" -#include -#include -#include -#include -#include #include -using namespace log4cxx; - -void LogUtils::init(const std::string& logfilePath) { - try { - if (logfilePath.empty()) { - if (!LogManager::getLoggerRepository()->isConfigured()) { - LogManager::getLoggerRepository()->setConfigured(true); - LoggerPtr root = Logger::getRootLogger(); - static const LogString TTCC_CONVERSION_PATTERN( - LOG4CXX_STR("%d{HH:mm:ss.SSS} [%t] %-5p %l - %m%n")); - LayoutPtr layout(new PatternLayout(TTCC_CONVERSION_PATTERN)); - AppenderPtr appender(new ConsoleAppender(layout)); - root->setLevel(log4cxx::Level::getInfo()); - root->addAppender(appender); - } - } else { - log4cxx::PropertyConfigurator::configure(logfilePath); - } - } catch (const std::exception& e) { - std::cerr << "exception caught while configuring log4cpp via '" << logfilePath << "': " << e.what() - << std::endl; - } catch (...) { - std::cerr << "unknown exception while configuring log4cpp via '" << logfilePath << "'." << std::endl; +#include "SimpleLoggerImpl.h" +#include "Log4CxxLogger.h" + +namespace pulsar { + +void LogUtils::init(const std::string &logfilePath) { +// If this is called explicitely, we fallback to Log4cxx config, if enabled + +#ifdef USE_LOG4CXX + if (!logfilePath.empty()) { + setLoggerFactory(Log4CxxLoggerFactory::create(logfilePath)); + } else { + setLoggerFactory(Log4CxxLoggerFactory::create()); } +#endif // USE_LOG4CXX } + +static LoggerFactoryPtr s_loggerFactory; + +void LogUtils::setLoggerFactory(LoggerFactoryPtr loggerFactory) { s_loggerFactory = loggerFactory; } + +LoggerFactoryPtr LogUtils::getLoggerFactory() { + if (!s_loggerFactory) { + s_loggerFactory.reset(new SimpleLoggerFactory()); + } + return s_loggerFactory; +} + +} // namespace pulsar \ No newline at end of file diff --git a/pulsar-client-cpp/lib/LogUtils.h b/pulsar-client-cpp/lib/LogUtils.h index 6371efed08278..12a5b0696c892 100644 --- a/pulsar-client-cpp/lib/LogUtils.h +++ b/pulsar-client-cpp/lib/LogUtils.h @@ -16,68 +16,64 @@ * specific language governing permissions and limitations * under the License. */ -#ifndef LOG_UTIL_H -#define LOG_UTIL_H + +#pragma once #include -#include #include +#include -#define DECLARE_LOG_OBJECT() \ - static log4cxx::LoggerPtr& logger() { \ - static boost::thread_specific_ptr threadSpecificLogPtr; \ - log4cxx::LoggerPtr* ptr = threadSpecificLogPtr.get(); \ - if (!ptr) { \ - threadSpecificLogPtr.reset( \ - new log4cxx::LoggerPtr(log4cxx::Logger::getLogger(LOG_CATEGORY_NAME __FILE__))); \ - ptr = threadSpecificLogPtr.get(); \ - } \ - return *ptr; \ - } +#include + +namespace pulsar { + +#define PULSAR_UNLIKELY(expr) __builtin_expect(expr, 0) -#define LOG_DEBUG(message) \ - { \ - if (LOG4CXX_UNLIKELY(logger()->isDebugEnabled())) { \ - ::log4cxx::helpers::MessageBuffer oss_; \ - logger()->forcedLog(::log4cxx::Level::getDebug(), oss_.str(((std::ostream&)oss_) << message), \ - LOG4CXX_LOCATION); \ - } \ +#define DECLARE_LOG_OBJECT() \ + static pulsar::Logger* logger() { \ + static boost::thread_specific_ptr threadSpecificLogPtr; \ + pulsar::Logger* ptr = threadSpecificLogPtr.get(); \ + if (PULSAR_UNLIKELY(!ptr)) { \ + threadSpecificLogPtr.reset(pulsar::LogUtils::getLoggerFactory()->getLogger(__FILE__)); \ + ptr = threadSpecificLogPtr.get(); \ + } \ + return ptr; \ } -#define LOG_INFO(message) \ - { \ - if (logger()->isInfoEnabled()) { \ - ::log4cxx::helpers::MessageBuffer oss_; \ - logger()->forcedLog(::log4cxx::Level::getInfo(), oss_.str(((std::ostream&)oss_) << message), \ - LOG4CXX_LOCATION); \ - } \ +#define LOG_DEBUG(message) \ + { \ + if (PULSAR_UNLIKELY(logger()->isEnabled(pulsar::Logger::DEBUG))) { \ + std::stringstream ss; \ + ss << message; \ + logger()->log(pulsar::Logger::DEBUG, __LINE__, ss.str()); \ + } \ } -#define LOG_WARN(message) \ - { \ - if (logger()->isWarnEnabled()) { \ - ::log4cxx::helpers::MessageBuffer oss_; \ - logger()->forcedLog(::log4cxx::Level::getWarn(), oss_.str(((std::ostream&)oss_) << message), \ - LOG4CXX_LOCATION); \ - } \ +#define LOG_INFO(message) \ + { \ + if (logger()->isEnabled(pulsar::Logger::INFO)) { \ + std::stringstream ss; \ + ss << message; \ + logger()->log(pulsar::Logger::INFO, __LINE__, ss.str()); \ + } \ } -#define LOG_ERROR(message) \ - { \ - if (logger()->isErrorEnabled()) { \ - ::log4cxx::helpers::MessageBuffer oss_; \ - logger()->forcedLog(::log4cxx::Level::getError(), oss_.str(((std::ostream&)oss_) << message), \ - LOG4CXX_LOCATION); \ - } \ +#define LOG_WARN(message) \ + { \ + if (logger()->isEnabled(pulsar::Logger::WARN)) { \ + std::stringstream ss; \ + ss << message; \ + logger()->log(pulsar::Logger::WARN, __LINE__, ss.str()); \ + } \ } -#define LOG_FATAL(message) \ - { \ - if (logger()->isFatalEnabled()) { \ - ::log4cxx::helpers::MessageBuffer oss_; \ - logger()->forcedLog(::log4cxx::Level::getFatal(), oss_.str(((std::ostream&)oss_) << message), \ - LOG4CXX_LOCATION); \ - } \ +#define LOG_ERROR(message) \ + { \ + if (logger()->isEnabled(pulsar::Logger::ERROR)) { \ + std::stringstream ss; \ + ss << message; \ + logger()->log(pulsar::Logger::ERROR, __LINE__, ss.str()); \ + } \ } #pragma GCC visibility push(default) @@ -85,8 +81,11 @@ class LogUtils { public: static void init(const std::string& logConfFilePath); + + static void setLoggerFactory(LoggerFactoryPtr loggerFactory); + + static LoggerFactoryPtr getLoggerFactory(); }; #pragma GCC visibility pop - -#endif +} diff --git a/pulsar-client-cpp/lib/MessageBuilder.cc b/pulsar-client-cpp/lib/MessageBuilder.cc index 4ea21b24e4833..5dd9df19894c9 100644 --- a/pulsar-client-cpp/lib/MessageBuilder.cc +++ b/pulsar-client-cpp/lib/MessageBuilder.cc @@ -48,7 +48,7 @@ Message MessageBuilder::build() { return Message(impl_); } void MessageBuilder::checkMetadata() { if (!impl_.get()) { - LOG_FATAL("Cannot reuse the same message builder to build a message"); + LOG_ERROR("Cannot reuse the same message builder to build a message"); abort(); } } diff --git a/pulsar-client-cpp/lib/MessageCrypto.cc b/pulsar-client-cpp/lib/MessageCrypto.cc index c5f41d8f27553..0203660a882aa 100644 --- a/pulsar-client-cpp/lib/MessageCrypto.cc +++ b/pulsar-client-cpp/lib/MessageCrypto.cc @@ -147,7 +147,7 @@ Result MessageCrypto::addPublicKeyCipher(std::set& keyNames, // Generate data key RAND_bytes(dataKey_.get(), dataKeyLen_); - if (LOG4CXX_UNLIKELY(logger()->isDebugEnabled())) { + if (PULSAR_UNLIKELY(logger()->isEnabled(Logger::DEBUG))) { std::string dataKeyStr(reinterpret_cast(dataKey_.get()), dataKeyLen_); std::string strHex = stringToHex(dataKeyStr, dataKeyStr.size()); LOG_DEBUG(logCtx_ << "Generated Data key " << strHex); @@ -203,7 +203,7 @@ Result MessageCrypto::addPublicKeyCipher(const std::string& keyName, const Crypt // Add a new entry or replace existing entry, if one is present. encryptedDataKeyMap_[keyName] = eki; - if (LOG4CXX_UNLIKELY(logger()->isDebugEnabled())) { + if (PULSAR_UNLIKELY(logger()->isEnabled(Logger::DEBUG))) { std::string strHex = stringToHex(encryptedKeyStr, encryptedKeyStr.size()); LOG_DEBUG(logCtx_ << " Data key encrypted for key " << keyName << ". Encrypted key size = " << encryptedKeyStr.size() << ", value = " << strHex); @@ -253,7 +253,7 @@ bool MessageCrypto::encrypt(std::set& encKeys, const CryptoKeyReade proto::EncryptionKeys* encKeys = proto::EncryptionKeys().New(); encKeys->set_key(keyName); encKeys->set_value(keyInfo->getKey()); - if (LOG4CXX_UNLIKELY(logger()->isDebugEnabled())) { + if (PULSAR_UNLIKELY(logger()->isEnabled(Logger::DEBUG))) { std::string strHex = stringToHex(keyInfo->getKey(), keyInfo->getKey().size()); LOG_DEBUG(logCtx_ << " Encrypted data key added for key " << keyName << ". Encrypted key size = " << keyInfo->getKey().size() << ", value = " << strHex); @@ -323,7 +323,7 @@ bool MessageCrypto::encrypt(std::set& encKeys, const CryptoKeyReade return false; } encryptedPayload.bytesWritten(tagLen_); - if (LOG4CXX_UNLIKELY(logger()->isDebugEnabled())) { + if (PULSAR_UNLIKELY(logger()->isEnabled(Logger::DEBUG))) { std::string strPayloadHex = stringToHex(payload.data(), payload.readableBytes()); std::string strHex = stringToHex(encryptedPayload.data(), encryptedPayload.readableBytes()); LOG_DEBUG(logCtx_ << " Original size = " << payload.readableBytes() << ", value = " << strPayloadHex @@ -376,7 +376,7 @@ bool MessageCrypto::decryptDataKey(const std::string& keyName, const std::string std::string keyDigestStr(reinterpret_cast(keyDigest), digestLen); std::string dataKeyStr(reinterpret_cast(dataKey_.get()), dataKeyLen_); dataKeyCache_[keyDigestStr] = make_pair(dataKeyStr, boost::posix_time::second_clock::universal_time()); - if (LOG4CXX_UNLIKELY(logger()->isDebugEnabled())) { + if (PULSAR_UNLIKELY(logger()->isEnabled(Logger::DEBUG))) { std::string strHex = stringToHex(dataKeyStr, dataKeyStr.size()); LOG_DEBUG(logCtx_ << "Data key for key " << keyName << " decrypted. Decrypted data key is " << strHex); @@ -395,7 +395,7 @@ bool MessageCrypto::decryptData(const std::string& dataKeySecret, const proto::M EVP_CIPHER_CTX* cipherCtx = NULL; decryptedPayload = SharedBuffer::allocate(payload.readableBytes() + EVP_MAX_BLOCK_LENGTH + tagLen_); - if (LOG4CXX_UNLIKELY(logger()->isDebugEnabled())) { + if (PULSAR_UNLIKELY(logger()->isEnabled(Logger::DEBUG))) { std::string strHex = stringToHex(payload.data(), payload.readableBytes()); LOG_DEBUG(logCtx_ << "Attempting to decrypt data with encrypted size " << payload.readableBytes() << ", data = " << strHex); @@ -443,7 +443,7 @@ bool MessageCrypto::decryptData(const std::string& dataKeySecret, const proto::M return false; } decryptedPayload.bytesWritten(decLen); - if (LOG4CXX_UNLIKELY(logger()->isDebugEnabled())) { + if (PULSAR_UNLIKELY(logger()->isEnabled(Logger::DEBUG))) { std::string strHex = stringToHex(decryptedPayload.data(), decryptedPayload.readableBytes()); LOG_DEBUG(logCtx_ << "Data decrypted. Decrypted size = " << decryptedPayload.readableBytes() << ", data = " << strHex); diff --git a/pulsar-client-cpp/lib/SimpleLoggerImpl.cc b/pulsar-client-cpp/lib/SimpleLoggerImpl.cc new file mode 100644 index 0000000000000..309eb33da1f63 --- /dev/null +++ b/pulsar-client-cpp/lib/SimpleLoggerImpl.cc @@ -0,0 +1,90 @@ +/** + * 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 "SimpleLoggerImpl.h" + +#include +#include +#include +#include + +namespace pulsar { + +inline std::ostream &operator<<(std::ostream &s, Logger::Level level) { + switch (level) { + case Logger::DEBUG: + s << "DEBUG"; + break; + case Logger::INFO: + s << "INFO "; + break; + case Logger::WARN: + s << "WARN "; + break; + case Logger::ERROR: + s << "ERROR"; + break; + } + + return s; +} + +class SimpleLogger : public Logger { + std::string _logger; + + public: + SimpleLogger(const std::string &logger) : _logger(logger) {} + + bool isEnabled(Level level) { return level >= Logger::INFO; } + + void log(Level level, int line, const std::string &message) { + std::stringstream ss; + + printTimestamp(ss); + ss << " " << level << " " << _logger << ":" << line << " | " << message << "\n"; + + std::cout << ss.str(); + std::cout.flush(); + } + + private: + static std::ostream &printTimestamp(std::ostream &s) { + boost::posix_time::ptime now = boost::posix_time::microsec_clock::local_time(); + + const boost::format f = + boost::format("%04d-%02d-%02d %02d:%02d:%02d.%03d") % now.date().year_month_day().year % + now.date().year_month_day().month.as_number() % now.date().year_month_day().day.as_number() % + now.time_of_day().hours() % now.time_of_day().minutes() % now.time_of_day().seconds() % + (now.time_of_day().fractional_seconds() / 1000); + + s << f.str(); + return s; + } +}; + +Logger *SimpleLoggerFactory::getLogger(const std::string &path) { + // Remove all directories from filename + int startIdx = path.find_last_of("/"); + int endIdx = path.find_last_of("."); + std::string fileName = path.substr(startIdx + 1, endIdx - startIdx - 1); + return new SimpleLogger(fileName); +} + +LoggerFactoryPtr SimpleLoggerFactory::create() { return LoggerFactoryPtr(new SimpleLoggerFactory); } +} // namespace pulsar diff --git a/pulsar-client-cpp/lib/SimpleLoggerImpl.h b/pulsar-client-cpp/lib/SimpleLoggerImpl.h new file mode 100644 index 0000000000000..2b81060c3303d --- /dev/null +++ b/pulsar-client-cpp/lib/SimpleLoggerImpl.h @@ -0,0 +1,33 @@ +/** + * 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. + */ + +#pragma once + +#include + +namespace pulsar { + +class SimpleLoggerFactory : public LoggerFactory { + public: + Logger* getLogger(const std::string& fileName); + + static LoggerFactoryPtr create(); +}; + +} // namespace pulsar \ No newline at end of file diff --git a/pulsar-client-cpp/lib/c/c_ClientConfiguration.cc b/pulsar-client-cpp/lib/c/c_ClientConfiguration.cc index 8caf8e87f1cea..6ceaf6b103762 100644 --- a/pulsar-client-cpp/lib/c/c_ClientConfiguration.cc +++ b/pulsar-client-cpp/lib/c/c_ClientConfiguration.cc @@ -69,13 +69,31 @@ int pulsar_client_configuration_get_concurrent_lookup_request(pulsar_client_conf return conf->conf.getConcurrentLookupRequest(); } -void pulsar_client_configuration_set_log_conf_file_path(pulsar_client_configuration_t *conf, - const char *logConfFilePath) { - conf->conf.setLogConfFilePath(logConfFilePath); -} +class PulsarCLogger : public pulsar::Logger { + std::string file_; + pulsar_logger logger_; + + public: + PulsarCLogger(const std::string &file, pulsar_logger logger) : file_(file), logger_(logger) {} + + bool isEnabled(Level level) { return level >= pulsar::Logger::INFO; } + + void log(Level level, int line, const std::string &message) { + logger_((pulsar_logger_level_t)level, file_.c_str(), line, message.c_str()); + } +}; + +class PulsarCLoggerFactory : public pulsar::LoggerFactory { + pulsar_logger logger_; + + public: + PulsarCLoggerFactory(pulsar_logger logger) : logger_(logger) {} + + pulsar::Logger *getLogger(const std::string &fileName) { return new PulsarCLogger(fileName, logger_); } +}; -const char *pulsar_client_configuration_get_log_conf_file_path(pulsar_client_configuration_t *conf) { - return conf->conf.getLogConfFilePath().c_str(); +void pulsar_client_configuration_set_logger(pulsar_client_configuration_t *conf, pulsar_logger logger) { + conf->conf.setLogger(pulsar::LoggerFactoryPtr(new PulsarCLoggerFactory(logger))); } void pulsar_client_configuration_set_use_tls(pulsar_client_configuration_t *conf, int useTls) { diff --git a/pulsar-client-cpp/perf/CMakeLists.txt b/pulsar-client-cpp/perf/CMakeLists.txt index b2988712ccaa5..b3c8dc8d10460 100644 --- a/pulsar-client-cpp/perf/CMakeLists.txt +++ b/pulsar-client-cpp/perf/CMakeLists.txt @@ -31,5 +31,5 @@ set(PERF_CONSUMER_SOURCES add_executable(perfProducer ${PERF_PRODUCER_SOURCES}) add_executable(perfConsumer ${PERF_CONSUMER_SOURCES}) -target_link_libraries(perfProducer ${CLIENT_LIBS}) -target_link_libraries(perfConsumer ${CLIENT_LIBS}) +target_link_libraries(perfProducer pulsarShared ${CLIENT_LIBS}) +target_link_libraries(perfConsumer pulsarShared ${CLIENT_LIBS}) diff --git a/pulsar-client-cpp/perf/PerfConsumer.cc b/pulsar-client-cpp/perf/PerfConsumer.cc index 337035ed2dc7b..a263c57f67733 100644 --- a/pulsar-client-cpp/perf/PerfConsumer.cc +++ b/pulsar-client-cpp/perf/PerfConsumer.cc @@ -237,8 +237,6 @@ void startPerfConsumer(const Arguments& args) { } int main(int argc, char** argv) { - LogUtils::init("conf/log4cxx.conf"); - // First try to read default values from config file if present const std::string confFile = "conf/client.conf"; std::string defaultServiceUrl; diff --git a/pulsar-client-cpp/perf/PerfProducer.cc b/pulsar-client-cpp/perf/PerfProducer.cc index d591d34299508..859d4bd3e1e04 100644 --- a/pulsar-client-cpp/perf/PerfProducer.cc +++ b/pulsar-client-cpp/perf/PerfProducer.cc @@ -30,6 +30,7 @@ DECLARE_LOG_OBJECT() #include #include #include +#include namespace po = boost::program_options; #include @@ -151,7 +152,7 @@ void runProducer(const Arguments& args, std::string topicName, int threadIndex, producer.sendAsync(msg, boost::bind(sendCallback, _1, _2, Clock::now())); boost::this_thread::interruption_point(); } - } catch(const boost::thread_interrupted&) { + } catch(const boost::thread_interrupted& e) { // Thread interruption request received, break the loop LOG_INFO("Thread interrupted. Exiting thread."); } @@ -187,8 +188,6 @@ void startPerfProducer(const Arguments& args, pulsar::ProducerConfiguration &pro } int main(int argc, char** argv) { - LogUtils::init("conf/log4cxx.conf"); - std::string defaultServiceUrl; // First try to read default values from config file if present @@ -305,6 +304,8 @@ int main(int argc, char** argv) { for (po::variables_map::iterator it = map.begin(); it != map.end(); ++it) { if (it->second.value().type() == typeid(std::string)) { LOG_INFO(it->first << ": " << it->second.as()); + } else if (it->second.value().type() == typeid(bool)) { + LOG_INFO(it->first << ": " << it->second.as()); } else if (it->second.value().type() == typeid(int)) { LOG_INFO(it->first << ": " << it->second.as()); } else if (it->second.value().type() == typeid(double)) { @@ -355,7 +356,8 @@ int main(int argc, char** argv) { Clock::time_point oldTime = Clock::now(); unsigned long totalMessagesProduced = 0; - while (args.numberOfSamples--) { + long messagesToSend = args.numberOfSamples; + while (args.numberOfSamples == 0 || --messagesToSend > 0) { std::this_thread::sleep_for(std::chrono::seconds(args.samplingPeriod)); Clock::time_point now = Clock::now(); diff --git a/pulsar-client-cpp/tests/main.cc b/pulsar-client-cpp/tests/main.cc index a600af3578d55..06599258f10da 100644 --- a/pulsar-client-cpp/tests/main.cc +++ b/pulsar-client-cpp/tests/main.cc @@ -20,7 +20,6 @@ #include int main(int argc, char **argv) { - LogUtils::init("log4cxx.conf"); ::testing::InitGoogleMock(&argc, argv); return RUN_ALL_TESTS(); }