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 个参数,如下: