Support ANDROID_LOG_TAGS.
This is the dalvik-compatible solution to the "I don't want non-FATAL logging
in my test output" problem.
Change-Id: I51b7b883ce89604af4661696e7c7b041a0ef8211
diff --git a/src/dex2oat.cc b/src/dex2oat.cc
index 6017ddb..47193e5 100644
--- a/src/dex2oat.cc
+++ b/src/dex2oat.cc
@@ -422,7 +422,7 @@
DISALLOW_IMPLICIT_CONSTRUCTORS(Dex2Oat);
};
-bool ParseInt(const char* in, int* out) {
+static bool ParseInt(const char* in, int* out) {
char* end;
int result = strtol(in, &end, 10);
if (in == end || *end != '\0') {
@@ -432,9 +432,9 @@
return true;
}
-void OpenDexFiles(const std::vector<const char*>& dex_filenames,
- const std::vector<const char*>& dex_locations,
- std::vector<const DexFile*>& dex_files) {
+static void OpenDexFiles(const std::vector<const char*>& dex_filenames,
+ const std::vector<const char*>& dex_locations,
+ std::vector<const DexFile*>& dex_files) {
for (size_t i = 0; i < dex_filenames.size(); i++) {
const char* dex_filename = dex_filenames[i];
const char* dex_location = dex_locations[i];
@@ -447,7 +447,9 @@
}
}
-int dex2oat(int argc, char** argv) {
+static int dex2oat(int argc, char** argv) {
+ InitLogging();
+
// Skip over argv[0].
argv++;
argc--;
diff --git a/src/logging.cc b/src/logging.cc
index b0f3055..7d176a2 100644
--- a/src/logging.cc
+++ b/src/logging.cc
@@ -24,12 +24,55 @@
LogVerbosity gLogVerbosity;
+static bool gInitLoggingCalled = false;
+static LogSeverity gMinimumLogSeverity = INFO;
+
static Mutex& GetLoggingLock() {
static Mutex logging_lock("LogMessage lock");
return logging_lock;
}
+// Configure logging based on ANDROID_LOG_TAGS environment variable.
+// We need to parse a string that looks like
+//
+// *:v jdwp:d dalvikvm:d dalvikvm-gc:i dalvikvmi:i
+//
+// The tag (or '*' for the global level) comes first, followed by a colon
+// and a letter indicating the minimum priority level we're expected to log.
+// This can be used to reveal or conceal logs with specific tags.
+void InitLogging() {
+ gInitLoggingCalled = true;
+ const char* tags = getenv("ANDROID_LOG_TAGS");
+ if (tags == NULL) {
+ return;
+ }
+
+ std::vector<std::string> specs;
+ Split(tags, ' ', specs);
+ for (size_t i = 0; i < specs.size(); ++i) {
+ // "tag-pattern:[vdiwefs]"
+ std::string spec(specs[i]);
+ if (spec.size() == 3 && StartsWith(spec, "*:")) {
+ switch (spec[2]) {
+ case 'v': gMinimumLogSeverity = VERBOSE; continue;
+ case 'd': gMinimumLogSeverity = DEBUG; continue;
+ case 'i': gMinimumLogSeverity = INFO; continue;
+ case 'w': gMinimumLogSeverity = WARNING; continue;
+ case 'e': gMinimumLogSeverity = ERROR; continue;
+ case 'f': gMinimumLogSeverity = FATAL; continue;
+ // liblog will even suppress FATAL if you say 's' for silent, but that's crazy!
+ case 's': gMinimumLogSeverity = FATAL; continue;
+ }
+ }
+ LOG(FATAL) << "unsupported '" << spec << "' in ANDROID_LOG_TAGS (" << tags << ")";
+ }
+}
+
LogMessage::~LogMessage() {
+ if (data_->severity < gMinimumLogSeverity) {
+ return; // No need to format something we're not going to output.
+ }
+
// Finish constructing the message.
if (data_->error != -1) {
data_->buffer << ": " << strerror(data_->error);
diff --git a/src/logging.h b/src/logging.h
index c1ea3ab..337f12e 100644
--- a/src/logging.h
+++ b/src/logging.h
@@ -262,18 +262,10 @@
bool startup;
bool third_party_jni; // Enabled with "-verbose:third-party-jni".
bool threads;
- std::ostream* logging_stream;
-
- void SetLoggingStream(std::ostream* new_logging_stream) {
- DCHECK(new_logging_stream->good());
- if (logging_stream != NULL) {
- delete logging_stream;
- }
- logging_stream = new_logging_stream;
- }
};
extern LogVerbosity gLogVerbosity;
+extern void InitLogging();
} // namespace art
diff --git a/src/logging_linux.cc b/src/logging_linux.cc
index 4e7c796..84a6843 100644
--- a/src/logging_linux.cc
+++ b/src/logging_linux.cc
@@ -34,11 +34,10 @@
}
void LogMessage::LogLine(const char* message) {
- std::ostream &out =
- (gLogVerbosity.logging_stream == NULL ? std::cerr : *gLogVerbosity.logging_stream);
- out << "VDIWEFF"[data_->severity] << ' '
- << StringPrintf("%5d %5d", getpid(), ::art::GetTid()) << ' '
- << data_->file << ':' << data_->line_number << "] " << message << std::endl;
+ std::ostream& os(std::cerr);
+ os << "VDIWEFF"[data_->severity] << ' '
+ << StringPrintf("%5d %5d", getpid(), ::art::GetTid()) << ' '
+ << data_->file << ':' << data_->line_number << "] " << message << std::endl;
}
} // namespace art
diff --git a/src/oatdump.cc b/src/oatdump.cc
index ea2e711..28126ae 100644
--- a/src/oatdump.cc
+++ b/src/oatdump.cc
@@ -1234,7 +1234,9 @@
DISALLOW_COPY_AND_ASSIGN(ImageDumper);
};
-int oatdump(int argc, char** argv) {
+static int oatdump(int argc, char** argv) {
+ InitLogging();
+
// Skip over argv[0].
argv++;
argc--;
diff --git a/src/oatexec.cc b/src/oatexec.cc
index 4f068db..d080560 100644
--- a/src/oatexec.cc
+++ b/src/oatexec.cc
@@ -105,7 +105,8 @@
// Parse arguments. Most of it just gets passed through to the runtime.
// The JNI spec defines a handful of standard arguments.
-int oatexec(int argc, char** argv) {
+static int oatexec(int argc, char** argv) {
+ InitLogging();
setvbuf(stdout, NULL, _IONBF, 0);
// Skip over argv[0].
diff --git a/src/runtime.cc b/src/runtime.cc
index 18d40f5..a94a93a 100644
--- a/src/runtime.cc
+++ b/src/runtime.cc
@@ -22,7 +22,6 @@
#include <cstdlib>
#include <limits>
#include <vector>
-#include <fstream>
#include "class_linker.h"
#include "class_loader.h"
@@ -432,15 +431,6 @@
gLogVerbosity.third_party_jni = true;
} else if (verbose_options[i] == "threads") {
gLogVerbosity.threads = true;
- } else if (StartsWith(verbose_options[i], "log-to=")) {
- std::string log_file_name(verbose_options[i].substr(strlen("log-to=")));
- std::ofstream* log_file = new std::ofstream(log_file_name.c_str());
- if (log_file->is_open() && log_file->good()) {
- gLogVerbosity.SetLoggingStream(log_file);
- } else {
- LOG(ERROR) << "Fail to open log file: \"" << log_file_name << "\","
- << " use default logging stream.";
- }
} else {
LOG(WARNING) << "Ignoring unknown -verbose option: " << verbose_options[i];
}