}
// Early out if we're not logging at this level.
- if ((level & GetLogLevel()) == 0)
+ if (!IsPassThrough(level) && ((level & GetLogLevel()) == 0))
{
return;
}
_vsnprintf_s(fullMsg, fullMsgLen, fullMsgLen, msg, argList);
va_end(argList);
- const char* logLevelStr = "INVALID_LOGLEVEL";
+ // Where to write messages? Default to stdout.
+ FILE* dest = stdout;
+
+ const char* logLevelStr = "";
switch (level)
{
case LOGLEVEL_ERROR:
logLevelStr = "ERROR";
+ dest = stderr;
break;
case LOGLEVEL_WARNING:
logLevelStr = "WARNING";
+ dest = stderr;
break;
case LOGLEVEL_MISSING:
case LOGLEVEL_DEBUG:
logLevelStr = "DEBUG";
break;
+
+ case LOGLEVEL_PASSTHROUGH_STDOUT:
+ logLevelStr = "STDOUT";
+ break;
+
+ case LOGLEVEL_PASSTHROUGH_STDERR:
+ logLevelStr = "STDERR";
+ dest = stderr;
+ break;
+
+ default:
+ logLevelStr = "INVALID_LOGLEVEL";
+ break;
}
// NOTE: This implementation doesn't guarantee that log messages will be written in chronological
EnterCriticalSection(&s_critSec);
- // Sends error messages to stderr instead out stdout
- FILE* dest = (level <= LOGLEVEL_WARNING) ? stderr : stdout;
-
if (level < LOGLEVEL_INFO)
fprintf(dest, "%s: ", logLevelStr);
#endif // TARGET_UNIX
const char logEntryFmtStr[] = "%s - %s [%s:%d] - %s - %s\r\n";
- size_t logEntryBuffSize = sizeof(logEntryFmtStr) + strlen(timeStr) + strlen(function) + strlen(file) + 10 +
+ size_t logEntryBuffSize = sizeof(logEntryFmtStr) + strlen(timeStr) + strlen(function) + strlen(file) + /* line number */ 10 +
strlen(logLevelStr) + strlen(fullMsg);
char* logEntry = new char[logEntryBuffSize];
sprintf_s(logEntry, logEntryBuffSize, logEntryFmtStr, timeStr, function, file, line, logLevelStr, fullMsg);
+ size_t logEntryLen = strlen(logEntry);
DWORD bytesWritten;
- if (!WriteFile(s_logFile, logEntry, (DWORD)logEntryBuffSize - 1, &bytesWritten, nullptr))
+ if (!WriteFile(s_logFile, logEntry, (DWORD)logEntryLen, &bytesWritten, nullptr))
fprintf(stderr, "WARNING: [Logger::LogVprintf] Failed to write to log file. GetLastError()=%u\n",
GetLastError());
#define LogVerbose(...) LogMessage(LOGLEVEL_VERBOSE, __VA_ARGS__)
#define LogDebug(...) LogMessage(LOGLEVEL_DEBUG, __VA_ARGS__)
+#define LogPassThroughStdout(...) LogMessage(LOGLEVEL_PASSTHROUGH_STDOUT, __VA_ARGS__)
+#define LogPassThroughStderr(...) LogMessage(LOGLEVEL_PASSTHROUGH_STDERR, __VA_ARGS__)
+
#define LogIssue(issue, msg, ...) IssueLogger::LogIssueHelper(__FUNCTION__, __FILE__, __LINE__, issue, msg, __VA_ARGS__)
// Captures the exception message before throwing so we can log it at the point of occurrence
// These are specified as flags so subsets of the logging functionality can be enabled/disabled at once
enum LogLevel : UINT32
{
- LOGLEVEL_ERROR = 0x00000001, // Internal fatal errors that are non-recoverable
- LOGLEVEL_WARNING = 0x00000002, // Internal conditions that are unusual, but not serious
- LOGLEVEL_MISSING = 0x00000004, // Failures to due to missing JIT-EE details
- LOGLEVEL_ISSUE = 0x00000008, // Issues found with the JIT, e.g. asm diffs, asserts
- LOGLEVEL_INFO = 0x00000010, // Notifications/summaries, e.g. 'Loaded 5 Jitted 4 FailedCompile 1'
- LOGLEVEL_VERBOSE = 0x00000020, // Status messages, e.g. 'Jit startup took 151.12ms'
- LOGLEVEL_DEBUG = 0x00000040 // Detailed output that's only useful for SuperPMI debugging
+ LOGLEVEL_ERROR = 0x00000001, // Internal fatal errors that are non-recoverable
+ LOGLEVEL_WARNING = 0x00000002, // Internal conditions that are unusual, but not serious
+ LOGLEVEL_MISSING = 0x00000004, // Failures to due to missing JIT-EE details
+ LOGLEVEL_ISSUE = 0x00000008, // Issues found with the JIT, e.g. asm diffs, asserts
+ LOGLEVEL_INFO = 0x00000010, // Notifications/summaries, e.g. 'Loaded 5 Jitted 4 FailedCompile 1'
+ LOGLEVEL_VERBOSE = 0x00000020, // Status messages, e.g. 'Jit startup took 151.12ms'
+ LOGLEVEL_DEBUG = 0x00000040, // Detailed output that's only useful for SuperPMI debugging
+ LOGLEVEL_PASSTHROUGH_STDOUT = 0x00000080, // Special: pass through parallel SuperPMI stdout
+ LOGLEVEL_PASSTHROUGH_STDERR = 0x00000100 // Special: pass through parallel SuperPMI stderr
};
// Preset log level combinations
{
return s_logLevel;
}
+ static bool IsPassThrough(LogLevel level)
+ {
+ return (level == LOGLEVEL_PASSTHROUGH_STDOUT) || (level == LOGLEVEL_PASSTHROUGH_STDERR);
+ }
// Return true if all specified log levels are enabled.
static bool IsLogLevelEnabled(UINT32 logLevelMask)
return false;
}
- Logger::SetLogLevel(Logger::ParseLogLevelString(argv[i]));
+ o->verbosity = argv[i];
+ Logger::SetLogLevel(Logger::ParseLogLevelString(o->verbosity));
}
else if ((_strnicmp(&argv[i][1], "writeLogFile", argLen) == 0))
{
: nameOfJit(nullptr)
, nameOfJit2(nullptr)
, nameOfInputMethodContextFile(nullptr)
+ , verbosity(nullptr)
, writeLogFile(nullptr)
, reproName(nullptr)
, breakOnError(false)
char* nameOfJit;
char* nameOfJit2;
char* nameOfInputMethodContextFile;
+ char* verbosity;
char* writeLogFile;
char* reproName;
bool breakOnError;
if (buff[buffLen - 1] == '\n')
buff[buffLen - 1] = 0;
- if (strncmp(buff, "ERROR: ", 7) == 0)
- LogError("%s", &buff[7]); // log as Error and remove the "ERROR: " in front
- else if (strncmp(buff, "WARNING: ", 9) == 0)
- LogWarning("%s", &buff[9]); // log as Warning and remove the "WARNING: " in front
- else if (strlen(buff) > 0)
- LogWarning("%s", buff); // unknown output, log it as a warning
+ LogPassThroughStderr(buff);
}
Cleanup:
if (buff[buffLen - 1] == '\n')
buff[buffLen - 1] = 0;
- if (strncmp(buff, "MISSING: ", 9) == 0)
- LogMissing("%s", &buff[9]); // log as Missing and remove the "MISSING: " in front
- else if (strncmp(buff, "ISSUE: ", 7) == 0)
- {
- if (strncmp(&buff[7], "<ASM_DIFF> ", 11) == 0)
- LogIssue(ISSUE_ASM_DIFF, "%s", &buff[18]); // log as Issue and remove the "ISSUE: <ASM_DIFF>" in front
- else if (strncmp(&buff[7], "<ASSERT> ", 9) == 0)
- LogIssue(ISSUE_ASSERT, "%s", &buff[16]); // log as Issue and remove the "ISSUE: <ASSERT>" in front
- }
- else if (strncmp(buff, g_SuperPMIUsageFirstLine, strlen(g_SuperPMIUsageFirstLine)) == 0)
+ if (strncmp(buff, g_SuperPMIUsageFirstLine, strlen(g_SuperPMIUsageFirstLine)) == 0)
{
*usageError = true; // Signals that we had a SuperPMI command line usage error
-
- // Read the entire stdout file and printf it
- printf("%s", buff);
- while (fgets(buff, MAX_LOG_LINE_SIZE, fp) != NULL)
- {
- printf("%s", buff);
- }
- break;
+ LogPassThroughStdout(buff);
}
else if (strncmp(buff, g_AllFormatStringFixedPrefix, strlen(g_AllFormatStringFixedPrefix)) == 0)
{
*excluded += childExcluded;
*missing += childMissing;
}
+ else
+ {
+ // Do output pass-through.
+ // Note that the same logging verbosity level is passed to the child processes.
+ LogPassThroughStdout(buff);
+ }
}
Cleanup:
char* spmiArgs = new char[MAX_CMDLINE_SIZE];
*spmiArgs = '\0';
-// We don't pass through /parallel, /skipCleanup, /verbosity, /failingMCList, or /diffMCList. Everything else we need to
-// reconstruct and pass through.
-
#define ADDSTRING(s) \
if (s != nullptr) \
{ \
bytesWritten += sprintf_s(spmiArgs + bytesWritten, MAX_CMDLINE_SIZE - bytesWritten, " %s %s", arg, s); \
}
+ // We don't pass through:
+ //
+ // -parallel
+ // -writeLogFile (the parent process writes the log file based on the output of the child processes)
+ // -reproName
+ // -coredistools
+ // -skipCleanup
+ // -metricsSummary
+ // -baseMetricsSummary
+ // -diffMetricsSummary
+ // -failingMCList
+ // -diffMCList
+ // -failureLimit
+ //
+ // Everything else we need to reconstruct and pass through.
+ //
+ // Note that for -verbosity, if the level includes LOGLEVEL_INFO, the process will output a
+ // "Loaded/Jitted/FailedCompile/Excluded/Missing[/Diffs]" line which is parsed and summarized by
+ // the parent process. If it isn't output, the summary doesn't happen.
+
ADDARG_BOOL(o.breakOnError, "-boe");
ADDARG_BOOL(o.breakOnAssert, "-boa");
ADDARG_BOOL(o.breakOnException, "-box");
ADDARG_BOOL(o.ignoreStoredConfig, "-ignoreStoredConfig");
ADDARG_BOOL(o.applyDiff, "-applyDiff");
+ ADDARG_STRING(o.verbosity, "-verbosity");
ADDARG_STRING(o.reproName, "-reproName");
- ADDARG_STRING(o.writeLogFile, "-writeLogFile");
ADDARG_STRING(o.methodStatsTypes, "-emitMethodStats");
ADDARG_STRING(o.hash, "-matchHash");
ADDARG_STRING(o.targetArchitecture, "-target");