SQLite 可以配置为在发生异常时调用一个回调函数,该函数包含错误代码和简短的错误消息。这种机制对于跟踪很少发生且在现场发生的模糊问题非常有帮助。鼓励应用程序开发人员在其产品中利用 SQLite 的错误日志记录功能,因为它非常节省 CPU 和内存,但可以极大地帮助调试。
每个进程只能有一个错误日志回调。错误日志回调是在启动时使用类似于以下内容的 C 代码注册的
sqlite3_config(SQLITE_CONFIG_LOG, errorLogCallback, pData);
错误日志回调函数可能看起来像这样
void errorLogCallback(void *pArg, int iErrCode, const char *zMsg){ fprintf(stderr, "(%d) %s\n", iErrCode, zMsg); }
上面的示例说明了错误日志回调的签名。但是,在嵌入式应用程序中,通常不会在 stderr 上打印消息。相反,可能会将消息存储在一个预分配的循环缓冲区中,以便在调试期间需要诊断信息时可以访问它们。或者,消息可以发送到Syslog。无论如何,需要将消息存储在开发人员可以访问的地方,而不是显示给最终用户。
不要误解:从技术上讲,将错误日志消息显示给最终用户没有任何问题。这些消息不包含必须防止未经授权查看的敏感或私人信息。相反,这些消息本质上是技术性的,对于典型的最终用户来说没有用处或意义。来自错误日志的消息旨在供数据库专家使用。相应地显示它们。
sqlite3_config(SQLITE_CONFIG_LOG,...) 接口的第三个参数(上面示例中的“pData”参数)是指向任意数据的指针。SQLite 将此指针传递给错误日志回调的第一个参数。如果需要,可以使用该指针传递特定于应用程序的设置或状态信息。或者它可以只是一个空指针,回调会忽略它。
错误日志回调的第二个参数是整数扩展错误代码。错误日志的第三个参数是错误消息的文本。错误消息文本存储在调用函数中的固定长度堆栈缓冲区中,因此仅在错误日志回调函数的持续时间内有效。如果需要保留消息,则错误日志应将此消息复制到持久存储中。
错误日志回调应像信号处理程序一样对待。应用程序应保存或以其他方式处理错误,然后尽快返回。不应该直接或间接地从错误日志调用其他 SQLite API。通过错误日志回调,SQLite不是可重入的。特别是,当内存分配失败时会调用错误日志回调,因此通常不建议尝试在错误日志内部分配内存。甚至不要考虑尝试将错误消息存储在另一个 SQLite 数据库中。
如果需要,应用程序可以使用sqlite3_log(E,F,..) API 将新消息发送到日志,但不建议这样做。 sqlite3_log() 接口仅供扩展使用,不供应用程序使用。
可能发送到错误日志的错误消息及其确切格式可能会在不同版本之间发生变化。因此,应用程序不应依赖任何特定的错误消息文本格式或错误代码。事情不会反复无常地改变,但它们有时确实会改变。
以下是可能出现在错误日志回调中的一些消息类型。
无论何时编译 SQL 语句(使用sqlite3_prepare_v2() 或其同类)或运行 SQL 语句(使用sqlite3_step())发生错误,都会记录该错误。
当发生需要重新解析和重新准备预准备语句的模式更改时,该事件将使用错误代码 SQLITE_SCHEMA 记录。重新解析和重新准备通常是自动的(假设已使用sqlite3_prepare_v2() 最初准备了语句,这是推荐的做法),因此这些日志记录事件通常是知道重新准备正在进行的唯一方法。
每当数据库必须恢复,因为之前的写入器崩溃且未完成其事务时,都会记录 SQLITE_NOTICE 消息。在恢复回滚日志时,错误代码为 SQLITE_NOTICE_RECOVER_ROLLBACK,在恢复预写日志时,错误代码为 SQLITE_NOTICE_RECOVER_WAL。
当数据库文件以可能导致数据库损坏的方式重命名或别名时,会记录 SQLITE_WARNING 消息。(有关其他信息,请参阅1 和2。)
内存不足 (OOM) 错误条件会生成错误日志事件,错误代码为 SQLITE_NOMEM,并且消息说明失败分配请求了多少字节的内存。
操作系统接口中的 I/O 错误会生成错误日志事件。这些事件的消息给出错误源代码中的行号,以及在有对应文件时与该事件关联的文件名。
检测到数据库损坏时,会调用 SQLITE_CORRUPT 错误日志回调。与 I/O 错误一样,错误消息文本包含最初检测到错误的原始源代码中的行号。
在 SQLITE_MISUSE 错误上会调用错误日志回调。这有助于在应用程序代码中不一致地检查返回值时检测应用程序设计问题。
SQLite 努力保持错误日志流量较低,并且仅在确实存在问题时才将消息发送到错误日志。应用程序可以通过故意忽略他们不关心的某些类别的错误消息来进一步剔除错误消息流量。例如,频繁更改数据库模式的应用程序可能希望忽略所有 SQLITE_SCHEMA 错误。
强烈建议使用错误日志回调。错误日志提供的调试信息已被证明在跟踪应用程序进入现场后发生的模糊问题方面非常有用。错误日志回调还被证明有助于捕获应用程序由于 API 返回代码检查不一致而错过的偶尔错误。鼓励开发人员在开发周期的早期实现错误日志回调,以便快速发现意外行为,并在部署过程中保持错误日志回调处于打开状态。如果错误日志从未发现问题,则不会造成任何损害。但是,未能设置适当的错误日志可能会在以后影响诊断功能。