1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "chrome/test/chromedriver/logging.h" 6 7 #include "base/basictypes.h" 8 #include "base/logging.h" 9 #include "base/time/time.h" 10 #include "chrome/test/chromedriver/capabilities.h" 11 #include "chrome/test/chromedriver/chrome/console_logger.h" 12 #include "chrome/test/chromedriver/chrome/performance_logger.h" 13 #include "chrome/test/chromedriver/chrome/status.h" 14 15 16 namespace { 17 18 // Map between WebDriverLog::WebDriverLevel and its name in WD wire protocol. 19 // Array indices are the WebDriverLog::WebDriverLevel enum values. 20 const char* const kWebDriverLevelNames[] = { 21 "ALL", "DEBUG", "INFO", "WARNING", "SEVERE", "OFF" 22 }; 23 24 // Map between Log::Level and WebDriverLog::WebDriverLevel. 25 // Array indices are the Log::Level enum values. 26 WebDriverLog::WebDriverLevel kLogLevelToWebDriverLevels[] = { 27 WebDriverLog::kWdDebug, // kDebug 28 WebDriverLog::kWdInfo, // kLog 29 WebDriverLog::kWdWarning, // kWarning 30 WebDriverLog::kWdSevere // kError 31 }; 32 33 // Translates Log::Level to WebDriverLog::WebDriverLevel. 34 WebDriverLog::WebDriverLevel LogLevelToWebDriverLevel(Log::Level level) { 35 const int index = level - Log::kDebug; 36 CHECK_GE(index, 0); 37 CHECK_LT(static_cast<size_t>(index), arraysize(kLogLevelToWebDriverLevels)); 38 return kLogLevelToWebDriverLevels[index]; 39 } 40 41 // Returns WD wire protocol level name for a WebDriverLog::WebDriverLevel. 42 std::string GetWebDriverLevelName( 43 const WebDriverLog::WebDriverLevel level) { 44 const int index = level - WebDriverLog::kWdAll; 45 CHECK_GE(index, 0); 46 CHECK_LT(static_cast<size_t>(index), arraysize(kWebDriverLevelNames)); 47 return kWebDriverLevelNames[index]; 48 } 49 50 } // namespace 51 52 bool WebDriverLog::NameToLevel( 53 const std::string& name, WebDriverLog::WebDriverLevel* out_level) { 54 for (size_t i = 0; i < arraysize(kWebDriverLevelNames); ++i) { 55 if (name == kWebDriverLevelNames[i]) { 56 CHECK_LE(WebDriverLog::kWdAll + i, 57 static_cast<size_t>(WebDriverLog::kWdOff)); 58 *out_level = 59 static_cast<WebDriverLog::WebDriverLevel>(WebDriverLog::kWdAll + i); 60 return true; 61 } 62 } 63 return false; 64 } 65 66 WebDriverLog::WebDriverLog( 67 const std::string& type, WebDriverLog::WebDriverLevel min_wd_level) 68 : type_(type), 69 min_wd_level_(min_wd_level), 70 entries_(new base::ListValue()) { 71 VLOG(1) << "Log(" << type_ << ", " << min_wd_level_ << ")"; 72 } 73 74 WebDriverLog::~WebDriverLog() { 75 VLOG(1) << "Log type '" << type_ << "' lost " 76 << entries_->GetSize() << " entries on destruction"; 77 } 78 79 const std::string& WebDriverLog::GetType() { 80 return type_; 81 } 82 83 void WebDriverLog::AddEntryTimestamped(const base::Time& timestamp, 84 Log::Level level, 85 const std::string& message) { 86 const WebDriverLog::WebDriverLevel wd_level = LogLevelToWebDriverLevel(level); 87 if (wd_level < min_wd_level_) 88 return; 89 scoped_ptr<base::DictionaryValue> log_entry_dict(new base::DictionaryValue()); 90 log_entry_dict->SetDouble("timestamp", 91 static_cast<int64>(timestamp.ToJsTime())); 92 log_entry_dict->SetString("level", GetWebDriverLevelName(wd_level)); 93 log_entry_dict->SetString("message", message); 94 entries_->Append(log_entry_dict.release()); 95 } 96 97 scoped_ptr<base::ListValue> WebDriverLog::GetAndClearEntries() { 98 scoped_ptr<base::ListValue> ret(entries_.release()); 99 entries_.reset(new base::ListValue()); 100 return ret.Pass(); 101 } 102 103 Status CreateLogs(const Capabilities& capabilities, 104 ScopedVector<WebDriverLog>* out_devtools_logs, 105 ScopedVector<DevToolsEventListener>* out_listeners) { 106 ScopedVector<WebDriverLog> devtools_logs; 107 ScopedVector<DevToolsEventListener> listeners; 108 WebDriverLog::WebDriverLevel browser_log_level = WebDriverLog::kWdInfo; 109 110 if (capabilities.logging_prefs) { 111 for (DictionaryValue::Iterator pref(*capabilities.logging_prefs); 112 !pref.IsAtEnd(); pref.Advance()) { 113 const std::string type = pref.key(); 114 std::string level_name; 115 if (!pref.value().GetAsString(&level_name)) { 116 return Status(kUnknownError, 117 "logging level must be a string for log type: " + type); 118 } 119 WebDriverLog::WebDriverLevel level = WebDriverLog::kWdOff; 120 if (!WebDriverLog::NameToLevel(level_name, &level)) { 121 return Status(kUnknownError, 122 "invalid log level \"" + level_name + 123 "\" for type: " + type); 124 } 125 if ("performance" == type) { 126 if (WebDriverLog::kWdOff != level) { 127 WebDriverLog* log = new WebDriverLog(type, WebDriverLog::kWdAll); 128 devtools_logs.push_back(log); 129 listeners.push_back(new PerformanceLogger(log)); 130 } 131 } else if ("browser" == type) { 132 browser_log_level = level; 133 } else { 134 // Driver "should" ignore unrecognized log types, per Selenium tests. 135 // For example the Java client passes the "client" log type in the caps, 136 // which the server should never provide. 137 LOG(WARNING) << "Ignoring unrecognized log type: LoggingPrefs." << type; 138 } 139 } 140 } 141 // Create "browser" log -- should always exist. 142 WebDriverLog* browser_log = new WebDriverLog("browser", browser_log_level); 143 devtools_logs.push_back(browser_log); 144 // If the level is OFF, don't even bother listening for DevTools events. 145 if (browser_log_level != WebDriverLog::kWdOff) 146 listeners.push_back(new ConsoleLogger(browser_log)); 147 148 out_devtools_logs->swap(devtools_logs); 149 out_listeners->swap(listeners); 150 return Status(kOk); 151 } 152