Skip to content

Commit 41e0e3e

Browse files
committed
cvd: Add support for logging to a file
Implement timestamped log file creation for the cvd command. Logs are saved in PerUserDir() + "/logs/" with a name like cvd_YYYYMMDD_HHMMSS.ms.log. This ensures logs are preserved across runs. Assisted-by: Jetski <jetski@google.com> Bug: b/507600500
1 parent 1175fe0 commit 41e0e3e

5 files changed

Lines changed: 113 additions & 4 deletions

File tree

base/cvd/cuttlefish/host/commands/cvd/BUILD.bazel

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ cf_cc_binary(
3535
"//cuttlefish/common/libs/utils:flag_parser",
3636
"//cuttlefish/common/libs/utils:subprocess",
3737
"//cuttlefish/common/libs/utils:tee_logging",
38+
"//cuttlefish/host/commands/cvd/cli:log_files",
3839
"//cuttlefish/host/commands/cvd/utils",
3940
"//cuttlefish/host/commands/cvd/version",
4041
"//cuttlefish/host/libs/vm_manager",

base/cvd/cuttlefish/host/commands/cvd/cli/BUILD.bazel

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,17 @@ cf_cc_library(
5151
],
5252
)
5353

54+
cf_cc_library(
55+
name = "log_files",
56+
srcs = ["log_files.cpp"],
57+
hdrs = ["log_files.h"],
58+
deps = [
59+
"//cuttlefish/common/libs/utils:files",
60+
"//cuttlefish/host/commands/cvd/utils",
61+
"@abseil-cpp//absl/strings",
62+
],
63+
)
64+
5465
# Commands that may invoke other commands
5566
cf_cc_library(
5667
name = "nesting_commands",
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
/*
2+
* Copyright (C) 2026 The Android Open Source Project
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
#include "cuttlefish/host/commands/cvd/cli/log_files.h"
18+
19+
#include <chrono>
20+
#include <iomanip>
21+
#include <iostream>
22+
#include <sstream>
23+
#include <string>
24+
#include <vector>
25+
26+
#include "absl/strings/str_cat.h"
27+
28+
#include "cuttlefish/common/libs/utils/files.h"
29+
#include "cuttlefish/host/commands/cvd/utils/common.h"
30+
31+
namespace cuttlefish {
32+
33+
std::optional<std::string> GetLogFile() {
34+
std::string log_dir = PerUserDir() + "/logs";
35+
if (!EnsureDirectoryExists(log_dir, 0777).ok()) {
36+
std::cerr << "Failed to create log directory: " << log_dir
37+
<< ". Logging to file disabled." << std::endl;
38+
return std::nullopt;
39+
}
40+
41+
std::chrono::system_clock::time_point now = std::chrono::system_clock::now();
42+
std::time_t now_time_t = std::chrono::system_clock::to_time_t(now);
43+
std::chrono::milliseconds now_ms =
44+
std::chrono::duration_cast<std::chrono::milliseconds>(
45+
now.time_since_epoch()) %
46+
1000;
47+
48+
std::tm tm_now;
49+
localtime_r(&now_time_t, &tm_now);
50+
51+
std::stringstream ss;
52+
ss << std::put_time(&tm_now, "%Y%m%d_%H%M%S") << "." << std::setfill('0')
53+
<< std::setw(3) << now_ms.count();
54+
return absl::StrCat(log_dir, "/cvd_", ss.str(), ".log");
55+
}
56+
57+
} // namespace cuttlefish
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/*
2+
* Copyright (C) 2026 The Android Open Source Project
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
#pragma once
18+
19+
#include <optional>
20+
#include <string>
21+
22+
namespace cuttlefish {
23+
24+
/**
25+
* Returns the path to a new timestamped log file for the
26+
* cvd command. The log file is created in PerUserDir() + "/logs/" with a name
27+
* like cvd_YYYYMMDD_HHMMSS.ms.log. If the logs directory cannot be created, the
28+
* function returns std::nullopt.
29+
*/
30+
std::optional<std::string> GetLogFile();
31+
32+
} // namespace cuttlefish

base/cvd/cuttlefish/host/commands/cvd/main.cc

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,17 +26,18 @@
2626
#include <unordered_map>
2727
#include <vector>
2828

29-
#include <android-base/file.h>
3029
#include "absl/cleanup/cleanup.h"
31-
#include "absl/strings/str_split.h"
32-
#include <fmt/format.h>
3330
#include "absl/log/log.h"
31+
#include "absl/strings/str_split.h"
32+
#include "android-base/file.h"
33+
#include "fmt/format.h"
3434

3535
#include "cuttlefish/common/libs/utils/environment.h"
3636
#include "cuttlefish/common/libs/utils/files.h"
3737
#include "cuttlefish/common/libs/utils/flag_parser.h"
3838
#include "cuttlefish/common/libs/utils/subprocess.h"
3939
#include "cuttlefish/common/libs/utils/tee_logging.h"
40+
#include "cuttlefish/host/commands/cvd/cli/log_files.h"
4041
#include "cuttlefish/host/commands/cvd/cvd.h"
4142
#include "cuttlefish/host/commands/cvd/utils/common.h"
4243
#include "cuttlefish/host/commands/cvd/version/version.h"
@@ -216,6 +217,7 @@ bool ValidateHostConfiguration() {
216217
}
217218

218219
} // namespace
220+
219221
} // namespace cuttlefish
220222

221223
int main(int argc, char** argv) {
@@ -228,7 +230,13 @@ int main(int argc, char** argv) {
228230
cuttlefish::MetadataLevel metadata_level =
229231
isatty(0) ? cuttlefish::MetadataLevel::ONLY_MESSAGE
230232
: cuttlefish::MetadataLevel::FULL;
231-
cuttlefish::LogToStderr("", metadata_level, verbosity);
233+
234+
std::optional<std::string> log_file = cuttlefish::GetLogFile();
235+
std::vector<std::string> log_files;
236+
if (log_file) {
237+
log_files.push_back(*log_file);
238+
}
239+
cuttlefish::LogToStderrAndFiles(log_files, "", metadata_level, verbosity);
232240

233241
if (!cuttlefish::ValidateHostConfiguration()) {
234242
return -1;

0 commit comments

Comments
 (0)