/** * cf_log.c */ #ifdef _WIN32 # define _USE_32BIT_TIME_T #endif #include "cf_log.h" #include "cf_file.h" #include "cf_thread.h" #include "cf_local.h" #include #include #include #include #include #ifdef _WIN32 # define snprintf _snprintf # include #else // #ifdef _WIN32 # include #endif // #ifdef _WIN32 #define CHECK_INVALID_CTX(__ctx) (__ctx == NULL) #define LOCK_LOG_CTX(__ctx) CF_Mutex_Lock (&__ctx->mutex) #define UNLOCK_LOG_CTX(__ctx) CF_Mutex_Unlock (&__ctx->mutex) #define CHECK_INITIALIZED() (gLogEnvironment.ctxPool == NULL|| \ gLogEnvironment.ctxSize <= 0 ) #define CHECK_INVALID_MAPID(__mapid) (gLogEnvironment.ctxSize <= __mapid) #define CHECK_MAPPED_ID(__mapid) (gLogEnvironment.ctxPool[__mapid] != NULL) \ #define CF_LOG_BUFFER_DEFAULT_SIZE 128 * 1024 typedef struct __cf_util_datetime__ { int year; int month; int day; int week; /* SUN:0 ~ SAT:6 */ int hour; int min; int sec; int usec; } S_CF_Log_DateTime, CF_Log_DateTime; typedef struct __cf_log_ctx__ { char path[NAME_LENGTH + 1]; int fd; char * buffer; size_t size; /* entire size of buffer */ size_t length; /* data length in current */ CF_Mutex mutex; } S_CF_LOG_CTX, CF_LOG_CTX; typedef struct __cf_log_environment__ { CF_Log_Ctx * ctxPool; int ctxSize; } S_CF_LOG_ENVIRONMENT, CF_LOG_ENVIRONMENT; CF_LOG_ENVIRONMENT gLogEnvironment; #if defined(_WIN32) || defined(_WIN64) /* #if defined(_WIN32) || defined(_WIN64) {{{ */ struct timezone { int tz_minuteswest; /* minutes W of Greenwich */ int tz_dsttime; /* type of dst correction */ }; // Definition of a gettimeofday function int gettimeofday(struct timeval *tv, struct timezone *tz) { // Define a structure to receive the current Windows filetime FILETIME ft; // Initialize the present time to 0 and the timezone to UTC unsigned __int64 ui64 =0; static int tzflag = 0; if (NULL != tv) { GetSystemTimeAsFileTime(&ft); ui64 = (((unsigned __int64) ft.dwHighDateTime << 32) + (unsigned __int64) ft.dwLowDateTime); if (ui64) { ui64 /= 10; ui64 -= ((369 * 365 + 89) * (unsigned __int64) 86400) * 1000000; } // Finally change microseconds to seconds and place in the seconds value. // The modulus picks up the microseconds. tv->tv_sec = (long)(ui64 / 1000000UL); tv->tv_usec = (long)(ui64 % 1000000UL); } if (NULL != tz) { if (!tzflag) { _tzset(); tzflag++; } // Adjust for the timezone west of Greenwich tz->tz_minuteswest = _timezone / 60; tz->tz_dsttime = _daylight; } return 0; } #endif // #if defined(_WIN32) || defined(_WIN64) /* }}} #if defined(_WIN32) || defined(_WIN64) */ static int CF_Log_Local_GetTime (CF_Log_DateTime * dt) { struct timeval timeVal; struct tm * timeSt; gettimeofday (&timeVal, NULL); timeSt = localtime ((const time_t *)&timeVal.tv_sec); dt->year = timeSt->tm_year + 1900; dt->month = timeSt->tm_mon + 1; dt->day = timeSt->tm_mday; dt->week = timeSt->tm_wday; dt->hour = timeSt->tm_hour; dt->min = timeSt->tm_min; dt->sec = timeSt->tm_sec; dt->usec = (int) timeVal.tv_usec; return CF_OK; } static int CF_Log_Local_GetTimeString (char * buffer) { CF_Log_DateTime dt; CF_Log_Local_GetTime (&dt); snprintf (buffer, strlen ("0000-00-00 00:00:00.000"), "%02d-%02d-%02d %02d:%02d:%02d.%03d", dt.year, dt.month, dt.day, dt.hour, dt.min, dt.sec, dt.usec); return CF_OK; } static int CF_Log_Local_Push (CF_LOG_CTX * ctx, const char * buffer) { strncat (ctx->buffer + ctx->length, buffer, ctx->size - ctx->length); ctx->length = strlen (ctx->buffer); return CF_OK; } static int CF_Log_Local_Flush (CF_LOG_CTX * ctx) { if (CF_File_Write (ctx->fd, ctx->buffer, ctx->length) < 0) return CF_ERROR_LOG_FLUSH; memset (ctx->buffer, 0x00, ctx->size); ctx->length = 0; return CF_OK; } int CF_Log_Initialize (const int logPool) { memset (&gLogEnvironment, 0x00, sizeof (CF_LOG_ENVIRONMENT)); if (logPool > 0) { gLogEnvironment.ctxPool = (CF_Log_Ctx *) calloc ((size_t) logPool, sizeof (CF_Log_Ctx)); if (gLogEnvironment.ctxPool == NULL) return CF_ERROR_LOG_INITIALIZE; gLogEnvironment.ctxSize = logPool; } return CF_OK; } int CF_Log_Finalize (void) { int mapid = 0; for (mapid = 0 ; mapid < gLogEnvironment.ctxSize ; mapid++) { CF_Log_UnmapCtxID (mapid); } if (gLogEnvironment.ctxPool != NULL) free (gLogEnvironment.ctxPool); memset (&gLogEnvironment, 0x00, sizeof (CF_LOG_ENVIRONMENT)); return CF_OK; } CF_Log_Ctx CF_Log_CreateCtx (const char * path, const int memsize) { int result = 0; int size = (memsize == CF_LOG_BUFFER_DEFAULT) ? CF_LOG_BUFFER_DEFAULT_SIZE : memsize; CF_LOG_CTX * context = NULL; if (path == NULL) return NULL; TRY { context = (CF_LOG_CTX *) calloc (sizeof (CF_LOG_CTX), 1); if (context == NULL) { result = -1; TRY_BREAK; } context->fd = CF_File_Create (path); if (context->fd < 0) { result = -2; TRY_BREAK; } sprintf (context->path, "%s", path); if (size > 0) { context->buffer = (char *) calloc ((size_t) size + 1, 1); if (context->buffer == NULL) { result = -3; TRY_BREAK; } context->size = (size_t) size; } } CATCH_IF (result < 0) { CF_Log_DestroyCtx ((CF_Log_Ctx) context); return NULL; } return (CF_Log_Ctx) context; } int CF_Log_DestroyCtx (CF_Log_Ctx ctx) { CF_LOG_CTX * context = (CF_LOG_CTX *) ctx; if (CHECK_INVALID_CTX (ctx)) return CF_ERROR_LOG_INVALID_CTX; memset (context->path, 0x00, sizeof (context->path)); if (context->buffer != NULL) { CF_Log_Flush (ctx); free (context->buffer); context->buffer = NULL; context->size = 0; } CF_File_Close (context->fd); if (context->mutex != NULL) { if (CF_Mutex_Destory (&context->mutex) < 0) /* do something ? */; context->mutex = NULL; } return CF_OK; } int CF_Log_SetMultiThread (CF_Log_Ctx ctx) { CF_LOG_CTX * context = (CF_LOG_CTX *) ctx; if (CHECK_INVALID_CTX (ctx)) return CF_ERROR_LOG_INVALID_CTX; if (CF_Mutex_Create (&context->mutex) < 0) return CF_ERROR_LOG_SET_MULTITHREAD; return CF_OK; } int CF_Log_UnsetMultiThread (CF_Log_Ctx ctx) { CF_LOG_CTX * context = (CF_LOG_CTX *) ctx; if (CHECK_INVALID_CTX (ctx)) return CF_ERROR_LOG_INVALID_CTX; if (CF_Mutex_Destory (&context->mutex) < 0) return CF_ERROR_LOG_UNSET_MULTITHREAD; return CF_OK; } int CF_Log_Write (CF_Log_Ctx ctx, const char * prefix, const char * fmt, ...) { CF_LOG_CTX * context = (CF_LOG_CTX *) ctx; va_list valist; char buffer[4096] = {0x00,}; size_t length = 0; if (CHECK_INVALID_CTX (ctx)) return CF_ERROR_LOG_INVALID_CTX; LOCK_LOG_CTX (context); va_start (valist, fmt); strncat (buffer, "[", 1); CF_Log_Local_GetTimeString (buffer + strlen (buffer)); sprintf (buffer + strlen (buffer), "][%s] ", prefix); vsprintf (buffer + strlen (buffer), fmt, valist); if (context->size == CF_LOG_BUFFER_NO) { context->buffer = buffer; context->length = strlen (buffer); CF_Log_Local_Flush (context); context->buffer = NULL; /* context->length = 0; // already did this in flush */ } else /* (context->size > 0) */ { length = context->size - context->length; CF_Log_Local_Push (context, buffer); if (context->length == context->size) { CF_Log_Local_Flush (context); CF_Log_Local_Push (context, buffer + length); } } va_end (valist); UNLOCK_LOG_CTX (context); return CF_OK; } int CF_Log_Flush (CF_Log_Ctx ctx) { CF_LOG_CTX * context = (CF_LOG_CTX *) ctx; if (CHECK_INVALID_CTX (ctx)) return CF_ERROR_LOG_INVALID_CTX; LOCK_LOG_CTX (context); CF_Log_Local_Flush (context); UNLOCK_LOG_CTX (context); return CF_OK; } int CF_Log_MapCtxID (const int mapid, const CF_Log_Ctx ctx) { int result = 0; TRY { if (CHECK_INITIALIZED()) { result = CF_ERROR_LOG_NOT_INITIALIZE; TRY_BREAK; } if (CHECK_INVALID_MAPID(mapid)) { result = CF_ERROR_LOG_INVALID_MAPID; TRY_BREAK; } if (CHECK_MAPPED_ID(mapid)) { result = CF_ERROR_LOG_ALREADY_MAPPED_ID; TRY_BREAK; } } CATCH_IF (result < 0) { CF_Log_DestroyCtx (ctx); return result; } gLogEnvironment.ctxPool[mapid] = ctx; return CF_OK; } int CF_Log_UnmapCtxID (const int mapid) { if (CHECK_INITIALIZED()) return CF_ERROR_LOG_NOT_INITIALIZE; if (CHECK_INVALID_MAPID(mapid)) return CF_ERROR_LOG_INVALID_MAPID; if (!CHECK_MAPPED_ID(mapid)) return CF_ERROR_LOG_NOT_MAPPED_ID; CF_Log_DestroyCtx (gLogEnvironment.ctxPool[mapid]); free (gLogEnvironment.ctxPool[mapid]); gLogEnvironment.ctxPool[mapid] = NULL; return CF_OK; } CF_Log_Ctx CF_Log_GetMappedCtx (const int mapid) { if (CHECK_INITIALIZED()) return NULL; if (CHECK_INVALID_MAPID(mapid)) return NULL; if (!CHECK_MAPPED_ID(mapid)) return NULL; return gLogEnvironment.ctxPool[mapid]; }