syslogs_provider.cc revision 2a99a7e74a7f215066514fe81d2bfa6639d9eddd
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" 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/file_util.h" 132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/files/file_path.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" 172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/message_loop_proxy.h" 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/string_util.h" 192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/task_runner.h" 202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/threading/sequenced_worker_pool.h" 212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/feedback/feedback_util.h" 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/memory_details.h" 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/chrome_switches.h" 242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chromeos/network/network_event_log.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) { 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_t equal_sign = data->find("="); 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (equal_sign == std::string::npos) 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return std::string(""); 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string key = data->substr(0, equal_sign); 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) data->erase(0, equal_sign); 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (data->size() > 0) { 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // erase the equal to sign also 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) data->erase(0,1); 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return key; 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return std::string(); 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. 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 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; 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { // single line value 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_t endl_pos = data->find_first_of(kNewLineChars); 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // if we don't find a new line, we just return the rest of the data 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string value = data->substr(0, endl_pos); 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) data->erase(0, endl_pos); 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return value; 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Returns a map of system log keys and values. 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Parameters: 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// temp_filename: This is an out parameter that holds the name of a file in 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Reads a value from the input string; erasing the read values from 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// the initial string; detects if the value is multiline and reads 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// accordingly 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// /tmp that contains the system logs in a KEY=VALUE format. 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// If this parameter is NULL, system logs are not retained on 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// the filesystem after this call completes. 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// context: This is an in parameter specifying what context should be 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// passed to the syslog collection script; currently valid 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// values are "sysinfo" or "feedback"; in case of an invalid 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// value, the script will currently default to "sysinfo" 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)LogDictionaryType* GetSystemLogs(base::FilePath* zip_file_name, 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& context) { 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Create the temp file, logs will go here 1232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::FilePath temp_filename; 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!file_util::CreateTemporaryFile(&temp_filename)) 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return NULL; 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string cmd = std::string(kSysLogsScript) + " " + context + " >> " + 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) temp_filename.value(); 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Ignore the return value - if the script execution didn't work 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // stderr won't go into the output file anyway. 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (::system(cmd.c_str()) == -1) 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LOG(WARNING) << "Command " << cmd << " failed to run"; 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Compress the logs file if requested. 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (zip_file_name) { 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cmd = std::string(kBzip2Command) + " -c " + temp_filename.value() + " > " + 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) zip_file_name->value(); 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (::system(cmd.c_str()) == -1) 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LOG(WARNING) << "Command " << cmd << " failed to run"; 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Read logs from the temp file 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string data; 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool read_success = file_util::ReadFileToString(temp_filename, 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &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 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) file_util::Delete(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); 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TrimWhitespaceASCII(key, TRIM_ALL, &key); 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!key.empty()) { 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string value = ReadValue(&data); 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (IsStringUTF8(value)) { 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TrimWhitespaceASCII(value, 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: 1852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) virtual CancelableTaskTracker::TaskId RequestSyslogs( 1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool compress_logs, 1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SyslogsContext context, 1882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const ReadCompleteCallback& callback, 1892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 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( 1992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const 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( 2162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const 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) 2282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)CancelableTaskTracker::TaskId SyslogsProviderImpl::RequestSyslogs( 2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool compress_logs, 2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SyslogsContext context, 2312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const ReadCompleteCallback& callback, 2322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) CancelableTaskTracker* tracker) { 2332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) CancelableTaskTracker::IsCanceledCallback is_canceled; 2342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) CancelableTaskTracker::TaskId id = tracker->NewTrackedTaskId(&is_canceled); 2352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ReadCompleteCallback callback_runner = 2372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::Bind(&SyslogsProviderImpl::RunCallbackIfNotCanceled, 2382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) is_canceled, base::MessageLoopProxy::current(), callback); 2392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Schedule a task which will run the callback later when complete. 2412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) BrowserThread::PostBlockingPoolTask( 2422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) FROM_HERE, 2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Bind(&SyslogsProviderImpl::ReadSyslogs, base::Unretained(this), 2442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) is_canceled, compress_logs, context, callback_runner)); 2452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return id; 2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Derived class from memoryDetails converts the results into a single string 2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// and adds a "mem_usage" entry to the logs, then forwards the result. 2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Format of entry is (one process per line, reverse-sorted by size): 2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Tab [Title1|Title2]: 50 MB 2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Browser: 30 MB 2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Tab [Title]: 20 MB 2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Extension [Title]: 10 MB 2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// ... 2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class SyslogsMemoryHandler : public MemoryDetails { 2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public: 2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) typedef SyslogsProvider::ReadCompleteCallback ReadCompleteCallback; 2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // |logs| is modified (see comment above) and passed to |request|. 2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // |zip_content| is passed to |request|. 2622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) SyslogsMemoryHandler(const ReadCompleteCallback& callback, 2632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) LogDictionaryType* logs, 2642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) std::string* zip_content); 2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) virtual void OnDetailsAvailable() OVERRIDE; 2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private: 2692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) virtual ~SyslogsMemoryHandler(); 2702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ReadCompleteCallback callback_; 2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LogDictionaryType* logs_; 2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string* zip_content_; 2752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DISALLOW_COPY_AND_ASSIGN(SyslogsMemoryHandler); 2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)SyslogsMemoryHandler::SyslogsMemoryHandler( 2802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const ReadCompleteCallback& callback, 2812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) LogDictionaryType* logs, 2822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) std::string* zip_content) 2832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) : callback_(callback), 2842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) logs_(logs), 2852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) zip_content_(zip_content) { 2862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(!callback_.is_null()); 2872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 2882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void SyslogsMemoryHandler::OnDetailsAvailable() { 2902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) (*logs_)["mem_usage"] = ToLogString(); 2912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) callback_.Run(logs_, zip_content_); 2922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 2932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)SyslogsMemoryHandler::~SyslogsMemoryHandler() {} 2952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Called from blocking pool thread. 2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SyslogsProviderImpl::ReadSyslogs( 2982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const CancelableTaskTracker::IsCanceledCallback& is_canceled, 2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool compress_logs, 3002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) SyslogsContext context, 3012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const ReadCompleteCallback& callback) { 3022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread()); 3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (is_canceled.Run()) 3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Create temp file. 3082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::FilePath zip_file; 3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (compress_logs && !file_util::CreateTemporaryFile(&zip_file)) { 3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LOG(ERROR) << "Cannot create temp file"; 3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) compress_logs = false; 3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LogDictionaryType* logs = NULL; 3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) logs = GetSystemLogs( 3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) compress_logs ? &zip_file : NULL, 3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GetSyslogsContextString(context)); 3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string* zip_content = NULL; 3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (compress_logs) { 3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Load compressed logs. 3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) zip_content = new std::string(); 3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LoadCompressedLogs(zip_file, zip_content); 3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) file_util::Delete(zip_file, false); 3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Include dbus statistics summary 3282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) (*logs)["dbus"] = dbus::statistics::GetAsString( 3292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) dbus::statistics::SHOW_INTERFACE, 3302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) dbus::statistics::FORMAT_ALL); 3312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Include recent network log events 3332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) (*logs)["network_event_log"] = chromeos::network_event_log::GetAsString( 3342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) chromeos::network_event_log::OLDEST_FIRST, 3352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) chromeos::system::kFeedbackMaxLineCount); 3362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // SyslogsMemoryHandler will clean itself up. 3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // SyslogsMemoryHandler::OnDetailsAvailable() will modify |logs| and call 3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // request->ForwardResult(logs, zip_content). 3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scoped_refptr<SyslogsMemoryHandler> 3412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) handler(new SyslogsMemoryHandler(callback, logs, zip_content)); 3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // TODO(jamescook): Maybe we don't need to update histograms here? 3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) handler->StartFetch(MemoryDetails::UPDATE_USER_METRICS); 3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void SyslogsProviderImpl::LoadCompressedLogs(const base::FilePath& zip_file, 3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string* zip_content) { 3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(zip_content); 3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!file_util::ReadFileToString(zip_file, zip_content)) { 3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LOG(ERROR) << "Cannot read compressed logs file from " << 3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) zip_file.value().c_str(); 3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char* SyslogsProviderImpl::GetSyslogsContextString( 3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SyslogsContext context) { 3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) switch (context) { 3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case(SYSLOGS_FEEDBACK): 3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return kContextFeedback; 3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case(SYSLOGS_SYSINFO): 3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return kContextSysInfo; 3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case(SYSLOGS_NETWORK): 3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return kContextNetwork; 3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case(SYSLOGS_DEFAULT): 3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return kContextSysInfo; 3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) default: 3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED(); 3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ""; 3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// static 3732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void SyslogsProviderImpl::RunCallbackIfNotCanceled( 3742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const CancelableTaskTracker::IsCanceledCallback& is_canceled, 3752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::TaskRunner* origin_runner, 3762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const ReadCompleteCallback& callback, 3772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) LogDictionaryType* logs, 3782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) std::string* zip_content) { 3792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(!is_canceled.is_null() && !callback.is_null()); 3802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (is_canceled.Run()) { 3822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) delete logs; 3832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) delete zip_content; 3842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; 3852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 3862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // TODO(achuith@chromium.org): Maybe always run callback asynchronously? 3882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (origin_runner->RunsTasksOnCurrentThread()) { 3892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) callback.Run(logs, zip_content); 3902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } else { 3912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) origin_runner->PostTask(FROM_HERE, base::Bind(callback, logs, zip_content)); 3922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 3932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 3942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SyslogsProviderImpl* SyslogsProviderImpl::GetInstance() { 3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return Singleton<SyslogsProviderImpl, 3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DefaultSingletonTraits<SyslogsProviderImpl> >::get(); 3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SyslogsProvider* SyslogsProvider::GetInstance() { 4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return SyslogsProviderImpl::GetInstance(); 4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace system 4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace chromeos 406