Changeset 36344 in vbox for trunk/src/VBox/Runtime/common
- Timestamp:
- Mar 22, 2011 2:29:37 PM (14 years ago)
- svn:sync-xref-src-repo-rev:
- 70679
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Runtime/common/log/log.cpp
r33595 r36344 5 5 6 6 /* 7 * Copyright (C) 2006-201 0Oracle Corporation7 * Copyright (C) 2006-2011 Oracle Corporation 8 8 * 9 9 * This file is part of VirtualBox Open Source Edition (OSE), as … … 89 89 static void rtR0LogLoggerExFallback(uint32_t fDestFlags, uint32_t fFlags, const char *pszFormat, va_list va); 90 90 #endif 91 #ifdef IN_RING3 92 static int rtlogFileOpen(PRTLOGGER pLogger, char *pszErrorMsg, size_t cchErrorMsg); 93 static void rtlogRotate(PRTLOGGER pLogger, uint32_t uTimeSlot, bool fFirst); 94 #endif 91 95 static void rtlogFlush(PRTLOGGER pLogger); 92 96 static DECLCALLBACK(size_t) rtLogOutput(void *pv, const char *pachChars, size_t cbChars); 93 97 static DECLCALLBACK(size_t) rtLogOutputPrefixed(void *pv, const char *pachChars, size_t cbChars); 98 static void rtlogLoggerExV(PRTLOGGER pLogger, unsigned fFlags, unsigned iGroup, const char *pszFormat, va_list args); 94 99 95 100 … … 190 195 { "file", sizeof("file" ) - 1, RTLOGDEST_FILE }, /* Must be 1st! */ 191 196 { "dir", sizeof("dir" ) - 1, RTLOGDEST_FILE }, /* Must be 2nd! */ 197 { "history", sizeof("history" ) - 1, 0 }, /* Must be 3rd! */ 198 { "histsize", sizeof("histsize") - 1, 0 }, /* Must be 4th! */ 199 { "histtime", sizeof("histtime") - 1, 0 }, /* Must be 5th! */ 192 200 { "stdout", sizeof("stdout" ) - 1, RTLOGDEST_STDOUT }, 193 201 { "stderr", sizeof("stderr" ) - 1, RTLOGDEST_STDERR }, … … 225 233 { 226 234 #ifndef IN_RC 227 if (pLogger->hSpinMtx != NIL_RTSEM FASTMUTEX)235 if (pLogger->hSpinMtx != NIL_RTSEMSPINMUTEX) 228 236 RTSemSpinMutexRelease(pLogger->hSpinMtx); 229 237 #endif … … 233 241 234 242 #ifndef IN_RC 243 # ifdef IN_RING3 244 /** 245 * Logging to file, output callback. 246 * 247 * @param pvArg User argument. 248 * @param pachChars Pointer to an array of utf-8 characters. 249 * @param cbChars Number of bytes in the character array pointed to by pachChars. 250 */ 251 static DECLCALLBACK(size_t) rtlogPhaseWrite(void *pvArg, const char *pachChars, size_t cbChars) 252 { 253 PRTLOGGER pLogger = (PRTLOGGER)pvArg; 254 RTFileWrite(pLogger->pFile->File, pachChars, cbChars, NULL); 255 return cbChars; 256 } 257 258 /** 259 * Callback to format VBox formatting extentions. 260 * See @ref pg_rt_str_format for a reference on the format types. 261 * 262 * @returns The number of bytes formatted. 263 * @param pvArg Formatter argument. 264 * @param pfnOutput Pointer to output function. 265 * @param pvArgOutput Argument for the output function. 266 * @param ppszFormat Pointer to the format string pointer. Advance this till the char 267 * after the format specifier. 268 * @param pArgs Pointer to the argument list. Use this to fetch the arguments. 269 * @param cchWidth Format Width. -1 if not specified. 270 * @param cchPrecision Format Precision. -1 if not specified. 271 * @param fFlags Flags (RTSTR_NTFS_*). 272 * @param chArgSize The argument size specifier, 'l' or 'L'. 273 */ 274 static DECLCALLBACK(size_t) rtlogPhaseFormatStr(void *pvArg, PFNRTSTROUTPUT pfnOutput, void *pvArgOutput, 275 const char **ppszFormat, va_list *pArgs, int cchWidth, 276 int cchPrecision, unsigned fFlags, char chArgSize) 277 { 278 char ch = *(*ppszFormat)++; 279 280 AssertMsgFailed(("Invalid logger phase format type '%%%c%.10s'!\n", ch, *ppszFormat)); NOREF(ch); 281 282 return 0; 283 } 284 285 /** 286 * Log phase callback function, assumes the lock is already held 287 * 288 * @param pLogger The logger instance. 289 * @param pszFormat Format string. 290 * @param ... Optional arguments as specified in the format string. 291 */ 292 static DECLCALLBACK(void) rtlogPhaseMsgLocked(PRTLOGGER pLogger, const char *pszFormat, ...) 293 { 294 va_list args; 295 AssertPtrReturnVoid(pLogger); 296 AssertPtrReturnVoid(pLogger->pFile); 297 Assert(pLogger->hSpinMtx != NIL_RTSEMSPINMUTEX); 298 299 va_start(args, pszFormat); 300 rtlogLoggerExV(pLogger, 0, ~0, pszFormat, args); 301 va_end(args); 302 } 303 304 /** 305 * Log phase callback function, assumes the lock is not held 306 * 307 * @param pLogger The logger instance. 308 * @param pszFormat Format string. 309 * @param ... Optional arguments as specified in the format string. 310 */ 311 static DECLCALLBACK(void) rtlogPhaseMsgNormal(PRTLOGGER pLogger, const char *pszFormat, ...) 312 { 313 va_list args; 314 AssertPtrReturnVoid(pLogger); 315 AssertPtrReturnVoid(pLogger->pFile); 316 Assert(pLogger->hSpinMtx != NIL_RTSEMSPINMUTEX); 317 318 va_start(args, pszFormat); 319 RTLogLoggerExV(pLogger, 0, ~0, pszFormat, args); 320 va_end(args); 321 } 322 # endif /* IN_RING3 */ 323 235 324 /** 236 325 * Create a logger instance, comprehensive version. … … 246 335 * logger instance. 247 336 * @param fDestFlags The destination flags. RTLOGDEST_FILE is ORed if pszFilenameFmt specified. 337 * @param pfnPhase Callback function for starting logging and for ending or starting a new file for log history rotation. 338 * @param cHistory Number of old log files to keep when performing log history rotation. 339 * @param cbHistoryFileMax Maximum size of log file when performing history rotation. 0=no size limit. 340 * @param uHistoryTimeSlotLength Maximum time interval per log file when performing history rotation, in seconds. 0=no time limit. 248 341 * @param pszErrorMsg A buffer which is filled with an error message if something fails. May be NULL. 249 342 * @param cchErrorMsg The size of the error message buffer. … … 253 346 RTDECL(int) RTLogCreateExV(PRTLOGGER *ppLogger, uint32_t fFlags, const char *pszGroupSettings, 254 347 const char *pszEnvVarBase, unsigned cGroups, const char * const * papszGroups, 255 uint32_t fDestFlags, char *pszErrorMsg, size_t cchErrorMsg, const char *pszFilenameFmt, va_list args) 348 uint32_t fDestFlags, PFNRTLOGPHASE pfnPhase, uint32_t cHistory, 349 uint64_t cbHistoryFileMax, uint32_t uHistoryTimeSlotLength, 350 char *pszErrorMsg, size_t cchErrorMsg, const char *pszFilenameFmt, va_list args) 256 351 { 257 352 int rc; … … 278 373 */ 279 374 cb = RT_OFFSETOF(RTLOGGER, afGroups[cGroups + 1]) + RTPATH_MAX; 375 #ifdef IN_RING3 376 cb += sizeof(RTLOGGERFILE); 377 #endif 280 378 pLogger = (PRTLOGGER)RTMemAllocZVar(cb); 281 379 if (pLogger) … … 289 387 pLogger->cMaxGroups = cGroups; 290 388 pLogger->cGroups = cGroups; 291 pLogger->pszFilename = (char *)&pLogger->afGroups[cGroups + 1]; 292 pLogger->File = NIL_RTFILE; 389 #ifdef IN_RING3 390 pLogger->pFile = (PRTLOGGERFILE)((char *)&pLogger->afGroups[cGroups + 1] + RTPATH_MAX); 391 pLogger->pFile->File = NIL_RTFILE; 392 pLogger->pFile->pszFilename = (char *)&pLogger->afGroups[cGroups + 1]; 393 pLogger->pFile->pfnPhase = pfnPhase; 394 pLogger->pFile->cHistory = cHistory; 395 if (cbHistoryFileMax == 0) 396 pLogger->pFile->cbHistoryFileMax = UINT64_MAX; 397 else 398 pLogger->pFile->cbHistoryFileMax = cbHistoryFileMax; 399 if (uHistoryTimeSlotLength == 0) 400 pLogger->pFile->uHistoryTimeSlotLength = UINT32_MAX; 401 else 402 pLogger->pFile->uHistoryTimeSlotLength = uHistoryTimeSlotLength; 403 #else /* !IN_RING3 */ 404 pLogger->pFile = NULL; 405 #endif /* !IN_RING3 */ 293 406 pLogger->fFlags = fFlags; 294 407 pLogger->fDestFlags = fDestFlags; … … 337 450 if (pszFilenameFmt) 338 451 { 339 RTStrPrintfV(pLogger->p szFilename, RTPATH_MAX, pszFilenameFmt, args);452 RTStrPrintfV(pLogger->pFile->pszFilename, RTPATH_MAX, pszFilenameFmt, args); 340 453 pLogger->fDestFlags |= RTLOGDEST_FILE; 341 454 } … … 384 497 if (pLogger->fDestFlags & RTLOGDEST_FILE) 385 498 { 386 uint32_t fOpen = RTFILE_O_WRITE | RTFILE_O_DENY_WRITE;387 499 if (pLogger->fFlags & RTLOGFLAGS_APPEND) 388 fOpen |= RTFILE_O_OPEN_CREATE | RTFILE_O_APPEND; 500 { 501 rc = rtlogFileOpen(pLogger, pszErrorMsg, cchErrorMsg); 502 /* Rotate in case of appending to a too big log file, 503 * otherwise this simply doesn't do anything. */ 504 rtlogRotate(pLogger, 0, true /* fFirst */); 505 } 389 506 else 390 fOpen |= RTFILE_O_CREATE_REPLACE; 391 if (pLogger->fFlags & RTLOGFLAGS_WRITE_THROUGH) 392 fOpen |= RTFILE_O_WRITE_THROUGH; 393 rc = RTFileOpen(&pLogger->File, pLogger->pszFilename, fOpen); 394 if (RT_FAILURE(rc) && pszErrorMsg) 395 RTStrPrintf(pszErrorMsg, cchErrorMsg, N_("could not open file '%s' (fOpen=%#x)"), pLogger->pszFilename, fOpen); 507 { 508 /* Force rotation if it is configured. */ 509 pLogger->pFile->cbHistoryFileWritten = UINT64_MAX; 510 rtlogRotate(pLogger, 0, true /* fFirst */); 511 /* If the file is not open then rotation is not set up. */ 512 if (pLogger->pFile->File == NIL_RTFILE) 513 { 514 pLogger->pFile->cbHistoryFileWritten = 0; 515 rc = rtlogFileOpen(pLogger, pszErrorMsg, cchErrorMsg); 516 } 517 } 396 518 } 519 520 /* Use the callback to generate some initial log contents. */ 521 Assert(VALID_PTR(pLogger->pFile->pfnPhase) || pLogger->pFile->pfnPhase == NULL); 522 if (pLogger->pFile->pfnPhase) 523 pfnPhase(pLogger, RTLOGPHASE_BEGIN, rtlogPhaseMsgNormal); 397 524 #endif /* IN_RING3 */ 398 525 … … 425 552 } 426 553 #ifdef IN_RING3 427 RTFileClose(pLogger-> File);554 RTFileClose(pLogger->pFile->File); 428 555 #endif 429 556 #if defined(LOG_USE_C99) && defined(RT_WITHOUT_EXEC_ALLOC) … … 456 583 * logger instance. 457 584 * @param fDestFlags The destination flags. RTLOGDEST_FILE is ORed if pszFilenameFmt specified. 585 * @param pfnPhase Callback function for starting logging and for ending or starting a new file for log history rotation. 586 * @param cHistory Number of old log files to keep when performing log history rotation. 587 * @param cbHistoryFileMax Maximum size of log file when performing history rotation. 0=no size limit. 588 * @param uHistoryTimeSlotLength Maximum time interval per log file when performing history rotation, in seconds. 0=no time limit. 458 589 * @param pszFilenameFmt Log filename format string. Standard RTStrFormat(). 459 590 * @param ... Format arguments. … … 461 592 RTDECL(int) RTLogCreate(PRTLOGGER *ppLogger, uint32_t fFlags, const char *pszGroupSettings, 462 593 const char *pszEnvVarBase, unsigned cGroups, const char * const * papszGroups, 463 uint32_t fDestFlags, const char *pszFilenameFmt, ...) 594 uint32_t fDestFlags, PFNRTLOGPHASE pfnPhase, uint32_t cHistory, 595 uint64_t cbHistoryFileMax, uint32_t uHistoryTimeSlotLength, 596 const char *pszFilenameFmt, ...) 464 597 { 465 598 va_list args; … … 467 600 468 601 va_start(args, pszFilenameFmt); 469 rc = RTLogCreateExV(ppLogger, fFlags, pszGroupSettings, pszEnvVarBase, cGroups, papszGroups, fDestFlags, NULL, 0, pszFilenameFmt, args);602 rc = RTLogCreateExV(ppLogger, fFlags, pszGroupSettings, pszEnvVarBase, cGroups, papszGroups, fDestFlags, pfnPhase, cHistory, cbHistoryFileMax, uHistoryTimeSlotLength, NULL, 0, pszFilenameFmt, args); 470 603 va_end(args); 471 604 return rc; … … 487 620 * logger instance. 488 621 * @param fDestFlags The destination flags. RTLOGDEST_FILE is ORed if pszFilenameFmt specified. 622 * @param pfnPhase Callback function for starting logging and for ending or starting a new file for log history rotation. 623 * @param cHistory Number of old log files to keep when performing log history rotation. 624 * @param cbHistoryFileMax Maximum size of log file when performing history rotation. 0=no size limit. 625 * @param uHistoryTimeSlotLength Maximum time interval per log file when performing history rotation, in seconds. 0=no time limit. 489 626 * @param pszErrorMsg A buffer which is filled with an error message if something fails. May be NULL. 490 627 * @param cchErrorMsg The size of the error message buffer. … … 494 631 RTDECL(int) RTLogCreateEx(PRTLOGGER *ppLogger, uint32_t fFlags, const char *pszGroupSettings, 495 632 const char *pszEnvVarBase, unsigned cGroups, const char * const * papszGroups, 496 uint32_t fDestFlags, char *pszErrorMsg, size_t cchErrorMsg, const char *pszFilenameFmt, ...) 633 uint32_t fDestFlags, PFNRTLOGPHASE pfnPhase, uint32_t cHistory, 634 uint64_t cbHistoryFileMax, uint32_t uHistoryTimeSlotLength, 635 char *pszErrorMsg, size_t cchErrorMsg, const char *pszFilenameFmt, ...) 497 636 { 498 637 va_list args; … … 500 639 501 640 va_start(args, pszFilenameFmt); 502 rc = RTLogCreateExV(ppLogger, fFlags, pszGroupSettings, pszEnvVarBase, cGroups, papszGroups, fDestFlags, p szErrorMsg, cchErrorMsg, pszFilenameFmt, args);641 rc = RTLogCreateExV(ppLogger, fFlags, pszGroupSettings, pszEnvVarBase, cGroups, papszGroups, fDestFlags, pfnPhase, cHistory, cbHistoryFileMax, uHistoryTimeSlotLength, pszErrorMsg, cchErrorMsg, pszFilenameFmt, args); 503 642 va_end(args); 504 643 return rc; … … 545 684 rtlogFlush(pLogger); 546 685 686 #ifdef IN_RING3 687 /* 688 * Add end of logging message. 689 */ 690 if (pLogger->fDestFlags & RTLOGDEST_FILE && pLogger->pFile->File != NIL_RTFILE) 691 pLogger->pFile->pfnPhase(pLogger, RTLOGPHASE_END, rtlogPhaseMsgLocked); 692 547 693 /* 548 694 * Close output stuffs. 549 695 */ 550 #ifdef IN_RING3 551 if (pLogger->File != NIL_RTFILE) 552 { 553 int rc2 = RTFileClose(pLogger->File); 696 if (pLogger->pFile->File != NIL_RTFILE) 697 { 698 int rc2 = RTFileClose(pLogger->pFile->File); 554 699 AssertRC(rc2); 555 700 if (RT_FAILURE(rc2) && RT_SUCCESS(rc)) 556 701 rc = rc2; 557 pLogger-> File = NIL_RTFILE;702 pLogger->pFile->File = NIL_RTFILE; 558 703 } 559 704 #endif … … 766 911 pLogger->fFlags = fFlags; 767 912 pLogger->fDestFlags = fDestFlags & ~RTLOGDEST_FILE; 768 pLogger->File = NIL_RTFILE; 769 pLogger->pszFilename = NULL; 913 pLogger->pFile = NULL; 770 914 pLogger->papszGroups = NULL; 771 915 pLogger->cMaxGroups = (uint32_t)((cbLogger - RT_OFFSETOF(RTLOGGER, afGroups[0])) / sizeof(pLogger->afGroups[0])); … … 1604 1748 { 1605 1749 AssertReturn(cch < RTPATH_MAX, VERR_OUT_OF_RANGE); 1606 memcpy(pLogger->p szFilename, pszVar, cch);1607 pLogger->p szFilename[cch] = '\0';1750 memcpy(pLogger->pFile->pszFilename, pszVar, cch); 1751 pLogger->pFile->pszFilename[cch] = '\0'; 1608 1752 } 1609 1753 /* log directory */ … … 1611 1755 { 1612 1756 char szTmp[RTPATH_MAX]; 1613 const char *pszFile = RTPathFilename(pLogger->p szFilename);1757 const char *pszFile = RTPathFilename(pLogger->pFile->pszFilename); 1614 1758 size_t cchFile = pszFile ? strlen(pszFile) : 0; 1615 1759 AssertReturn(cchFile + cch + 1 < RTPATH_MAX, VERR_OUT_OF_RANGE); 1616 1760 memcpy(szTmp, cchFile ? pszFile : "", cchFile + 1); 1617 1761 1618 memcpy(pLogger->pszFilename, pszVar, cch); 1619 pLogger->pszFilename[cch] = '\0'; 1620 RTPathStripTrailingSlash(pLogger->pszFilename); 1621 1622 cch = strlen(pLogger->pszFilename); 1623 pLogger->pszFilename[cch++] = '/'; 1624 memcpy(&pLogger->pszFilename[cch], szTmp, cchFile); 1625 pLogger->pszFilename[cch+cchFile] = '\0'; 1762 memcpy(pLogger->pFile->pszFilename, pszVar, cch); 1763 pLogger->pFile->pszFilename[cch] = '\0'; 1764 RTPathStripTrailingSlash(pLogger->pFile->pszFilename); 1765 1766 cch = strlen(pLogger->pFile->pszFilename); 1767 pLogger->pFile->pszFilename[cch++] = '/'; 1768 memcpy(&pLogger->pFile->pszFilename[cch], szTmp, cchFile); 1769 pLogger->pFile->pszFilename[cch+cchFile] = '\0'; 1770 } 1771 else if (i == 2 /* history */) 1772 { 1773 if (!fNo) 1774 { 1775 char szTmp[32]; 1776 int rc = RTStrCopyEx(szTmp, sizeof(szTmp), pszVar, cch); 1777 if (RT_SUCCESS(rc)) 1778 rc = RTStrToUInt32Full(szTmp, 0, &pLogger->pFile->cHistory); 1779 if (RT_FAILURE(rc)) 1780 AssertMsgFailedReturn(("Invalid history value %s (%Rrc)!\n", 1781 szTmp, rc), rc); 1782 } 1783 else 1784 pLogger->pFile->cHistory = 0; 1785 } 1786 else if (i == 3 /* histsize */) 1787 { 1788 if (!fNo) 1789 { 1790 char szTmp[32]; 1791 int rc = RTStrCopyEx(szTmp, sizeof(szTmp), pszVar, cch); 1792 if (RT_SUCCESS(rc)) 1793 rc = RTStrToUInt64Full(szTmp, 0, &pLogger->pFile->cbHistoryFileMax); 1794 if (RT_FAILURE(rc)) 1795 AssertMsgFailedReturn(("Invalid history file size value %s (%Rrc)!\n", 1796 szTmp, rc), rc); 1797 if (pLogger->pFile->cbHistoryFileMax == 0) 1798 pLogger->pFile->cbHistoryFileMax = UINT64_MAX; 1799 } 1800 else 1801 pLogger->pFile->cbHistoryFileMax = UINT64_MAX; 1802 } 1803 else if (i == 4 /* histtime */) 1804 { 1805 if (!fNo) 1806 { 1807 char szTmp[32]; 1808 int rc = RTStrCopyEx(szTmp, sizeof(szTmp), pszVar, cch); 1809 if (RT_SUCCESS(rc)) 1810 rc = RTStrToUInt32Full(szTmp, 0, &pLogger->pFile->uHistoryTimeSlotLength); 1811 if (RT_FAILURE(rc)) 1812 AssertMsgFailedReturn(("Invalid history timespan value %s (%Rrc)!\n", 1813 szTmp, rc), rc); 1814 if (pLogger->pFile->uHistoryTimeSlotLength == 0) 1815 pLogger->pFile->uHistoryTimeSlotLength = UINT32_MAX; 1816 } 1817 else 1818 pLogger->pFile->uHistoryTimeSlotLength = UINT32_MAX; 1626 1819 } 1627 1820 else … … 1704 1897 } 1705 1898 1899 #ifdef IN_RING3 1706 1900 /* 1707 1901 * Add the filename. 1708 1902 */ 1709 1903 if ( (fDestFlags & RTLOGDEST_FILE) 1710 && VALID_PTR(pLogger->p szFilename)1904 && VALID_PTR(pLogger->pFile->pszFilename) 1711 1905 && RT_SUCCESS(rc)) 1712 1906 { 1713 size_t cchFilename = strlen(pLogger->p szFilename);1907 size_t cchFilename = strlen(pLogger->pFile->pszFilename); 1714 1908 if (cchFilename + sizeof("file=") - 1 + fNotFirst + 1 <= cchBuf) 1715 1909 { … … 1718 1912 else 1719 1913 APPEND_SZ("file="); 1720 APPEND_PSZ(pLogger->p szFilename, cchFilename);1914 APPEND_PSZ(pLogger->pFile->pszFilename, cchFilename); 1721 1915 } 1722 1916 else 1723 1917 rc = VERR_BUFFER_OVERFLOW; 1724 1918 } 1919 #endif 1725 1920 1726 1921 #undef APPEND_PSZ … … 2032 2227 2033 2228 /* 2034 * Format the message and perhaps flush it. 2035 */ 2036 if (pLogger->fFlags & (RTLOGFLAGS_PREFIX_MASK | RTLOGFLAGS_USECRLF)) 2037 { 2038 RTLOGOUTPUTPREFIXEDARGS OutputArgs; 2039 OutputArgs.pLogger = pLogger; 2040 OutputArgs.iGroup = iGroup; 2041 OutputArgs.fFlags = fFlags; 2042 RTLogFormatV(rtLogOutputPrefixed, &OutputArgs, pszFormat, args); 2043 } 2044 else 2045 RTLogFormatV(rtLogOutput, pLogger, pszFormat, args); 2046 if ( !(pLogger->fFlags & RTLOGFLAGS_BUFFERED) 2047 && pLogger->offScratch) 2048 rtlogFlush(pLogger); 2229 * Call worker. 2230 */ 2231 rtlogLoggerExV(pLogger, fFlags, iGroup, pszFormat, args); 2049 2232 2050 2233 /* … … 2217 2400 2218 2401 2402 #ifdef IN_RING3 2403 /** 2404 * Opens/creates the log file. 2405 * 2406 * @param pLogger The logger instance to update. NULL is not allowed! 2407 * @param pszErrorMsg A buffer which is filled with an error message if something fails. May be NULL. 2408 * @param cchErrorMsg The size of the error message buffer. 2409 */ 2410 static int rtlogFileOpen(PRTLOGGER pLogger, char *pszErrorMsg, size_t cchErrorMsg) 2411 { 2412 uint32_t fOpen = RTFILE_O_WRITE | RTFILE_O_DENY_WRITE; 2413 if (pLogger->fFlags & RTLOGFLAGS_APPEND) 2414 fOpen |= RTFILE_O_OPEN_CREATE | RTFILE_O_APPEND; 2415 else 2416 fOpen |= RTFILE_O_CREATE_REPLACE; 2417 if (pLogger->fFlags & RTLOGFLAGS_WRITE_THROUGH) 2418 fOpen |= RTFILE_O_WRITE_THROUGH; 2419 int rc = RTFileOpen(&pLogger->pFile->File, pLogger->pFile->pszFilename, fOpen); 2420 if (RT_FAILURE(rc)) 2421 { 2422 pLogger->pFile->File = NIL_RTFILE; 2423 if (pszErrorMsg) 2424 RTStrPrintf(pszErrorMsg, cchErrorMsg, N_("could not open file '%s' (fOpen=%#x)"), pLogger->pFile->pszFilename, fOpen); 2425 } 2426 else 2427 { 2428 rc = RTFileGetSize(pLogger->pFile->File, &pLogger->pFile->cbHistoryFileWritten); 2429 if (RT_FAILURE(rc)) 2430 { 2431 /* Don't complain if this fails, assume the file is empty. */ 2432 pLogger->pFile->cbHistoryFileWritten = 0; 2433 rc = VINF_SUCCESS; 2434 } 2435 } 2436 return rc; 2437 } 2438 2439 2440 /** 2441 * Closes, rotates and opens the log files if necessary. 2442 * Used by the rtlogFlush() function. 2443 * 2444 * @param pLogger The logger instance to update. NULL is not allowed! 2445 * @param uTimeSlit Current time slot (for tikme based rotation). 2446 * @param fFirst Flag whether this is the beginning of logging. 2447 */ 2448 static void rtlogRotate(PRTLOGGER pLogger, uint32_t uTimeSlot, bool fFirst) 2449 { 2450 /* Suppress rotating empty log files simply because the time elapsed. */ 2451 if (RT_UNLIKELY(!pLogger->pFile->cbHistoryFileWritten)) 2452 pLogger->pFile->uHistoryTimeSlotStart = uTimeSlot; 2453 2454 /* Check rotation condition: file still small enough and not too old? */ 2455 if (RT_LIKELY( pLogger->pFile->cbHistoryFileWritten < pLogger->pFile->cbHistoryFileMax 2456 && uTimeSlot == pLogger->pFile->uHistoryTimeSlotStart)) 2457 return; 2458 2459 /* Save "disabled" log flag and make sure logging is disabled. 2460 * The logging in the functions called during log file history 2461 * rotation would cause severe trouble otherwise. */ 2462 uint32_t fOFlags = pLogger->fFlags; 2463 pLogger->fFlags |= RTLOGFLAGS_DISABLED; 2464 2465 /* Disable log rotation temporarily, otherwise with extreme settings and 2466 * chatty phase logging we could run into endless rotation. */ 2467 uint32_t cOHistory = pLogger->pFile->cHistory; 2468 pLogger->pFile->cHistory = 0; 2469 2470 /* Close the old log file. */ 2471 if (pLogger->pFile->File != NIL_RTFILE) 2472 { 2473 /* Use the callback to generate some final log contents, but only if 2474 * this is a rotation with a fully set up logger. Leave the other case 2475 * to the RTLogCreateExV function. */ 2476 if (pLogger->pFile->pfnPhase && !fFirst) 2477 { 2478 uint32_t fODestFlags = pLogger->fDestFlags; 2479 pLogger->fDestFlags &= RTLOGDEST_FILE; 2480 pLogger->pFile->pfnPhase(pLogger, RTLOGPHASE_PREROTATE, rtlogPhaseMsgLocked); 2481 pLogger->fDestFlags = fODestFlags; 2482 } 2483 RTFileClose(pLogger->pFile->File); 2484 pLogger->pFile->File = NIL_RTFILE; 2485 } 2486 2487 /* Rotate the log files. */ 2488 if (cOHistory) 2489 { 2490 for (uint32_t i = cOHistory - 1; i + 1 > 0; i--) 2491 { 2492 char szOldName[RTPATH_MAX]; 2493 if (i > 0) 2494 RTStrPrintf(szOldName, sizeof(szOldName), "%s.%u", pLogger->pFile->pszFilename, i); 2495 else 2496 RTStrCopy(szOldName, sizeof(szOldName), pLogger->pFile->pszFilename); 2497 char szNewName[RTPATH_MAX]; 2498 RTStrPrintf(szNewName, sizeof(szNewName), "%s.%u", pLogger->pFile->pszFilename, i + 1); 2499 if (RTFileRename(szOldName, szNewName, 2500 RTFILEMOVE_FLAGS_REPLACE) == VERR_FILE_NOT_FOUND) 2501 RTFileDelete(szNewName); 2502 } 2503 } 2504 /* Delete excess log files. */ 2505 for (uint32_t i = cOHistory + 1; i++; ) 2506 { 2507 char szExcessName[RTPATH_MAX]; 2508 RTStrPrintf(szExcessName, sizeof(szExcessName), "%s.%u", pLogger->pFile->pszFilename, i); 2509 int rc = RTFileDelete(szExcessName); 2510 if (RT_FAILURE(rc)) 2511 break; 2512 } 2513 2514 /* Update logger state and create new log file. */ 2515 pLogger->pFile->cbHistoryFileWritten = 0; 2516 pLogger->pFile->uHistoryTimeSlotStart = uTimeSlot; 2517 rtlogFileOpen(pLogger, NULL, 0); 2518 2519 /* Use the callback to generate some initial log contents, but only if this 2520 * is a rotation with a fully set up logger. Leave the other case to the 2521 * RTLogCreateExV function. */ 2522 if (pLogger->pFile->pfnPhase && !fFirst) 2523 { 2524 uint32_t fODestFlags = pLogger->fDestFlags; 2525 pLogger->fDestFlags &= RTLOGDEST_FILE; 2526 pLogger->pFile->pfnPhase(pLogger, RTLOGPHASE_POSTROTATE, rtlogPhaseMsgLocked); 2527 pLogger->fDestFlags = fODestFlags; 2528 } 2529 2530 /* Restore log rotation to the previous value. */ 2531 pLogger->pFile->cHistory = cOHistory; 2532 2533 /* Restore the log flags to the previous value. */ 2534 pLogger->fFlags = fOFlags; 2535 } 2536 #endif /* IN_RING3 */ 2537 2538 2219 2539 /** 2220 2540 * Writes the buffer to the given log device without checking for buffered … … 2239 2559 if (pLogger->fDestFlags & RTLOGDEST_FILE) 2240 2560 { 2241 RTFileWrite(pLogger->File, pLogger->achScratch, pLogger->offScratch, NULL); 2242 if (pLogger->fFlags & RTLOGFLAGS_FLUSH) 2243 RTFileFlush(pLogger->File); 2561 if (pLogger->pFile->File != NIL_RTFILE) 2562 { 2563 RTFileWrite(pLogger->pFile->File, pLogger->achScratch, pLogger->offScratch, NULL); 2564 if (pLogger->fFlags & RTLOGFLAGS_FLUSH) 2565 RTFileFlush(pLogger->pFile->File); 2566 } 2567 if (pLogger->pFile->cHistory) 2568 pLogger->pFile->cbHistoryFileWritten += pLogger->offScratch; 2244 2569 } 2245 2570 # endif … … 2262 2587 /* empty the buffer. */ 2263 2588 pLogger->offScratch = 0; 2589 2590 # ifdef IN_RING3 2591 /* Rotate the log file if configured. Must be done after everything is 2592 * flushed, since this will also use logging/flushing to write the header 2593 * and footer messages. */ 2594 if ((pLogger->fDestFlags & RTLOGDEST_FILE) && pLogger->pFile->cHistory) 2595 { 2596 rtlogRotate(pLogger, 2597 RTTimeProgramSecTS() / pLogger->pFile->uHistoryTimeSlotLength, 2598 false /* fFirst */); 2599 } 2600 #endif 2264 2601 } 2265 2602 … … 2729 3066 } 2730 3067 3068 /** 3069 * Write to a logger instance (worker function). 3070 * 3071 * This function will check whether the instance, group and flags makes up a 3072 * logging kind which is currently enabled before writing anything to the log. 3073 * 3074 * @param pLogger Pointer to logger instance. Must be non-NULL. 3075 * @param fFlags The logging flags. 3076 * @param iGroup The group. 3077 * The value ~0U is reserved for compatibility with RTLogLogger[V] and is 3078 * only for internal usage! 3079 * @param pszFormat Format string. 3080 * @param args Format arguments. 3081 */ 3082 static void rtlogLoggerExV(PRTLOGGER pLogger, unsigned fFlags, unsigned iGroup, const char *pszFormat, va_list args) 3083 { 3084 /* 3085 * Format the message and perhaps flush it. 3086 */ 3087 if (pLogger->fFlags & (RTLOGFLAGS_PREFIX_MASK | RTLOGFLAGS_USECRLF)) 3088 { 3089 RTLOGOUTPUTPREFIXEDARGS OutputArgs; 3090 OutputArgs.pLogger = pLogger; 3091 OutputArgs.iGroup = iGroup; 3092 OutputArgs.fFlags = fFlags; 3093 RTLogFormatV(rtLogOutputPrefixed, &OutputArgs, pszFormat, args); 3094 } 3095 else 3096 RTLogFormatV(rtLogOutput, pLogger, pszFormat, args); 3097 if ( !(pLogger->fFlags & RTLOGFLAGS_BUFFERED) 3098 && pLogger->offScratch) 3099 rtlogFlush(pLogger); 3100 } 3101
Note:
See TracChangeset
for help on using the changeset viewer.