diff --git a/src/HttpContext.h b/src/HttpContext.h index 9a4cc346b..2efdd6bf1 100644 --- a/src/HttpContext.h +++ b/src/HttpContext.h @@ -25,9 +25,9 @@ #include "HttpResponseData.h" #include "AsyncSocket.h" #include "WebSocketData.h" +#include "Log.h" #include -#include #include "f2/function2.hpp" namespace uWS { @@ -144,6 +144,7 @@ struct HttpContext { /* Are we not ready for another request yet? Terminate the connection. */ if (httpResponseData->state & HttpResponseData::HTTP_RESPONSE_PENDING) { + UWS_LOG_REQUEST(3, "terminating connection (HTTP_RESPONSE_PENDING)"); us_socket_close(SSL, (us_socket_t *) s, 0, nullptr); return nullptr; } @@ -155,30 +156,36 @@ struct HttpContext { httpContextData->router.getUserData() = {(HttpResponse *) s, httpRequest}; if (!httpContextData->router.route(httpRequest->getMethod(), httpRequest->getUrl())) { /* We have to force close this socket as we have no handler for it */ + UWS_LOG_REQUEST(1, "No handler for route ", httpRequest->getMethod(), " ", httpRequest->getUrl()); us_socket_close(SSL, (us_socket_t *) s, 0, nullptr); return nullptr; } + else { + UWS_LOG_REQUEST(3, "Successfully handled route ", httpRequest->getMethod(), " ", httpRequest->getUrl()); + } /* First of all we need to check if this socket was deleted due to upgrade */ if (httpContextData->upgradedWebSocket) { /* We differ between closed and upgraded below */ + UWS_LOG_REQUEST(3, "socket was deleted due to upgrade"); return nullptr; } /* Was the socket closed? */ if (us_socket_is_closed(SSL, (struct us_socket_t *) s)) { + UWS_LOG_REQUEST(3, "socket was closed"); return nullptr; } /* We absolutely have to terminate parsing if shutdown */ if (us_socket_is_shut_down(SSL, (us_socket_t *) s)) { + UWS_LOG_REQUEST(3, "socket was shutdown"); return nullptr; } /* Returning from a request handler without responding or attaching an onAborted handler is ill-use */ if (!((HttpResponse *) s)->hasResponded() && !httpResponseData->onAborted) { - /* Throw exception here? */ - std::cerr << "Error: Returning from a request handler without responding or attaching an abort handler is forbidden!" << std::endl; + UWS_LOG_REQUEST(0, "Error: Returning from a request handler without responding or attaching an abort handler is forbidden!"); std::terminate(); } @@ -208,11 +215,13 @@ struct HttpContext { /* Was the socket closed? */ if (us_socket_is_closed(SSL, (struct us_socket_t *) user)) { + UWS_LOG_REQUEST(3, "socket was closed"); return nullptr; } /* We absolutely have to terminate parsing if shutdown */ if (us_socket_is_shut_down(SSL, (us_socket_t *) user)) { + UWS_LOG_REQUEST(3, "socket was shutdown"); return nullptr; } @@ -340,6 +349,7 @@ struct HttpContext { httpContext = (HttpContext *) us_create_socket_context(SSL, (us_loop_t *) loop, sizeof(HttpContextData), options); if (!httpContext) { + UWS_LOG_REQUEST(0, "Error: Failed to create a httpContext"); return nullptr; } diff --git a/src/Log.h b/src/Log.h new file mode 100644 index 000000000..d3aa3903c --- /dev/null +++ b/src/Log.h @@ -0,0 +1,72 @@ +#ifndef UWS_LOG_H +#define UWS_LOG_H +#include +#include +#include +#include + +#define UWS_LOG_LEVEL 0 // override this to get more verbose logging + +namespace uWS { + +/*! + * \brief Log a message. The user of this lib is free to override this function object with a custom logger. + * \param [in] message The message to be logged. + * \param [in] logLevel The severity of the message. 0 is error, 1 is warning, 2 is info, 3 is debug. With each increment the severity decrements. + */ +typedef std::function LogFunction; + +inline LogFunction log = [](std::string_view message, int logLevel) -> void { + if(logLevel <= 1) { + std::cerr << message << std::endl; + } + else { + std::cout << message << std::endl; + } +}; + +class LogBuffer +{ + private: + std::array buf{0}; + size_t cursor = 0; + + LogBuffer& operator<< (std::string_view sv) { + const size_t bytesFree = buf.size() - cursor; + if(sv.size() > bytesFree) + return *this; + memcpy(&buf[cursor], sv.data(), sv.size()); + cursor += sv.size(); + return *this; + } + + public: + template + void put(T msg) { + *this << msg; + } + template + void put(T t, Ts... ts) { + put(t); + put(ts...); + } + std::string_view get() { + std::string_view ret(buf.data(), cursor); + cursor = 0; + return ret; + } +}; + +thread_local LogBuffer logBuffer; + +#define UWS_LOG_REQUEST(loglevel, ...) { \ + if constexpr(loglevel <= UWS_LOG_LEVEL) { \ + ::uWS::logBuffer.put(__VA_ARGS__); \ + ::uWS::log(::uWS::logBuffer.get(), loglevel); \ + } \ +} + +} // namespace uWS + +#endif // UWS_LOG_H +