• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
LogMessage(const char * fname,int line,int severity)32 LogMessage::LogMessage(const char* fname, int line, int severity)
33     : fname_(fname), line_(line), severity_(severity) {}
34 
35 #if defined(PLATFORM_POSIX_ANDROID)
GenerateLogMessage()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 
GenerateLogMessage()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*)
LogLevelStrToInt(const char * tf_env_var_val)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 
MinLogLevelFromEnv()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 
MinVLogLevelFromEnv()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 
~LogMessage()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 
MinVLogLevel()134 int64 LogMessage::MinVLogLevel() {
135   static int64 min_vlog_level = MinVLogLevelFromEnv();
136   return min_vlog_level;
137 }
138 
LogMessageFatal(const char * file,int line)139 LogMessageFatal::LogMessageFatal(const char* file, int line)
140     : LogMessage(file, line, FATAL) {}
~LogMessageFatal()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 
LogString(const char * fname,int line,int severity,const string & message)148 void LogString(const char* fname, int line, int severity,
149                const string& message) {
150   LogMessage(fname, line, severity) << message;
151 }
152 
153 template <>
MakeCheckOpValueString(std::ostream * os,const char & v)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 <>
MakeCheckOpValueString(std::ostream * os,const signed char & v)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 <>
MakeCheckOpValueString(std::ostream * os,const unsigned char & v)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 <>
MakeCheckOpValueString(std::ostream * os,const std::nullptr_t & p)182 void MakeCheckOpValueString(std::ostream* os, const std::nullptr_t& p) {
183   (*os) << "nullptr";
184 }
185 #endif
186 
CheckOpMessageBuilder(const char * exprtext)187 CheckOpMessageBuilder::CheckOpMessageBuilder(const char* exprtext)
188     : stream_(new std::ostringstream) {
189   *stream_ << "Check failed: " << exprtext << " (";
190 }
191 
~CheckOpMessageBuilder()192 CheckOpMessageBuilder::~CheckOpMessageBuilder() { delete stream_; }
193 
ForVar2()194 std::ostream* CheckOpMessageBuilder::ForVar2() {
195   *stream_ << " vs. ";
196   return stream_;
197 }
198 
NewString()199 string* CheckOpMessageBuilder::NewString() {
200   *stream_ << ")";
201   return new string(stream_->str());
202 }
203 
204 }  // namespace internal
205 }  // namespace tensorflow
206