Add GWBUF pretty-printing
The gwbuf_hexdump_pretty displays the hex contents of the buffer alongside the human-readable version of it. The text version helps identify parts of the buffer that contain text which makes protocol data decoding easier.
This commit is contained in:
@ -165,7 +165,7 @@ inline bool gwbuf_is_contiguous(const GWBUF* b)
|
|||||||
/*< True if all bytes in the buffer have been consumed */
|
/*< True if all bytes in the buffer have been consumed */
|
||||||
inline bool gwbuf_link_empty(const GWBUF* b)
|
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)
|
#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
|
* Debug function for dumping buffer contents to log
|
||||||
*
|
*
|
||||||
|
* @see mxs::Buffer::hexdump
|
||||||
|
*
|
||||||
* @param buffer Buffer to dump
|
* @param buffer Buffer to dump
|
||||||
* @param log_level Log priority where the message is written
|
* @param log_level Log priority where the message is written
|
||||||
*/
|
*/
|
||||||
void gwbuf_hexdump(GWBUF* buffer, int log_level);
|
void gwbuf_hexdump(GWBUF* buffer, int log_level = LOG_INFO);
|
||||||
void gwbuf_hexdump(const mxs::Buffer& buffer, int log_level);
|
|
||||||
|
/**
|
||||||
|
* 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
|
* 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:
|
private:
|
||||||
// To prevent @c Buffer from being created on the heap.
|
// To prevent @c Buffer from being created on the heap.
|
||||||
void* operator new(size_t); // standard new
|
void* operator new(size_t); // standard new
|
||||||
|
@ -29,7 +29,7 @@ static void gwbuf_free_one(GWBUF* buf);
|
|||||||
static buffer_object_t* gwbuf_remove_buffer_object(GWBUF* buf,
|
static buffer_object_t* gwbuf_remove_buffer_object(GWBUF* buf,
|
||||||
buffer_object_t* bufobj);
|
buffer_object_t* bufobj);
|
||||||
|
|
||||||
#if defined(SS_DEBUG)
|
#if defined (SS_DEBUG)
|
||||||
inline void invalidate_tail_pointers(GWBUF* head)
|
inline void invalidate_tail_pointers(GWBUF* head)
|
||||||
{
|
{
|
||||||
if (head && head->next)
|
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());
|
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<mxs::Buffer&>(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());
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user