AU: Timestamp logs at startup.
This will allow logs to be rotated by init/chromeos-cleanup-logs (separate CL).
BUG=5527
TEST=tested on device, chrome://system
Change-Id: I844ebd198510a8f600afa99f840624b2e65d1584
Review URL: http://codereview.chromium.org/4771007
diff --git a/main.cc b/main.cc
index 571f337..0e5d3bc 100644
--- a/main.cc
+++ b/main.cc
@@ -3,11 +3,11 @@
// found in the LICENSE file.
#include <string>
-#include <tr1/memory>
#include <vector>
#include <base/at_exit.h>
#include <base/command_line.h>
+#include <base/file_util.h>
#include <base/logging.h>
#include <base/string_util.h>
#include <gflags/gflags.h>
@@ -34,7 +34,6 @@
"Don't daemon()ize; run in foreground.");
using std::string;
-using std::tr1::shared_ptr;
using std::vector;
namespace chromeos_update_engine {
@@ -95,12 +94,60 @@
G_OBJECT(service));
}
+void SetupLogSymlink(const string& symlink_path, const string& log_path) {
+ // TODO(petkov): To ensure a smooth transition between non-timestamped and
+ // timestamped logs, move an existing log to start the first timestamped
+ // one. This code can go away once all clients are switched to this version or
+ // we stop caring about the old-style logs.
+ if (utils::FileExists(symlink_path.c_str()) &&
+ !utils::IsSymlink(symlink_path.c_str())) {
+ file_util::ReplaceFile(FilePath(symlink_path), FilePath(log_path));
+ }
+ file_util::Delete(FilePath(symlink_path), true);
+ if (symlink(log_path.c_str(), symlink_path.c_str()) == -1) {
+ PLOG(ERROR) << "Unable to create symlink " << symlink_path
+ << " pointing at " << log_path;
+ }
+}
+
+string GetTimeAsString(time_t utime) {
+ struct tm tm;
+ CHECK(localtime_r(&utime, &tm) == &tm);
+ char str[16];
+ CHECK(strftime(str, sizeof(str), "%Y%m%d-%H%M%S", &tm) == 15);
+ return str;
+}
+
+string SetupLogFile(const string& kLogsRoot) {
+ const string kLogSymlink = kLogsRoot + "/update_engine.log";
+ const string kLogsDir = kLogsRoot + "/update_engine";
+ const string kLogPath =
+ StringPrintf("%s/update_engine.%s",
+ kLogsDir.c_str(),
+ GetTimeAsString(::time(NULL)).c_str());
+ mkdir(kLogsDir.c_str(), 0755);
+ SetupLogSymlink(kLogSymlink, kLogPath);
+ return kLogSymlink;
+}
+
+void SetupLogging() {
+ // Log to stderr initially.
+ logging::InitLogging(NULL,
+ logging::LOG_ONLY_TO_SYSTEM_DEBUG_LOG,
+ logging::DONT_LOCK_LOG_FILE,
+ logging::APPEND_TO_OLD_LOG_FILE);
+ if (FLAGS_logtostderr) {
+ return;
+ }
+ const string log_file = SetupLogFile("/var/log");
+ logging::InitLogging(log_file.c_str(),
+ logging::LOG_ONLY_TO_FILE,
+ logging::DONT_LOCK_LOG_FILE,
+ logging::APPEND_TO_OLD_LOG_FILE);
+}
} // namespace {}
-
} // namespace chromeos_update_engine
-#include "update_engine/subprocess.h"
-
int main(int argc, char** argv) {
::g_type_init();
g_thread_init(NULL);
@@ -110,12 +157,7 @@
chromeos_update_engine::Subprocess::Init();
google::ParseCommandLineFlags(&argc, &argv, true);
CommandLine::Init(argc, argv);
- logging::InitLogging("/var/log/update_engine.log",
- (FLAGS_logtostderr ?
- logging::LOG_ONLY_TO_SYSTEM_DEBUG_LOG :
- logging::LOG_ONLY_TO_FILE),
- logging::DONT_LOCK_LOG_FILE,
- logging::APPEND_TO_OLD_LOG_FILE);
+ chromeos_update_engine::SetupLogging();
if (!FLAGS_foreground)
PLOG_IF(FATAL, daemon(0, 0) == 1) << "daemon() failed";
diff --git a/utils.cc b/utils.cc
index 162fe7b..359b6b8 100644
--- a/utils.cc
+++ b/utils.cc
@@ -301,6 +301,11 @@
return 0 == lstat(path, &stbuf);
}
+bool IsSymlink(const char* path) {
+ struct stat stbuf;
+ return lstat(path, &stbuf) == 0 && S_ISLNK(stbuf.st_mode) != 0;
+}
+
std::string TempFilename(string path) {
static const string suffix("XXXXXX");
CHECK(StringHasSuffix(path, suffix));
diff --git a/utils.h b/utils.h
index 208abe8..34b862e 100644
--- a/utils.h
+++ b/utils.h
@@ -60,6 +60,9 @@
// or an error occurs.
bool FileExists(const char* path);
+// Returns true if |path| exists and is a symbolic link.
+bool IsSymlink(const char* path);
+
// The last 6 chars of path must be XXXXXX. They will be randomly changed
// and a non-existent path will be returned. Intentionally makes a copy
// of the string passed in.