mirror of
https://github.com/Xahau/xahaud.git
synced 2025-11-04 10:45:50 +00:00
feat(logging): add flexible log formatting and positioning options
- Add LOG_LOCATION_POSITION env var to control file:line placement (prefix/suffix/none) - Add LOG_DATE_FORMAT env var for custom timestamp formats (supports date::format syntax) - Add LOG_DATE_LOCAL env var to use local timezone instead of UTC - Add LOG_LOCATION_ESCAPE env var for custom colors (red/green/cyan/etc) - Default to suffix position for better readability - Move implementation to .cpp files to reduce recompilation - Update zlib to 1.3.1 to fix macOS build issues - Enable date-tz library for timezone support
This commit is contained in:
@@ -9,6 +9,9 @@
|
||||
|
||||
find_package (date QUIET)
|
||||
if (NOT TARGET date::date)
|
||||
# Tell date to build the timezone library
|
||||
set(BUILD_TZ_LIB ON CACHE BOOL "Build date-tz library")
|
||||
|
||||
FetchContent_Declare(
|
||||
hh_date_src
|
||||
GIT_REPOSITORY https://github.com/HowardHinnant/date.git
|
||||
|
||||
@@ -35,7 +35,7 @@ class Xrpl(ConanFile):
|
||||
'snappy/1.1.10',
|
||||
'soci/4.0.3',
|
||||
'sqlite3/3.42.0',
|
||||
'zlib/1.2.13',
|
||||
'zlib/1.3.1',
|
||||
'wasmedge/0.11.2',
|
||||
]
|
||||
|
||||
@@ -52,7 +52,7 @@ class Xrpl(ConanFile):
|
||||
'unity': False,
|
||||
|
||||
'cassandra-cpp-driver:shared': False,
|
||||
'date:header_only': True,
|
||||
'date:header_only': False,
|
||||
'grpc:shared': False,
|
||||
'grpc:secure': True,
|
||||
'libarchive:shared': False,
|
||||
|
||||
@@ -17,11 +17,16 @@
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#include <date/date.h>
|
||||
#include <date/tz.h>
|
||||
|
||||
#include <ripple/basics/Log.h>
|
||||
#include <ripple/basics/chrono.h>
|
||||
#include <ripple/basics/contract.h>
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
#include <ctime>
|
||||
#include <fstream>
|
||||
#include <functional>
|
||||
#include <iostream>
|
||||
@@ -316,9 +321,35 @@ Logs::format(
|
||||
{
|
||||
output.reserve(message.size() + partition.size() + 100);
|
||||
|
||||
output = to_string(std::chrono::system_clock::now());
|
||||
#ifdef LOG_LINE_NUMBERS
|
||||
static const char* fmt = []() {
|
||||
const char* env = std::getenv("LOG_DATE_FORMAT");
|
||||
return env ? env : "%Y-%b-%d %T %Z"; // Default format
|
||||
}();
|
||||
|
||||
// Check if we should use local time
|
||||
static const bool useLocalTime = []() {
|
||||
const char* env = std::getenv("LOG_DATE_LOCAL");
|
||||
return env && std::strcmp(env, "1") == 0;
|
||||
}();
|
||||
|
||||
if (useLocalTime)
|
||||
{
|
||||
auto now = std::chrono::system_clock::now();
|
||||
auto local = date::make_zoned(date::current_zone(), now);
|
||||
output = date::format(fmt, local);
|
||||
}
|
||||
else
|
||||
{
|
||||
output = date::format(fmt, std::chrono::system_clock::now());
|
||||
}
|
||||
#else
|
||||
output = to_string(std::chrono::system_clock::now());
|
||||
#endif
|
||||
|
||||
if (!output.empty()) // Allow setting date format to an empty string
|
||||
output += " ";
|
||||
|
||||
output += " ";
|
||||
if (!partition.empty())
|
||||
output += partition + ":";
|
||||
|
||||
|
||||
@@ -146,6 +146,10 @@ private:
|
||||
|
||||
ScopedStream(Sink& sink, Severity level);
|
||||
|
||||
#ifdef LOG_LINE_NUMBERS
|
||||
ScopedStream(Sink& sink, Severity level, const char* file, int line);
|
||||
#endif
|
||||
|
||||
template <typename T>
|
||||
ScopedStream(Stream const& stream, T const& t);
|
||||
|
||||
@@ -173,6 +177,10 @@ private:
|
||||
Sink& m_sink;
|
||||
Severity const m_level;
|
||||
std::ostringstream mutable m_ostream;
|
||||
#ifdef LOG_LINE_NUMBERS
|
||||
const char* file_ = nullptr;
|
||||
int line_ = 0;
|
||||
#endif
|
||||
};
|
||||
|
||||
#ifndef __INTELLISENSE__
|
||||
@@ -212,11 +220,6 @@ public:
|
||||
operator<<(std::ostream& manip(std::ostream&)) const;
|
||||
|
||||
private:
|
||||
// Helper to write the location prefix (implemented after detail
|
||||
// namespace)
|
||||
void
|
||||
writeLocationPrefix(ScopedStream& s) const;
|
||||
|
||||
const char* file_;
|
||||
int line_;
|
||||
const Stream& stream_;
|
||||
@@ -398,6 +401,8 @@ static_assert(std::is_nothrow_destructible<Journal>::value == true, "");
|
||||
#ifdef LOG_LINE_NUMBERS
|
||||
namespace detail {
|
||||
// Helper to strip source root path from __FILE__ at compile time
|
||||
// IMPORTANT: This MUST stay in the header as constexpr for compile-time
|
||||
// evaluation!
|
||||
constexpr const char*
|
||||
stripSourceRoot(const char* file)
|
||||
{
|
||||
@@ -474,9 +479,8 @@ template <typename T>
|
||||
Journal::ScopedStream
|
||||
Journal::StreamWithLocation::operator<<(T const& t) const
|
||||
{
|
||||
// Create a ScopedStream and inject the location info first
|
||||
ScopedStream scoped(stream_.sink(), stream_.level());
|
||||
writeLocationPrefix(scoped);
|
||||
// Create a ScopedStream with location info
|
||||
ScopedStream scoped(stream_.sink(), stream_.level(), file_, line_);
|
||||
scoped.ostream() << t;
|
||||
return scoped;
|
||||
}
|
||||
|
||||
@@ -136,37 +136,51 @@ Journal::ScopedStream::ScopedStream(
|
||||
m_ostream << manip;
|
||||
}
|
||||
|
||||
Journal::ScopedStream::~ScopedStream()
|
||||
{
|
||||
std::string const& s(m_ostream.str());
|
||||
if (!s.empty())
|
||||
{
|
||||
if (s == "\n")
|
||||
m_sink.write(m_level, "");
|
||||
else
|
||||
m_sink.write(m_level, s);
|
||||
}
|
||||
}
|
||||
|
||||
std::ostream&
|
||||
Journal::ScopedStream::operator<<(std::ostream& manip(std::ostream&)) const
|
||||
{
|
||||
return m_ostream << manip;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
Journal::ScopedStream
|
||||
Journal::Stream::operator<<(std::ostream& manip(std::ostream&)) const
|
||||
{
|
||||
return ScopedStream(*this, manip);
|
||||
}
|
||||
|
||||
#ifdef LOG_LINE_NUMBERS
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace detail {
|
||||
|
||||
// Location position enum
|
||||
enum class LocationPosition { PREFIX, SUFFIX, NONE };
|
||||
|
||||
// Get configured position - cached at startup
|
||||
LocationPosition
|
||||
getLocationPosition()
|
||||
{
|
||||
static const LocationPosition position = []() {
|
||||
const char* env = std::getenv("LOG_LOCATION_POSITION");
|
||||
if (!env)
|
||||
return LocationPosition::SUFFIX; // Default to suffix for better
|
||||
// readability
|
||||
|
||||
if (std::strcmp(env, "suffix") == 0 || std::strcmp(env, "end") == 0)
|
||||
return LocationPosition::SUFFIX;
|
||||
if (std::strcmp(env, "prefix") == 0 || std::strcmp(env, "start") == 0)
|
||||
return LocationPosition::PREFIX;
|
||||
if (std::strcmp(env, "none") == 0)
|
||||
return LocationPosition::NONE;
|
||||
|
||||
return LocationPosition::PREFIX;
|
||||
}();
|
||||
return position;
|
||||
}
|
||||
|
||||
// Helper to write location string (no leading/trailing space)
|
||||
void
|
||||
writeLocationString(std::ostream& os, const char* file, int line)
|
||||
{
|
||||
if (detail::shouldUseColors())
|
||||
{
|
||||
os << detail::getLocationEscape() << "["
|
||||
<< detail::stripSourceRoot(file) << ":" << line << "]\033[0m";
|
||||
}
|
||||
else
|
||||
{
|
||||
os << "[" << detail::stripSourceRoot(file) << ":" << line << "]";
|
||||
}
|
||||
}
|
||||
|
||||
// Check if we should use colors - cached at startup
|
||||
bool
|
||||
shouldUseColors()
|
||||
@@ -225,30 +239,80 @@ getLocationEscape()
|
||||
|
||||
} // namespace detail
|
||||
|
||||
// Implementation of writeLocationPrefix helper
|
||||
void
|
||||
Journal::StreamWithLocation::writeLocationPrefix(ScopedStream& s) const
|
||||
#endif
|
||||
|
||||
#ifdef LOG_LINE_NUMBERS
|
||||
Journal::ScopedStream::ScopedStream(
|
||||
Sink& sink,
|
||||
Severity level,
|
||||
const char* file,
|
||||
int line)
|
||||
: m_sink(sink), m_level(level), file_(file), line_(line)
|
||||
{
|
||||
if (detail::shouldUseColors())
|
||||
// Modifiers applied from all ctors
|
||||
m_ostream << std::boolalpha << std::showbase;
|
||||
|
||||
// Write prefix if configured
|
||||
if (file_ &&
|
||||
detail::getLocationPosition() == detail::LocationPosition::PREFIX)
|
||||
{
|
||||
s.ostream() << detail::getLocationEscape() << "["
|
||||
<< detail::stripSourceRoot(file_) << ":" << line_
|
||||
<< "]\033[0m ";
|
||||
detail::writeLocationString(m_ostream, file_, line_);
|
||||
m_ostream << " ";
|
||||
}
|
||||
else
|
||||
}
|
||||
#endif
|
||||
|
||||
Journal::ScopedStream::~ScopedStream()
|
||||
{
|
||||
std::string s(m_ostream.str());
|
||||
|
||||
#ifdef LOG_LINE_NUMBERS
|
||||
// Add suffix if configured
|
||||
if (file_ &&
|
||||
detail::getLocationPosition() == detail::LocationPosition::SUFFIX &&
|
||||
!s.empty() && s != "\n")
|
||||
{
|
||||
s.ostream() << "[" << detail::stripSourceRoot(file_) << ":" << line_
|
||||
<< "] ";
|
||||
std::ostringstream combined;
|
||||
combined << s;
|
||||
if (!s.empty() && s.back() != ' ')
|
||||
combined << " ";
|
||||
detail::writeLocationString(combined, file_, line_);
|
||||
s = combined.str();
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!s.empty())
|
||||
{
|
||||
if (s == "\n")
|
||||
m_sink.write(m_level, "");
|
||||
else
|
||||
m_sink.write(m_level, s);
|
||||
}
|
||||
}
|
||||
|
||||
std::ostream&
|
||||
Journal::ScopedStream::operator<<(std::ostream& manip(std::ostream&)) const
|
||||
{
|
||||
return m_ostream << manip;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
Journal::ScopedStream
|
||||
Journal::Stream::operator<<(std::ostream& manip(std::ostream&)) const
|
||||
{
|
||||
return ScopedStream(*this, manip);
|
||||
}
|
||||
|
||||
#ifdef LOG_LINE_NUMBERS
|
||||
|
||||
// Implementation moved to use new constructor
|
||||
Journal::ScopedStream
|
||||
Journal::StreamWithLocation::operator<<(
|
||||
std::ostream& manip(std::ostream&)) const
|
||||
{
|
||||
// Create a ScopedStream and inject the location info first
|
||||
ScopedStream scoped(stream_.sink(), stream_.level());
|
||||
writeLocationPrefix(scoped);
|
||||
// Create a ScopedStream with location info
|
||||
ScopedStream scoped(stream_.sink(), stream_.level(), file_, line_);
|
||||
scoped.ostream() << manip;
|
||||
return scoped;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user