From 6ab39622e5d4030a233d9242e850b8d4882ff5db Mon Sep 17 00:00:00 2001 From: Peter Thorson Date: Sun, 20 Jan 2013 20:24:26 -0600 Subject: [PATCH] adds basic logger class, with tests, and updates configs to include it --- SConstruct | 2 +- test/logger/SConscript | 23 ++++ test/logger/basic.cpp | 52 ++++++++ websocketpp/config/asio.hpp | 6 + websocketpp/config/asio_no_tls.hpp | 3 + websocketpp/config/core.hpp | 13 +- websocketpp/logger/basic.hpp | 188 +++++++++++++++++++++++++++++ 7 files changed, 284 insertions(+), 3 deletions(-) create mode 100644 test/logger/SConscript create mode 100644 test/logger/basic.cpp create mode 100644 websocketpp/logger/basic.hpp diff --git a/SConstruct b/SConstruct index aa9c8017e5..3a91ec263a 100644 --- a/SConstruct +++ b/SConstruct @@ -171,7 +171,7 @@ Export('polyfill_libs') ## TARGETS: # Unit tests, add test folders with SConscript files to to_test list. -to_test = ['utility','http','processors','message_buffer','extension','transport/asio','endpoint','connection'] #,'http','processors','connection' +to_test = ['utility','http','logger','processors','message_buffer','extension','transport/asio','endpoint','connection'] #,'http','processors','connection' for t in to_test: new_tests = SConscript('#/test/'+t+'/SConscript',variant_dir = testdir + t, duplicate = 0) diff --git a/test/logger/SConscript b/test/logger/SConscript new file mode 100644 index 0000000000..2f37cde609 --- /dev/null +++ b/test/logger/SConscript @@ -0,0 +1,23 @@ +## logger unit tests +## + +Import('env') +Import('env_cpp11') +Import('boostlibs') +Import('platform_libs') +Import('polyfill_libs') + +env = env.Clone () +env_cpp11 = env_cpp11.Clone () + +BOOST_LIBS = boostlibs(['unit_test_framework','regex','chrono','system'],env) + [platform_libs] + +objs = env.Object('logger_basic_boost.o', ["basic.cpp"], LIBS = BOOST_LIBS) +prgs = env.Program('logger_basic_boost', ["logger_basic_boost.o"], LIBS = BOOST_LIBS) + +if env_cpp11.has_key('WSPP_CPP11_ENABLED'): + BOOST_LIBS_CPP11 = boostlibs(['unit_test_framework'],env_cpp11) + [platform_libs] + [polyfill_libs] + objs += env_cpp11.Object('logger_basic_stl.o', ["basic.cpp"], LIBS = BOOST_LIBS_CPP11) + prgs += env_cpp11.Program('logger_basic_stl', ["logger_basic_stl.o"], LIBS = BOOST_LIBS_CPP11) + +Return('prgs') diff --git a/test/logger/basic.cpp b/test/logger/basic.cpp new file mode 100644 index 0000000000..d19ef437f0 --- /dev/null +++ b/test/logger/basic.cpp @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2013, Peter Thorson. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the WebSocket++ Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +//#define BOOST_TEST_DYN_LINK +#define BOOST_TEST_MODULE basic_logger +#include + +#include + +#include +#include + +BOOST_AUTO_TEST_CASE( is_token_char ) { + typedef websocketpp::logger::basic error_logger; + + error_logger elog; + + BOOST_CHECK( elog.static_test(websocketpp::logger::error_names::info ) == true ); + BOOST_CHECK( elog.static_test(websocketpp::logger::error_names::warn ) == true ); + BOOST_CHECK( elog.static_test(websocketpp::logger::error_names::rerror ) == true ); + BOOST_CHECK( elog.static_test(websocketpp::logger::error_names::fatal ) == true ); + + elog.set_channels(websocketpp::logger::error_names::info); + + elog.write(websocketpp::logger::error_names::info,"Information"); + elog.write(websocketpp::logger::error_names::warn,"A warning"); + elog.write(websocketpp::logger::error_names::rerror,"A error"); + elog.write(websocketpp::logger::error_names::fatal,"A critical error"); +} diff --git a/websocketpp/config/asio.hpp b/websocketpp/config/asio.hpp index dfc2dd3f3d..240cc8a7ad 100644 --- a/websocketpp/config/asio.hpp +++ b/websocketpp/config/asio.hpp @@ -49,6 +49,9 @@ struct asio : public core { typedef core::message_type message_type; typedef core::con_msg_manager_type con_msg_manager_type; typedef core::endpoint_msg_manager_type endpoint_msg_manager_type; + + typedef core::alog_type alog_type; + typedef core::alog_type elog_type; }; struct asio_tls : public core { @@ -65,6 +68,9 @@ struct asio_tls : public core { typedef core::message_type message_type; typedef core::con_msg_manager_type con_msg_manager_type; typedef core::endpoint_msg_manager_type endpoint_msg_manager_type; + + typedef core::alog_type alog_type; + typedef core::alog_type elog_type; }; } // namespace config diff --git a/websocketpp/config/asio_no_tls.hpp b/websocketpp/config/asio_no_tls.hpp index a59726507a..a1b44d712f 100644 --- a/websocketpp/config/asio_no_tls.hpp +++ b/websocketpp/config/asio_no_tls.hpp @@ -48,6 +48,9 @@ struct asio : public core { typedef core::message_type message_type; typedef core::con_msg_manager_type con_msg_manager_type; typedef core::endpoint_msg_manager_type endpoint_msg_manager_type; + + typedef core::alog_type alog_type; + typedef core::alog_type elog_type; }; } // namespace config diff --git a/websocketpp/config/core.hpp b/websocketpp/config/core.hpp index a1b3068682..418c0acda7 100644 --- a/websocketpp/config/core.hpp +++ b/websocketpp/config/core.hpp @@ -29,7 +29,7 @@ #define WEBSOCKETPP_CONFIG_CORE_HPP // Concurrency -#include +#include // Transport #include @@ -42,6 +42,9 @@ #include #include +// Loggers +#include + // Extensions #include @@ -50,7 +53,7 @@ namespace config { struct core { // Concurrency policy - typedef websocketpp::concurrency::none concurrency_type; + typedef websocketpp::concurrency::basic concurrency_type; // Transport Policy typedef websocketpp::transport::iostream::endpoint @@ -68,6 +71,12 @@ struct core { typedef message_buffer::alloc::endpoint_msg_manager endpoint_msg_manager_type; + /// Logging policies + typedef websocketpp::logger::basic elog_type; + typedef websocketpp::logger::basic alog_type; + /// static const size_t connection_read_buffer_size = 32; diff --git a/websocketpp/logger/basic.hpp b/websocketpp/logger/basic.hpp new file mode 100644 index 0000000000..e0d78b7f92 --- /dev/null +++ b/websocketpp/logger/basic.hpp @@ -0,0 +1,188 @@ +/* + * Copyright (c) 2013, Peter Thorson. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the WebSocket++ Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef WEBSOCKETPP_LOGGER_HPP +#define WEBSOCKETPP_LOGGER_HPP + +/* Need a way to print a message to the log + * + * - timestamps + * - channels + * - thread safe + * - output to stdout or file + * - selective output channels, both compile time and runtime + * - named channels + * - ability to test whether a log message will be printed at compile time + * + */ + +#include + +namespace websocketpp { +namespace logger { + +struct error_names { + static const uint32_t none = 0x0; + static const uint32_t devel = 0x1; + static const uint32_t library = 0x2; + static const uint32_t info = 0x4; + static const uint32_t warn = 0x8; + static const uint32_t rerror = 0x10; + static const uint32_t fatal = 0x20; + static const uint32_t all = 0xffffffff; + + static const char* channel_name(uint32_t channel) { + switch(channel) { + case devel: + return "devel"; + case library: + return "library"; + case info: + return "info"; + case warn: + return "warning"; + case rerror: + return "error"; + case fatal: + return "fatal"; + default: + return "unknown"; + } + } +}; + +struct access_names { + static const uint32_t none = 0x0; + static const uint32_t connect = 0x1; + static const uint32_t disconnect = 0x2; + static const uint32_t control = 0x4; + static const uint32_t frame_header = 0x8; + static const uint32_t frame_payload = 0x10; + static const uint32_t message_header = 0x20; + static const uint32_t message_payload = 0x40; + static const uint32_t endpoint = 0x80; + static const uint32_t debug_handshake = 0x100; + static const uint32_t debug_close = 0x200; + static const uint32_t devel = 0x400; + static const uint32_t all = 0xffffffff; + + static const char* channel_name(uint32_t channel) { + switch(channel) { + case connect: + return "connect"; + case disconnect: + return "disconnect"; + case control: + return "control"; + case frame_header: + return "frame_header"; + case frame_payload: + return "frame_payload"; + case message_header: + return "message_header"; + case message_payload: + return "message_payload"; + case endpoint: + return "endpoint"; + case debug_handshake: + return "debug_handshake"; + case debug_close: + return "debug_close"; + case devel: + return "devel"; + default: + return "unknown"; + } + } +}; + +template +class basic { +public: + basic() + : m_static_channels(0xffffffff) + , m_dynamic_channels(0) {} + + basic(uint32_t c) + : m_static_channels(c) + , m_dynamic_channels(0) {} + + void set_channels(uint32_t channels) { + scoped_lock_type lock(m_lock); + m_dynamic_channels |= (channels & m_static_channels); + } + + void clear_channels(uint32_t channels) { + scoped_lock_type lock(m_lock); + m_dynamic_channels &= channels; + } + + void write(uint32_t channel, const std::string& msg) { + scoped_lock_type lock(m_lock); + if (!this->dynamic_test(channel)) { return; } + std::cout << "[" << get_timestamp() << "] " + << "[" << names::channel_name(channel) << "] " + << msg << std::endl; + } + + void write(uint32_t channel, const char* msg) { + scoped_lock_type lock(m_lock); + if (!this->dynamic_test(channel)) { return; } + std::cout << "[" << get_timestamp() << "] " + << "[" << names::channel_name(channel) << "] " + << msg << std::endl; + } + + bool static_test(uint32_t channel) const { + return channel & m_static_channels; + } + +private: + typedef typename concurrency::scoped_lock_type scoped_lock_type; + typedef typename concurrency::mutex_type mutex_type; + + bool dynamic_test(uint32_t channel) { + return channel & m_dynamic_channels; + } + + const char* get_timestamp() { + std::time_t t = std::time(NULL); + std::strftime(buffer,30,"%Y-%m-%d %H:%M:%S%z",std::localtime(&t)); + return buffer; + } + + mutex_type m_lock; + + char buffer[30]; + const uint32_t m_static_channels; + uint32_t m_dynamic_channels; +}; + +} // logger +} // websocketpp + +#endif //WEBSOCKETPP_LOGGER_HPP