#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include "log.h"
#include "sys.h"
#include <ucs/sys/compiler.h>
#include <ucs/sys/string.h>
#include <sys/time.h>
#include <string.h>
#include <stdlib.h>
#include <stdarg.h>
#include <stdint.h>
#include <unistd.h>
#include <stdio.h>
#include <ctype.h>
#include <errno.h>
#include <limits.h>
#include <syscall.h>
#define UCM_LOG_BUG_SIZE 512
static int ucm_log_fileno = 1;
static char ucm_log_hostname[HOST_NAME_MAX] = {0};
const char *ucm_log_level_names[] = {
[UCS_LOG_LEVEL_FATAL] = "FATAL",
[UCS_LOG_LEVEL_ERROR] = "ERROR",
[UCS_LOG_LEVEL_WARN] = "WARN",
[UCS_LOG_LEVEL_DIAG] = "DIAG",
[UCS_LOG_LEVEL_INFO] = "INFO",
[UCS_LOG_LEVEL_DEBUG] = "DEBUG",
[UCS_LOG_LEVEL_TRACE] = "TRACE",
NULL
};
#define UCM_LOG_LTOA_FLAG_SIGN UCS_BIT(0)
#define UCM_LOG_LTOA_FLAG_UNSIGN UCS_BIT(1)
#define UCM_LOG_LTOA_FLAG_LONG UCS_BIT(2)
#define UCM_LOG_LTOA_FLAG_PAD0 UCS_BIT(3)
#define UCM_LOG_LTOA_PAD_LEFT UCS_BIT(4)
static char *ucm_log_add_padding(char *p, char *end, int pad, char fill)
{
while ((pad > 0) && (p < end)) {
*(p++) = fill;
--pad;
}
return p;
}
static char *ucm_log_ltoa(char *p, char *end, long n, int base, int flags,
int pad)
{
static const char digits[] = "0123456789abcdef";
long divider, top_divider;
if (((n < 0) || (flags & UCM_LOG_LTOA_FLAG_SIGN)) && (p < end)) {
*(p++) = (n < 0 ) ? '-' : '+';
}
if (n == 0) {
if (p < end) {
*(p++) = '0';
}
goto out;
}
n = labs(n);
divider = 1;
top_divider = 0;
while ((divider > 0) && ((n / divider) != 0)) {
top_divider = divider;
divider *= base;
--pad;
}
if (!(flags & UCM_LOG_LTOA_PAD_LEFT)) {
p = ucm_log_add_padding(p, end, pad,
(flags & UCM_LOG_LTOA_FLAG_PAD0) ? '0' : ' ');
}
divider = top_divider;
while ((p < end) && (divider > 0)) {
*(p++) = digits[(n / divider + base) % base];
divider /= base;
}
if (flags & UCM_LOG_LTOA_PAD_LEFT) {
p = ucm_log_add_padding(p, end, pad, ' ');
}
out:
return p;
}
static void ucm_log_vsnprintf(char *buf, size_t max, const char *fmt, va_list ap)
{
const char *pf;
char *pb, *endb;
union {
char *s;
long d;
unsigned long u;
uintptr_t p;
} value;
int flags;
int pad;
int base;
int eno;
pf = fmt;
pb = buf;
endb = buf + max - 1;
eno = errno;
while ((pb < endb) && (*pf != '\0')) {
if (*pf != '%') {
*(pb++) = *(pf++);
continue;
}
pad = 0;
flags = 0;
base = 10;
while (pb < endb) {
++pf;
switch (*pf) {
case '%':
*(pb++) = '%';
goto done;
case 'm':
ucm_strerror(eno, pb, endb - pb);
pb += strlen(pb);
goto done;
case 's':
value.s = va_arg(ap, char *);
if (!value.s) {
value.s = "(null)";
}
pad -= strlen(value.s);
if (!(flags & UCM_LOG_LTOA_PAD_LEFT)) {
pb = ucm_log_add_padding(pb, endb, pad, ' ');
}
while ((pb < endb) && (*value.s != '\0')) {
*(pb++) = *(value.s++);
}
if (flags & UCM_LOG_LTOA_PAD_LEFT) {
pb = ucm_log_add_padding(pb, endb, pad, ' ');
}
goto done;
case 'd':
if (flags & UCM_LOG_LTOA_FLAG_LONG) {
value.d = va_arg(ap, long);
} else {
value.d = va_arg(ap, int);
}
pb = ucm_log_ltoa(pb, endb, value.d, base, flags, pad);
goto done;
case 'x':
base = 16;
case 'u':
if (flags & UCM_LOG_LTOA_FLAG_LONG) {
value.u = va_arg(ap, unsigned long);
} else {
value.u = va_arg(ap, unsigned);
}
flags |= UCM_LOG_LTOA_FLAG_UNSIGN;
pb = ucm_log_ltoa(pb, endb, value.u, base, flags, pad);
goto done;
case 'p':
value.p = va_arg(ap, uintptr_t);
if (pb < endb) {
*(pb++) = '0';
}
if (pb < endb) {
*(pb++) = 'x';
}
pb = ucm_log_ltoa(pb, endb, value.p, 16, flags, pad);
goto done;
case '+':
flags |= UCM_LOG_LTOA_FLAG_SIGN;
break;
case '-':
flags |= UCM_LOG_LTOA_PAD_LEFT;
break;
case 'l':
case 'z':
flags |= UCM_LOG_LTOA_FLAG_LONG;
break;
case '0':
if (pad == 0) {
flags |= UCM_LOG_LTOA_FLAG_PAD0;
}
default:
if (isdigit(*pf)) {
pad = (pad * 10) + (*pf - '0');
}
break;
}
}
done:
++pf;
}
*pb = '\0';
}
static void ucm_log_snprintf(char *buf, size_t max, const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
ucm_log_vsnprintf(buf, max, fmt, ap);
va_end(ap);
}
void __ucm_log(const char *file, unsigned line, const char *function,
ucs_log_level_t level, const char *message, ...)
{
char buf[UCM_LOG_BUG_SIZE];
size_t length;
va_list ap;
struct timeval tv;
ssize_t nwrite;
pid_t pid;
gettimeofday(&tv, NULL);
pid = getpid();
ucm_log_snprintf(buf, UCM_LOG_BUG_SIZE - 1,
"[%lu.%06lu] [%s:%d:%d] %18s:%-4d UCX %s ",
tv.tv_sec, tv.tv_usec, ucm_log_hostname, pid,
ucm_get_tid() - pid, ucs_basename(file), line,
ucm_log_level_names[level]);
buf[UCM_LOG_BUG_SIZE - 1] = '\0';
length = strlen(buf);
va_start(ap, message);
ucm_log_vsnprintf(buf + length, UCM_LOG_BUG_SIZE - length, message, ap);
va_end(ap);
strncat(buf, "\n", UCM_LOG_BUG_SIZE - 1);
nwrite = write(ucm_log_fileno, buf, strlen(buf));
(void)nwrite;
if (level <= UCS_LOG_LEVEL_FATAL) {
abort();
}
}
UCS_STATIC_INIT {
gethostname(ucm_log_hostname, sizeof(ucm_log_hostname));
}