Arduino自定义printf风格日志函数前缀格式异常问题求助
Arduino DebugSystem 日志格式修复:处理开头换行符问题
问题重现
当前DebugSystem的print方法会先输出日志前缀,再输出格式化后的消息。当用户传入的消息开头包含换行符(或其他空白/控制字符)时,会出现格式混乱:
调用代码:
debug.print(DEBUG_INFO,"Test message: %s\n","TEST"); debug.print(DEBUG_INFO,"\nTest message: %s\n","TEST");
实际输出:
[INFO] Test message: TEST [INFO] Test message: TEST
期望输出:
[INFO] Test message: TEST [INFO] Test message: TEST
解决方案
核心思路是先输出消息开头的所有空白/控制字符,再输出前缀和剩余的有效内容。这样既保留了用户想要的换行效果,又不会让前缀和有效内容分离。具体步骤:
- 先完成消息的格式化,得到完整的缓冲区内容
- 遍历缓冲区,提取开头所有的空白/控制字符(包括
\n、\r、\t、空格等),先输出这些字符 - 如果还有剩余的非空白内容,先输出对应级别的前缀,再输出剩余内容
- 如果消息全是空白字符,则只输出这些空白,不输出前缀
代码实现
修改DebugSystem::print方法,替换原有的逻辑(注意需要包含<ctype.h>头文件以使用isspace函数):
#include <ctype.h> void DebugSystem::print(byte level, const char *message, ...){ if( level > debugLevel || level == NO_DEBUG ){ return; } char buffer[PRINT_BUFFER_SIZE]; // 先完成消息格式化 va_list args; va_start(args, message); vsprintf(buffer, message, args); va_end(args); // 处理开头的空白/控制字符 char* ptr = buffer; // 输出所有开头的空白/控制字符 while (*ptr != '\0' && isspace((unsigned char)*ptr)) { Serial.print(*ptr); ptr++; } // 如果还有剩余内容,输出前缀+剩余内容 if (*ptr != '\0') { if (levelPrefix && level != NO_PREFIX) { const char* prefix = level == DEBUG_ERROR ? DEBUG_ERROR_PREFIX : level == DEBUG_WARN ? DEBUG_WARN_PREFIX : level == DEBUG_SUCCESS ? DEBUG_SUCCESS_PREFIX : DEBUG_INFO_PREFIX; Serial.print(prefix); } Serial.print(ptr); } }
说明
- 用
isspace函数覆盖所有常见的空白/控制字符,不止处理换行符,兼容更多开头格式场景 - 先格式化再处理,避免直接解析原格式字符串的复杂性
- 保留原有
levelPrefix和NO_PREFIX的控制逻辑,不破坏已有的功能
额外优化(可选)
如果需要支持多行消息中每行自动添加前缀,可以用以下逻辑,遍历整个缓冲区,遇到换行且后续还有内容时,自动在下一行开头补前缀:
#include <ctype.h> void DebugSystem::print(byte level, const char *message, ...){ if( level > debugLevel || level == NO_DEBUG ){ return; } char buffer[PRINT_BUFFER_SIZE]; va_list args; va_start(args, message); vsprintf(buffer, message, args); va_end(args); const char* prefix = nullptr; if (levelPrefix && level != NO_PREFIX) { prefix = level == DEBUG_ERROR ? DEBUG_ERROR_PREFIX : level == DEBUG_WARN ? DEBUG_WARN_PREFIX : level == DEBUG_SUCCESS ? DEBUG_SUCCESS_PREFIX : DEBUG_INFO_PREFIX; } char* ptr = buffer; bool needPrefix = true; while (*ptr != '\0') { if (needPrefix && prefix != nullptr) { Serial.print(prefix); needPrefix = false; } if (*ptr == '\n') { Serial.print(*ptr); needPrefix = true; // 下一行开头需要补前缀 } else { Serial.print(*ptr); } ptr++; } }
该版本输入"\nLine1\nLine2"会输出:
[INFO] Line1 [INFO] Line2
内容的提问来源于stack exchange,提问作者Dr.Random
相关产品推荐
相关产品推荐

