📄 cplog.cxx
字号:
va_list ap; if (pri <= CpLogPriority::getPriority()) { Lock lock(cpLogMutex); va_start(ap, fmt); vCpLog(pri, m_fname, m_lineno, fmt, ap); va_end(ap); }}#endifvoid cpLog_impl_(int pri, const char* file, int line, const char* fmt, ...){ va_list ap; if (pri <= CpLogPriority::getPriority()) { // We need to protect access to vCpLog. The race we are really // worried about is not the multiple writes to the same file // descriptor, since the underlying system libraries protect // against that. We are more worried about the race caused by file // rotation. If we aren't locked here, we could possible close the // cpLogFd during file rotation, then try to write to that file // from another thread. This is something that the underlying // system libraries cannot protect against. // Lock lock(cpLogMutex); va_start(ap, fmt); vCpLog(pri, file, line, fmt, ap); va_end(ap); }}voidvCpLog(int pri, const char* file, int line, const char* fmt, va_list ap){ assert (pri >= 0 && pri <= LAST_PRIORITY); char datebuf [DATEBUF_SIZE]; int datebufCharsRemaining; struct timeval tv; int result = gettimeofday (&tv, NULL); if (result == -1) { /* If we can't get the time of day, don't print a timestamp. (Under Unix, this will never happen: gettimeofday can fail only if the timezone is invalid [which it can't be, since it is uninitialized] or if &tv or &tz are invalid pointers.) */ datebuf [0] = '\0'; } else { /* The tv_sec field represents the number of seconds passed since the Epoch, which is exactly the argument gettimeofday needs. */ const time_t timeInSeconds = (time_t) tv.tv_sec; struct tm localT; strftime (datebuf, DATEBUF_SIZE, "%Y%m%d-%H%M%S", /* guaranteed to fit in 256 chars, hence don't check return code */#if defined( __APPLE__ ) localtime (&timeInSeconds));#else localtime_r (&timeInSeconds, &localT));#endif } char msbuf[5]; /* Dividing (without remainder) by 1000 rounds the microseconds measure to the nearest millisecond. */ sprintf(msbuf, ".%3.3ld", (tv.tv_usec / 1000)); datebufCharsRemaining = DATEBUF_SIZE - strlen (datebuf); strncat (datebuf, msbuf, datebufCharsRemaining - 1); datebuf[DATEBUF_SIZE - 1] = '\0'; /* Just in case strncat truncated msbuf, thereby leaving its last character at the end, instead of a null terminator */ if (usingSyslog) { #if !defined(WIN32) /* syslog does not recognize priorities conceptually lower (numerically greater) than LOG_DEBUG. If our current priority is lower, "promote" it to LOG_DEBUG. */ int coercedPriority = (pri <= LOG_DEBUG) ? pri : LOG_DEBUG; char buf[4097]; vsnprintf(buf, 4096, fmt, ap); syslog (coercedPriority, "%s [%5.5ld] %s %s: %s:%d %s\n", datebuf, VThread::selfId(), priNameShort[pri], CpLogPriority::getLabel(), file, line, buf); #else printf("syslog not implemented for win32"); assert(0); #endif // !defined(WIN32) } else { fprintf (cpLogFd, "%s [%5.5ld] %s %s: %s:%d ", datebuf, VThread::selfId(), priNameShort[pri], CpLogPriority::getLabel(), file, line); vfprintf (cpLogFd, fmt, ap); fprintf (cpLogFd, "\n"); fflush(cpLogFd); /* in case we just pushed the current file past the size limit... */ rotateFilesIfNecessary(); }}/* Handle a critical error in cpLog itself (an error so bad, by definition,it prevents logging in the normal way). Do this by reverting to usingstandard error as the log "file" and immediately printing a warning aboutthe situation.*/voidhandleCriticalError (char* fmt, ...){ cpLogFd = stderr; strcpy (cpLogFilename, ""); fprintf (cpLogFd, "\nCRITICAL LOGGING ERROR:\n"); va_list ap; va_start (ap, fmt); vfprintf (cpLogFd, fmt, ap); va_end (ap); fprintf (cpLogFd, "\ncpLog has reverted to logging to standard error...\n\n");}inlinevoidrotateFilesIfNecessary(){ /* If we are logging to standard error, there are no files to rotate. */ if (cpLogFd == stderr) { return; } /* If we are logging to syslog, log rotation is somebody else's problem (SEP); the log file name is outside of our knowledge, and the file itself may be outside of our permissions */ if (usingSyslog) { return; } /* Test to see if the present log file has exceeded the maximum size. (If it has, rotate it.) */ struct stat fileInfo; if (stat (cpLogFilename, &fileInfo)) { /* What? We can't see the log file? */ handleCriticalError ("cpLog could not stat its own current log file, %s: %s", cpLogFilename, strerror (errno)); return; } if (fileInfo.st_size >= SIZE_PER_LOGFILE) { rotateFiles(); }}/* Move the file names, cascading down, so that logfile.1 is renamedto logfile.2, logfile.2 is renamed to logfile.3, et cetera. logfile.6,if it exists, will be overwritten. */voidrotateFiles(){ /* First double-check the log file size, to avoid a race condition. It is possible that, between the time rotateFiles was called and the present moment, some other thread has attempted to log a message (using vCpLog), noticed that fileInfo.st_size +. SIZE_PER_LOGFILE (in rotateFilesIfNecessary), and rotated the logs out from under us. */ struct stat fileInfo; if (stat (cpLogFilename, &fileInfo) != 0) { handleCriticalError ("rotateFiles could not stat the log file (%s)", cpLogFilename); } if (fileInfo.st_size < SIZE_PER_LOGFILE) { /* The race condition occurred; our files have already been moved for us. */ return; } /* Close the current log file */ if( fclose (cpLogFd) ) { handleCriticalError ("Could not close the log file: %s", strerror (errno)); } /* Make room for the new log file */ for( int i = numberOfBackupFilesToKeep - 1; i >= 0; i-- ) { string oldFilename( cpLogFilename ); if( i > 0 ) { oldFilename += "." + itos( i ); } const char* oldFilename_c_str = oldFilename.c_str(); if (stat (oldFilename_c_str, &fileInfo) == 0) /* if the file _does_ exist... */ { string newFilename( cpLogFilename ); newFilename += "." + itos( i+1 ); const char* newFilename_c_str = newFilename.c_str(); if (rename (oldFilename_c_str, newFilename_c_str) != 0) /* If rename() fails... */ { handleCriticalError ("cpLog could not rename %s to %s: %s", oldFilename_c_str, newFilename_c_str, strerror (errno)); return; } } /* The only reason the file should be un-stat-able is that it does not exist. That is a legitimate condition, since rotation may not yet have created a file with that number (i). Any other failure is an error. */ else if (errno != ENOENT) { handleCriticalError ("cpLog could not stat %s: %s", oldFilename_c_str, strerror (errno)); return; } } /* Open the log file for writing once more. (The current log file will always have the name stored in cpLogFilename, without a numeric extension.)*/ openTheLogFile();}voidcpLogSetPriority (int pri){ CpLogPriority::setPriority(pri);}intcpLogGetPriority (){ return CpLogPriority::getPriority();}voidcpLogSetPriorityThread (vthread_t thread_id, int pri){ if (pri < 0) return ; CpLogPriority::setPriorityThread(thread_id, pri);}voidcpLogClearPriorityThread (vthread_t thread_id){ CpLogPriority::clearPriorityThread(thread_id);}voidcpLogSetLabel (const char* label){ CpLogPriority::setLabel(label);}voidcpLogSetLabelThread (vthread_t thread_id, const char* label){ CpLogPriority::setLabelThread(thread_id, label);}voidcpLogClearLabelThread (vthread_t thread_id){ CpLogPriority::clearLabelThread(thread_id);}voidcpLogShow (void){ fprintf (stderr, "\tLabel : %s\n", CpLogPriority::getLabel()); fprintf (stderr, "\tPriority : %s\n", priName[CpLogPriority::getPriority()]); fprintf (stderr, "\tFile : %s (cpLogFd = %d)\n", cpLogFilename, fileno(cpLogFd));}intcpLogStrToPriority(const char* priority){ string pri = priority; if (pri.find("LOG_", 0) == 0) { pri.erase(0, 4); } int i = 0; while (priName[i] != 0) { if (pri == priName[i]) { return i; } i++; } return -1; // invalid}void cpLogSetFileSize (const int size){ SIZE_PER_LOGFILE = size;} void cpLogSetNumOfBackupFiles (const int num){ numberOfBackupFilesToKeep = num;}const char*cpLogPriorityToStr(int priority){ int priorityCount = 0; while (priName[priorityCount] != 0) { priorityCount++; } if ((priority >= 0) && (priority < priorityCount)) { return priName[priority]; } else { return 0; }}/* this function is not called, it is just compiled to make sure that the cpLog Macro expansion works */voidtestCpLogMacroExpansion(){ if (true) cpLog(LOG_DEBUG, "this is a test"); else cpLog(LOG_DEBUG, "and a second");}/* Local Variables: *//* c-file-style: "stroustrup" *//* indent-tabs-mode: nil *//* c-file-offsets: ((access-label . -) (inclass . ++)) *//* c-basic-offset: 4 *//* End: */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -