| /********************************************************************************* | 
|  *      Copyright:  (C) 2012 Guo Wenxue <guowenxue@gmail.com> | 
|  *                  All rights reserved. | 
|  * | 
|  *       Filename:  cp_log.c | 
|  *    Description:  This file is the linux infrastructural logger system library | 
|  *                  | 
|  *        Version:  1.0.0(08/08/2012~) | 
|  *         Author:  Guo Wenxue <guowenxue@gmail.com> | 
|  *      ChangeLog:  1, Release initial version on "08/08/2012 04:24:01 PM" | 
|  *                  | 
|  ********************************************************************************/ | 
|   | 
| #include "cp_logger.h" | 
| #include "cp_common.h" | 
|   | 
| #define PRECISE_TIME_FACTOR 1000 | 
|   | 
| static unsigned long log_rollback_size = LOG_ROLLBACK_NONE; | 
|   | 
| static cp_logger *logger = NULL; | 
|   | 
| char *log_str[LOG_LEVEL_MAX + 1] = { "", "F", "E", "W", "N", "D", "I", "T", "M" }; | 
|   | 
| static char *cp_time_format = DEFAULT_TIME_FORMAT; | 
|   | 
| void cp_log_set_time_format(char *time_format) | 
| { | 
|     cp_time_format = time_format; | 
| } | 
|   | 
| static void cp_log_default_signal_handler(int sig) | 
| { | 
|     if(!logger) | 
|         return ; | 
|   | 
|     if (sig == SIGHUP) | 
|     { | 
|         signal(SIGHUP, cp_log_default_signal_handler); | 
|         log_fatal("SIGHUP received - reopenning log file [%s]", logger->file); | 
|         cp_log_reopen(); | 
|     } | 
| } | 
|   | 
| static void log_banner(char *prefix) | 
| { | 
|     if(!logger) | 
|         return ; | 
|   | 
|     fprintf(logger->fp, "%s log \"%s\" on level [%s] size [%lu], log system version %s\n", | 
|             prefix, logger->file, log_str[logger->level], log_rollback_size / 1024, LOG_VERSION_STR); | 
| #ifdef LOG_FILE_LINE | 
|     fprintf(logger->fp, " [Date]    [Time]   [Level] [PID/TID] [File/Line]  [Content]\n"); | 
| #else | 
|     fprintf(logger->fp, " [Date]    [Time]   [Level] [PID/TID] [Content]\n"); | 
| #endif | 
|     fprintf(logger->fp, "-------------------------------------------------------------\n"); | 
| } | 
|   | 
| static void check_and_rollback(void) | 
| { | 
|     if(!logger) | 
|         return ; | 
|   | 
|     if (log_rollback_size != LOG_ROLLBACK_NONE) | 
|     { | 
|         long _curOffset = ftell(logger->fp); | 
|   | 
|         if ((_curOffset != -1) && (_curOffset >= log_rollback_size)) | 
|         { | 
|             char cmd[512]; | 
|   | 
|             snprintf(cmd, sizeof(cmd), "cp -f %s %s.roll", logger->file, logger->file); | 
|             system(cmd); | 
|   | 
|             if (-1 == fseek(logger->fp, 0L, SEEK_SET)) | 
|                 fprintf(logger->fp, "log rollback fseek failed \n"); | 
|   | 
|             rewind(logger->fp); | 
|   | 
|             truncate(logger->file, 0); | 
|             log_banner("Already rollback"); | 
|         } | 
|     } | 
| } | 
|   | 
| cp_logger *cp_log_init(cp_logger *log, char *filename, int level, int log_size) | 
| { | 
|     if(NULL == log) | 
|     { | 
|         logger = malloc(sizeof(cp_logger)); | 
|         memset(logger, 0, sizeof(cp_logger)); | 
|         logger->flag |= CP_LOGGER_MALLOC;  | 
|     } | 
|     else | 
|     { | 
|         logger = log; | 
|         memset(logger, 0, sizeof(cp_logger)); | 
|         logger->flag |= CP_LOGGER_ARGUMENT;  | 
|     } | 
|   | 
|     if(NULL == logger) | 
|     { | 
|         return NULL; | 
|     } | 
|   | 
|     strncpy(logger->file, filename, FILENAME_LEN);  | 
|     logger->level = level; | 
|     logger->size = log_size;  | 
|   | 
|     return logger; | 
| } | 
|   | 
| int cp_log_open(void) | 
| { | 
|     struct sigaction act; | 
|     char *filemode; | 
|   | 
|     if(!logger) | 
|     { | 
|         return -1; | 
|     } | 
|   | 
|     log_rollback_size = logger->size <= 0 ? LOG_ROLLBACK_NONE : logger->size*1024;    /* Unit KiB */ | 
|          | 
|     if ('\0' == logger->file) | 
|         return -1; | 
|   | 
|     if (!strcmp(logger->file, DBG_LOG_FILE)) | 
|     { | 
|         logger->fp = stderr; | 
|         log_rollback_size = LOG_ROLLBACK_NONE; | 
|         logger->flag |= CP_LOGGER_CONSOLE; | 
|         goto OUT; | 
|     } | 
|   | 
|     //filemode = (log_rollback_size==LOG_ROLLBACK_NONE) ? "a+" : "w+"; | 
|     filemode = "a+"; | 
|   | 
|     logger->fp = fopen(logger->file, filemode); | 
|     if (NULL == logger->fp) | 
|     { | 
|         fprintf(stderr, "Open log file \"%s\" in %s failure\n", logger->file, filemode); | 
|         return -2; | 
|     } | 
|   | 
|     act.sa_handler = cp_log_default_signal_handler; | 
|     sigemptyset(&act.sa_mask); | 
|     act.sa_flags = 0; | 
|     sigaction(SIGHUP, &act, NULL); | 
|   | 
|   OUT: | 
|     log_banner("Initialize"); | 
|   | 
|     return 0; | 
| } | 
|   | 
| void cp_log_close(void) | 
| { | 
|     if (!logger || !logger->fp ) | 
|         return; | 
|   | 
|     log_banner("\nTerminate"); | 
|     cp_log_raw("\n\n\n\n"); | 
|   | 
|     fflush(logger->fp); | 
|   | 
|     fclose(logger->fp); | 
|     logger->fp = NULL; | 
|   | 
|     return ; | 
| } | 
|   | 
| int cp_log_reopen(void) | 
| { | 
|     int rc = 0; | 
|     char *filemode; | 
|   | 
|     if( !logger ) | 
|         return -1; | 
|   | 
|     if (logger->flag & CP_LOGGER_CONSOLE ) | 
|     { | 
|         fflush(logger->fp); | 
|         logger->fp = stderr; | 
|         return 0; | 
|     } | 
|   | 
|     if (logger->fp) | 
|     { | 
|         cp_log_close(); | 
|         //filemode = log_rollback_size == LOG_ROLLBACK_NONE ? "a+" : "w+"; | 
|         filemode = "a+"; | 
|         logger->fp = fopen(logger->file, filemode);  | 
|          | 
|         if (logger->fp == NULL) | 
|             rc = -2; | 
|     } | 
|     else | 
|     { | 
|         rc = -3; | 
|     } | 
|   | 
|     if (!rc) | 
|     { | 
|         log_banner("\nReopen"); | 
|     } | 
|     return rc; | 
| } | 
|   | 
| void cp_log_term(void) | 
| { | 
|     if(!logger) | 
|         return ; | 
|   | 
|     cp_log_close(); | 
|   | 
|     if (logger->flag & CP_LOGGER_MALLOC ) | 
|     { | 
|         free(logger); | 
|     } | 
|     logger = NULL; | 
| } | 
|   | 
| void cp_log_raw(const char *fmt, ...) | 
| { | 
|     va_list argp; | 
|   | 
|     if (!logger || !logger->fp) | 
|         return; | 
|   | 
|     check_and_rollback(); | 
|   | 
|     va_start(argp, fmt); | 
|     vfprintf(logger->fp, fmt, argp); | 
|     va_end(argp); | 
| } | 
|   | 
| static void cp_printout(char *level, char *fmt, va_list argp) | 
| { | 
|     char buf[MAX_LOG_MESSAGE_LEN]; | 
|     struct tm *local; | 
|     struct timeval now; | 
|     char timestr[256]; | 
|   | 
|     if(!logger) | 
|         return ; | 
|   | 
|     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, cp_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 (logger->fp) | 
|         fprintf(logger->fp, "%s.%03ld [%s] [%06lu]: %s", timestr, now.tv_usec / PRECISE_TIME_FACTOR, | 
|                 level, tid, buf); | 
|   | 
|     if (logger->fp) | 
|         fflush(logger->fp); | 
| } | 
|   | 
| static void cp_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]; | 
|   | 
|     if(!logger) | 
|         return ; | 
|   | 
|     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, cp_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 (logger->fp) | 
|         fprintf(logger->fp, "%s.%03ld [%s] [%06lu] (%s [%04d]) : %s", | 
|                 timestr, now.tv_usec / PRECISE_TIME_FACTOR, level, tid, file, line, buf); | 
|   | 
|     if (logger->fp) | 
|         fflush(logger->fp); | 
| } | 
|   | 
| void cp_log(int level, char *fmt, ...) | 
| { | 
|     va_list argp; | 
|   | 
|     if (!logger || level>logger->level) | 
|         return; | 
|   | 
|     va_start(argp, fmt); | 
|     cp_printout(log_str[level], fmt, argp); | 
|     va_end(argp); | 
| } | 
|   | 
| void cp_log_line(int level, char *file, int line, char *fmt, ...) | 
| { | 
|     va_list argp; | 
|   | 
|     if (!logger || level>logger->level) | 
|         return; | 
|   | 
|     va_start(argp, fmt); | 
|     cp_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 cp_log_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 (!logger || level>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 (logger->fp) | 
|                 fprintf(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 (logger->fp) | 
|             fprintf(logger->fp, "%s  %s\n", prn, lit); | 
|   | 
|     } | 
| } |