精华内容
下载资源
问答
  • linux日志打印.cpp

    2020-01-13 16:04:43
    linux系统下打印日志到文件中,包含当前时间,不限定日志内容和参数。用来调试软件,查看方便日志信息。
  • Cpp调用Log4cpp生成日志

    千次阅读 2017-09-29 19:03:26
    Log4cpp是一个开源的C++类库,它提供了在C++程序中使用日志和跟踪调试的功能。 官网地址: [访问](http://log4cpp.sourceforge.net/)初始化代码: log4cpp::PatternLayout* pLayout = new log4cpp::PatternLayout();...

    Log4cpp是一个开源的C++类库,它提供了在C++程序中使用日志和跟踪调试的功能。
    官网地址: 访问

    初始化代码:

    	log4cpp::PatternLayout* pLayout = new log4cpp::PatternLayout();
    	pLayout->setConversionPattern("%d: %p %c %x: %m%n");
    
    	log4cpp::Appender* fileAppender = new log4cpp::FileAppender("fileAppender","日志.log");
    	fileAppender->setLayout(pLayout);
    
    	log4cpp::Category& root = log4cpp::Category::getRoot().getInstance("日志类型");
    	root.addAppender(fileAppender);
    	root.setPriority(log4cpp::Priority::DEBUG);
    

    初始化布局, 文件适配器, 类型基本算设置完成, 可以使用了.

    直接使用类型实例的方法就可以按级别打印日志了.
    root.error 错误
    root.info 提示
    root.debug 调试

    在这里插入图片描述

    需要完整代码请访问 CPlusPlusExamples

    联系方式:


    作者郑天佐
    QQ278969898
    主页http://www.camelstudio.cn
    邮箱camelsoft@163.com
    博客http://blog.csdn.net/zhengtianzuo06
    githubhttps://github.com/zhengtianzuo
    QQ群199672080

    在这里插入图片描述

    觉得分享的内容还不错, 就请作者喝杯咖啡吧~~

    展开全文
  • Log4cpp输出日志到Kafka

    2019-04-25 19:00:18
    ELK很不错,但是公司原来都是使用Log4cpp,能不能在改动最小的情况下,将日志输出到ELK?当然没有问题,Logstash有可以从kafka输入,只需要实现日志输出到kafka,剩下的ELK配置好就ok!但是Log4cpp并没有提供kafka...

    最近的项目需要做一个生物识别的分布式比对服务,在机器集群上如何做日志汇总和分析?ELK很不错,但是公司原来都是使用Log4cpp,能不能在改动最小的情况下,将日志输出到ELK?当然没有问题,Logstash有可以从kafka输入,只需要实现日志输出到kafka,剩下的ELK配置好就ok!但是Log4cpp并没有提供kafka输出,自定义一个即可!



    1. 下载Log4cpp

    2. 编码

    只需两步:

    1. 添加KafkaAppender类,继承LayoutAppender
    2. 修改PropertyConfiguratorImpl配置类

    2.1 添加KafkaAppender实现

    2.1.1 添加KafkaAppender.hh

    将KafkaAppender.hh添加到include/log4cpp下
    后缀.hh是c++的头文件,为了和log4cpp统一而没用.h;.hh是为了区分c语言的.h头文件

    // include/log4cpp/KafkaAppender.hh
    #ifndef _LOG4CPP_KAFKAAPPENDER_HH
    #define _LOG4CPP_KAFKAAPPENDER_HH
    
    #include <log4cpp/Portability.hh>
    #include <log4cpp/LayoutAppender.hh>
    #include <string>
    #include <stdarg.h>
    #include <librdkafka/rdkafkacpp.h>
    #include <librdkafka/rdkafka.h>
    
    namespace log4cpp
    {
    
    // 数据异步发送结果回调
    class ExampleDeliveryReportCb : public RdKafka::DeliveryReportCb
    {
    public:
      void dr_cb(RdKafka::Message &message);
    };
    
    class LOG4CPP_EXPORT KafkaAppender : public LayoutAppender
    {
    public:
      KafkaAppender(const std::string &name, const std::string &brokers, const std::string &topic, int timeout);
      virtual ~KafkaAppender();
    
      virtual bool reopen();
      virtual void close();
    
    protected:
      virtual void _append(const LoggingEvent &event);
    
      const std::string _brokers;
      const std::string _topic;
      const int _timeout;
    
      RdKafka::Producer *_producer = nullptr;
    
      int32_t _partition = RdKafka::Topic::PARTITION_UA;
    
      ExampleDeliveryReportCb *ex_dr_cb = nullptr;
    };
    } // namespace log4cpp
    
    #endif
    

    2.1.2 添加KafkaAppender.cpp

    在src下添加KafkaAppender.cpp文件

    // src/KafkaAppender.cpp
    
    #include "PortabilityImpl.hh"
    #ifdef LOG4CPP_HAVE_IO_H
    #include <io.h>
    #endif
    #ifdef LOG4CPP_HAVE_UNISTD_H
    #include <unistd.h>
    #endif
    
    #include <memory>
    #include <stdio.h>
    #include <time.h>
    #include <log4cpp/KafkaAppender.hh>
    #include <log4cpp/Category.hh>
    #include <log4cpp/FactoryParams.hh>
    
    namespace log4cpp
    {
    // 数据异步发送结果回调
    void ExampleDeliveryReportCb::dr_cb(RdKafka::Message &message)
    {
        std::cout << "ExampleDeliveryReportCb dr_cb" << std::endl;
    
        std::string status_name;
        switch (message.status())
        {
        case RdKafka::Message::MSG_STATUS_NOT_PERSISTED:
            status_name = "NotPersisted";
            break;
        case RdKafka::Message::MSG_STATUS_POSSIBLY_PERSISTED:
            status_name = "PossiblyPersisted";
            break;
        case RdKafka::Message::MSG_STATUS_PERSISTED:
            status_name = "Persisted";
            break;
        default:
            status_name = "Unknown?";
            break;
        }
        std::cout << "Message delivery for (" << message.len() << " bytes): " << status_name << ": " << message.errstr() << std::endl;
        if (message.key())
            std::cout << "Key: " << *(message.key()) << ";" << std::endl;
    }
    
    KafkaAppender::KafkaAppender(const std::string &name, const std::string &brokers, const std::string &topic, int timeout)
        : LayoutAppender(name), _brokers(brokers), _topic(topic), _timeout(timeout)
    {
    
        std::cout << "kafka appender name : " << name << ", brokers : " << brokers << ",topic " << _topic << ",timeout " << _timeout << std::endl;
    
        // 连接kafka
    
        std::string errstr;
        int64_t start_offset = RdKafka::Topic::OFFSET_BEGINNING;
    
        /*
       * Create configuration objects
       */
        RdKafka::Conf *conf = RdKafka::Conf::create(RdKafka::Conf::CONF_GLOBAL);
        RdKafka::Conf *tconf = RdKafka::Conf::create(RdKafka::Conf::CONF_TOPIC);
    
        // 设置brokers
        conf->set("metadata.broker.list", brokers, errstr);
    
        /* Set delivery report callback 异步数据发送结果回调 */
        ex_dr_cb = new ExampleDeliveryReportCb;
        conf->set("dr_cb", ex_dr_cb, errstr);
    
        // 设置topic
        conf->set("default_topic_conf", tconf, errstr);
    
        // 创建producer
        _producer = RdKafka::Producer::create(conf, errstr);
    
        if (!_producer)
        {
            std::cerr << "Failed to create producer: " << errstr << std::endl;
            exit(1);
        }
    }
    KafkaAppender::~KafkaAppender()
    {
        // 析构,释放kafka
        close();
    }
    
    bool KafkaAppender::reopen()
    {
        // 重新打开kafka
    }
    
    void KafkaAppender::close()
    {
        // 关闭kafka连接
    
        while (_producer->outq_len() > 0)
        {
            std::cerr << "Waiting for " << _producer->outq_len() << std::endl;
            _producer->poll(1000);
        }
    
        delete _producer;
        _producer = nullptr;
    
        RdKafka::wait_destroyed(5000);
    
        delete ex_dr_cb;
        ex_dr_cb = nullptr;
    }
    
    void KafkaAppender::_append(const LoggingEvent &event)
    {
        std::string message(_getLayout().format(event));
    
        std::cout << "kafka appender " << message << std::endl;
        // 写入kafka
    
        RdKafka::Headers *headers = RdKafka::Headers::create();
        headers->add("my header", "header value");
        headers->add("other header", "yes");
    
        RdKafka::ErrorCode resp =
            _producer->produce(_topic, _partition,
                               RdKafka::Producer::RK_MSG_COPY /* Copy payload */,
                               /* Value */
                               const_cast<char *>(message.c_str()), message.size(),
                               /* Key */
                               NULL, 0,
                               /* Timestamp (defaults to now) */
                               0,
                               /* Message headers, if any */
                               headers,
                               /* Per-message opaque value passed to
                               * delivery report */
                               NULL);
    
        if (resp != RdKafka::ERR_NO_ERROR)
        {
            std::cerr << "% Produce failed: " << RdKafka::err2str(resp) << std::endl;
            delete headers; /* Headers are automatically deleted on produce()
                             * success. */
        }
        else
        {
            std::cerr << "% Produced message (" << message.size() << " bytes)" << std::endl;
        }
    
        _producer->poll(_timeout);
    }
    
    } // namespace log4cpp
    
    

    2.2 修改PropertyConfiguratorImpl.cpp,添加Kafka配置

    添加kafka配置,修改PropertyConfiguratorImpl.cpp

    /*
     * PropertyConfiguratorImpl.cpp
     *
     * Copyright 2002, Log4cpp Project. All rights reserved.
     *
     * See the COPYING file for the terms of usage and distribution.
     */
    #include "PortabilityImpl.hh"
    
    #ifdef LOG4CPP_HAVE_UNISTD_H
    #include <unistd.h>
    #endif
    #ifdef LOG4CPP_HAVE_IO_H
    #include <io.h>
    #endif
    #include <iostream>
    
    #include <string>
    #include <fstream>
    
    #include <log4cpp/Category.hh>
    
    // appenders
    #include <log4cpp/Appender.hh>
    #include <log4cpp/OstreamAppender.hh>
    #include <log4cpp/FileAppender.hh>
    #include <log4cpp/RollingFileAppender.hh>
    #include <log4cpp/DailyRollingFileAppender.hh>
    #include <log4cpp/AbortAppender.hh>
    #include <log4cpp/KafkaAppender.hh>
    #ifdef WIN32
    #include <log4cpp/Win32DebugAppender.hh>
    #include <log4cpp/NTEventLogAppender.hh>
    #endif
    #ifndef LOG4CPP_DISABLE_REMOTE_SYSLOG
    #include <log4cpp/RemoteSyslogAppender.hh>
    #endif // LOG4CPP_DISABLE_REMOTE_SYSLOG
    #ifdef LOG4CPP_HAVE_LIBIDSA
    #include <log4cpp/IdsaAppender.hh>
    #endif // LOG4CPP_HAVE_LIBIDSA
    #ifdef LOG4CPP_HAVE_SYSLOG
    #include <log4cpp/SyslogAppender.hh>
    #endif
    
    // layouts
    #include <log4cpp/Layout.hh>
    #include <log4cpp/BasicLayout.hh>
    #include <log4cpp/SimpleLayout.hh>
    #include <log4cpp/PatternLayout.hh>
    
    #include <log4cpp/Priority.hh>
    #include <log4cpp/NDC.hh>
    
    #include <list>
    #include <vector>
    #include <iterator>
    #include <algorithm>
    
    #include "PropertyConfiguratorImpl.hh"
    #include "StringUtil.hh"
    
    namespace log4cpp
    {
    
    PropertyConfiguratorImpl::PropertyConfiguratorImpl()
    {
    }
    
    PropertyConfiguratorImpl::~PropertyConfiguratorImpl()
    {
    }
    
    // 根据配置文件配置log4cpp
    void PropertyConfiguratorImpl::doConfigure(const std::string &initFileName)
    {
        std::ifstream initFile(initFileName.c_str());
    
        if (!initFile)
        {
            throw ConfigureFailure(std::string("File ") + initFileName + " does not exist");
        }
    
        doConfigure(initFile);
    }
    
    // 使用输入流配置log4cpp
    void PropertyConfiguratorImpl::doConfigure(std::istream &in)
    {
        // parse the file to get all of the configuration
    
        // 解析配置
        _properties.load(in);
    
        instantiateAllAppenders();
        // get categories
        std::vector<std::string> catList;
        getCategories(catList);
    
        // configure each category
        for (std::vector<std::string>::const_iterator iter = catList.begin();
             iter != catList.end(); ++iter)
        {
            configureCategory(*iter);
        }
    }
    
    // 初始化全部appender
    void PropertyConfiguratorImpl::instantiateAllAppenders()
    {
        std::string currentAppender;
    
        std::string prefix("appender");
        Properties::const_iterator from = _properties.lower_bound(prefix + '.');
        Properties::const_iterator to = _properties.lower_bound(prefix + '/');
    
        for (Properties::const_iterator i = from; i != to; ++i)
        {
            const std::string &key = (*i).first;
            const std::string &value = (*i).second;
            std::list<std::string> propNameParts;
            std::back_insert_iterator<std::list<std::string>> pnpIt(propNameParts);
            StringUtil::split(pnpIt, key, '.');
            std::list<std::string>::const_iterator i2 = propNameParts.begin();
            std::list<std::string>::const_iterator iEnd = propNameParts.end();
            if (++i2 == iEnd)
            {
                throw ConfigureFailure(std::string("missing appender name"));
            }
    
            const std::string appenderName = *i2++;
    
            /* WARNING, approaching lame code section:
                   skipping of the Appenders properties only to get them 
                   again in instantiateAppender.
                */
            if (appenderName == currentAppender)
            {
                // simply skip properties for the current appender
            }
            else
            {
                if (i2 == iEnd)
                {
                    // a new appender
                    currentAppender = appenderName;
                    _allAppenders[currentAppender] =
                        instantiateAppender(currentAppender);
                }
                else
                {
                    throw ConfigureFailure(std::string("partial appender definition : ") + key);
                }
            }
        }
    }
    
    // 配置category
    void PropertyConfiguratorImpl::configureCategory(const std::string &categoryName)
    {
        // start by reading the "rootCategory" key
        std::string tempCatName =
            (categoryName == "rootCategory") ? categoryName : "category." + categoryName;
    
        Properties::iterator iter = _properties.find(tempCatName);
    
        if (iter == _properties.end())
            throw ConfigureFailure(std::string("Unable to find category: ") + tempCatName);
    
        // need to get the root instance of the category
        Category &category = (categoryName == "rootCategory") ? Category::getRoot() : Category::getInstance(categoryName);
    
        std::list<std::string> tokens;
        std::back_insert_iterator<std::list<std::string>> tokIt(tokens);
        StringUtil::split(tokIt, (*iter).second, ',');
        std::list<std::string>::const_iterator i = tokens.begin();
        std::list<std::string>::const_iterator iEnd = tokens.end();
    
        Priority::Value priority = Priority::NOTSET;
        if (i != iEnd)
        {
            std::string priorityName = StringUtil::trim(*i++);
            try
            {
                if (priorityName != "")
                {
                    priority = Priority::getPriorityValue(priorityName);
                }
            }
            catch (std::invalid_argument &e)
            {
                throw ConfigureFailure(std::string(e.what()) +
                                       " for category '" + categoryName + "'");
            }
        }
    
        try
        {
            category.setPriority(priority);
        }
        catch (std::invalid_argument &e)
        {
            throw ConfigureFailure(std::string(e.what()) +
                                   " for category '" + categoryName + "'");
        }
    
        bool additive = _properties.getBool("additivity." + categoryName, true);
        category.setAdditivity(additive);
    
        category.removeAllAppenders();
        for (/**/; i != iEnd; ++i)
        {
            std::string appenderName = StringUtil::trim(*i);
            AppenderMap::const_iterator appIt =
                _allAppenders.find(appenderName);
            if (appIt == _allAppenders.end())
            {
                // appender not found;
                throw ConfigureFailure(std::string("Appender '") +
                                       appenderName + "' not found for category '" + categoryName + "'");
            }
            else
            {
                /* pass by reference, i.e. don't transfer ownership
                     */
                category.addAppender(*((*appIt).second));
            }
        }
    }
    
    Appender *PropertyConfiguratorImpl::instantiateAppender(const std::string &appenderName)
    {
        Appender *appender = NULL;
        std::string appenderPrefix = std::string("appender.") + appenderName;
    
        // determine the type by the appenderName
        Properties::iterator key = _properties.find(appenderPrefix);
        if (key == _properties.end())
            throw ConfigureFailure(std::string("Appender '") + appenderName + "' not defined");
    
        std::string::size_type length = (*key).second.find_last_of(".");
        std::string appenderType = (length == std::string::npos) ? (*key).second : (*key).second.substr(length + 1);
    
        // and instantiate the appropriate object  ConsoleAppender使用OstreamAppender
        if (appenderType == "ConsoleAppender")
        {
            std::string target = _properties.getString(appenderPrefix + ".target", "stdout");
            std::transform(target.begin(), target.end(), target.begin(), ::tolower);
            if (target.compare("stdout") == 0)
            {
                appender = new OstreamAppender(appenderName, &std::cout);
            }
            else if (target.compare("stderr") == 0)
            {
                appender = new OstreamAppender(appenderName, &std::cerr);
            }
            else
            {
                throw ConfigureFailure(appenderName + "' has invalid target '" + target + "'");
            }
        }
        else if (appenderType == "FileAppender")
        {
            std::string fileName = _properties.getString(appenderPrefix + ".fileName", "foobar");
            bool append = _properties.getBool(appenderPrefix + ".append", true);
            appender = new FileAppender(appenderName, fileName, append);
        }
        else if (appenderType == "RollingFileAppender")
        {
            std::string fileName = _properties.getString(appenderPrefix + ".fileName", "foobar");
            size_t maxFileSize = _properties.getInt(appenderPrefix + ".maxFileSize", 10 * 1024 * 1024);
            int maxBackupIndex = _properties.getInt(appenderPrefix + ".maxBackupIndex", 1);
            bool append = _properties.getBool(appenderPrefix + ".append", true);
            appender = new RollingFileAppender(appenderName, fileName, maxFileSize, maxBackupIndex,
                                               append);
        }
        else if (appenderType == "DailyRollingFileAppender")
        {
            std::string fileName = _properties.getString(appenderPrefix + ".fileName", "foobar");
            unsigned int maxDaysKeep = _properties.getInt(appenderPrefix + ".maxDaysKeep", 0);
            bool append = _properties.getBool(appenderPrefix + ".append", true);
            appender = new DailyRollingFileAppender(appenderName, fileName, maxDaysKeep, append);
        }
        else if (appenderType == "KafkaAppender")
        {
        	// 配置输入参数brokers、topic、timeout
            std::string brokers = _properties.getString(appenderPrefix + ".brokers", "localhost:9092");
            std::string topic = _properties.getString(appenderPrefix + ".topic", "log4cpp_kafka");
            unsigned int timeout = _properties.getInt(appenderPrefix + ".timeout", 0);
            // bool append = _properties.getBool(appenderPrefix + ".append", true);
            appender = new KafkaAppender(appenderName, brokers, topic, timeout);
        }
    #ifndef LOG4CPP_DISABLE_REMOTE_SYSLOG
        else if (appenderType == "SyslogAppender")
        {
            std::string syslogName = _properties.getString(appenderPrefix + ".syslogName", "syslog");
            std::string syslogHost = _properties.getString(appenderPrefix + ".syslogHost", "localhost");
            int facility = _properties.getInt(appenderPrefix + ".facility", -1) * 8; // * 8 to get LOG_KERN, etc. compatible values.
            int portNumber = _properties.getInt(appenderPrefix + ".portNumber", -1);
            appender = new RemoteSyslogAppender(appenderName, syslogName,
                                                syslogHost, facility, portNumber);
        }
    #endif // LOG4CPP_DISABLE_REMOTE_SYSLOG
    #ifdef LOG4CPP_HAVE_SYSLOG
        else if (appenderType == "LocalSyslogAppender")
        {
            std::string syslogName = _properties.getString(appenderPrefix + ".syslogName", "syslog");
            int facility = _properties.getInt(appenderPrefix + ".facility", -1) * 8; // * 8 to get LOG_KERN, etc. compatible values.
            appender = new SyslogAppender(appenderName, syslogName, facility);
        }
    #endif // LOG4CPP_HAVE_SYSLOG
        else if (appenderType == "AbortAppender")
        {
            appender = new AbortAppender(appenderName);
        }
    #ifdef LOG4CPP_HAVE_LIBIDSA
        else if (appenderType == "IdsaAppender")
        {
            // default idsa name ???
            std::string idsaName = _properties.getString(appenderPrefix + ".idsaName", "foobar");
    
            appender = new IdsaAppender(appenderName, idsaname);
        }
    #endif // LOG4CPP_HAVE_LIBIDSA
    
    #ifdef WIN32
        // win32 debug appender
        else if (appenderType == "Win32DebugAppender")
        {
            appender = new Win32DebugAppender(appenderName);
        }
        // win32 NT event log appender
        else if (appenderType == "NTEventLogAppender")
        {
            std::string source = _properties.getString(appenderPrefix + ".source", "foobar");
            appender = new NTEventLogAppender(appenderName, source);
        }
    #endif // WIN32
        else
        {
            throw ConfigureFailure(std::string("Appender '") + appenderName +
                                   "' has unknown type '" + appenderType + "'");
        }
    
        if (appender->requiresLayout())
        {
            setLayout(appender, appenderName);
        }
    
        // set threshold
        std::string thresholdName = _properties.getString(appenderPrefix + ".threshold", "");
        try
        {
            if (thresholdName != "")
            {
                appender->setThreshold(Priority::getPriorityValue(thresholdName));
            }
        }
        catch (std::invalid_argument &e)
        {
            delete appender; // fix for #3109495
            throw ConfigureFailure(std::string(e.what()) +
                                   " for threshold of appender '" + appenderName + "'");
        }
    
        return appender;
    }
    
    void PropertyConfiguratorImpl::setLayout(Appender *appender, const std::string &appenderName)
    {
        // determine the type by appenderName
        std::string tempString;
        Properties::iterator key =
            _properties.find(std::string("appender.") + appenderName + ".layout");
    
        if (key == _properties.end())
            throw ConfigureFailure(std::string("Missing layout property for appender '") +
                                   appenderName + "'");
    
        std::string::size_type length = (*key).second.find_last_of(".");
        std::string layoutType = (length == std::string::npos) ? (*key).second : (*key).second.substr(length + 1);
    
        Layout *layout;
        // and instantiate the appropriate object
        if (layoutType == "BasicLayout")
        {
            layout = new BasicLayout();
        }
        else if (layoutType == "SimpleLayout")
        {
            layout = new SimpleLayout();
        }
        else if (layoutType == "PatternLayout")
        {
            // need to read the properties to configure this one
            PatternLayout *patternLayout = new PatternLayout();
    
            key = _properties.find(std::string("appender.") + appenderName + ".layout.ConversionPattern");
            if (key == _properties.end())
            {
                // leave default pattern
            }
            else
            {
                // set pattern
                patternLayout->setConversionPattern((*key).second);
            }
    
            layout = patternLayout;
        }
        else
        {
            throw ConfigureFailure(std::string("Unknown layout type '" + layoutType +
                                               "' for appender '") +
                                   appenderName + "'");
        }
    
        appender->setLayout(layout);
    }
    
    /**
         * Get the categories contained within the map of properties.  Since
         * the category looks something like "category.xxxxx.yyy.zzz", we need
         * to search the entire map to figure out which properties are category
         * listings.  Seems like there might be a more elegant solution.
         */
    void PropertyConfiguratorImpl::getCategories(std::vector<std::string> &categories) const
    {
        categories.clear();
    
        // add the root category first
        categories.push_back(std::string("rootCategory"));
    
        // then look for "category."
        std::string prefix("category");
        Properties::const_iterator from = _properties.lower_bound(prefix + '.');
        Properties::const_iterator to = _properties.lower_bound(prefix + (char)('.' + 1));
        for (Properties::const_iterator iter = from; iter != to; iter++)
        {
            categories.push_back((*iter).first.substr(prefix.size() + 1));
        }
    }
    } // namespace log4cpp
    
    

    3. 编译

    1. CMakeLists.txt 添加src/KafkaAppender.c
    #
    # Nicholas Yue nicholas_yue@users.sourceforge.net
    #
    # Note:
    # (1) A dummy file include/config.h is required (remance from configure)
    # (2) Default installation directory is /usr/local, override with -DCMAKE_INSTALL_PREFIX="" during cmake
    #     invocation
    # (3) Do the usual "make clean all" to build the library
    # (4) To install either "make install" or "make install DESTDIR=<your directory>"
    # (5) Need to include changes in include/log4cpp/Portability.hh for OSX to build
    
    cmake_minimum_required (VERSION 2.8)
    
    PROJECT ( LOG4CPP )
    
    INCLUDE_DIRECTORIES ( include )
    INCLUDE_DIRECTORIES ( . )
    
    IF (WIN32)
      ADD_DEFINITIONS ( -D_CRT_SECURE_NO_WARNINGS )
    ELSE (WIN32)
      IF (APPLE)
        ADD_DEFINITIONS ( -DNDEBUG -DLOG4CPP_HAVE_SSTREAM )
      ELSE (APPLE)
        ADD_DEFINITIONS ( -pthread -DNDEBUG -DLOG4CPP_HAVE_SSTREAM )
      ENDIF (APPLE)
    ENDIF (WIN32)
    
    IF ( CMAKE_BUILD_TYPE MATCHES "Debug" )
      SET ( LOG4CPP_LIBRARY_NAME "log4cppD" )
    ELSE ( CMAKE_BUILD_TYPE MATCHES "Debug" )
      SET ( LOG4CPP_LIBRARY_NAME "log4cpp" )
    ENDIF ( CMAKE_BUILD_TYPE MATCHES "Debug" )
    
    ADD_LIBRARY ( ${LOG4CPP_LIBRARY_NAME}
      src/Appender.cpp
      src/AppenderSkeleton.cpp
      src/AppendersFactory.cpp
      src/BufferingAppender.cpp
      src/FactoryParams.cpp
      src/LayoutsFactory.cpp
      src/LevelEvaluator.cpp
      src/Localtime.cpp
      src/PassThroughLayout.cpp
      src/TriggeringEventEvaluatorFactory.cpp
      src/LayoutAppender.cpp
      src/FileAppender.cpp
      src/DailyRollingFileAppender.cpp
      src/RollingFileAppender.cpp
      src/FixedContextCategory.cpp
      src/IdsaAppender.cpp
      src/OstreamAppender.cpp
      src/StringQueueAppender.cpp
      src/SyslogAppender.cpp
      src/RemoteSyslogAppender.cpp
      src/KafkaAppender.cpp
      src/SimpleLayout.cpp
      src/BasicLayout.cpp
      src/PatternLayout.cpp
      src/Category.cpp
      src/CategoryStream.cpp
      src/HierarchyMaintainer.cpp
      src/Configurator.cpp
      src/BasicConfigurator.cpp
      src/SimpleConfigurator.cpp
      src/PropertyConfigurator.cpp
      src/PropertyConfiguratorImpl.cpp
      src/LoggingEvent.cpp
      src/Priority.cpp
      src/NDC.cpp
      src/Filter.cpp
      src/TimeStamp.cpp
      src/StringUtil.cpp
      src/Properties.cpp
      src/Win32DebugAppender.cpp
      src/NTEventLogAppender.cpp
      src/DllMain.cpp
      src/DummyThreads.cpp
      src/MSThreads.cpp
      src/OmniThreads.cpp
      src/PThreads.cpp
      src/PortabilityImpl.cpp
      src/AbortAppender.cpp
    )
    
    IF (WIN32)
      TARGET_LINK_LIBRARIES (${LOG4CPP_LIBRARY_NAME} kernel32 user32 ws2_32 advapi32 )
      SET_TARGET_PROPERTIES(${LOG4CPP_LIBRARY_NAME} PROPERTIES LINK_FLAGS /NODEFAULTLIB:msvcrt )
    ENDIF (WIN32)
    
    
    TARGET_LINK_LIBRARIES(${LOG4CPP_LIBRARY_NAME} rdkafka++)
    
    INSTALL (
      DIRECTORY include/log4cpp
      DESTINATION include
      PATTERN "config.h" EXCLUDE
      PATTERN ".svn" EXCLUDE
      PATTERN "*.am" EXCLUDE
      PATTERN "*.in" EXCLUDE
      )
    
    INSTALL (
      TARGETS ${LOG4CPP_LIBRARY_NAME}
      ARCHIVE DESTINATION lib
      )
    
    
    1. 生成config.h文件
    ./configure
    
    1. 编译
    make
    
    1. 安装
    sudo make install
    

    4. 测试

    在tests文件夹下有很多个测试文件,我们用testPropertyConfig.cpp来测试,只需要修改testConfig.log4cpp.properties配置文件即可:

    # a simple test config
    
    # log4j和log4cpp及其之前的数据都会被忽略,以${}引用环境变量和之前的kv值
    
    log4j.rootCategory=DEBUG, rootAppender
    log4j.category.sub1=,A1
    log4j.category.sub2=INFO
    log4j.category.sub1.sub2=ERROR, A2
    log4j.category.sub1.sub2.sub3=INFO, A4, A5, A6, A7, A8
    
    log4j.additivity.sub1.sub2=false
    log4j.additivity.sub1.sub2.sub3=false
    
    # 设置为KafkaAppender,设置brokers、topic、timeout
    log4j.appender.rootAppender=org.apache.log4j.KafkaAppender
    log4j.appender.rootAppender.brokers=localhost:9092
    log4j.appender.rootAppender.topic=pt
    log4j.appender.rootAppender.timeout=0
    log4j.appender.rootAppender.layout=org.apache.log4j.BasicLayout
    
    log4j.appender.A1=org.apache.log4j.AbortAppender
    log4j.appender.A1.fileName=A1.log
    log4j.appender.A1.layout=org.apache.log4j.SimpleLayout
    
    log4j.appender.A2=org.apache.log4j.ConsoleAppender
    log4j.appender.A2.layout=org.apache.log4j.PatternLayout
    log4j.appender.A2.layout.ConversionPattern=The message '%m' at time %d thread %t%n
    
    # tests for looong strings within the config file  
    log4cpp.appender.A4=RollingFileAppender
    log4cpp.appender.A4.fileName=A4.log
    log4cpp.appender.A4.maxFileSize=10240
    log4cpp.appender.A4.maxBackupIndex=1
    log4cpp.appender.A4.layout=PatternLayout
    log4cpp.appender.A4.layout.ConversionPattern=The message %m at time %d{%H:%M} thread %t %n is going to be very looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong%n
    
    log4cpp.appender.A5=RollingFileAppender
    log4cpp.appender.A5.fileName=A4.log
    log4cpp.appender.A5.maxFileSize=10240
    log4cpp.appender.A5.maxBackupIndex=1
    log4cpp.appender.A5.layout=PatternLayout
    log4cpp.appender.A5.layout.ConversionPattern=The message %m at time %d{%H:%M} thread %t %n is going to be very looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooongg%n
    
    log4cpp.appender.A6=RollingFileAppender
    log4cpp.appender.A6.fileName=A4.log
    log4cpp.appender.A6.maxFileSize=10240
    log4cpp.appender.A6.maxBackupIndex=1
    log4cpp.appender.A6.layout=PatternLayout
    log4cpp.appender.A6.layout.ConversionPattern=The message %m at time %d{%H:%M} thread %t %n is going to be very loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooonggg%n
    
    log4cpp.appender.A7=RollingFileAppender
    log4cpp.appender.A7.fileName=A4.log
    log4cpp.appender.A7.maxFileSize=10240
    log4cpp.appender.A7.maxBackupIndex=1
    log4cpp.appender.A7.layout=PatternLayout
    log4cpp.appender.A7.layout.ConversionPattern=The message %m at time %d{%H:%M}%n is going to be very loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooongggeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeer%n
    
    log4cpp.appender.A8=RollingFileAppender
    log4cpp.appender.A8.fileName=A4.log
    log4cpp.appender.A8.maxFileSize=10240
    log4cpp.appender.A8.maxBackupIndex=1
    log4cpp.appender.A8.layout=PatternLayout
    log4cpp.appender.A8.layout.ConversionPattern=The message %m at time %d{%H:%M}%n is going to be very loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooongggeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeer%n
    
    

    编译程序:

    注意:需将/usr/local/lib添加至LD_LIBRARY_PATH环境变量

    g++ testPropertyConfig.cpp -I../src  -I../include -o testPropertyConfig -llog4cpp -lpthread -lrdkafka++
    

    运行:

    ./testPropertyConfig
    

    ok!需要查看结果可使用kafka的工具查看。

    全部代码:https://github.com/BuildSoftwareBetter/Log4cpp-kafka

    展开全文
  • 实例化一个PatternLayout对象 log4cpp::PatternLayout* pLayout = new log4cpp::PatternLayout(); // 2. 实例化一个RollingFileAppender对象 log4cpp::RollingFileAppender* rollingAppender = new log4cpp::...

    // 1. 实例化一个PatternLayout对象
    log4cpp::PatternLayout* pLayout = new log4cpp::PatternLayout();
    // 2. 实例化一个RollingFileAppender对象
    log4cpp::RollingFileAppender* rollingAppender = new log4cpp::RollingFileAppender("RollingFileAppender",path);
    pLayout->setConversionPattern("%d:[%t][%05p] %c %x- %m%n");
    // 3. 把pLayout对象附着在rollingAppender对象上   
    rollingAppender->setLayout(pLayout);
    // 4. 实例化一个category对象
    log4cpp::Category& logcat = log4cpp::Category::getInstance(CATRGORY_NAME);
    // 5. 设置additivity为false,替换已有的appender
    logcat.setAdditivity(false);
    // 5. 把appender对象附到category上
    logcat.setAppender(rollingAppender);
    // 6. 设置category的优先级,低于此优先级的日志不被记录
    switch (level)
    {
    case DebugLevel:
        logcat.setPriority(log4cpp::Priority::DEBUG);
        break;
    case InfoLevel:
        logcat.setPriority(log4cpp::Priority::INFO);
        break;
    case WarnLevel:
        logcat.setPriority(log4cpp::Priority::WARN);
        break;
    case ErrLevel:
        logcat.setPriority(log4cpp::Priority::ERROR);
        break;
    default:
        logcat.setPriority(log4cpp::Priority::INFO);
        break;
    }

    // 记录开始日志
    logcat.alert("-------------Init-------------");

    转载于:https://www.cnblogs.com/monkeyfeng/p/4638459.html

    展开全文
  • log4cpp日志无法分卷的解决方案

    千次阅读 2014-09-28 15:20:15
    我们的项目采用log4cpp作为日志输出模块,但在使用中发现,如果是一个Services,或者是在Windows Server版本上,会出现日志无法正常分割的现象。即日志一直往一个文件里持续写,即使超过规定的文件大小,也不会分卷。
    

    我们的项目采用log4cpp作为日志输出模块,但在使用中发现,如果是一个Services,或者是在Windows Server版本上,会出现日志无法正常分割的现象。即日志一直往一个文件里持续写,即使超过规定的文件大小,也不会分卷。

    log4cpp中分割日志的核心算法为:(假设允许的最大文件个数为4)
    1.关闭xxx.log.
    2.删除 xxx.log.4
    3.是一个loop, 将xxx.log.3--->xxx.log.4,xxx.log.2--->xxx.log.3,xxx.log.1----->xxx.log.2
    4.将xxx.log--->xxx.log.1
    5.打开xxx.log.

    相关代码为:  

    void RollingFileAppender::rollOver() {  
          ::close(_fd); // 1  
          if (_maxBackupIndex > 0) {  
               std::ostringstream oldName;  
               oldName << _fileName << "." << _maxBackupIndex << std::ends;  
               ::remove(oldName.str().c_str());   //2  
      
               size_t n = _fileName.length() + 1;  
               for(unsigned int i = _maxBackupIndex; i > 1; i--) {  //3  
                     std::string newName = oldName.str();  
                     oldName.seekp(n);  
                     oldName << i-1 << std::ends;  
                     ::rename(oldName.str().c_str(), newName.c_str());   
                }  
      
               ::rename(_fileName.c_str(), oldName.str().c_str()); //4  
          }  
          _fd = ::open(_fileName.c_str(), _flags, _mode);//5  
    }  
    

    日志文件无法分割(目前发现只在win server版本无法work),原因出在步骤1,4,5上,
    关闭文件后,随后将文件重命名,会导致重命名失败。通过打印错误码得知,错误码为32,意思为:文件句柄被占用。
    解决方案为,往两个不同的文件里中写日志,不再只往一个文件名里写日志,交替写日志,交替关闭文件。write(A),close(B)---->Write(B),Close(A),----->Write(A),Close(B).
    修改后的代码为:

    void RollingFileAppender::rollOver() {  
            ::close(_fd);  
            if (_maxBackupIndex > 0) {  
                std::ostringstream oldName;  
                oldName << _fileName << "." << _maxBackupIndex << std::ends;  
                ::remove(oldName.str().c_str());  
                size_t n = _fileName.length() + 1;  
                for(unsigned int i = _maxBackupIndex; i > 1; i--) {  
                    std::string newName = oldName.str();  
                    oldName.seekp(n);  
      
                    oldName << i-1 << std::ends;  
                    ::rename(oldName.str().c_str(), newName.c_str());  
                }  
    if(_bUsingTempFile)  
                ::rename(_fileNameTmp.c_str(), oldName.str().c_str());  
    else  
                ::rename(_fileName.c_str(), oldName.str().c_str());  
            }  
    if(_bUsingTempFile)  
            _fd = ::open(_fileName.c_str(), _flags, _mode);  
    else  
            _fd = ::open(_fileNameTmp.c_str(), _flags, _mode);  
            _bUsingTempFile = !_bUsingTempFile;  
        }  
    展开全文
  • log4cpp 日志库的使用

    2021-01-19 20:14:44
    平时调试c++、c程序和记录一些程序打印信息时,使用的最多的就是printf,但是终端显示有限,而且不利于统计,所以想把开源的日志库加入到工程中;测试对比了一些日志库,发现log4cpp比较适合我们的工程。 1)可以...
  • Log4cpp C++ 中的日志管理,有Log4cpp的源代码工程以已经编译好的lib文件和DLL文件等可直接加载使用
  • C++打印日志输出文件

    万次阅读 2016-08-06 10:51:38
    做后台服务程序很多情况下都需要打印日志输出,我这里有简单的C++使用的打印日志输出文件可以直接复制粘贴使用,很方便,直接贴代码了。#ifndef NETDATALOG_H #define NETDATALOG_H #include #include #include #...
  • cpp 文件打印LOG

    千次阅读 2015-08-28 09:57:42
    1、android.mk LOCAL_LDLIBS:= -llog LOCAL_SHARED_LIBRARIES := liblog libcutils ...2、CPP文件 #include #define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__) #define LOGI(.
  • 我们的项目用途log4cpp由于日志输出模块,但在使用中发现,假设Services,或者是在Windows Server版本号。不会有一个正常的日志切削现象。该日志已被写入到文件中,持续,即使超过规定的文件大小。也不会分卷。 log4...
  • ROS学习之 cpp日志记录

    千次阅读 2016-07-18 22:18:53
    日志打印语句  roscpp使用rosconsole程序包来提供客户端API.这些API以一系列的ROS_宏  rosconsole提供4种不同的记录输出语句,以5种不同的冗长等级,这些都支持printf和流式格式化.  基本版本:简单打印...
  • 一个简单的log4cpp写本地日志的配置文件,并附有如何自定义日志文件名以及写配置需要注意的一些地方。
  • C++ 打印日志的宏

    2019-09-16 14:01:22
    利用C++宏,可以很简单的编写出一个打印日志的语句 代码 // 文件名 log.h class MyLog { public: ~MyLog() { ::std::cout << ::std::endl; } std::ostream& operator << (const char* s){ ...
  • 好用的打印日志的源码,因为该源码商未用在具体工程上,但是经过了严格的测试。所以有什么问题及好的建议请联系 QQ915566420,感激不尽。
  • FFMPEG打印日志及线程技巧

    千次阅读 2014-09-24 11:37:22
    1: 在vc中使用ffmpeg静态库做二次开发的时候,如果不是控制台应用程序,又需要查看ffmpeg的日志信息,可使用 [cpp] view plaincopy av_log_set_callback  函数注册一个回调函数,...
  • Linux环境下cpp日志库,支持日志分级别、自定义文件大小、自定义文件前后缀、打印日志到设备(终端)等功能,线程安全。 地址 说明 支持自定义级别,默认定义五个级别(FATAL、ERROR、WARNING、INFO、DEBUG) 支持分级别...
  • 程序中如何打印日志
  • 最近在工作中中需要在Android集成鉴权库的静态链接库,而在集成过程中遇到了一些问题,所以需要在Android Studio中打印静态链接库中的日志进行问题定位,特此记录便于日后查阅。 首先我们需要修改Android.mk文件...
  • DebugView打印日志

    千次阅读 2012-04-17 15:02:51
    首先在目录下创建一个Log.ini文件,这个文件用于是否打印日志的开关。 文件内容为: [LogSettings] IsLog=1 调用GetPrivateProfileInt获取打印日志的开关。 1==GetPrivateProfileInt( _T("LogSettings"), _T(...
  • log4cpp:简单输出日志示例

    千次阅读 2013-12-13 11:26:34
    一、log4cpp概念  Category: 写日志。  Appender: 指定日志的目的地。  Layout: 设定日志的格式。  Priority: 指定Category的优先级和日志的优先级。  NDC: 嵌套的上下文诊断,可用于多线程、多...
  • C++日志开源库log4cpp快速使用示例 一、简介 log4cpp是由C++实现,可输出到控制台、日志文件、syslog 二、源码下载 https://sourceforge.net/projects/log4cpp/files/ 官网地址:...
  • tensorflow运行时会输出一大串的日志信息 眼花缭乱,用以下方法可以去除警告和错误...os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2' import tensorflow as tf 切记:日志等级设置代码要放在导入tensorflow之前! ...
  • 日志打印

    千次阅读 2017-02-22 19:28:28
    I0222 19:22:12.178056 10448 caffe.cpp:218] Using GPUs 0 I0222 19:22:12.236059 10448 caffe.cpp:223] GPU 0: GeForce GTX 1080 I0222 19:22:12.749089 10448 common.cpp:36] System entropy source not availa
  • C++编程之自定义日志类 ——log4cpp使用详解log4cpp简介与安装log4cpp安装log4cpp简单介绍layout布局——日志输出格式log4cpp::BasicLayoutlog4cpp::PatternLayoutappenderlog4cpp::FileAppenderlog4cpp::...
  • "打印日志........" ) ; LOGD ( "hello:%s" , hello . c_str ( ) ) ; return env - > NewStringUTF ( hello . c_str ( ) ) ; } 输出结果如下 I / LOG_TGA : 打印日志 . . . . . . . . D / ...
  • 日志记录工具:log4cpp一、主要工具类二、使用流程三、使用单例模式进行简易封装四、改进方向 一、主要工具类 日志系统,就是将用户指定的信息,按照一定的格式,存储到一个指定的区域。 根据面向对象的思想,可以...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 10,472
精华内容 4,188
关键字:

cpp打印日志