log.cpp 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336
  1. #include "precompile.h"
  2. #include "SpBase.h"
  3. #include "app.h"
  4. #include "sp_log.h"
  5. #include "sp_dbg_export.h"
  6. #include "sp_svc.h"
  7. #include "sp_cfg.h"
  8. #include "sp_env.h"
  9. #include "fileutil.h"
  10. #include "strutil.h"
  11. #ifdef _WIN32
  12. #include "SpShellConsole.h"
  13. #endif //_WIN32
  14. #define MAX_LOGFILE_SIZE (1<<20)
  15. typedef struct log_t {
  16. SYSTEMTIME tm_start;
  17. FILE *fp;
  18. int file_seq;// non-zero when file is already exist
  19. int last_error;
  20. sp_log_daemon_t *log_daemon;
  21. }log_t;
  22. static const char *str_types[] = {
  23. "Nil",
  24. "Evt",
  25. "Wrn",
  26. "Err",
  27. "Dbg",
  28. };
  29. static const char *str_severity[] = {
  30. "Nil",
  31. "low",
  32. "mid",
  33. "hgh",
  34. };
  35. static BOOL __log_need_change(log_t *log, LPSYSTEMTIME now)
  36. {
  37. assert(now);
  38. /* if error occurs, may be Hard Disk broken or space is run out. so no need to change file */
  39. if (log->last_error)
  40. return FALSE;
  41. /* fp currently is null, when system start */
  42. if (!log->fp)
  43. return TRUE;
  44. /* a new day come */
  45. if (log->tm_start.wYear != now->wYear ||
  46. log->tm_start.wMonth != now->wMonth ||
  47. log->tm_start.wDay != now->wDay)
  48. return TRUE;
  49. /* file size has exceed MAX_LOGFILE_SIZE */
  50. if (ftell(log->fp) > MAX_LOGFILE_SIZE) {
  51. return TRUE;
  52. }
  53. /* 10 minutes pass */
  54. {
  55. int diff = (now->wHour - log->tm_start.wHour) * 3600;
  56. diff += (now->wMinute - log->tm_start.wMinute) * 60;
  57. diff += (now->wSecond - log->tm_start.wSecond);
  58. if (diff >= 600) {
  59. return TRUE;
  60. }
  61. }
  62. return FALSE;
  63. }
  64. static const char *get_temp_path(char *buf, LPSYSTEMTIME now, int seq)
  65. {
  66. sp_env_t *env = sp_get_env();
  67. sp_cfg_t *cfg = env->cfg;
  68. sp_cfg_root_ini_t *root_cfg = cfg->root_ini;
  69. const char *dir = root_cfg->ref_syslog_path;
  70. if (seq) {
  71. sprintf(buf, "%s" SPLIT_SLASH_STR "%08X_%02d-%02d-%02d_%02d-%02d-%02d(%03d)", dir,
  72. cfg->install_ini->current_startup_time,
  73. now->wYear, now->wMonth, now->wDay,
  74. now->wHour, now->wMinute, now->wSecond, seq%1000);
  75. } else {
  76. sprintf(buf, "%s" SPLIT_SLASH_STR "%08X_%02d-%02d-%02d_%02d-%02d-%02d", dir,
  77. cfg->install_ini->current_startup_time,
  78. now->wYear, now->wMonth, now->wDay,
  79. now->wHour, now->wMinute, now->wSecond);
  80. }
  81. return buf;
  82. }
  83. static const char *new_tmp_path(char *buf, LPSYSTEMTIME now, int *file_seq)
  84. {
  85. int seq = 0;
  86. int i;
  87. const int max_tries = 1000;
  88. for (i = 0; i < max_tries; ++i) {
  89. get_temp_path(buf, now, seq);
  90. strcat(buf, ".xml");
  91. if (ExistsFileA(buf)) {
  92. seq++;
  93. } else {
  94. break;
  95. }
  96. }
  97. if (i == max_tries) {
  98. return NULL;
  99. }
  100. //buf[strlen(buf) - 4] = 0;
  101. *file_seq = seq;
  102. return buf;
  103. }
  104. static BOOL rename_file1(LPSYSTEMTIME tm_start, int file_seq)
  105. {
  106. char x[MAX_PATH];
  107. char y[MAX_PATH];
  108. get_temp_path(x, tm_start, file_seq);
  109. strcpy(y, x);
  110. strcat(y, ".xml");
  111. return MoveFileExA(x, y, MOVEFILE_REPLACE_EXISTING);
  112. }
  113. static void __log_change_file(log_t *log, LPSYSTEMTIME now)
  114. {
  115. char tmp[MAX_PATH];
  116. if (log->fp) {
  117. fflush(log->fp);
  118. fclose(log->fp);
  119. log->fp = NULL;
  120. }
  121. if (!new_tmp_path(tmp, now, &log->file_seq)) {
  122. log->last_error = -1;
  123. sp_dbg_warn("cannot create log tmp file");
  124. return;
  125. }
  126. log->fp = fopen(tmp, "wb");
  127. if (!log->fp) {
  128. log->last_error = -1;
  129. sp_dbg_warn("cannot fopen log tmp file %s", tmp);
  130. return;
  131. } else {
  132. memcpy(&log->tm_start, now, sizeof(SYSTEMTIME));
  133. }
  134. }
  135. static void __log_write_record(log_t *log,
  136. u__int64_t log_id,
  137. LPSYSTEMTIME tm,
  138. int log_type,
  139. u__int64_t prev_rsn,
  140. u__int64_t curr_rsn,
  141. int original_rsn_type,
  142. int rsn_depth,
  143. int log_severity,
  144. int log_sys_error,
  145. int log_usr_error,
  146. const char *module,
  147. const char *entity,
  148. const char *msg)
  149. {
  150. int n;
  151. n = fprintf(log->fp,
  152. //"<Log SN=\"0x%llX\" Time=\"%02d:%02d:%02d\" LogType=\"%d\" CRS=\"0x%llX\" LRS=\"0x%llX\" ORS=\"0x%X\" RunCount=\"%d\" SeverityLevel=\"%d\" SysCode=\"0x%X\" UserCode=\"0x%X\" SpName=\"%s\" Entity=\"%s\">%s</Log>\r\n",
  153. "<Log SN=\"0x%llX\" Time=\"%02d:%02d:%02d\" LogType=\"%d\" SeverityLevel=\"%d\" SysCode=\"0x%X\" UserCode=\"0x%X\" SpName=\"%s\" Entity=\"%s\">%s</Log>\r\n",
  154. log_id,
  155. tm->wHour, tm->wMinute, tm->wSecond,
  156. log_type,
  157. /*curr_rsn,
  158. prev_rsn,
  159. original_rsn_type,
  160. rsn_depth, */
  161. log_severity,
  162. log_sys_error,
  163. log_usr_error,
  164. module,
  165. entity,
  166. msg);
  167. if (n < 0) {
  168. log->last_error = -1;
  169. fclose(log->fp);
  170. log->fp = NULL;
  171. sp_dbg_warn("write log record failed!");
  172. }
  173. }
  174. static void on_log(void *inst,
  175. int nsub,
  176. u__int64_t *sub,
  177. int client_id,
  178. int log_epid,
  179. int client_instance_id,
  180. u__int64_t log_id,
  181. u__int64_t prev_rsn,
  182. u__int64_t curr_rsn,
  183. int original_rsn_type,
  184. int rsn_depth,
  185. unsigned int log_time,
  186. int log_type,
  187. int log_severity,
  188. int log_sys_error,
  189. int log_usr_error,
  190. int param_cnt,
  191. int *params,
  192. const char *msg,
  193. void *user_data)
  194. {
  195. sp_env_t *env = sp_get_env();
  196. sp_cfg_t *cfg = env->cfg;
  197. sp_cfg_shell_entity_t *ent = sp_cfg_get_entity_by_idx(cfg, client_id);
  198. sp_cfg_shell_module_t *mod = ent ? ent->mod : sp_cfg_get_module_by_idx(cfg, log_epid);
  199. log_t *log = (log_t*)user_data;
  200. app_t *app = get_app_instance();
  201. #ifdef _WIN32
  202. // 在调试控制台显示已订阅实体日志
  203. if (app->pConsole != NULL && app->pConsole->HasSubLogCnn()) {
  204. app->pConsole->OutputLog(client_id, ent->name, msg);
  205. }
  206. // 在启动画面显示日志
  207. if (log_type == 1) // Log_Event
  208. sp_gui_show_running_info(app->bsc_gui, CSimpleString::Format("[%s] I:{%s}(uc:0x%X)", ent->name, msg, log_usr_error), 0);
  209. else if (log_type == 2) // Log_Warning
  210. sp_gui_show_running_info(app->bsc_gui, CSimpleString::Format("[%s] W:{%s}(sc:0x%X, uc:0x%X)", ent->name, msg, log_sys_error, log_usr_error), 0);
  211. else if (log_type == 3) // Log_Error
  212. sp_gui_show_running_info(app->bsc_gui, CSimpleString::Format("[%s] E:{%s}(sc:0x%X, uc:0x%X)", ent->name, msg, log_sys_error, log_usr_error), 0);
  213. else if (log_type == 4 || log_type == 0) // Log_Debug
  214. sp_gui_show_running_info(app->bsc_gui, CSimpleString::Format("[%s] D:{%s}", ent->name, msg), 0);
  215. #endif //_WIN32
  216. // 输出到文件
  217. SYSTEMTIME st;
  218. y2k_to_localtime(log_time, &st);
  219. if (__log_need_change(log, &st)) {
  220. __log_change_file(log, &st);
  221. }
  222. if (!log->last_error && log->fp) {
  223. LARGE_INTEGER t;
  224. char *escape = str_xml_escape(msg);
  225. t.QuadPart = log_id;
  226. __log_write_record(log,
  227. log_id, &st, log_type,
  228. prev_rsn, curr_rsn, original_rsn_type, rsn_depth,
  229. log_severity, log_sys_error, log_usr_error,
  230. mod->name, ent ? ent->name : "$Anonymous$", escape);
  231. FREE(escape);
  232. }
  233. }
  234. // user send flush command
  235. static void on_flush(void *inst,
  236. int client_id,
  237. LPSYSTEMTIME lst,
  238. void *user_data)
  239. {
  240. log_t *log = (log_t*)user_data;
  241. if (log->fp) {
  242. fflush(log->fp);
  243. /*fclose(log->fp);
  244. log->fp = NULL;*/
  245. }
  246. }
  247. static void on_timeout_interval(void *inst, LPSYSTEMTIME lst, void *user_data)
  248. {
  249. log_t *log = (log_t*)user_data;
  250. if (log->fp) {
  251. if (__log_need_change(log, lst)) {
  252. fclose(log->fp);
  253. log->fp = NULL;
  254. } else {
  255. fflush(log->fp);
  256. }
  257. }
  258. }
  259. int log_create(sp_svc_t *svc, log_t **p_log)
  260. {
  261. log_t *log = ZALLOC_T(log_t);
  262. sp_env_t *env = sp_get_env();
  263. sp_cfg_t *cfg = env->cfg;
  264. sp_cfg_root_ini_t *root_cfg = cfg->root_ini;
  265. const char *dir = root_cfg->ref_syslog_path;
  266. int rc;
  267. rc = sp_log_daemon_create(&on_log, &on_flush, &on_timeout_interval, log, svc, &log->log_daemon);
  268. if (rc == 0) {
  269. *p_log = log;
  270. } else {
  271. free(log);
  272. }
  273. return rc;
  274. }
  275. int log_destroy(log_t *log)
  276. {
  277. int rc;
  278. rc = sp_log_daemon_destroy(log->log_daemon);
  279. if (rc == 0) {
  280. if (log->fp) {
  281. fflush(log->fp);
  282. fclose(log->fp);
  283. log->fp = NULL;
  284. }
  285. free(log);
  286. }
  287. return 0;
  288. }