BIMHome v1.0.0
BIMHome接口文档说明
基于标签的日志辅助工具

简单的基于标签的日志和计时辅助宏和函数。

动机

BIMHome Base::Console() 能够输出到不同的目标,并且对不同类型日志有一些基本的启用/禁用控制。然而, 对于各种 FC 模块来说,却没有一种简单的方式来使用日志设施。这一组辅助宏和函数旨在提供一个统一的日志(和计时) 该接口主要为 C++ 代码设计。Python 代码也可以利用日志级别控制接口获得一些好处。开发者现在可以在源代码中永久激活他们的日志代码, 而不会影响性能,并且可以使用 Python 控制台动态地开启/关闭日志,用于调试目的,即使在发布构建中也是如此。

示例用法

提供了一组宏来简化基于标签的日志使用。所有宏都定义在 <Base/Console.h> 中。在你的 C++ 源代码开头, 你需要使用以下代码初始化你选择的标签的日志级别,

#define FC_LOG_LEVEL_INIT(_tag,...)
Definition Console.h:289

在多个文件中使用相同的标签进行日志级别控制是有意义的。如果你想要在同一个源文件中使用多个标签,请查看 自定义部分。

预定义的日志级别为,

#define FC_LOGLEVEL_ERR 0
#define FC_LOGLEVEL_WARN 1
#define FC_LOGLEVEL_MSG 2
#define FC_LOGLEVEL_LOG 3
#define FC_LOGLEVEL_TRACE 4

日志级别整数值越大,优先级越低。还有一个特殊的日志级别,

#define FC_LOGLEVEL_DEFAULT -1

实际上,任何负的日志级别行为都是一样的,这是为了那些用户尚未配置的标签。实际应用的日志级别由 Base::Console().SetDefaultLogLevel() 控制。 Python 开发者/最终用户可以通过调用以下代码配置默认日志级别:

BIMHome.setLogLevel('Default',level)
BIMHome.setLogLevel('DebugDefault',level)

其中 level 是一个字符串,值为 Error, Warning, Message, Log, Trace 或一个整数值。默认情况下,在发布构建中,默认日志级别是 FC_LOGLEVEL_MSG, 在调试构建中是 FC_LOGLEVEL_LOG。

Python 代码可以调用 BIMHome.setLogLevel(tag,level) 来配置任何其他标签的日志级别,以及 BIMHome.getLogLevel(tag),它只输出整数日志级别。

你可以通过向 FC_LOG_LEVEL_INIT() 传递额外的参数来微调日志的输出方式。所有额外的参数都是布尔值,如下所示,连同它们的默认值。

FC_LOG_LEVEL_INIT(tag, print_tag=true, print_src=0,
print_time=false, add_eol=true, refresh=false)

你也可以通过在实际日志输出宏之前更改这些变量来动态修改日志样式。更多详情请查看 自定义部分。

FC_LOG_INSTANCE.refresh = true; // 每次日志打印时刷新时间,默认为 false。
// 打印文件和行号,默认为 0,如果设置为 2,则打印当前调用帧的 Python 源代码。
FC_LOG_INSTANCE.print_src = 1;
FC_LOG_INSTANCE.print_tag = false; // 不打印标签,默认为 true
FC_LOG_INSTANCE.add_eol = false; // 不添加换行符
FC_LOG_INSTANCE.refresh = true; // 每次日志后刷新 GUI
#define FC_LOG_INSTANCE
Definition Console.h:286

注意使用 'refresh' 选项。其当前实现调用了 QCoreApplication::sendPostedEvent(),这可能会导致一些意外行为, 特别是在析构函数中调用时。

实际的日志宏是

FC_ERR(msg)
FC_WARN(msg)
FC_MSG(msg)
FC_LOG(msg)
#define FC_WARN(_msg)
Definition Console.h:306
#define FC_ERR(_msg)
Definition Console.h:307
#define FC_LOG(_msg)
Definition Console.h:308
#define FC_MSG(_msg)
Definition Console.h:305
#define FC_TRACE(_msg)
Definition Console.h:309

日志宏对应于现有的 Base::Console() 输出函数,FC_TRACE 使用 Base::Console().Log(),与 FC_LOG 相同。这些宏会检查在 FC_LOG_LEVEL_INIT 中定义的日志级别, 以决定是否打印日志。msg 应该是一个 C++ 流式表达式。默认情况下,会自动追加换行符。

FC_ERR("error: " << code << ". exiting")

计时辅助工具

这一组宏用于帮助 C++ 代码计时耗时的操作。 示例:

void operation() {
// 执行操作
FC_TIME_LOG(t,"操作完成。");
}
#define FC_TIME_INIT(_t)
Definition Console.h:327
#define FC_TIME_LOG(_t, _msg)
Definition Console.h:342

这将在控制台输出类似以下内容:

操作完成。时间:1.12秒

每次调用 FC_TIME_LOG 时,它都会计算此次调用与上一次 FC_TIME_LOGFC_TIME_INIT 之间的时长。 时间变量 t 将更新为当前时间。你也可以使用 FC_TIME_MSG, FC_TIME_TRACE,类似于 FC_MSG 和 FC_TRACE

要分阶段计时操作,

void operation() {
// 执行阶段 1
FC_TIME_LOG(t1,"阶段1");
// 执行阶段 2
FC_TIME_LOG(t1,"阶段2");
// 执行其他操作
FC_TIME_LOG(t,"总计");
}
#define FC_TIME_INIT2(_t1, _t2)
Definition Console.h:328

将输出类似以下内容:

阶段1 时间:1.2秒
阶段2 时间:2.3秒
总计时间:4.0秒

要在多个函数中计时操作,

class Timing {
Timing() {
}
};
void operation1(Timing &timing) {
for(...) {
// 执行步骤 1
FC_DURATION_PLUS(timing.d1_1,t1);
// 执行步骤 2
FC_DURATION_PLUS(timing.d1_2,t1);
}
// 执行其他操作
FC_DURATION_PLUS(timing.d1, t);
}
void operation2(Timing &timing) {
// 执行操作
FC_DURATION_PLUS(timing.d2, t);
}
void operation() {
Timing timing;
for(...) {
operation1(timing);
// 执行其他操作
operation2(timing);
}
FC_DURATION_LOG(timing.d1_1,"操作 1 步骤 1");
FC_DURATION_LOG(timing.d1_2,"操作 1 步骤 2");
FC_DURATION_LOG(timing.d1,"操作 1");
FC_DURATION_LOG(timing.d2,"操作 2");
FC_TIME_LOG(t,"操作总计");
}
#define FC_DURATION_LOG(_d, _msg)
Definition Console.h:335
#define FC_DURATION_PLUS(_d, _t)
Definition Console.h:357
#define FC_DURATION_INIT(_d)
Definition Console.h:349
#define FC_DURATION_DECLARE(_d)
Definition Console.h:345

你也可以像往常一样使用 FC_DURATION_MSG, FC_DURATION_TRACE

如果你只使用这里提供的宏来进行计时,那么可以通过在包含 App/Console.h 之前定义 FC_LOG_NO_TIMING 来将整个计时代码编译出去。

自定义

大部分日志设施都是通过宏暴露的。本节简要介绍它们在幕后是如何实现的,以防你想要进行自定义。新增了一个函数 GetLogLevel(tag) 到 Base::Console() 以便 C++ 开发者查询任意字符串标签的日志级别。该函数返回一个指向整数的指针,该整数表示日志级别。Python 开发者或最终用户可以使用