#include "precompile.h" #include #include "log_periodic.h" #include "log_base.h" #include "log_factory.h" #include "log.h" #include "spinlock.h" #include "fileutil.h" #include #include #include #define TAG TOOLKIT_TAG("log_periodic") #ifndef _WIN32 #include #define RWRWRE (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH) #endif //NOT _WIN32 typedef struct periodiclogfactory_t periodiclogfactory_t; extern int fastlock_tryenter(lock_t l); typedef struct periodicfile_t { logbase_t base; char curr_file[MAX_PATH]; char path_template[MAX_PATH]; FILE *fp; LONG use_lock; lock_t lock; LONG flush; int first_record; }periodicfile_t; struct periodiclogfactory_t { logfactory_t base; }; static char* ExpandTemplatePath(SYSTEMTIME *pTime, const char *pTemplatePath, char *path) { char *q = path; const char *p = pTemplatePath; while (*p != 0) { if (*p == '{') { if (0 == strncmp(p, "{yyyy}", 6)) { int t = sprintf(q, "%04d", pTime->wYear); p+=6; q+=t; continue; } else if (0 == strncmp(p, "{MM}", 4)) { int t = sprintf(q, "%02d", pTime->wMonth); p+=4; q+=t; continue; } else if (0 == strncmp(p, "{dd}", 4)) { int t = sprintf(q, "%02d", pTime->wDay); p+=4; q+=t; continue; } else if (0 == strncmp(p, "{hh}", 4)) { int t = sprintf(q, "%02d", pTime->wHour); p+=4; q+=t; continue; } else if (0 == strncmp(p, "{mm}", 4)) { int t = sprintf(q, "%02d", pTime->wMinute); p+=4; q+=t; continue; } else if (0 == strncmp(p, "{ss}", 4)) { int t = sprintf(q, "%02d", pTime->wSecond); p+=4; q+=t; continue; } } *q++ = *p++; } *q = 0; return path; } static void periodicfilefactory_destroy(void *self) { periodiclogfactory_t *fac = (periodiclogfactory_t *)self; if (fac) { free(fac->base.name); free(fac); } } static void* periodicfilefactory_create_log(void *self, const char* inst) { periodiclogfactory_t *fac = (periodiclogfactory_t *)self; periodicfile_t *log = MALLOC_T(periodicfile_t); log->base.level = XLOG_LEVEL_ALL; log->base.factory = self; log->base.inst_name = _strdup(inst); log->fp = NULL; log->use_lock = 0; log->flush = 1; log->curr_file[0] = 0; log->path_template[0] = 0; log->first_record = 0; fastlock_init(log->lock); return log; } static int periodicfilefactory_set_log_param(void *self, void *log, const char *key, const char *value) { periodiclogfactory_t *fac = (periodiclogfactory_t *)self; periodicfile_t *plog = (periodicfile_t *)log; if (_stricmp(key, "file") == 0) { if (value != NULL) { #ifdef _WIN32 if (strchr(value, ':') == NULL) { #else if (value[0] != '/') { #endif // _WIN32 char* p; GetModuleFileNameA(NULL, plog->path_template, MAX_PATH); p = strrchr(plog->path_template, '/'); if (!p) p = strrchr(plog->path_template, '\\'); *(p + 1) = 0; strcpy(p + 1, value); } else { strcpy(plog->path_template, value); } } else { return -1; } } else if (_stricmp(key, "use_lock") == 0) { if (_stricmp(value, "true") == 0 || _stricmp(value, "1") == 0) { plog->use_lock = 1; } else { plog->use_lock = 0; } }else if (_stricmp(key, "flush") == 0) { if (_stricmp(value, "true") == 0 || _stricmp(value, "1") == 0) { plog->flush = 1; } else { plog->flush = 0; } } else if (_stricmp(key, "level") == 0) { if (_stricmp(value, "all") == 0) { plog->base.level = 0; } else if (_stricmp(value, "trace") == 0) { plog->base.level = 1; } else if (_stricmp(value, "debug") == 0) { plog->base.level = 2; } else if (_stricmp(value, "info") == 0) { plog->base.level = 3; } else if (_stricmp(value, "warn") == 0) { plog->base.level = 4; } else if (_stricmp(value, "error") == 0) { plog->base.level = 5; } else if (_stricmp(value, "fatal") == 0) { plog->base.level = 6; } else if (_stricmp(value, "none") == 0) { plog->base.level = 7; } else { return -1; } } else { return -1; } return 0; } static int periodicfilefactory_init_log(void *self, void *log) { periodiclogfactory_t *fac = (periodiclogfactory_t *)self; periodicfile_t *plog = (periodicfile_t *)log; return 0; } static int periodicfilefactory_term_log(void *self, void *log) { periodiclogfactory_t *fac = (periodiclogfactory_t *)self; periodicfile_t *plog = (periodicfile_t *)log; if (plog->fp) { fclose(plog->fp); plog->fp = NULL; } plog->use_lock = 0; return 0; } static void periodicfilefactory_destroy_log(void *self, void *log) { periodiclogfactory_t *fac = (periodiclogfactory_t *)self; periodicfile_t *plog = (periodicfile_t *)log; if (plog) { if (plog->base.inst_name) free(plog->base.inst_name); if (plog->fp) { fclose(plog->fp); plog->fp = NULL; } free(plog); } } static int periodicfilefactory_record_log(void *self, void *log, int level, unsigned long ts_low, unsigned long ts_high, const char *s, int sn) { periodiclogfactory_t *fac = (periodiclogfactory_t *)self; periodicfile_t *plog = (periodicfile_t *)log; SYSTEMTIME st; FILETIME utc_ft, local_ft; char tmp[MAX_PATH]; char *ptmp; int status = 0; //存在可能,某个线程正在Dbg, 未释放,但线程被destory导致lock未释放 if (plog->use_lock) { if (*(plog->lock) == 1) { int i = 0; for (i = 0; i < 10 && 0 == fastlock_tryenter(plog->lock); i++) { } if(10 == i) fastlock_leave(plog->lock); } else fastlock_enter(plog->lock); } //TODO: test the calculate performation. #ifdef _WIN32 utc_ft.dwLowDateTime = (DWORD)ts_low; utc_ft.dwHighDateTime = (DWORD)ts_high; FileTimeToLocalFileTime(&utc_ft, &local_ft); FileTimeToSystemTime(&local_ft, &st); #else GetLocalTime(&st); #endif // _WIN32 ExpandTemplatePath(&st, plog->path_template, tmp); ptmp = strrchr(tmp, '/'); if(!ptmp) ptmp = strrchr(tmp, '\\'); *ptmp = 0; CreateDirRecursiveA(tmp); *ptmp = SPLIT_SLASH; if (strcmp(tmp, plog->curr_file) != 0) { if (plog->fp) { fclose(plog->fp); plog->fp = NULL; } plog->fp = fopen(tmp, "ab"); if (plog->fp) { /*fix bug*/ int flen = 0; strcpy(plog->curr_file, tmp); fseek(plog->fp, 0, SEEK_END); flen = ftell(plog->fp); plog->first_record = !flen; } else { plog->curr_file[0] = 0; } } if (plog->fp) { if (NULL != s && sn > 0) { #ifndef _WIN32 if (plog->first_record) { fchmod(fileno(plog->fp), RWRWRE); } #endif //NOT _WIN32 DWORD dwBytesWritten = 0; char tmp[64]; int n; if (plog->first_record) { n = sprintf(tmp, "[%02d:%02d:%02d.%03d][%s] ", st.wHour, st.wMinute, st.wSecond, st.wMilliseconds, log_level2str(level)); plog->first_record = 0; } else { //TODO: CrossPlaform 这个不太好处理,需要直接修改WINPR中的GetCurrentThreadId原始函数,但这个函数有其他引用 [Gifur@202584] n = sprintf(tmp, LINE_BREAK_STR "[%02d:%02d:%02d.%03d][%5u][%s] ", st.wHour, st.wMinute, st.wSecond, st.wMilliseconds, #if defined(_MSC_VER) GetCurrentThreadId(), #else GetCurrentThreadIdFromSys(), #endif log_level2str(level)); } _fwrite_nolock(tmp, n, 1, plog->fp); _fwrite_nolock(s, sn, 1, plog->fp); // Only for debugging. [3/24/2020 16:58 Gifur] WLog_DBG(TAG, s); if (plog->flush) _fflush_nolock(plog->fp); } } else { status = -1; } if (plog->use_lock) { fastlock_leave(plog->lock); } return status; } int periodicfilefactory_create(logfactory_t **p_fac) { periodiclogfactory_t *fac; if (!p_fac) return -1; fac = ZALLOC_T(periodiclogfactory_t); if (!fac) { return -1; } fac->base.name = _strdup("periodic"); fac->base.record_log = &periodicfilefactory_record_log; fac->base.init_log = &periodicfilefactory_init_log; fac->base.set_log_param = &periodicfilefactory_set_log_param; fac->base.term_log = &periodicfilefactory_term_log; fac->base.create_log = &periodicfilefactory_create_log; fac->base.destroy_log = &periodicfilefactory_destroy_log; fac->base.destroy = &periodicfilefactory_destroy; *p_fac = &fac->base; return 0; }