Skip to content

Commit 634b4d8

Browse files
authored
Merge pull request #257 from nicklewis/PCP-906
(PCP-906) Enable websocketpp logging
2 parents 16c63f8 + 8779b1c commit 634b4d8

19 files changed

+356
-175
lines changed

lib/inc/cpp-pcp-client/connector/client_metadata.hpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
#define CPP_PCP_CLIENT_SRC_CONNECTOR_CLIENT_METADATA_H_
33

44
#include <cpp-pcp-client/export.h>
5+
#include <cpp-pcp-client/util/logging.hpp>
56

67
#include <string>
78
#include <cstdint>
@@ -25,6 +26,8 @@ class LIBCPP_PCP_CLIENT_EXPORT ClientMetadata {
2526
long ws_connection_timeout_ms;
2627
uint32_t pong_timeouts_before_retry;
2728
long pong_timeout_ms;
29+
leatherman::logging::log_level loglevel{};
30+
std::ofstream* logstream;
2831

2932
/// Throws a connection_config_error in case: the client
3033
/// certificate file does not exist or is invalid; it fails to
@@ -60,6 +63,19 @@ class LIBCPP_PCP_CLIENT_EXPORT ClientMetadata {
6063
long _ws_connection_timeout_ms,
6164
uint32_t _pong_timeouts_before_retry,
6265
long _pong_timeout_ms);
66+
67+
// constructor logging addition
68+
ClientMetadata(std::string _client_type,
69+
std::string _ca,
70+
std::string _crt,
71+
std::string _key,
72+
std::string _crl,
73+
std::string proxy,
74+
leatherman::logging::log_level loglevel,
75+
std::ofstream* logstream,
76+
long _ws_connection_timeout_ms,
77+
uint32_t _pong_timeouts_before_retry,
78+
long _pong_timeout_ms);
6379
};
6480

6581
} // namespace PCPClient

lib/inc/cpp-pcp-client/connector/connection.hpp

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,12 @@
33

44
#include <cpp-pcp-client/connector/timings.hpp>
55
#include <cpp-pcp-client/connector/client_metadata.hpp>
6+
#include <cpp-pcp-client/util/logging.hpp>
67
#include <cpp-pcp-client/util/thread.hpp>
78
#include <cpp-pcp-client/export.h>
89

