blob: d272a55333cbc88c99bec19095eccb27b53b487a [file] [log] [blame]
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/test/chromedriver/chrome/log.h"
#include <stdio.h>
#include "base/json/json_reader.h"
#include "base/json/json_writer.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "base/values.h"
namespace {
// Truncates the given string to 200 characters, adding an ellipsis if
// truncation was necessary.
void TruncateString(std::string* data) {
const size_t kMaxLength = 200;
if (data->length() > kMaxLength) {
data->resize(kMaxLength);
data->replace(kMaxLength - 3, 3, "...");
}
}
// Truncates all strings contained in the given value.
void TruncateContainedStrings(base::Value* value) {
base::ListValue* list = NULL;
base::DictionaryValue* dict = NULL;
if (value->GetAsDictionary(&dict)) {
for (base::DictionaryValue::Iterator it(*dict); !it.IsAtEnd();
it.Advance()) {
std::string data;
if (it.value().GetAsString(&data)) {
TruncateString(&data);
dict->SetWithoutPathExpansion(it.key(), new base::StringValue(data));
} else {
base::Value* child = NULL;
dict->GetWithoutPathExpansion(it.key(), &child);
TruncateContainedStrings(child);
}
}
} else if (value->GetAsList(&list)) {
for (size_t i = 0; i < list->GetSize(); ++i) {
base::Value* child = NULL;
if (!list->Get(i, &child))
continue;
std::string data;
if (child->GetAsString(&data)) {
TruncateString(&data);
list->Set(i, new base::StringValue(data));
} else {
TruncateContainedStrings(child);
}
}
}
}
std::string ConvertForDisplayInternal(const std::string& input) {
size_t left = input.find("{");
size_t right = input.rfind("}");
if (left == std::string::npos || right == std::string::npos)
return input.substr(0, 10 << 10);
scoped_ptr<base::Value> value(
base::JSONReader::Read(input.substr(left, right - left + 1)));
if (!value)
return input.substr(0, 10 << 10);
TruncateContainedStrings(value.get());
std::string json;
base::JSONWriter::WriteWithOptions(
value.get(), base::JSONWriter::OPTIONS_PRETTY_PRINT, &json);
std::string display = input.substr(0, left) + json;
if (input.length() > right)
display += input.substr(right + 1);
return display;
}
// Pretty prints encapsulated JSON and truncates long strings for display.
std::string ConvertForDisplay(const std::string& input) {
std::string display = ConvertForDisplayInternal(input);
char remove_chars[] = {'\r', '\0'};
RemoveChars(display, remove_chars, &display);
return display;
}
} // namespace
void Log::AddEntry(Level level, const std::string& message) {
AddEntryTimestamped(base::Time::Now(), level, message);
}
Logger::Logger() : min_log_level_(kLog), start_(base::Time::Now()) {}
Logger::Logger(Level min_log_level)
: min_log_level_(min_log_level), start_(base::Time::Now()) {}
Logger::~Logger() {}
void Logger::AddEntryTimestamped(const base::Time& timestamp,
Level level,
const std::string& message) {
if (level < min_log_level_)
return;
const char* level_name = "UNKNOWN";
switch (level) {
case kDebug:
level_name = "DEBUG";
break;
case kLog:
level_name = "INFO";
break;
case kWarning:
level_name = "WARNING";
break;
case kError:
level_name = "ERROR";
break;
default:
break;
}
std::string entry =
base::StringPrintf("[%.3lf][%s]: %s",
base::TimeDelta(timestamp - start_).InSecondsF(),
level_name,
ConvertForDisplay(message).c_str());
const char* format = "%s\n";
if (entry[entry.length() - 1] == '\n')
format = "%s";
fprintf(stderr, format, entry.c_str());
fflush(stderr);
}