/********************************************************************************* * Copyright: (C) 2018 LingYun IoT System Studio * All rights reserved. * * Filename: logger.c * Description: This file is the linux infrastructural logger system library, which * is not thread safe. * * Version: 1.0.0(08/08/2012~) * Author: Guo Wenxue * ChangeLog: 1, Release initial version on "08/08/2018 04:24:01 PM" * ********************************************************************************/ #include "logger.h" #define PRECISE_TIME_FACTOR 1000 static unsigned long log_rollback_size = LOG_ROLLBACK_NONE; static st_logger _g_logger; static st_logger *g_logger = &_g_logger; char *log_str[LOG_LEVEL_MAX + 1] = { "", "F", "E", "W", "N", "D", "I", "T", "M" }; static char *log_time_format = "%Y-%m-%d %H:%M:%S"; static void logger_default_signal_handler(int sig) { if (sig == SIGHUP) { signal(SIGHUP, logger_default_signal_handler); log_fatal("SIGHUP received - reopenning log file [%s]", g_logger->file); logger_reopen(); } } static void logger_banner(char *prefix) { fprintf(g_logger->fp, "%s log \"%s\" on level [%s] size [%lu], log system version %s\n", prefix, g_logger->file, log_str[g_logger->level], log_rollback_size / 1024, LOG_VERSION_STR); #if 0 #ifdef LOG_FILE_LINE fprintf(g_logger->fp, " [Date] [Time] [Level] [PID/TID] [File/Line] [Content]\n"); #else fprintf(g_logger->fp, " [Date] [Time] [Level] [PID/TID] [Content]\n"); #endif #endif fprintf(g_logger->fp, "-----------------------------------------------------------------------------\n"); } static void check_and_rollback(void) { if (log_rollback_size != LOG_ROLLBACK_NONE) { long _curOffset = ftell(g_logger->fp); if ((_curOffset != -1) && (_curOffset >= log_rollback_size)) { char cmd[512]; snprintf(cmd, sizeof(cmd), "cp -f %s %s.roll", g_logger->file, g_logger->file); system(cmd); if (-1 == fseek(g_logger->fp, 0L, SEEK_SET)) fprintf(g_logger->fp, "log rollback fseek failed \n"); rewind(g_logger->fp); truncate(g_logger->file, 0); logger_banner("Already rollback"); } } } int logger_init(char *filename, int level, int log_size) { struct sigaction act; if( !filename || strlen(filename)<=0 ) { fprintf(stderr, "%s() invalid input arguments\n", __FUNCTION__); return -1; } memset(g_logger, 0, sizeof(st_logger)); strncpy(g_logger->file, filename, FILENAME_LEN); g_logger->level = level; g_logger->size = log_size; log_rollback_size = g_logger->size <= 0 ? LOG_ROLLBACK_NONE : g_logger->size*1024; /* Unit KiB */ /* logger to console, just need point to standard error */ if (!strcmp(g_logger->file, DBG_LOG_FILE)) { g_logger->fp = stderr; log_rollback_size = LOG_ROLLBACK_NONE; g_logger->flag |= LOGGER_CONSOLE; goto OUT; } g_logger->fp = fopen(g_logger->file, "a+"); if ( !g_logger->fp ) { fprintf(stderr, "Open log file \"%s\" failure\n", g_logger->file); return -2; } OUT: act.sa_handler = logger_default_signal_handler; sigemptyset(&act.sa_mask); act.sa_flags = 0; sigaction(SIGHUP, &act, NULL); logger_banner("\nInitialize"); return 0; } void logger_raw(const char *fmt, ...) { va_list argp; if ( !g_logger->fp ) return; check_and_rollback(); va_start(argp, fmt); vfprintf(g_logger->fp, fmt, argp); va_end(argp); } void logger_term(void) { if ( !g_logger->fp ) return; logger_banner("\nTerminate"); logger_raw("\n\n"); fflush(g_logger->fp); fclose(g_logger->fp); g_logger->fp = NULL; memset(g_logger, 0, sizeof(*g_logger)); return ; } int logger_reopen(void) { int rc = 0; if (g_logger->flag & LOGGER_CONSOLE ) { fflush(g_logger->fp); g_logger->fp = stderr; return 0; } if( g_logger->fp ) { logger_banner("\nClose"); fflush(g_logger->fp); g_logger->fp = fopen(g_logger->file, "a+"); if ( !g_logger->fp ) rc = -2; } else { rc = -3; } if (!rc) { logger_banner("\nReopen"); } return rc; } static void logger_printout(char *level, char *fmt, va_list argp) { char buf[MAX_LOG_MESSAGE_LEN]; struct tm *local; struct timeval now; char timestr[256]; pthread_t tid; check_and_rollback(); #ifdef MULTHREADS tid = pthread_self(); #else tid = getpid(); #endif gettimeofday(&now, NULL); local = localtime(&now.tv_sec); strftime(timestr, 256, log_time_format, local); vsnprintf(buf, MAX_LOG_MESSAGE_LEN, fmt, argp); #ifdef DUMPLICATE_OUTPUT printf("%s.%03ld [%s] [%06lu]: %s", timestr, now.tv_usec / PRECISE_TIME_FACTOR, level, tid, buf); #endif if (g_logger->fp) fprintf(g_logger->fp, "%s.%03ld [%s] [%06lu]: %s", timestr, now.tv_usec / PRECISE_TIME_FACTOR, level, tid, buf); if (g_logger->fp) fflush(g_logger->fp); } static void logger_printout_line(char *level, char *fmt, char *file, int line, va_list argp) { char buf[MAX_LOG_MESSAGE_LEN]; struct tm *local; struct timeval now; char timestr[256]; pthread_t tid; check_and_rollback(); #ifdef MULTHREADS tid = pthread_self(); #else tid = getpid(); #endif gettimeofday(&now, NULL); local = localtime(&now.tv_sec); strftime(timestr, 256, log_time_format, local); vsnprintf(buf, MAX_LOG_MESSAGE_LEN, fmt, argp); #ifdef DUMPLICATE_OUTPUT printf("%s.%03ld [%s] [%06lu] (%s [%04d]) : %s", timestr, now.tv_usec / PRECISE_TIME_FACTOR, level, tid, file, line, buf); #endif if (g_logger->fp) fprintf(g_logger->fp, "%s.%03ld [%s] [%06lu] (%s [%04d]) : %s", timestr, now.tv_usec / PRECISE_TIME_FACTOR, level, tid, file, line, buf); if (g_logger->fp) fflush(g_logger->fp); } void logger_comm(int level, char *fmt, ...) { va_list argp; if ( level > g_logger->level ) return; va_start(argp, fmt); logger_printout(log_str[level], fmt, argp); va_end(argp); } void logger_line(int level, char *file, int line, char *fmt, ...) { va_list argp; if ( level > g_logger->level ) return; va_start(argp, fmt); logger_printout_line(log_str[level], fmt, file, line, argp); va_end(argp); } #define LINELEN 81 #define CHARS_PER_LINE 16 static char *print_char = " " " " " !\"#$%&'()*+,-./" "0123456789:;<=>?" "@ABCDEFGHIJKLMNO" "PQRSTUVWXYZ[\\]^_" "`abcdefghijklmno" "pqrstuvwxyz{|}~ " " " " " " ???????????????" "????????????????" "????????????????" "????????????????" "????????????????" "????????????????"; void logger_dump(int level, char *buf, int len) { int rc; int idx; char prn[LINELEN]; char lit[CHARS_PER_LINE + 2]; char hc[4]; short line_done = 1; if ( level > g_logger->level ) return; rc = len; idx = 0; lit[CHARS_PER_LINE] = '\0'; while (rc > 0) { if (line_done) snprintf(prn, LINELEN, "%08X: ", idx); do { unsigned char c = buf[idx]; snprintf(hc, 4, "%02X ", c); strncat(prn, hc, LINELEN); lit[idx % CHARS_PER_LINE] = print_char[c]; } while (--rc > 0 && (++idx % CHARS_PER_LINE != 0)); line_done = (idx % CHARS_PER_LINE) == 0; if (line_done) { #ifdef DUMPLICATE_OUTPUT printf("%s %s\n", prn, lit); #endif if (g_logger->fp) fprintf(g_logger->fp, "%s %s\n", prn, lit); } } if (!line_done) { int ldx = idx % CHARS_PER_LINE; lit[ldx++] = print_char[(int)buf[idx]]; lit[ldx] = '\0'; while ((++idx % CHARS_PER_LINE) != 0) strncat(prn, " ", LINELEN); #ifdef DUMPLICATE_OUTPUT printf("%s %s\n", prn, lit); #endif if (g_logger->fp) fprintf(g_logger->fp, "%s %s\n", prn, lit); } }