1
#include "git-compat-util.h"
3
#include "json-writer.h"
5
#include "run-command.h"
7
#include "trace2/tr2_dst.h"
8
#include "trace2/tr2_tbuf.h"
9
#include "trace2/tr2_sid.h"
10
#include "trace2/tr2_sysenv.h"
11
#include "trace2/tr2_tgt.h"
12
#include "trace2/tr2_tls.h"
13
#include "trace2/tr2_tmr.h"
15
static struct tr2_dst tr2dst_event = {
16
.sysenv_var = TR2_SYSENV_EVENT,
20
* The version number of the JSON data generated by the EVENT target in this
21
* source file. The version should be incremented if new event types are added,
22
* if existing fields are removed, or if there are significant changes in
23
* interpretation of existing events or fields. Smaller changes, such as adding
24
* a new field to an existing event, do not require an increment to the EVENT
27
#define TR2_EVENT_VERSION "3"
30
* Region nesting limit for messages written to the event target.
32
* The "region_enter" and "region_leave" messages (especially recursive
33
* messages such as those produced while diving the worktree or index)
34
* are primarily intended for the performance target during debugging.
36
* Some of the outer-most messages, however, may be of interest to the
37
* event target. Use the TR2_SYSENV_EVENT_NESTING setting to increase
38
* region details in the event target.
40
static int tr2env_event_max_nesting_levels = 2;
43
* Use the TR2_SYSENV_EVENT_BRIEF to omit the <time>, <file>, and
44
* <line> fields from most events.
46
static int tr2env_event_be_brief;
48
static int fn_init(void)
50
int want = tr2_dst_trace_want(&tr2dst_event);
59
nesting = tr2_sysenv_get(TR2_SYSENV_EVENT_NESTING);
60
if (nesting && *nesting && ((max_nesting = atoi(nesting)) > 0))
61
tr2env_event_max_nesting_levels = max_nesting;
63
brief = tr2_sysenv_get(TR2_SYSENV_EVENT_BRIEF);
64
if (brief && *brief &&
65
((want_brief = git_parse_maybe_bool(brief)) != -1))
66
tr2env_event_be_brief = want_brief;
71
static void fn_term(void)
73
tr2_dst_trace_disable(&tr2dst_event);
77
* Append common key-value pairs to the currently open JSON object.
78
* "event:"<event_name>"
80
* "thread":"<thread_name>"
83
* "line":<line_number>
86
static void event_fmt_prepare(const char *event_name, const char *file,
87
int line, const struct repository *repo,
88
struct json_writer *jw)
90
struct tr2tls_thread_ctx *ctx = tr2tls_get_self();
91
struct tr2_tbuf tb_now;
93
jw_object_string(jw, "event", event_name);
94
jw_object_string(jw, "sid", tr2_sid_get());
95
jw_object_string(jw, "thread", ctx->thread_name);
98
* In brief mode, only emit <time> on these 2 event types.
100
if (!tr2env_event_be_brief || !strcmp(event_name, "version") ||
101
!strcmp(event_name, "atexit")) {
102
tr2_tbuf_utc_datetime_extended(&tb_now);
103
jw_object_string(jw, "time", tb_now.buf);
106
if (!tr2env_event_be_brief && file && *file) {
107
jw_object_string(jw, "file", file);
108
jw_object_intmax(jw, "line", line);
112
jw_object_intmax(jw, "repo", repo->trace2_repo_id);
115
static void fn_too_many_files_fl(const char *file, int line)
117
const char *event_name = "too_many_files";
118
struct json_writer jw = JSON_WRITER_INIT;
120
jw_object_begin(&jw, 0);
121
event_fmt_prepare(event_name, file, line, NULL, &jw);
124
tr2_dst_write_line(&tr2dst_event, &jw.json);
128
static void fn_version_fl(const char *file, int line)
130
const char *event_name = "version";
131
struct json_writer jw = JSON_WRITER_INIT;
133
jw_object_begin(&jw, 0);
134
event_fmt_prepare(event_name, file, line, NULL, &jw);
135
jw_object_string(&jw, "evt", TR2_EVENT_VERSION);
136
jw_object_string(&jw, "exe", git_version_string);
139
tr2_dst_write_line(&tr2dst_event, &jw.json);
142
if (tr2dst_event.too_many_files)
143
fn_too_many_files_fl(file, line);
146
static void fn_start_fl(const char *file, int line,
147
uint64_t us_elapsed_absolute, const char **argv)
149
const char *event_name = "start";
150
struct json_writer jw = JSON_WRITER_INIT;
151
double t_abs = (double)us_elapsed_absolute / 1000000.0;
153
jw_object_begin(&jw, 0);
154
event_fmt_prepare(event_name, file, line, NULL, &jw);
155
jw_object_double(&jw, "t_abs", 6, t_abs);
156
jw_object_inline_begin_array(&jw, "argv");
157
jw_array_argv(&jw, argv);
161
tr2_dst_write_line(&tr2dst_event, &jw.json);
165
static void fn_exit_fl(const char *file, int line, uint64_t us_elapsed_absolute,
168
const char *event_name = "exit";
169
struct json_writer jw = JSON_WRITER_INIT;
170
double t_abs = (double)us_elapsed_absolute / 1000000.0;
172
jw_object_begin(&jw, 0);
173
event_fmt_prepare(event_name, file, line, NULL, &jw);
174
jw_object_double(&jw, "t_abs", 6, t_abs);
175
jw_object_intmax(&jw, "code", code);
178
tr2_dst_write_line(&tr2dst_event, &jw.json);
182
static void fn_signal(uint64_t us_elapsed_absolute, int signo)
184
const char *event_name = "signal";
185
struct json_writer jw = JSON_WRITER_INIT;
186
double t_abs = (double)us_elapsed_absolute / 1000000.0;
188
jw_object_begin(&jw, 0);
189
event_fmt_prepare(event_name, __FILE__, __LINE__, NULL, &jw);
190
jw_object_double(&jw, "t_abs", 6, t_abs);
191
jw_object_intmax(&jw, "signo", signo);
194
tr2_dst_write_line(&tr2dst_event, &jw.json);
198
static void fn_atexit(uint64_t us_elapsed_absolute, int code)
200
const char *event_name = "atexit";
201
struct json_writer jw = JSON_WRITER_INIT;
202
double t_abs = (double)us_elapsed_absolute / 1000000.0;
204
jw_object_begin(&jw, 0);
205
event_fmt_prepare(event_name, __FILE__, __LINE__, NULL, &jw);
206
jw_object_double(&jw, "t_abs", 6, t_abs);
207
jw_object_intmax(&jw, "code", code);
210
tr2_dst_write_line(&tr2dst_event, &jw.json);
214
static void maybe_add_string_va(struct json_writer *jw, const char *field_name,
215
const char *fmt, va_list ap)
219
struct strbuf buf = STRBUF_INIT;
221
va_copy(copy_ap, ap);
222
strbuf_vaddf(&buf, fmt, copy_ap);
225
jw_object_string(jw, field_name, buf.buf);
226
strbuf_release(&buf);
231
static void fn_error_va_fl(const char *file, int line, const char *fmt,
234
const char *event_name = "error";
235
struct json_writer jw = JSON_WRITER_INIT;
237
jw_object_begin(&jw, 0);
238
event_fmt_prepare(event_name, file, line, NULL, &jw);
239
maybe_add_string_va(&jw, "msg", fmt, ap);
241
* Also emit the format string as a field in case
242
* post-processors want to aggregate common error
243
* messages by type without argument fields (such
244
* as pathnames or branch names) cluttering it up.
247
jw_object_string(&jw, "fmt", fmt);
250
tr2_dst_write_line(&tr2dst_event, &jw.json);
254
static void fn_command_path_fl(const char *file, int line, const char *pathname)
256
const char *event_name = "cmd_path";
257
struct json_writer jw = JSON_WRITER_INIT;
259
jw_object_begin(&jw, 0);
260
event_fmt_prepare(event_name, file, line, NULL, &jw);
261
jw_object_string(&jw, "path", pathname);
264
tr2_dst_write_line(&tr2dst_event, &jw.json);
268
static void fn_command_ancestry_fl(const char *file, int line, const char **parent_names)
270
const char *event_name = "cmd_ancestry";
271
const char *parent_name = NULL;
272
struct json_writer jw = JSON_WRITER_INIT;
274
jw_object_begin(&jw, 0);
275
event_fmt_prepare(event_name, file, line, NULL, &jw);
276
jw_object_inline_begin_array(&jw, "ancestry");
278
while ((parent_name = *parent_names++))
279
jw_array_string(&jw, parent_name);
281
jw_end(&jw); /* 'ancestry' array */
282
jw_end(&jw); /* event object */
284
tr2_dst_write_line(&tr2dst_event, &jw.json);
288
static void fn_command_name_fl(const char *file, int line, const char *name,
289
const char *hierarchy)
291
const char *event_name = "cmd_name";
292
struct json_writer jw = JSON_WRITER_INIT;
294
jw_object_begin(&jw, 0);
295
event_fmt_prepare(event_name, file, line, NULL, &jw);
296
jw_object_string(&jw, "name", name);
297
if (hierarchy && *hierarchy)
298
jw_object_string(&jw, "hierarchy", hierarchy);
301
tr2_dst_write_line(&tr2dst_event, &jw.json);
305
static void fn_command_mode_fl(const char *file, int line, const char *mode)
307
const char *event_name = "cmd_mode";
308
struct json_writer jw = JSON_WRITER_INIT;
310
jw_object_begin(&jw, 0);
311
event_fmt_prepare(event_name, file, line, NULL, &jw);
312
jw_object_string(&jw, "name", mode);
315
tr2_dst_write_line(&tr2dst_event, &jw.json);
319
static void fn_alias_fl(const char *file, int line, const char *alias,
322
const char *event_name = "alias";
323
struct json_writer jw = JSON_WRITER_INIT;
325
jw_object_begin(&jw, 0);
326
event_fmt_prepare(event_name, file, line, NULL, &jw);
327
jw_object_string(&jw, "alias", alias);
328
jw_object_inline_begin_array(&jw, "argv");
329
jw_array_argv(&jw, argv);
333
tr2_dst_write_line(&tr2dst_event, &jw.json);
337
static void fn_child_start_fl(const char *file, int line,
338
uint64_t us_elapsed_absolute UNUSED,
339
const struct child_process *cmd)
341
const char *event_name = "child_start";
342
struct json_writer jw = JSON_WRITER_INIT;
344
jw_object_begin(&jw, 0);
345
event_fmt_prepare(event_name, file, line, NULL, &jw);
346
jw_object_intmax(&jw, "child_id", cmd->trace2_child_id);
347
if (cmd->trace2_hook_name) {
348
jw_object_string(&jw, "child_class", "hook");
349
jw_object_string(&jw, "hook_name", cmd->trace2_hook_name);
351
const char *child_class =
352
cmd->trace2_child_class ? cmd->trace2_child_class : "?";
353
jw_object_string(&jw, "child_class", child_class);
356
jw_object_string(&jw, "cd", cmd->dir);
357
jw_object_bool(&jw, "use_shell", cmd->use_shell);
358
jw_object_inline_begin_array(&jw, "argv");
360
jw_array_string(&jw, "git");
361
jw_array_argv(&jw, cmd->args.v);
365
tr2_dst_write_line(&tr2dst_event, &jw.json);
369
static void fn_child_exit_fl(const char *file, int line,
370
uint64_t us_elapsed_absolute UNUSED,
372
int code, uint64_t us_elapsed_child)
374
const char *event_name = "child_exit";
375
struct json_writer jw = JSON_WRITER_INIT;
376
double t_rel = (double)us_elapsed_child / 1000000.0;
378
jw_object_begin(&jw, 0);
379
event_fmt_prepare(event_name, file, line, NULL, &jw);
380
jw_object_intmax(&jw, "child_id", cid);
381
jw_object_intmax(&jw, "pid", pid);
382
jw_object_intmax(&jw, "code", code);
383
jw_object_double(&jw, "t_rel", 6, t_rel);
386
tr2_dst_write_line(&tr2dst_event, &jw.json);
391
static void fn_child_ready_fl(const char *file, int line,
392
uint64_t us_elapsed_absolute UNUSED,
394
const char *ready, uint64_t us_elapsed_child)
396
const char *event_name = "child_ready";
397
struct json_writer jw = JSON_WRITER_INIT;
398
double t_rel = (double)us_elapsed_child / 1000000.0;
400
jw_object_begin(&jw, 0);
401
event_fmt_prepare(event_name, file, line, NULL, &jw);
402
jw_object_intmax(&jw, "child_id", cid);
403
jw_object_intmax(&jw, "pid", pid);
404
jw_object_string(&jw, "ready", ready);
405
jw_object_double(&jw, "t_rel", 6, t_rel);
408
tr2_dst_write_line(&tr2dst_event, &jw.json);
413
static void fn_thread_start_fl(const char *file, int line,
414
uint64_t us_elapsed_absolute UNUSED)
416
const char *event_name = "thread_start";
417
struct json_writer jw = JSON_WRITER_INIT;
419
jw_object_begin(&jw, 0);
420
event_fmt_prepare(event_name, file, line, NULL, &jw);
423
tr2_dst_write_line(&tr2dst_event, &jw.json);
427
static void fn_thread_exit_fl(const char *file, int line,
428
uint64_t us_elapsed_absolute UNUSED,
429
uint64_t us_elapsed_thread)
431
const char *event_name = "thread_exit";
432
struct json_writer jw = JSON_WRITER_INIT;
433
double t_rel = (double)us_elapsed_thread / 1000000.0;
435
jw_object_begin(&jw, 0);
436
event_fmt_prepare(event_name, file, line, NULL, &jw);
437
jw_object_double(&jw, "t_rel", 6, t_rel);
440
tr2_dst_write_line(&tr2dst_event, &jw.json);
444
static void fn_exec_fl(const char *file, int line,
445
uint64_t us_elapsed_absolute UNUSED,
446
int exec_id, const char *exe, const char **argv)
448
const char *event_name = "exec";
449
struct json_writer jw = JSON_WRITER_INIT;
451
jw_object_begin(&jw, 0);
452
event_fmt_prepare(event_name, file, line, NULL, &jw);
453
jw_object_intmax(&jw, "exec_id", exec_id);
455
jw_object_string(&jw, "exe", exe);
456
jw_object_inline_begin_array(&jw, "argv");
457
jw_array_argv(&jw, argv);
461
tr2_dst_write_line(&tr2dst_event, &jw.json);
465
static void fn_exec_result_fl(const char *file, int line,
466
uint64_t us_elapsed_absolute UNUSED,
467
int exec_id, int code)
469
const char *event_name = "exec_result";
470
struct json_writer jw = JSON_WRITER_INIT;
472
jw_object_begin(&jw, 0);
473
event_fmt_prepare(event_name, file, line, NULL, &jw);
474
jw_object_intmax(&jw, "exec_id", exec_id);
475
jw_object_intmax(&jw, "code", code);
478
tr2_dst_write_line(&tr2dst_event, &jw.json);
482
static void fn_param_fl(const char *file, int line, const char *param,
483
const char *value, const struct key_value_info *kvi)
485
const char *event_name = "def_param";
486
struct json_writer jw = JSON_WRITER_INIT;
487
enum config_scope scope = kvi->scope;
488
const char *scope_name = config_scope_name(scope);
490
jw_object_begin(&jw, 0);
491
event_fmt_prepare(event_name, file, line, NULL, &jw);
492
jw_object_string(&jw, "scope", scope_name);
493
jw_object_string(&jw, "param", param);
494
jw_object_string(&jw, "value", value);
497
tr2_dst_write_line(&tr2dst_event, &jw.json);
501
static void fn_repo_fl(const char *file, int line,
502
const struct repository *repo)
504
const char *event_name = "def_repo";
505
struct json_writer jw = JSON_WRITER_INIT;
507
jw_object_begin(&jw, 0);
508
event_fmt_prepare(event_name, file, line, repo, &jw);
509
jw_object_string(&jw, "worktree", repo->worktree);
512
tr2_dst_write_line(&tr2dst_event, &jw.json);
516
static void fn_region_enter_printf_va_fl(const char *file, int line,
517
uint64_t us_elapsed_absolute UNUSED,
518
const char *category,
520
const struct repository *repo,
521
const char *fmt, va_list ap)
523
const char *event_name = "region_enter";
524
struct tr2tls_thread_ctx *ctx = tr2tls_get_self();
525
if (ctx->nr_open_regions <= tr2env_event_max_nesting_levels) {
526
struct json_writer jw = JSON_WRITER_INIT;
528
jw_object_begin(&jw, 0);
529
event_fmt_prepare(event_name, file, line, repo, &jw);
530
jw_object_intmax(&jw, "nesting", ctx->nr_open_regions);
532
jw_object_string(&jw, "category", category);
534
jw_object_string(&jw, "label", label);
535
maybe_add_string_va(&jw, "msg", fmt, ap);
538
tr2_dst_write_line(&tr2dst_event, &jw.json);
543
static void fn_region_leave_printf_va_fl(
544
const char *file, int line, uint64_t us_elapsed_absolute UNUSED,
545
uint64_t us_elapsed_region, const char *category, const char *label,
546
const struct repository *repo, const char *fmt, va_list ap)
548
const char *event_name = "region_leave";
549
struct tr2tls_thread_ctx *ctx = tr2tls_get_self();
550
if (ctx->nr_open_regions <= tr2env_event_max_nesting_levels) {
551
struct json_writer jw = JSON_WRITER_INIT;
552
double t_rel = (double)us_elapsed_region / 1000000.0;
554
jw_object_begin(&jw, 0);
555
event_fmt_prepare(event_name, file, line, repo, &jw);
556
jw_object_double(&jw, "t_rel", 6, t_rel);
557
jw_object_intmax(&jw, "nesting", ctx->nr_open_regions);
559
jw_object_string(&jw, "category", category);
561
jw_object_string(&jw, "label", label);
562
maybe_add_string_va(&jw, "msg", fmt, ap);
565
tr2_dst_write_line(&tr2dst_event, &jw.json);
570
static void fn_data_fl(const char *file, int line, uint64_t us_elapsed_absolute,
571
uint64_t us_elapsed_region, const char *category,
572
const struct repository *repo, const char *key,
575
const char *event_name = "data";
576
struct tr2tls_thread_ctx *ctx = tr2tls_get_self();
577
if (ctx->nr_open_regions <= tr2env_event_max_nesting_levels) {
578
struct json_writer jw = JSON_WRITER_INIT;
579
double t_abs = (double)us_elapsed_absolute / 1000000.0;
580
double t_rel = (double)us_elapsed_region / 1000000.0;
582
jw_object_begin(&jw, 0);
583
event_fmt_prepare(event_name, file, line, repo, &jw);
584
jw_object_double(&jw, "t_abs", 6, t_abs);
585
jw_object_double(&jw, "t_rel", 6, t_rel);
586
jw_object_intmax(&jw, "nesting", ctx->nr_open_regions);
587
jw_object_string(&jw, "category", category);
588
jw_object_string(&jw, "key", key);
589
jw_object_string(&jw, "value", value);
592
tr2_dst_write_line(&tr2dst_event, &jw.json);
597
static void fn_data_json_fl(const char *file, int line,
598
uint64_t us_elapsed_absolute,
599
uint64_t us_elapsed_region, const char *category,
600
const struct repository *repo, const char *key,
601
const struct json_writer *value)
603
const char *event_name = "data_json";
604
struct tr2tls_thread_ctx *ctx = tr2tls_get_self();
605
if (ctx->nr_open_regions <= tr2env_event_max_nesting_levels) {
606
struct json_writer jw = JSON_WRITER_INIT;
607
double t_abs = (double)us_elapsed_absolute / 1000000.0;
608
double t_rel = (double)us_elapsed_region / 1000000.0;
610
jw_object_begin(&jw, 0);
611
event_fmt_prepare(event_name, file, line, repo, &jw);
612
jw_object_double(&jw, "t_abs", 6, t_abs);
613
jw_object_double(&jw, "t_rel", 6, t_rel);
614
jw_object_intmax(&jw, "nesting", ctx->nr_open_regions);
615
jw_object_string(&jw, "category", category);
616
jw_object_string(&jw, "key", key);
617
jw_object_sub_jw(&jw, "value", value);
620
tr2_dst_write_line(&tr2dst_event, &jw.json);
625
static void fn_timer(const struct tr2_timer_metadata *meta,
626
const struct tr2_timer *timer,
629
const char *event_name = is_final_data ? "timer" : "th_timer";
630
struct json_writer jw = JSON_WRITER_INIT;
631
double t_total = NS_TO_SEC(timer->total_ns);
632
double t_min = NS_TO_SEC(timer->min_ns);
633
double t_max = NS_TO_SEC(timer->max_ns);
635
jw_object_begin(&jw, 0);
636
event_fmt_prepare(event_name, __FILE__, __LINE__, NULL, &jw);
637
jw_object_string(&jw, "category", meta->category);
638
jw_object_string(&jw, "name", meta->name);
639
jw_object_intmax(&jw, "intervals", timer->interval_count);
640
jw_object_double(&jw, "t_total", 6, t_total);
641
jw_object_double(&jw, "t_min", 6, t_min);
642
jw_object_double(&jw, "t_max", 6, t_max);
645
tr2_dst_write_line(&tr2dst_event, &jw.json);
649
static void fn_counter(const struct tr2_counter_metadata *meta,
650
const struct tr2_counter *counter,
653
const char *event_name = is_final_data ? "counter" : "th_counter";
654
struct json_writer jw = JSON_WRITER_INIT;
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, "count", counter->value);
663
tr2_dst_write_line(&tr2dst_event, &jw.json);
667
struct tr2_tgt tr2_tgt_event = {
668
.pdst = &tr2dst_event,
673
.pfn_version_fl = fn_version_fl,
674
.pfn_start_fl = fn_start_fl,
675
.pfn_exit_fl = fn_exit_fl,
676
.pfn_signal = fn_signal,
677
.pfn_atexit = fn_atexit,
678
.pfn_error_va_fl = fn_error_va_fl,
679
.pfn_command_path_fl = fn_command_path_fl,
680
.pfn_command_ancestry_fl = fn_command_ancestry_fl,
681
.pfn_command_name_fl = fn_command_name_fl,
682
.pfn_command_mode_fl = fn_command_mode_fl,
683
.pfn_alias_fl = fn_alias_fl,
684
.pfn_child_start_fl = fn_child_start_fl,
685
.pfn_child_exit_fl = fn_child_exit_fl,
686
.pfn_child_ready_fl = fn_child_ready_fl,
687
.pfn_thread_start_fl = fn_thread_start_fl,
688
.pfn_thread_exit_fl = fn_thread_exit_fl,
689
.pfn_exec_fl = fn_exec_fl,
690
.pfn_exec_result_fl = fn_exec_result_fl,
691
.pfn_param_fl = fn_param_fl,
692
.pfn_repo_fl = fn_repo_fl,
693
.pfn_region_enter_printf_va_fl = fn_region_enter_printf_va_fl,
694
.pfn_region_leave_printf_va_fl = fn_region_leave_printf_va_fl,
695
.pfn_data_fl = fn_data_fl,
696
.pfn_data_json_fl = fn_data_json_fl,
697
.pfn_printf_va_fl = NULL,
698
.pfn_timer = fn_timer,
699
.pfn_counter = fn_counter,