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/webdriver/webdriver_logging.h" 6 7 #include <cmath> 8 9 #include "base/file_util.h" 10 #include "base/files/file_path.h" 11 #include "base/logging.h" 12 #include "base/strings/string_number_conversions.h" 13 #include "base/strings/string_util.h" 14 #include "base/strings/stringprintf.h" 15 #include "base/time/time.h" 16 #include "build/build_config.h" 17 18 using base::DictionaryValue; 19 using base::ListValue; 20 using base::Value; 21 22 namespace webdriver { 23 24 FileLog* FileLog::singleton_ = NULL; 25 26 double start_time = 0; 27 28 LogLevel LogLevelFromString(const std::string& name) { 29 // Default logging level is INFO. 30 LogLevel level = kInfoLogLevel; 31 const std::string upper_case_name = StringToUpperASCII(name); 32 if (upper_case_name == "OFF") { 33 level = kOffLogLevel; 34 } else if (upper_case_name == "SEVERE") { 35 level = kSevereLogLevel; 36 } else if (upper_case_name == "WARNING") { 37 level = kWarningLogLevel; 38 } else if (upper_case_name == "INFO" || upper_case_name == "CONFIG") { 39 40 } else if (upper_case_name == "FINE") { 41 level = kFineLogLevel; 42 } else if (upper_case_name == "FINER") { 43 level = kFinerLogLevel; 44 } else if (upper_case_name == "ALL" || upper_case_name == "FINEST") { 45 level = kAllLogLevel; 46 } 47 return level; 48 } 49 50 // static 51 bool LogType::FromString(const std::string& name, LogType* log_type) { 52 if (name == "driver") { 53 *log_type = LogType(kDriver); 54 } else { 55 return false; 56 } 57 return true; 58 } 59 60 LogType::LogType() : type_(kInvalid) { } 61 62 LogType::LogType(Type type) : type_(type) { } 63 64 LogType::~LogType() { } 65 66 std::string LogType::ToString() const { 67 switch (type_) { 68 case kDriver: 69 return "driver"; 70 default: 71 return "unknown"; 72 }; 73 } 74 75 LogType::Type LogType::type() const { 76 return type_; 77 } 78 79 LogHandler::LogHandler() { } 80 81 LogHandler::~LogHandler() { } 82 83 // static 84 void FileLog::SetGlobalLog(FileLog* log) { 85 singleton_ = log; 86 } 87 88 // static 89 FileLog* FileLog::Get() { 90 return singleton_; 91 } 92 93 // static 94 FileLog* FileLog::CreateFileLog(const base::FilePath::StringType& log_name, 95 LogLevel level) { 96 base::FilePath log_path(log_name); 97 file_util::ScopedFILE file(file_util::OpenFile(log_path, "w")); 98 base::FilePath temp_dir; 99 if (!file.get() && file_util::GetTempDir(&temp_dir)) 100 log_path = temp_dir.Append(log_name); 101 file.reset(); 102 return new FileLog(log_path, level); 103 } 104 105 FileLog::FileLog(const base::FilePath& path, LogLevel level) 106 : path_(path), 107 min_log_level_(level) { 108 if (!path_.IsAbsolute()) { 109 base::FilePath cwd; 110 if (file_util::GetCurrentDirectory(&cwd)) 111 path_ = cwd.Append(path_); 112 } 113 file_.reset(file_util::OpenFile(path_, "w")); 114 } 115 116 FileLog::~FileLog() { } 117 118 void FileLog::Log(LogLevel level, const base::Time& time, 119 const std::string& message) { 120 if (!file_.get() || level < min_log_level_) 121 return; 122 123 const char* level_name = "UNKNOWN"; 124 switch (level) { 125 case kOffLogLevel: 126 level_name = "OFF"; 127 break; 128 case kSevereLogLevel: 129 level_name = "SEVERE"; 130 break; 131 case kWarningLogLevel: 132 level_name = "WARNING"; 133 break; 134 case kInfoLogLevel: 135 level_name = "INFO"; 136 break; 137 case kFineLogLevel: 138 level_name = "FINE"; 139 break; 140 case kFinerLogLevel: 141 level_name = "FINER"; 142 break; 143 default: 144 break; 145 } 146 base::TimeDelta delta(time - base::Time::FromDoubleT(start_time)); 147 std::string entry = base::StringPrintf( 148 "[%.3lf][%s]:", delta.InSecondsF(), level_name); 149 150 int pad_length = 20 - entry.length(); 151 if (pad_length < 1) 152 pad_length = 1; 153 std::string padding(pad_length, ' '); 154 entry += padding + message; 155 #if defined(OS_WIN) 156 entry += "\r\n"; 157 #else 158 entry += "\n"; 159 #endif 160 161 base::AutoLock auto_lock(lock_); 162 fprintf(file_.get(), "%s", entry.c_str()); 163 fflush(file_.get()); 164 } 165 166 bool FileLog::GetLogContents(std::string* contents) const { 167 if (!file_.get()) 168 return false; 169 return file_util::ReadFileToString(path_, contents); 170 } 171 172 bool FileLog::IsOpen() const { 173 return !!file_.get(); 174 } 175 176 void FileLog::set_min_log_level(LogLevel level) { 177 min_log_level_ = level; 178 } 179 180 const base::FilePath& FileLog::path() const { 181 return path_; 182 } 183 184 InMemoryLog::InMemoryLog() { } 185 186 InMemoryLog::~InMemoryLog() { } 187 188 void InMemoryLog::Log(LogLevel level, const base::Time& time, 189 const std::string& message) { 190 base::TimeDelta delta = time - base::Time::UnixEpoch(); 191 DictionaryValue* entry = new DictionaryValue(); 192 entry->SetInteger("level", level); 193 entry->SetDouble("timestamp", std::floor(delta.InMillisecondsF())); 194 entry->SetString("message", message); 195 base::AutoLock auto_lock(entries_lock_); 196 entries_list_.Append(entry); 197 } 198 199 const ListValue* InMemoryLog::entries_list() const { 200 return &entries_list_; 201 } 202 203 Logger::Logger() : min_log_level_(kAllLogLevel) { } 204 205 Logger::Logger(LogLevel level) : min_log_level_(level) { } 206 207 Logger::~Logger() { } 208 209 void Logger::Log(LogLevel level, const std::string& message) const { 210 if (level < min_log_level_) 211 return; 212 213 base::Time time = base::Time::Now(); 214 for (size_t i = 0; i < handlers_.size(); ++i) { 215 handlers_[i]->Log(level, time, message); 216 } 217 } 218 219 void Logger::AddHandler(LogHandler* log_handler) { 220 handlers_.push_back(log_handler); 221 } 222 223 void Logger::set_min_log_level(LogLevel level) { 224 min_log_level_ = level; 225 } 226 227 bool InitWebDriverLogging(const base::FilePath& log_path, 228 LogLevel min_log_level) { 229 start_time = base::Time::Now().ToDoubleT(); 230 // Turn off base/logging. 231 logging::LoggingSettings settings; 232 settings.logging_dest = logging::LOG_NONE; 233 bool success = logging::InitLogging(settings); 234 if (!success) { 235 PLOG(ERROR) << "Unable to initialize logging"; 236 } 237 logging::SetLogItems(false, // enable_process_id 238 false, // enable_thread_id 239 true, // enable_timestamp 240 false); // enable_tickcount 241 242 // Init global file log. 243 FileLog* log; 244 if (log_path.empty()) { 245 log = FileLog::CreateFileLog(FILE_PATH_LITERAL("chromedriver.log"), 246 min_log_level); 247 } else { 248 log = new FileLog(log_path, min_log_level); 249 } 250 FileLog::SetGlobalLog(log); 251 return log->IsOpen(); 252 } 253 254 } // namespace webdriver 255