1
0
Fork 0
mirror of https://github.com/albfan/miraclecast.git synced 2025-03-09 23:38:56 +00:00
miraclecast/src/shared/shl_log.c
2024-07-13 19:10:37 +02:00

320 lines
6.9 KiB
C

/*
* SHL - Log/Debug Interface
*
* Copyright (c) 2010-2013 David Herrmann <dh.herrmann@gmail.com>
* Dedicated to the Public Domain
*/
#include <errno.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/time.h>
#include <time.h>
#include <math.h>
#include <limits.h>
#include "shl_log.h"
/*
* Locking
* Dummies to implement locking. If we ever want lock-protected logging, these
* need to be provided by the user.
*/
static inline void log_lock()
{
}
static inline void log_unlock()
{
}
/*
* Time Management
* We print seconds and microseconds since application start for each
* log-message in case log_init_time() has been called.
*/
static struct timeval log__ftime;
bool log__have_time(void)
{
return !(log__ftime.tv_sec == 0 && log__ftime.tv_usec == 0);
}
void log_init_time(void)
{
if (!log__have_time())
gettimeofday(&log__ftime, NULL);
}
void log__time(long long *sec, long long *usec)
{
struct timeval t;
/* In case this is called in parallel to log_init_time(), we need to
* catch negative time-diffs. Other than that, this can be called
* unlocked. */
gettimeofday(&t, NULL);
*sec = t.tv_sec - log__ftime.tv_sec;
*usec = (long long)t.tv_usec - (long long)log__ftime.tv_usec;
if (*usec < 0) {
*sec -= 1;
if (*sec < 0)
*sec = 0;
*usec = 1000000 + *usec;
}
}
/*
* Default Values
* Several logging-parameters may be omitted by applications. To provide sane
* default values we provide constants here.
*
* LOG_SUBSYSTEM: By default no subsystem is specified
*/
const char *LOG_SUBSYSTEM = NULL;
/*
* Max Severity
* Messages with severities between log_max_sev and LOG_SEV_NUM (exclusive)
* are not logged, but discarded.
*/
unsigned int log_max_sev = LOG_NOTICE;
bool log_date_time = false;
char *gst_debug = NULL;
/*
* Forward declaration so we can use the locked-versions in other functions
* here. Be careful to avoid deadlocks, though.
* Also set default log-subsystem to "log" for all logging inside this API.
*/
static void log__submit(const char *file,
int line,
const char *func,
const char *subs,
unsigned int sev,
const char *format,
va_list args);
#define LOG_SUBSYSTEM "log"
/*
* Basic logger
* The log__submit function writes the message into the current log-target. It
* must be called with log__mutex locked.
* By default the current time elapsed since the first message was logged is
* prepended to the message. file, line and func information are appended to the
* message if sev == LOG_DEBUG.
* The subsystem, if not NULL, is prepended as "SUBS: " to the message and a
* newline is always appended by default. Multiline-messages are not allowed.
*/
static const char *log__sev2str[LOG_SEV_NUM] = {
[LOG_TRACE] = "TRACE",
[LOG_DEBUG] = "DEBUG",
[LOG_INFO] = "INFO",
[LOG_NOTICE] = "NOTICE",
[LOG_WARNING] = "WARNING",
[LOG_ERROR] = "ERROR",
[LOG_CRITICAL] = "CRITICAL",
[LOG_ALERT] = "ALERT",
[LOG_FATAL] = "FATAL",
};
static void log__submit(const char *file,
int line,
const char *func,
const char *subs,
unsigned int sev,
const char *format,
va_list args)
{
int saved_errno = errno;
const char *prefix = NULL;
FILE *out;
long long sec, usec;
time_t now;
struct tm *timeinfo;
struct timeval tv;
char buffertmp[80];
char buffer[120];
int millisec;
out = stderr;
if (sev < LOG_SEV_NUM && sev > log_max_sev)
return;
log__time(&sec, &usec);
if (log_date_time) {
gettimeofday(&tv, NULL);
millisec = lrint(tv.tv_usec/1000.0);
if (millisec>=1000) {
millisec -=1000;
tv.tv_sec++;
}
time(&now);
timeinfo = localtime(&now);
strftime(buffertmp, 80, "%x - %X.%03d", timeinfo);
sprintf(buffer, "%s.%03d", buffertmp, millisec);
}
if (sev < LOG_SEV_NUM)
prefix = log__sev2str[sev];
if (prefix) {
if (subs) {
if (log_date_time)
fprintf(out, "[%s] %s: %s: ", buffer, prefix, subs);
else if (log__have_time())
fprintf(out, "[%.4lld.%.6lld] %s: %s: ",
sec, usec, prefix, subs);
else
fprintf(out, "%s: %s: ", prefix, subs);
} else {
if (log_date_time)
fprintf(out, "[%s] %s: ", buffer, prefix);
else if (log__have_time())
fprintf(out, "[%.4lld.%.6lld] %s: ",
sec, usec, prefix);
else
fprintf(out, "%s: ", prefix);
}
} else {
if (subs) {
if (log_date_time)
fprintf(out, "[%s] %s: ",
buffer, subs);
else if (log__have_time())
fprintf(out, "[%.4lld.%.6lld] %s: ",
sec, usec, subs);
else
fprintf(out, "%s: ", subs);
} else {
if (log_date_time)
fprintf(out, "[%s] ", buffer);
else if (log__have_time())
fprintf(out, "[%.4lld.%.6lld] ", sec, usec);
}
}
errno = saved_errno;
vfprintf(out, format, args);
if (sev == LOG_DEBUG || sev <= LOG_WARNING) {
if (!func)
func = "<unknown>";
if (!file)
file = "<unknown>";
if (line < 0)
line = 0;
fprintf(out, " (%s() in %s:%d)\n", func, file, line);
} else {
fprintf(out, "\n");
}
}
void log_submit(const char *file,
int line,
const char *func,
const char *subs,
unsigned int sev,
const char *format,
va_list args)
{
int saved_errno = errno;
log_lock();
errno = saved_errno;
log__submit(file, line, func, subs, sev, format, args);
log_unlock();
errno = saved_errno;
}
void log_format(const char *file,
int line,
const char *func,
const char *subs,
unsigned int sev,
const char *format,
...)
{
int saved_errno = errno;
va_list list;
va_start(list, format);
log_lock();
errno = saved_errno;
log__submit(file, line, func, subs, sev, format, list);
log_unlock();
va_end(list);
errno = saved_errno;
}
void log_llog(void *data,
const char *file,
int line,
const char *func,
const char *subs,
unsigned int sev,
const char *format,
va_list args)
{
log_submit(file, line, func, subs, sev, format, args);
}
unsigned int log_parse_arg(char *optarg)
{
unsigned int log_max_sev;
if(!strcasecmp(optarg, "fatal")) {
log_max_sev = LOG_FATAL;
} else if(!strcasecmp(optarg, "alert")) {
log_max_sev = LOG_ALERT;
} else if(!strcasecmp(optarg, "critical")) {
log_max_sev = LOG_CRITICAL;
} else if(!strcasecmp(optarg, "error")) {
log_max_sev = LOG_ERROR;
} else if(!strcasecmp(optarg, "warning")) {
log_max_sev = LOG_WARNING;
} else if(!strcasecmp(optarg, "notice")) {
log_max_sev = LOG_NOTICE;
} else if(!strcasecmp(optarg, "info")) {
log_max_sev = LOG_INFO;
} else if(!strcasecmp(optarg, "debug")) {
log_max_sev = LOG_DEBUG;
} else if(!strcasecmp(optarg, "trace")) {
log_max_sev = LOG_TRACE;
} else {
errno = 0;
char *temp;
long val = strtoul(optarg, &temp, 0);
if (temp == optarg || *temp != '\0'
|| ((val == LONG_MIN || val == LONG_MAX) && errno == ERANGE)) {
log_error("Could not convert '%s' to long and leftover string is: '%s'\n", optarg, temp);
}
if (val > INT_MAX) {
errno = ERANGE;
return INT_MAX;
}
if (val < INT_MIN) {
errno = ERANGE;
return INT_MIN;
}
log_max_sev = (unsigned int) val;
}
return log_max_sev;
}