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