VirtualBox

Changeset 36344 in vbox for trunk/src/VBox


Ignore:
Timestamp:
Mar 22, 2011 2:29:37 PM (14 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
70679
Message:

Runtime/log: implement log rotation, adapt all code creating log files and make use of it in the webservice

Location:
trunk/src/VBox
Files:
8 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Frontends/VBoxBFE/VBoxBFE.cpp

    r35346 r36344  
    1111
    1212/*
    13  * Copyright (C) 2006-2009 Oracle Corporation
     13 * Copyright (C) 2006-2011 Oracle Corporation
    1414 *
    1515 * This file is part of VirtualBox Open Source Edition (OSE), as
     
    11361136        PRTLOGGER pLogger;
    11371137        rc2 = RTLogCreateEx(&pLogger, RTLOGFLAGS_PREFIX_TIME_PROG, "all",
    1138                             "VBOX_RELEASE_LOG", RT_ELEMENTS(s_apszGroups), s_apszGroups,
    1139                             RTLOGDEST_FILE, s_szError, sizeof(s_szError), "./VBoxBFE.log");
     1138                            "VBOX_RELEASE_LOG", RT_ELEMENTS(s_apszGroups), s_apszGroups, RTLOGDEST_FILE,
     1139                            NULL /* pfnBeginEnd */, 0 /* cHistory */, 0 /* cbHistoryFileMax */, 0 /* uHistoryTimeMax */,
     1140                            s_szError, sizeof(s_szError), "./VBoxBFE.log");
    11401141        if (RT_SUCCESS(rc2))
    11411142        {
  • trunk/src/VBox/HostDrivers/Support/SUPDrv.c

    r36265 r36344  
    55
    66/*
    7  * Copyright (C) 2006-2010 Oracle Corporation
     7 * Copyright (C) 2006-2011 Oracle Corporation
    88 *
    99 * This file is part of VirtualBox Open Source Edition (OSE), as
     
    425425    PRTLOGGER pRelLogger;
    426426    rc = RTLogCreate(&pRelLogger, 0 /* fFlags */, "all",
    427                      "VBOX_RELEASE_LOG", RT_ELEMENTS(s_apszGroups), s_apszGroups,
    428                      RTLOGDEST_STDOUT | RTLOGDEST_DEBUGGER, NULL);
     427                     "VBOX_RELEASE_LOG", RT_ELEMENTS(s_apszGroups), s_apszGroups, RTLOGDEST_STDOUT | RTLOGDEST_DEBUGGER,
     428                     NULL /* pfnBeginEnd */, 0 /* cHistory */, 0 /* cbHistoryFileMax */, 0 /* uHistoryTimeMax */,
     429                     NULL);
    429430    if (RT_SUCCESS(rc))
    430431        RTLogRelSetDefaultInstance(pRelLogger);
     
    47464747                                 s_apszGroups,
    47474748                                 RTLOGDEST_STDOUT | RTLOGDEST_DEBUGGER,
     4749                                 NULL /* pfnBeginEnd */, 0 /* cHistory */, 0 /* cbHistoryFileMax */, 0 /* uHistoryTimeMax */,
    47484750                                 NULL);
    47494751                if (RT_SUCCESS(rc))
  • trunk/src/VBox/Main/src-client/ConsoleImpl.cpp

    r36247 r36344  
    53945394    char szError[RTPATH_MAX + 128] = "";
    53955395    int vrc = RTLogCreateEx(&loggerRelease, fFlags, "all",
    5396                             "VBOX_RELEASE_LOG", RT_ELEMENTS(s_apszGroups), s_apszGroups,
    5397                             RTLOGDEST_FILE, szError, sizeof(szError), logFile.c_str());
     5396                            "VBOX_RELEASE_LOG", RT_ELEMENTS(s_apszGroups), s_apszGroups, RTLOGDEST_FILE,
     5397                            NULL /* pfnBeginEnd */, 0 /* cHistory */, 0 /* cbHistoryFileMax */, 0 /* uHistoryTimeMax */,
     5398                            szError, sizeof(szError), logFile.c_str());
    53985399    if (RT_SUCCESS(vrc))
    53995400    {
  • trunk/src/VBox/Main/src-server/generic/OpenGLTestApp.cpp

    r33806 r36344  
    55
    66/*
    7  * Copyright (C) 2009-2010 Oracle Corporation
     7 * Copyright (C) 2009-2011 Oracle Corporation
    88 *
    99 * This file is part of VirtualBox Open Source Edition (OSE), as
     
    133133
    134134    int vrc = RTLogCreateEx(&loggerRelease, fFlags, "all",
    135                             "VBOX_RELEASE_LOG", RT_ELEMENTS(s_apszGroups), s_apszGroups,
    136                             enmLogDest, szError, sizeof(szError), pszFilenameFmt, pszFilename, RTTimeMilliTS());
     135                            "VBOX_RELEASE_LOG", RT_ELEMENTS(s_apszGroups), s_apszGroups, enmLogDest,
     136                            NULL /* pfnBeginEnd */, 0 /* cHistory */, 0 /* cbHistoryFileMax */, 0 /* uHistoryTimeMax */,
     137                            szError, sizeof(szError), pszFilenameFmt, pszFilename, RTTimeMilliTS());
    137138    if (RT_SUCCESS(vrc))
    138139    {
  • trunk/src/VBox/Main/webservice/vboxweb.cpp

    r36168 r36344  
    111111unsigned int            g_cMaxKeepAlive = 100;          // maximum number of soap requests in one connection
    112112
     113uint32_t                g_cHistory = 10;                // enable log rotation, 10 files
     114uint32_t                g_uHistoryFileTime = RT_SEC_1WEEK; // max 1 week per file
     115uint64_t                g_uHistoryFileSize = 100 * _1M; // max 100MB per file
    113116bool                    g_fVerbose = false;             // be verbose
    114 bool                    g_fStdOutLogging = true;        // log to stdout
    115 PRTSTREAM               g_pStrmLog = NULL;
    116117
    117118#if defined(RT_OS_DARWIN) || defined(RT_OS_LINUX) || defined (RT_OS_SOLARIS) || defined(RT_OS_FREEBSD)
     
    177178        { "--pidfile",          'P', RTGETOPT_REQ_STRING },
    178179        { "--logfile",          'F', RTGETOPT_REQ_STRING },
     180        { "--logrotate",        'R', RTGETOPT_REQ_UINT32 },
     181        { "--logsize",          'S', RTGETOPT_REQ_UINT64 },
     182        { "--loginterval",      'I', RTGETOPT_REQ_UINT32 }
    179183    };
    180184
     
    239243            case 'F':
    240244                pcszDescr = "Name of file to write log to (no file).";
     245                break;
     246
     247            case 'R':
     248                pcszDescr = "Number of log files (0 disables log rotation).";
     249                break;
     250
     251            case 'S':
     252                pcszDescr = "Maximum size of a log file to trigger rotationi (bytes).";
     253                break;
     254
     255            case 'I':
     256                pcszDescr = "Maximum time interval to trigger log rotation (seconds).";
    241257                break;
    242258        }
     
    582598    va_end(args);
    583599
    584     if (g_fStdOutLogging || g_pStrmLog)
    585     {
    586         const char *pcszPrefix = "[   ]";
    587         util::AutoReadLock thrLock(g_pThreadsLockHandle COMMA_LOCKVAL_SRC_POS);
    588         ThreadsMap::iterator it = g_mapThreads.find(RTThreadSelf());
    589         if (it != g_mapThreads.end())
    590             pcszPrefix = it->second.c_str();
    591         thrLock.release();
    592 
    593         // make a timestamp
    594         RTTIMESPEC ts;
    595         RTTimeLocalNow(&ts);
    596         RTTIME t;
    597         RTTimeExplode(&t, &ts);
    598 
    599         com::Utf8StrFmt strPrefix("%04d-%02u-%02u %02u:%02u:%02u %s",
    600                                   t.i32Year, t.u8Month, t.u8MonthDay,
    601                                   t.u8Hour, t.u8Minute, t.u8Second,
    602                                   pcszPrefix);
    603 
    604         // synchronize the actual output
    605         util::AutoWriteLock logLock(g_pWebLogLockHandle COMMA_LOCKVAL_SRC_POS);
    606         // terminal
    607         if (g_fStdOutLogging)
    608             RTPrintf("%s %s", strPrefix.c_str(), psz);
    609 
    610         // log file
    611         if (g_pStrmLog)
    612         {
    613             RTStrmPrintf(g_pStrmLog, "%s %s", strPrefix.c_str(), psz);
    614             RTStrmFlush(g_pStrmLog);
    615         }
    616 
    617 #ifdef DEBUG
    618         // debug logger instance
    619         RTLogLoggerEx(LOG_INSTANCE, RTLOGGRPFLAGS_DJ, LOG_GROUP, "%s %s", pcszPrefix, psz);
    620 #endif
    621 
    622         logLock.release();
    623     }
    624 
    625600    LogRel(("%s", psz));
    626601
     
    645620           pcszFaultString ? pcszFaultString : "[no fault string available]",
    646621           (ppcszDetail && *ppcszDetail) ? *ppcszDetail : "no details available");
     622}
     623
     624static void WebLogHeaderFooter(PRTLOGGER pLoggerRelease, RTLOGPHASE enmPhase, PFNRTLOGPHASEMSG pfnLog)
     625{
     626    /* some introductory information */
     627    static RTTIMESPEC timeSpec = {0};
     628    char szTmp[256];
     629    if (enmPhase == RTLOGPHASE_BEGIN)
     630        RTTimeNow(&timeSpec);
     631    RTTimeSpecToString(&timeSpec, szTmp, sizeof(szTmp));
     632
     633    switch (enmPhase)
     634    {
     635        case RTLOGPHASE_BEGIN:
     636        {
     637            pfnLog(pLoggerRelease,
     638                   "VirtualBox web service %s r%u %s (%s %s) release log\n"
     639#ifdef VBOX_BLEEDING_EDGE
     640                   "EXPERIMENTAL build " VBOX_BLEEDING_EDGE "\n"
     641#endif
     642                   "Log opened %s\n",
     643                   VBOX_VERSION_STRING, RTBldCfgRevision(), VBOX_BUILD_TARGET,
     644                   __DATE__, __TIME__, szTmp);
     645
     646            int vrc = RTSystemQueryOSInfo(RTSYSOSINFO_PRODUCT, szTmp, sizeof(szTmp));
     647            if (RT_SUCCESS(vrc) || vrc == VERR_BUFFER_OVERFLOW)
     648                pfnLog(pLoggerRelease, "OS Product: %s\n", szTmp);
     649            vrc = RTSystemQueryOSInfo(RTSYSOSINFO_RELEASE, szTmp, sizeof(szTmp));
     650            if (RT_SUCCESS(vrc) || vrc == VERR_BUFFER_OVERFLOW)
     651                pfnLog(pLoggerRelease, "OS Release: %s\n", szTmp);
     652            vrc = RTSystemQueryOSInfo(RTSYSOSINFO_VERSION, szTmp, sizeof(szTmp));
     653            if (RT_SUCCESS(vrc) || vrc == VERR_BUFFER_OVERFLOW)
     654                pfnLog(pLoggerRelease, "OS Version: %s\n", szTmp);
     655            if (RT_SUCCESS(vrc) || vrc == VERR_BUFFER_OVERFLOW)
     656                pfnLog(pLoggerRelease, "OS Service Pack: %s\n", szTmp);
     657
     658            /* the package type is interesting for Linux distributions */
     659            char szExecName[RTPATH_MAX];
     660            char *pszExecName = RTProcGetExecutablePath(szExecName, sizeof(szExecName));
     661            pfnLog(pLoggerRelease,
     662                   "Executable: %s\n"
     663                   "Process ID: %u\n"
     664                   "Package type: %s"
     665#ifdef VBOX_OSE
     666                   " (OSE)"
     667#endif
     668                   "\n",
     669                   pszExecName ? pszExecName : "unknown",
     670                   RTProcSelf(),
     671                   VBOX_PACKAGE_STRING);
     672            break;
     673        }
     674
     675        case RTLOGPHASE_PREROTATE:
     676            pfnLog(pLoggerRelease, "Log rotated - Log started %s\n", szTmp);
     677            break;
     678
     679        case RTLOGPHASE_POSTROTATE:
     680            pfnLog(pLoggerRelease, "Log continuation - Log started %s\n", szTmp);
     681            break;
     682
     683        case RTLOGPHASE_END:
     684            pfnLog(pLoggerRelease, "End of log file - Log started %s\n", szTmp);
     685            break;
     686
     687        default:
     688            /* nothing */;
     689    }
    647690}
    648691
     
    692735
    693736            // add the socket to the queue and tell worker threads to
    694             // pick up the jobn
     737            // pick up the job
    695738            size_t cItemsOnQ = g_pSoapQ->add(s);
    696739            WebLog("Request %llu on socket %d queued for processing (%d items on Q)\n", i, s, cItemsOnQ);
     
    748791
    749792    int c;
     793    const char *pszLogFile = NULL;
    750794    const char *pszPidFile = NULL;
    751795    RTGETOPTUNION ValueUnion;
     
    781825            case 'F':
    782826            {
    783                 int rc2 = RTStrmOpen(ValueUnion.psz, "a", &g_pStrmLog);
    784                 if (rc2)
    785                     return RTMsgErrorExit(RTEXITCODE_FAILURE, "Cannot open log file \"%s\" for writing: %Rrc", ValueUnion.psz, rc2);
    786 
    787                 WebLog(VBOX_PRODUCT " Webservice Version %s\n"
    788                        "Opened log file \"%s\"\n", VBOX_VERSION_STRING, ValueUnion.psz);
     827                pszLogFile = ValueUnion.psz;
    789828                break;
    790829            }
     830
     831            case 'R':
     832                g_cHistory = ValueUnion.u32;
     833                break;
     834
     835            case 'S':
     836                g_uHistoryFileSize = ValueUnion.u64;
     837                break;
     838
     839            case 'I':
     840                g_uHistoryFileTime = ValueUnion.u32;
     841                break;
    791842
    792843            case 'P':
     
    824875        }
    825876    }
     877
     878    /* create release logger */
     879    PRTLOGGER pLoggerRelease;
     880    static const char * const s_apszGroups[] = VBOX_LOGGROUP_NAMES;
     881    RTUINT fFlags = RTLOGFLAGS_PREFIX_THREAD | RTLOGFLAGS_PREFIX_TIME_PROG;
     882#if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2)
     883    fFlags |= RTLOGFLAGS_USECRLF;
     884#endif
     885    char szError[RTPATH_MAX + 128] = "";
     886    int vrc = RTLogCreateEx(&pLoggerRelease, fFlags, "all",
     887                            "VBOXWEBSRV_RELEASE_LOG", RT_ELEMENTS(s_apszGroups), s_apszGroups, RTLOGDEST_STDOUT,
     888                            WebLogHeaderFooter, g_cHistory, g_uHistoryFileSize, g_uHistoryFileTime,
     889                            szError, sizeof(szError), pszLogFile);
     890    if (RT_SUCCESS(vrc))
     891    {
     892        /* register this logger as the release logger */
     893        RTLogRelSetDefaultInstance(pLoggerRelease);
     894
     895        /* Explicitly flush the log in case of VBOXWEBSRV_RELEASE_LOG=buffered. */
     896        RTLogFlush(pLoggerRelease);
     897    }
     898    else
     899        return RTMsgErrorExit(RTEXITCODE_FAILURE, "failed to open release log (%s, %Rrc)", szError, vrc);
    826900
    827901#if defined(RT_OS_DARWIN) || defined(RT_OS_LINUX) || defined (RT_OS_SOLARIS) || defined(RT_OS_FREEBSD)
     
    842916            return RTMsgErrorExit(RTEXITCODE_FAILURE, "failed to daemonize, rc=%Rrc. exiting.", rc);
    843917
    844         /* From now on it's a waste of CPU cycles to send logging to stdout. */
    845         g_fStdOutLogging = false;
    846 
    847918        /* create release logger */
    848         PRTLOGGER loggerRelease;
     919        PRTLOGGER pLoggerRelease;
    849920        static const char * const s_apszGroups[] = VBOX_LOGGROUP_NAMES;
    850921        RTUINT fFlags = RTLOGFLAGS_PREFIX_THREAD | RTLOGFLAGS_PREFIX_TIME_PROG;
     
    853924#endif
    854925        char szError[RTPATH_MAX + 128] = "";
    855         int vrc = RTLogCreateEx(&loggerRelease, fFlags, "all",
    856                                 "VBOXWEBSRV_RELEASE_LOG", RT_ELEMENTS(s_apszGroups), s_apszGroups,
    857                                 RTLOGDEST_FILE, szError, sizeof(szError), szLogFile);
     926        int vrc = RTLogCreateEx(&pLoggerRelease, fFlags, "all",
     927                                "VBOXWEBSRV_RELEASE_LOG", RT_ELEMENTS(s_apszGroups), s_apszGroups, RTLOGDEST_FILE,
     928                                WebLogHeaderFooter, g_cHistory, g_uHistoryFileSize, g_uHistoryFileTime,
     929                                szError, sizeof(szError), szLogFile);
    858930        if (RT_SUCCESS(vrc))
    859931        {
    860             /* some introductory information */
    861             RTTIMESPEC timeSpec;
    862             char szTmp[256];
    863             RTTimeSpecToString(RTTimeNow(&timeSpec), szTmp, sizeof(szTmp));
    864             RTLogRelLogger(loggerRelease, 0, ~0U,
    865                            "VirtualBox web service %s r%u %s (%s %s) release log\n"
    866 #ifdef VBOX_BLEEDING_EDGE
    867                            "EXPERIMENTAL build " VBOX_BLEEDING_EDGE "\n"
    868 #endif
    869                            "Log opened %s\n",
    870                            VBOX_VERSION_STRING, RTBldCfgRevision(), VBOX_BUILD_TARGET,
    871                            __DATE__, __TIME__, szTmp);
    872 
    873             vrc = RTSystemQueryOSInfo(RTSYSOSINFO_PRODUCT, szTmp, sizeof(szTmp));
    874             if (RT_SUCCESS(vrc) || vrc == VERR_BUFFER_OVERFLOW)
    875                 RTLogRelLogger(loggerRelease, 0, ~0U, "OS Product: %s\n", szTmp);
    876             vrc = RTSystemQueryOSInfo(RTSYSOSINFO_RELEASE, szTmp, sizeof(szTmp));
    877             if (RT_SUCCESS(vrc) || vrc == VERR_BUFFER_OVERFLOW)
    878                 RTLogRelLogger(loggerRelease, 0, ~0U, "OS Release: %s\n", szTmp);
    879             vrc = RTSystemQueryOSInfo(RTSYSOSINFO_VERSION, szTmp, sizeof(szTmp));
    880             if (RT_SUCCESS(vrc) || vrc == VERR_BUFFER_OVERFLOW)
    881                 RTLogRelLogger(loggerRelease, 0, ~0U, "OS Version: %s\n", szTmp);
    882             if (RT_SUCCESS(vrc) || vrc == VERR_BUFFER_OVERFLOW)
    883                 RTLogRelLogger(loggerRelease, 0, ~0U, "OS Service Pack: %s\n", szTmp);
    884 
    885             /* the package type is interesting for Linux distributions */
    886             char szExecName[RTPATH_MAX];
    887             char *pszExecName = RTProcGetExecutablePath(szExecName, sizeof(szExecName));
    888             RTLogRelLogger(loggerRelease, 0, ~0U,
    889                            "Executable: %s\n"
    890                            "Process ID: %u\n"
    891                            "Package type: %s"
    892 #ifdef VBOX_OSE
    893                            " (OSE)"
    894 #endif
    895                            "\n",
    896                            pszExecName ? pszExecName : "unknown",
    897                            RTProcSelf(),
    898                            VBOX_PACKAGE_STRING);
    899 
    900932            /* register this logger as the release logger */
    901             RTLogRelSetDefaultInstance(loggerRelease);
     933            RTLogRelSetDefaultInstance(pLoggerRelease);
    902934
    903935            /* Explicitly flush the log in case of VBOXWEBSRV_RELEASE_LOG=buffered. */
    904             RTLogFlush(loggerRelease);
     936            RTLogFlush(pLoggerRelease);
    905937        }
    906938        else
  • trunk/src/VBox/Runtime/VBox/log-vbox.cpp

    r34848 r36344  
    55
    66/*
    7  * Copyright (C) 2006-2009 Oracle Corporation
     7 * Copyright (C) 2006-2011 Oracle Corporation
    88 *
    99 * This file is part of VirtualBox Open Source Edition (OSE), as
     
    303303    RTTimeExplode(&Time, RTTimeNow(&TimeSpec));
    304304    rc = RTLogCreate(&pLogger, 0, NULL, "VBOX_LOG", RT_ELEMENTS(g_apszGroups), &g_apszGroups[0], RTLOGDEST_FILE,
     305                     NULL /* pfnBeginEnd */, 0 /* cHistory */, 0 /* cbHistoryFileMax */, 0 /* uHistoryTimeMax */,
    305306                     "./%04d-%02d-%02d-%02d-%02d-%02d.%03d-%s-%d.log",
    306307                     Time.i32Year, Time.u8Month, Time.u8MonthDay, Time.u8Hour, Time.u8Minute, Time.u8Second, Time.u32Nanosecond / 10000000,
     
    419420#else /* IN_RING0 */
    420421# ifndef IN_GUEST
    421     rc = RTLogCreate(&pLogger, 0, NULL, "VBOX_LOG", RT_ELEMENTS(g_apszGroups), &g_apszGroups[0], RTLOGDEST_FILE, "VBox-ring0.log");
     422    rc = RTLogCreate(&pLogger, 0, NULL, "VBOX_LOG", RT_ELEMENTS(g_apszGroups), &g_apszGroups[0], RTLOGDEST_FILE,
     423                     NULL /* pfnBeginEnd */, 0 /* cHistory */, 0 /* cbHistoryFileMax */, 0 /* uHistoryTimeMax */,
     424                     "VBox-ring0.log");
    422425# else  /* IN_GUEST */
    423     rc = RTLogCreate(&pLogger, 0, NULL, "VBOX_LOG", RT_ELEMENTS(g_apszGroups), &g_apszGroups[0], RTLOGDEST_USER, "VBox-ring0.log");
     426    rc = RTLogCreate(&pLogger, 0, NULL, "VBOX_LOG", RT_ELEMENTS(g_apszGroups), &g_apszGroups[0], RTLOGDEST_USER,
     427                     NULL /* pfnBeginEnd */, 0 /* cHistory */, 0 /* cbHistoryFileMax */, 0 /* uHistoryTimeMax */,
     428                     "VBox-ring0.log");
    424429# endif /* IN_GUEST */
    425430    if (RT_SUCCESS(rc))
  • trunk/src/VBox/Runtime/common/log/log.cpp

    r33595 r36344  
    55
    66/*
    7  * Copyright (C) 2006-2010 Oracle Corporation
     7 * Copyright (C) 2006-2011 Oracle Corporation
    88 *
    99 * This file is part of VirtualBox Open Source Edition (OSE), as
     
    8989static void rtR0LogLoggerExFallback(uint32_t fDestFlags, uint32_t fFlags, const char *pszFormat, va_list va);
    9090#endif
     91#ifdef IN_RING3
     92static int rtlogFileOpen(PRTLOGGER pLogger, char *pszErrorMsg, size_t cchErrorMsg);
     93static void rtlogRotate(PRTLOGGER pLogger, uint32_t uTimeSlot, bool fFirst);
     94#endif
    9195static void rtlogFlush(PRTLOGGER pLogger);
    9296static DECLCALLBACK(size_t) rtLogOutput(void *pv, const char *pachChars, size_t cbChars);
    9397static DECLCALLBACK(size_t) rtLogOutputPrefixed(void *pv, const char *pachChars, size_t cbChars);
     98static void rtlogLoggerExV(PRTLOGGER pLogger, unsigned fFlags, unsigned iGroup, const char *pszFormat, va_list args);
    9499
    95100
     
    190195    { "file",     sizeof("file"    ) - 1,  RTLOGDEST_FILE }, /* Must be 1st! */
    191196    { "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! */
    192200    { "stdout",   sizeof("stdout"  ) - 1,  RTLOGDEST_STDOUT },
    193201    { "stderr",   sizeof("stderr"  ) - 1,  RTLOGDEST_STDERR },
     
    225233{
    226234#ifndef IN_RC
    227     if (pLogger->hSpinMtx != NIL_RTSEMFASTMUTEX)
     235    if (pLogger->hSpinMtx != NIL_RTSEMSPINMUTEX)
    228236        RTSemSpinMutexRelease(pLogger->hSpinMtx);
    229237#endif
     
    233241
    234242#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 */
     251static 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 */
     274static 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 */
     292static 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 */
     311static 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
    235324/**
    236325 * Create a logger instance, comprehensive version.
     
    246335 *                              logger instance.
    247336 * @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.
    248341 * @param   pszErrorMsg         A buffer which is filled with an error message if something fails. May be NULL.
    249342 * @param   cchErrorMsg         The size of the error message buffer.
     
    253346RTDECL(int) RTLogCreateExV(PRTLOGGER *ppLogger, uint32_t fFlags, const char *pszGroupSettings,
    254347                           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)
    256351{
    257352    int        rc;
     
    278373     */
    279374    cb = RT_OFFSETOF(RTLOGGER, afGroups[cGroups + 1]) + RTPATH_MAX;
     375#ifdef IN_RING3
     376    cb += sizeof(RTLOGGERFILE);
     377#endif
    280378    pLogger = (PRTLOGGER)RTMemAllocZVar(cb);
    281379    if (pLogger)
     
    289387        pLogger->cMaxGroups  = cGroups;
    290388        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 */
    293406        pLogger->fFlags      = fFlags;
    294407        pLogger->fDestFlags  = fDestFlags;
     
    337450            if (pszFilenameFmt)
    338451            {
    339                 RTStrPrintfV(pLogger->pszFilename, RTPATH_MAX, pszFilenameFmt, args);
     452                RTStrPrintfV(pLogger->pFile->pszFilename, RTPATH_MAX, pszFilenameFmt, args);
    340453                pLogger->fDestFlags |= RTLOGDEST_FILE;
    341454            }
     
    384497            if (pLogger->fDestFlags & RTLOGDEST_FILE)
    385498            {
    386                 uint32_t fOpen = RTFILE_O_WRITE | RTFILE_O_DENY_WRITE;
    387499                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                }
    389506                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                }
    396518            }
     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);
    397524#endif  /* IN_RING3 */
    398525
     
    425552            }
    426553#ifdef IN_RING3
    427             RTFileClose(pLogger->File);
     554            RTFileClose(pLogger->pFile->File);
    428555#endif
    429556#if defined(LOG_USE_C99) && defined(RT_WITHOUT_EXEC_ALLOC)
     
    456583 *                              logger instance.
    457584 * @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.
    458589 * @param   pszFilenameFmt      Log filename format string. Standard RTStrFormat().
    459590 * @param   ...                 Format arguments.
     
    461592RTDECL(int) RTLogCreate(PRTLOGGER *ppLogger, uint32_t fFlags, const char *pszGroupSettings,
    462593                        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, ...)
    464597{
    465598    va_list args;
     
    467600
    468601    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);
    470603    va_end(args);
    471604    return rc;
     
    487620 *                              logger instance.
    488621 * @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.
    489626 * @param   pszErrorMsg         A buffer which is filled with an error message if something fails. May be NULL.
    490627 * @param   cchErrorMsg         The size of the error message buffer.
     
    494631RTDECL(int) RTLogCreateEx(PRTLOGGER *ppLogger, uint32_t fFlags, const char *pszGroupSettings,
    495632                          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, ...)
    497636{
    498637    va_list args;
     
    500639
    501640    va_start(args, pszFilenameFmt);
    502     rc = RTLogCreateExV(ppLogger, fFlags, pszGroupSettings, pszEnvVarBase, cGroups, papszGroups, fDestFlags, pszErrorMsg, cchErrorMsg, pszFilenameFmt, args);
     641    rc = RTLogCreateExV(ppLogger, fFlags, pszGroupSettings, pszEnvVarBase, cGroups, papszGroups, fDestFlags, pfnPhase, cHistory, cbHistoryFileMax, uHistoryTimeSlotLength, pszErrorMsg, cchErrorMsg, pszFilenameFmt, args);
    503642    va_end(args);
    504643    return rc;
     
    545684    rtlogFlush(pLogger);
    546685
     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
    547693    /*
    548694     * Close output stuffs.
    549695     */
    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);
    554699        AssertRC(rc2);
    555700        if (RT_FAILURE(rc2) && RT_SUCCESS(rc))
    556701            rc = rc2;
    557         pLogger->File = NIL_RTFILE;
     702        pLogger->pFile->File = NIL_RTFILE;
    558703    }
    559704#endif
     
    766911    pLogger->fFlags       = fFlags;
    767912    pLogger->fDestFlags   = fDestFlags & ~RTLOGDEST_FILE;
    768     pLogger->File         = NIL_RTFILE;
    769     pLogger->pszFilename  = NULL;
     913    pLogger->pFile        = NULL;
    770914    pLogger->papszGroups  = NULL;
    771915    pLogger->cMaxGroups   = (uint32_t)((cbLogger - RT_OFFSETOF(RTLOGGER, afGroups[0])) / sizeof(pLogger->afGroups[0]));
     
    16041748                    {
    16051749                        AssertReturn(cch < RTPATH_MAX, VERR_OUT_OF_RANGE);
    1606                         memcpy(pLogger->pszFilename, pszVar, cch);
    1607                         pLogger->pszFilename[cch] = '\0';
     1750                        memcpy(pLogger->pFile->pszFilename, pszVar, cch);
     1751                        pLogger->pFile->pszFilename[cch] = '\0';
    16081752                    }
    16091753                    /* log directory */
     
    16111755                    {
    16121756                        char        szTmp[RTPATH_MAX];
    1613                         const char *pszFile = RTPathFilename(pLogger->pszFilename);
     1757                        const char *pszFile = RTPathFilename(pLogger->pFile->pszFilename);
    16141758                        size_t      cchFile = pszFile ? strlen(pszFile) : 0;
    16151759                        AssertReturn(cchFile + cch + 1 < RTPATH_MAX, VERR_OUT_OF_RANGE);
    16161760                        memcpy(szTmp, cchFile ? pszFile : "", cchFile + 1);
    16171761
    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;
    16261819                    }
    16271820                    else
     
    17041897        }
    17051898
     1899#ifdef IN_RING3
    17061900    /*
    17071901     * Add the filename.
    17081902     */
    17091903    if (    (fDestFlags & RTLOGDEST_FILE)
    1710         &&  VALID_PTR(pLogger->pszFilename)
     1904        &&  VALID_PTR(pLogger->pFile->pszFilename)
    17111905        &&  RT_SUCCESS(rc))
    17121906    {
    1713         size_t cchFilename = strlen(pLogger->pszFilename);
     1907        size_t cchFilename = strlen(pLogger->pFile->pszFilename);
    17141908        if (cchFilename + sizeof("file=") - 1 + fNotFirst + 1 <= cchBuf)
    17151909        {
     
    17181912            else
    17191913                APPEND_SZ("file=");
    1720             APPEND_PSZ(pLogger->pszFilename, cchFilename);
     1914            APPEND_PSZ(pLogger->pFile->pszFilename, cchFilename);
    17211915        }
    17221916        else
    17231917            rc = VERR_BUFFER_OVERFLOW;
    17241918    }
     1919#endif
    17251920
    17261921#undef APPEND_PSZ
     
    20322227
    20332228    /*
    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);
    20492232
    20502233    /*
     
    22172400
    22182401
     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 */
     2410static 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 */
     2448static 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
    22192539/**
    22202540 * Writes the buffer to the given log device without checking for buffered
     
    22392559    if (pLogger->fDestFlags & RTLOGDEST_FILE)
    22402560    {
    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;
    22442569    }
    22452570# endif
     
    22622587    /* empty the buffer. */
    22632588    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
    22642601}
    22652602
     
    27293066}
    27303067
     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 */
     3082static 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
  • trunk/src/VBox/Storage/testcase/vditool.cpp

    r33567 r36344  
    55
    66/*
    7  * Copyright (C) 2006-2010 Oracle Corporation
     7 * Copyright (C) 2006-2011 Oracle Corporation
    88 *
    99 * This file is part of VirtualBox Open Source Edition (OSE), as
     
    398398    static const char * const s_apszGroups[] = VBOX_LOGGROUP_NAMES;
    399399    int rc = RTLogCreate(&pLogger, 0, "all",
    400                          NULL, RT_ELEMENTS(s_apszGroups), s_apszGroups,
    401                           RTLOGDEST_STDOUT, NULL);
     400                         NULL, RT_ELEMENTS(s_apszGroups), s_apszGroups, RTLOGDEST_STDOUT,
     401                         NULL /* pfnBeginEnd */, 0 /* cHistory */, 0 /* cbHistoryFileMax */, 0 /* uHistoryTimeMax */,
     402                         NULL);
    402403    RTLogRelSetDefaultInstance(pLogger);
    403404
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette