1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182
|
/* This file is part of the Spring engine (GPL v2 or later), see LICENSE.html */
/**
* This is the default formatter for the ILog.h logging API.
* It formats the message and eventually adds a prefix.
* The prefix will usually consist of the level, section and possibly a
* timestamp.
*/
#include "LogUtil.h"
#include "Level.h"
#include "Section.h"
#include "System/maindefines.h"
#include "System/SafeCStrings.h"
#include <cstdio>
#include <cstdarg>
#include <cstring>
#ifdef __cplusplus
extern "C" {
#endif
#ifdef _MSC_VER
#define va_copy(dst, src) ((dst) = (src))
#endif
static const int SECTION_SIZE_MIN = 10;
static const int SECTION_SIZE_MAX = 20;
// *******************************************************************************************
// Helpers
static inline void ResizeBuffer(char** buffer, size_t* bufferSize, const bool copy = false)
{
char* old = *buffer;
*bufferSize <<= 2; // `2` to increase it faster
*buffer = new char[*bufferSize];
if (copy) {
memcpy(*buffer, old, (*bufferSize) >> 2);
}
delete[] old;
}
static inline void PrintfAppend(char** buffer, size_t* bufferSize, const char* fmt, va_list arguments)
{
// dynamically adjust the buffer size until VSNPRINTF returns fine
size_t bufferPos = strlen(*buffer);
do {
const size_t freeBufferSize = (*bufferSize) - bufferPos;
char* bufAppendPos = &((*buffer)[bufferPos]);
// printf will move the internal pointer of va_list.
// So we need to make a copy, if want to run it again.
va_list arguments_;
va_copy(arguments_, arguments);
const int writtenChars = VSNPRINTF(bufAppendPos, freeBufferSize, fmt, arguments_);
va_end(arguments_);
// since writtenChars excludes the null terminator (if any was written),
// writtenChars >= freeBufferSize always means buffer was too small
// NOTE: earlier glibc versions and MSVC will return -1 when buffer is too small
// const bool bufferTooSmall = writtenChars >= freeBufferSize || writtenChars < 0;
if (writtenChars >= 0 && writtenChars < freeBufferSize)
break;
ResizeBuffer(buffer, bufferSize, true);
} while (true);
}
// *******************************************************************************************
/*
static void log_formatter_createPrefix_xorgStyle(
char** buffer,
size_t* bufferSize,
const char* section,
int level
) {
const char* prepSection = log_util_prepareSection(section);
const char levelChar = log_util_levelToChar(level);
SNPRINTF(*buffer, *bufferSize, "(%c%c) %*.*s - ", levelChar, levelChar,
SECTION_SIZE_MIN, SECTION_SIZE_MAX, prepSection);
}
*/
/*
static void log_formatter_createPrefix_testing(
char** buffer,
size_t* bufferSize,
const char* section,
int level
) {
const char* prepSection = log_util_prepareSection(section);
const char* levelStr = log_util_levelToString(level);
SNPRINTF(*buffer, *bufferSize, "%s %s: ", levelStr, prepSection);
}
*/
static void log_formatter_createPrefix_default(
char** buffer,
size_t* bufferSize,
const char* section,
int level
) {
(*buffer)[0] = '\0';
if (!LOG_SECTION_IS_DEFAULT(section)) {
const char* prepSection = log_util_prepareSection(section);
STRCAT_T(*buffer, *bufferSize, "[");
STRCAT_T(*buffer, *bufferSize, prepSection);
STRCAT_T(*buffer, *bufferSize, "] ");
}
if (level != LOG_LEVEL_INFO && level != LOG_LEVEL_NOTICE) {
const char* levelStr = log_util_levelToString(level);
STRCAT_T(*buffer, *bufferSize, levelStr);
STRCAT_T(*buffer, *bufferSize, ": ");
}
}
static inline void log_formatter_createPrefix(
char** buffer,
size_t* bufferSize,
const char* section,
int level
) {
//log_formatter_createPrefix_xorgStyle(buffer, bufferSize, section, level);
//log_formatter_createPrefix_testing(buffer, bufferSize, section, level);
log_formatter_createPrefix_default(buffer, bufferSize, section, level);
// check if the buffer was large enough, if not resize it and try again
if ((strlen(*buffer) + 1) >= *bufferSize) {
ResizeBuffer(buffer, bufferSize);
log_formatter_createPrefix(buffer, bufferSize, section, level); // recursive
}
}
// *******************************************************************************************
/**
* @name logging_formatter
* ILog.h formatter implementation.
*/
///@{
/**
* Formats a log entry into its final string form.
* @return a string buffer, allocated with new[] -> you have to delete[] it
*/
char* log_formatter_format(const char* section, int level, const char* fmt, va_list arguments)
{
size_t bufferSize = 256;
char* mem = new char[bufferSize];
char** buffer = &mem;
memset(&mem[0], 0, bufferSize);
#if 1
log_formatter_createPrefix(buffer, &bufferSize, section, level);
PrintfAppend(buffer, &bufferSize, fmt, arguments);
#endif
return mem;
}
///@}
#ifdef __cplusplus
} // extern "C"
#endif
|