Home | History | Annotate | Download | only in base
      1 /*
      2  * Copyright (C) 2015 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 "base/logging.h"
     18 
     19 #include <libgen.h>
     20 
     21 // For getprogname(3) or program_invocation_short_name.
     22 #if defined(__ANDROID__) || defined(__APPLE__)
     23 #include <stdlib.h>
     24 #elif defined(__GLIBC__)
     25 #include <errno.h>
     26 #endif
     27 
     28 #include <iostream>
     29 #include <limits>
     30 #include <mutex>
     31 #include <sstream>
     32 #include <string>
     33 #include <utility>
     34 #include <vector>
     35 
     36 #include "base/strings.h"
     37 #include "cutils/threads.h"
     38 
     39 // Headers for LogMessage::LogLine.
     40 #ifdef __ANDROID__
     41 #include <android/set_abort_message.h>
     42 #include "cutils/log.h"
     43 #else
     44 #include <sys/types.h>
     45 #include <unistd.h>
     46 #endif
     47 
     48 namespace android {
     49 namespace base {
     50 
     51 static std::mutex logging_lock;
     52 
     53 #ifdef __ANDROID__
     54 static LogFunction gLogger = LogdLogger();
     55 #else
     56 static LogFunction gLogger = StderrLogger;
     57 #endif
     58 
     59 static bool gInitialized = false;
     60 static LogSeverity gMinimumLogSeverity = INFO;
     61 static std::unique_ptr<std::string> gProgramInvocationName;
     62 
     63 #if defined(__GLIBC__)
     64 static const char* getprogname() {
     65   return program_invocation_short_name;
     66 }
     67 #endif
     68 
     69 static const char* ProgramInvocationName() {
     70   if (gProgramInvocationName == nullptr) {
     71     gProgramInvocationName.reset(new std::string(getprogname()));
     72   }
     73 
     74   return gProgramInvocationName->c_str();
     75 }
     76 
     77 void StderrLogger(LogId, LogSeverity severity, const char*, const char* file,
     78                   unsigned int line, const char* message) {
     79   static const char* log_characters = "VDIWEF";
     80   CHECK_EQ(strlen(log_characters), FATAL + 1U);
     81   char severity_char = log_characters[severity];
     82   fprintf(stderr, "%s %c %5d %5d %s:%u] %s\n", ProgramInvocationName(),
     83           severity_char, getpid(), gettid(), file, line, message);
     84 }
     85 
     86 
     87 #ifdef __ANDROID__
     88 LogdLogger::LogdLogger(LogId default_log_id) : default_log_id_(default_log_id) {
     89 }
     90 
     91 static const android_LogPriority kLogSeverityToAndroidLogPriority[] = {
     92     ANDROID_LOG_VERBOSE, ANDROID_LOG_DEBUG, ANDROID_LOG_INFO,
     93     ANDROID_LOG_WARN,    ANDROID_LOG_ERROR, ANDROID_LOG_FATAL,
     94 };
     95 static_assert(arraysize(kLogSeverityToAndroidLogPriority) == FATAL + 1,
     96               "Mismatch in size of kLogSeverityToAndroidLogPriority and values "
     97               "in LogSeverity");
     98 
     99 static const log_id kLogIdToAndroidLogId[] = {
    100     LOG_ID_MAX, LOG_ID_MAIN, LOG_ID_SYSTEM,
    101 };
    102 static_assert(arraysize(kLogIdToAndroidLogId) == SYSTEM + 1,
    103               "Mismatch in size of kLogIdToAndroidLogId and values in LogId");
    104 
    105 void LogdLogger::operator()(LogId id, LogSeverity severity, const char* tag,
    106                             const char* file, unsigned int line,
    107                             const char* message) {
    108   int priority = kLogSeverityToAndroidLogPriority[severity];
    109   if (id == DEFAULT) {
    110     id = default_log_id_;
    111   }
    112 
    113   log_id lg_id = kLogIdToAndroidLogId[id];
    114 
    115   if (priority == ANDROID_LOG_FATAL) {
    116     __android_log_buf_print(lg_id, priority, tag, "%s:%u] %s", file, line,
    117                             message);
    118   } else {
    119     __android_log_buf_print(lg_id, priority, tag, "%s", message);
    120   }
    121 }
    122 #endif
    123 
    124 void InitLogging(char* argv[], LogFunction&& logger) {
    125   SetLogger(std::forward<LogFunction>(logger));
    126   InitLogging(argv);
    127 }
    128 
    129 void InitLogging(char* argv[]) {
    130   if (gInitialized) {
    131     return;
    132   }
    133 
    134   gInitialized = true;
    135 
    136   // Stash the command line for later use. We can use /proc/self/cmdline on
    137   // Linux to recover this, but we don't have that luxury on the Mac, and there
    138   // are a couple of argv[0] variants that are commonly used.
    139   if (argv != nullptr) {
    140     gProgramInvocationName.reset(new std::string(basename(argv[0])));
    141   }
    142 
    143   const char* tags = getenv("ANDROID_LOG_TAGS");
    144   if (tags == nullptr) {
    145     return;
    146   }
    147 
    148   std::vector<std::string> specs = Split(tags, " ");
    149   for (size_t i = 0; i < specs.size(); ++i) {
    150     // "tag-pattern:[vdiwefs]"
    151     std::string spec(specs[i]);
    152     if (spec.size() == 3 && StartsWith(spec, "*:")) {
    153       switch (spec[2]) {
    154         case 'v':
    155           gMinimumLogSeverity = VERBOSE;
    156           continue;
    157         case 'd':
    158           gMinimumLogSeverity = DEBUG;
    159           continue;
    160         case 'i':
    161           gMinimumLogSeverity = INFO;
    162           continue;
    163         case 'w':
    164           gMinimumLogSeverity = WARNING;
    165           continue;
    166         case 'e':
    167           gMinimumLogSeverity = ERROR;
    168           continue;
    169         case 'f':
    170           gMinimumLogSeverity = FATAL;
    171           continue;
    172         // liblog will even suppress FATAL if you say 's' for silent, but that's
    173         // crazy!
    174         case 's':
    175           gMinimumLogSeverity = FATAL;
    176           continue;
    177       }
    178     }
    179     LOG(FATAL) << "unsupported '" << spec << "' in ANDROID_LOG_TAGS (" << tags
    180                << ")";
    181   }
    182 }
    183 
    184 void SetLogger(LogFunction&& logger) {
    185   std::lock_guard<std::mutex> lock(logging_lock);
    186   gLogger = std::move(logger);
    187 }
    188 
    189 // This indirection greatly reduces the stack impact of having lots of
    190 // checks/logging in a function.
    191 class LogMessageData {
    192  public:
    193   LogMessageData(const char* file, unsigned int line, LogId id,
    194                  LogSeverity severity, int error)
    195       : file_(file),
    196         line_number_(line),
    197         id_(id),
    198         severity_(severity),
    199         error_(error) {
    200     const char* last_slash = strrchr(file, '/');
    201     file = (last_slash == nullptr) ? file : last_slash + 1;
    202   }
    203 
    204   const char* GetFile() const {
    205     return file_;
    206   }
    207 
    208   unsigned int GetLineNumber() const {
    209     return line_number_;
    210   }
    211 
    212   LogSeverity GetSeverity() const {
    213     return severity_;
    214   }
    215 
    216   LogId GetId() const {
    217     return id_;
    218   }
    219 
    220   int GetError() const {
    221     return error_;
    222   }
    223 
    224   std::ostream& GetBuffer() {
    225     return buffer_;
    226   }
    227 
    228   std::string ToString() const {
    229     return buffer_.str();
    230   }
    231 
    232  private:
    233   std::ostringstream buffer_;
    234   const char* const file_;
    235   const unsigned int line_number_;
    236   const LogId id_;
    237   const LogSeverity severity_;
    238   const int error_;
    239 
    240   DISALLOW_COPY_AND_ASSIGN(LogMessageData);
    241 };
    242 
    243 LogMessage::LogMessage(const char* file, unsigned int line, LogId id,
    244                        LogSeverity severity, int error)
    245     : data_(new LogMessageData(file, line, id, severity, error)) {
    246 }
    247 
    248 LogMessage::~LogMessage() {
    249   if (data_->GetSeverity() < gMinimumLogSeverity) {
    250     return;  // No need to format something we're not going to output.
    251   }
    252 
    253   // Finish constructing the message.
    254   if (data_->GetError() != -1) {
    255     data_->GetBuffer() << ": " << strerror(data_->GetError());
    256   }
    257   std::string msg(data_->ToString());
    258 
    259   if (msg.find('\n') == std::string::npos) {
    260     LogLine(data_->GetFile(), data_->GetLineNumber(), data_->GetId(),
    261             data_->GetSeverity(), msg.c_str());
    262   } else {
    263     msg += '\n';
    264     size_t i = 0;
    265     while (i < msg.size()) {
    266       size_t nl = msg.find('\n', i);
    267       msg[nl] = '\0';
    268       LogLine(data_->GetFile(), data_->GetLineNumber(), data_->GetId(),
    269               data_->GetSeverity(), &msg[i]);
    270       i = nl + 1;
    271     }
    272   }
    273 
    274   // Abort if necessary.
    275   if (data_->GetSeverity() == FATAL) {
    276 #ifdef __ANDROID__
    277     android_set_abort_message(msg.c_str());
    278 #endif
    279     abort();
    280   }
    281 }
    282 
    283 std::ostream& LogMessage::stream() {
    284   return data_->GetBuffer();
    285 }
    286 
    287 void LogMessage::LogLine(const char* file, unsigned int line, LogId id,
    288                          LogSeverity severity, const char* message) {
    289   const char* tag = ProgramInvocationName();
    290   std::lock_guard<std::mutex> lock(logging_lock);
    291   gLogger(id, severity, tag, file, line, message);
    292 }
    293 
    294 ScopedLogSeverity::ScopedLogSeverity(LogSeverity level) {
    295   old_ = gMinimumLogSeverity;
    296   gMinimumLogSeverity = level;
    297 }
    298 
    299 ScopedLogSeverity::~ScopedLogSeverity() {
    300   gMinimumLogSeverity = old_;
    301 }
    302 
    303 }  // namespace base
    304 }  // namespace android
    305