log.cpp revision 57f871fa4a9f6157b0f16daa1307e7db25d964a6
cb7ae3378eb7595a9f486c189a192af8390b1d5dRam Anaswara * Runtime VBox - Logger.
cb7ae3378eb7595a9f486c189a192af8390b1d5dRam Anaswara * Copyright (C) 2006-2007 Sun Microsystems, Inc.
cb7ae3378eb7595a9f486c189a192af8390b1d5dRam Anaswara * This file is part of VirtualBox Open Source Edition (OSE), as
cb7ae3378eb7595a9f486c189a192af8390b1d5dRam Anaswara * available from http://www.virtualbox.org. This file is free software;
cb7ae3378eb7595a9f486c189a192af8390b1d5dRam Anaswara * you can redistribute it and/or modify it under the terms of the GNU
cb7ae3378eb7595a9f486c189a192af8390b1d5dRam Anaswara * General Public License (GPL) as published by the Free Software
cb7ae3378eb7595a9f486c189a192af8390b1d5dRam Anaswara * Foundation, in version 2 as it comes in the "COPYING" file of the
cb7ae3378eb7595a9f486c189a192af8390b1d5dRam Anaswara * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
cb7ae3378eb7595a9f486c189a192af8390b1d5dRam Anaswara * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
cb7ae3378eb7595a9f486c189a192af8390b1d5dRam Anaswara * The contents of this file may alternatively be used under the terms
cb7ae3378eb7595a9f486c189a192af8390b1d5dRam Anaswara * of the Common Development and Distribution License Version 1.0
cb7ae3378eb7595a9f486c189a192af8390b1d5dRam Anaswara * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
cb7ae3378eb7595a9f486c189a192af8390b1d5dRam Anaswara * VirtualBox OSE distribution, in which case the provisions of the
cb7ae3378eb7595a9f486c189a192af8390b1d5dRam Anaswara * CDDL are applicable instead of those of the GPL.
cb7ae3378eb7595a9f486c189a192af8390b1d5dRam Anaswara * You may elect to license modified versions of this file under the
cb7ae3378eb7595a9f486c189a192af8390b1d5dRam Anaswara * terms and conditions of either the GPL or the CDDL or both.
cb7ae3378eb7595a9f486c189a192af8390b1d5dRam Anaswara * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
cb7ae3378eb7595a9f486c189a192af8390b1d5dRam Anaswara * Clara, CA 95054 USA or visit http://www.sun.com if you need
cb7ae3378eb7595a9f486c189a192af8390b1d5dRam Anaswara * additional information or have any questions.
cb7ae3378eb7595a9f486c189a192af8390b1d5dRam Anaswara/*******************************************************************************
cb7ae3378eb7595a9f486c189a192af8390b1d5dRam Anaswara* Header Files *
cb7ae3378eb7595a9f486c189a192af8390b1d5dRam Anaswara*******************************************************************************/
cb7ae3378eb7595a9f486c189a192af8390b1d5dRam Anaswara/*******************************************************************************
cb7ae3378eb7595a9f486c189a192af8390b1d5dRam Anaswara* Structures and Typedefs *
cb7ae3378eb7595a9f486c189a192af8390b1d5dRam Anaswara*******************************************************************************/
cb7ae3378eb7595a9f486c189a192af8390b1d5dRam Anaswara * Arguments passed to the output function.
cb7ae3378eb7595a9f486c189a192af8390b1d5dRam Anaswara /** The logger instance. */
cb7ae3378eb7595a9f486c189a192af8390b1d5dRam Anaswara /** The flags. (used for prefixing.) */
cb7ae3378eb7595a9f486c189a192af8390b1d5dRam Anaswara /** The group. (used for prefixing.) */
cb7ae3378eb7595a9f486c189a192af8390b1d5dRam Anaswara} RTLOGOUTPUTPREFIXEDARGS, *PRTLOGOUTPUTPREFIXEDARGS;
cb7ae3378eb7595a9f486c189a192af8390b1d5dRam Anaswara/*******************************************************************************
cb7ae3378eb7595a9f486c189a192af8390b1d5dRam Anaswara* Internal Functions *
cb7ae3378eb7595a9f486c189a192af8390b1d5dRam Anaswara*******************************************************************************/
cb7ae3378eb7595a9f486c189a192af8390b1d5dRam Anaswarastatic unsigned rtlogGroupFlags(const char *psz);
cb7ae3378eb7595a9f486c189a192af8390b1d5dRam Anaswarastatic void rtR0LogLoggerExFallback(uint32_t fDestFlags, const char *pszFormat, va_list va);
cb7ae3378eb7595a9f486c189a192af8390b1d5dRam Anaswarastatic DECLCALLBACK(size_t) rtLogOutput(void *pv, const char *pachChars, size_t cbChars);
cb7ae3378eb7595a9f486c189a192af8390b1d5dRam Anaswarastatic DECLCALLBACK(size_t) rtLogOutputPrefixed(void *pv, const char *pachChars, size_t cbChars);
cb7ae3378eb7595a9f486c189a192af8390b1d5dRam Anaswara/*******************************************************************************
cb7ae3378eb7595a9f486c189a192af8390b1d5dRam Anaswara* Global Variables *
cb7ae3378eb7595a9f486c189a192af8390b1d5dRam Anaswara*******************************************************************************/
cb7ae3378eb7595a9f486c189a192af8390b1d5dRam Anaswara/** Default logger instance. */
cb7ae3378eb7595a9f486c189a192af8390b1d5dRam Anaswara#else /* !IN_RC */
cb7ae3378eb7595a9f486c189a192af8390b1d5dRam Anaswara/** Default logger instance. */
cb7ae3378eb7595a9f486c189a192af8390b1d5dRam Anaswara#endif /* !IN_RC */
cb7ae3378eb7595a9f486c189a192af8390b1d5dRam Anaswara/** The RTThreadGetWriteLockCount() change caused by the logger mutex semaphore. */
cb7ae3378eb7595a9f486c189a192af8390b1d5dRam Anaswara/** Number of per-thread loggers. */
cb7ae3378eb7595a9f486c189a192af8390b1d5dRam Anaswara/** Per-thread loggers.
cb7ae3378eb7595a9f486c189a192af8390b1d5dRam Anaswara * This is just a quick TLS hack suitable for debug logging only.
cb7ae3378eb7595a9f486c189a192af8390b1d5dRam Anaswara * If we run out of entries, just unload and reload the driver. */
cb7ae3378eb7595a9f486c189a192af8390b1d5dRam Anaswara /** The thread. */
cb7ae3378eb7595a9f486c189a192af8390b1d5dRam Anaswara /** The (process / session) key. */
cb7ae3378eb7595a9f486c189a192af8390b1d5dRam Anaswara /** The logger instance.*/
cb7ae3378eb7595a9f486c189a192af8390b1d5dRam Anaswara#endif /* IN_RING0 */
cb7ae3378eb7595a9f486c189a192af8390b1d5dRam Anaswara * Locks the logger instance.
cb7ae3378eb7595a9f486c189a192af8390b1d5dRam Anaswara * @returns See RTSemFastMutexRequest().
cb7ae3378eb7595a9f486c189a192af8390b1d5dRam Anaswara * @param pLogger The logger instance.
cb7ae3378eb7595a9f486c189a192af8390b1d5dRam Anaswara# if defined(IN_RING0) \
cb7ae3378eb7595a9f486c189a192af8390b1d5dRam Anaswara && (defined(RT_OS_WINDOWS) || defined(RT_OS_SOLARIS) || defined(RT_OS_LINUX))
cb7ae3378eb7595a9f486c189a192af8390b1d5dRam Anaswara * Unlocks the logger instance.
cb7ae3378eb7595a9f486c189a192af8390b1d5dRam Anaswara * @param pLogger The logger instance.
cb7ae3378eb7595a9f486c189a192af8390b1d5dRam Anaswara * Create a logger instance, comprehensive version.
cb7ae3378eb7595a9f486c189a192af8390b1d5dRam Anaswara * @returns iprt status code.
cb7ae3378eb7595a9f486c189a192af8390b1d5dRam Anaswara * @param ppLogger Where to store the logger instance.
cb7ae3378eb7595a9f486c189a192af8390b1d5dRam Anaswara * @param fFlags Logger instance flags, a combination of the RTLOGFLAGS_* values.
cb7ae3378eb7595a9f486c189a192af8390b1d5dRam Anaswara * @param pszGroupSettings The initial group settings.
cb7ae3378eb7595a9f486c189a192af8390b1d5dRam Anaswara * @param pszEnvVarBase Base name for the environment variables for this instance.
cb7ae3378eb7595a9f486c189a192af8390b1d5dRam Anaswara * @param cGroups Number of groups in the array.
cb7ae3378eb7595a9f486c189a192af8390b1d5dRam Anaswara * @param papszGroups Pointer to array of groups. This must stick around for the life of the
cb7ae3378eb7595a9f486c189a192af8390b1d5dRam Anaswara * logger instance.
cb7ae3378eb7595a9f486c189a192af8390b1d5dRam Anaswara * @param fDestFlags The destination flags. RTLOGDEST_FILE is ORed if pszFilenameFmt specified.
cb7ae3378eb7595a9f486c189a192af8390b1d5dRam Anaswara * @param pszErrorMsg A buffer which is filled with an error message if something fails. May be NULL.
cb7ae3378eb7595a9f486c189a192af8390b1d5dRam Anaswara * @param cchErrorMsg The size of the error message buffer.
cb7ae3378eb7595a9f486c189a192af8390b1d5dRam Anaswara * @param pszFilenameFmt Log filename format string. Standard RTStrFormat().
cb7ae3378eb7595a9f486c189a192af8390b1d5dRam Anaswara * @param ... Format arguments.
cb7ae3378eb7595a9f486c189a192af8390b1d5dRam AnaswaraRTDECL(int) RTLogCreateExV(PRTLOGGER *ppLogger, uint32_t fFlags, const char *pszGroupSettings,
cb7ae3378eb7595a9f486c189a192af8390b1d5dRam Anaswara const char *pszEnvVarBase, unsigned cGroups, const char * const * papszGroups,
cb7ae3378eb7595a9f486c189a192af8390b1d5dRam Anaswara uint32_t fDestFlags, char *pszErrorMsg, size_t cchErrorMsg, const char *pszFilenameFmt, va_list args)
cb7ae3378eb7595a9f486c189a192af8390b1d5dRam Anaswara * Validate input.
cb7ae3378eb7595a9f486c189a192af8390b1d5dRam Anaswara RTStrPrintf(pszErrorMsg, cchErrorMsg, "unknown error");
cb7ae3378eb7595a9f486c189a192af8390b1d5dRam Anaswara * Allocate a logger instance.
cb7ae3378eb7595a9f486c189a192af8390b1d5dRam Anaswara cb = RT_OFFSETOF(RTLOGGER, afGroups[cGroups + 1]) + RTPATH_MAX;
cb7ae3378eb7595a9f486c189a192af8390b1d5dRam Anaswara pLogger->pszFilename = (char *)&pLogger->afGroups[cGroups + 1];
cb7ae3378eb7595a9f486c189a192af8390b1d5dRam Anaswara * Emit wrapper code.
cb7ae3378eb7595a9f486c189a192af8390b1d5dRam Anaswara /* this wrapper will not be used on AMD64, we will be requiring C99 compilers there. */
cb7ae3378eb7595a9f486c189a192af8390b1d5dRam Anaswara pu8Code += sizeof(void *);
cb7ae3378eb7595a9f486c189a192af8390b1d5dRam Anaswara *(uint32_t *)pu8Code = (uintptr_t)RTLogLogger - ((uintptr_t)pu8Code + sizeof(uint32_t));
cb7ae3378eb7595a9f486c189a192af8390b1d5dRam Anaswara AssertMsg((uintptr_t)pu8Code - (uintptr_t)pLogger->pfnLogger <= 64,
cb7ae3378eb7595a9f486c189a192af8390b1d5dRam Anaswara ("Wrapper assembly is too big! %d bytes\n", (uintptr_t)pu8Code - (uintptr_t)pLogger->pfnLogger));
cb7ae3378eb7595a9f486c189a192af8390b1d5dRam Anaswara#ifdef IN_RING3 /* files and env.vars. are only accessible when in R3 at the present time. */
cb7ae3378eb7595a9f486c189a192af8390b1d5dRam Anaswara * Format the filename.
cb7ae3378eb7595a9f486c189a192af8390b1d5dRam Anaswara RTStrPrintfV(pLogger->pszFilename, RTPATH_MAX, pszFilenameFmt, args);
cb7ae3378eb7595a9f486c189a192af8390b1d5dRam Anaswara * Parse the environment variables.
cb7ae3378eb7595a9f486c189a192af8390b1d5dRam Anaswara /* make temp copy of environment variable base. */
cb7ae3378eb7595a9f486c189a192af8390b1d5dRam Anaswara char *pszEnvVar = (char *)alloca(cchEnvVarBase + 16);
cb7ae3378eb7595a9f486c189a192af8390b1d5dRam Anaswara memcpy(pszEnvVar, pszEnvVarBase, cchEnvVarBase);
cb7ae3378eb7595a9f486c189a192af8390b1d5dRam Anaswara * Destination.
cb7ae3378eb7595a9f486c189a192af8390b1d5dRam Anaswara /* skip blanks. */
cb7ae3378eb7595a9f486c189a192af8390b1d5dRam Anaswara /* parse instruction. */
cb7ae3378eb7595a9f486c189a192af8390b1d5dRam Anaswara static struct
cb7ae3378eb7595a9f486c189a192af8390b1d5dRam Anaswara /* check no prefix. */
cb7ae3378eb7595a9f486c189a192af8390b1d5dRam Anaswara bool fNo = false;
cb7ae3378eb7595a9f486c189a192af8390b1d5dRam Anaswara /* instruction. */
cb7ae3378eb7595a9f486c189a192af8390b1d5dRam Anaswara if (!strncmp(pszVar, aDest[i].pszInstr, cchInstr))
cb7ae3378eb7595a9f486c189a192af8390b1d5dRam Anaswara /* check for value. */
cb7ae3378eb7595a9f486c189a192af8390b1d5dRam Anaswara /* log file name */
cb7ae3378eb7595a9f486c189a192af8390b1d5dRam Anaswara /* log directory */
cb7ae3378eb7595a9f486c189a192af8390b1d5dRam Anaswara const char *pszFile = RTPathFilename(pLogger->pszFilename);
cb7ae3378eb7595a9f486c189a192af8390b1d5dRam Anaswara RTPathStripTrailingSlash(pLogger->pszFilename);
cb7ae3378eb7595a9f486c189a192af8390b1d5dRam Anaswara AssertMsgFailed(("Invalid %s_DEST! %s%s doesn't take a value!\n", pszEnvVarBase, fNo ? "no" : "", aDest[i].pszInstr));
cb7ae3378eb7595a9f486c189a192af8390b1d5dRam Anaswara /* unknown instruction? */
cb7ae3378eb7595a9f486c189a192af8390b1d5dRam Anaswara AssertMsgFailed(("Invalid %s_DEST! unknown instruction %.20s\n", pszEnvVarBase, pszVar));
cb7ae3378eb7595a9f486c189a192af8390b1d5dRam Anaswara /* skip blanks and delimiters. */
cb7ae3378eb7595a9f486c189a192af8390b1d5dRam Anaswara while (RT_C_IS_SPACE(*pszVar) || *pszVar == ';')
cb7ae3378eb7595a9f486c189a192af8390b1d5dRam Anaswara } /* while more environment variable value left */
cb7ae3378eb7595a9f486c189a192af8390b1d5dRam Anaswara * The flags.
cb7ae3378eb7595a9f486c189a192af8390b1d5dRam Anaswara * The group settings.
cb7ae3378eb7595a9f486c189a192af8390b1d5dRam Anaswara#endif /* IN_RING3 */
cb7ae3378eb7595a9f486c189a192af8390b1d5dRam Anaswara * Open the destination(s).
cb7ae3378eb7595a9f486c189a192af8390b1d5dRam Anaswara rc = RTFileOpen(&pLogger->File, pLogger->pszFilename,
cb7ae3378eb7595a9f486c189a192af8390b1d5dRam Anaswara RTFILE_O_WRITE | RTFILE_O_CREATE_REPLACE | RTFILE_O_DENY_WRITE);
cb7ae3378eb7595a9f486c189a192af8390b1d5dRam Anaswara /** @todo RTFILE_O_APPEND. */
return VINF_SUCCESS;
if (pszErrorMsg)
#ifdef IN_RING3
#ifdef RT_OS_LINUX
if (pszErrorMsg)
return rc;
int rc;
rc = RTLogCreateExV(ppLogger, fFlags, pszGroupSettings, pszEnvVarBase, cGroups, papszGroups, fDestFlags, NULL, 0, pszFilenameFmt, args);
return rc;
* @param pszErrorMsg A buffer which is filled with an error message if something fails. May be NULL.
int rc;
rc = RTLogCreateExV(ppLogger, fFlags, pszGroupSettings, pszEnvVarBase, cGroups, papszGroups, fDestFlags, pszErrorMsg, cchErrorMsg, pszFilenameFmt, args);
return rc;
int rc;
if (!pLogger)
return VINF_SUCCESS;
while (iGroup-- > 0)
#ifdef IN_RING3
int rc2;
return rc;
if ( !pLoggerRC
|| !pfnFlushRCPtr
|| !pfnLoggerRCPtr)
return VERR_INVALID_PARAMETER;
return VERR_INVALID_PARAMETER;
if (!pLogger)
if (!pLogger)
return VINF_SUCCESS;
AssertMsgFailed(("%d req=%d cGroups=%d\n", cbLoggerRC, RT_OFFSETOF(RTLOGGERRC, afGroups[pLogger->cGroups]), pLogger->cGroups));
return VERR_INVALID_PARAMETER;
memcpy(&pLoggerRC->afGroups[0], &pLogger->afGroups[0], pLogger->cGroups * sizeof(pLoggerRC->afGroups[0]));
return VINF_SUCCESS;
if (!pLogger)
if (!pLogger)
#ifdef IN_RING3
RTDECL(int) RTLogCreateForR0(PRTLOGGER pLogger, size_t cbLogger, PFNRTLOGGER pfnLogger, PFNRTLOGFLUSH pfnFlush,
pLogger->cMaxGroups = (uint32_t)((cbLogger - RT_OFFSETOF(RTLOGGER, afGroups[0])) / sizeof(pLogger->afGroups[0]));
return VINF_SUCCESS;
RTDECL(int) RTLogCopyGroupsAndFlags(PRTLOGGER pDstLogger, PCRTLOGGER pSrcLogger, unsigned fFlagsOr, unsigned fFlagsAnd)
int rc;
unsigned cGroups;
if (!pSrcLogger)
if (!pSrcLogger)
return VINF_SUCCESS;
memcpy(&pDstLogger->afGroups[0], &pSrcLogger->afGroups[0], cGroups * sizeof(pDstLogger->afGroups[0]));
return rc;
if (!pDstLogger)
if (!pDstLogger)
RTDECL(int) RTLogSetCustomPrefixCallback(PRTLOGGER pLogger, PFNRTLOGPREFIX pfnCallback, void *pvUser)
if (!pLogger)
if (!pLogger)
return VINF_SUCCESS;
return VINF_SUCCESS;
const char *pachMask;
const char *pszTmp;
do pachMask++;
if ( !cchMask
if (!pszTmp)
if (!pszTmp)
if (!*++pszGrp)
pachMask++;
cchMask--;
if ( !cchMask
if (!--cchMask)
pachMask++;
if (!pLogger)
if (!pLogger)
return VINF_SUCCESS;
while (*pszVar)
bool fEnabled = true;
char ch;
const char *pszStart;
pszVar++;
if (!*pszVar)
pszVar++;
if (fEnabled)
if (fEnabled)
return VINF_SUCCESS;
unsigned fFlags = 0;
unsigned fFlag;
} aFlags[] =
bool fFound = false;
psz++;
psz1++;
psz2++;
if (!*psz1)
fFound = true;
psz++;
return fFlags;
if (!pLogger)
if (!pLogger)
return VINF_SUCCESS;
while (*pszVar)
const char *pszInstr;
unsigned fFlag;
bool fInverted;
} const aDest[] =
bool fNo = false;
char ch;
pszVar++;
if (!*pszVar)
return rc;
pszVar++;
fNo = true;
pszVar++;
pszVar++;
pszVar++;
return rc;
if (!pLogger)
#ifdef IN_RC
if (!pLogger)
#ifndef IN_RC
#ifndef IN_RC
#ifdef IN_RC
return &g_Logger;
# ifdef IN_RING0
if (g_cPerThreadLoggers)
if (!g_pLogger)
return g_pLogger;
#ifdef IN_RC
return &g_Logger;
# ifdef IN_RING0
if (g_cPerThreadLoggers)
return g_pLogger;
#ifndef IN_RC
#ifdef IN_RING0
int rc;
if (pLogger)
int32_t i;
return VINF_SUCCESS;
&& ASMAtomicCmpXchgPtr((void * volatile *)&g_aPerThreadLoggers[i].NativeThread, (void *)Self, (void *)NIL_RTNATIVETHREAD))
return VINF_SUCCESS;
ASMAtomicXchgPtr((void * volatile *)&g_aPerThreadLoggers[i].NativeThread, (void *)NIL_RTNATIVETHREAD);
return rc;
RTDECL(void) RTLogLoggerExV(PRTLOGGER pLogger, unsigned fFlags, unsigned iGroup, const char *pszFormat, va_list args)
int rc;
if (!pLogger)
if (!pLogger)
iGroup = 0;
#ifndef IN_RC
if ( iGroup != ~0U
&& (pLogger->afGroups[iGroup] & (fFlags | RTLOGGRPFLAGS_ENABLED)) != (fFlags | RTLOGGRPFLAGS_ENABLED))
#ifdef IN_RING0
#ifdef IN_RING0
typedef struct RTR0LOGLOGGERFALLBACK
#ifndef LOG_NO_COM
static DECLCALLBACK(size_t) rtR0LogLoggerExFallbackOutput(void *pv, const char *pachChars, size_t cbChars)
if (cbChars)
uint32_t cb = sizeof(pThis->achScratch) - pThis->offScratch - 1; /* minus 1 - for the string terminator. */
if (cbChars <= 0)
return cbRet;
#ifndef IN_RC
# ifdef IN_RING3
if (cbChars)
if (cbChars <= 0)
return cbRet;
if (cbChars)
char *psz;
const char *pszNewLine;
fFlags = 0;
fFlags = 0;
#ifdef IN_RING3
#ifdef IN_RING3
#ifndef IN_RC
#ifndef IN_RC
#ifdef IN_RING3
if (pszName)
#ifndef IN_RC
#ifdef IN_RING3
if (pszGroup)
const char *pszGroup;
if (pszGroup)
else if (cb <= 0)
if (pszNewLine)
if ( pszNewLine
cbRet++;
cbChars--;
cb++;
if (cbChars <= 0)
return cbRet;