1b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)// Copyright (c) 2013 The Chromium Authors. All rights reserved.
2b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
3b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)// found in the LICENSE file.
4b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
5b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)#include "chrome/test/chromedriver/chrome/console_logger.h"
6b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
7b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)#include "base/json/json_writer.h"
8868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/logging.h"
9868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/stringprintf.h"
10b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)#include "base/values.h"
11b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)#include "chrome/test/chromedriver/chrome/devtools_client.h"
12b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)#include "chrome/test/chromedriver/chrome/log.h"
13b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)#include "chrome/test/chromedriver/chrome/status.h"
14b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
15b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)namespace {
16b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
17868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// Translates Console.messageAdded.message.level into Log::Level.
18b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)bool ConsoleLevelToLogLevel(const std::string& name, Log::Level *out_level) {
19868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  const char* const kConsoleLevelNames[] = {
20b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    "debug", "log", "warning", "error"
21b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  };
22b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
23b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  for (size_t i = 0; i < arraysize(kConsoleLevelNames); ++i) {
24b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    if (name == kConsoleLevelNames[i]) {
25868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      CHECK_LE(Log::kDebug + i, static_cast<size_t>(Log::kError));
26b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      *out_level = static_cast<Log::Level>(Log::kDebug + i);
27b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      return true;
28b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    }
29b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  }
30b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  return false;
31b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)}
32b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
33b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)}  // namespace
34b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
35b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)ConsoleLogger::ConsoleLogger(Log* log)
36b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    : log_(log) {}
37b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
38b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)Status ConsoleLogger::OnConnected(DevToolsClient* client) {
39b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  base::DictionaryValue params;
40b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  return client->SendCommand("Console.enable", params);
41b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)}
42b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
43868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)Status ConsoleLogger::OnEvent(
44b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    DevToolsClient* client,
45b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    const std::string& method,
46b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    const base::DictionaryValue& params) {
47868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (method != "Console.messageAdded")
48868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    return Status(kOk);
49b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
50b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  // If the event has proper structure and fields, log formatted.
51b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  // Else it's a weird message that we don't know how to format, log full JSON.
52b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  const base::DictionaryValue *message_dict = NULL;
53b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (params.GetDictionary("message", &message_dict)) {
54868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    std::string text;
55868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    std::string level_name;
5658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    Log::Level level = Log::kInfo;
57868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    if (message_dict->GetString("text", &text) && !text.empty() &&
58868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        message_dict->GetString("level", &level_name) &&
59868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        ConsoleLevelToLogLevel(level_name, &level)) {
60b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
61868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      const char* origin_cstr = "unknown";
62868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      std::string origin;
63868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      if ((message_dict->GetString("url", &origin) && !origin.empty()) ||
64868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)          (message_dict->GetString("source", &origin) && !origin.empty())) {
65868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        origin_cstr = origin.c_str();
66b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      }
67b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
68868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      std::string line_column;
69868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      int line = -1;
70868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      if (message_dict->GetInteger("line", &line)) {
71868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        int column = -1;
72868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        if (message_dict->GetInteger("column", &column)) {
73868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)          base::SStringPrintf(&line_column, "%d:%d", line, column);
74868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        } else {
75868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)          base::SStringPrintf(&line_column, "%d", line);
76b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)        }
77868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      } else {
78868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        // No line number, but print anyway, just to maintain the number of
79868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        // fields in the formatted message in case someone wants to parse it.
80868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        line_column = "-";
81b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      }
82868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
834e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      std::string source;
844e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      message_dict->GetString("source", &source);
854e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      log_->AddEntry(level, source, base::StringPrintf("%s %s %s",
864e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                                                       origin_cstr,
874e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                                                       line_column.c_str(),
884e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                                                       text.c_str()));
894e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
90868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      return Status(kOk);
91b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    }
92b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  }
93b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
94b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  // Don't know how to format, log full JSON.
95b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  std::string message_json;
96b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  base::JSONWriter::Write(&params, &message_json);
97b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  log_->AddEntry(Log::kWarning, message_json);
98868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  return Status(kOk);
99b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)}
100