Merge "Base: Add default tag manipulation"
diff --git a/base/include/android-base/logging.h b/base/include/android-base/logging.h
index afff2c9..cc7aaf6 100644
--- a/base/include/android-base/logging.h
+++ b/base/include/android-base/logging.h
@@ -105,6 +105,9 @@
 
 void DefaultAborter(const char* abort_message);
 
+std::string GetDefaultTag();
+void SetDefaultTag(const std::string& tag);
+
 #ifdef __ANDROID__
 // We expose this even though it is the default because a user that wants to
 // override the default log buffer will have to construct this themselves.
diff --git a/base/logging.cpp b/base/logging.cpp
index 1f7bc2a..a31feef 100644
--- a/base/logging.cpp
+++ b/base/logging.cpp
@@ -139,9 +139,27 @@
   return aborter;
 }
 
-static std::string& ProgramInvocationName() {
-  static auto& programInvocationName = *new std::string(getprogname());
-  return programInvocationName;
+static std::recursive_mutex& TagLock() {
+  static auto& tag_lock = *new std::recursive_mutex();
+  return tag_lock;
+}
+static std::string* gDefaultTag;
+std::string GetDefaultTag() {
+  std::lock_guard<std::recursive_mutex> lock(TagLock());
+  if (gDefaultTag == nullptr) {
+    return "";
+  }
+  return *gDefaultTag;
+}
+void SetDefaultTag(const std::string& tag) {
+  std::lock_guard<std::recursive_mutex> lock(TagLock());
+  if (gDefaultTag != nullptr) {
+    delete gDefaultTag;
+    gDefaultTag = nullptr;
+  }
+  if (!tag.empty()) {
+    gDefaultTag = new std::string(tag);
+  }
 }
 
 static bool gInitialized = false;
@@ -269,8 +287,7 @@
   // Linux to recover this, but we don't have that luxury on the Mac/Windows,
   // and there are a couple of argv[0] variants that are commonly used.
   if (argv != nullptr) {
-    std::lock_guard<std::mutex> lock(LoggingLock());
-    ProgramInvocationName() = basename(argv[0]);
+    SetDefaultTag(basename(argv[0]));
   }
 
   const char* tags = getenv("ANDROID_LOG_TAGS");
@@ -448,8 +465,15 @@
 
 void LogMessage::LogLine(const char* file, unsigned int line, LogId id, LogSeverity severity,
                          const char* tag, const char* message) {
-  if (tag == nullptr) tag = ProgramInvocationName().c_str();
-  Logger()(id, severity, tag, file, line, message);
+  if (tag == nullptr) {
+    std::lock_guard<std::recursive_mutex> lock(TagLock());
+    if (gDefaultTag == nullptr) {
+      gDefaultTag = new std::string(getprogname());
+    }
+    Logger()(id, severity, gDefaultTag->c_str(), file, line, message);
+  } else {
+    Logger()(id, severity, tag, file, line, message);
+  }
 }
 
 void LogMessage::LogLine(const char* file, unsigned int line, LogId id, LogSeverity severity,
diff --git a/base/logging_test.cpp b/base/logging_test.cpp
index 6f05d9b..5f689fa 100644
--- a/base/logging_test.cpp
+++ b/base/logging_test.cpp
@@ -206,8 +206,8 @@
 }
 #endif
 
-static void CheckMessage(const CapturedStderr& cap,
-                         android::base::LogSeverity severity, const char* expected) {
+static void CheckMessage(const CapturedStderr& cap, android::base::LogSeverity severity,
+                         const char* expected, const char* expected_tag = nullptr) {
   std::string output;
   ASSERT_EQ(0, lseek(cap.fd(), 0, SEEK_SET));
   android::base::ReadFdToString(cap.fd(), &output);
@@ -217,9 +217,18 @@
   // many characters are in the log message.
   ASSERT_GT(output.length(), strlen(expected));
   ASSERT_NE(nullptr, strstr(output.c_str(), expected)) << output;
+  if (expected_tag != nullptr) {
+    ASSERT_NE(nullptr, strstr(output.c_str(), expected_tag)) << output;
+  }
 
 #if !defined(_WIN32)
-  std::regex message_regex(make_log_pattern(severity, expected));
+  std::string regex_str;
+  if (expected_tag != nullptr) {
+    regex_str.append(expected_tag);
+    regex_str.append(" ");
+  }
+  regex_str.append(make_log_pattern(severity, expected));
+  std::regex message_regex(regex_str);
   ASSERT_TRUE(std::regex_search(output, message_regex)) << output;
 #endif
 }
@@ -600,3 +609,17 @@
 __attribute__((constructor)) void TestLoggingInConstructor() {
   LOG(ERROR) << "foobar";
 }
+
+TEST(logging, SetDefaultTag) {
+  constexpr const char* expected_tag = "test_tag";
+  constexpr const char* expected_msg = "foobar";
+  CapturedStderr cap;
+  {
+    std::string old_default_tag = android::base::GetDefaultTag();
+    android::base::SetDefaultTag(expected_tag);
+    android::base::ScopedLogSeverity sls(android::base::LogSeverity::INFO);
+    LOG(INFO) << expected_msg;
+    android::base::SetDefaultTag(old_default_tag);
+  }
+  CheckMessage(cap, android::base::LogSeverity::INFO, expected_msg, expected_tag);
+}