1 /* 2 * Copyright (C) 2011 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 "logging.h" 18 19 #include "base/mutex.h" 20 #include "runtime.h" 21 #include "thread-inl.h" 22 #include "utils.h" 23 24 namespace art { 25 26 LogVerbosity gLogVerbosity; 27 28 std::vector<std::string> gVerboseMethods; 29 30 unsigned int gAborting = 0; 31 32 static LogSeverity gMinimumLogSeverity = INFO; 33 static std::unique_ptr<std::string> gCmdLine; 34 static std::unique_ptr<std::string> gProgramInvocationName; 35 static std::unique_ptr<std::string> gProgramInvocationShortName; 36 37 const char* GetCmdLine() { 38 return (gCmdLine.get() != nullptr) ? gCmdLine->c_str() : nullptr; 39 } 40 41 const char* ProgramInvocationName() { 42 return (gProgramInvocationName.get() != nullptr) ? gProgramInvocationName->c_str() : "art"; 43 } 44 45 const char* ProgramInvocationShortName() { 46 return (gProgramInvocationShortName.get() != nullptr) ? gProgramInvocationShortName->c_str() 47 : "art"; 48 } 49 50 // Configure logging based on ANDROID_LOG_TAGS environment variable. 51 // We need to parse a string that looks like 52 // 53 // *:v jdwp:d dalvikvm:d dalvikvm-gc:i dalvikvmi:i 54 // 55 // The tag (or '*' for the global level) comes first, followed by a colon 56 // and a letter indicating the minimum priority level we're expected to log. 57 // This can be used to reveal or conceal logs with specific tags. 58 void InitLogging(char* argv[]) { 59 if (gCmdLine.get() != nullptr) { 60 return; 61 } 62 // TODO: Move this to a more obvious InitART... 63 Locks::Init(); 64 65 // Stash the command line for later use. We can use /proc/self/cmdline on Linux to recover this, 66 // but we don't have that luxury on the Mac, and there are a couple of argv[0] variants that are 67 // commonly used. 68 if (argv != NULL) { 69 gCmdLine.reset(new std::string(argv[0])); 70 for (size_t i = 1; argv[i] != NULL; ++i) { 71 gCmdLine->append(" "); 72 gCmdLine->append(argv[i]); 73 } 74 gProgramInvocationName.reset(new std::string(argv[0])); 75 const char* last_slash = strrchr(argv[0], '/'); 76 gProgramInvocationShortName.reset(new std::string((last_slash != NULL) ? last_slash + 1 77 : argv[0])); 78 } else { 79 // TODO: fall back to /proc/self/cmdline when argv is NULL on Linux 80 gCmdLine.reset(new std::string("<unset>")); 81 } 82 const char* tags = getenv("ANDROID_LOG_TAGS"); 83 if (tags == NULL) { 84 return; 85 } 86 87 std::vector<std::string> specs; 88 Split(tags, ' ', specs); 89 for (size_t i = 0; i < specs.size(); ++i) { 90 // "tag-pattern:[vdiwefs]" 91 std::string spec(specs[i]); 92 if (spec.size() == 3 && StartsWith(spec, "*:")) { 93 switch (spec[2]) { 94 case 'v': 95 gMinimumLogSeverity = VERBOSE; 96 continue; 97 case 'd': 98 gMinimumLogSeverity = DEBUG; 99 continue; 100 case 'i': 101 gMinimumLogSeverity = INFO; 102 continue; 103 case 'w': 104 gMinimumLogSeverity = WARNING; 105 continue; 106 case 'e': 107 gMinimumLogSeverity = ERROR; 108 continue; 109 case 'f': 110 gMinimumLogSeverity = FATAL; 111 continue; 112 // liblog will even suppress FATAL if you say 's' for silent, but that's crazy! 113 case 's': 114 gMinimumLogSeverity = FATAL; 115 continue; 116 } 117 } 118 LOG(FATAL) << "unsupported '" << spec << "' in ANDROID_LOG_TAGS (" << tags << ")"; 119 } 120 } 121 122 LogMessageData::LogMessageData(const char* file, int line, LogSeverity severity, int error) 123 : file(file), 124 line_number(line), 125 severity(severity), 126 error(error) { 127 const char* last_slash = strrchr(file, '/'); 128 file = (last_slash == NULL) ? file : last_slash + 1; 129 } 130 131 LogMessage::~LogMessage() { 132 if (data_->severity < gMinimumLogSeverity) { 133 return; // No need to format something we're not going to output. 134 } 135 136 // Finish constructing the message. 137 if (data_->error != -1) { 138 data_->buffer << ": " << strerror(data_->error); 139 } 140 std::string msg(data_->buffer.str()); 141 142 // Do the actual logging with the lock held. 143 { 144 MutexLock mu(Thread::Current(), *Locks::logging_lock_); 145 if (msg.find('\n') == std::string::npos) { 146 LogLine(*data_, msg.c_str()); 147 } else { 148 msg += '\n'; 149 size_t i = 0; 150 while (i < msg.size()) { 151 size_t nl = msg.find('\n', i); 152 msg[nl] = '\0'; 153 LogLine(*data_, &msg[i]); 154 i = nl + 1; 155 } 156 } 157 } 158 159 // Abort if necessary. 160 if (data_->severity == FATAL) { 161 Runtime::Abort(); 162 } 163 } 164 165 } // namespace art 166