Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update default log formats to escape messages using JSON encoding rules #116

Merged
merged 27 commits into from
May 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
756aafd
added initial json logging format
nnshah1 Apr 19, 2024
c5eb21f
force error to be uint8_t storage type
nnshah1 Apr 19, 2024
e5a682e
updated
nnshah1 Apr 19, 2024
16ecd88
updating to allow escaping in current log formats
nnshah1 Apr 20, 2024
f812f8e
adding support for escaping log messages
nnshah1 May 11, 2024
1714c90
adding logging macros for JSON
nnshah1 May 14, 2024
c75d8a6
updated comment
nnshah1 May 14, 2024
fc3ef22
reverting format changes (usec and bracket)
nnshah1 May 15, 2024
18e7055
update based on review comments
nnshah1 May 15, 2024
b018f4b
updated based on review comments
nnshah1 May 15, 2024
e808c04
updated based on review comment
nnshah1 May 15, 2024
b9a037f
remove blank line
nnshah1 May 15, 2024
8eb29df
escape heading for uniformity
nnshah1 May 15, 2024
9fe0e4c
reverting - for proper handling need to move to LogMessage class
nnshah1 May 16, 2024
353b904
removing macros for logging JSON messages - will addd as seperate PR
nnshah1 May 16, 2024
6d57a83
updated for typo
nnshah1 May 16, 2024
e3d721d
updated
nnshah1 May 16, 2024
1b159ba
update remove blank lines
nnshah1 May 16, 2024
b0cd3c9
updated based on comments
nnshah1 May 16, 2024
0d98b63
update based on review comments
nnshah1 May 17, 2024
17c4e66
update to test include directive
nnshah1 May 18, 2024
547ff4b
updated variable name based on review
nnshah1 May 20, 2024
f808c64
update naming to be clear
nnshah1 May 20, 2024
ac5e206
removing empty line
nnshah1 May 20, 2024
bc0c7f5
update include order
nnshah1 May 20, 2024
e6d3fb2
updated to have single constructor
nnshah1 May 20, 2024
a4c5a7d
updating error message
nnshah1 May 20, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion include/triton/common/error.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ namespace triton { namespace common {
//
class Error {
public:
enum class Code {
enum class Code : uint8_t {
SUCCESS,
UNKNOWN,
INTERNAL,
Expand Down
196 changes: 152 additions & 44 deletions include/triton/common/logging.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,38 +33,46 @@
#include <string>
#include <vector>

namespace triton { namespace common {

// A log message.
class LogMessage {
public:
// Log levels.
enum Level { kERROR = 0, kWARNING = 1, kINFO = 2 };
#include "table_printer.h"
#ifdef _WIN32
// suppress the min and max definitions in Windef.h.
#define NOMINMAX
#include <Windows.h>
#else
#include <sys/time.h>
#include <sys/types.h>
#include <time.h>
#include <unistd.h>
#endif

LogMessage(const char* file, int line, uint32_t level);
~LogMessage();

std::stringstream& stream() { return stream_; }
namespace triton { namespace common {

private:
static const std::vector<char> level_name_;
std::stringstream stream_;
};

// Global logger for messages. Controls how log messages are reported.
class Logger {
public:
// Log Formats.
enum class Format { kDEFAULT, kISO8601 };

// Log levels.
enum class Level : uint8_t { kERROR = 0, kWARNING = 1, kINFO = 2, kEND };

inline static const std::array<const char*, static_cast<uint8_t>(Level::kEND)>
LEVEL_NAMES{"E", "W", "I"};

Logger();

// Is a log level enabled.
bool IsEnabled(LogMessage::Level level) const { return enables_[level]; }
bool IsEnabled(Level level) const
{
return enables_[static_cast<uint8_t>(level)];
}

// Set enable for a log Level.
void SetEnabled(LogMessage::Level level, bool enable)
void SetEnabled(Level level, bool enable)
{
enables_[level] = enable;
enables_[static_cast<uint8_t>(level)] = enable;
}

// Get the current verbose logging level.
Expand All @@ -73,6 +81,16 @@ class Logger {
// Set the current verbose logging level.
void SetVerboseLevel(uint32_t vlevel) { vlevel_ = vlevel; }

// Whether to escape log messages
// using JSON string escaping rules.
// Default is true but can be disabled by setting
// the following environment variable to '0'.
// If the variable is unset or set to any value !='0'
// log messages will be escaped
//
// TRITON_SERVER_ESCAPE_LOG_MESSAGES=0
bool EscapeLogMessages() const { return escape_log_messages_; };

// Get the logging format.
Format LogFormat() { return format_; }

Expand Down Expand Up @@ -126,7 +144,10 @@ class Logger {
void Flush();

private:
std::vector<bool> enables_;
inline static const char* ESCAPE_ENVIRONMENT_VARIABLE =
"TRITON_SERVER_ESCAPE_LOG_MESSAGES";
bool escape_log_messages_;
std::array<bool, static_cast<uint8_t>(Level::kEND)> enables_;
uint32_t vlevel_;
Format format_;
std::mutex mutex_;
Expand All @@ -136,15 +157,60 @@ class Logger {

extern Logger gLogger_;

#define LOG_ENABLE_INFO(E) \
triton::common::gLogger_.SetEnabled( \
triton::common::LogMessage::Level::kINFO, (E))
// A log message.
class LogMessage {
public:
LogMessage(
const char* file, int line, Logger::Level level,
const char* heading = nullptr,
bool escape_log_messages = gLogger_.EscapeLogMessages())
: path_(file), line_(line), level_(level), pid_(GetProcessId()),
heading_(heading), escape_log_messages_(escape_log_messages)
{
SetTimestamp();
size_t path_start = path_.rfind('/');
if (path_start != std::string::npos) {
path_ = path_.substr(path_start + 1, std::string::npos);
}
nnshah1 marked this conversation as resolved.
Show resolved Hide resolved
}

~LogMessage();

std::stringstream& stream() { return message_; }

private:
std::string path_;
const int line_;
const Logger::Level level_;
const uint32_t pid_;
void LogPreamble(std::stringstream& stream);
void LogTimestamp(std::stringstream& stream);

#ifdef _WIN32
SYSTEMTIME timestamp_;
void SetTimestamp() { GetSystemTime(&timestamp_); }
static uint32_t GetProcessId()
{
return static_cast<uint32_t>(GetCurrentProcessId());
};
#else
struct timeval timestamp_;
void SetTimestamp() { gettimeofday(&timestamp_, NULL); }
static uint32_t GetProcessId() { return static_cast<uint32_t>(getpid()); };
#endif
std::stringstream message_;
const char* heading_;
bool escape_log_messages_;
};

#define LOG_ENABLE_INFO(E) \
nnshah1 marked this conversation as resolved.
Show resolved Hide resolved
triton::common::gLogger_.SetEnabled(triton::common::Logger::Level::kINFO, (E))
#define LOG_ENABLE_WARNING(E) \
triton::common::gLogger_.SetEnabled( \
triton::common::LogMessage::Level::kWARNING, (E))
triton::common::Logger::Level::kWARNING, (E))
#define LOG_ENABLE_ERROR(E) \
triton::common::gLogger_.SetEnabled( \
triton::common::LogMessage::Level::kERROR, (E))
triton::common::Logger::Level::kERROR, (E))
#define LOG_SET_VERBOSE(L) \
triton::common::gLogger_.SetVerboseLevel( \
static_cast<uint32_t>(std::max(0, (L))))
Expand All @@ -159,12 +225,11 @@ extern Logger gLogger_;
#ifdef TRITON_ENABLE_LOGGING

#define LOG_INFO_IS_ON \
triton::common::gLogger_.IsEnabled(triton::common::LogMessage::Level::kINFO)
#define LOG_WARNING_IS_ON \
triton::common::gLogger_.IsEnabled( \
triton::common::LogMessage::Level::kWARNING)
triton::common::gLogger_.IsEnabled(triton::common::Logger::Level::kINFO)
#define LOG_WARNING_IS_ON \
triton::common::gLogger_.IsEnabled(triton::common::Logger::Level::kWARNING)
#define LOG_ERROR_IS_ON \
triton::common::gLogger_.IsEnabled(triton::common::LogMessage::Level::kERROR)
triton::common::gLogger_.IsEnabled(triton::common::Logger::Level::kERROR)
#define LOG_VERBOSE_IS_ON(L) (triton::common::gLogger_.VerboseLevel() >= (L))

#else
Expand All @@ -178,25 +243,25 @@ extern Logger gLogger_;
#endif // TRITON_ENABLE_LOGGING

// Macros that use explicitly given filename and line number.
#define LOG_INFO_FL(FN, LN) \
if (LOG_INFO_IS_ON) \
triton::common::LogMessage( \
(char*)(FN), LN, triton::common::LogMessage::Level::kINFO) \
#define LOG_INFO_FL(FN, LN) \
if (LOG_INFO_IS_ON) \
triton::common::LogMessage( \
(char*)(FN), LN, triton::common::Logger::Level::kINFO) \
.stream()
#define LOG_WARNING_FL(FN, LN) \
if (LOG_WARNING_IS_ON) \
triton::common::LogMessage( \
(char*)(FN), LN, triton::common::LogMessage::Level::kWARNING) \
#define LOG_WARNING_FL(FN, LN) \
if (LOG_WARNING_IS_ON) \
triton::common::LogMessage( \
(char*)(FN), LN, triton::common::Logger::Level::kWARNING) \
.stream()
#define LOG_ERROR_FL(FN, LN) \
if (LOG_ERROR_IS_ON) \
triton::common::LogMessage( \
(char*)(FN), LN, triton::common::LogMessage::Level::kERROR) \
#define LOG_ERROR_FL(FN, LN) \
if (LOG_ERROR_IS_ON) \
triton::common::LogMessage( \
(char*)(FN), LN, triton::common::Logger::Level::kERROR) \
.stream()
#define LOG_VERBOSE_FL(L, FN, LN) \
if (LOG_VERBOSE_IS_ON(L)) \
triton::common::LogMessage( \
(char*)(FN), LN, triton::common::LogMessage::Level::kINFO) \
#define LOG_VERBOSE_FL(L, FN, LN) \
if (LOG_VERBOSE_IS_ON(L)) \
triton::common::LogMessage( \
(char*)(FN), LN, triton::common::Logger::Level::kINFO) \
.stream()

// Macros that use current filename and line number.
Expand All @@ -205,7 +270,50 @@ extern Logger gLogger_;
#define LOG_ERROR LOG_ERROR_FL(__FILE__, __LINE__)
#define LOG_VERBOSE(L) LOG_VERBOSE_FL(L, __FILE__, __LINE__)

// Macros for use with triton::common::table_printer objects
//
// Data is assumed to be server / backend generated
// and not for use with client input.
//
// Tables are printed without escaping
#define LOG_TABLE_VERBOSE(L, TABLE) \
nnshah1 marked this conversation as resolved.
Show resolved Hide resolved
\
do { \
if (LOG_VERBOSE_IS_ON(L)) \
triton::common::LogMessage( \
__FILE__, __LINE__, triton::common::Logger::Level::kINFO, nullptr, \
false) \
.stream() \
<< TABLE.PrintTable(); \
} while (false)

#define LOG_TABLE_INFO(TABLE) \
do { \
if (LOG_INFO_IS_ON) \
triton::common::LogMessage( \
__FILE__, __LINE__, triton::common::Logger::Level::kINFO, nullptr, \
false) \
.stream() \
<< TABLE.PrintTable(); \
} while (false)


// Macros for use with protobuf messages
//
// Data is serialized via DebugString()
//
// Data is printed without further escaping
#define LOG_PROTOBUF_VERBOSE(L, HEADING, PB_MESSAGE) \
do { \
if (LOG_VERBOSE_IS_ON(L)) \
triton::common::LogMessage( \
__FILE__, __LINE__, triton::common::Logger::Level::kINFO, HEADING, \
false) \
.stream() \
<< PB_MESSAGE.DebugString(); \
} while (false)

// Macros for logging errors
#define LOG_STATUS_ERROR(X, MSG) \
do { \
const Status& status__ = (X); \
Expand Down
19 changes: 19 additions & 0 deletions include/triton/common/triton_json.h
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,25 @@ class TritonJson {
std::string buffer_;
};

//
// Utility to serialize input string
// as a JSON string value

static std::string SerializeString(const std::string& input)
{
WriteBuffer writebuffer;
const unsigned int writeFlags = rapidjson::kWriteNanAndInfFlag;
// Provide default template arguments to pass writeFlags
rapidjson::Writer<
WriteBuffer, rapidjson::UTF8<>, rapidjson::UTF8<>,
rapidjson::CrtAllocator, writeFlags>
writer(writebuffer);
if (RAPIDJSON_UNLIKELY(!writer.String(input.c_str()))) {
return "Error Serializing String";
}
return writebuffer.Contents();
}

//
// Value representing the entire document or an element within a
// document.
Expand Down
1 change: 1 addition & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ target_include_directories(
$<INSTALL_INTERFACE:include>
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/../include>
PRIVATE
${RAPIDJSON_INCLUDE_DIRS}
${CMAKE_CURRENT_SOURCE_DIR}
)

Expand Down
Loading
Loading