| Index: chrome/test/chromedriver/logging.cc
|
| diff --git a/chrome/test/chromedriver/logging.cc b/chrome/test/chromedriver/logging.cc
|
| index bf0a50a69abbd07b3229c181e3e1c076b0492d95..4a8cfa1ce83435d4ab675f575b3fbf88101d2125 100644
|
| --- a/chrome/test/chromedriver/logging.cc
|
| +++ b/chrome/test/chromedriver/logging.cc
|
| @@ -4,71 +4,137 @@
|
|
|
| #include "chrome/test/chromedriver/logging.h"
|
|
|
| +#include <stdio.h>
|
| +
|
| #include "base/basictypes.h"
|
| +#include "base/command_line.h"
|
| +#include "base/json/json_reader.h"
|
| #include "base/logging.h"
|
| +#include "base/strings/stringprintf.h"
|
| #include "base/time/time.h"
|
| #include "chrome/test/chromedriver/capabilities.h"
|
| #include "chrome/test/chromedriver/chrome/console_logger.h"
|
| #include "chrome/test/chromedriver/chrome/performance_logger.h"
|
| #include "chrome/test/chromedriver/chrome/status.h"
|
| +#include "chrome/test/chromedriver/session.h"
|
| +
|
| +#if defined(OS_POSIX)
|
| +#include <fcntl.h>
|
| +#include <unistd.h>
|
| +#endif
|
|
|
|
|
| namespace {
|
|
|
| -// Map between WebDriverLog::WebDriverLevel and its name in WD wire protocol.
|
| -// Array indices are the WebDriverLog::WebDriverLevel enum values.
|
| -const char* const kWebDriverLevelNames[] = {
|
| - "ALL", "DEBUG", "INFO", "WARNING", "SEVERE", "OFF"
|
| -};
|
| +Log::Level g_log_level = Log::kWarning;
|
| +
|
| +int64 g_start_time = 0;
|
|
|
| -// Map between Log::Level and WebDriverLog::WebDriverLevel.
|
| // Array indices are the Log::Level enum values.
|
| -WebDriverLog::WebDriverLevel kLogLevelToWebDriverLevels[] = {
|
| - WebDriverLog::kWdDebug, // kDebug
|
| - WebDriverLog::kWdInfo, // kLog
|
| - WebDriverLog::kWdWarning, // kWarning
|
| - WebDriverLog::kWdSevere // kError
|
| +const char* kLevelToName[] = {
|
| + "ALL", // kAll
|
| + "DEBUG", // kDebug
|
| + "INFO", // kInfo
|
| + "WARNING", // kWarning
|
| + "SEVERE", // kError
|
| + "OFF", // kOff
|
| };
|
|
|
| -// Translates Log::Level to WebDriverLog::WebDriverLevel.
|
| -WebDriverLog::WebDriverLevel LogLevelToWebDriverLevel(Log::Level level) {
|
| - const int index = level - Log::kDebug;
|
| +const char* LevelToName(Log::Level level) {
|
| + const int index = level - Log::kAll;
|
| CHECK_GE(index, 0);
|
| - CHECK_LT(static_cast<size_t>(index), arraysize(kLogLevelToWebDriverLevels));
|
| - return kLogLevelToWebDriverLevels[index];
|
| + CHECK_LT(static_cast<size_t>(index), arraysize(kLevelToName));
|
| + return kLevelToName[index];
|
| }
|
|
|
| -// Returns WD wire protocol level name for a WebDriverLog::WebDriverLevel.
|
| -std::string GetWebDriverLevelName(
|
| - const WebDriverLog::WebDriverLevel level) {
|
| - const int index = level - WebDriverLog::kWdAll;
|
| - CHECK_GE(index, 0);
|
| - CHECK_LT(static_cast<size_t>(index), arraysize(kWebDriverLevelNames));
|
| - return kWebDriverLevelNames[index];
|
| +struct LevelPair {
|
| + const char* name;
|
| + Log::Level level;
|
| +};
|
| +
|
| +const LevelPair kNameToLevel[] = {
|
| + {"ALL", Log::kAll},
|
| + {"DEBUG", Log::kDebug},
|
| + {"INFO", Log::kInfo},
|
| + {"WARNING", Log::kWarning},
|
| + {"SEVERE", Log::kError},
|
| + {"OFF", Log::kOff},
|
| +};
|
| +
|
| +Log::Level GetLevelFromSeverity(int severity) {
|
| + switch (severity) {
|
| + case logging::LOG_FATAL:
|
| + case logging::LOG_ERROR_REPORT:
|
| + case logging::LOG_ERROR:
|
| + return Log::kError;
|
| + case logging::LOG_WARNING:
|
| + return Log::kWarning;
|
| + case logging::LOG_INFO:
|
| + return Log::kInfo;
|
| + case logging::LOG_VERBOSE:
|
| + default:
|
| + return Log::kDebug;
|
| + }
|
| +}
|
| +
|
| +bool InternalIsVLogOn(int vlog_level) {
|
| + return GetLevelFromSeverity(vlog_level * -1) >= g_log_level;
|
| +}
|
| +
|
| +bool HandleLogMessage(int severity,
|
| + const char* file,
|
| + int line,
|
| + size_t message_start,
|
| + const std::string& str) {
|
| + Log::Level level = GetLevelFromSeverity(severity);
|
| + if (level < g_log_level)
|
| + return true;
|
| +
|
| + std::string message = str.substr(message_start);
|
| + const char* level_name = "UNKNOWN";
|
| + switch (level) {
|
| + case Log::kDebug:
|
| + level_name = "DEBUG";
|
| + break;
|
| + case Log::kInfo:
|
| + level_name = "INFO";
|
| + break;
|
| + case Log::kWarning:
|
| + level_name = "WARNING";
|
| + break;
|
| + case Log::kError:
|
| + level_name = "ERROR";
|
| + break;
|
| + default:
|
| + break;
|
| + }
|
| + std::string entry = base::StringPrintf(
|
| + "[%.3lf][%s]: %s",
|
| + base::TimeDelta(base::TimeTicks::Now() -
|
| + base::TimeTicks::FromInternalValue(g_start_time))
|
| + .InSecondsF(),
|
| + level_name,
|
| + message.c_str());
|
| +
|
| + fprintf(stderr, "%s", entry.c_str());
|
| + fflush(stderr);
|
| + return true;
|
| }
|
|
|
| } // namespace
|
|
|
| -bool WebDriverLog::NameToLevel(
|
| - const std::string& name, WebDriverLog::WebDriverLevel* out_level) {
|
| - for (size_t i = 0; i < arraysize(kWebDriverLevelNames); ++i) {
|
| - if (name == kWebDriverLevelNames[i]) {
|
| - CHECK_LE(WebDriverLog::kWdAll + i,
|
| - static_cast<size_t>(WebDriverLog::kWdOff));
|
| - *out_level =
|
| - static_cast<WebDriverLog::WebDriverLevel>(WebDriverLog::kWdAll + i);
|
| +bool WebDriverLog::NameToLevel(const std::string& name, Log::Level* out_level) {
|
| + for (size_t i = 0; i < arraysize(kNameToLevel); ++i) {
|
| + if (name == kNameToLevel[i].name) {
|
| + *out_level = kNameToLevel[i].level;
|
| return true;
|
| }
|
| }
|
| return false;
|
| }
|
|
|
| -WebDriverLog::WebDriverLog(
|
| - const std::string& type, WebDriverLog::WebDriverLevel min_wd_level)
|
| - : type_(type),
|
| - min_wd_level_(min_wd_level),
|
| - entries_(new base::ListValue()) {
|
| - VLOG(1) << "Log(" << type_ << ", " << min_wd_level_ << ")";
|
| +WebDriverLog::WebDriverLog(const std::string& type, Log::Level min_level)
|
| + : type_(type), min_level_(min_level), entries_(new base::ListValue()) {
|
| }
|
|
|
| WebDriverLog::~WebDriverLog() {
|
| @@ -76,76 +142,127 @@ WebDriverLog::~WebDriverLog() {
|
| << entries_->GetSize() << " entries on destruction";
|
| }
|
|
|
| -const std::string& WebDriverLog::GetType() {
|
| - return type_;
|
| +scoped_ptr<base::ListValue> WebDriverLog::GetAndClearEntries() {
|
| + scoped_ptr<base::ListValue> ret(entries_.release());
|
| + entries_.reset(new base::ListValue());
|
| + return ret.Pass();
|
| }
|
|
|
| void WebDriverLog::AddEntryTimestamped(const base::Time& timestamp,
|
| Log::Level level,
|
| const std::string& message) {
|
| - const WebDriverLog::WebDriverLevel wd_level = LogLevelToWebDriverLevel(level);
|
| - if (wd_level < min_wd_level_)
|
| + if (level < min_level_)
|
| return;
|
| +
|
| scoped_ptr<base::DictionaryValue> log_entry_dict(new base::DictionaryValue());
|
| log_entry_dict->SetDouble("timestamp",
|
| static_cast<int64>(timestamp.ToJsTime()));
|
| - log_entry_dict->SetString("level", GetWebDriverLevelName(wd_level));
|
| + log_entry_dict->SetString("level", LevelToName(level));
|
| log_entry_dict->SetString("message", message);
|
| entries_->Append(log_entry_dict.release());
|
| }
|
|
|
| -scoped_ptr<base::ListValue> WebDriverLog::GetAndClearEntries() {
|
| - scoped_ptr<base::ListValue> ret(entries_.release());
|
| - entries_.reset(new base::ListValue());
|
| - return ret.Pass();
|
| +const std::string& WebDriverLog::type() const {
|
| + return type_;
|
| +}
|
| +
|
| +Log::Level WebDriverLog::min_level() const {
|
| + return min_level_;
|
| +}
|
| +
|
| +bool InitLogging() {
|
| + InitLogging(&InternalIsVLogOn);
|
| + g_start_time = base::TimeTicks::Now().ToInternalValue();
|
| +
|
| + CommandLine* cmd_line = CommandLine::ForCurrentProcess();
|
| + if (cmd_line->HasSwitch("log-path")) {
|
| + g_log_level = Log::kInfo;
|
| + base::FilePath log_path = cmd_line->GetSwitchValuePath("log-path");
|
| +#if defined(OS_WIN)
|
| + FILE* redir_stderr = _wfreopen(log_path.value().c_str(), L"w", stderr);
|
| +#else
|
| + FILE* redir_stderr = freopen(log_path.value().c_str(), "w", stderr);
|
| +#endif
|
| + if (!redir_stderr) {
|
| + printf("Failed to redirect stderr to log file.\n");
|
| + return false;
|
| + }
|
| + }
|
| + if (cmd_line->HasSwitch("silent"))
|
| + g_log_level = Log::kOff;
|
| +
|
| + if (cmd_line->HasSwitch("verbose")) {
|
| + g_log_level = Log::kAll;
|
| + } else {
|
| +#if defined(OS_POSIX)
|
| + // Close stderr on exec, so that Chrome log spew doesn't confuse users.
|
| + fcntl(STDERR_FILENO, F_SETFD, FD_CLOEXEC);
|
| +#endif
|
| + }
|
| +
|
| + // Turn on VLOG for chromedriver. This is parsed during logging::InitLogging.
|
| + cmd_line->AppendSwitchASCII("vmodule", "*/chrome/test/chromedriver/*=3");
|
| +
|
| + logging::SetMinLogLevel(logging::LOG_WARNING);
|
| + logging::SetLogItems(false, // enable_process_id
|
| + false, // enable_thread_id
|
| + false, // enable_timestamp
|
| + false); // enable_tickcount
|
| + logging::SetLogMessageHandler(&HandleLogMessage);
|
| +
|
| + logging::LoggingSettings logging_settings;
|
| + logging_settings.logging_dest = logging::LOG_TO_SYSTEM_DEBUG_LOG;
|
| + return logging::InitLogging(logging_settings);
|
| }
|
|
|
| Status CreateLogs(const Capabilities& capabilities,
|
| - ScopedVector<WebDriverLog>* out_devtools_logs,
|
| + ScopedVector<WebDriverLog>* out_logs,
|
| + scoped_ptr<WebDriverLog>* out_driver_log,
|
| ScopedVector<DevToolsEventListener>* out_listeners) {
|
| - ScopedVector<WebDriverLog> devtools_logs;
|
| + ScopedVector<WebDriverLog> logs;
|
| ScopedVector<DevToolsEventListener> listeners;
|
| - WebDriverLog::WebDriverLevel browser_log_level = WebDriverLog::kWdInfo;
|
| -
|
| - if (capabilities.logging_prefs) {
|
| - for (DictionaryValue::Iterator pref(*capabilities.logging_prefs);
|
| - !pref.IsAtEnd(); pref.Advance()) {
|
| - const std::string type = pref.key();
|
| - std::string level_name;
|
| - if (!pref.value().GetAsString(&level_name)) {
|
| - return Status(kUnknownError,
|
| - "logging level must be a string for log type: " + type);
|
| - }
|
| - WebDriverLog::WebDriverLevel level = WebDriverLog::kWdOff;
|
| - if (!WebDriverLog::NameToLevel(level_name, &level)) {
|
| - return Status(kUnknownError,
|
| - "invalid log level \"" + level_name +
|
| - "\" for type: " + type);
|
| - }
|
| - if ("performance" == type) {
|
| - if (WebDriverLog::kWdOff != level) {
|
| - WebDriverLog* log = new WebDriverLog(type, WebDriverLog::kWdAll);
|
| - devtools_logs.push_back(log);
|
| - listeners.push_back(new PerformanceLogger(log));
|
| - }
|
| - } else if ("browser" == type) {
|
| - browser_log_level = level;
|
| - } else {
|
| - // Driver "should" ignore unrecognized log types, per Selenium tests.
|
| - // For example the Java client passes the "client" log type in the caps,
|
| - // which the server should never provide.
|
| - LOG(WARNING) << "Ignoring unrecognized log type: LoggingPrefs." << type;
|
| + Log::Level browser_log_level = Log::kOff;
|
| + Log::Level driver_log_level = Log::kWarning;
|
| + const LoggingPrefs& prefs = capabilities.logging_prefs;
|
| +
|
| + const char kBrowserLogType[] = "browser";
|
| + const char kDriverLogType[] = "driver";
|
| + for (LoggingPrefs::const_iterator iter = prefs.begin();
|
| + iter != prefs.end();
|
| + ++iter) {
|
| + std::string type = iter->first;
|
| + Log::Level level = iter->second;
|
| + if (type == "performance") {
|
| + if (level != Log::kOff) {
|
| + WebDriverLog* log = new WebDriverLog(type, Log::kAll);
|
| + logs.push_back(log);
|
| + listeners.push_back(new PerformanceLogger(log));
|
| }
|
| + } else if (type == kBrowserLogType) {
|
| + browser_log_level = level;
|
| + } else if (type == kDriverLogType) {
|
| + driver_log_level = level;
|
| + } else {
|
| + // Driver "should" ignore unrecognized log types, per Selenium tests.
|
| + // For example the Java client passes the "client" log type in the caps,
|
| + // which the server should never provide.
|
| + LOG(WARNING) << "Ignoring unrecognized log type: " << type;
|
| }
|
| }
|
| // Create "browser" log -- should always exist.
|
| - WebDriverLog* browser_log = new WebDriverLog("browser", browser_log_level);
|
| - devtools_logs.push_back(browser_log);
|
| + WebDriverLog* browser_log =
|
| + new WebDriverLog(kBrowserLogType, browser_log_level);
|
| + logs.push_back(browser_log);
|
| // If the level is OFF, don't even bother listening for DevTools events.
|
| - if (browser_log_level != WebDriverLog::kWdOff)
|
| + if (browser_log_level != Log::kOff)
|
| listeners.push_back(new ConsoleLogger(browser_log));
|
|
|
| - out_devtools_logs->swap(devtools_logs);
|
| + // Create "driver" log -- should always exist.
|
| + scoped_ptr<WebDriverLog> driver_log(
|
| + new WebDriverLog(kDriverLogType, driver_log_level));
|
| +
|
| + out_logs->swap(logs);
|
| + *out_driver_log = driver_log.Pass();
|
| out_listeners->swap(listeners);
|
| return Status(kOk);
|
| }
|
|
|