SRS的错误处理SrsCplxError—SRS源码分析
作者:罗上文,微信:Loken1,公众号:FFmpeg弦外之音
SrsCplxError 是 SRS 的错误处理类,可以发现,大部分函数,它的返回值都是 SrsCplxError 结构的,如下:

srs_error_t 是 SrsCplxError* 的别名。
SrsCplxError 类的使用是比较简单的,下面介绍一下类里面的字段与方法。
1,int code
code 是错误码,你可以用 srs_error_create() 函数来设置这个错误码。
2,SrsCplxError* wrapped
这个是嵌套 的 SrsCplxError 类,这样可以记录两层返回错误,如下:

第一层 SrsCplxError 是 fw->open() 函数返回的,记录的是 open() 内部哪里出了问题,而第二层 是 srs_error_wrap() 返回的,记录的是当前的函数哪里出了问题。
srs_error_wrap() 函数是一个宏来的,他里面用了 __FUNCTION__ 等特性来记录函数名,文件名,代码行数等信息,如下:
#define srs_error_wrap(err, fmt, ...) SrsCplxError::wrap(__FUNCTION__, __FILE__, __LINE__, err, fmt, ##__VA_ARGS__)
SrsCplxError* wrapped 不仅仅可以嵌套两层,可以套多层,只要遍历这个东西,就能很方便遍展示 出问题的函数调用链条。
SRS 的宏函数是小写的,我一开始看有点奇怪,不过 clion 有颜色区分,看着看着发现小写也挺舒服的。虽然习惯是用大写来命名宏函数。
3,std::string msg
这个 msg 是我们调用 srs_error_new() 的时候自己设置进去的,如下:
srs_error_new(ERROR_STREAM_CASTER_PORT, "invalid port=%d", port);
上面的 invalid port=%d 就会赋值给 msg 字段。
4,std::string func、std::string file、int line
func 记录是哪个函数发生的错误,file 记录的是哪个文件发生的错误,而 line 记录的是文件的哪一行发生的错误。
5,SrsContextId cid
你可以把 cid 理解成协程的 ID,每个协程都有自己独立的 ID,cid 是一个 8 字节长度的字符串。SRS 是每一个链接,就用一个协程来处理。因此记录这个 ID,可以方便排查问题。
关于 协程上下文ID 是如何生成,请阅读《SRS的协程ID-SrsContextId》
6,std::string desc
根据 SrsCplxError 的各个字段的信息,生成一个详细的描述,如下:
thread [51445][u923y9l1]: do_main() [./src/main/srs_main_server.cpp:248][errno=13]
thread [51445][u923y9l1]: run_directly_or_daemon() [./src/main/srs_main_server.cpp:496][errno=13]
thread [51445][u923y9l1]: run_in_thread_pool() [./src/main/srs_main_server.cpp:513][errno=13]
thread [51445][u923y9l1]: initialize() [./src/app/srs_app_threads.cpp:570][errno=13]
thread [51445][u923y9l1]: acquire_pid_file() [./src/app/srs_app_threads.cpp:594][errno=13](Permission denied)
上面是从 srs.log 文件里面提取出来的一段 desc
51445 是当前进程的ID,u923y9l1 是协程的ID,然后是发生错误的函数 的整个调用栈,以及对应的文件行数,这就是通过之前的 SrsCplxError* wrapped 嵌套类来实现的。
因为用 wrapped 形成了一个 链表,所以可以循环遍历出来 函数调用栈。
7,std::string _summary
根据 SrsCplxError 的各个字段的信息,生成一个简短的总结,如下:
TODO:后面再补充一个例子
上面已经介绍完了 SrsCplxError 类的字段,下面简单介绍一下他的一些函数。
SrsCplxError 类里面的方法都是 static 静态方法,所以你不用 new,可以直接调。

首先 creator() 负责 new 一个 SrsCplxError 对象出来,然后 wrap() 负责套上上一个错误,这样可以形成一个链表,方便遍历出来函数调用栈
这些函数其实相对比较简单,读者自行看代码 与 注释即可。
另外需要补充的是,SRS 创建了好几个宏函数给我们用,你不需要自己去传前面的 3 个参数,如下:

