Home | History | Annotate | Download | only in default
      1 /* Copyright 2015 The TensorFlow Authors. All Rights Reserved.
      2 
      3 Licensed under the Apache License, Version 2.0 (the "License");
      4 you may not use this file except in compliance with the License.
      5 You may obtain a copy of the License at
      6 
      7     http://www.apache.org/licenses/LICENSE-2.0
      8 
      9 Unless required by applicable law or agreed to in writing, software
     10 distributed under the License is distributed on an "AS IS" BASIS,
     11 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     12 See the License for the specific language governing permissions and
     13 limitations under the License.
     14 ==============================================================================*/
     15 
     16 #include "tensorflow/core/platform/default/logging.h"
     17 #include "tensorflow/core/platform/env_time.h"
     18 #include "tensorflow/core/platform/macros.h"
     19 
     20 #if defined(PLATFORM_POSIX_ANDROID)
     21 #include <android/log.h>
     22 #include <iostream>
     23 #include <sstream>
     24 #endif
     25 
     26 #include <stdlib.h>
     27 #include <time.h>
     28 
     29 namespace tensorflow {
     30 namespace internal {
     31 
     32 LogMessage::LogMessage(const char* fname, int line, int severity)
     33     : fname_(fname), line_(line), severity_(severity) {}
     34 
     35 #if defined(PLATFORM_POSIX_ANDROID)
     36 void LogMessage::GenerateLogMessage() {
     37   int android_log_level;
     38   switch (severity_) {
     39     case INFO:
     40       android_log_level = ANDROID_LOG_INFO;
     41       break;
     42     case WARNING:
     43       android_log_level = ANDROID_LOG_WARN;
     44       break;
     45     case ERROR:
     46       android_log_level = ANDROID_LOG_ERROR;
     47       break;
     48     case FATAL:
     49       android_log_level = ANDROID_LOG_FATAL;
     50       break;
     51     default:
     52       if (severity_ < INFO) {
     53         android_log_level = ANDROID_LOG_VERBOSE;
     54       } else {
     55         android_log_level = ANDROID_LOG_ERROR;
     56       }
     57       break;
     58   }
     59 
     60   std::stringstream ss;
     61   const char* const partial_name = strrchr(fname_, '/');
     62   ss << (partial_name != nullptr ? partial_name + 1 : fname_) << ":" << line_
     63      << " " << str();
     64   __android_log_write(android_log_level, "native", ss.str().c_str());
     65 
     66   // Also log to stderr (for standalone Android apps).
     67   std::cerr << "native : " << ss.str() << std::endl;
     68 
     69   // Android logging at level FATAL does not terminate execution, so abort()
     70   // is still required to stop the program.
     71   if (severity_ == FATAL) {
     72     abort();
     73   }
     74 }
     75 
     76 #else
     77 
     78 void LogMessage::GenerateLogMessage() {
     79   static EnvTime* env_time = tensorflow::EnvTime::Default();
     80   uint64 now_micros = env_time->NowMicros();
     81   time_t now_seconds = static_cast<time_t>(now_micros / 1000000);
     82   int32 micros_remainder = static_cast<int32>(now_micros % 1000000);
     83   const size_t time_buffer_size = 30;
     84   char time_buffer[time_buffer_size];
     85   strftime(time_buffer, time_buffer_size, "%Y-%m-%d %H:%M:%S",
     86            localtime(&now_seconds));
     87 
     88   // TODO(jeff,sanjay): Replace this with something that logs through the env.
     89   fprintf(stderr, "%s.%06d: %c %s:%d] %s\n", time_buffer, micros_remainder,
     90           "IWEF"[severity_], fname_, line_, str().c_str());
     91 }
     92 #endif
     93 
     94 namespace {
     95 
     96 // Parse log level (int64) from environment variable (char*)
     97 int64 LogLevelStrToInt(const char* tf_env_var_val) {
     98   if (tf_env_var_val == nullptr) {
     99     return 0;
    100   }
    101 
    102   // Ideally we would use env_var / safe_strto64, but it is
    103   // hard to use here without pulling in a lot of dependencies,
    104   // so we use std:istringstream instead
    105   string min_log_level(tf_env_var_val);
    106   std::istringstream ss(min_log_level);
    107   int64 level;
    108   if (!(ss >> level)) {
    109     // Invalid vlog level setting, set level to default (0)
    110     level = 0;
    111   }
    112 
    113   return level;
    114 }
    115 
    116 }  // namespace
    117 
    118 int64 MinLogLevelFromEnv() {
    119   const char* tf_env_var_val = getenv("TF_CPP_MIN_LOG_LEVEL");
    120   return LogLevelStrToInt(tf_env_var_val);
    121 }
    122 
    123 int64 MinVLogLevelFromEnv() {
    124   const char* tf_env_var_val = getenv("TF_CPP_MIN_VLOG_LEVEL");
    125   return LogLevelStrToInt(tf_env_var_val);
    126 }
    127 
    128 LogMessage::~LogMessage() {
    129   // Read the min log level once during the first call to logging.
    130   static int64 min_log_level = MinLogLevelFromEnv();
    131   if (TF_PREDICT_TRUE(severity_ >= min_log_level)) GenerateLogMessage();
    132 }
    133 
    134 int64 LogMessage::MinVLogLevel() {
    135   static int64 min_vlog_level = MinVLogLevelFromEnv();
    136   return min_vlog_level;
    137 }
    138 
    139 LogMessageFatal::LogMessageFatal(const char* file, int line)
    140     : LogMessage(file, line, FATAL) {}
    141 LogMessageFatal::~LogMessageFatal() {
    142   // abort() ensures we don't return (we promised we would not via
    143   // ATTRIBUTE_NORETURN).
    144   GenerateLogMessage();
    145   abort();
    146 }
    147 
    148 void LogString(const char* fname, int line, int severity,
    149                const string& message) {
    150   LogMessage(fname, line, severity) << message;
    151 }
    152 
    153 template <>
    154 void MakeCheckOpValueString(std::ostream* os, const char& v) {
    155   if (v >= 32 && v <= 126) {
    156     (*os) << "'" << v << "'";
    157   } else {
    158     (*os) << "char value " << static_cast<short>(v);
    159   }
    160 }
    161 
    162 template <>
    163 void MakeCheckOpValueString(std::ostream* os, const signed char& v) {
    164   if (v >= 32 && v <= 126) {
    165     (*os) << "'" << v << "'";
    166   } else {
    167     (*os) << "signed char value " << static_cast<short>(v);
    168   }
    169 }
    170 
    171 template <>
    172 void MakeCheckOpValueString(std::ostream* os, const unsigned char& v) {
    173   if (v >= 32 && v <= 126) {
    174     (*os) << "'" << v << "'";
    175   } else {
    176     (*os) << "unsigned char value " << static_cast<unsigned short>(v);
    177   }
    178 }
    179 
    180 #if LANG_CXX11
    181 template <>
    182 void MakeCheckOpValueString(std::ostream* os, const std::nullptr_t& p) {
    183   (*os) << "nullptr";
    184 }
    185 #endif
    186 
    187 CheckOpMessageBuilder::CheckOpMessageBuilder(const char* exprtext)
    188     : stream_(new std::ostringstream) {
    189   *stream_ << "Check failed: " << exprtext << " (";
    190 }
    191 
    192 CheckOpMessageBuilder::~CheckOpMessageBuilder() { delete stream_; }
    193 
    194 std::ostream* CheckOpMessageBuilder::ForVar2() {
    195   *stream_ << " vs. ";
    196   return stream_;
    197 }
    198 
    199 string* CheckOpMessageBuilder::NewString() {
    200   *stream_ << ")";
    201   return new string(stream_->str());
    202 }
    203 
    204 }  // namespace internal
    205 }  // namespace tensorflow
    206