15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/chromeos/system/syslogs_provider.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ash/shell.h"
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h"
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind_helpers.h"
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/command_line.h"
112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/compiler_specific.h"
122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/files/file_path.h"
131320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "base/files/file_util.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/memory/scoped_ptr.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/memory/singleton.h"
17b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)#include "base/message_loop/message_loop_proxy.h"
185e3f23d412006dc4db4e659864679f29341e113fTorne (Richard Coles)#include "base/strings/string_util.h"
192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/task_runner.h"
202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/threading/sequenced_worker_pool.h"
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/memory_details.h"
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/chrome_switches.h"
232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chromeos/network/network_event_log.h"
24010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#include "components/feedback/feedback_util.h"
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/browser_thread.h"
262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "dbus/dbus_statistics.h"
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using content::BrowserThread;
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace chromeos {
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace system {
322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const size_t kFeedbackMaxLength = 4 * 1024;
342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const size_t kFeedbackMaxLineCount = 40;
352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kSysLogsScript[] =
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "/usr/share/userfeedback/scripts/sysinfo_script_runner";
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kBzip2Command[] =
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "/bin/bzip2";
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kMultilineQuote[] = "\"\"\"";
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kNewLineChars[] = "\r\n";
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kInvalidLogEntry[] = "<invalid characters in log entry>";
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kEmptyLogEntry[] = "<no value>";
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kContextFeedback[] = "feedback";
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kContextSysInfo[] = "sysinfo";
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kContextNetwork[] = "network";
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Reads a key from the input string erasing the read values + delimiters read
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// from the initial string
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::string ReadKey(std::string* data) {
545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::string key;
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  size_t equal_sign = data->find("=");
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (equal_sign == std::string::npos)
575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return key;
585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  key = data->substr(0, equal_sign);
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  data->erase(0, equal_sign);
605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (data->empty())
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return key;
625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // erase the equal to sign also
635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  data->erase(0, 1);
645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return key;
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Reads a value from the input string; erasing the read values from
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// the initial string; detects if the value is multiline and reads
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// accordingly
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::string ReadValue(std::string* data) {
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Trim the leading spaces and tabs. In order to use a multi-line
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // value, you have to place the multi-line quote on the same line as
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the equal sign.
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Why not use TrimWhitespace? Consider the following input:
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // KEY1=
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // KEY2=VALUE
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If we use TrimWhitespace, we will incorrectly trim the new line
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // and assume that KEY1's value is "KEY2=VALUE" rather than empty.
82a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  base::TrimString(*data, " \t", data);
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If multiline value
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (StartsWithASCII(*data, std::string(kMultilineQuote), false)) {
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    data->erase(0, strlen(kMultilineQuote));
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    size_t next_multi = data->find(kMultilineQuote);
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (next_multi == std::string::npos) {
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Error condition, clear data to stop further processing
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      data->erase();
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return std::string();
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::string value = data->substr(0, next_multi);
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    data->erase(0, next_multi + 3);
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return value;
965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  } else {
975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // single line value
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    size_t endl_pos = data->find_first_of(kNewLineChars);
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // if we don't find a new line, we just return the rest of the data
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::string value = data->substr(0, endl_pos);
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    data->erase(0, endl_pos);
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return value;
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Returns a map of system log keys and values.
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Parameters:
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// temp_filename: This is an out parameter that holds the name of a file in
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Reads a value from the input string; erasing the read values from
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// the initial string; detects if the value is multiline and reads
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// accordingly
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//                /tmp that contains the system logs in a KEY=VALUE format.
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//                If this parameter is NULL, system logs are not retained on
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//                the filesystem after this call completes.
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// context:       This is an in parameter specifying what context should be
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//                passed to the syslog collection script; currently valid
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//                values are "sysinfo" or "feedback"; in case of an invalid
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//                value, the script will currently default to "sysinfo"
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)LogDictionaryType* GetSystemLogs(base::FilePath* zip_file_name,
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                 const std::string& context) {
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Create the temp file, logs will go here
1242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath temp_filename;
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
126a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  if (!base::CreateTemporaryFile(&temp_filename))
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return NULL;
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string cmd = std::string(kSysLogsScript) + " " + context + " >> " +
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      temp_filename.value();
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Ignore the return value - if the script execution didn't work
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // stderr won't go into the output file anyway.
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (::system(cmd.c_str()) == -1)
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(WARNING) << "Command " << cmd << " failed to run";
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Compress the logs file if requested.
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (zip_file_name) {
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cmd = std::string(kBzip2Command) + " -c " + temp_filename.value() + " > " +
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        zip_file_name->value();
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (::system(cmd.c_str()) == -1)
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      LOG(WARNING) << "Command " << cmd << " failed to run";
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Read logs from the temp file
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string data;
14658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  bool read_success = base::ReadFileToString(temp_filename, &data);
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // if we were using an internal temp file, the user does not need the
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // logs to stay past the ReadFile call - delete the file
1497dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  base::DeleteFile(temp_filename, false);
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!read_success)
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return NULL;
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Parse the return data into a dictionary
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  LogDictionaryType* logs = new LogDictionaryType();
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while (data.length() > 0) {
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::string key = ReadKey(&data);
158a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    base::TrimWhitespaceASCII(key, base::TRIM_ALL, &key);
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!key.empty()) {
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      std::string value = ReadValue(&data);
161010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      if (base::IsStringUTF8(value)) {
162a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        base::TrimWhitespaceASCII(value, base::TRIM_ALL, &value);
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (value.empty())
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          (*logs)[key] = kEmptyLogEntry;
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        else
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          (*logs)[key] = value;
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      } else {
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        LOG(WARNING) << "Invalid characters in system log entry: " << key;
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        (*logs)[key] = kInvalidLogEntry;
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // no more keys, we're done
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return logs;
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class SyslogsProviderImpl : public SyslogsProvider {
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // SyslogsProvider implementation:
1855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  virtual base::CancelableTaskTracker::TaskId RequestSyslogs(
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      bool compress_logs,
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      SyslogsContext context,
1882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      const ReadCompleteCallback& callback,
1895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      base::CancelableTaskTracker* tracker) OVERRIDE;
1902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  static SyslogsProviderImpl* GetInstance();
1922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) private:
1942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  friend struct DefaultSingletonTraits<SyslogsProviderImpl>;
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Reads system logs, compresses content if requested.
1972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Called from blocking pool thread.
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void ReadSyslogs(
1995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      const base::CancelableTaskTracker::IsCanceledCallback& is_canceled,
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      bool compress_logs,
2012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      SyslogsContext context,
2022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      const ReadCompleteCallback& callback);
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Loads compressed logs and writes into |zip_content|.
2052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  void LoadCompressedLogs(const base::FilePath& zip_file,
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          std::string* zip_content);
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SyslogsProviderImpl();
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Gets syslogs context string from the enum value.
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const char* GetSyslogsContextString(SyslogsContext context);
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // If not canceled, run callback on originating thread (the thread on which
2142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // ReadSyslogs was run).
2152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  static void RunCallbackIfNotCanceled(
2165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      const base::CancelableTaskTracker::IsCanceledCallback& is_canceled,
2172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::TaskRunner* origin_runner,
2182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      const ReadCompleteCallback& callback,
2192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      LogDictionaryType* logs,
2202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      std::string* zip_content);
2212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(SyslogsProviderImpl);
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SyslogsProviderImpl::SyslogsProviderImpl() {
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)base::CancelableTaskTracker::TaskId SyslogsProviderImpl::RequestSyslogs(
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool compress_logs,
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SyslogsContext context,
2312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const ReadCompleteCallback& callback,
2325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    base::CancelableTaskTracker* tracker) {
2335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::CancelableTaskTracker::IsCanceledCallback is_canceled;
2345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::CancelableTaskTracker::TaskId id =
2355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      tracker->NewTrackedTaskId(&is_canceled);
2362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ReadCompleteCallback callback_runner =
2382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::Bind(&SyslogsProviderImpl::RunCallbackIfNotCanceled,
2392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                 is_canceled, base::MessageLoopProxy::current(), callback);
2402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Schedule a task which will run the callback later when complete.
2422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  BrowserThread::PostBlockingPoolTask(
2432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      FROM_HERE,
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(&SyslogsProviderImpl::ReadSyslogs, base::Unretained(this),
2452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                 is_canceled, compress_logs, context, callback_runner));
2462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return id;
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Derived class from memoryDetails converts the results into a single string
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// and adds a "mem_usage" entry to the logs, then forwards the result.
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Format of entry is (one process per line, reverse-sorted by size):
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//   Tab [Title1|Title2]: 50 MB
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//   Browser: 30 MB
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//   Tab [Title]: 20 MB
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//   Extension [Title]: 10 MB
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// ...
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class SyslogsMemoryHandler : public MemoryDetails {
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  typedef SyslogsProvider::ReadCompleteCallback ReadCompleteCallback;
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // |logs| is modified (see comment above) and passed to |request|.
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // |zip_content| is passed to |request|.
2632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  SyslogsMemoryHandler(const ReadCompleteCallback& callback,
2642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                       LogDictionaryType* logs,
2652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                       std::string* zip_content);
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual void OnDetailsAvailable() OVERRIDE;
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
2702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual ~SyslogsMemoryHandler();
2712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ReadCompleteCallback callback_;
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  LogDictionaryType* logs_;
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string* zip_content_;
2762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(SyslogsMemoryHandler);
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)SyslogsMemoryHandler::SyslogsMemoryHandler(
2812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const ReadCompleteCallback& callback,
2822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    LogDictionaryType* logs,
2832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    std::string* zip_content)
2842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    : callback_(callback),
2852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      logs_(logs),
2862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      zip_content_(zip_content) {
2872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!callback_.is_null());
2882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void SyslogsMemoryHandler::OnDetailsAvailable() {
2912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    (*logs_)["mem_usage"] = ToLogString();
2922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    callback_.Run(logs_, zip_content_);
2932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)SyslogsMemoryHandler::~SyslogsMemoryHandler() {}
2962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Called from blocking pool thread.
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SyslogsProviderImpl::ReadSyslogs(
2995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const base::CancelableTaskTracker::IsCanceledCallback& is_canceled,
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool compress_logs,
3012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    SyslogsContext context,
3022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const ReadCompleteCallback& callback) {
3032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread());
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (is_canceled.Run())
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Create temp file.
3092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath zip_file;
310a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  if (compress_logs && !base::CreateTemporaryFile(&zip_file)) {
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "Cannot create temp file";
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    compress_logs = false;
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  LogDictionaryType* logs = NULL;
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  logs = GetSystemLogs(
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      compress_logs ? &zip_file : NULL,
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      GetSyslogsContextString(context));
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string* zip_content = NULL;
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (compress_logs) {
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Load compressed logs.
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    zip_content = new std::string();
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LoadCompressedLogs(zip_file, zip_content);
3257dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    base::DeleteFile(zip_file, false);
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Include dbus statistics summary
3292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  (*logs)["dbus"] = dbus::statistics::GetAsString(
3302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      dbus::statistics::SHOW_INTERFACE,
3312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      dbus::statistics::FORMAT_ALL);
3322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Include recent network log events
33490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  (*logs)["network_event_log"] = network_event_log::GetAsString(
33590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      network_event_log::OLDEST_FIRST,
33690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      "time,file,desc",
33790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      network_event_log::kDefaultLogLevel,
33890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      system::kFeedbackMaxLineCount);
3392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // SyslogsMemoryHandler will clean itself up.
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // SyslogsMemoryHandler::OnDetailsAvailable() will modify |logs| and call
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // request->ForwardResult(logs, zip_content).
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_refptr<SyslogsMemoryHandler>
3442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      handler(new SyslogsMemoryHandler(callback, logs, zip_content));
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(jamescook): Maybe we don't need to update histograms here?
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  handler->StartFetch(MemoryDetails::UPDATE_USER_METRICS);
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void SyslogsProviderImpl::LoadCompressedLogs(const base::FilePath& zip_file,
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                            std::string* zip_content) {
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(zip_content);
35258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  if (!base::ReadFileToString(zip_file, zip_content)) {
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "Cannot read compressed logs file from " <<
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        zip_file.value().c_str();
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char* SyslogsProviderImpl::GetSyslogsContextString(
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SyslogsContext context) {
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  switch (context) {
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case(SYSLOGS_FEEDBACK):
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return kContextFeedback;
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case(SYSLOGS_SYSINFO):
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return kContextSysInfo;
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case(SYSLOGS_NETWORK):
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return kContextNetwork;
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case(SYSLOGS_DEFAULT):
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return kContextSysInfo;
3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    default:
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NOTREACHED();
3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return "";
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// static
3762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void SyslogsProviderImpl::RunCallbackIfNotCanceled(
3775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const base::CancelableTaskTracker::IsCanceledCallback& is_canceled,
3782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::TaskRunner* origin_runner,
3792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const ReadCompleteCallback& callback,
3802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    LogDictionaryType* logs,
3812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    std::string* zip_content) {
3822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!is_canceled.is_null() && !callback.is_null());
3832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (is_canceled.Run()) {
3852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    delete logs;
3862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    delete zip_content;
3872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
3882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
3892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // TODO(achuith@chromium.org): Maybe always run callback asynchronously?
3912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (origin_runner->RunsTasksOnCurrentThread()) {
3922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    callback.Run(logs, zip_content);
3932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  } else {
3942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    origin_runner->PostTask(FROM_HERE, base::Bind(callback, logs, zip_content));
3952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
3962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SyslogsProviderImpl* SyslogsProviderImpl::GetInstance() {
3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return Singleton<SyslogsProviderImpl,
4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   DefaultSingletonTraits<SyslogsProviderImpl> >::get();
4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SyslogsProvider* SyslogsProvider::GetInstance() {
4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return SyslogsProviderImpl::GetInstance();
4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace system
4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace chromeos
409