luat_lib_log.c 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256
  1. /*
  2. @module log
  3. @summary 日志库
  4. @version 1.0
  5. @date 2020.03.30
  6. @tag LUAT_CONF_BSP
  7. */
  8. #include "luat_base.h"
  9. #include "luat_sys.h"
  10. #include "luat_msgbus.h"
  11. #include "ldebug.h"
  12. #define LUAT_LOG_TAG "log"
  13. #include "luat_log.h"
  14. typedef struct luat_log_conf
  15. {
  16. uint8_t style;
  17. }luat_log_conf_t;
  18. #define LOG_STYLE_NORMAL 0
  19. #define LOG_STYLE_DEBUG_INFO 1
  20. #define LOG_STYLE_FULL 2
  21. static luat_log_conf_t lconf = {
  22. .style=0
  23. };
  24. static int add_debug_info(lua_State *L, uint8_t pos, const char* LEVEL) {
  25. lua_Debug ar;
  26. // int arg;
  27. // int d = 0;
  28. // // 查找当前stack的深度
  29. // while (lua_getstack(L, d, &ar) != 0) {
  30. // d++;
  31. // }
  32. // // 防御一下, 不太可能直接d==0都失败
  33. // if (d == 0)
  34. // return 0;
  35. // 获取真正的stack位置信息
  36. if (!lua_getstack(L, 1, &ar))
  37. return 0;
  38. // S包含源码, l包含当前行号
  39. if (0 == lua_getinfo(L, "Sl", &ar))
  40. return 0;
  41. // 没有调试信息就跳过了
  42. if (ar.source == NULL)
  43. return 0;
  44. int line = ar.currentline > 64*1024 ? 0 : ar.currentline;
  45. // 推入文件名和行号, 注意: 源码路径的第一个字符是标识,需要跳过
  46. if (LEVEL)
  47. lua_pushfstring(L, "%s/%s:%d", LEVEL, ar.source + 1, line);
  48. else
  49. lua_pushfstring(L, "%s:%d", ar.source + 1, line);
  50. if (lua_gettop(L) > pos)
  51. lua_insert(L, pos);
  52. return 1;
  53. }
  54. /*
  55. 设置日志级别
  56. @api log.setLevel(level)
  57. @string level 日志级别,可用字符串或数值, 字符串为(SILENT,DEBUG,INFO,WARN,ERROR,FATAL), 数值为(0,1,2,3,4,5)
  58. @return nil 无返回值
  59. @usage
  60. -- 设置日志级别为INFO
  61. log.setLevel("INFO")
  62. */
  63. static int l_log_set_level(lua_State *L) {
  64. int LOG_LEVEL = 0;
  65. if (lua_isinteger(L, 1)) {
  66. LOG_LEVEL = lua_tointeger(L, 1);
  67. }
  68. else if (lua_isstring(L, 1)) {
  69. const char* lv = lua_tostring(L, 1);
  70. if (strcmp("SILENT", lv) == 0) {
  71. LOG_LEVEL = LUAT_LOG_CLOSE;
  72. }
  73. else if (strcmp("DEBUG", lv) == 0) {
  74. LOG_LEVEL = LUAT_LOG_DEBUG;
  75. }
  76. else if (strcmp("INFO", lv) == 0) {
  77. LOG_LEVEL = LUAT_LOG_INFO;
  78. }
  79. else if (strcmp("WARN", lv) == 0) {
  80. LOG_LEVEL = LUAT_LOG_WARN;
  81. }
  82. else if (strcmp("ERROR", lv) == 0) {
  83. LOG_LEVEL = LUAT_LOG_ERROR;
  84. }
  85. }
  86. if (LOG_LEVEL == 0) {
  87. LOG_LEVEL = LUAT_LOG_CLOSE;
  88. }
  89. luat_log_set_level(LOG_LEVEL);
  90. return 0;
  91. }
  92. /*
  93. 设置日志风格
  94. @api log.style(val)
  95. @int 日志风格,默认为0, 不传就是获取当前值
  96. @return int 当前的日志风格
  97. @usage
  98. -- 以 log.info("ABC", "DEF", 123) 为例, 假设该代码位于main.lua的12行
  99. -- 默认日志0
  100. -- I/user.ABC DEF 123
  101. -- 调试风格1, 添加额外的调试信息
  102. -- I/main.lua:12 ABC DEF 123
  103. -- 调试风格2, 添加额外的调试信息, 位置有所区别
  104. -- I/user.ABC main.lua:12 DEF 123
  105. log.setLevel("DEBUG", 0) -- 默认风格0
  106. log.setLevel("DEBUG", 1) -- 调试风格1
  107. log.setLevel("DEBUG", 2) -- 调试风格2
  108. */
  109. static int l_log_style(lua_State *L) {
  110. if (lua_isinteger(L, 1))
  111. lconf.style = luaL_checkinteger(L, 1);
  112. lua_pushinteger(L, lconf.style);
  113. return 1;
  114. }
  115. /*
  116. 获取日志级别
  117. @api log.getLevel()
  118. @return int 日志级别对应0,1,2,3,4,5
  119. @usage
  120. -- 得到日志级别
  121. log.getLevel()
  122. */
  123. int l_log_get_level(lua_State *L) {
  124. lua_pushinteger(L, luat_log_get_level());
  125. return 1;
  126. }
  127. static int l_log_2_log(lua_State *L, const char* LEVEL) {
  128. // 是不是什么都不传呀?
  129. int argc = lua_gettop(L);
  130. if (argc < 1) {
  131. // 最起码传1个参数
  132. return 0;
  133. }
  134. if (lconf.style == LOG_STYLE_NORMAL) {
  135. lua_pushfstring(L, "%s/user.%s", LEVEL, lua_tostring(L, 1));
  136. lua_remove(L, 1); // remove tag
  137. lua_insert(L, 1);
  138. }
  139. else if (lconf.style == LOG_STYLE_DEBUG_INFO) {
  140. add_debug_info(L, 1, LEVEL);
  141. }
  142. else if (lconf.style == LOG_STYLE_FULL) {
  143. lua_pushfstring(L, "%s/user.%s", LEVEL, lua_tostring(L, 1));
  144. lua_remove(L, 1); // remove tag
  145. lua_insert(L, 1);
  146. add_debug_info(L, 2, NULL);
  147. }
  148. lua_getglobal(L, "print");
  149. lua_insert(L, 1);
  150. lua_call(L, lua_gettop(L) - 1, 0);
  151. return 0;
  152. }
  153. /*
  154. 输出日志,级别debug
  155. @api log.debug(tag, val, val2, val3, ...)
  156. @string tag 日志标识,必须是字符串
  157. @... 需打印的参数
  158. @return nil 无返回值
  159. @usage
  160. -- 日志输出 D/onenet connect ok
  161. log.debug("onenet", "connect ok")
  162. */
  163. static int l_log_debug(lua_State *L) {
  164. if (luat_log_get_level() > LUAT_LOG_DEBUG) return 0;
  165. return l_log_2_log(L, "D");
  166. }
  167. /*
  168. 输出日志,级别info
  169. @api log.info(tag, val, val2, val3, ...)
  170. @string tag 日志标识,必须是字符串
  171. @... 需打印的参数
  172. @return nil 无返回值
  173. @usage
  174. -- 日志输出 I/onenet connect ok
  175. log.info("onenet", "connect ok")
  176. */
  177. static int l_log_info(lua_State *L) {
  178. if (luat_log_get_level() > LUAT_LOG_INFO) return 0;
  179. return l_log_2_log(L, "I");
  180. }
  181. /*
  182. 输出日志,级别warn
  183. @api log.warn(tag, val, val2, val3, ...)
  184. @string tag 日志标识,必须是字符串
  185. @... 需打印的参数
  186. @return nil 无返回值
  187. @usage
  188. -- 日志输出 W/onenet connect ok
  189. log.warn("onenet", "connect ok")
  190. */
  191. static int l_log_warn(lua_State *L) {
  192. if (luat_log_get_level() > LUAT_LOG_WARN) return 0;
  193. return l_log_2_log(L, "W");
  194. }
  195. /*
  196. 输出日志,级别error
  197. @api log.error(tag, val, val2, val3, ...)
  198. @string tag 日志标识,必须是字符串
  199. @... 需打印的参数
  200. @return nil 无返回值
  201. @usage
  202. -- 日志输出 E/onenet connect ok
  203. log.error("onenet", "connect ok")
  204. */
  205. static int l_log_error(lua_State *L) {
  206. if (luat_log_get_level() > LUAT_LOG_ERROR) return 0;
  207. return l_log_2_log(L, "E");
  208. }
  209. #include "rotable2.h"
  210. static const rotable_Reg_t reg_log[] =
  211. {
  212. { "debug" , ROREG_FUNC(l_log_debug)},
  213. { "info" , ROREG_FUNC(l_log_info)},
  214. { "warn" , ROREG_FUNC(l_log_warn)},
  215. { "error" , ROREG_FUNC(l_log_error)},
  216. { "fatal" , ROREG_FUNC(l_log_error)}, // 以error对待
  217. { "setLevel" , ROREG_FUNC(l_log_set_level)},
  218. { "getLevel" , ROREG_FUNC(l_log_get_level)},
  219. { "style", ROREG_FUNC(l_log_style)},
  220. //{ "_log" , ROREG_FUNC(l_log_2_log)},
  221. //@const LOG_SILENT number 无日志模式
  222. { "LOG_SILENT", ROREG_INT(LUAT_LOG_CLOSE)},
  223. //@const LOG_DEBUG number debug日志模式
  224. { "LOG_DEBUG", ROREG_INT(LUAT_LOG_DEBUG)},
  225. //@const LOG_INFO number info日志模式
  226. { "LOG_INFO", ROREG_INT(LUAT_LOG_INFO)},
  227. //@const LOG_WARN number warning日志模式
  228. { "LOG_WARN", ROREG_INT(LUAT_LOG_WARN)},
  229. //@const LOG_ERROR number error日志模式
  230. { "LOG_ERROR", ROREG_INT(LUAT_LOG_ERROR)},
  231. { NULL, ROREG_INT(0) }
  232. };
  233. LUAMOD_API int luaopen_log( lua_State *L ) {
  234. luat_newlib2(L, reg_log);
  235. return 1;
  236. }