From 5a2e61161792cf51209f240e40e28036195f35be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Mon, 13 Jun 2016 19:59:17 +0200 Subject: Show off, with some variadic templates, for the logger module --- louloulibs/logger/logger.hpp | 74 ++++++++++++++++++++++++------ louloulibs/network/credentials_manager.cpp | 6 +-- louloulibs/network/poller.cpp | 14 +++--- louloulibs/network/tcp_socket_handler.cpp | 40 ++++++++-------- louloulibs/xmpp/adhoc_commands_handler.cpp | 2 +- louloulibs/xmpp/xmpp_component.cpp | 20 ++++---- louloulibs/xmpp/xmpp_parser.cpp | 6 +-- src/irc/irc_client.cpp | 22 ++++----- tests/logger.cpp | 2 +- 9 files changed, 115 insertions(+), 71 deletions(-) diff --git a/louloulibs/logger/logger.hpp b/louloulibs/logger/logger.hpp index 3547513..8ff4dcd 100644 --- a/louloulibs/logger/logger.hpp +++ b/louloulibs/logger/logger.hpp @@ -33,21 +33,6 @@ # define __FILENAME__ __FILE__ #endif -#define WHERE\ - __FILENAME__ << ":" << __LINE__ - -#define log_debug(text)\ - Logger::instance()->get_stream(debug_lvl) << SD_DEBUG << WHERE << ":\t" << text << std::endl - -#define log_info(text)\ - Logger::instance()->get_stream(info_lvl) << SD_INFO << WHERE << ":\t" << text << std::endl - -#define log_warning(text)\ - Logger::instance()->get_stream(warning_lvl) << SD_WARNING << WHERE << ":\t" << text << std::endl - -#define log_error(text)\ - Logger::instance()->get_stream(error_lvl) << SD_ERR << WHERE << ":\t" << text << std::endl - /** * Juste a structure representing a stream doing nothing with its input. */ @@ -79,4 +64,63 @@ private: std::ostream stream; }; +#define WHERE __FILENAME__, ":", __LINE__, ":\t" + +namespace logging_details +{ + template + void log(std::ostream& os, const T& arg) + { + os << arg << std::endl; + } + + template + void log(std::ostream& os, const T& first, U&&... rest) + { + os << first; + log(os, std::forward(rest)...); + } + + template + void log_debug(U&&... args) + { + auto& os = Logger::instance()->get_stream(debug_lvl); + os << SD_DEBUG; + log(os, std::forward(args)...); + } + + template + void log_info(U&&... args) + { + auto& os = Logger::instance()->get_stream(info_lvl); + os << SD_INFO; + log(os, std::forward(args)...); + } + + template + void log_warning(U&&... args) + { + auto& os = Logger::instance()->get_stream(warning_lvl); + os << SD_WARNING; + log(os, std::forward(args)...); + } + + template + void log_error(U&&... args) + { + auto& os = Logger::instance()->get_stream(error_lvl); + os << SD_ERR; + log(os, std::forward(args)...); + } +} + +#define log_info(...) logging_details::log_info(WHERE, __VA_ARGS__) + +#define log_warning(...) logging_details::log_warning(WHERE, __VA_ARGS__) + +#define log_error(...) logging_details::log_error(WHERE, __VA_ARGS__) + +#define log_debug(...) logging_details::log_debug(WHERE, __VA_ARGS__) + + #endif // LOGGER_INCLUDED diff --git a/louloulibs/network/credentials_manager.cpp b/louloulibs/network/credentials_manager.cpp index c5b8493..ee83c3b 100644 --- a/louloulibs/network/credentials_manager.cpp +++ b/louloulibs/network/credentials_manager.cpp @@ -41,7 +41,7 @@ void BasicCredentialsManager::verify_certificate_chain(const std::string& type, const std::string& purported_hostname, const std::vector& certs) { - log_debug("Checking remote certificate (" << type << ") for hostname " << purported_hostname); + log_debug("Checking remote certificate (", type, ") for hostname ", purported_hostname); try { Botan::Credentials_Manager::verify_certificate_chain(type, purported_hostname, certs); @@ -49,7 +49,7 @@ void BasicCredentialsManager::verify_certificate_chain(const std::string& type, } catch (const std::exception& tls_exception) { - log_warning("TLS certificate check failed: " << tls_exception.what()); + log_warning("TLS certificate check failed: ", tls_exception.what()); if (!this->trusted_fingerprint.empty() && !certs.empty() && this->trusted_fingerprint == certs[0].fingerprint() && certs[0].matches_dns_name(purported_hostname)) @@ -78,7 +78,7 @@ void BasicCredentialsManager::load_certs() try { Botan::DataSource_Stream bundle(path); - log_debug("Using ca bundle: " << path); + log_debug("Using ca bundle: ", path); while (!bundle.end_of_data() && bundle.check_available(27)) { // TODO: remove this work-around for Botan 1.11.29 diff --git a/louloulibs/network/poller.cpp b/louloulibs/network/poller.cpp index 959567e..8a6fd97 100644 --- a/louloulibs/network/poller.cpp +++ b/louloulibs/network/poller.cpp @@ -20,7 +20,7 @@ Poller::Poller() this->epfd = ::epoll_create1(0); if (this->epfd == -1) { - log_error("epoll failed: " << strerror(errno)); + log_error("epoll failed: ", strerror(errno)); throw std::runtime_error("Could not create epoll instance"); } #endif @@ -54,7 +54,7 @@ void Poller::add_socket_handler(SocketHandler* socket_handler) const int res = ::epoll_ctl(this->epfd, EPOLL_CTL_ADD, socket_handler->get_socket(), &event); if (res == -1) { - log_error("epoll_ctl failed: " << strerror(errno)); + log_error("epoll_ctl failed: ", strerror(errno)); throw std::runtime_error("Could not add socket to epoll"); } #endif @@ -86,7 +86,7 @@ void Poller::remove_socket_handler(const socket_t socket) const int res = ::epoll_ctl(this->epfd, EPOLL_CTL_DEL, socket, nullptr); if (res == -1) { - log_error("epoll_ctl failed: " << strerror(errno)); + log_error("epoll_ctl failed: ", strerror(errno)); throw std::runtime_error("Could not remove socket from epoll"); } #endif @@ -109,7 +109,7 @@ void Poller::watch_send_events(SocketHandler* socket_handler) const int res = ::epoll_ctl(this->epfd, EPOLL_CTL_MOD, socket_handler->get_socket(), &event); if (res == -1) { - log_error("epoll_ctl failed: " << strerror(errno)); + log_error("epoll_ctl failed: ", strerror(errno)); throw std::runtime_error("Could not modify socket flags in epoll"); } #endif @@ -132,7 +132,7 @@ void Poller::stop_watching_send_events(SocketHandler* socket_handler) const int res = ::epoll_ctl(this->epfd, EPOLL_CTL_MOD, socket_handler->get_socket(), &event); if (res == -1) { - log_error("epoll_ctl failed: " << strerror(errno)); + log_error("epoll_ctl failed: ", strerror(errno)); throw std::runtime_error("Could not modify socket flags in epoll"); } #endif @@ -165,7 +165,7 @@ int Poller::poll(const std::chrono::milliseconds& timeout) { if (errno == EINTR) return true; - log_error("poll failed: " << strerror(errno)); + log_error("poll failed: ", strerror(errno)); throw std::runtime_error("Poll failed"); } // We cannot possibly have more ready events than the number of fds we are @@ -205,7 +205,7 @@ int Poller::poll(const std::chrono::milliseconds& timeout) { if (errno == EINTR) return 0; - log_error("epoll wait: " << strerror(errno)); + log_error("epoll wait: ", strerror(errno)); throw std::runtime_error("Epoll_wait failed"); } for (int i = 0; i < nb_events; ++i) diff --git a/louloulibs/network/tcp_socket_handler.cpp b/louloulibs/network/tcp_socket_handler.cpp index 81369dd..5420b1c 100644 --- a/louloulibs/network/tcp_socket_handler.cpp +++ b/louloulibs/network/tcp_socket_handler.cpp @@ -64,8 +64,8 @@ void TCPSocketHandler::init_socket(const struct addrinfo* rp) struct addrinfo* result; int err = ::getaddrinfo(this->bind_addr.data(), nullptr, nullptr, &result); if (err != 0 || !result) - log_error("Failed to bind socket to " << this->bind_addr << ": " - << gai_strerror(err)); + log_error("Failed to bind socket to ", this->bind_addr, ": ", + gai_strerror(err)); else { utils::ScopeGuard sg([result](){ freeaddrinfo(result); }); @@ -79,15 +79,15 @@ void TCPSocketHandler::init_socket(const struct addrinfo* rp) break; } if (!rp) - log_error("Failed to bind socket to " << this->bind_addr << ": " - << strerror(bind_error)); + log_error("Failed to bind socket to ", this->bind_addr, ": ", + strerror(bind_error)); else - log_info("Socket successfully bound to " << this->bind_addr); + log_info("Socket successfully bound to ", this->bind_addr); } } int optval = 1; if (::setsockopt(this->socket, SOL_SOCKET, SO_KEEPALIVE, &optval, sizeof(optval)) == -1) - log_warning("Failed to enable TCP keepalive on socket: " << strerror(errno)); + log_warning("Failed to enable TCP keepalive on socket: ", strerror(errno)); // Set the socket on non-blocking mode. This is useful to receive a EAGAIN // error when connect() would block, to not block the whole process if a // remote is not responsive. @@ -113,7 +113,7 @@ void TCPSocketHandler::connect(const std::string& address, const std::string& po // this is the first call of this function. if (!this->resolver.is_resolved()) { - log_info("Trying to connect to " << address << ":" << port); + log_info("Trying to connect to ", address, ":", port); // Start the asynchronous process of resolving the hostname. Once // the addresses have been found and `resolved` has been set to true // (but connecting will still be false), TCPSocketHandler::connect() @@ -161,7 +161,7 @@ void TCPSocketHandler::connect(const std::string& address, const std::string& po this->init_socket(rp); } catch (const std::runtime_error& error) { - log_error("Failed to init socket: " << error.what()); + log_error("Failed to init socket: ", error.what()); break; } } @@ -204,7 +204,7 @@ void TCPSocketHandler::connect(const std::string& address, const std::string& po "connection_timeout"s + std::to_string(this->socket))); return ; } - log_info("Connection failed:" << strerror(errno)); + log_info("Connection failed:", strerror(errno)); } log_error("All connection attempts failed."); this->close(); @@ -268,9 +268,9 @@ ssize_t TCPSocketHandler::do_recv(void* recv_buf, const size_t buf_size) else if (-1 == size) { if (this->connecting) - log_warning("Error connecting: " << strerror(errno)); + log_warning("Error connecting: ", strerror(errno)); else - log_warning("Error while reading from socket: " << strerror(errno)); + log_warning("Error while reading from socket: ", strerror(errno)); // Remember if we were connecting, or already connected when this // happened, because close() sets this->connecting to false const auto were_connecting = this->connecting; @@ -300,7 +300,7 @@ void TCPSocketHandler::on_send() ssize_t res = ::sendmsg(this->socket, &msg, MSG_NOSIGNAL); if (res < 0) { - log_error("sendmsg failed: " << strerror(errno)); + log_error("sendmsg failed: ", strerror(errno)); this->on_connection_close(strerror(errno)); this->close(); } @@ -351,9 +351,9 @@ void TCPSocketHandler::close() void TCPSocketHandler::display_resolved_ip(struct addrinfo* rp) const { if (rp->ai_family == AF_INET) - log_debug("Trying IPv4 address " << addr_to_string(rp)); + log_debug("Trying IPv4 address ", addr_to_string(rp)); else if (rp->ai_family == AF_INET6) - log_debug("Trying IPv6 address " << addr_to_string(rp)); + log_debug("Trying IPv6 address ", addr_to_string(rp)); } void TCPSocketHandler::send_data(std::string&& data) @@ -478,18 +478,18 @@ void TCPSocketHandler::tls_output_fn(const Botan::byte* data, size_t size) void TCPSocketHandler::tls_alert_cb(Botan::TLS::Alert alert, const Botan::byte*, size_t) { - log_debug("tls_alert: " << alert.type_string()); + log_debug("tls_alert: ", alert.type_string()); } bool TCPSocketHandler::tls_handshake_cb(const Botan::TLS::Session& session) { - log_debug("Handshake with " << session.server_info().hostname() << " complete." - << " Version: " << session.version().to_string() - << " using " << session.ciphersuite().to_string()); + log_debug("Handshake with ", session.server_info().hostname(), " complete.", + " Version: ", session.version().to_string(), + " using ", session.ciphersuite().to_string()); if (!session.session_id().empty()) - log_debug("Session ID " << Botan::hex_encode(session.session_id())); + log_debug("Session ID ", Botan::hex_encode(session.session_id())); if (!session.session_ticket().empty()) - log_debug("Session ticket " << Botan::hex_encode(session.session_ticket())); + log_debug("Session ticket ", Botan::hex_encode(session.session_ticket())); return true; } diff --git a/louloulibs/xmpp/adhoc_commands_handler.cpp b/louloulibs/xmpp/adhoc_commands_handler.cpp index 714c440..17c4e67 100644 --- a/louloulibs/xmpp/adhoc_commands_handler.cpp +++ b/louloulibs/xmpp/adhoc_commands_handler.cpp @@ -119,5 +119,5 @@ void AdhocCommandsHandler::remove_session(const std::string& session_id, const s this->sessions.erase(session_it); return ; } - log_error("Tried to remove ad-hoc session for [" << session_id << ", " << initiator_jid << "] but none found"); + log_error("Tried to remove ad-hoc session for [", session_id, ", ", initiator_jid, "] but none found"); } diff --git a/louloulibs/xmpp/xmpp_component.cpp b/louloulibs/xmpp/xmpp_component.cpp index b92d9a3..1be7a06 100644 --- a/louloulibs/xmpp/xmpp_component.cpp +++ b/louloulibs/xmpp/xmpp_component.cpp @@ -72,14 +72,14 @@ bool XmppComponent::is_document_open() const void XmppComponent::send_stanza(const Stanza& stanza) { std::string str = stanza.to_string(); - log_debug("XMPP SENDING: " << str); + log_debug("XMPP SENDING: ", str); this->send_data(std::move(str)); } void XmppComponent::on_connection_failed(const std::string& reason) { this->first_connection_try = false; - log_error("Failed to connect to the XMPP server: " << reason); + log_error("Failed to connect to the XMPP server: ", reason); #ifdef SYSTEMD_FOUND sd_notifyf(0, "STATUS=Failed to connect to the XMPP server: %s", reason.data()); #endif @@ -91,7 +91,7 @@ void XmppComponent::on_connected() this->first_connection_try = true; auto data = ""; - log_debug("XMPP SENDING: " << data); + log_debug("XMPP SENDING: ", data); this->send_data(std::move(data)); this->doc_open = true; // We may have some pending data to send: this happens when we try to send @@ -104,7 +104,7 @@ void XmppComponent::on_connection_close(const std::string& error) if (error.empty()) log_info("XMPP server closed connection"); else - log_info("XMPP server closed connection: " << error); + log_info("XMPP server closed connection: ", error); } void XmppComponent::parse_in_buffer(const size_t size) @@ -125,7 +125,7 @@ void XmppComponent::parse_in_buffer(const size_t size) void XmppComponent::on_remote_stream_open(const XmlNode& node) { - log_debug("XMPP RECEIVING: " << node.to_string()); + log_debug("XMPP RECEIVING: ", node.to_string()); this->stream_id = node.get_tag("id"); if (this->stream_id.empty()) { @@ -147,13 +147,13 @@ void XmppComponent::on_remote_stream_open(const XmlNode& node) digest[HASH_LENGTH * 2] = '\0'; auto data = ""s + digest + ""; - log_debug("XMPP SENDING: " << data); + log_debug("XMPP SENDING: ", data); this->send_data(std::move(data)); } void XmppComponent::on_remote_stream_close(const XmlNode& node) { - log_debug("XMPP RECEIVING: " << node.to_string()); + log_debug("XMPP RECEIVING: ", node.to_string()); this->doc_open = false; } @@ -164,7 +164,7 @@ void XmppComponent::reset() void XmppComponent::on_stanza(const Stanza& stanza) { - log_debug("XMPP RECEIVING: " << stanza.to_string()); + log_debug("XMPP RECEIVING: ", stanza.to_string()); std::function handler; try { @@ -172,7 +172,7 @@ void XmppComponent::on_stanza(const Stanza& stanza) } catch (const std::out_of_range& exception) { - log_warning("No handler for stanza of type " << stanza.get_name()); + log_warning("No handler for stanza of type ", stanza.get_name()); return; } handler(stanza); @@ -257,7 +257,7 @@ void XmppComponent::handle_error(const Stanza& stanza) std::string error_message("Unspecified error"); if (text) error_message = text->get_inner(); - log_error("Stream error received from the XMPP server: " << error_message); + log_error("Stream error received from the XMPP server: ", error_message); #ifdef SYSTEMD_FOUND if (!this->ever_auth) sd_notifyf(0, "STATUS=Failed to authenticate to the XMPP server: %s", error_message.data()); diff --git a/louloulibs/xmpp/xmpp_parser.cpp b/louloulibs/xmpp/xmpp_parser.cpp index dc12000..0488be9 100644 --- a/louloulibs/xmpp/xmpp_parser.cpp +++ b/louloulibs/xmpp/xmpp_parser.cpp @@ -56,7 +56,7 @@ int XmppParser::feed(const char* data, const int len, const bool is_final) int res = XML_Parse(this->parser, data, len, is_final); if (res == XML_STATUS_ERROR && (XML_GetErrorCode(this->parser) != XML_ERROR_FINISHED)) - log_error("Xml_Parse encountered an error: " << + log_error("Xml_Parse encountered an error: ", XML_ErrorString(XML_GetErrorCode(this->parser))); return res; } @@ -65,7 +65,7 @@ int XmppParser::parse(const int len, const bool is_final) { int res = XML_ParseBuffer(this->parser, len, is_final); if (res == XML_STATUS_ERROR) - log_error("Xml_Parsebuffer encountered an error: " << + log_error("Xml_Parsebuffer encountered an error: ", XML_ErrorString(XML_GetErrorCode(this->parser))); return res; } @@ -139,7 +139,7 @@ void XmppParser::stanza_event(const Stanza& stanza) const try { callback(stanza); } catch (const std::exception& e) { - log_error("Unhandled exception: " << e.what()); + log_error("Unhandled exception: ", e.what()); } } } diff --git a/src/irc/irc_client.cpp b/src/irc/irc_client.cpp index d16ffc7..e320db9 100644 --- a/src/irc/irc_client.cpp +++ b/src/irc/irc_client.cpp @@ -333,7 +333,7 @@ void IrcClient::parse_in_buffer(const size_t) break ; IrcMessage message(this->in_buf.substr(0, pos)); this->in_buf = this->in_buf.substr(pos + 2, std::string::npos); - log_debug("IRC RECEIVING: (" << this->get_hostname() << ") " << message); + log_debug("IRC RECEIVING: (", this->get_hostname(), ") ", message); // Call the standard callback (if any), associated with the command // name that we just received. @@ -346,21 +346,21 @@ void IrcClient::parse_in_buffer(const size_t) // second is the max if (message.arguments.size() < limits.first || (limits.second > 0 && message.arguments.size() > limits.second)) - log_warning("Invalid number of arguments for IRC command “" << message.command << - "”: " << message.arguments.size()); + log_warning("Invalid number of arguments for IRC command “", message.command, + "”: ", message.arguments.size()); else { const auto& cb = it->second.first; try { (this->*(cb))(message); } catch (const std::exception& e) { - log_error("Unhandled exception: " << e.what()); + log_error("Unhandled exception: ", e.what()); } } } else { - log_info("No handler for command " << message.command << + log_info("No handler for command ", message.command, ", forwarding the arguments to the user"); this->on_unknown_message(message); } @@ -371,7 +371,7 @@ void IrcClient::parse_in_buffer(const size_t) void IrcClient::send_message(IrcMessage&& message) { - log_debug("IRC SENDING: (" << this->get_hostname() << ") " << message); + log_debug("IRC SENDING: (", this->get_hostname(), ") ", message); std::string res; if (!message.prefix.empty()) res += ":" + std::move(message.prefix) + " "; @@ -392,7 +392,7 @@ void IrcClient::send_message(IrcMessage&& message) void IrcClient::send_raw(const std::string& txt) { - log_debug("IRC SENDING (raw): (" << this->get_hostname() << ") " << txt); + log_debug("IRC SENDING (raw): (", this->get_hostname(), ") ", txt); this->send_data(txt + "\r\n"); } @@ -452,7 +452,7 @@ bool IrcClient::send_channel_message(const std::string& chan_name, const std::st IrcChannel* channel = this->get_channel(chan_name); if (channel->joined == false) { - log_warning("Cannot send message to channel " << chan_name << ", it is not joined"); + log_warning("Cannot send message to channel ", chan_name, ", it is not joined"); return false; } // Cut the message body into 400-bytes parts (because the whole command @@ -698,7 +698,7 @@ void IrcClient::empty_motd(const IrcMessage&) void IrcClient::on_empty_topic(const IrcMessage& message) { const std::string chan_name = utils::tolower(message.arguments[1]); - log_debug("empty topic for " << chan_name); + log_debug("empty topic for ", chan_name); IrcChannel* channel = this->get_channel(chan_name); if (channel) channel->topic.clear(); @@ -1026,8 +1026,8 @@ void IrcClient::on_channel_mode(const IrcMessage& message) IrcUser* user = channel->find_user(target); if (!user) { - log_warning("Trying to set mode for non-existing user '" << target - << "' in channel" << iid.get_local()); + log_warning("Trying to set mode for non-existing user '", target + , "' in channel", iid.get_local()); return; } if (add) diff --git a/tests/logger.cpp b/tests/logger.cpp index 2a99374..7ae4f03 100644 --- a/tests/logger.cpp +++ b/tests/logger.cpp @@ -24,7 +24,7 @@ TEST_CASE("Basic logging") WHEN("we log some debug text") { IoTester out(std::cout); - log_debug("debug"); + log_debug("deb", "ug"); THEN("debug logs are written") CHECK(out.str() == debug_header + "tests/logger.cpp:" + std::to_string(__LINE__ - 2) + ":\tdebug\n"); } -- cgit v1.2.3