Skip to content

Commit

Permalink
Improvements to loguru for rack extensions
Browse files Browse the repository at this point in the history
  • Loading branch information
ypujante committed Jan 23, 2022
1 parent 99e1d9e commit 3e084a2
Show file tree
Hide file tree
Showing 6 changed files with 176 additions and 17 deletions.
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -318,6 +318,13 @@ It is strongly recommended checking the [re-blank-plugin](https://github.com/pon

Release notes
-------------
#### 1.4.1 - 2022/01/23

- Added `JBOX_LOGVALUES` (simpler api than `JBOX_TRACEVALUES`)
- Added `loguru::init_for_re` to make loguru output nicer for Rack Extensions (replace (useless) thread by RE name)
- Added `loguru::init_for_test` to make loguru throw exception instead of aborting when running tests
- Added generic `loguru::add_preamble_handler` to display any kind of information when logging

#### 1.4.0 - 2022/01/22

- Introduced `main.cmake` with convenient macros to make writing the `CMakeLists.txt` file for the plugin easier and less error-prone
Expand Down
2 changes: 1 addition & 1 deletion cmake/RECMakeOptions.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

set(RE_CMAKE_MAJOR_VERSION 1)
set(RE_CMAKE_MINOR_VERSION 4)
set(RE_CMAKE_PATCH_VERSION 0)
set(RE_CMAKE_PATCH_VERSION 1)

# Location of RE SDK: can be set when invoking cmake => cmake -D "RE_SDK_ROOT:PATH=/path/to/re_sdk"
# or via -p option in configure.py script or in cmake-gui
Expand Down
10 changes: 3 additions & 7 deletions re-logging/src/cpp/logging/logging.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,13 +56,9 @@ inline void JBox_LogValues(const char iFile[], TJBox_Int32 iLine, char const *iM
namespace loguru {
/**
* This function can be called when the device is created to make loguru output nicer (essentially replaces
* the name of the thread which is useless, by the name of the rack extension which can be useful when you
* have different REs using loguru) */
inline void init_for_re(char const *iREName = nullptr)
{
loguru::g_preamble_thread = false;
// loguru::g_preamble_prefix = iREName;
}
* the name of the thread which is useless, by the name of the rack extension which can be useful when there
* are different REs using loguru) */
void init_for_re(char const *iREName = nullptr);

/**
* This function can be used from tests to replace loguru aborts with exception (which can be checked) */
Expand Down
140 changes: 133 additions & 7 deletions re-logging/src/cpp/logging/loguru.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,9 @@
#ifndef LOGURU_HAS_BEEN_IMPLEMENTED
#define LOGURU_HAS_BEEN_IMPLEMENTED

#define LOGURU_PREAMBLE_WIDTH (53 + LOGURU_THREADNAME_WIDTH + LOGURU_FILENAME_WIDTH)
#ifndef LOGURU_PREAMBLE_WIDTH
#define LOGURU_PREAMBLE_WIDTH 256
#endif

#undef min
#undef max
Expand Down Expand Up @@ -198,6 +200,8 @@ namespace loguru
static bool s_strip_file_path = true;
static std::atomic<unsigned> s_stderr_indentation { 0 };

static std::unique_ptr<preamble_handler_t> s_preambles[8]{};

// For periodic flushing:
static std::thread* s_flush_thread = nullptr;
static bool s_needs_flushing = false;
Expand Down Expand Up @@ -843,7 +847,24 @@ namespace loguru
on_callback_change();
}

// Returns a custom verbosity name if one is available, or nullptr.
bool add_preamble_handler(
int position, // [0-7]
std::unique_ptr<preamble_handler_t> preamble_handler)
{
if(position >= 0 && position <= 7)
{
std::lock_guard<std::recursive_mutex> lock(s_mutex);
s_preambles[position] = std::move(preamble_handler);
return true;
}
else
{
LOG_F(ERROR, "Failed to add preamble handler: position must be [0-7]");
return false;
}
}

// Returns a custom verbosity name if one is available, or nullptr.
// See also set_verbosity_to_name_callback.
const char* get_verbosity_name(Verbosity verbosity)
{
Expand Down Expand Up @@ -1155,28 +1176,60 @@ namespace loguru
{
if (out_buff_size == 0) { return; }
out_buff[0] = '\0';
long pos = 0;
size_t pos = 0;
size_t preamble = 0;
if(s_preambles[preamble] && pos < out_buff_size) {
pos += s_preambles[preamble]->header(out_buff + pos, out_buff_size - pos);
}
if (g_preamble_date && pos < out_buff_size) {
pos += snprintf(out_buff + pos, out_buff_size - pos, "date ");
}
preamble++;
if(s_preambles[preamble] && pos < out_buff_size) {
pos += s_preambles[preamble]->header(out_buff + pos, out_buff_size - pos);
}
if (g_preamble_time && pos < out_buff_size) {
pos += snprintf(out_buff + pos, out_buff_size - pos, "time ");
}
preamble++;
if(s_preambles[preamble] && pos < out_buff_size) {
pos += s_preambles[preamble]->header(out_buff + pos, out_buff_size - pos);
}
if (g_preamble_uptime && pos < out_buff_size) {
pos += snprintf(out_buff + pos, out_buff_size - pos, "( uptime ) ");
}
preamble++;
if(s_preambles[preamble] && pos < out_buff_size) {
pos += s_preambles[preamble]->header(out_buff + pos, out_buff_size - pos);
}
if (g_preamble_thread && pos < out_buff_size) {
pos += snprintf(out_buff + pos, out_buff_size - pos, "[%-*s]", LOGURU_THREADNAME_WIDTH, " thread name/id");
}
preamble++;
if(s_preambles[preamble] && pos < out_buff_size) {
pos += s_preambles[preamble]->header(out_buff + pos, out_buff_size - pos);
}
if (g_preamble_file && pos < out_buff_size) {
pos += snprintf(out_buff + pos, out_buff_size - pos, "%*s:line ", LOGURU_FILENAME_WIDTH, "file");
}
preamble++;
if(s_preambles[preamble] && pos < out_buff_size) {
pos += s_preambles[preamble]->header(out_buff + pos, out_buff_size - pos);
}
if (g_preamble_verbose && pos < out_buff_size) {
pos += snprintf(out_buff + pos, out_buff_size - pos, " v");
}
preamble++;
if(s_preambles[preamble] && pos < out_buff_size) {
pos += s_preambles[preamble]->header(out_buff + pos, out_buff_size - pos);
}
if (g_preamble_pipe && pos < out_buff_size) {
pos += snprintf(out_buff + pos, out_buff_size - pos, "| ");
}
preamble++;
if(s_preambles[preamble] && pos < out_buff_size) {
pos += s_preambles[preamble]->header(out_buff + pos, out_buff_size - pos);
}
}

static void print_preamble(char* out_buff, size_t out_buff_size, Verbosity verbosity, const char* file, unsigned line)
Expand Down Expand Up @@ -1207,37 +1260,69 @@ namespace loguru
snprintf(level_buff, sizeof(level_buff) - 1, "% 4d", verbosity);
}

long pos = 0;
size_t pos = 0;
size_t preamble = 0;

if (g_preamble_date && pos < out_buff_size) {
if(s_preambles[preamble] && pos < out_buff_size) {
pos += s_preambles[preamble]->entry(out_buff + pos, out_buff_size - pos);
}
if (g_preamble_date && pos < out_buff_size) {
pos += snprintf(out_buff + pos, out_buff_size - pos, "%04d-%02d-%02d ",
1900 + time_info.tm_year, 1 + time_info.tm_mon, time_info.tm_mday);
}
preamble++;
if(s_preambles[preamble] && pos < out_buff_size) {
pos += s_preambles[preamble]->entry(out_buff + pos, out_buff_size - pos);
}
if (g_preamble_time && pos < out_buff_size) {
pos += snprintf(out_buff + pos, out_buff_size - pos, "%02d:%02d:%02d.%03lld ",
time_info.tm_hour, time_info.tm_min, time_info.tm_sec, ms_since_epoch % 1000);
}
preamble++;
if(s_preambles[preamble] && pos < out_buff_size) {
pos += s_preambles[preamble]->entry(out_buff + pos, out_buff_size - pos);
}
if (g_preamble_uptime && pos < out_buff_size) {
pos += snprintf(out_buff + pos, out_buff_size - pos, "(%8.3fs) ",
uptime_sec);
}
preamble++;
if(s_preambles[preamble] && pos < out_buff_size) {
pos += s_preambles[preamble]->entry(out_buff + pos, out_buff_size - pos);
}
if (g_preamble_thread && pos < out_buff_size) {
pos += snprintf(out_buff + pos, out_buff_size - pos, "[%-*s]",
LOGURU_THREADNAME_WIDTH, thread_name);
}
preamble++;
if(s_preambles[preamble] && pos < out_buff_size) {
pos += s_preambles[preamble]->entry(out_buff + pos, out_buff_size - pos);
}
if (g_preamble_file && pos < out_buff_size) {
char shortened_filename[LOGURU_FILENAME_WIDTH + 1];
snprintf(shortened_filename, LOGURU_FILENAME_WIDTH + 1, "%s", file);
pos += snprintf(out_buff + pos, out_buff_size - pos, "%*s:%-5u ",
LOGURU_FILENAME_WIDTH, shortened_filename, line);
}
preamble++;
if(s_preambles[preamble] && pos < out_buff_size) {
pos += s_preambles[preamble]->entry(out_buff + pos, out_buff_size - pos);
}
if (g_preamble_verbose && pos < out_buff_size) {
pos += snprintf(out_buff + pos, out_buff_size - pos, "%4s",
level_buff);
}
preamble++;
if(s_preambles[preamble] && pos < out_buff_size) {
pos += s_preambles[preamble]->entry(out_buff + pos, out_buff_size - pos);
}
if (g_preamble_pipe && pos < out_buff_size) {
pos += snprintf(out_buff + pos, out_buff_size - pos, "| ");
}
preamble++;
if(s_preambles[preamble] && pos < out_buff_size) {
pos += s_preambles[preamble]->entry(out_buff + pos, out_buff_size - pos);
}
}

// stack_trace_skip is just if verbosity == FATAL.
Expand Down Expand Up @@ -1862,18 +1947,59 @@ namespace loguru
}
}

