12-31-2024:14:45:06: test.c:000075: DEBUG : Address of logger: 0x5596cc360160
12-31-2024:14:45:06: test.c:000076: INFO : Logger is set at level: -1
12-31-2024:14:45:06: test.c:000077: WARNING : Dereference pointers with care
12-31-2024:14:45:06: test.c:000078: ERROR : Logger buffer size: 76
12-31-2024:14:45:06: test.c:000079: CRITICAL: Thanks for using logger
struct loge logger;
/* Initialize with default buffer size, 6 digits for line number,
* LOGE_ALL level, stdout stream and default callback function
*/
loge_setup(
&logger, /* struct loge *ploge */
0, /* size_t max_log_size */
-1, /* int linenumwidth */
-1, /* int wdith */
-1, /* int precision */
LOGE_ALL, /* enum loge_level level */
NULL, /* FILE *file */
NULL /* log_fn fn */
);
LOGE_COLOR(&logger, LOGE_DEBUG, "Address of logger: %p", &logger);
LOGE_COLOR(&logger, LOGE_INFO, "Logger is set at level: %d", logger.level);
LOGE_COLOR(&logger, LOGE_WARNING, "Dereference pointers with care");
LOGE_COLOR(&logger, LOGE_ERROR, "Logger buffer size: %zu", logger.buflen);
LOGE_COLOR(&logger, LOGE_CRITICAL, "Thanks for using logger");
loge_set_level(&logger, LOGE_CRITICAL);
LOGE(&logger, LOGE_WARNING, "This will not get logged");
LOGE(&logger, LOGE_ERROR, "This will not get logged");
LOGE(&logger, LOGE_CRITICAL, "This will get logged");
loge_set_file(&logger, "ctest.log");
LOGE(&logger, LOGE_INFO, "Logger is set at level: %d", logger.level);
loge_unset_file(&logger);
/* Logger callback is unset now */
LOGE(&logger, LOGE_CRITICAL, "This should cause an error message");
loge_set_stdout(&logger);
LOGE_COLOR(&logger, LOGE_DEBUG, "Address of logger: %p", &logger);
loge_set_stderr(&logger);
LOGE(&logger, LOGE_INFO, "Logger is set at level: %d", logger.level);
#ifdef _MSC_VER
loge_set_fd(&logger, _fileno(stdout));
#else
loge_set_fd(&logger, STDOUT_FILENO);
#endif
LOGE(&logger, LOGE_DEBUG, "Address of logger: %p", &logger);
/* Loge to UDP server over IPv6 */
if (!loge_connect(&logger, "::1", 8887, 0, 1, NULL)) {
LOGE(&logger, LOGE_DEBUG, "Address of logger: %p", &logger);
loge_disconnect(&logger);
}
/* Loge to TCP server over IPv6 */
if (!loge_connect(&logger, "::1", 8889, 1, 1, NULL)) {
LOGE(&logger, LOGE_DEBUG, "Address of logger: %p", &logger);
loge_disconnect(&logger);
}
loge_set_syslog(&logger, LOG_NOTICE);
LOGE(&logger, LOGE_DEBUG, "Address of logger: %p", &logger);
void mylogfn(const struct loge *ploge) {
if (!ploge) {
return;
}
const char *msg = loge_bufptr(ploge);
/* Filter messages that contain "log" (case insensitive) */
#if defined(__GLIBC__) || defined(__FreeBSD__) || defined(__OpenBSD__)
if (strcasestr(msg, "log") == NULL) {
return;
}
#else
if (strstr(msg, "log") == NULL &&
strstr(msg, "LOG") == NULL &&
strstr(msg, "Log") == NULL) {
return;
}
#endif
char *newmsg = strreplace(msg, "Logger", "This logger");
if (!newmsg) {
return;
}
FILE *file = loge_fileptr(ploge);
fprintf(file, ANSI_BOLD"%s\n", newmsg);
free(newmsg);
}
loge_set_fn(&logger, mylogfn);
LOGE(&logger, LOGE_DEBUG, "Address of logger: %p", &logger);
void mydatafn(
FILE *file,
time_t timestamp,
const char *filename,
int linenum,
enum loge_level level,
const char *msg
) {
if (!file) {
return;
}
const char *loglvl_str = loge_get_level_color(level);
fprintf(file,
#ifdef _MSC_VER
"%llu: %s:%04d: %-22s: %s\n",
#else
"%lu: %s:%04d: %-22s: %s\n",
#endif
timestamp,
filename, linenum,
loglvl_str,
msg);
}
loge_set_data_fn(&logger, mydatafn);
LOGE(&logger, LOGE_DEBUG, "Address of logger: %p", &logger);
/* Use put functions */
time_t t = time(NULL);
struct tm tm = *localtime(&t);
/* Reset message buffer */
loge_reset(&logger);
loge_put_str(&logger, "hello ");
loge_put_time(&logger, &tm);
loge_put_char(&logger, ' ');
loge_put_int(&logger, 12);
loge_put_char(&logger, '-');
loge_put_long(&logger, 2025L);
loge_put_char(&logger, ' ');
loge_set_width(&logger, 8);
loge_put_int(&logger, 312);
loge_put_char(&logger, ' ');
loge_set_width(&logger, 12);
loge_set_precision(&logger, 6);
loge_put_float(&logger, 2747.33333333);
loge_put_char(&logger, ' ');
loge_put_double(&logger, 333.33333333);
/* Flush message buffer */
loge_flush(&logger);
/* Definition */
template <bool timestamp = true>
class loge {
/* Constructors */
loge(
std::ostream *p_os_,
int linenumwidth_ = constants::LINENUMBER_WIDTH,
int width_ = -1,
int precision_ = -1,
enum loge_level level_ = loge_level::ERROR
) : level(level_), logfnptr(&loge<timestamp>::logfn) {
...
}
loge(enum loge_level loglevel = loge_level::ERROR)
: loge(nullptr, constants::LINENUMBER_WIDTH, -1, -1, loglevel) {
}
...
};
loge<false> syslogger(loge<false>::ALL);
loge<> logger(loge<>::ALL);
logger.set_level(loge<>::CRITICAL);
LOGE_COLOR(&logger, loge<>::WARNING, "This will not be logged");
loge<> logger(loge<>::ALL);
logger.set_file("cctest.log", true);
LOGE(&logger, loge<>::INFO, "Logging to file %s", "cctest.log");
logger.set_stdout();
LOGE_COLOR(&logger, loge<>::INFO, "Stdout filestream");
logger.set_stderr();
LOGE(&logger, loge<>::INFO, "Stderr filestream");
#if defined(__linux__) || defined(__linux)
logger.set_fd(STDOUT_FILENO);
#elif defined(_MSC_VER)
logger.set_fd(_fileno(stdout));
#endif
LOGE_COLOR(&logger, loge<>::INFO, "Log to stdio");
/* Loge to UDP server over IPv6 */
if (logger.connect("::1", 8887, 0, 1)) {
LOGE(&logger, file_logger_base::INFO, "Log to UDP socket");
logger.disconnect();
}
/* Loge to TCP server over IPv6 */
if (logger.connect("::1", 8889, 1, 1)) {
LOGE(&logger, file_logger_base::INFO, "Log to TCP socket");
logger.disconnect();
}
loge<false> syslogger(loge<false>::ALL);
syslogger.set_syslog(LOG_USER | LOG_NOTICE);
LOGE(&syslogger, loge<false>::INFO, "Log to syslog daemon");
using fd_logger_base = loge<true>;
class fd_logger : public fd_logger_base {
int fd_ = -1;
public:
/* Override log function */
void logfn() override {
/* buffer char array may not be null-terminated */
buffer[buffer.size() - 1] = '\0';
dprintf(fd_, "%s\n", buffer.data());
}
fd_logger(int fd, fd_logger_base::loge_level loglevel)
: loge(loglevel) , fd_(fd) {
}
};
#if defined(__linux__) || defined(__linux)
fd_logger fdlogger(STDOUT_FILENO, fd_logger_base::ALL);
#elif defined(_MSC_VER)
fd_logger fdlogger(_fileno(stdout), fd_logger_base::ALL);
#endif
LOGE_COLOR(&fdlogger, fd_logger_base::INFO, "Log to stdout using custom log function");
using custom_logger_base = loge<true>;
class custom_logger : public custom_logger_base {
public:
bool datafn(std::ostream *p_os, std::time_t &time,
const std::string &filename, unsigned int linenum,
enum loge_level loglevel, const std::string &msg) override {
const char *loglvl_str = get_level_color(loglevel);
char buf[1024];
int done = snprintf(buf, sizeof(buf),
#ifdef _MSC_VER
"%llu: %s:%04d: %-22s - %s\n",
#else
"%lu: %s:%04d: %-22s - %s\n",
#endif
time,
filename.c_str(), linenum,
loglvl_str,
msg.c_str());
p_os->write(buf, done);
return false;
}
custom_logger(custom_logger_base::loge_level loglevel)
: loge(loglevel) {
}
};
custom_logger customlogger(custom_logger_base::ALL);
LOGE(&customlogger, custom_logger_base::INFO,
"Custom log function with unformatted log data %d %s", 10, "foo");
/* Demo for insertion operator */
loge<true> log(&std::cerr);
std::time_t t = std::time(nullptr);
struct tm tm = *std::localtime(&t);
std::string prefix = "test log: ";
/* Reset message buffer */
log.reset();
log << prefix << "hello: " << 121 << " : " <<
loge<>::setw(loge<>::constants::NUMBER_WIDTH) << 312 << " : " << tm
<< ": " << loge<>::setw(6) << 1970 << loge<>::endl;
long l = 0xffffffffffffffff;
unsigned long u = 0xffffffffffffffff;
std::size_t s = 0xffffffffffffffff;
log << "integers: " << loge<>::setw(24) << ' ' << l << ' ' << u << ' ' << s;
log.flush();
float f = 2747.33333333;
double d = 333.33333333;
log << "fractions: " << loge<>::setw_default() << 312.3145926535 << " "
<< loge<>::setw(12) << loge<>::setprecision(6) << " " << f << " " << d;
/* Write message to ostream or socket */
log.flush();