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