一、Paddle-Mobile 的日志开关
1.Paddle-Mobile 的日志开关在 cmakeList 中进行配置的。
通过 option 定义了日志的开关。如果 WITH_LOGGING 开启,将通过 add_definitions 定义 PADDLE_MOBILE_DEBUG 的宏。
option(WITH_LOGGING "print logging for debug" ON)
if(WITH_LOGGING)
message(STATUS "Debugging mode")
add_definitions(-DPADDLE_MOBILE_DEBUG)
else()
2.在编译时添加 ANDROID 宏定义
cmake .. \
-B"../build/release/${PLATFORM}" \
.....
-DANDROID=true \
-DNET="${NETS}" \
-D"${ARM_PLATFORM}"=true
也可以在 cmakelist 中添加
IF (op_android MATCHES ON)
SET(tag android)
ADD_DEFINITIONS(-DANDROID)
ENDIF()
二、避免引入不需要的库
1.根据宏定义来决定引入什么库
include <vector>
#ifdef PADDLE_MOBILE_DEBUG
#include <cstring>
#include <iostream>
#include <sstream>
#include <string>
#endif
2.如果还定义了 ANDROID,引入Android的日志文件
这样做的好处时可以避免引入不需要的库
#ifdef ANDROID
#include <android/log.h>
#endif
三、日志打印的核心
1.宏定义日志打印方法,简化代码量
#ifdef ANDROID
static const char *ANDROID_LOG_TAG =
"paddle_mobile LOG built on " __DATE__ " " __TIME__;
#define ANDROIDLOGI(...) \
__android_log_print(ANDROID_LOG_INFO, ANDROID_LOG_TAG, __VA_ARGS__); \
fprintf(stderr, "%s\n", __VA_ARGS__); \
fflush(stderr)
.....
#else
#define ANDROIDLOGI(...)
#define ANDROIDLOGW(...)
#define ANDROIDLOGD(...)
#define ANDROIDLOGE(...)
#endif
2.fprintf和fflush
fprintf函数根据输入的格式需求将日志输入到文件中,但是在 Paddle-Mobile 中,fprintf 传入的是 stderr 参数,这样会使 fprintf输出的内容到控制台的屏幕上。
**fflush 强制刷新缓冲区,可以让日志打印内容更快的输出到屏幕上
对 ToLog 对象是友好的,可以让ToLog对象轻松的访问到私有的 buffer_对象
3.日志打印对象
Paddle-Mobile定义了两个日志打印对象(结构体),Print和ToLog,Print是实际调用定义好的宏去打印日志。
1.std::cerr 输出错误类型的信息到控制台
2. ostringstream 可以更加安全的进行类型转换
3.重写了<< 运算符,可以更方便的使用
struct Print {
friend struct ToLog;
template <typename T>
Print &operator<<(T const &value) {
buffer_ << value;
return *this;
}
private:
void print(LogLevel level) {
// buffer_ << std::endl;
if (level == kLOG_ERROR) {
#ifdef ANDROID
ANDROIDLOGE(buffer_.str().c_str());
#else
std::cerr << buffer_.str() << std::endl;
#endif
} else {
#ifdef ANDROID
ANDROIDLOGI(buffer_.str().c_str());
#else
std::cout << buffer_.str() << std::endl;
#endif
}
}
std::ostringstream buffer_;
};
ostringstream的例子
ostringstream oss;//创建一个流
oss<<t;//把值传递如流中
result=oss.str();//获取转换后的字符转并将其写入result
3.ToLog对象
1.explicit防止隐士的赋值
2.重写了<<云算符,并且将输入定义成模板方法,因为这些输入最后是交给 print 对象,而 print 对象最终是交给 ostringsteam 对象,模板类型可以将各种输入更好的交给ostringstream对象以便打印
struct ToLog {
explicit ToLog(LogLevel level = kLOG_DEBUG, const std::string &info = "")
: level_(level) {
unsigned blanks =
(unsigned)(level > kLOG_DEBUG ? (level - kLOG_DEBUG) * 4 : 1);
printer_ << logs[level] << " " << info << ":" << std::string(blanks, ' ');
}
template <typename T>
ToLog &operator<<(T const &value) {
printer_ << value;
return *this;
}
~ToLog() { printer_.print(level_); }
private:
LogLevel level_;
Print printer_;
};
4.定义了规范的日志打印方式
这种方式会具体定位到某个文件的某一行
#define LOG(level) \
if (level > paddle_mobile::log_level) { \
} else \
paddle_mobile::ToLog( \
level, static_cast<const std::stringstream &>( \
std::stringstream() \
<< "[file: " \
<< (strrchr(__FILE__, '/') ? (strrchr(__FILE__, '/') + 1) \
: __FILE__) \
<< "] [line: " << __LINE__ << "] ") \
.str())
五、如果没有开启 Debug 开关
Paddle-Mobile 对象上面的所有方法都在没有定义 PADDLE_DEBUG宏时重新定义了一份,保证在没有定义开关时,不会出现任何问题
网友评论