blob: 0e68e7b8c473220f4610cc476354e820a828dd2b [file] [log] [blame]
James Kuszmaul011b67a2019-12-15 12:52:34 -08001#include "aos/logging/log_namer.h"
2
3#include <dirent.h>
James Kuszmaul011b67a2019-12-15 12:52:34 -08004#include <mntent.h>
James Kuszmaul011b67a2019-12-15 12:52:34 -08005#include <unistd.h>
Tyler Chatowbf0609c2021-07-31 16:13:27 -07006
7#include <cerrno>
8#include <cstdio>
9#include <cstdlib>
10#include <cstring>
Stephan Pleines0960c262024-05-31 20:29:24 -070011#include <ostream>
James Kuszmaul011b67a2019-12-15 12:52:34 -080012#include <string>
13
Austin Schuh99f7c6a2024-06-25 22:07:44 -070014#include "absl/flags/flag.h"
15#include "absl/log/check.h"
16#include "absl/log/log.h"
James Kuszmaul011b67a2019-12-15 12:52:34 -080017
Jim Ostrowski0dd46662024-02-25 17:08:26 -080018#include "aos/configuration.h"
19#include "aos/time/time.h"
20
Adam Snaider13d48d92023-08-03 12:20:15 -070021#if defined(__clang)
22#pragma clang diagnostic ignored "-Wformat-nonliteral"
23#elif defined(__GNUC__)
24#pragma GCC diagnostic ignored "-Wformat-nonliteral"
25#endif
26
Austin Schuh99f7c6a2024-06-25 22:07:44 -070027ABSL_FLAG(std::string, logging_folder,
Austin Schuh03e80a62019-12-28 15:18:54 -080028#ifdef AOS_ARCHITECTURE_arm_frc
Austin Schuh99f7c6a2024-06-25 22:07:44 -070029 "",
Austin Schuh03e80a62019-12-28 15:18:54 -080030#else
Austin Schuh99f7c6a2024-06-25 22:07:44 -070031 "./logs",
Austin Schuh03e80a62019-12-28 15:18:54 -080032#endif
Austin Schuh99f7c6a2024-06-25 22:07:44 -070033 "The folder to log to. If empty, search for the /media/sd*1/ "
34 "folder and place logs there.");
Austin Schuh03e80a62019-12-28 15:18:54 -080035
Stephan Pleinesf63bde82024-01-13 15:59:33 -080036namespace aos::logging {
James Kuszmaul011b67a2019-12-15 12:52:34 -080037namespace {
38void AllocateLogName(char **filename, const char *directory,
39 const char *basename) {
40 int fileindex = 0;
41 DIR *const d = opendir(directory);
42 if (d == nullptr) {
43 PLOG(FATAL) << "could not open directory" << directory;
44 }
45 int index = 0;
46 while (true) {
47 errno = 0;
48 struct dirent *const dir = readdir(d);
49 if (dir == nullptr) {
50 if (errno == 0) {
51 break;
52 } else {
53 PLOG(FATAL) << "readdir(" << d << ") failed";
54 }
55 } else {
Jim Ostrowski0dd46662024-02-25 17:08:26 -080056 char previous_date[512];
57 // Look for previous index and date
58 const std::string format_string = std::string(basename) + "-%d_%s";
59 if (sscanf(dir->d_name, format_string.c_str(), &index, &previous_date) ==
60 2) {
James Kuszmaul011b67a2019-12-15 12:52:34 -080061 if (index >= fileindex) {
62 fileindex = index + 1;
63 }
64 }
65 }
66 }
67 closedir(d);
68
69 char previous[512];
70 ::std::string path = ::std::string(directory) + "/" + basename + "-current";
71 ssize_t len = ::readlink(path.c_str(), previous, sizeof(previous));
72 if (len != -1) {
73 previous[len] = '\0';
74 } else {
75 previous[0] = '\0';
76 LOG(INFO) << "Could not find " << path;
77 }
Jim Ostrowski0dd46662024-02-25 17:08:26 -080078 // Remove subsecond accuracy (after the "."). We don't need it, and it makes
79 // the string very long
80 std::string time_short = aos::ToString(aos::realtime_clock::now());
81 time_short = time_short.substr(0, time_short.find("."));
82
83 if (asprintf(filename, "%s/%s-%03d_%s", directory, basename, fileindex,
84 time_short.c_str()) == -1) {
James Kuszmaul011b67a2019-12-15 12:52:34 -080085 PLOG(FATAL) << "couldn't create final name";
86 }
James Kuszmaul131aa042021-08-01 17:28:50 -070087 // Fix basename formatting.
Austin Schuh2b378b42024-02-26 22:01:04 -080088 LOG(INFO) << "Created log file (" << *filename << "). Previous file was ("
James Kuszmaul131aa042021-08-01 17:28:50 -070089 << directory << "/" << previous << ").";
James Kuszmaul011b67a2019-12-15 12:52:34 -080090}
91
James Kuszmaul011b67a2019-12-15 12:52:34 -080092bool FoundThumbDrive(const char *path) {
93 FILE *mnt_fp = setmntent("/etc/mtab", "r");
94 if (mnt_fp == nullptr) {
95 LOG(FATAL) << "Could not open /etc/mtab";
96 }
97
98 bool found = false;
99 struct mntent mntbuf;
100 char buf[256];
101 while (!found) {
102 struct mntent *mount_list = getmntent_r(mnt_fp, &mntbuf, buf, sizeof(buf));
103 if (mount_list == nullptr) {
104 break;
105 }
106 if (strcmp(mount_list->mnt_dir, path) == 0) {
107 found = true;
108 }
109 }
110 endmntent(mnt_fp);
111 return found;
112}
113
114bool FindDevice(char *device, size_t device_size) {
115 char test_device[10];
116 for (char i = 'a'; i < 'z'; ++i) {
117 snprintf(test_device, sizeof(test_device), "/dev/sd%c", i);
Austin Schuh73fcab12020-02-22 14:59:23 -0800118 VLOG(1) << "Trying to access" << test_device;
James Kuszmaul011b67a2019-12-15 12:52:34 -0800119 if (access(test_device, F_OK) != -1) {
120 snprintf(device, device_size, "sd%c", i);
121 return true;
122 }
123 }
124 return false;
125}
Austin Schuh03e80a62019-12-28 15:18:54 -0800126
James Kuszmaul011b67a2019-12-15 12:52:34 -0800127} // namespace
128
Ravago Jones1a4bc762023-04-09 16:21:57 -0700129std::optional<std::string> MaybeGetLogName(const char *basename) {
Austin Schuh99f7c6a2024-06-25 22:07:44 -0700130 if (absl::GetFlag(FLAGS_logging_folder).empty()) {
Austin Schuh03e80a62019-12-28 15:18:54 -0800131 char folder[128];
132 {
133 char dev_name[8];
Ravago Jones1a4bc762023-04-09 16:21:57 -0700134 if (!FindDevice(dev_name, sizeof(dev_name))) {
Austin Schuh03e80a62019-12-28 15:18:54 -0800135 LOG(INFO) << "Waiting for a device";
Ravago Jones1a4bc762023-04-09 16:21:57 -0700136 return std::nullopt;
Austin Schuh03e80a62019-12-28 15:18:54 -0800137 }
138 snprintf(folder, sizeof(folder), "/media/%s1", dev_name);
Ravago Jones1a4bc762023-04-09 16:21:57 -0700139 if (!FoundThumbDrive(folder)) {
Austin Schuh03e80a62019-12-28 15:18:54 -0800140 LOG(INFO) << "Waiting for" << folder;
Ravago Jones1a4bc762023-04-09 16:21:57 -0700141 return std::nullopt;
Austin Schuh03e80a62019-12-28 15:18:54 -0800142 }
143 snprintf(folder, sizeof(folder), "/media/%s1/", dev_name);
James Kuszmaul011b67a2019-12-15 12:52:34 -0800144 }
James Kuszmaul011b67a2019-12-15 12:52:34 -0800145
Austin Schuh03e80a62019-12-28 15:18:54 -0800146 if (access(folder, F_OK) == -1) {
147 LOG(FATAL) << "folder '" << folder
148 << "' does not exist. please create it.";
149 }
150
Austin Schuh99f7c6a2024-06-25 22:07:44 -0700151 absl::SetFlag(&FLAGS_logging_folder, folder);
Austin Schuh03e80a62019-12-28 15:18:54 -0800152 }
Austin Schuh99f7c6a2024-06-25 22:07:44 -0700153 const std::string folder = absl::GetFlag(FLAGS_logging_folder);
154 if (access(folder.c_str(), R_OK | W_OK) == -1) {
James Kuszmaul011b67a2019-12-15 12:52:34 -0800155 LOG(FATAL) << "folder '" << folder << "' does not exist. please create it.";
156 }
157 LOG(INFO) << "logging to folder '" << folder << "'";
158
159 char *tmp;
Austin Schuh99f7c6a2024-06-25 22:07:44 -0700160 AllocateLogName(&tmp, folder.c_str(), basename);
Austin Schuh2d0471d2020-02-29 13:27:07 -0800161
162 std::string log_base_name = tmp;
Austin Schuhe715eae2020-10-10 15:39:30 -0700163 std::string log_roborio_name = log_base_name + "/";
Austin Schuh2d0471d2020-02-29 13:27:07 -0800164 free(tmp);
165
James Kuszmaul011b67a2019-12-15 12:52:34 -0800166 char *tmp2;
Austin Schuh99f7c6a2024-06-25 22:07:44 -0700167 if (asprintf(&tmp2, "%s/%s-current", folder.c_str(), basename) == -1) {
James Kuszmaul011b67a2019-12-15 12:52:34 -0800168 PLOG(WARNING) << "couldn't create current symlink name";
169 } else {
170 if (unlink(tmp2) == -1 && (errno != EROFS && errno != ENOENT)) {
171 LOG(WARNING) << "unlink('" << tmp2 << "') failed";
172 }
Austin Schuh2d0471d2020-02-29 13:27:07 -0800173 if (symlink(log_roborio_name.c_str(), tmp2) == -1) {
174 PLOG(WARNING) << "symlink('" << log_roborio_name.c_str() << "', '" << tmp2
175 << "') failed";
James Kuszmaul011b67a2019-12-15 12:52:34 -0800176 }
177 free(tmp2);
178 }
Austin Schuh2d0471d2020-02-29 13:27:07 -0800179 return log_base_name;
James Kuszmaul011b67a2019-12-15 12:52:34 -0800180}
181
Ravago Jones1a4bc762023-04-09 16:21:57 -0700182std::string GetLogName(const char *basename) {
183 std::optional<std::string> log_base_name;
184
185 while (true) {
186 log_base_name = MaybeGetLogName(basename);
187
188 if (log_base_name.has_value()) {
189 break;
190 }
191
192 sleep(5);
193 }
194
195 return log_base_name.value();
196}
197
Stephan Pleinesf63bde82024-01-13 15:59:33 -0800198} // namespace aos::logging