struct static_string_preamble_handler_t : public preamble_handler_t
{
static_string_preamble_handler_t(char const *iHeader, char const *iEntry) :
fHeader{iHeader ? iHeader : ""}, fEntry{iEntry ? iEntry : ""} {}

size_t header(char *buffer, size_t buffer_size) override
{
if(fHeader.empty())
return 0;
else
return snprintf(buffer, buffer_size, "%-*s", static_cast<int>(std::max(fHeader.size(), fEntry.size())), fHeader.c_str());
}

size_t entry(char *buffer, size_t buffer_size) override
{
if(fEntry.empty())
return 0;
else
return snprintf(buffer, buffer_size, "%s", fEntry.c_str());
}

private:
std::string fHeader;
std::string fEntry;
};

//------------------------------------------------------------------------
// init_for_test
//------------------------------------------------------------------------
void init_for_test(char const *iPrefix)
{
loguru::g_preamble_thread = false;
// loguru::g_preamble_prefix = iPrefix;
if(iPrefix)
{
loguru::g_preamble_thread = false;
loguru::add_preamble_handler(4, std::make_unique<static_string_preamble_handler_t>(iPrefix, iPrefix));
}
loguru::set_fatal_handler([](const loguru::Message& message) {
throw std::runtime_error(std::string(message.prefix) + message.message);
});
}

