Home | History | Annotate | Download | only in chrome
      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