Skip to content

Commit ba0bc82

Browse files
authored
CXXCBC-346: allow to log network communication (#425)
1 parent e5b69c8 commit ba0bc82

File tree

12 files changed

+234
-43
lines changed

12 files changed

+234
-43
lines changed

core/io/dns_client.cxx

Lines changed: 48 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -72,16 +72,25 @@ class dns_srv_command : public std::enable_shared_from_this<dns_srv_command>
7272

7373
void execute(std::chrono::milliseconds total_timeout, std::chrono::milliseconds udp_timeout)
7474
{
75-
CB_LOG_TRACE("Query DNS-SRV (UDP) address=\"{}:{}\", udp_timeout={}, total_timeout={}{:a}",
75+
CB_LOG_TRACE("Query DNS-SRV (UDP) address=\"{}:{}\", udp_timeout={}, total_timeout={}",
7676
address_.to_string(),
7777
port_,
7878
udp_timeout,
79-
total_timeout,
80-
spdlog::to_hex(send_buf_));
79+
total_timeout);
8180
asio::ip::udp::endpoint endpoint(address_, port_);
8281
udp_.open(endpoint.protocol());
82+
CB_LOG_PROTOCOL("[DNS, UDP, OUT] host=\"{}\", port={}, buffer_size={}{:a}",
83+
address_.to_string(),
84+
port_,
85+
send_buf_.size(),
86+
spdlog::to_hex(send_buf_));
8387
udp_.async_send_to(
84-
asio::buffer(send_buf_), endpoint, [self = shared_from_this()](std::error_code ec1, std::size_t /* bytes_transferred */) mutable {
88+
asio::buffer(send_buf_), endpoint, [self = shared_from_this()](std::error_code ec1, std::size_t bytes_transferred1) mutable {
89+
CB_LOG_PROTOCOL("[DNS, UDP, OUT] host=\"{}\", port={}, rc={}, bytes_sent={}",
90+
self->address_.to_string(),
91+
self->port_,
92+
ec1 ? ec1.message() : "ok",
93+
bytes_transferred1);
8594
if (ec1) {
8695
self->udp_deadline_.cancel();
8796
CB_LOG_DEBUG("DNS UDP write operation has got error, retrying with TCP, address=\"{}:{}\", ec={}",
@@ -94,6 +103,13 @@ class dns_srv_command : public std::enable_shared_from_this<dns_srv_command>
94103
self->recv_buf_.resize(512);
95104
self->udp_.async_receive_from(
96105
asio::buffer(self->recv_buf_), self->udp_sender_, [self](std::error_code ec2, std::size_t bytes_transferred) mutable {
106+
CB_LOG_PROTOCOL("[DNS, UDP, IN] host=\"{}\", port={}, rc={}, bytes_received={}{:a}",
107+
self->address_.to_string(),
108+
self->port_,
109+
ec2 ? ec2.message() : "ok",
110+
bytes_transferred,
111+
spdlog::to_hex(self->recv_buf_.data(), self->recv_buf_.data() + bytes_transferred));
112+
97113
self->udp_deadline_.cancel();
98114
if (ec2) {
99115
CB_LOG_DEBUG("DNS UDP read operation has got error, retrying with TCP, address=\"{}:{}\", ec={}",
@@ -168,10 +184,18 @@ class dns_srv_command : public std::enable_shared_from_this<dns_srv_command>
168184
auto send_size = static_cast<std::uint16_t>(self->send_buf_.size());
169185
self->send_buf_.insert(self->send_buf_.begin(), static_cast<std::uint8_t>(send_size & 0xffU));
170186
self->send_buf_.insert(self->send_buf_.begin(), static_cast<std::uint8_t>(send_size >> 8U));
171-
CB_LOG_TRACE(
172-
"Query DNS-SRV (TCP) address=\"{}:{}\"{:a}", self->address_.to_string(), self->port_, spdlog::to_hex(self->send_buf_));
187+
CB_LOG_PROTOCOL("[DNS, TCP, OUT] host=\"{}\", port={}, buffer_size={}{:a}",
188+
self->address_.to_string(),
189+
self->port_,
190+
self->send_buf_.size(),
191+
spdlog::to_hex(self->send_buf_));
173192
asio::async_write(
174-
self->tcp_, asio::buffer(self->send_buf_), [self](std::error_code ec2, std::size_t /* bytes_transferred */) mutable {
193+
self->tcp_, asio::buffer(self->send_buf_), [self](std::error_code ec2, std::size_t bytes_transferred2) mutable {
194+
CB_LOG_PROTOCOL("[DNS, TCP, OUT] host=\"{}\", port={}, rc={}, bytes_sent={}",
195+
self->address_.to_string(),
196+
self->port_,
197+
ec2 ? ec2.message() : "ok",
198+
bytes_transferred2);
175199
if (ec2) {
176200
CB_LOG_DEBUG("DNS TCP write operation has been aborted, address=\"{}:{}\", ec={}",
177201
self->address_.to_string(),
@@ -186,7 +210,14 @@ class dns_srv_command : public std::enable_shared_from_this<dns_srv_command>
186210
asio::async_read(
187211
self->tcp_,
188212
asio::buffer(&self->recv_buf_size_, sizeof(std::uint16_t)),
189-
[self](std::error_code ec3, std::size_t /* bytes_transferred */) mutable {
213+
[self](std::error_code ec3, std::size_t bytes_transferred3) mutable {
214+
CB_LOG_PROTOCOL("[DNS, TCP, IN] host=\"{}\", port={}, rc={}, bytes_received={}{:a}",
215+
self->address_.to_string(),
216+
self->port_,
217+
ec3 ? ec3.message() : "ok",
218+
bytes_transferred3,
219+
spdlog::to_hex(reinterpret_cast<std::uint8_t*>(&self->recv_buf_size_),
220+
reinterpret_cast<std::uint8_t*>(&self->recv_buf_size_) + bytes_transferred3));
190221
if (ec3) {
191222
CB_LOG_DEBUG("DNS TCP buf size read operation has been aborted, address=\"{}:{}\", ec={}",
192223
self->address_.to_string(),
@@ -199,16 +230,23 @@ class dns_srv_command : public std::enable_shared_from_this<dns_srv_command>
199230
self->recv_buf_.resize(self->recv_buf_size_);
200231
CB_LOG_DEBUG("DNS TCP schedule read of {} bytes", self->recv_buf_size_);
201232
asio::async_read(
202-
self->tcp_, asio::buffer(self->recv_buf_), [self](std::error_code ec4, std::size_t bytes_transferred) mutable {
233+
self->tcp_, asio::buffer(self->recv_buf_), [self](std::error_code ec4, std::size_t bytes_transferred4) mutable {
203234
self->deadline_.cancel();
235+
CB_LOG_PROTOCOL("[DNS, TCP, IN] host=\"{}\", port={}, rc={}, bytes_received={}{:a}",
236+
self->address_.to_string(),
237+
self->port_,
238+
ec4 ? ec4.message() : "ok",
239+
bytes_transferred4,
240+
spdlog::to_hex(self->recv_buf_.data(), self->recv_buf_.data() + bytes_transferred4));
241+
204242
if (ec4) {
205243
CB_LOG_DEBUG("DNS TCP read operation has been aborted, address=\"{}:{}\", ec={}",
206244
self->address_.to_string(),
207245
self->port_,
208246
ec4.message());
209247
return self->handler_({ ec4 });
210248
}
211-
self->recv_buf_.resize(bytes_transferred);
249+
self->recv_buf_.resize(bytes_transferred4);
212250
const dns_message message = dns_codec::decode(self->recv_buf_);
213251
dns_srv_response resp{ ec4 };
214252
resp.targets.reserve(message.answers.size());

core/io/http_session.hxx

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,10 @@
3131

3232
#include <couchbase/error_codes.hxx>
3333

34+
#include <spdlog/fmt/bin_to_hex.h>
35+
3436
#include <asio.hpp>
37+
3538
#include <list>
3639
#include <memory>
3740
#include <utility>
@@ -448,7 +451,20 @@ class http_session : public std::enable_shared_from_this<http_session>
448451
stream_->async_read_some(
449452
asio::buffer(input_buffer_), [self = shared_from_this()](std::error_code ec, std::size_t bytes_transferred) {
450453
if (ec == asio::error::operation_aborted || self->stopped_) {
454+
CB_LOG_PROTOCOL("[HTTP, IN] type={}, host=\"{}\", rc={}, bytes_received={}",
455+
self->type_,
456+
self->info_.remote_address(),
457+
ec ? ec.message() : "ok",
458+
bytes_transferred);
451459
return;
460+
} else {
461+
CB_LOG_PROTOCOL("[HTTP, IN] type={}, host=\"{}\", rc={}, bytes_received={}{:a}",
462+
self->type_,
463+
self->info_.remote_address(),
464+
ec ? ec.message() : "ok",
465+
bytes_transferred,
466+
spdlog::to_hex(self->input_buffer_.data(),
467+
self->input_buffer_.data() + static_cast<std::ptrdiff_t>(bytes_transferred)));
452468
}
453469
self->last_active_ = std::chrono::steady_clock::now();
454470
if (ec) {
@@ -495,9 +511,16 @@ class http_session : public std::enable_shared_from_this<http_session>
495511
std::vector<asio::const_buffer> buffers;
496512
buffers.reserve(writing_buffer_.size());
497513
for (auto& buf : writing_buffer_) {
514+
CB_LOG_PROTOCOL(
515+
"[HTTP, OUT] type={}, host=\"{}\", buffer_size={}{:a}", type_, info_.remote_address(), buf.size(), spdlog::to_hex(buf));
498516
buffers.emplace_back(asio::buffer(buf));
499517
}
500-
stream_->async_write(buffers, [self = shared_from_this()](std::error_code ec, std::size_t /* bytes_transferred */) {
518+
stream_->async_write(buffers, [self = shared_from_this()](std::error_code ec, std::size_t bytes_transferred) {
519+
CB_LOG_PROTOCOL("[HTTP, OUT] type={}, host=\"{}\", rc={}, bytes_sent={}",
520+
self->type_,
521+
self->info_.remote_address(),
522+
ec ? ec.message() : "ok",
523+
bytes_transferred);
501524
if (ec == asio::error::operation_aborted || self->stopped_) {
502525
return;
503526
}

core/io/mcbp_session.cxx

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1365,7 +1365,20 @@ class mcbp_session_impl
13651365
asio::buffer(input_buffer_),
13661366
[self = shared_from_this(), stream_id = stream_->id()](std::error_code ec, std::size_t bytes_transferred) {
13671367
if (ec == asio::error::operation_aborted || self->stopped_) {
1368+
CB_LOG_PROTOCOL("[MCBP, IN] host=\"{}\", port={}, rc={}, bytes_received={}",
1369+
self->endpoint_address_,
1370+
self->endpoint_.port(),
1371+
ec ? ec.message() : "ok",
1372+
bytes_transferred);
13681373
return;
1374+
} else {
1375+
CB_LOG_PROTOCOL("[MCBP, IN] host=\"{}\", port={}, rc={}, bytes_received={}{:a}",
1376+
self->endpoint_address_,
1377+
self->endpoint_.port(),
1378+
ec ? ec.message() : "ok",
1379+
bytes_transferred,
1380+
spdlog::to_hex(self->input_buffer_.data(),
1381+
self->input_buffer_.data() + static_cast<std::ptrdiff_t>(bytes_transferred)));
13691382
}
13701383
self->last_active_ = std::chrono::steady_clock::now();
13711384
if (ec) {
@@ -1433,13 +1446,21 @@ class mcbp_session_impl
14331446
std::vector<asio::const_buffer> buffers;
14341447
buffers.reserve(writing_buffer_.size());
14351448
for (auto& buf : writing_buffer_) {
1449+
CB_LOG_PROTOCOL(
1450+
"[MCBP, OUT] host=\"{}\", port={}, buffer_size={}{:a}", endpoint_address_, endpoint_.port(), buf.size(), spdlog::to_hex(buf));
14361451
buffers.emplace_back(asio::buffer(buf));
14371452
}
1438-
stream_->async_write(buffers, [self = shared_from_this()](std::error_code ec, std::size_t /*unused*/) {
1453+
stream_->async_write(buffers, [self = shared_from_this()](std::error_code ec, std::size_t bytes_transferred) {
1454+
CB_LOG_PROTOCOL("[MCBP, OUT] host=\"{}\", port={}, rc={}, bytes_sent={}",
1455+
self->endpoint_address_,
1456+
self->endpoint_.port(),
1457+
ec ? ec.message() : "ok",
1458+
bytes_transferred);
14391459
if (ec == asio::error::operation_aborted || self->stopped_) {
14401460
return;
14411461
}
14421462
self->last_active_ = std::chrono::steady_clock::now();
1463+
14431464
if (ec) {
14441465
CB_LOG_ERROR(R"({} IO error while writing to the socket("{}"): {} ({}))",
14451466
self->log_prefix_,

core/logger/custom_rotating_file_sink.cxx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ custom_rotating_file_sink<Mutex>::add_hook(const std::string& hook)
127127

128128
// Payload shouldn't contain anything yet, overwrite it
129129
Expects(msg.payload.size() == 0);
130-
msg.payload = hook;
130+
msg.payload = hookToAdd;
131131

132132
spdlog::memory_buf_t formatted;
133133
formatter->format(msg, formatted);

core/logger/logger.cxx

Lines changed: 80 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@
2222
#include <spdlog/sinks/stdout_color_sinks.h>
2323
#include <spdlog/spdlog.h>
2424

25-
static const std::string logger_name{ "couchbase_cxx_client_file_logger" };
25+
static const std::string file_logger_name{ "couchbase_cxx_client_file_logger" };
26+
static const std::string protocol_logger_name{ "couchbase_cxx_client_protocol_logger" };
2627

2728
/**
2829
* Custom log pattern which the loggers will use.
@@ -39,7 +40,12 @@ static const std::string log_pattern{ "[%Y-%m-%d %T.%e] [%P,%t] [%^%l%$] %oms, %
3940
* messages and send them to the sinks, which do the actual writing (to file,
4041
* to stream etc.) or further processing.
4142
*/
42-
static std::shared_ptr<spdlog::logger> file_logger;
43+
static std::shared_ptr<spdlog::logger> file_logger{};
44+
45+
/**
46+
* Instance of the protocol logger.
47+
*/
48+
static std::shared_ptr<spdlog::logger> protocol_logger{};
4349

4450
namespace couchbase::core::logger
4551
{
@@ -146,13 +152,11 @@ is_initialized()
146152
return file_logger != nullptr;
147153
}
148154

149-
/**
150-
* Initialises the loggers. Called if the logger configuration is
151-
* specified in a separate settings object.
152-
*/
153-
std::optional<std::string>
154-
create_file_logger(const configuration& logger_settings)
155+
std::pair<std::optional<std::string>, std::shared_ptr<spdlog::logger>>
156+
create_file_logger_impl(const std::string logger_name, const configuration& logger_settings)
155157
{
158+
std::shared_ptr<spdlog::logger> logger{};
159+
156160
auto fname = logger_settings.filename;
157161
auto buffersz = logger_settings.buffer_size;
158162
auto cyclesz = logger_settings.cycle_size;
@@ -218,31 +222,79 @@ create_file_logger(const configuration& logger_settings)
218222
spdlog::drop(logger_name);
219223

220224
if (logger_settings.unit_test) {
221-
file_logger = std::make_shared<spdlog::logger>(logger_name, sink);
225+
logger = std::make_shared<spdlog::logger>(logger_name, sink);
222226
} else {
223227
// Create the default thread pool for async logging
224228
spdlog::init_thread_pool(buffersz, 1);
225229

226230
// Get the thread pool so that we can actually construct the
227231
// object with already created sinks...
228232
auto tp = spdlog::thread_pool();
229-
file_logger = std::make_shared<spdlog::async_logger>(logger_name, sink, tp, spdlog::async_overflow_policy::block);
233+
logger = std::make_shared<spdlog::async_logger>(logger_name, sink, tp, spdlog::async_overflow_policy::block);
230234
}
231235

232-
file_logger->set_pattern(log_pattern);
233-
file_logger->set_level(translate_level(logger_settings.log_level));
236+
logger->set_pattern(log_pattern);
237+
logger->set_level(translate_level(logger_settings.log_level));
234238

235239
// Set the flushing interval policy
236240
spdlog::flush_every(std::chrono::seconds(1));
237241

238-
spdlog::register_logger(file_logger);
242+
spdlog::register_logger(logger);
239243
} catch (const spdlog::spdlog_ex& ex) {
240244
std::string msg = std::string{ "Log initialization failed: " } + ex.what();
241-
return std::optional<std::string>{ msg };
245+
return { msg, {} };
246+
}
247+
return { {}, logger };
248+
}
249+
250+
/**
251+
* Initialises the loggers. Called if the logger configuration is
252+
* specified in a separate settings object.
253+
*/
254+
std::optional<std::string>
255+
create_file_logger(const configuration& logger_settings)
256+
{
257+
auto [error, logger] = create_file_logger_impl(file_logger_name, logger_settings);
258+
if (error) {
259+
return error;
260+
}
261+
file_logger = std::move(logger);
262+
return {};
263+
}
264+
265+
std::optional<std::string>
266+
create_protocol_logger(const configuration& logger_settings)
267+
{
268+
if (logger_settings.filename.empty()) {
269+
return "File name is missing";
270+
}
271+
auto config = logger_settings;
272+
config.log_level = couchbase::core::logger::level::trace;
273+
auto [error, logger] = create_file_logger_impl(protocol_logger_name, config);
274+
if (error) {
275+
return error;
242276
}
277+
protocol_logger = std::move(logger);
243278
return {};
244279
}
245280

281+
bool
282+
should_log_protocol()
283+
{
284+
return protocol_logger != nullptr;
285+
}
286+
287+
namespace detail
288+
{
289+
void
290+
log_protocol(const char* file, int line, const char* function, std::string_view msg)
291+
{
292+
if (should_log_protocol()) {
293+
return protocol_logger->log(spdlog::source_loc{ file, line, function }, spdlog::level::level_enum::trace, msg);
294+
}
295+
}
296+
} // namespace detail
297+
246298
spdlog::logger*
247299
get()
248300
{
@@ -252,17 +304,20 @@ get()
252304
void
253305
reset()
254306
{
255-
spdlog::drop(logger_name);
307+
spdlog::drop(file_logger_name);
256308
file_logger.reset();
309+
310+
spdlog::drop(protocol_logger_name);
311+
protocol_logger.reset();
257312
}
258313

259314
void
260315
create_blackhole_logger()
261316
{
262317
// delete if already exists
263-
spdlog::drop(logger_name);
318+
spdlog::drop(file_logger_name);
264319

265-
file_logger = std::make_shared<spdlog::logger>(logger_name, std::make_shared<spdlog::sinks::null_sink_mt>());
320+
file_logger = std::make_shared<spdlog::logger>(file_logger_name, std::make_shared<spdlog::sinks::null_sink_mt>());
266321

267322
file_logger->set_level(spdlog::level::off);
268323
file_logger->set_pattern(log_pattern);
@@ -274,11 +329,11 @@ void
274329
create_console_logger()
275330
{
276331
// delete if already exists
277-
spdlog::drop(logger_name);
332+
spdlog::drop(file_logger_name);
278333

279334
auto stderrsink = std::make_shared<spdlog::sinks::stderr_color_sink_mt>();
280335

281-
file_logger = std::make_shared<spdlog::logger>(logger_name, stderrsink);
336+
file_logger = std::make_shared<spdlog::logger>(file_logger_name, stderrsink);
282337
file_logger->set_level(spdlog::level::info);
283338
file_logger->set_pattern(log_pattern);
284339

@@ -322,8 +377,13 @@ void
322377
set_log_levels(level lvl)
323378
{
324379
auto level = translate_level(lvl);
325-
// Apply the function to each registered spdlog::logger
380+
// Apply the function to each registered spdlog::logger except protocol logger
326381
spdlog::apply_all([level](std::shared_ptr<spdlog::logger> l) {
382+
if (l->name() == protocol_logger_name) {
383+
l->set_level(spdlog::level::trace);
384+
return;
385+
}
386+
327387
try {
328388
l->set_level(level);
329389
} catch (const spdlog::spdlog_ex& e) {

0 commit comments

Comments
 (0)