Stiffstream / restinio

Cross-platform, efficient, customizable, and robust asynchronous HTTP(S)/WebSocket server C++ library with the right balance between performance and ease of use
Other
1.15k stars 93 forks source link

use logger in request handler #34

Closed bigerl closed 5 years ago

bigerl commented 5 years ago

I would like to use RESTinio's logger inside of a request handler lambda function. Is there any way to do so? I have had a looked through the examples but could not find anything where things are actually written to the logger.

eao197 commented 5 years ago

RESTinio doesn't expose its internal logger to a request_handler. But you can create your own logger type and tell RESTinio to use it. In that case, you can also pass a reference to the actual logger to your request_hander. Like in that example:

#include <iostream>

#include <restinio/all.hpp>

class my_logger
{
    restinio::shared_ostream_logger_t & logger_;

public:
    my_logger( restinio::shared_ostream_logger_t & logger ) noexcept
        :   logger_{logger}
    {}

    template< typename Message_Builder >
    void trace( Message_Builder && msg_builder )
    {
        logger_.trace( std::forward<Message_Builder>(msg_builder) );
    }

    template< typename Message_Builder >
    void info( Message_Builder && msg_builder )
    {
        logger_.info( std::forward<Message_Builder>(msg_builder) );
    }

    template< typename Message_Builder >
    void warn( Message_Builder && msg_builder )
    {
        logger_.warn( std::forward<Message_Builder>(msg_builder) );
    }

    template< typename Message_Builder >
    void error( Message_Builder && msg_builder )
    {
        logger_.error( std::forward<Message_Builder>(msg_builder) );
    }
};

// Create request handler.
restinio::request_handling_status_t handler(
    restinio::shared_ostream_logger_t & logger,
    restinio::request_handle_t req )
{
    logger.trace( [&]{
            return fmt::format( "Request received: {}", req->header().request_target() );
    } );

    if( restinio::http_method_get() == req->header().method() &&
        req->header().request_target() == "/" )
    {
        req->create_response()
            .append_header( restinio::http_field::server, "RESTinio hello world server" )
            .append_header_date_field()
            .append_header( restinio::http_field::content_type, "text/plain; charset=utf-8" )
            .set_body( fmt::format( "{}: Hello world!", req->remote_endpoint() ) )
            .done();

        return restinio::request_accepted();
    }
    else
    {
        logger.warn( [&]{
                return fmt::format( "Request rejected: {}", req->header().request_target() );
        } );
    }

    return restinio::request_rejected();
}

int main()
{
    try
    {
        struct my_traits : public restinio::default_traits_t
        {
            using logger_t = my_logger;
        };

        restinio::shared_ostream_logger_t actual_logger;

        restinio::run(
            restinio::on_thread_pool< my_traits >( std::thread::hardware_concurrency() )
                .port( 8080 )
                .address( "localhost" )
                .logger( actual_logger )
                .request_handler(
                    [&actual_logger]( auto req ) {
                        return handler( actual_logger, req );
                    } )
        );
    }
    catch( const std::exception & ex )
    {
        std::cerr << "Error: " << ex.what() << std::endl;
        return 1;
    }

    return 0;
}

Please note that RESTinio creates an instance of my_logger type automatically under the hood. You can't pass an already created instance of my_logger to logger method -- only a set of arguments for my_logger constructor.

Another example of usage of a custom logger can be found in our Shrimp demo project. See slides 30-36 in the presentation.

bigerl commented 5 years ago

Ah, that's feasible. Thanks a lot for your solution and fast response.

eao197 commented 5 years ago

Thanks for your interest in RESTinio!