THIS IS A TEST INSTANCE ONLY! REPOSITORIES CAN BE DELETED AT ANY TIME!

Git Source Code Mirror - This is a publish-only repository and all pull requests are ignored. Please follow Documentation/SubmittingPatches procedure for any of your improvements.
git
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

604 lines
17KB

  1. #include "cache.h"
  2. #include "config.h"
  3. #include "json-writer.h"
  4. #include "run-command.h"
  5. #include "version.h"
  6. #include "trace2/tr2_dst.h"
  7. #include "trace2/tr2_tbuf.h"
  8. #include "trace2/tr2_sid.h"
  9. #include "trace2/tr2_sysenv.h"
  10. #include "trace2/tr2_tgt.h"
  11. #include "trace2/tr2_tls.h"
  12. static struct tr2_dst tr2dst_event = { TR2_SYSENV_EVENT, 0, 0, 0, 0 };
  13. /*
  14. * The version number of the JSON data generated by the EVENT target in this
  15. * source file. The version should be incremented if new event types are added,
  16. * if existing fields are removed, or if there are significant changes in
  17. * interpretation of existing events or fields. Smaller changes, such as adding
  18. * a new field to an existing event, do not require an increment to the EVENT
  19. * format version.
  20. */
  21. #define TR2_EVENT_VERSION "2"
  22. /*
  23. * Region nesting limit for messages written to the event target.
  24. *
  25. * The "region_enter" and "region_leave" messages (especially recursive
  26. * messages such as those produced while diving the worktree or index)
  27. * are primarily intended for the performance target during debugging.
  28. *
  29. * Some of the outer-most messages, however, may be of interest to the
  30. * event target. Use the TR2_SYSENV_EVENT_NESTING setting to increase
  31. * region details in the event target.
  32. */
  33. static int tr2env_event_max_nesting_levels = 2;
  34. /*
  35. * Use the TR2_SYSENV_EVENT_BRIEF to omit the <time>, <file>, and
  36. * <line> fields from most events.
  37. */
  38. static int tr2env_event_be_brief;
  39. static int fn_init(void)
  40. {
  41. int want = tr2_dst_trace_want(&tr2dst_event);
  42. int max_nesting;
  43. int want_brief;
  44. const char *nesting;
  45. const char *brief;
  46. if (!want)
  47. return want;
  48. nesting = tr2_sysenv_get(TR2_SYSENV_EVENT_NESTING);
  49. if (nesting && *nesting && ((max_nesting = atoi(nesting)) > 0))
  50. tr2env_event_max_nesting_levels = max_nesting;
  51. brief = tr2_sysenv_get(TR2_SYSENV_EVENT_BRIEF);
  52. if (brief && *brief &&
  53. ((want_brief = git_parse_maybe_bool(brief)) != -1))
  54. tr2env_event_be_brief = want_brief;
  55. return want;
  56. }
  57. static void fn_term(void)
  58. {
  59. tr2_dst_trace_disable(&tr2dst_event);
  60. }
  61. /*
  62. * Append common key-value pairs to the currently open JSON object.
  63. * "event:"<event_name>"
  64. * "sid":"<sid>"
  65. * "thread":"<thread_name>"
  66. * "time":"<time>"
  67. * "file":"<filename>"
  68. * "line":<line_number>
  69. * "repo":<repo_id>
  70. */
  71. static void event_fmt_prepare(const char *event_name, const char *file,
  72. int line, const struct repository *repo,
  73. struct json_writer *jw)
  74. {
  75. struct tr2tls_thread_ctx *ctx = tr2tls_get_self();
  76. struct tr2_tbuf tb_now;
  77. jw_object_string(jw, "event", event_name);
  78. jw_object_string(jw, "sid", tr2_sid_get());
  79. jw_object_string(jw, "thread", ctx->thread_name.buf);
  80. /*
  81. * In brief mode, only emit <time> on these 2 event types.
  82. */
  83. if (!tr2env_event_be_brief || !strcmp(event_name, "version") ||
  84. !strcmp(event_name, "atexit")) {
  85. tr2_tbuf_utc_datetime_extended(&tb_now);
  86. jw_object_string(jw, "time", tb_now.buf);
  87. }
  88. if (!tr2env_event_be_brief && file && *file) {
  89. jw_object_string(jw, "file", file);
  90. jw_object_intmax(jw, "line", line);
  91. }
  92. if (repo)
  93. jw_object_intmax(jw, "repo", repo->trace2_repo_id);
  94. }
  95. static void fn_too_many_files_fl(const char *file, int line)
  96. {
  97. const char *event_name = "too_many_files";
  98. struct json_writer jw = JSON_WRITER_INIT;
  99. jw_object_begin(&jw, 0);
  100. event_fmt_prepare(event_name, file, line, NULL, &jw);
  101. jw_end(&jw);
  102. tr2_dst_write_line(&tr2dst_event, &jw.json);
  103. jw_release(&jw);
  104. }
  105. static void fn_version_fl(const char *file, int line)
  106. {
  107. const char *event_name = "version";
  108. struct json_writer jw = JSON_WRITER_INIT;
  109. jw_object_begin(&jw, 0);
  110. event_fmt_prepare(event_name, file, line, NULL, &jw);
  111. jw_object_string(&jw, "evt", TR2_EVENT_VERSION);
  112. jw_object_string(&jw, "exe", git_version_string);
  113. jw_end(&jw);
  114. tr2_dst_write_line(&tr2dst_event, &jw.json);
  115. jw_release(&jw);
  116. if (tr2dst_event.too_many_files)
  117. fn_too_many_files_fl(file, line);
  118. }
  119. static void fn_start_fl(const char *file, int line,
  120. uint64_t us_elapsed_absolute, const char **argv)
  121. {
  122. const char *event_name = "start";
  123. struct json_writer jw = JSON_WRITER_INIT;
  124. double t_abs = (double)us_elapsed_absolute / 1000000.0;
  125. jw_object_begin(&jw, 0);
  126. event_fmt_prepare(event_name, file, line, NULL, &jw);
  127. jw_object_double(&jw, "t_abs", 6, t_abs);
  128. jw_object_inline_begin_array(&jw, "argv");
  129. jw_array_argv(&jw, argv);
  130. jw_end(&jw);
  131. jw_end(&jw);
  132. tr2_dst_write_line(&tr2dst_event, &jw.json);
  133. jw_release(&jw);
  134. }
  135. static void fn_exit_fl(const char *file, int line, uint64_t us_elapsed_absolute,
  136. int code)
  137. {
  138. const char *event_name = "exit";
  139. struct json_writer jw = JSON_WRITER_INIT;
  140. double t_abs = (double)us_elapsed_absolute / 1000000.0;
  141. jw_object_begin(&jw, 0);
  142. event_fmt_prepare(event_name, file, line, NULL, &jw);
  143. jw_object_double(&jw, "t_abs", 6, t_abs);
  144. jw_object_intmax(&jw, "code", code);
  145. jw_end(&jw);
  146. tr2_dst_write_line(&tr2dst_event, &jw.json);
  147. jw_release(&jw);
  148. }
  149. static void fn_signal(uint64_t us_elapsed_absolute, int signo)
  150. {
  151. const char *event_name = "signal";
  152. struct json_writer jw = JSON_WRITER_INIT;
  153. double t_abs = (double)us_elapsed_absolute / 1000000.0;
  154. jw_object_begin(&jw, 0);
  155. event_fmt_prepare(event_name, __FILE__, __LINE__, NULL, &jw);
  156. jw_object_double(&jw, "t_abs", 6, t_abs);
  157. jw_object_intmax(&jw, "signo", signo);
  158. jw_end(&jw);
  159. tr2_dst_write_line(&tr2dst_event, &jw.json);
  160. jw_release(&jw);
  161. }
  162. static void fn_atexit(uint64_t us_elapsed_absolute, int code)
  163. {
  164. const char *event_name = "atexit";
  165. struct json_writer jw = JSON_WRITER_INIT;
  166. double t_abs = (double)us_elapsed_absolute / 1000000.0;
  167. jw_object_begin(&jw, 0);
  168. event_fmt_prepare(event_name, __FILE__, __LINE__, NULL, &jw);
  169. jw_object_double(&jw, "t_abs", 6, t_abs);
  170. jw_object_intmax(&jw, "code", code);
  171. jw_end(&jw);
  172. tr2_dst_write_line(&tr2dst_event, &jw.json);
  173. jw_release(&jw);
  174. }
  175. static void maybe_add_string_va(struct json_writer *jw, const char *field_name,
  176. const char *fmt, va_list ap)
  177. {
  178. if (fmt && *fmt) {
  179. va_list copy_ap;
  180. struct strbuf buf = STRBUF_INIT;
  181. va_copy(copy_ap, ap);
  182. strbuf_vaddf(&buf, fmt, copy_ap);
  183. va_end(copy_ap);
  184. jw_object_string(jw, field_name, buf.buf);
  185. strbuf_release(&buf);
  186. return;
  187. }
  188. }
  189. static void fn_error_va_fl(const char *file, int line, const char *fmt,
  190. va_list ap)
  191. {
  192. const char *event_name = "error";
  193. struct json_writer jw = JSON_WRITER_INIT;
  194. jw_object_begin(&jw, 0);
  195. event_fmt_prepare(event_name, file, line, NULL, &jw);
  196. maybe_add_string_va(&jw, "msg", fmt, ap);
  197. /*
  198. * Also emit the format string as a field in case
  199. * post-processors want to aggregate common error
  200. * messages by type without argument fields (such
  201. * as pathnames or branch names) cluttering it up.
  202. */
  203. if (fmt && *fmt)
  204. jw_object_string(&jw, "fmt", fmt);
  205. jw_end(&jw);
  206. tr2_dst_write_line(&tr2dst_event, &jw.json);
  207. jw_release(&jw);
  208. }
  209. static void fn_command_path_fl(const char *file, int line, const char *pathname)
  210. {
  211. const char *event_name = "cmd_path";
  212. struct json_writer jw = JSON_WRITER_INIT;
  213. jw_object_begin(&jw, 0);
  214. event_fmt_prepare(event_name, file, line, NULL, &jw);
  215. jw_object_string(&jw, "path", pathname);
  216. jw_end(&jw);
  217. tr2_dst_write_line(&tr2dst_event, &jw.json);
  218. jw_release(&jw);
  219. }
  220. static void fn_command_name_fl(const char *file, int line, const char *name,
  221. const char *hierarchy)
  222. {
  223. const char *event_name = "cmd_name";
  224. struct json_writer jw = JSON_WRITER_INIT;
  225. jw_object_begin(&jw, 0);
  226. event_fmt_prepare(event_name, file, line, NULL, &jw);
  227. jw_object_string(&jw, "name", name);
  228. if (hierarchy && *hierarchy)
  229. jw_object_string(&jw, "hierarchy", hierarchy);
  230. jw_end(&jw);
  231. tr2_dst_write_line(&tr2dst_event, &jw.json);
  232. jw_release(&jw);
  233. }
  234. static void fn_command_mode_fl(const char *file, int line, const char *mode)
  235. {
  236. const char *event_name = "cmd_mode";
  237. struct json_writer jw = JSON_WRITER_INIT;
  238. jw_object_begin(&jw, 0);
  239. event_fmt_prepare(event_name, file, line, NULL, &jw);
  240. jw_object_string(&jw, "name", mode);
  241. jw_end(&jw);
  242. tr2_dst_write_line(&tr2dst_event, &jw.json);
  243. jw_release(&jw);
  244. }
  245. static void fn_alias_fl(const char *file, int line, const char *alias,
  246. const char **argv)
  247. {
  248. const char *event_name = "alias";
  249. struct json_writer jw = JSON_WRITER_INIT;
  250. jw_object_begin(&jw, 0);
  251. event_fmt_prepare(event_name, file, line, NULL, &jw);
  252. jw_object_string(&jw, "alias", alias);
  253. jw_object_inline_begin_array(&jw, "argv");
  254. jw_array_argv(&jw, argv);
  255. jw_end(&jw);
  256. jw_end(&jw);
  257. tr2_dst_write_line(&tr2dst_event, &jw.json);
  258. jw_release(&jw);
  259. }
  260. static void fn_child_start_fl(const char *file, int line,
  261. uint64_t us_elapsed_absolute,
  262. const struct child_process *cmd)
  263. {
  264. const char *event_name = "child_start";
  265. struct json_writer jw = JSON_WRITER_INIT;
  266. jw_object_begin(&jw, 0);
  267. event_fmt_prepare(event_name, file, line, NULL, &jw);
  268. jw_object_intmax(&jw, "child_id", cmd->trace2_child_id);
  269. if (cmd->trace2_hook_name) {
  270. jw_object_string(&jw, "child_class", "hook");
  271. jw_object_string(&jw, "hook_name", cmd->trace2_hook_name);
  272. } else {
  273. const char *child_class =
  274. cmd->trace2_child_class ? cmd->trace2_child_class : "?";
  275. jw_object_string(&jw, "child_class", child_class);
  276. }
  277. if (cmd->dir)
  278. jw_object_string(&jw, "cd", cmd->dir);
  279. jw_object_bool(&jw, "use_shell", cmd->use_shell);
  280. jw_object_inline_begin_array(&jw, "argv");
  281. if (cmd->git_cmd)
  282. jw_array_string(&jw, "git");
  283. jw_array_argv(&jw, cmd->argv);
  284. jw_end(&jw);
  285. jw_end(&jw);
  286. tr2_dst_write_line(&tr2dst_event, &jw.json);
  287. jw_release(&jw);
  288. }
  289. static void fn_child_exit_fl(const char *file, int line,
  290. uint64_t us_elapsed_absolute, int cid, int pid,
  291. int code, uint64_t us_elapsed_child)
  292. {
  293. const char *event_name = "child_exit";
  294. struct json_writer jw = JSON_WRITER_INIT;
  295. double t_rel = (double)us_elapsed_child / 1000000.0;
  296. jw_object_begin(&jw, 0);
  297. event_fmt_prepare(event_name, file, line, NULL, &jw);
  298. jw_object_intmax(&jw, "child_id", cid);
  299. jw_object_intmax(&jw, "pid", pid);
  300. jw_object_intmax(&jw, "code", code);
  301. jw_object_double(&jw, "t_rel", 6, t_rel);
  302. jw_end(&jw);
  303. tr2_dst_write_line(&tr2dst_event, &jw.json);
  304. jw_release(&jw);
  305. }
  306. static void fn_thread_start_fl(const char *file, int line,
  307. uint64_t us_elapsed_absolute)
  308. {
  309. const char *event_name = "thread_start";
  310. struct json_writer jw = JSON_WRITER_INIT;
  311. jw_object_begin(&jw, 0);
  312. event_fmt_prepare(event_name, file, line, NULL, &jw);
  313. jw_end(&jw);
  314. tr2_dst_write_line(&tr2dst_event, &jw.json);
  315. jw_release(&jw);
  316. }
  317. static void fn_thread_exit_fl(const char *file, int line,
  318. uint64_t us_elapsed_absolute,
  319. uint64_t us_elapsed_thread)
  320. {
  321. const char *event_name = "thread_exit";
  322. struct json_writer jw = JSON_WRITER_INIT;
  323. double t_rel = (double)us_elapsed_thread / 1000000.0;
  324. jw_object_begin(&jw, 0);
  325. event_fmt_prepare(event_name, file, line, NULL, &jw);
  326. jw_object_double(&jw, "t_rel", 6, t_rel);
  327. jw_end(&jw);
  328. tr2_dst_write_line(&tr2dst_event, &jw.json);
  329. jw_release(&jw);
  330. }
  331. static void fn_exec_fl(const char *file, int line, uint64_t us_elapsed_absolute,
  332. int exec_id, const char *exe, const char **argv)
  333. {
  334. const char *event_name = "exec";
  335. struct json_writer jw = JSON_WRITER_INIT;
  336. jw_object_begin(&jw, 0);
  337. event_fmt_prepare(event_name, file, line, NULL, &jw);
  338. jw_object_intmax(&jw, "exec_id", exec_id);
  339. if (exe)
  340. jw_object_string(&jw, "exe", exe);
  341. jw_object_inline_begin_array(&jw, "argv");
  342. jw_array_argv(&jw, argv);
  343. jw_end(&jw);
  344. jw_end(&jw);
  345. tr2_dst_write_line(&tr2dst_event, &jw.json);
  346. jw_release(&jw);
  347. }
  348. static void fn_exec_result_fl(const char *file, int line,
  349. uint64_t us_elapsed_absolute, int exec_id,
  350. int code)
  351. {
  352. const char *event_name = "exec_result";
  353. struct json_writer jw = JSON_WRITER_INIT;
  354. jw_object_begin(&jw, 0);
  355. event_fmt_prepare(event_name, file, line, NULL, &jw);
  356. jw_object_intmax(&jw, "exec_id", exec_id);
  357. jw_object_intmax(&jw, "code", code);
  358. jw_end(&jw);
  359. tr2_dst_write_line(&tr2dst_event, &jw.json);
  360. jw_release(&jw);
  361. }
  362. static void fn_param_fl(const char *file, int line, const char *param,
  363. const char *value)
  364. {
  365. const char *event_name = "def_param";
  366. struct json_writer jw = JSON_WRITER_INIT;
  367. jw_object_begin(&jw, 0);
  368. event_fmt_prepare(event_name, file, line, NULL, &jw);
  369. jw_object_string(&jw, "param", param);
  370. jw_object_string(&jw, "value", value);
  371. jw_end(&jw);
  372. tr2_dst_write_line(&tr2dst_event, &jw.json);
  373. jw_release(&jw);
  374. }
  375. static void fn_repo_fl(const char *file, int line,
  376. const struct repository *repo)
  377. {
  378. const char *event_name = "def_repo";
  379. struct json_writer jw = JSON_WRITER_INIT;
  380. jw_object_begin(&jw, 0);
  381. event_fmt_prepare(event_name, file, line, repo, &jw);
  382. jw_object_string(&jw, "worktree", repo->worktree);
  383. jw_end(&jw);
  384. tr2_dst_write_line(&tr2dst_event, &jw.json);
  385. jw_release(&jw);
  386. }
  387. static void fn_region_enter_printf_va_fl(const char *file, int line,
  388. uint64_t us_elapsed_absolute,
  389. const char *category,
  390. const char *label,
  391. const struct repository *repo,
  392. const char *fmt, va_list ap)
  393. {
  394. const char *event_name = "region_enter";
  395. struct tr2tls_thread_ctx *ctx = tr2tls_get_self();
  396. if (ctx->nr_open_regions <= tr2env_event_max_nesting_levels) {
  397. struct json_writer jw = JSON_WRITER_INIT;
  398. jw_object_begin(&jw, 0);
  399. event_fmt_prepare(event_name, file, line, repo, &jw);
  400. jw_object_intmax(&jw, "nesting", ctx->nr_open_regions);
  401. if (category)
  402. jw_object_string(&jw, "category", category);
  403. if (label)
  404. jw_object_string(&jw, "label", label);
  405. maybe_add_string_va(&jw, "msg", fmt, ap);
  406. jw_end(&jw);
  407. tr2_dst_write_line(&tr2dst_event, &jw.json);
  408. jw_release(&jw);
  409. }
  410. }
  411. static void fn_region_leave_printf_va_fl(
  412. const char *file, int line, uint64_t us_elapsed_absolute,
  413. uint64_t us_elapsed_region, const char *category, const char *label,
  414. const struct repository *repo, const char *fmt, va_list ap)
  415. {
  416. const char *event_name = "region_leave";
  417. struct tr2tls_thread_ctx *ctx = tr2tls_get_self();
  418. if (ctx->nr_open_regions <= tr2env_event_max_nesting_levels) {
  419. struct json_writer jw = JSON_WRITER_INIT;
  420. double t_rel = (double)us_elapsed_region / 1000000.0;
  421. jw_object_begin(&jw, 0);
  422. event_fmt_prepare(event_name, file, line, repo, &jw);
  423. jw_object_double(&jw, "t_rel", 6, t_rel);
  424. jw_object_intmax(&jw, "nesting", ctx->nr_open_regions);
  425. if (category)
  426. jw_object_string(&jw, "category", category);
  427. if (label)
  428. jw_object_string(&jw, "label", label);
  429. maybe_add_string_va(&jw, "msg", fmt, ap);
  430. jw_end(&jw);
  431. tr2_dst_write_line(&tr2dst_event, &jw.json);
  432. jw_release(&jw);
  433. }
  434. }
  435. static void fn_data_fl(const char *file, int line, uint64_t us_elapsed_absolute,
  436. uint64_t us_elapsed_region, const char *category,
  437. const struct repository *repo, const char *key,
  438. const char *value)
  439. {
  440. const char *event_name = "data";
  441. struct tr2tls_thread_ctx *ctx = tr2tls_get_self();
  442. if (ctx->nr_open_regions <= tr2env_event_max_nesting_levels) {
  443. struct json_writer jw = JSON_WRITER_INIT;
  444. double t_abs = (double)us_elapsed_absolute / 1000000.0;
  445. double t_rel = (double)us_elapsed_region / 1000000.0;
  446. jw_object_begin(&jw, 0);
  447. event_fmt_prepare(event_name, file, line, repo, &jw);
  448. jw_object_double(&jw, "t_abs", 6, t_abs);
  449. jw_object_double(&jw, "t_rel", 6, t_rel);
  450. jw_object_intmax(&jw, "nesting", ctx->nr_open_regions);
  451. jw_object_string(&jw, "category", category);
  452. jw_object_string(&jw, "key", key);
  453. jw_object_string(&jw, "value", value);
  454. jw_end(&jw);
  455. tr2_dst_write_line(&tr2dst_event, &jw.json);
  456. jw_release(&jw);
  457. }
  458. }
  459. static void fn_data_json_fl(const char *file, int line,
  460. uint64_t us_elapsed_absolute,
  461. uint64_t us_elapsed_region, const char *category,
  462. const struct repository *repo, const char *key,
  463. const struct json_writer *value)
  464. {
  465. const char *event_name = "data_json";
  466. struct tr2tls_thread_ctx *ctx = tr2tls_get_self();
  467. if (ctx->nr_open_regions <= tr2env_event_max_nesting_levels) {
  468. struct json_writer jw = JSON_WRITER_INIT;
  469. double t_abs = (double)us_elapsed_absolute / 1000000.0;
  470. double t_rel = (double)us_elapsed_region / 1000000.0;
  471. jw_object_begin(&jw, 0);
  472. event_fmt_prepare(event_name, file, line, repo, &jw);
  473. jw_object_double(&jw, "t_abs", 6, t_abs);
  474. jw_object_double(&jw, "t_rel", 6, t_rel);
  475. jw_object_intmax(&jw, "nesting", ctx->nr_open_regions);
  476. jw_object_string(&jw, "category", category);
  477. jw_object_string(&jw, "key", key);
  478. jw_object_sub_jw(&jw, "value", value);
  479. jw_end(&jw);
  480. tr2_dst_write_line(&tr2dst_event, &jw.json);
  481. jw_release(&jw);
  482. }
  483. }
  484. struct tr2_tgt tr2_tgt_event = {
  485. &tr2dst_event,
  486. fn_init,
  487. fn_term,
  488. fn_version_fl,
  489. fn_start_fl,
  490. fn_exit_fl,
  491. fn_signal,
  492. fn_atexit,
  493. fn_error_va_fl,
  494. fn_command_path_fl,
  495. fn_command_name_fl,
  496. fn_command_mode_fl,
  497. fn_alias_fl,
  498. fn_child_start_fl,
  499. fn_child_exit_fl,
  500. fn_thread_start_fl,
  501. fn_thread_exit_fl,
  502. fn_exec_fl,
  503. fn_exec_result_fl,
  504. fn_param_fl,
  505. fn_repo_fl,
  506. fn_region_enter_printf_va_fl,
  507. fn_region_leave_printf_va_fl,
  508. fn_data_fl,
  509. fn_data_json_fl,
  510. NULL, /* printf */
  511. };