mirror of
https://github.com/albfan/miraclecast.git
synced 2025-03-09 23:38:56 +00:00
320 lines
6.9 KiB
C
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;
|
|
}
|