void P_CCONV pLog(PLogVerbosityEnum verbosity, PLogChannelEnum channel, const pchar *file, puint32 line, const pchar *format, ...) { // The global verbosity value controls which kinds of log can be // printed. if (verbosity < g_logVerbosity) { return ; } static const pchar *verbosityText[] = { "(debug)", "(info)", "(warning)", "(error)", "(fatal)", }; va_list arguments; va_start(arguments, format); if (pstrlen(format) > 200) { pchar message[1024]; puint32 nchars = psprintf(message, 1024, "(warning)%s:%d,log buffer for formatting data is too small.", __FILE__, __LINE__); pLogOutput(P_LOG_CHANNEL2, message, nchars); } else { pchar msg[3000]; puint32 nchars; if (verbosity == P_LOG_ERROR || verbosity == P_LOG_WARNING) { pchar fmt[256]; psprintf(fmt, 256, "%s%s:%d,%s", verbosityText[verbosity], file, line, format); nchars = pvsprintf(msg, 3000, fmt, arguments); } else { nchars = pvsprintf(msg, 3000, format, arguments); } pLogOutput(channel, msg, nchars); } if (verbosity == P_LOG_FATAL) { // FIXME: make it more polite pabort(); } }
/** * Unconditionally logs an error message. * * @param msg The message format specification (ala printf). * @return ESR_SUCCESS if success, anything else if an error occurs. */ ESR_ReturnCode PLogError(const char* msg, ...) { va_list args; ESR_ReturnCode rc; #if defined (ANDROID) #if defined (HAVE_ANDROID_OS) char log_text [2048]; #endif #endif va_start(args, msg); #if defined (ANDROID) #if defined (HAVE_ANDROID_OS) pvsprintf ( log_text, msg, args); /* We need to disable some error messages because they are frequently not * errors but due to sloppy use of some functions. This prevents us from * getting flooded with bad error messages. SteveR */ if ( ( strncmp ( log_text, FILTER_MSG_1, FILTER_MSG_1_SIZE ) != 0 ) && ( strncmp ( log_text, FILTER_MSG_2, FILTER_MSG_2_SIZE ) != 0 ) ) { LOGE ( log_text ); } rc = 0; #else rc = logIt(msg, args, ESR_TRUE); #endif #else rc = logIt(msg, args, ESR_TRUE); #endif va_end(args); return rc; }
static ESR_ReturnCode logIt(const LCHAR *format, va_list args, ESR_BOOL showStackTrace) { ESR_ReturnCode rc = ESR_SUCCESS; ESR_ReturnCode flushRC = ESR_SUCCESS; #ifdef USE_STACKTRACE #define BUFFER_SIZE P_MAX_STACKTRACE + 2000 #else #define BUFFER_SIZE 2000 #endif LCHAR buffer[BUFFER_SIZE] = L(""); // TODO: Remove once logging subsystem supports "warn" level if (strstr(format, "ESR_BUFFER_OVERFLOW")==format) return ESR_SUCCESS; #ifdef USE_STACKTRACE if (Glogger == NULL) { /* * There are three possible scenerios for why logging would occur although the PLog module * is uninitialized: * * 1) The code fails before PLog is initialized (perhaps in other portable components) * 2) The user forgets to initialize the PLog module * 3) The code fails after PLog is uninitialized (on shutdown) * * We do our best by logging any errors but this might result in the memory leak of * the PStackTrace module in case 3. */ rc = PStackTraceCreate(); if (rc != ESR_SUCCESS) { PLOG_PANIC(L("PStackTraceCreate"), rc); goto CLEANUP; } } else { #ifdef USE_THREAD rc = PtrdMutexLock(Gmutex); if (rc != ESR_SUCCESS) return rc; #endif } if (locked) return ESR_INVALID_STATE; locked = ESR_TRUE; if (GlogFormat & LOG_OUTPUT_FORMAT_DATE_TIME) { PTimeStamp now; struct tm* loctime; LCHAR timeStr[TIME_BUF_SIZE]; size_t timeStrSize; PTimeStampSet(&now); loctime = localtime(&now.secs); timeStrSize = LSTRFTIME(timeStr, TIME_BUF_SIZE, TIME_FORMAT, loctime); passert(timeStrSize == (TIME_BUF_SIZE - 5)); psprintf(timeStr + (TIME_BUF_SIZE - 5), ".%03hu", now.msecs); psprintf(buffer + LSTRLEN(buffer), L("%s|"), timeStr); passert(LSTRLEN(buffer) < BUFFER_SIZE); } if (GlogFormat & LOG_OUTPUT_FORMAT_THREAD_ID) { rc = psprintf(buffer + LSTRLEN(buffer), L("trd=%u|"), PtrdGetCurrentThreadId()); passert(LSTRLEN(buffer) < BUFFER_SIZE); } if (GlogFormat & LOG_OUTPUT_FORMAT_MODULE_NAME && showStackTrace) { size_t len = P_MAX_STACKTRACE; LCHAR text[P_MAX_STACKTRACE]; LCHAR* index; size_t i; rc = PStackTraceGetValue((LCHAR*) & text, &len); if (rc == ESR_SUCCESS) { for (i = 0; i < 2; ++i) { rc = PStackTracePopLevel((LCHAR*) & text); if (rc != ESR_SUCCESS) { PLOG_PANIC(L("PStackTracePopLevel"), rc); goto CLEANUP; } } index = text; while (index) { index = LSTRSTR(index, L(" at\n")); if (index != NULL) { *(index + 1) = L('<'); *(index + 2) = L('-'); *(index + 3) = L(' '); } } } else if (rc == ESR_NOT_SUPPORTED) LSTRCPY(text, L("")); else if (rc != ESR_SUCCESS) { PLOG_PANIC(L("PStackTraceGetValue"), rc); goto CLEANUP; } rc = psprintf(buffer + LSTRLEN(buffer), L("Module=%s|"), text); passert(LSTRLEN(buffer) < BUFFER_SIZE); } pvsprintf(buffer + LSTRLEN(buffer), format, args); #else pvsprintf(buffer + LSTRLEN(buffer), format, args); #endif passert(LSTRLEN(buffer) < BUFFER_SIZE); psprintf(buffer + LSTRLEN(buffer), L("\n")); passert(LSTRLEN(buffer) < BUFFER_SIZE); if (Glogger != NULL) { rc = Glogger->printf(Glogger, L("%s"), buffer); if (rc != ESR_SUCCESS) goto CLEANUP; flushRC = Glogger->flush(Glogger); } else { /* We need to log but the logging module is disabled or is locked so we output to stderr instead */ { pfprintf(PSTDERR, L("%s"), buffer); pfflush(PSTDERR); } } locked = ESR_FALSE; #ifdef USE_THREAD PtrdMutexUnlock(Gmutex); #endif return flushRC; CLEANUP: if (Glogger != NULL && Glogger->flush != NULL) flushRC = Glogger->flush(Glogger); locked = ESR_FALSE; #ifdef USE_THREAD PtrdMutexUnlock(Gmutex); #endif return rc != ESR_SUCCESS ? rc : flushRC; }