zaphoyd / websocketpp

C++ websocket client/server library
http://www.zaphoyd.com/websocketpp
Other
6.95k stars 1.96k forks source link

Set up custom logger, but some log entries still logged with the default logger #1022

Open fferri opened 2 years ago

fferri commented 2 years ago

I've setup a custom logger to use my application's logging facility. Here's what I did, omitting the actual API call to use the application's logger:

namespace websocketpp
{
    namespace log
    {
        template<typename concurrency, typename names>
        class my_logger : public basic<concurrency, names>
        {
        public:
            typedef basic<concurrency, names> base;

            my_logger<concurrency, names>(channel_type_hint::value hint = channel_type_hint::access)
                    : basic<concurrency, names>(hint), m_channel_type_hint(hint)
            {
            }

            my_logger<concurrency, names>(level channels, channel_type_hint::value hint = channel_type_hint::access)
                    : basic<concurrency, names>(channels, hint), m_channel_type_hint(hint)
            {
            }

            void write(level channel, std::string const &msg)
            {
                write(channel, msg.c_str());
            }

            void write(level channel, char const *msg)
            {
                scoped_lock_type lock(base::m_lock);
                if(!this->dynamic_test(channel)) return;
                // custom logging, e.g.: std::cout with specific format:
                std::cout << "[MY_LOGGER]" << ...
            }

        private:
            typedef typename base::scoped_lock_type scoped_lock_type;
            channel_type_hint::value m_channel_type_hint;
        };
    } // log
} // websocketpp

struct my_config : public websocketpp::config::asio
{
    typedef websocketpp::log::my_logger<concurrency_type, websocketpp::log::elevel> elog_type;
    typedef websocketpp::log::my_logger<concurrency_type, websocketpp::log::alevel> alog_type;
};

typedef websocketpp::server<my_config> my_server;
typedef my_server::connection_type my_connection;

// etc...

In the console I see my custom logger is used, but sometimes the default logger is used:

[2022-01-14 15:24:23] [info] asio listen error: asio.system:48 (Address already in use) [MY_LOGGER] handle_read_frame error: websocketpp.transport:7 (End of File) [MY_LOGGER] handle_read_frame error: asio.system:54 (Connection reset by peer) [2022-01-14 16:14:12] [info] asio async_write error: asio.system:32 (Broken pipe) [MY_LOGGER] handle_write_frame error: websocketpp.transport:2 (Underlying Transport Error) [MY_LOGGER] handle_read_frame error: websocketpp.transport:7 (End of File) [MY_LOGGER] handle_read_frame error: asio.system:54 (Connection reset by peer) [2022-01-14 16:14:17] [info] asio async_write error: asio.system:32 (Broken pipe) [MY_LOGGER] handle_write_frame error: websocketpp.transport:2 (Underlying Transport Error) [MY_LOGGER] handle_read_frame error: websocketpp.transport:7 (End of File) [MY_LOGGER] handle_read_frame error: asio.system:54 (Connection reset by peer) [2022-01-14 16:14:20] [info] asio async_write error: asio.system:32 (Broken pipe) ...

What am I missing to log the remaining entries with my custom logger as well?

barsnick commented 2 years ago

Did you configure both the access (alog) and the error (elog) interface?

Something like:

std::ostream os(&myLogger);
connectionEndpoint.get_alog().set_ostream(&os);
connectionEndpoint.get_elog().set_ostream(&os);

BTW, I haven't got it to work yet with my custom logger class (derived from std::streambuf), I have found no complete working examples.

fferri commented 2 years ago

I don't call .get_alog() nor .get_elog().

The types alog_type and elog_type are overridden in struct my_config, then I use the type websocketpp::server<my_config> to construct the server.

Since most of the log entries go through my logger, I think this approach should work as well.

By the way, I use a custom logger, and std::cout << ... is there just as an example, I don't use any otsream-like interface.

barsnick commented 2 years ago

The types alog_type and elog_type are overridden in struct my_config, then I use the type websocketpp::server<my_config> to construct the server.

Yeah, I missed that. Sorry for being of no help.

zaphoyd commented 2 years ago

What is going on here is that you are seeing logs printed both by WebSocket++ core (the ones that are using your custom logger) and also messages printed by the websocketpp::transport::asio transport policy (the ones that are still using the default logger).

The underlying reason is that transport policies are independent replacable policies that are not coupled to the core library. The transport policy config doesn't know about or have access to my_config. As such, if you want the transport policy to also use a custom logger you'll need to override that explicitly.

Example:

// same custom config as you specified earlier
struct my_config : public websocketpp::config::asio
{
    typedef websocketpp::log::my_logger<concurrency_type, websocketpp::log::elevel> elog_type;
    typedef websocketpp::log::my_logger<concurrency_type, websocketpp::log::alevel> alog_type;

    // create a custom transport config based on the base asio transport config
    struct my_transport_config : public websocketpp::config::asio::transport_config {
        // just override the logger types
        typedef my_config::alog_type alog_type;
        typedef my_config::elog_type elog_type;
    };

    // let `my_config` know to create transport endpoints with `my_transport_config`
    typedef websocketpp::transport::asio::endpoint<my_transport_config>
        transport_type;
};
fferri commented 2 years ago

Thanks @zaphoyd that solves my issue.