在学习trime同文输入法的时候需要打印日志。源代码中有很多DLOG() LOG()
宏,于是想着借助这些宏打印日志。
如:
DLOG(INFO) << "scanning " << dirs.size() << " temp directory for log files.";
找到这些宏所在的no_logging.h
文件中的相关代码。如下:
namespace rime
{
class VoidLogger
{
public:
VoidLogger() {}
// hack: an unnamed VoidLogger() cannot be used as an l-value
VoidLogger &stream() { return *this; }
template <class T>
VoidLogger &operator<<(const T &x) { return *this; }
};
// to avoid compiler warnings
class Voidify
{
public:
Voidify() {}
void operator&(VoidLogger &) {}
};
} // namespace rime
#define RIME_NO_LOG true ? (void)0 : rime::Voidify() & rime::VoidLogger().stream()
#define DLOG(severity) LOG(severity)
此时运行trime同文输入法时什么都不会输出。需要对重载操作法“<<”
和LOG()
进行一些改动。
/**
* operator 与&operator的区别:
* 简单来说就是operator 返回的是这个值,而&operator返回的是这个的地址(引用)。
* 主要的区别于用处就在于这个运算符的连用性,如果需要连用的话必须使用引用。
*/
template <class T>
VoidLogger &operator<<(const T &x)
{
__android_log_print(ANDROID_LOG_INFO, " BBB ", " %s", &x);
return *this;
}
// LOG改为
#define LOG(severity) rime::Voidify() & rime::VoidLogger().stream() <<__LINE__<< "行 "<< __FILE__ <<" "<< __FUNCTION__ <<"() "
这样一条LOG()
会输出至少6行,每遇到一次<<
就会重新换行,__FILE__
也是全路径输出,并且极度消耗资源和时间。这显然不是我们想要的,得让每一条LOG输出成一行才行。继续改动VoidLogger &operator<<(const T &x)
代码如下:
char fmt[550] = " ";
template <class T>
VoidLogger &operator<<(const T &x)
{
char *str = (char *)&x;
char *ret;
ret = strrchr(str, '/') ? strrchr(str, '/') + 1 : str;
strcat(fmt, ret);
return *this;
}
还需改Voidify
类中的重载运算符“&”
// 参数表示传入的是一个VoidLogger对象的引用
void operator&(VoidLogger &vl)
{
__android_log_print(ANDROID_LOG_INFO, " FF ", " %s", &vl.fmt);
}
再次运行,行号、文件、函数以及参数都会打印在一行内。效果如下:
2022-04-19 04:44:59.895 10853-10853/com.osfans.trime I/ FF: �行 setup.cc LoadModules() module_names: core
也许你已经发现了行号根本不对,是的问题就出在这。
template <class T>
VoidLogger &operator<<(const T &x)
{
__android_log_print(ANDROID_LOG_INFO, "BBBBBBBB", " %s", typeid(&x).name());
return *this;
}
当用typeid(&x).name()
输出时会出现一些未知的类型,如下:
2022-04-18 22:32:18.665 29439-29439/? I/BBBBBBBB: PKi
2022-04-18 22:32:18.665 29439-29439/? I/BBBBBBBB: PA5_Kc
2022-04-18 22:32:18.665 29439-29439/? I/BBBBBBBB: PA74_Kc
2022-04-18 22:32:18.665 29439-29439/? I/BBBBBBBB: PA2_Kc
2022-04-18 22:32:18.665 29439-29439/? I/BBBBBBBB: PA9_Kc
2022-04-18 22:32:18.665 29439-29439/? I/BBBBBBBB: PA4_Kc
2022-04-18 22:32:18.666 29439-29439/? I/BBBBBBBB: PA8_Kc
2022-04-18 22:32:18.666 29439-29439/? I/BBBBBBBB: PKNSt6__ndk112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEE
2022-04-18 22:32:18.666 29439-29439/? I/ FF: config_component.cc GetValue() �行 read: 1
__LINE__
的类型是int,在上面输出成了PKi。感觉非常莫名其妙!不过还有一种办法是把__LINE__
转换成string
类型因为C++中无法直接把int类型转换成char*
类型。改动宏LOG()
如下:
// LOG改为
#define STRRCHR_FILE_PATH(file_path) ((strrchr(file_path, '/') ? strrchr(file_path, '/') + 1 : file_path)[0])
#define LOG(severity) rime::Voidify() & rime::VoidLogger().stream() << (std::to_string(__LINE__))[0] << "行 " \
<< STRRCHR_FILE_PATH(__FILE__) << " " << __FUNCTION__ << "() "
输出如下:
2022-04-19 08:08:18.787 17532-17675/com.osfans.trime I/ FF: 622行 deployment_tasks.cc Run() SymlinkingPrebuiltDictionaries
虽然任然有乱码,不过勉强能用。