blob: d7f55326306df929a68ef66bba7f1e0431ea15ae [file] [log] [blame]
// 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();
}