merlimat closed pull request #1827: Added option for custom loggers in C++ and 
C APIs
URL: https://github.com/apache/incubator-pulsar/pull/1827
 
 
   

This is a PR merged from a forked repository.
As GitHub hides the original diff on merge, it is displayed below for
the sake of provenance:

As this is a foreign pull request (from a fork), the diff is supplied
below (as it won't show otherwise due to GitHub magic):

diff --git a/pulsar-client-cpp/CMakeLists.txt b/pulsar-client-cpp/CMakeLists.txt
index e5fd716d8e..38a47742ef 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 137d528ca2..eedf716240 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 <pulsar/Authentication.h>
+#include <pulsar/Logger.h>
+
 #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 0000000000..e319a04f0b
--- /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 <boost/shared_ptr.hpp>
+
+#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<LoggerFactory> 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 7725e7cca8..b04c21d03a 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 6f011e3b6d..246c7af932 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 4ea77cf92e..b5da7908ed 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 1390336cd7..80f947b607 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 <boost/bind.hpp>
 #include <boost/algorithm/string/predicate.hpp>
 #include <sstream>
@@ -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 0000000000..184c33652f
--- /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 <pulsar/Logger.h>
+
+#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 0000000000..99cc6144ca
--- /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 <iostream>
+
+#ifdef USE_LOG4CXX
+
+#include <log4cxx/logger.h>
+#include <log4cxx/logmanager.h>
+#include <log4cxx/consoleappender.h>
+#include <log4cxx/propertyconfigurator.h>
+#include <log4cxx/patternlayout.h>
+
+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 70507d94fc..219232702d 100644
--- a/pulsar-client-cpp/lib/LogUtils.cc
+++ b/pulsar-client-cpp/lib/LogUtils.cc
@@ -18,35 +18,34 @@
  */
 #include "LogUtils.h"
 
-#include <log4cxx/logger.h>
-#include <log4cxx/logmanager.h>
-#include <log4cxx/consoleappender.h>
-#include <log4cxx/propertyconfigurator.h>
-#include <log4cxx/patternlayout.h>
 #include <iostream>
 
-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 6371efed08..12a5b0696c 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 <boost/thread/tss.hpp>
-#include <log4cxx/logger.h>
 #include <string>
+#include <sstream>
 
-#define DECLARE_LOG_OBJECT()                                                   
                  \
-    static log4cxx::LoggerPtr& logger() {                                      
                  \
-        static boost::thread_specific_ptr<log4cxx::LoggerPtr> 
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 <pulsar/Logger.h>
+
+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<pulsar::Logger> 
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 4ea21b24e4..5dd9df1989 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 c5f41d8f27..0203660a88 100644
--- a/pulsar-client-cpp/lib/MessageCrypto.cc
+++ b/pulsar-client-cpp/lib/MessageCrypto.cc
@@ -147,7 +147,7 @@ Result 
MessageCrypto::addPublicKeyCipher(std::set<std::string>& 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<char*>(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<std::string>& 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<std::string>& 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<char*>(keyDigest), digestLen);
     std::string dataKeyStr(reinterpret_cast<char*>(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 0000000000..309eb33da1
--- /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 <iostream>
+#include <sstream>
+#include <boost/date_time/posix_time/posix_time.hpp>
+#include <boost/format.hpp>
+
+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 0000000000..2b81060c33
--- /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 <pulsar/Logger.h>
+
+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 8caf8e87f1..6ceaf6b103 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 b2988712cc..b3c8dc8d10 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 337035ed2d..a263c57f67 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 d591d34299..859d4bd3e1 100644
--- a/pulsar-client-cpp/perf/PerfProducer.cc
+++ b/pulsar-client-cpp/perf/PerfProducer.cc
@@ -30,6 +30,7 @@ DECLARE_LOG_OBJECT()
 #include <boost/accumulators/statistics/p_square_quantile.hpp>
 #include <boost/program_options/variables_map.hpp>
 #include <boost/program_options.hpp>
+#include <boost/thread.hpp>
 namespace po = boost::program_options;
 
 #include <iostream>
@@ -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<std::string>());
+        } else if (it->second.value().type() == typeid(bool)) {
+            LOG_INFO(it->first << ": " << it->second.as<bool>());
         } else if (it->second.value().type() == typeid(int)) {
             LOG_INFO(it->first << ": " << it->second.as<int>());
         } 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 a600af3578..06599258f1 100644
--- a/pulsar-client-cpp/tests/main.cc
+++ b/pulsar-client-cpp/tests/main.cc
@@ -20,7 +20,6 @@
 #include <gmock/gmock.h>
 
 int main(int argc, char **argv) {
-    LogUtils::init("log4cxx.conf");
     ::testing::InitGoogleMock(&argc, argv);
     return RUN_ALL_TESTS();
 }


 

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
us...@infra.apache.org


With regards,
Apache Git Services

Reply via email to