10+
#include <boost/nowide/fstream.hpp>
11+
912
#include <string>
1013
#include <vector>
1114
#include <memory>
@@ -26,10 +29,6 @@ namespace websocketpp {
2629
template <typename T>
2730
class client;
2831

29-
namespace config {
30-
struct asio_tls_client;
31-
}
32-
3332
namespace message_buffer {
3433
namespace alloc {
3534
template <typename message>
@@ -49,6 +48,8 @@ namespace websocketpp {
4948

5049
namespace PCPClient {
5150

51+
struct ws_config;
52+
5253
// Constants
5354

5455
static const std::string PING_PAYLOAD_DEFAULT { "" };
@@ -57,7 +58,7 @@ static const std::string DEFAULT_CLOSE_REASON { "Closed by client" };
5758

5859
// Configuration of the WebSocket transport layer
5960

60-
using WS_Client_Type = websocketpp::client<websocketpp::config::asio_tls_client>;
61+
using WS_Client_Type = websocketpp::client<ws_config>;
6162
using WS_Context_Ptr = websocketpp::lib::shared_ptr<boost::asio::ssl::context>;
6263
using WS_Connection_Handle = websocketpp::connection_hdl;
6364

@@ -119,6 +120,10 @@ class LIBCPP_PCP_CLIENT_EXPORT Connection {
119120
/// Reset all the callbacks
120121
void resetCallbacks();
121122

123+
/// WebSocket++ logging configuration
124+
void setWebSocketLogLevel(leatherman::logging::log_level loglevel);
125+
void setWebSocketLogStream(std::ofstream* logstream);
126+
122127
/// Check the state of the WebSocket connection; in case it's not
123128
/// open, try to re-open it.
124129
/// Try to reopen for max_connect_attempts times or indefinitely,

lib/inc/cpp-pcp-client/connector/connector_base.hpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,12 @@
1010
#include <cpp-pcp-client/validator/validator.hpp>
1111
#include <cpp-pcp-client/validator/schema.hpp>
1212

13+
#include <cpp-pcp-client/util/logging.hpp>
1314
#include <cpp-pcp-client/util/thread.hpp>
1415

1516
#include <cpp-pcp-client/export.h>
1617

18+
1719
namespace PCPClient {
1820

1921
//
@@ -60,6 +62,21 @@ class LIBCPP_PCP_CLIENT_EXPORT ConnectorBase {
6062
uint32_t pong_timeouts_before_retry,
6163
long ws_pong_timeout_ms);
6264

65+
66+
// constructor logging addition
67+
ConnectorBase(std::vector<std::string> broker_ws_uris,
68+
std::string client_type,
69+
std::string ca_crt_path,
70+
std::string client_crt_path,
71+
std::string client_key_path,
72+
std::string client_crl_path,
73+
std::string ws_proxy,
74+
leatherman::logging::log_level loglevel,
75+
std::ofstream* logstream,
76+
long ws_connection_timeout_ms,
77+
uint32_t pong_timeouts_before_retry,
78+
long ws_pong_timeout_ms);
79+
6380
/// Calls stopMonitorTaskAndWait if the Monitoring Task thread is
6481
/// still active. In case an exception was previously stored by
6582
/// the Monitoring Task, the error message will be logged, but

lib/inc/cpp-pcp-client/connector/v1/connector.hpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,22 @@ class LIBCPP_PCP_CLIENT_EXPORT Connector : public ConnectorBase {
106106
uint32_t pong_timeouts_before_retry = 3,
107107
long ws_pong_timeout_ms = 5000);
108108

109+
// constructor for logging addition
110+
Connector(std::vector<std::string> broker_ws_uris,
111+
std::string client_type,
112+
std::string ca_crt_path,
113+
std::string client_crt_path,
114+
std::string client_key_path,
115+
std::string client_crl_path,
116+
std::string ws_proxy,
117+
leatherman::logging::log_level loglevel,
118+
std::ofstream* logstream,
119+
long ws_connection_timeout_ms = 5000,
120+
uint32_t association_timeout_s = 15,
121+
uint32_t association_request_ttl_s = 10, // Unused
122+
uint32_t pong_timeouts_before_retry = 3,
123+
long ws_pong_timeout_ms = 5000);
124+
109125
/// Set an optional callback for associate responses
110126
void setAssociateCallback(MessageCallback callback);
111127

lib/inc/cpp-pcp-client/connector/v2/connector.hpp

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,14 +81,28 @@ class LIBCPP_PCP_CLIENT_EXPORT Connector : public ConnectorBase {
8181
uint32_t pong_timeouts_before_retry = 3,
8282
long ws_pong_timeout_ms = 5000);
8383

84-
// constructor for proxy addition
84+
// constructor for crl addition
85+
Connector(std::vector<std::string> broker_ws_uris,
86+
std::string client_type,
87+
std::string ca_crt_path,
88+
std::string client_crt_path,
89+
std::string client_key_path,
90+
std::string client_crl_path,
91+
std::string ws_proxy,
92+
long ws_connection_timeout_ms = 5000,
93+
uint32_t pong_timeouts_before_retry = 3,
94+
long ws_pong_timeout_ms = 5000);
95+
96+
// constructor for logging addition
8597
Connector(std::vector<std::string> broker_ws_uris,
8698
std::string client_type,
8799
std::string ca_crt_path,
88100
std::string client_crt_path,
89101
std::string client_key_path,
90102
std::string client_crl_path,
91103
std::string ws_proxy,
104+
leatherman::logging::log_level loglevel,
105+
std::ofstream* logstream,
92106
long ws_connection_timeout_ms = 5000,
93107
uint32_t pong_timeouts_before_retry = 3,
94108
long ws_pong_timeout_ms = 5000);

lib/inc/cpp-pcp-client/ws_config.hpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
#pragma once
2+
3+
#include <websocketpp/config/asio_client.hpp>
4+
5+
namespace PCPClient {
6+
struct ws_config : public websocketpp::config::asio_tls_client {
7+
static const websocketpp::log::level elog_level =
8+
websocketpp::log::elevel::all;
9+
static const websocketpp::log::level alog_level =
10+
websocketpp::log::alevel::all;
11+
};
12+
}

lib/src/connector/client_metadata.cc

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
namespace PCPClient {
1818

1919
namespace lth_loc = leatherman::locale;
20+
namespace lth_log = leatherman::logging;
2021

2122
// Get rid of OSX 10.7 and greater deprecation warnings.
2223
#if defined(__APPLE__) && defined(__clang__)
@@ -121,6 +122,7 @@ ClientMetadata::ClientMetadata(std::string _client_type,
121122
ws_connection_timeout_ms { std::move(_ws_connection_timeout_ms) },
122123
pong_timeouts_before_retry { std::move(_pong_timeouts_before_retry) },
123124
pong_timeout_ms { std::move(_pong_timeout_ms) }
125+
124126
{
125127
LOG_INFO("Retrieved common name from the certificate and determined "
126128
"the client URI: {1}", uri);
@@ -183,4 +185,36 @@ ClientMetadata::ClientMetadata(std::string _client_type,
183185
}
184186

185187

188+
// constructor for logging addition
189+
ClientMetadata::ClientMetadata(std::string _client_type,
190+
std::string _ca,
191+
std::string _crt,
192+
std::string _key,
193+
std::string _crl,
194+
std::string _proxy,
195+
lth_log::log_level _loglevel,
196+
std::ofstream* _logstream,
197+
long _ws_connection_timeout_ms,
198+
uint32_t _pong_timeouts_before_retry,
199+
long _pong_timeout_ms)
200+
: ca { std::move(_ca) },
201+
crt { std::move(_crt) },
202+
key { std::move(_key) },
203+
crl { std::move(_crl) },
204+
proxy { std::move(_proxy) },
205+
client_type { std::move(_client_type) },
206+
common_name { getCommonNameFromCert(crt) },
207+
uri { PCP_URI_SCHEME + common_name + "/" + client_type },
208+
loglevel { std::move(_loglevel) },
209+
logstream { _logstream },
210+
ws_connection_timeout_ms { std::move(_ws_connection_timeout_ms) },
211+
pong_timeouts_before_retry { std::move(_pong_timeouts_before_retry) },
212+
pong_timeout_ms { std::move(_pong_timeout_ms) }
213+
{
214+
LOG_INFO("Retrieved common name from the certificate and determined "
215+
"the client URI: {1}", uri);
216+
validatePrivateKeyCertPair(key, crt);
217+
LOG_DEBUG("Validated the private key / certificate pair");
218+
}
219+
186220
} // namespace PCPClient

lib/src/connector/connection.cc

Lines changed: 61 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include <cpp-pcp-client/protocol/v1/message.hpp>
1313
#include <cpp-pcp-client/util/thread.hpp>
1414
#include <cpp-pcp-client/util/chrono.hpp>
15+
#include <cpp-pcp-client/ws_config.hpp>
1516

1617
// This is hacky because MinGW-w64 5.2 with Boost 1.58 is printing warnings that should be suppressed. Preserve the
1718
// warnings elsewhere to make sure we have coverage of our code, but suppress for the whole file on Windows to avoid
@@ -22,7 +23,6 @@
2223
#pragma GCC diagnostic ignored "-Wunused-variable"
2324
#include <websocketpp/common/connection_hdl.hpp>
2425
#include <websocketpp/client.hpp>
25-
#include <websocketpp/config/asio_client.hpp>
2626
#ifndef _WIN32
2727
#pragma GCC diagnostic pop
2828
#endif
@@ -54,6 +54,7 @@ namespace PCPClient {
5454

5555
namespace lth_util = leatherman::util;
5656
namespace lth_loc = leatherman::locale;
57+
namespace lth_log = leatherman::logging;
5758

5859
//
5960
// Constants
@@ -84,12 +85,10 @@ Connection::Connection(std::vector<std::string> broker_ws_uris,
8485
consecutive_pong_timeouts_ { 0 },
8586
endpoint_ { new WS_Client_Type() }
8687
{
87-
// Turn off websocketpp logging to avoid runtime errors (see CTH-69)
88-
endpoint_->clear_access_channels(websocketpp::log::alevel::all);
89-
endpoint_->clear_error_channels(websocketpp::log::elevel::all);
90-
9188
// Initialize the transport system. Note that in perpetual mode,
9289
// the event loop does not terminate when there are no connections
90+
setWebSocketLogLevel(client_metadata_.loglevel);
91+
setWebSocketLogStream(client_metadata_.logstream);
9392
endpoint_->init_asio();
9493
endpoint_->start_perpetual();
9594

@@ -143,6 +142,63 @@ ConnectionState Connection::getConnectionState() const
143142
return connection_state_.load();
144143
}
145144

145+
//
146+
// WebSocket logging configuration
147+
//
148+
149+
void Connection::setWebSocketLogLevel(lth_log::log_level loglevel)
150+
{
151+
// Ensure all log channels are disabled
152+
endpoint_->set_access_channels(websocketpp::log::alevel::none);
153+
endpoint_->set_error_channels(websocketpp::log::elevel::none);
154+
155+
// WebSocket++ log levels are defined at
156+
// https://raw.githubusercontent.com/zaphoyd/websocketpp/master/docs/logging.dox
157+
// For any given log level, fallthrough and set logs at all higher levels.
158+
// This could also be accomplished by defining a custom log package for each
159+
// leatherman log level using a bitwise OR operator, but this is simpler.
160+
switch (loglevel) {
161+
case(lth_log::log_level::trace):
162+
endpoint_->set_access_channels(websocketpp::log::alevel::devel |
163+
websocketpp::log::alevel::frame_header);
164+
endpoint_->set_error_channels(websocketpp::log::elevel::devel);
165+
166+
case(lth_log::log_level::debug):
167+
endpoint_->set_access_channels(websocketpp::log::alevel::debug_handshake |
168+
websocketpp::log::alevel::debug_close);
169+
endpoint_->set_error_channels(websocketpp::log::elevel::library);
170+
171+
case(lth_log::log_level::info):
172+
endpoint_->set_access_channels(websocketpp::log::alevel::connect |
173+
websocketpp::log::alevel::disconnect);
174+
endpoint_->set_error_channels(websocketpp::log::elevel::info);
175+
176+
case(lth_log::log_level::warning):
177+
endpoint_->set_error_channels(websocketpp::log::elevel::warn);
178+
179+
case(lth_log::log_level::error):
180+
endpoint_->set_error_channels(websocketpp::log::elevel::rerror);
181+
182+
case(lth_log::log_level::fatal):
183+
endpoint_->set_error_channels(websocketpp::log::elevel::fatal);
184+
break;
185+
186+
case(lth_log::log_level::none):
187+
break; // All log channels already disabled, do nothing
188+
189+
default:
190+
throw connection_config_error { lth_loc::format("invalid log level: '{1}'", loglevel) };
191+
}
192+
}
193+
194+
void Connection::setWebSocketLogStream(std::ofstream* logstream)
195+
{
196+
if (logstream != nullptr) {
197+
endpoint_->get_alog().set_ostream(logstream);
198+
endpoint_->get_elog().set_ostream(logstream);
199+
}
200+
}
201+
146202
//
147203
// Callback modifiers
148204
//

0 commit comments

Comments
 (0)