// Copyright 2019 Fuzhou Rockchip Electronics Co., Ltd. All rights reserved.
|
// Use of this source code is governed by a BSD-style license that can be
|
// found in the LICENSE file.
|
|
#include "minilogger/log.h"
|
#include "minilogger/backtrace.h"
|
|
#include <dlfcn.h>
|
#include <glib.h>
|
#include <limits.h>
|
#include <signal.h>
|
#include <stdarg.h>
|
#include <stdio.h>
|
#include <stdlib.h>
|
#include <string.h>
|
#include <syslog.h>
|
#include <unistd.h>
|
|
typedef void (*sighandler_t)(int);
|
|
static const char *program_exec;
|
static const char *program_path;
|
|
/* This makes sure we always have a __debug section. */
|
MINILOG_DEBUG_DEFINE(dummy)
|
|
void minilog_info(const char *format, ...) {
|
va_list ap;
|
va_start(ap, format);
|
vsyslog(LOG_INFO, format, ap);
|
va_end(ap);
|
}
|
|
void minilog_warn(const char *format, ...) {
|
va_list ap;
|
va_start(ap, format);
|
vsyslog(LOG_WARNING, format, ap);
|
va_end(ap);
|
}
|
|
void minilog_error(const char *format, ...) {
|
va_list ap;
|
va_start(ap, format);
|
vsyslog(LOG_ERR, format, ap);
|
va_end(ap);
|
}
|
|
void minilog_debug(const char *format, ...) {
|
va_list ap;
|
va_start(ap, format);
|
vsyslog(LOG_DEBUG, format, ap);
|
va_end(ap);
|
}
|
|
static void signal_handler(int signo) {
|
minilog_error("Aborting (signal %d) [%s]", signo, program_exec);
|
show_backtrace();
|
exit(EXIT_FAILURE);
|
}
|
|
static void signal_setup(sighandler_t handler) {
|
struct sigaction sa;
|
sigset_t mask;
|
|
sigemptyset(&mask);
|
sa.sa_handler = handler;
|
sa.sa_mask = mask;
|
sa.sa_flags = 0;
|
sigaction(SIGBUS, &sa, NULL);
|
sigaction(SIGILL, &sa, NULL);
|
sigaction(SIGFPE, &sa, NULL);
|
sigaction(SIGSEGV, &sa, NULL);
|
sigaction(SIGABRT, &sa, NULL);
|
sigaction(SIGPIPE, &sa, NULL);
|
}
|
|
#if !__APPLE__
|
extern struct minilog_debug_desc __start___debug[];
|
extern struct minilog_debug_desc __stop___debug[];
|
#endif
|
|
static char **enabled = NULL;
|
|
static bool is_enabled(struct minilog_debug_desc *desc) {
|
int i;
|
|
if (!enabled)
|
return false;
|
|
for (i = 0; enabled[i]; i++) {
|
if (desc->name && g_pattern_match_simple(enabled[i], desc->name))
|
return true;
|
if (desc->file && g_pattern_match_simple(enabled[i], desc->file))
|
return true;
|
}
|
|
return false;
|
}
|
|
void __minilog_log_enable(struct minilog_debug_desc *start,
|
struct minilog_debug_desc *stop) {
|
struct minilog_debug_desc *desc;
|
const char *name = NULL, *file = NULL;
|
|
if (!start || !stop)
|
return;
|
|
for (desc = start; desc < stop; desc++) {
|
if (desc->flags & MINILOG_DEBUG_FLAG_ALIAS) {
|
file = desc->file;
|
name = desc->name;
|
continue;
|
}
|
|
if (file || name) {
|
if (strcmp(desc->file, file) == 0) {
|
if (!desc->name)
|
desc->name = name;
|
} else
|
file = NULL;
|
}
|
|
if (is_enabled(desc))
|
desc->flags |= MINILOG_DEBUG_FLAG_PRINT;
|
}
|
}
|
|
int __minilog_log_init(const char *program, const char *debug, bool detach,
|
bool backtrace, const char *program_name,
|
const char *program_version) {
|
static char path[PATH_MAX];
|
int option = LOG_NDELAY | LOG_PID;
|
|
program_exec = program;
|
program_path = getcwd(path, sizeof(path));
|
|
if (debug)
|
enabled = g_strsplit_set(debug, ":, ", 0);
|
|
#if !__APPLE__
|
__minilog_log_enable(__start___debug, __stop___debug);
|
#endif
|
|
if (!detach)
|
option |= LOG_PERROR;
|
|
if (backtrace)
|
signal_setup(signal_handler);
|
|
#if !__APPLE__
|
openlog(basename(program), option, LOG_DAEMON);
|
#else
|
openlog(g_path_get_basename(program), option, LOG_DAEMON);
|
#endif
|
|
syslog(LOG_INFO, "%s version %s", program_name, program_version);
|
|
return 0;
|
}
|
|
void __minilog_log_cleanup(bool backtrace) {
|
syslog(LOG_INFO, "Exit");
|
|
closelog();
|
|
if (backtrace)
|
signal_setup(SIG_DFL);
|
|
g_strfreev(enabled);
|
}
|