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/chrome/log.h" 6 7 #include <stdio.h> 8 9 #include "base/json/json_reader.h" 10 #include "base/json/json_writer.h" 11 #include "base/strings/string_util.h" 12 #include "base/strings/stringprintf.h" 13 #include "base/values.h" 14 15 namespace { 16 17 // Truncates the given string to 200 characters, adding an ellipsis if 18 // truncation was necessary. 19 void TruncateString(std::string* data) { 20 const size_t kMaxLength = 200; 21 if (data->length() > kMaxLength) { 22 data->resize(kMaxLength); 23 data->replace(kMaxLength - 3, 3, "..."); 24 } 25 } 26 27 // Truncates all strings contained in the given value. 28 void TruncateContainedStrings(base::Value* value) { 29 base::ListValue* list = NULL; 30 base::DictionaryValue* dict = NULL; 31 if (value->GetAsDictionary(&dict)) { 32 for (base::DictionaryValue::Iterator it(*dict); !it.IsAtEnd(); 33 it.Advance()) { 34 std::string data; 35 if (it.value().GetAsString(&data)) { 36 TruncateString(&data); 37 dict->SetWithoutPathExpansion(it.key(), new base::StringValue(data)); 38 } else { 39 base::Value* child = NULL; 40 dict->GetWithoutPathExpansion(it.key(), &child); 41 TruncateContainedStrings(child); 42 } 43 } 44 } else if (value->GetAsList(&list)) { 45 for (size_t i = 0; i < list->GetSize(); ++i) { 46 base::Value* child = NULL; 47 if (!list->Get(i, &child)) 48 continue; 49 std::string data; 50 if (child->GetAsString(&data)) { 51 TruncateString(&data); 52 list->Set(i, new base::StringValue(data)); 53 } else { 54 TruncateContainedStrings(child); 55 } 56 } 57 } 58 } 59 60 std::string ConvertForDisplayInternal(const std::string& input) { 61 size_t left = input.find("{"); 62 size_t right = input.rfind("}"); 63 if (left == std::string::npos || right == std::string::npos) 64 return input.substr(0, 10 << 10); 65 66 scoped_ptr<base::Value> value( 67 base::JSONReader::Read(input.substr(left, right - left + 1))); 68 if (!value) 69 return input.substr(0, 10 << 10); 70 TruncateContainedStrings(value.get()); 71 std::string json; 72 base::JSONWriter::WriteWithOptions( 73 value.get(), base::JSONWriter::OPTIONS_PRETTY_PRINT, &json); 74 std::string display = input.substr(0, left) + json; 75 if (input.length() > right) 76 display += input.substr(right + 1); 77 return display; 78 } 79 80 // Pretty prints encapsulated JSON and truncates long strings for display. 81 std::string ConvertForDisplay(const std::string& input) { 82 std::string display = ConvertForDisplayInternal(input); 83 char remove_chars[] = {'\r', '\0'}; 84 RemoveChars(display, remove_chars, &display); 85 return display; 86 } 87 88 } // namespace 89 90 void Log::AddEntry(Level level, const std::string& message) { 91 AddEntryTimestamped(base::Time::Now(), level, message); 92 } 93 94 Logger::Logger() : min_log_level_(kLog), start_(base::Time::Now()) {} 95 96 Logger::Logger(Level min_log_level) 97 : min_log_level_(min_log_level), start_(base::Time::Now()) {} 98 99 Logger::~Logger() {} 100 101 void Logger::AddEntryTimestamped(const base::Time& timestamp, 102 Level level, 103 const std::string& message) { 104 if (level < min_log_level_) 105 return; 106 107 const char* level_name = "UNKNOWN"; 108 switch (level) { 109 case kDebug: 110 level_name = "DEBUG"; 111 break; 112 case kLog: 113 level_name = "INFO"; 114 break; 115 case kWarning: 116 level_name = "WARNING"; 117 break; 118 case kError: 119 level_name = "ERROR"; 120 break; 121 default: 122 break; 123 } 124 std::string entry = 125 base::StringPrintf("[%.3lf][%s]: %s", 126 base::TimeDelta(timestamp - start_).InSecondsF(), 127 level_name, 128 ConvertForDisplay(message).c_str()); 129 const char* format = "%s\n"; 130 if (entry[entry.length() - 1] == '\n') 131 format = "%s"; 132 fprintf(stderr, format, entry.c_str()); 133 fflush(stderr); 134 } 135