0

我正在使用 websocketpp 创建遥测服务器,并遵循此处的示例。我的应用程序将作为启动时启动的 linux 守护程序运行,因此我将无法将日志写入标准输出。因此,我想使用spdlog添加一个客户记录器,并了解它可以根据页面上的内容来完成。看起来我需要使用该websocketpp::log::stub界面来创建自己的客户记录器。问题是,关于日志记录的文档非常有限,我不确定从哪里开始以及如何将其合并到上面链接的遥测服务器示例的上下文中。当我定义我的服务器时,我不确定如何指定记录器:typedef websocketpp::server<websocketpp::config::asio> server;

如何扩展stub课程,以及如何使用此客户记录器初始化我的服务器?

我能找到的唯一示例代码在此线程中但根据链接的注释,此代码之后不再相关V 0.3.x+

4

2 回答 2

3

对于任何想要使用spdlog作为客户记录器的示例代码的人,这里是:

使用以下内容创建一个新文件customerLogger.hpp

#pragma once

#include <websocketpp/logger/basic.hpp>

#include <websocketpp/common/cpp11.hpp>
#include <websocketpp/logger/levels.hpp>
#include "spdlog/logger.h"
#include "spdlog/sinks/rotating_file_sink.h"

namespace websocketpp {
    namespace log {

/// Basic logger that outputs to syslog
        template <typename concurrency, typename names>
        class myLogger : public basic<concurrency, names> {
        public:
            typedef basic<concurrency, names> base;

            /// Construct the logger
            /**
             * @param hint A channel type specific hint for how to construct the logger
             */
            myLogger<concurrency,names>(channel_type_hint::value hint =
            channel_type_hint::access)
                    : basic<concurrency,names>(hint), m_channel_type_hint(hint) {
                auto max_size = 1048576 * 5;
                auto max_files = 3;
                auto rotating_sink = std::make_shared<spdlog::sinks::rotating_file_sink_mt> ("/var/logs/my_logger.log", max_size, max_files);
                m_logger = std::make_shared<spdlog::logger>("my_logger", rotating_sink);
                m_logger->flush_on(spdlog::level::info);
                m_logger->set_level(spdlog::level::level_enum::info);
            }

            /// Construct the logger
            /**
             * @param channels A set of channels to statically enable
             * @param hint A channel type specific hint for how to construct the logger
             */
            myLogger<concurrency,names>(level channels, channel_type_hint::value hint =
            channel_type_hint::access)
                    : basic<concurrency,names>(channels, hint), m_channel_type_hint(hint) {
                auto max_size = 1048576 * 5;
                auto max_files = 3;
                auto rotating_sink = std::make_shared<spdlog::sinks::rotating_file_sink_mt> ("/var/logs/my_logger.log", max_size, max_files);
                m_logger = std::make_shared<spdlog::logger>("my_logger", rotating_sink);
                m_logger->flush_on(spdlog::level::info);
                m_logger->set_level(spdlog::level::level_enum::info);
            }

            /// Write a string message to the given channel
            /**
             * @param channel The channel to write to
             * @param msg The message to write
             */
            void write(level channel, std::string const & msg) {
                write(channel, msg.c_str());
            }

            /// Write a cstring message to the given channel
            /**
             * @param channel The channel to write to
             * @param msg The message to write
             */
            void write(level channel, char const * msg) {
                scoped_lock_type lock(base::m_lock);
                if (!this->dynamic_test(channel)) { return; }

                if (m_channel_type_hint == channel_type_hint::access) {
                    m_logger->info(msg);
                } else {
                    if (channel == elevel::devel) {
                        m_logger->debug(msg);
                    } else if (channel == elevel::library) {
                        m_logger->debug(msg);
                    } else if (channel == elevel::info) {
                        m_logger->info(msg);
                    } else if (channel == elevel::warn) {
                        m_logger->warn(msg);
                    } else if (channel == elevel::rerror) {
                        m_logger->error(msg);
                    } else if (channel == elevel::fatal) {
                        m_logger->critical(msg);
                    }
                }

            }

        private:
            std::shared_ptr<spdlog::logger> m_logger;
            typedef typename base::scoped_lock_type scoped_lock_type;
            channel_type_hint::value m_channel_type_hint;
        };

    } // log
} // websocketpp

接下来,创建另一个文件,customConfig.hpp该文件具有以下内容:

#pragma once

#include "./customLogger.hpp"
#include <websocketpp/logger/syslog.hpp>
#include <websocketpp/extensions/permessage_deflate/enabled.hpp>

// Custom server config based on bundled asio config
struct my_config : public websocketpp::config::asio {
    // Replace default stream logger with the custom logger
    typedef websocketpp::log::myLogger<concurrency_type, websocketpp::log::elevel> elog_type;
    typedef websocketpp::log::myLogger<concurrency_type, websocketpp::log::alevel> alog_type;
};

typedef websocketpp::server<my_config> my_server;

最后,当你想创建服务器时,你很简单my_server endpoint;

于 2020-06-25T19:50:53.657 回答
2

构建自定义记录器有两个步骤。首先,使用适当的接口编写一个策略类,然后创建一个使用该策略的自定义配置。

编写策略类websocketpp::log::stub是一个最小的实现,它实际上不做任何事情(它主要用于在单元测试中存根日志),但它演示并记录了日志类需要实现的接口。日志记录类不需要是websocketpp::log::stub. 您可以查看websocketpp/logger/*文件夹中的其他示例。尤其是 syslog 记录器,作为输出到标准输出以外的其他内容的日志记录策略的示例,可能会很有趣。

要设置自定义配置,您将创建一个配置类。它可以是独立的,也可以是其中一个标准的子类,例如websocketpp::config::asio,它只是覆盖了少量的东西。例如,您的配置可能只会覆盖记录器。创建后,您会将配置类传递给端点模板参数,而不是websocketpp::config::asio.

有关可以通过此配置系统在编译时覆盖的内容的更多详细信息,请参见https://docs.websocketpp.org/reference_8config.html。此页面上有一个示例,显示了替换默认记录器的自定义配置(以及其他更改)。

于 2020-06-24T22:36:48.153 回答