| // Copyright 2021 The Chromium OS 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 <deque> |
| #include <limits> |
| #include <string> |
| #include <vector> |
| |
| #include <base/command_line.h> |
| #include <base/logging.h> |
| #include "base/files/file_path.h" |
| #include <base/files/file_util.h> |
| #include <base/files/file_enumerator.h> |
| |
| #include <brillo/syslog_logging.h> |
| #include <metrics/metrics_library.h> |
| |
| #include "croslog/constants.h" |
| #include "croslog/log_parser_audit.h" |
| #include "croslog/log_parser_syslog.h" |
| #include "croslog/metrics_collector_util.h" |
| |
| namespace { |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // Min, max, bucket size of metricses: |
| // |
| // NOTE: these value can't be changed. If we want, we need to delete the |
| // existing metrics and create new one (eg. SystemLogTotalFileSize2). |
| |
| // We expect the log file size is between 1MB to 4GB. |
| // Note these values can't be changed |
| const int kFileSizeMegabyteMetricsMin = 1; |
| const int kFileSizeMegabyteMetricsMax = 4 * 1024; |
| // 24 = log2(kFileSizeMegabyteMetricsMax) * 2 |
| const int kFileSizeMegabyteMetricsNumberOfBuckets = 24; |
| |
| // We expect the total of log file sizes is between 1MB to 8GB. |
| const int kTotalLogMegabyteMetricsMin = 1; |
| const int kTotalLogMegabyteMetricsMax = 8 * 1024; |
| // 26 = log2(kFileSizeMegabyteMetricsMax) * 2 |
| const int kTotalLogMegabyteMetricsNumberOfBuckets = 26; |
| |
| // We expect the throughput is 1 to 60 * 500 entries per minute. |
| const int kNumberOfEntriesPerMinuteMetricsMin = 1; |
| const int kNumberOfEntriesPerMinuteMetricsMax = 60 * 500; |
| // 30 ~= log2(kNumberOfEntriesMetricsMax) * 2 |
| const int kNumberOfEntriesPerMinuteMetricsNumberOfBuckets = 30; |
| |
| // We expect the throughput is 1 to 86.4k * 50 entries per day. |
| const int kNumberOfEntriesPerDayMetricsMin = 1; |
| const int kNumberOfEntriesPerDayMetricsMax = 86400 * 50; |
| // 44 ~= log2(kNumberOfEntriesMetricsMax) * 2 |
| const int kNumberOfEntriesPerDayMetricsNumberOfBuckets = 44; |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // Log path constants: |
| |
| // Patterns to match with the specific logs: |
| const char kChromeLogFileNamePattern[] = "chrome_\?\?\?\?\?\?\?\?-\?\?\?\?\?\?"; |
| const char kChromeUiLogFileNamePattern[] = "ui.\?\?\?\?\?\?\?\?-\?\?\?\?\?\?"; |
| |
| // Log files: |
| const base::FilePath kSystemLogDirectoryPath("/var/log/"); |
| const base::FilePath kSystemChromeLogDirectoryPath("/var/log/chrome/"); |
| const base::FilePath kSystemChromeUiLogDirectoryPath("/var/log/ui/"); |
| const base::FilePath kSystemMessagesLogPath("/var/log/messages"); |
| const base::FilePath kSystemNetLogPath("/var/log/net.log"); |
| const base::FilePath kSystemAuditLogPath("/var/log/audit/audit.log"); |
| const base::FilePath kSystemArcLogPath("/var/log/arc.log"); |
| const base::FilePath kUserLogDirectoryPath("/home/chronos/user/log/"); |
| const base::FilePath kUserChromeLogDirectoryPath("/home/chronos/user/log/"); |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // Utility methods |
| |
| int ByteToMB(int64_t bytes) { |
| return bytes / 1024 / 1024; |
| } |
| |
| void CalculateSysLogFileSizePerDayWithinDay(const base::FilePath& path, |
| int64_t* byte_count_out) { |
| base::Time count_after = base::Time::Now() - base::TimeDelta::FromDays(1); |
| croslog::CalculateLogMetrics(path, count_after, |
| std::make_unique<croslog::LogParserSyslog>(), |
| byte_count_out, nullptr, nullptr); |
| } |
| |
| void CalculateAuditLogFileSizePerDayWithinDay(const base::FilePath& path, |
| int64_t* byte_count_out) { |
| base::Time count_after = base::Time::Now() - base::TimeDelta::FromDays(1); |
| croslog::CalculateLogMetrics(path, count_after, |
| std::make_unique<croslog::LogParserAudit>(), |
| byte_count_out, nullptr, nullptr); |
| } |
| |
| void CalculateSystemChromeLogsByteCountWithinDay(int64_t* byte_count_out) { |
| base::Time count_after = base::Time::Now() - base::TimeDelta::FromDays(1); |
| croslog::CalculateChromeLogMetrics(kSystemChromeLogDirectoryPath, |
| kChromeLogFileNamePattern, count_after, |
| byte_count_out, nullptr, nullptr); |
| croslog::CalculateChromeLogMetrics(kSystemChromeUiLogDirectoryPath, |
| kChromeUiLogFileNamePattern, count_after, |
| byte_count_out, nullptr, nullptr); |
| } |
| |
| } // anonymous namespace |
| |
| namespace metrics { |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // Metrics names: |
| |
| const char kSystemArcLogFileSizePerDay[] = |
| "ChromeOS.Logging.SystemArcLogFileSizePerDay"; |
| const char kSystemAuditLogFileSizePerDay[] = |
| "ChromeOS.Logging.SystemAuditLogFileSizePerDay"; |
| const char kSystemChromeLogFileSizePerDay[] = |
| "ChromeOS.Logging.SystemChromeLogFileSizePerDay"; |
| const char kSystemMessageLogFileSizePerDay[] = |
| "ChromeOS.Logging.SystemMessageLogFileSizePerDay"; |
| const char kSystemNetLogFileSizePerDay[] = "Logging.SystemNetLogFileSizePerDay"; |
| const char kUserChromeLogFileSizePerDay[] = |
| "ChromeOS.Logging.UserChromeLogFileSizePerDay"; |
| |
| const char kSystemLogTotalSize[] = "ChromeOS.Logging.SystemLogTotalFileSize"; |
| const char kUserLogTotalSize[] = "ChromeOS.Logging.UserLogTotalFileSize"; |
| |
| const char kSystemLogTotalEntryCountPerDay[] = |
| "ChromeOS.Logging.SystemLogEntryCountPerDay"; |
| const char kUserLogTotalEntryCountPerDay[] = |
| "ChromeOS.Logging.UserLogEntryCountPerDay"; |
| |
| const char kSystemLogMaximumThroughput[] = |
| "ChromeOS.Logging.SystemLogMaxThroughputPerMin"; |
| const char kUserLogMaximumThroughput[] = |
| "ChromeOS.Logging.UserLogMaxThroughputPerMin"; |
| |
| } // namespace metrics |
| |
| class MetricsCollector { |
| public: |
| MetricsCollector() { metrics_library_.Init(); } |
| |
| void Run() { |
| // [Entire system log directory] Total file size. |
| { |
| int64_t system_log_total_size = |
| ComputeDirectorySize(kSystemLogDirectoryPath); |
| SendTotalLogSizeToUMA(metrics::kSystemLogTotalSize, |
| system_log_total_size); |
| LOG(INFO) << "Total system log size: " << system_log_total_size |
| << " bytes"; |
| } |
| |
| // [Major system log files] Number of entries per day and the maximum |
| // throughput per minute. |
| { |
| int64_t max_throughput; |
| int64_t entry_count; |
| |
| croslog::Multiplexer multiplexer; |
| for (const auto& log_path_str : croslog::kLogSources) { |
| base::FilePath path(log_path_str.data()); |
| if (!base::PathExists(path)) |
| continue; |
| multiplexer.AddSource( |
| path, std::make_unique<croslog::LogParserSyslog>(), false); |
| } |
| |
| for (const auto& log_path_str : croslog::kAuditLogSources) { |
| base::FilePath path(log_path_str.data()); |
| if (!base::PathExists(path)) |
| continue; |
| multiplexer.AddSource(path, std::make_unique<croslog::LogParserAudit>(), |
| false); |
| } |
| |
| base::Time count_after = base::Time::Now() - base::TimeDelta::FromDays(1); |
| croslog::CalculateMultipleLogMetrics(&multiplexer, count_after, |
| &entry_count, &max_throughput); |
| |
| if (entry_count != -1) { |
| SendNumberOfEntriesPerDayToUMA(metrics::kSystemLogTotalEntryCountPerDay, |
| entry_count); |
| } |
| LOG(INFO) << "Total system log: " << entry_count << " entries per day."; |
| |
| if (max_throughput != -1) { |
| SendNumberOfEntriesPerMinuteToUMA(metrics::kSystemLogMaximumThroughput, |
| max_throughput); |
| } |
| LOG(INFO) << "Maximum throughput of system logs: " << max_throughput |
| << " entries per minute."; |
| } |
| |
| // [System "message" log] Byte count of logs per day. |
| { |
| int64_t byte_count_message; |
| CalculateSysLogFileSizePerDayWithinDay(kSystemMessagesLogPath, |
| &byte_count_message); |
| if (byte_count_message != -1) { |
| SendLogFileSizeToUMA(metrics::kSystemMessageLogFileSizePerDay, |
| byte_count_message); |
| LOG(INFO) << "Total message (system) log: " << byte_count_message |
| << " bytes per day."; |
| } |
| } |
| |
| // [System "net" log] Byte count of logs per day. |
| { |
| int64_t byte_count_net; |
| CalculateSysLogFileSizePerDayWithinDay(kSystemNetLogPath, |
| &byte_count_net); |
| if (byte_count_net != -1) { |
| SendLogFileSizeToUMA(metrics::kSystemNetLogFileSizePerDay, |
| byte_count_net); |
| LOG(INFO) << "Total net (system) log: " << byte_count_net |
| << " bytes per day."; |
| } |
| } |
| |
| // [System "audit" log] Byte count of logs per day. |
| { |
| int64_t byte_count_audit; |
| CalculateAuditLogFileSizePerDayWithinDay(kSystemAuditLogPath, |
| &byte_count_audit); |
| if (byte_count_audit != -1) { |
| SendLogFileSizeToUMA(metrics::kSystemAuditLogFileSizePerDay, |
| byte_count_audit); |
| LOG(INFO) << "Total audit (system) log: " << byte_count_audit |
| << " bytes per day."; |
| } |
| } |
| |
| // [System "ARC" log] Byte count of logs per day. |
| { |
| int64_t byte_count_arc; |
| CalculateSysLogFileSizePerDayWithinDay(kSystemArcLogPath, |
| &byte_count_arc); |
| if (byte_count_arc != -1) { |
| SendLogFileSizeToUMA(metrics::kSystemArcLogFileSizePerDay, |
| byte_count_arc); |
| LOG(INFO) << "Total arc (system) log: " << byte_count_arc |
| << " bytes per day."; |
| } |
| } |
| |
| // [System chrome logs] Byte count of logs per day. |
| { |
| int64_t byte_count_chrome; |
| CalculateSystemChromeLogsByteCountWithinDay(&byte_count_chrome); |
| if (byte_count_chrome != -1) { |
| SendLogFileSizeToUMA(metrics::kSystemChromeLogFileSizePerDay, |
| byte_count_chrome); |
| } |
| LOG(INFO) << "Total chrome (system) log: " << byte_count_chrome |
| << " bytes per day."; |
| } |
| |
| // [Entire user log directory] Total file size. |
| { |
| int64_t user_log_total_size = ComputeDirectorySize(kUserLogDirectoryPath); |
| if (user_log_total_size > 0) { |
| SendTotalLogSizeToUMA(metrics::kUserLogTotalSize, user_log_total_size); |
| } |
| LOG(INFO) << "Total user log size: " << user_log_total_size << " bytes"; |
| } |
| |
| // [User chrome logs] Byte count of logs per day, and the maximum throughput |
| // per minute. |
| { |
| int64_t max_throughput; |
| int64_t entry_count; |
| int64_t byte_count_chrome; |
| |
| base::Time count_after = base::Time::Now() - base::TimeDelta::FromDays(1); |
| croslog::CalculateChromeLogMetrics( |
| kUserChromeLogDirectoryPath, kChromeLogFileNamePattern, count_after, |
| &byte_count_chrome, &entry_count, &max_throughput); |
| |
| if (byte_count_chrome > 0) { |
| SendNumberOfEntriesPerMinuteToUMA(metrics::kUserLogMaximumThroughput, |
| max_throughput); |
| LOG(INFO) << "Maximum throughput of user logs: " << max_throughput |
| << " entries per minute."; |
| SendNumberOfEntriesPerDayToUMA(metrics::kUserLogTotalEntryCountPerDay, |
| entry_count); |
| LOG(INFO) << "Total user log: " << entry_count << " entries per day."; |
| SendLogFileSizeToUMA(metrics::kUserChromeLogFileSizePerDay, |
| byte_count_chrome); |
| LOG(INFO) << "Total chrome (user) log: " << byte_count_chrome |
| << " bytes per day."; |
| } |
| } |
| } |
| |
| private: |
| void SendLogFileSizeToUMA(const std::string& name, int64_t value_in_bytes) { |
| metrics_library_.SendToUMA( |
| name, ByteToMB(value_in_bytes), kFileSizeMegabyteMetricsMin, |
| kFileSizeMegabyteMetricsMax, kFileSizeMegabyteMetricsNumberOfBuckets); |
| } |
| |
| void SendTotalLogSizeToUMA(const std::string& name, int64_t value_in_bytes) { |
| metrics_library_.SendToUMA( |
| name, ByteToMB(value_in_bytes), kTotalLogMegabyteMetricsMin, |
| kTotalLogMegabyteMetricsMax, kTotalLogMegabyteMetricsNumberOfBuckets); |
| } |
| |
| void SendNumberOfEntriesPerMinuteToUMA(const std::string& name, |
| int64_t value) { |
| metrics_library_.SendToUMA(name, static_cast<int>(value), |
| kNumberOfEntriesPerMinuteMetricsMin, |
| kNumberOfEntriesPerMinuteMetricsMax, |
| kNumberOfEntriesPerMinuteMetricsNumberOfBuckets); |
| } |
| |
| void SendNumberOfEntriesPerDayToUMA(const std::string& name, int64_t value) { |
| metrics_library_.SendToUMA(name, static_cast<int>(value), |
| kNumberOfEntriesPerDayMetricsMin, |
| kNumberOfEntriesPerDayMetricsMax, |
| kNumberOfEntriesPerDayMetricsNumberOfBuckets); |
| } |
| |
| MetricsLibrary metrics_library_; |
| }; |
| |
| int main(int argc, char* argv[]) { |
| // Configure the log destination. |
| brillo::InitLog(brillo::kLogToSyslog | brillo::kLogToStderrIfTty); |
| |
| std::unique_ptr<MetricsCollector> collector = |
| std::make_unique<MetricsCollector>(); |
| collector->Run(); |
| } |