const char *pszFormat, va_list va);
#endif
#ifdef IN_RING3
-static int rtlogFileOpen(PRTLOGGER pLogger, char *pszErrorMsg, size_t cchErrorMsg);
-static void rtlogRotate(PRTLOGGER pLogger, uint32_t uTimeSlot, bool fFirst);
+static int rtR3LogOpenFileDestination(PRTLOGGER pLogger, PRTERRINFO pErrInfo);
#endif
#ifndef IN_RC
static void rtLogRingBufFlush(PRTLOGGER pLogger);
#endif
-static void rtlogFlush(PRTLOGGER pLogger);
+static void rtlogFlush(PRTLOGGER pLogger, bool fNeedSpace);
static DECLCALLBACK(size_t) rtLogOutput(void *pv, const char *pachChars, size_t cbChars);
static DECLCALLBACK(size_t) rtLogOutputPrefixed(void *pv, const char *pachChars, size_t cbChars);
static void rtlogLoggerExVLocked(PRTLOGGER pLogger, unsigned fFlags, unsigned iGroup, const char *pszFormat, va_list args);
}
-
-
RTDECL(int) RTLogCreateExV(PRTLOGGER *ppLogger, uint32_t fFlags, const char *pszGroupSettings,
const char *pszEnvVarBase, unsigned cGroups, const char * const *papszGroups,
uint32_t fDestFlags, PFNRTLOGPHASE pfnPhase, uint32_t cHistory,
uint64_t cbHistoryFileMax, uint32_t cSecsHistoryTimeSlot,
- char *pszErrorMsg, size_t cchErrorMsg, const char *pszFilenameFmt, va_list args)
+ PRTERRINFO pErrInfo, const char *pszFilenameFmt, va_list args)
{
int rc;
size_t offInternal;
/*
* Validate input.
*/
- if ( (cGroups && !papszGroups)
- || !VALID_PTR(ppLogger) )
+ if ( (cGroups && !papszGroups)
+ || !VALID_PTR(ppLogger) )
{
AssertMsgFailed(("Invalid parameters!\n"));
return VERR_INVALID_PARAMETER;
}
*ppLogger = NULL;
- if (pszErrorMsg)
- RTStrPrintf(pszErrorMsg, cchErrorMsg, N_("unknown error"));
-
AssertMsgReturn(cHistory < _1M, ("%#x", cHistory), VERR_OUT_OF_RANGE);
/*
}
else
{
+ rc = VERR_NO_MEMORY;
# ifdef RT_OS_LINUX
- if (pszErrorMsg) /* Most probably SELinux causing trouble since the larger RTMemAlloc succeeded. */
- RTStrPrintf(pszErrorMsg, cchErrorMsg, N_("mmap(PROT_WRITE | PROT_EXEC) failed -- SELinux?"));
+ /* Most probably SELinux causing trouble since the larger RTMemAlloc succeeded. */
+ RTErrInfoSet(pErrInfo, rc, N_("mmap(PROT_WRITE | PROT_EXEC) failed -- SELinux?"));
# endif
- rc = VERR_NO_MEMORY;
}
if (RT_SUCCESS(rc))
# endif /* X86 wrapper code*/
{
/** @todo validate the length, fail on overflow. */
RTStrPrintfV(pLogger->pInt->szFilename, sizeof(pLogger->pInt->szFilename), pszFilenameFmt, args);
- pLogger->fDestFlags |= RTLOGDEST_FILE;
+ if (pLogger->pInt->szFilename[0])
+ pLogger->fDestFlags |= RTLOGDEST_FILE;
}
/*
* Open the destination(s).
*/
rc = VINF_SUCCESS;
+ if ((pLogger->fDestFlags & (RTLOGDEST_F_DELAY_FILE | RTLOGDEST_FILE)) == RTLOGDEST_F_DELAY_FILE)
+ pLogger->fDestFlags &= ~RTLOGDEST_F_DELAY_FILE;
# ifdef IN_RING3
- if (pLogger->fDestFlags & RTLOGDEST_FILE)
- {
- if (pLogger->fFlags & RTLOGFLAGS_APPEND)
- {
- rc = rtlogFileOpen(pLogger, pszErrorMsg, cchErrorMsg);
-
- /* Rotate in case of appending to a too big log file,
- otherwise this simply doesn't do anything. */
- rtlogRotate(pLogger, 0, true /* fFirst */);
- }
- else
- {
- /* Force rotation if it is configured. */
- pLogger->pInt->cbHistoryFileWritten = UINT64_MAX;
- rtlogRotate(pLogger, 0, true /* fFirst */);
-
- /* If the file is not open then rotation is not set up. */
- if (pLogger->pInt->hFile == NIL_RTFILE)
- {
- pLogger->pInt->cbHistoryFileWritten = 0;
- rc = rtlogFileOpen(pLogger, pszErrorMsg, cchErrorMsg);
- }
- }
- }
-# endif /* IN_RING3 */
+ if ((pLogger->fDestFlags & (RTLOGDEST_FILE | RTLOGDEST_F_DELAY_FILE)) == RTLOGDEST_FILE)
+ rc = rtR3LogOpenFileDestination(pLogger, pErrInfo);
+# endif
if ((pLogger->fDestFlags & RTLOGDEST_RINGBUF) && RT_SUCCESS(rc))
rc = rtLogRingBufAdjust(pLogger, pLogger->pInt->cbRingBuf, true /*fForce*/);
return VINF_SUCCESS;
}
- if (pszErrorMsg)
- RTStrPrintf(pszErrorMsg, cchErrorMsg, N_("failed to create semaphore"));
+ RTErrInfoSet(pErrInfo, rc, N_("failed to create semaphore"));
}
# ifdef IN_RING3
RTFileClose(pLogger->pInt->hFile);
va_start(args, pszFilenameFmt);
rc = RTLogCreateExV(ppLogger, fFlags, pszGroupSettings, pszEnvVarBase, cGroups, papszGroups,
fDestFlags, NULL /*pfnPhase*/, 0 /*cHistory*/, 0 /*cbHistoryFileMax*/, 0 /*cSecsHistoryTimeSlot*/,
- NULL /*pszErrorMsg*/, 0 /*cchErrorMsg*/, pszFilenameFmt, args);
+ NULL /*pErrInfo*/, pszFilenameFmt, args);
va_end(args);
return rc;
}
const char *pszEnvVarBase, unsigned cGroups, const char * const * papszGroups,
uint32_t fDestFlags, PFNRTLOGPHASE pfnPhase, uint32_t cHistory,
uint64_t cbHistoryFileMax, uint32_t cSecsHistoryTimeSlot,
- char *pszErrorMsg, size_t cchErrorMsg, const char *pszFilenameFmt, ...)
+ PRTERRINFO pErrInfo, const char *pszFilenameFmt, ...)
{
va_list args;
int rc;
va_start(args, pszFilenameFmt);
rc = RTLogCreateExV(ppLogger, fFlags, pszGroupSettings, pszEnvVarBase, cGroups, papszGroups,
fDestFlags, pfnPhase, cHistory, cbHistoryFileMax, cSecsHistoryTimeSlot,
- pszErrorMsg, cchErrorMsg, pszFilenameFmt, args);
+ pErrInfo, pszFilenameFmt, args);
va_end(args);
return rc;
}
/*
* Flush it.
*/
- rtlogFlush(pLogger);
+ rtlogFlush(pLogger, false /*fNeedSpace*/);
# ifdef IN_RING3
/*
RT_EXPORT_SYMBOL(RTLogDestinations);
+/**
+ * Clear the file delay flag if set, opening the destination and flushing.
+ *
+ * @returns IPRT status code.
+ * @param pLogger Logger instance (NULL for default logger).
+ * @param pszValue The value to parse.
+ * @param pErrInfo Where to return extended error info. Optional.
+ */
+RTDECL(int) RTLogClearFileDelayFlag(PRTLOGGER pLogger, PRTERRINFO pErrInfo)
+{
+ /*
+ * Resolve defaults.
+ */
+ if (!pLogger)
+ {
+ pLogger = RTLogDefaultInstance();
+ if (!pLogger)
+ return VINF_SUCCESS;
+ }
+
+ /*
+ * Do the work.
+ */
+ int rc = rtlogLock(pLogger);
+ if (RT_SUCCESS(rc))
+ {
+ if (pLogger->fDestFlags & RTLOGDEST_F_DELAY_FILE)
+ {
+ pLogger->fDestFlags &= ~RTLOGDEST_F_DELAY_FILE;
+# ifdef IN_RING3
+ if ( pLogger->fDestFlags & RTLOGDEST_FILE
+ && pLogger->pInt->hFile == NIL_RTFILE)
+ {
+ rc = rtR3LogOpenFileDestination(pLogger, pErrInfo);
+ if (RT_SUCCESS(rc))
+ rtlogFlush(pLogger, false /*fNeedSpace*/);
+ }
+# endif
+ RT_NOREF(pErrInfo); /** @todo fix create API to use RTErrInfo */
+ }
+ rtlogUnlock(pLogger);
+ }
+ return VINF_SUCCESS;
+}
+RT_EXPORT_SYMBOL(RTLogClearFileDelayFlag);
+
+
/**
* Get the current log destinations as a string.
*
/*
* Call worker.
*/
- rtlogFlush(pLogger);
+ rtlogFlush(pLogger, false /*fNeedSpace*/);
#ifndef IN_RC
/*
* Opens/creates the log file.
*
* @param pLogger The logger instance to update. NULL is not allowed!
- * @param pszErrorMsg A buffer which is filled with an error message if
- * something fails. May be NULL.
- * @param cchErrorMsg The size of the error message buffer.
+ * @param pErrInfo Where to return extended error information.
+ * Optional.
*/
-static int rtlogFileOpen(PRTLOGGER pLogger, char *pszErrorMsg, size_t cchErrorMsg)
+static int rtlogFileOpen(PRTLOGGER pLogger, PRTERRINFO pErrInfo)
{
uint32_t fOpen = RTFILE_O_WRITE | RTFILE_O_DENY_NONE;
if (pLogger->fFlags & RTLOGFLAGS_APPEND)
else
{
pLogger->pInt->hFile = NIL_RTFILE;
- if (pszErrorMsg)
- RTStrPrintf(pszErrorMsg, cchErrorMsg, N_("could not open file '%s' (fOpen=%#x)"), pLogger->pInt->szFilename, fOpen);
+ RTErrInfoSetF(pErrInfo, rc, N_("could not open file '%s' (fOpen=%#x)"), pLogger->pInt->szFilename, fOpen);
}
return rc;
}
* @param fFirst Flag whether this is the beginning of logging, i.e.
* called from RTLogCreateExV. Prevents pfnPhase from
* being called.
+ * @param pErrInfo Where to return extended error information. Optional.
*/
-static void rtlogRotate(PRTLOGGER pLogger, uint32_t uTimeSlot, bool fFirst)
+static void rtlogRotate(PRTLOGGER pLogger, uint32_t uTimeSlot, bool fFirst, PRTERRINFO pErrInfo)
{
/* Suppress rotating empty log files simply because the time elapsed. */
if (RT_UNLIKELY(!pLogger->pInt->cbHistoryFileWritten))
*/
pLogger->pInt->cbHistoryFileWritten = 0;
pLogger->pInt->uHistoryTimeSlotStart = uTimeSlot;
- rtlogFileOpen(pLogger, NULL, 0);
+ rtlogFileOpen(pLogger, pErrInfo);
/*
* Use the callback to generate some initial log contents, but only if this
pLogger->fFlags = fSavedFlags;
}
+
+/**
+ * Worker for RTLogCreateExV and RTLogClearFileDelayFlag.
+ *
+ * This will later be used to reopen the file by RTLogDestinations.
+ *
+ * @returns IPRT status code.
+ * @param pLogger The logger.
+ * @param pErrInfo Where to return extended error information.
+ * Optional.
+ */
+static int rtR3LogOpenFileDestination(PRTLOGGER pLogger, PRTERRINFO pErrInfo)
+{
+ int rc;
+ if (pLogger->fFlags & RTLOGFLAGS_APPEND)
+ {
+ rc = rtlogFileOpen(pLogger, pErrInfo);
+
+ /* Rotate in case of appending to a too big log file,
+ otherwise this simply doesn't do anything. */
+ rtlogRotate(pLogger, 0, true /* fFirst */, pErrInfo);
+ }
+ else
+ {
+ /* Force rotation if it is configured. */
+ pLogger->pInt->cbHistoryFileWritten = UINT64_MAX;
+ rtlogRotate(pLogger, 0, true /* fFirst */, pErrInfo);
+
+ /* If the file is not open then rotation is not set up. */
+ if (pLogger->pInt->hFile == NIL_RTFILE)
+ {
+ pLogger->pInt->cbHistoryFileWritten = 0;
+ rc = rtlogFileOpen(pLogger, pErrInfo);
+ }
+ else
+ rc = VINF_SUCCESS;
+ }
+ return rc;
+}
+
#endif /* IN_RING3 */
/**
* Writes the buffer to the given log device without checking for buffered
* data or anything.
+ *
* Used by the RTLogFlush() function.
*
* @param pLogger The logger instance to write to. NULL is not allowed!
+ * @param fNeedSpace Set if the caller assumes space will be made available.
*/
-static void rtlogFlush(PRTLOGGER pLogger)
+static void rtlogFlush(PRTLOGGER pLogger, bool fNeedSpace)
{
uint32_t const cchScratch = pLogger->offScratch;
if (cchScratch == 0)
return; /* nothing to flush. */
+ NOREF(fNeedSpace);
#ifndef IN_RC
/*
rtLogRingBufWrite(pLogger->pInt, pLogger->achScratch, pLogger->offScratch);
pLogger->offScratch = 0; /* empty the buffer. */
}
+ /*
+ * In file delay mode, we ignore flush requests except when we're full
+ * and the caller really needs some scratch space to get work done.
+ */
else
+# ifdef IN_RING3
+ if (!(pLogger->fDestFlags & RTLOGDEST_F_DELAY_FILE))
+# endif
#endif
{
/* Make sure the string is terminated. On Windows, RTLogWriteDebugger
*/
if ( (pLogger->fDestFlags & RTLOGDEST_FILE)
&& pLogger->pInt->cHistory)
- rtlogRotate(pLogger, RTTimeProgramSecTS() / pLogger->pInt->cSecsHistoryTimeSlot, false /* fFirst */);
+ rtlogRotate(pLogger, RTTimeProgramSecTS() / pLogger->pInt->cSecsHistoryTimeSlot, false /*fFirst*/, NULL /*pErrInfo*/);
#endif
}
+#ifdef IN_RING3
+ else
+ {
+ /*
+ * Delay file open but the caller really need some space. So, give him half a
+ * buffer and insert a message indicating that we've dropped output.
+ */
+ uint32_t offHalf = sizeof(pLogger->achScratch) / 2;
+ if (cchScratch > offHalf)
+ {
+ if (pLogger->fFlags & RTLOGFLAGS_USECRLF)
+ pLogger->achScratch[offHalf++] = '\r';
+ static const char s_szDropMsg[] = "\n[DROP DROP DROP]";
+ memcpy(&pLogger->achScratch[offHalf], RT_STR_TUPLE(s_szDropMsg));
+ offHalf += sizeof(s_szDropMsg) - 1;
+ if (pLogger->fFlags & RTLOGFLAGS_USECRLF)
+ pLogger->achScratch[offHalf++] = '\r';
+ pLogger->achScratch[offHalf++] = '\n';
+
+ pLogger->offScratch = offHalf;
+ }
+ }
+#endif
}
pachChars += cb;
/* flush */
- rtlogFlush(pLogger);
+ rtlogFlush(pLogger, true /*fNeedSpace*/);
}
/* won't ever get here! */
*/
if (cb < 256 + 16)
{
- rtlogFlush(pLogger);
+ rtlogFlush(pLogger, true /*fNeedSpace*/);
offScratch = pLogger->offScratch;
cb = sizeof(pLogger->achScratch) - offScratch - 1;
}
}
else if (cb <= 0)
{
- rtlogFlush(pLogger);
+ rtlogFlush(pLogger, true /*fNeedSpace*/);
offScratch = pLogger->offScratch;
cb = sizeof(pLogger->achScratch) - offScratch - 1;
}
RTLogFormatV(rtLogOutput, pLogger, pszFormat, args);
if ( !(pLogger->fFlags & RTLOGFLAGS_BUFFERED)
&& pLogger->offScratch)
- rtlogFlush(pLogger);
+ rtlogFlush(pLogger, false /*fNeedSpace*/);
}