diff --git a/include/maxscale/buffer.hh b/include/maxscale/buffer.hh index 77d6b3993..d9458b6ce 100644 --- a/include/maxscale/buffer.hh +++ b/include/maxscale/buffer.hh @@ -165,7 +165,7 @@ inline bool gwbuf_is_contiguous(const GWBUF* b) /*< True if all bytes in the buffer have been consumed */ inline bool gwbuf_link_empty(const GWBUF* b) { - return ((char*)b->start >= (char*)b->end); + return (char*)b->start >= (char*)b->end; } #define GWBUF_EMPTY(b) gwbuf_link_empty(b) @@ -422,11 +422,22 @@ extern void dprintAllBuffers(void* pdcb); /** * Debug function for dumping buffer contents to log * + * @see mxs::Buffer::hexdump + * * @param buffer Buffer to dump * @param log_level Log priority where the message is written */ -void gwbuf_hexdump(GWBUF* buffer, int log_level); -void gwbuf_hexdump(const mxs::Buffer& buffer, int log_level); +void gwbuf_hexdump(GWBUF* buffer, int log_level = LOG_INFO); + +/** + * Debug function for pretty-printing buffer contents to log + * + * @see mxs::Buffer::hexdump_pretty + * + * @param buffer Buffer to dump + * @param log_level Log priority where the message is written + */ +void gwbuf_hexdump_pretty(GWBUF* buffer, int log_level = LOG_INFO); /** * Return pointer of the byte at offset from start of chained buffer @@ -1213,6 +1224,24 @@ public: } } + /** + * Debug function for dumping buffer contents to log + * + * Prints contents as hexadecimal. Only the first 1024 bytes are dumped to avoid filling up the log. + * + * @param log_level Log priority where the message is written + */ + void hexdump(int log_level = LOG_INFO) const; + + /** + * Debug function for pretty-printing buffer contents to log + * + * The output format is similar to `hexdump -C` and provides both hex and human-readable values. + * + * @param log_level Log priority where the message is written + */ + void hexdump_pretty(int log_level = LOG_INFO) const; + private: // To prevent @c Buffer from being created on the heap. void* operator new(size_t); // standard new diff --git a/server/core/buffer.cc b/server/core/buffer.cc index 4548ec9f9..c897baa08 100644 --- a/server/core/buffer.cc +++ b/server/core/buffer.cc @@ -29,7 +29,7 @@ static void gwbuf_free_one(GWBUF* buf); static buffer_object_t* gwbuf_remove_buffer_object(GWBUF* buf, buffer_object_t* bufobj); -#if defined(SS_DEBUG) +#if defined (SS_DEBUG) inline void invalidate_tail_pointers(GWBUF* head) { if (head && head->next) @@ -845,7 +845,55 @@ void gwbuf_hexdump(GWBUF* buffer, int log_level) MXS_LOG_MESSAGE(log_level, "%.*s", n, ss.str().c_str()); } -void gwbuf_hexdump(const mxs::Buffer& buffer, int log_level) +void gwbuf_hexdump_pretty(GWBUF* buffer, int log_level) { - return gwbuf_hexdump(const_cast(buffer).get(), log_level); + mxs::Buffer buf(buffer); + buf.hexdump_pretty(log_level); + buf.release(); +} + +void mxs::Buffer::hexdump(int log_level) const +{ + return gwbuf_hexdump(m_pBuffer, log_level); +} + +void mxs::Buffer::hexdump_pretty(int log_level) const +{ + constexpr const char as_hex[] = "0123456789abcdefghijklmnopqrstuvwxyz"; + std::string result = "\n"; + std::string hexed; + std::string readable; + auto it = begin(); + + while (it != end()) + { + for (int i = 0; i < 16 && it != end(); i++) + { + uint8_t c = *it; + hexed += as_hex[c >> 4]; + hexed += as_hex[c & 0x0f]; + hexed += ' '; + readable += isprint(c) && (!isspace(c) || c == ' ') ? (char)c : '.'; + ++it; + } + + if (readable.length() < 16) + { + hexed.append(48 - hexed.length(), ' '); + readable.append(16 - readable.length(), ' '); + } + + mxb_assert(hexed.length() == readable.length() * 3); + result += hexed.substr(0, 24); + result += " "; + result += hexed.substr(24); + result += " "; + result += readable; + result += '\n'; + + hexed.clear(); + readable.clear(); + } + + MXS_LOG_MESSAGE(log_level, "%s", result.c_str()); }