//------------------------------------------------------------------------
// init_for_re
//------------------------------------------------------------------------
void init_for_re(char const *iREName)
{
loguru::g_preamble_thread = false; // thread is useless in the context of REs!
if(iREName)
{
loguru::add_preamble_handler(4, std::make_unique<static_string_preamble_handler_t>("[Device]", iREName));
}
}

} // namespace loguru

#endif // _WIN32
Expand Down
22 changes: 21 additions & 1 deletion re-logging/src/cpp/logging/loguru.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,8 @@ Website: www.ilikebigbits.com

// --------------------------------------------------------------------

#include <memory>

namespace loguru
{
// Simple RAII ownership of a char*.
Expand Down Expand Up @@ -375,7 +377,25 @@ namespace loguru
LOGURU_EXPORT extern bool g_preamble_verbose; // The verbosity field
LOGURU_EXPORT extern bool g_preamble_pipe; // The pipe symbol right before the message

// May not throw!
struct preamble_handler_t
{
// Render the header in the buffer and return the number of chars written
virtual size_t header(char *buffer, size_t buffer_size) = 0;

// Render the entry in the buffer and return the number of chars written
virtual size_t entry(char *buffer, size_t buffer_size) = 0;

virtual ~preamble_handler_t() = default;
};

// Add a preamble handler. The position refers to where it is located: 0 means before g_preamble_date, 1 means
// before g_preamble_time, etc...
LOGURU_EXPORT
bool add_preamble_handler(
int position, // [0-7]
std::unique_ptr<preamble_handler_t> preamble_handler);

// May not throw!
typedef void (*log_handler_t)(void* user_data, const Message& message);
typedef void (*close_handler_t)(void* user_data);
typedef void (*flush_handler_t)(void* user_data);
Expand Down
12 changes: 11 additions & 1 deletion test/cpp/re-logging/TestLogging.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,16 @@
TEST(Logging, init_for_test)
{
// init_for_test changes abort into exception that can be caught
loguru::init_for_test();
loguru::init_for_test("[Logging.init_for_test]");
ASSERT_THROW(loguru::log_and_abort(0, "test", __FILE__, __LINE__), std::runtime_error);
DLOG_F(INFO, "output 1");
DLOG_F(INFO, "output 2");
}

TEST(Logging, init_for_re)
{
// init_for_re displays the name of the re
loguru::init_for_re("[My RE]");
DLOG_F(INFO, "output 1");
DLOG_F(INFO, "output 2");
}

0 comments on commit 3e084a2

Please sign in to comment.