Raw
1 #define DISABLE_SIGN_COMPARE_WARNINGS
2
3 #include "git-compat-util.h"
4 #include "config.h"
5 #include "json-writer.h"
6 #include "repository.h"
7 #include "run-command.h"
8 #include "version.h"
9 #include "trace2/tr2_dst.h"
10 #include "trace2/tr2_tbuf.h"
11 #include "trace2/tr2_sid.h"
12 #include "trace2/tr2_sysenv.h"
13 #include "trace2/tr2_tgt.h"
14 #include "trace2/tr2_tls.h"
15 #include "trace2/tr2_tmr.h"
16
17 static struct tr2_dst tr2dst_event = {
18 .sysenv_var = TR2_SYSENV_EVENT,
19 };
20
21 /*
22 * The version number of the JSON data generated by the EVENT target in this
23 * source file. The version should be incremented if new event types are added,
24 * if existing fields are removed, or if there are significant changes in
25 * interpretation of existing events or fields. Smaller changes, such as adding
26 * a new field to an existing event, do not require an increment to the EVENT
27 * format version.
28 */
29 #define TR2_EVENT_VERSION "4"
30
31 /*
32 * Region nesting limit for messages written to the event target.
33 *
34 * The "region_enter" and "region_leave" messages (especially recursive
35 * messages such as those produced while diving the worktree or index)
36 * are primarily intended for the performance target during debugging.
37 *
38 * Some of the outer-most messages, however, may be of interest to the
39 * event target. Use the TR2_SYSENV_EVENT_NESTING setting to increase
40 * region details in the event target.
41 */
42 static int tr2env_event_max_nesting_levels = 2;
43
44 /*
45 * Use the TR2_SYSENV_EVENT_BRIEF to omit the <time>, <file>, and
46 * <line> fields from most events.
47 */
48 static int tr2env_event_be_brief;
49
50 static int fn_init(void)
51 {
52 int want = tr2_dst_trace_want(&tr2dst_event);
53 int max_nesting;
54 int want_brief;
55 const char *nesting;
56 const char *brief;
57
58 if (!want)
59 return want;
60
61 nesting = tr2_sysenv_get(TR2_SYSENV_EVENT_NESTING);
62 if (nesting && *nesting && ((max_nesting = atoi(nesting)) > 0))
63 tr2env_event_max_nesting_levels = max_nesting;
64
65 brief = tr2_sysenv_get(TR2_SYSENV_EVENT_BRIEF);
66 if (brief && *brief &&
67 ((want_brief = git_parse_maybe_bool(brief)) != -1))
68 tr2env_event_be_brief = want_brief;
69
70 return want;
71 }
72
73 static void fn_term(void)
74 {
75 tr2_dst_trace_disable(&tr2dst_event);
76 }
77
78 /*
79 * Append common key-value pairs to the currently open JSON object.
80 * "event:"<event_name>"
81 * "sid":"<sid>"
82 * "thread":"<thread_name>"
83 * "time":"<time>"
84 * "file":"<filename>"
85 * "line":<line_number>
86 * "repo":<repo_id>
87 */
88 static void event_fmt_prepare(const char *event_name, const char *file,
89 int line, const struct repository *repo,
90 struct json_writer *jw)
91 {
92 struct tr2tls_thread_ctx *ctx = tr2tls_get_self();
93 struct tr2_tbuf tb_now;
94
95 jw_object_string(jw, "event", event_name);
96 jw_object_string(jw, "sid", tr2_sid_get());
97 jw_object_string(jw, "thread", ctx->thread_name);
98
99 /*
100 * In brief mode, only emit <time> on these 2 event types.
101 */
102 if (!tr2env_event_be_brief || !strcmp(event_name, "version") ||
103 !strcmp(event_name, "atexit")) {
104 tr2_tbuf_utc_datetime_extended(&tb_now);
105 jw_object_string(jw, "time", tb_now.buf);
106 }
107
108 if (!tr2env_event_be_brief && file && *file) {
109 jw_object_string(jw, "file", file);
110 jw_object_intmax(jw, "line", line);
111 }
112
113 if (repo)
114 jw_object_intmax(jw, "repo", repo->trace2_repo_id);
115 }
116
117 static void fn_too_many_files_fl(const char *file, int line)
118 {
119 const char *event_name = "too_many_files";
120 struct json_writer jw = JSON_WRITER_INIT;
121
122 jw_object_begin(&jw, 0);
123 event_fmt_prepare(event_name, file, line, NULL, &jw);
124 jw_end(&jw);
125
126 tr2_dst_write_line(&tr2dst_event, &jw.json);
127 jw_release(&jw);
128 }
129
130 static void fn_version_fl(const char *file, int line)
131 {
132 const char *event_name = "version";
133 struct json_writer jw = JSON_WRITER_INIT;
134
135 jw_object_begin(&jw, 0);
136 event_fmt_prepare(event_name, file, line, NULL, &jw);
137 jw_object_string(&jw, "evt", TR2_EVENT_VERSION);
138 jw_object_string(&jw, "exe", git_version_string);
139 jw_end(&jw);
140
141 tr2_dst_write_line(&tr2dst_event, &jw.json);
142 jw_release(&jw);
143
144 if (tr2dst_event.too_many_files)
145 fn_too_many_files_fl(file, line);
146 }
147
148 static void fn_start_fl(const char *file, int line,
149 uint64_t us_elapsed_absolute, const char **argv)
150 {
151 const char *event_name = "start";
152 struct json_writer jw = JSON_WRITER_INIT;
153 double t_abs = (double)us_elapsed_absolute / 1000000.0;
154
155 jw_object_begin(&jw, 0);
156 event_fmt_prepare(event_name, file, line, NULL, &jw);
157 jw_object_double(&jw, "t_abs", 6, t_abs);
158 jw_object_inline_begin_array(&jw, "argv");
159 jw_array_argv(&jw, argv);
160 jw_end(&jw);
161 jw_end(&jw);
162
163 tr2_dst_write_line(&tr2dst_event, &jw.json);
164 jw_release(&jw);
165 }
166
167 static void fn_exit_fl(const char *file, int line, uint64_t us_elapsed_absolute,
168 int code)
169 {
170 const char *event_name = "exit";
171 struct json_writer jw = JSON_WRITER_INIT;
172 double t_abs = (double)us_elapsed_absolute / 1000000.0;
173
174 jw_object_begin(&jw, 0);
175 event_fmt_prepare(event_name, file, line, NULL, &jw);
176 jw_object_double(&jw, "t_abs", 6, t_abs);
177 jw_object_intmax(&jw, "code", code);
178 jw_end(&jw);
179
180 tr2_dst_write_line(&tr2dst_event, &jw.json);
181 jw_release(&jw);
182 }
183
184 static void fn_signal(uint64_t us_elapsed_absolute, int signo)
185 {
186 const char *event_name = "signal";
187 struct json_writer jw = JSON_WRITER_INIT;
188 double t_abs = (double)us_elapsed_absolute / 1000000.0;
189
190 jw_object_begin(&jw, 0);
191 event_fmt_prepare(event_name, __FILE__, __LINE__, NULL, &jw);
192 jw_object_double(&jw, "t_abs", 6, t_abs);
193 jw_object_intmax(&jw, "signo", signo);
194 jw_end(&jw);
195
196 tr2_dst_write_line(&tr2dst_event, &jw.json);
197 jw_release(&jw);
198 }
199
200 static void fn_atexit(uint64_t us_elapsed_absolute, int code)
201 {
202 const char *event_name = "atexit";
203 struct json_writer jw = JSON_WRITER_INIT;
204 double t_abs = (double)us_elapsed_absolute / 1000000.0;
205
206 jw_object_begin(&jw, 0);
207 event_fmt_prepare(event_name, __FILE__, __LINE__, NULL, &jw);
208 jw_object_double(&jw, "t_abs", 6, t_abs);
209 jw_object_intmax(&jw, "code", code);
210 jw_end(&jw);
211
212 tr2_dst_write_line(&tr2dst_event, &jw.json);
213 jw_release(&jw);
214 }
215
216 static void maybe_add_string_va(struct json_writer *jw, const char *field_name,
217 const char *fmt, va_list ap)
218 {
219 if (fmt && *fmt) {
220 va_list copy_ap;
221 struct strbuf buf = STRBUF_INIT;
222
223 va_copy(copy_ap, ap);
224 strbuf_vaddf(&buf, fmt, copy_ap);
225 va_end(copy_ap);
226
227 jw_object_string(jw, field_name, buf.buf);
228 strbuf_release(&buf);
229 return;
230 }
231 }
232
233 static void fn_error_va_fl(const char *file, int line, const char *fmt,
234 va_list ap)
235 {
236 const char *event_name = "error";
237 struct json_writer jw = JSON_WRITER_INIT;
238
239 jw_object_begin(&jw, 0);
240 event_fmt_prepare(event_name, file, line, NULL, &jw);
241 maybe_add_string_va(&jw, "msg", fmt, ap);
242 /*
243 * Also emit the format string as a field in case
244 * post-processors want to aggregate common error
245 * messages by type without argument fields (such
246 * as pathnames or branch names) cluttering it up.
247 */
248 if (fmt && *fmt)
249 jw_object_string(&jw, "fmt", fmt);
250 jw_end(&jw);
251
252 tr2_dst_write_line(&tr2dst_event, &jw.json);
253 jw_release(&jw);
254 }
255
256 static void fn_command_path_fl(const char *file, int line, const char *pathname)
257 {
258 const char *event_name = "cmd_path";
259 struct json_writer jw = JSON_WRITER_INIT;
260
261 jw_object_begin(&jw, 0);
262 event_fmt_prepare(event_name, file, line, NULL, &jw);
263 jw_object_string(&jw, "path", pathname);
264 jw_end(&jw);
265
266 tr2_dst_write_line(&tr2dst_event, &jw.json);
267 jw_release(&jw);
268 }
269
270 static void fn_command_ancestry_fl(const char *file, int line, const char **parent_names)
271 {
272 const char *event_name = "cmd_ancestry";
273 const char *parent_name = NULL;
274 struct json_writer jw = JSON_WRITER_INIT;
275
276 jw_object_begin(&jw, 0);
277 event_fmt_prepare(event_name, file, line, NULL, &jw);
278 jw_object_inline_begin_array(&jw, "ancestry");
279
280 while ((parent_name = *parent_names++))
281 jw_array_string(&jw, parent_name);
282
283 jw_end(&jw); /* 'ancestry' array */
284 jw_end(&jw); /* event object */
285
286 tr2_dst_write_line(&tr2dst_event, &jw.json);
287 jw_release(&jw);
288 }
289
290 static void fn_command_name_fl(const char *file, int line, const char *name,
291 const char *hierarchy)
292 {
293 const char *event_name = "cmd_name";
294 struct json_writer jw = JSON_WRITER_INIT;
295
296 jw_object_begin(&jw, 0);
297 event_fmt_prepare(event_name, file, line, NULL, &jw);
298 jw_object_string(&jw, "name", name);
299 if (hierarchy && *hierarchy)
300 jw_object_string(&jw, "hierarchy", hierarchy);
301 jw_end(&jw);
302
303 tr2_dst_write_line(&tr2dst_event, &jw.json);
304 jw_release(&jw);
305 }
306
307 static void fn_command_mode_fl(const char *file, int line, const char *mode)
308 {
309 const char *event_name = "cmd_mode";
310 struct json_writer jw = JSON_WRITER_INIT;
311
312 jw_object_begin(&jw, 0);
313 event_fmt_prepare(event_name, file, line, NULL, &jw);
314 jw_object_string(&jw, "name", mode);
315 jw_end(&jw);
316
317 tr2_dst_write_line(&tr2dst_event, &jw.json);
318 jw_release(&jw);
319 }
320
321 static void fn_alias_fl(const char *file, int line, const char *alias,
322 const char **argv)
323 {
324 const char *event_name = "alias";
325 struct json_writer jw = JSON_WRITER_INIT;
326
327 jw_object_begin(&jw, 0);
328 event_fmt_prepare(event_name, file, line, NULL, &jw);
329 jw_object_string(&jw, "alias", alias);
330 jw_object_inline_begin_array(&jw, "argv");
331 jw_array_argv(&jw, argv);
332 jw_end(&jw);
333 jw_end(&jw);
334
335 tr2_dst_write_line(&tr2dst_event, &jw.json);
336 jw_release(&jw);
337 }
338
339 static void fn_child_start_fl(const char *file, int line,
340 uint64_t us_elapsed_absolute UNUSED,
341 const struct child_process *cmd)
342 {
343 const char *event_name = "child_start";
344 struct json_writer jw = JSON_WRITER_INIT;
345
346 jw_object_begin(&jw, 0);
347 event_fmt_prepare(event_name, file, line, NULL, &jw);
348 jw_object_intmax(&jw, "child_id", cmd->trace2_child_id);
349 if (cmd->trace2_hook_name) {
350 jw_object_string(&jw, "child_class", "hook");
351 jw_object_string(&jw, "hook_name", cmd->trace2_hook_name);
352 } else {
353 const char *child_class =
354 cmd->trace2_child_class ? cmd->trace2_child_class : "?";
355 jw_object_string(&jw, "child_class", child_class);
356 }
357 if (cmd->dir)
358 jw_object_string(&jw, "cd", cmd->dir);
359 jw_object_bool(&jw, "use_shell", cmd->use_shell);
360 jw_object_inline_begin_array(&jw, "argv");
361 if (cmd->git_cmd)
362 jw_array_string(&jw, "git");
363 jw_array_argv(&jw, cmd->args.v);
364 jw_end(&jw);
365 jw_end(&jw);
366
367 tr2_dst_write_line(&tr2dst_event, &jw.json);
368 jw_release(&jw);
369 }
370
371 static void fn_child_exit_fl(const char *file, int line,
372 uint64_t us_elapsed_absolute UNUSED,
373 int cid, int pid,
374 int code, uint64_t us_elapsed_child)
375 {
376 const char *event_name = "child_exit";
377 struct json_writer jw = JSON_WRITER_INIT;
378 double t_rel = (double)us_elapsed_child / 1000000.0;
379
380 jw_object_begin(&jw, 0);
381 event_fmt_prepare(event_name, file, line, NULL, &jw);
382 jw_object_intmax(&jw, "child_id", cid);
383 jw_object_intmax(&jw, "pid", pid);
384 jw_object_intmax(&jw, "code", code);
385 jw_object_double(&jw, "t_rel", 6, t_rel);
386 jw_end(&jw);
387
388 tr2_dst_write_line(&tr2dst_event, &jw.json);
389
390 jw_release(&jw);
391 }
392
393 static void fn_child_ready_fl(const char *file, int line,
394 uint64_t us_elapsed_absolute UNUSED,
395 int cid, int pid,
396 const char *ready, uint64_t us_elapsed_child)
397 {
398 const char *event_name = "child_ready";
399 struct json_writer jw = JSON_WRITER_INIT;
400 double t_rel = (double)us_elapsed_child / 1000000.0;
401
402 jw_object_begin(&jw, 0);
403 event_fmt_prepare(event_name, file, line, NULL, &jw);
404 jw_object_intmax(&jw, "child_id", cid);
405 jw_object_intmax(&jw, "pid", pid);
406 jw_object_string(&jw, "ready", ready);
407 jw_object_double(&jw, "t_rel", 6, t_rel);
408 jw_end(&jw);
409
410 tr2_dst_write_line(&tr2dst_event, &jw.json);
411
412 jw_release(&jw);
413 }
414
415 static void fn_thread_start_fl(const char *file, int line,
416 uint64_t us_elapsed_absolute UNUSED)
417 {
418 const char *event_name = "thread_start";
419 struct json_writer jw = JSON_WRITER_INIT;
420
421 jw_object_begin(&jw, 0);
422 event_fmt_prepare(event_name, file, line, NULL, &jw);
423 jw_end(&jw);
424
425 tr2_dst_write_line(&tr2dst_event, &jw.json);
426 jw_release(&jw);
427 }
428
429 static void fn_thread_exit_fl(const char *file, int line,
430 uint64_t us_elapsed_absolute UNUSED,
431 uint64_t us_elapsed_thread)
432 {
433 const char *event_name = "thread_exit";
434 struct json_writer jw = JSON_WRITER_INIT;
435 double t_rel = (double)us_elapsed_thread / 1000000.0;
436
437 jw_object_begin(&jw, 0);
438 event_fmt_prepare(event_name, file, line, NULL, &jw);
439 jw_object_double(&jw, "t_rel", 6, t_rel);
440 jw_end(&jw);
441
442 tr2_dst_write_line(&tr2dst_event, &jw.json);
443 jw_release(&jw);
444 }
445
446 static void fn_exec_fl(const char *file, int line,
447 uint64_t us_elapsed_absolute UNUSED,
448 int exec_id, const char *exe, const char **argv)
449 {
450 const char *event_name = "exec";
451 struct json_writer jw = JSON_WRITER_INIT;
452
453 jw_object_begin(&jw, 0);
454 event_fmt_prepare(event_name, file, line, NULL, &jw);
455 jw_object_intmax(&jw, "exec_id", exec_id);
456 if (exe)
457 jw_object_string(&jw, "exe", exe);
458 jw_object_inline_begin_array(&jw, "argv");
459 jw_array_argv(&jw, argv);
460 jw_end(&jw);
461 jw_end(&jw);
462
463 tr2_dst_write_line(&tr2dst_event, &jw.json);
464 jw_release(&jw);
465 }
466
467 static void fn_exec_result_fl(const char *file, int line,
468 uint64_t us_elapsed_absolute UNUSED,
469 int exec_id, int code)
470 {
471 const char *event_name = "exec_result";
472 struct json_writer jw = JSON_WRITER_INIT;
473
474 jw_object_begin(&jw, 0);
475 event_fmt_prepare(event_name, file, line, NULL, &jw);
476 jw_object_intmax(&jw, "exec_id", exec_id);
477 jw_object_intmax(&jw, "code", code);
478 jw_end(&jw);
479
480 tr2_dst_write_line(&tr2dst_event, &jw.json);
481 jw_release(&jw);
482 }
483
484 static void fn_param_fl(const char *file, int line, const char *param,
485 const char *value, const struct key_value_info *kvi)
486 {
487 const char *event_name = "def_param";
488 struct json_writer jw = JSON_WRITER_INIT;
489 enum config_scope scope = kvi->scope;
490 const char *scope_name = config_scope_name(scope);
491
492 jw_object_begin(&jw, 0);
493 event_fmt_prepare(event_name, file, line, NULL, &jw);
494 jw_object_string(&jw, "scope", scope_name);
495 jw_object_string(&jw, "param", param);
496 if (value)
497 jw_object_string(&jw, "value", value);
498 jw_end(&jw);
499
500 tr2_dst_write_line(&tr2dst_event, &jw.json);
501 jw_release(&jw);
502 }
503
504 static void fn_repo_fl(const char *file, int line,
505 const struct repository *repo)
506 {
507 const char *event_name = "def_repo";
508 struct json_writer jw = JSON_WRITER_INIT;
509
510 jw_object_begin(&jw, 0);
511 event_fmt_prepare(event_name, file, line, repo, &jw);
512 jw_object_string(&jw, "worktree", repo->worktree);
513 jw_end(&jw);
514
515 tr2_dst_write_line(&tr2dst_event, &jw.json);
516 jw_release(&jw);
517 }
518
519 static void fn_region_enter_printf_va_fl(const char *file, int line,
520 uint64_t us_elapsed_absolute UNUSED,
521 const char *category,
522 const char *label,
523 const struct repository *repo,
524 const char *fmt, va_list ap)
525 {
526 const char *event_name = "region_enter";
527 struct tr2tls_thread_ctx *ctx = tr2tls_get_self();
528 if (ctx->nr_open_regions <= tr2env_event_max_nesting_levels) {
529 struct json_writer jw = JSON_WRITER_INIT;
530
531 jw_object_begin(&jw, 0);
532 event_fmt_prepare(event_name, file, line, repo, &jw);
533 jw_object_intmax(&jw, "nesting", ctx->nr_open_regions);
534 if (category)
535 jw_object_string(&jw, "category", category);
536 if (label)
537 jw_object_string(&jw, "label", label);
538 maybe_add_string_va(&jw, "msg", fmt, ap);
539 jw_end(&jw);
540
541 tr2_dst_write_line(&tr2dst_event, &jw.json);
542 jw_release(&jw);
543 }
544 }
545
546 static void fn_region_leave_printf_va_fl(
547 const char *file, int line, uint64_t us_elapsed_absolute UNUSED,
548 uint64_t us_elapsed_region, const char *category, const char *label,
549 const struct repository *repo, const char *fmt, va_list ap)
550 {
551 const char *event_name = "region_leave";
552 struct tr2tls_thread_ctx *ctx = tr2tls_get_self();
553 if (ctx->nr_open_regions <= tr2env_event_max_nesting_levels) {
554 struct json_writer jw = JSON_WRITER_INIT;
555 double t_rel = (double)us_elapsed_region / 1000000.0;
556
557 jw_object_begin(&jw, 0);
558 event_fmt_prepare(event_name, file, line, repo, &jw);
559 jw_object_double(&jw, "t_rel", 6, t_rel);
560 jw_object_intmax(&jw, "nesting", ctx->nr_open_regions);
561 if (category)
562 jw_object_string(&jw, "category", category);
563 if (label)
564 jw_object_string(&jw, "label", label);
565 maybe_add_string_va(&jw, "msg", fmt, ap);
566 jw_end(&jw);
567
568 tr2_dst_write_line(&tr2dst_event, &jw.json);
569 jw_release(&jw);
570 }
571 }
572
573 static void fn_data_fl(const char *file, int line, uint64_t us_elapsed_absolute,
574 uint64_t us_elapsed_region, const char *category,
575 const struct repository *repo, const char *key,
576 const char *value)
577 {
578 const char *event_name = "data";
579 struct tr2tls_thread_ctx *ctx = tr2tls_get_self();
580 if (ctx->nr_open_regions <= tr2env_event_max_nesting_levels) {
581 struct json_writer jw = JSON_WRITER_INIT;
582 double t_abs = (double)us_elapsed_absolute / 1000000.0;
583 double t_rel = (double)us_elapsed_region / 1000000.0;
584
585 jw_object_begin(&jw, 0);
586 event_fmt_prepare(event_name, file, line, repo, &jw);
587 jw_object_double(&jw, "t_abs", 6, t_abs);
588 jw_object_double(&jw, "t_rel", 6, t_rel);
589 jw_object_intmax(&jw, "nesting", ctx->nr_open_regions);
590 jw_object_string(&jw, "category", category);
591 jw_object_string(&jw, "key", key);
592 jw_object_string(&jw, "value", value);
593 jw_end(&jw);
594
595 tr2_dst_write_line(&tr2dst_event, &jw.json);
596 jw_release(&jw);
597 }
598 }
599
600 static void fn_data_json_fl(const char *file, int line,
601 uint64_t us_elapsed_absolute,
602 uint64_t us_elapsed_region, const char *category,
603 const struct repository *repo, const char *key,
604 const struct json_writer *value)
605 {
606 const char *event_name = "data_json";
607 struct tr2tls_thread_ctx *ctx = tr2tls_get_self();
608 if (ctx->nr_open_regions <= tr2env_event_max_nesting_levels) {
609 struct json_writer jw = JSON_WRITER_INIT;
610 double t_abs = (double)us_elapsed_absolute / 1000000.0;
611 double t_rel = (double)us_elapsed_region / 1000000.0;
612
613 jw_object_begin(&jw, 0);
614 event_fmt_prepare(event_name, file, line, repo, &jw);
615 jw_object_double(&jw, "t_abs", 6, t_abs);
616 jw_object_double(&jw, "t_rel", 6, t_rel);
617 jw_object_intmax(&jw, "nesting", ctx->nr_open_regions);
618 jw_object_string(&jw, "category", category);
619 jw_object_string(&jw, "key", key);
620 jw_object_sub_jw(&jw, "value", value);
621 jw_end(&jw);
622
623 tr2_dst_write_line(&tr2dst_event, &jw.json);
624 jw_release(&jw);
625 }
626 }
627
628 static void fn_printf_va_fl(const char *file, int line,
629 uint64_t us_elapsed_absolute,
630 const char *fmt, va_list ap)
631 {
632 const char *event_name = "printf";
633 struct json_writer jw = JSON_WRITER_INIT;
634 double t_abs = (double)us_elapsed_absolute / 1000000.0;
635
636 jw_object_begin(&jw, 0);
637 event_fmt_prepare(event_name, file, line, NULL, &jw);
638 jw_object_double(&jw, "t_abs", 6, t_abs);
639 maybe_add_string_va(&jw, "msg", fmt, ap);
640 jw_end(&jw);
641
642 tr2_dst_write_line(&tr2dst_event, &jw.json);
643 jw_release(&jw);
644 }
645
646 static void fn_timer(const struct tr2_timer_metadata *meta,
647 const struct tr2_timer *timer,
648 int is_final_data)
649 {
650 const char *event_name = is_final_data ? "timer" : "th_timer";
651 struct json_writer jw = JSON_WRITER_INIT;
652 double t_total = NS_TO_SEC(timer->total_ns);
653 double t_min = NS_TO_SEC(timer->min_ns);
654 double t_max = NS_TO_SEC(timer->max_ns);
655
656 jw_object_begin(&jw, 0);
657 event_fmt_prepare(event_name, __FILE__, __LINE__, NULL, &jw);
658 jw_object_string(&jw, "category", meta->category);
659 jw_object_string(&jw, "name", meta->name);
660 jw_object_intmax(&jw, "intervals", timer->interval_count);
661 jw_object_double(&jw, "t_total", 6, t_total);
662 jw_object_double(&jw, "t_min", 6, t_min);
663 jw_object_double(&jw, "t_max", 6, t_max);
664 jw_end(&jw);
665
666 tr2_dst_write_line(&tr2dst_event, &jw.json);
667 jw_release(&jw);
668 }
669
670 static void fn_counter(const struct tr2_counter_metadata *meta,
671 const struct tr2_counter *counter,
672 int is_final_data)
673 {
674 const char *event_name = is_final_data ? "counter" : "th_counter";
675 struct json_writer jw = JSON_WRITER_INIT;
676
677 jw_object_begin(&jw, 0);
678 event_fmt_prepare(event_name, __FILE__, __LINE__, NULL, &jw);
679 jw_object_string(&jw, "category", meta->category);
680 jw_object_string(&jw, "name", meta->name);
681 jw_object_intmax(&jw, "count", counter->value);
682 jw_end(&jw);
683
684 tr2_dst_write_line(&tr2dst_event, &jw.json);
685 jw_release(&jw);
686 }
687
688 struct tr2_tgt tr2_tgt_event = {
689 .pdst = &tr2dst_event,
690
691 .pfn_init = fn_init,
692 .pfn_term = fn_term,
693
694 .pfn_version_fl = fn_version_fl,
695 .pfn_start_fl = fn_start_fl,
696 .pfn_exit_fl = fn_exit_fl,
697 .pfn_signal = fn_signal,
698 .pfn_atexit = fn_atexit,
699 .pfn_error_va_fl = fn_error_va_fl,
700 .pfn_command_path_fl = fn_command_path_fl,
701 .pfn_command_ancestry_fl = fn_command_ancestry_fl,
702 .pfn_command_name_fl = fn_command_name_fl,
703 .pfn_command_mode_fl = fn_command_mode_fl,
704 .pfn_alias_fl = fn_alias_fl,
705 .pfn_child_start_fl = fn_child_start_fl,
706 .pfn_child_exit_fl = fn_child_exit_fl,
707 .pfn_child_ready_fl = fn_child_ready_fl,
708 .pfn_thread_start_fl = fn_thread_start_fl,
709 .pfn_thread_exit_fl = fn_thread_exit_fl,
710 .pfn_exec_fl = fn_exec_fl,
711 .pfn_exec_result_fl = fn_exec_result_fl,
712 .pfn_param_fl = fn_param_fl,
713 .pfn_repo_fl = fn_repo_fl,
714 .pfn_region_enter_printf_va_fl = fn_region_enter_printf_va_fl,
715 .pfn_region_leave_printf_va_fl = fn_region_leave_printf_va_fl,
716 .pfn_data_fl = fn_data_fl,
717 .pfn_data_json_fl = fn_data_json_fl,
718 .pfn_printf_va_fl = fn_printf_va_fl,
719 .pfn_timer = fn_timer,
720 .pfn_counter = fn_counter,
721 };