diff --git a/llarp/CMakeLists.txt b/llarp/CMakeLists.txt index 21504ed4c..161795de6 100644 --- a/llarp/CMakeLists.txt +++ b/llarp/CMakeLists.txt @@ -8,6 +8,7 @@ add_library(lokinet-util util/fs.cpp util/json.cpp util/logging/android_logger.cpp + util/logging/buffer.cpp util/logging/file_logger.cpp util/logging/json_logger.cpp util/logging/logger.cpp diff --git a/llarp/util/logging/buffer.cpp b/llarp/util/logging/buffer.cpp new file mode 100644 index 000000000..59a75d771 --- /dev/null +++ b/llarp/util/logging/buffer.cpp @@ -0,0 +1,45 @@ +#include "buffer.hpp" +#include +#include + +namespace llarp { + std::ostream& + operator<<(std::ostream& o, const buffer_printer& bp) + { + auto& b = bp.buf; + auto oldfill = o.fill(); + o.fill('0'); + o << "Buffer[" << b.size() << "/0x" << std::hex << b.size() << " bytes]:"; + for (size_t i = 0; i < b.size(); i += 32) + { + o << "\n" << std::setw(4) << i << " "; + + size_t stop = std::min(b.size(), i + 32); + for (size_t j = 0; j < 32; j++) + { + auto k = i + j; + if (j % 4 == 0) + o << ' '; + if (k >= stop) + o << " "; + else + o << std::setw(2) << std::to_integer(b[k]); + } + o << u8" โ”ƒ"; + for (size_t j = i; j < stop; j++) + { + auto c = std::to_integer(b[j]); + if (c == 0x00) + o << u8"โˆ…"; + else if (c < 0x20 || c > 0x7e) + o << u8"ยท"; + else + o << c; + } + o << u8"โ”ƒ"; + } + o << std::dec; + o.fill(oldfill); + return o; + } +} diff --git a/llarp/util/logging/buffer.hpp b/llarp/util/logging/buffer.hpp new file mode 100644 index 000000000..362714b7e --- /dev/null +++ b/llarp/util/logging/buffer.hpp @@ -0,0 +1,52 @@ +#pragma once + +#include + +#include +#include +#include +#include + +namespace llarp +{ + // Buffer printer lets you print a string as a nicely formatted buffer with a hex breakdown and + // visual representation of the data for logging purposes. Wraps the string data with a object + // that prints the buffer format during output; use as: + // + // out << buffer_printer(my_buffer); + // + struct buffer_printer + { + std::basic_string_view buf; + + // Constructed from any type of string_view for a single-byte T (char, std::byte, uint8_t, + // etc.) + template > + explicit buffer_printer(std::basic_string_view buf) + : buf{reinterpret_cast(buf.data()), buf.size()} + {} + + // Constructed from any type of lvalue string for a single-byte T (char, std::byte, uint8_t, etc.) + template > + explicit buffer_printer(const std::basic_string& buf) + : buffer_printer(std::basic_string_view{buf}) + {} + + // *Not* constructable from a string rvalue (because we only hold a view and do not take ownership). + template > + explicit buffer_printer(std::basic_string&& buf) = delete; + + // Constructable from a (T*, size) argument pair, for byte-sized T's. + template > + explicit buffer_printer(const T* data, size_t size) + : buffer_printer(std::basic_string_view{data, size}) + {} + + // llarp_buffer_t printer: + explicit buffer_printer(const llarp_buffer_t& buf) + : buffer_printer(std::basic_string_view{buf.base, buf.sz}) + {} + }; + std::ostream& + operator<<(std::ostream& o, const buffer_printer& bp); +}