Coverage Report

Created: 2025-12-31 07:01

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/git/trace2/tr2_tgt_event.c
Line
Count
Source
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
0
#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
0
{
52
0
  int want = tr2_dst_trace_want(&tr2dst_event);
53
0
  int max_nesting;
54
0
  int want_brief;
55
0
  const char *nesting;
56
0
  const char *brief;
57
58
0
  if (!want)
59
0
    return want;
60
61
0
  nesting = tr2_sysenv_get(TR2_SYSENV_EVENT_NESTING);
62
0
  if (nesting && *nesting && ((max_nesting = atoi(nesting)) > 0))
63
0
    tr2env_event_max_nesting_levels = max_nesting;
64
65
0
  brief = tr2_sysenv_get(TR2_SYSENV_EVENT_BRIEF);
66
0
  if (brief && *brief &&
67
0
      ((want_brief = git_parse_maybe_bool(brief)) != -1))
68
0
    tr2env_event_be_brief = want_brief;
69
70
0
  return want;
71
0
}
72
73
static void fn_term(void)
74
0
{
75
0
  tr2_dst_trace_disable(&tr2dst_event);
76
0
}
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
0
{
92
0
  struct tr2tls_thread_ctx *ctx = tr2tls_get_self();
93
0
  struct tr2_tbuf tb_now;
94
95
0
  jw_object_string(jw, "event", event_name);
96
0
  jw_object_string(jw, "sid", tr2_sid_get());
97
0
  jw_object_string(jw, "thread", ctx->thread_name);
98
99
  /*
100
   * In brief mode, only emit <time> on these 2 event types.
101
   */
102
0
  if (!tr2env_event_be_brief || !strcmp(event_name, "version") ||
103
0
      !strcmp(event_name, "atexit")) {
104
0
    tr2_tbuf_utc_datetime_extended(&tb_now);
105
0
    jw_object_string(jw, "time", tb_now.buf);
106
0
  }
107
108
0
  if (!tr2env_event_be_brief && file && *file) {
109
0
    jw_object_string(jw, "file", file);
110
0
    jw_object_intmax(jw, "line", line);
111
0
  }
112
113
0
  if (repo)
114
0
    jw_object_intmax(jw, "repo", repo->trace2_repo_id);
115
0
}
116
117
static void fn_too_many_files_fl(const char *file, int line)
118
0
{
119
0
  const char *event_name = "too_many_files";
120
0
  struct json_writer jw = JSON_WRITER_INIT;
121
122
0
  jw_object_begin(&jw, 0);
123
0
  event_fmt_prepare(event_name, file, line, NULL, &jw);
124
0
  jw_end(&jw);
125
126
0
  tr2_dst_write_line(&tr2dst_event, &jw.json);
127
0
  jw_release(&jw);
128
0
}
129
130
static void fn_version_fl(const char *file, int line)
131
0
{
132
0
  const char *event_name = "version";
133
0
  struct json_writer jw = JSON_WRITER_INIT;
134
135
0
  jw_object_begin(&jw, 0);
136
0
  event_fmt_prepare(event_name, file, line, NULL, &jw);
137
0
  jw_object_string(&jw, "evt", TR2_EVENT_VERSION);
138
0
  jw_object_string(&jw, "exe", git_version_string);
139
0
  jw_end(&jw);
140
141
0
  tr2_dst_write_line(&tr2dst_event, &jw.json);
142
0
  jw_release(&jw);
143
144
0
  if (tr2dst_event.too_many_files)
145
0
    fn_too_many_files_fl(file, line);
146
0
}
147
148
static void fn_start_fl(const char *file, int line,
149
      uint64_t us_elapsed_absolute, const char **argv)
150
0
{
151
0
  const char *event_name = "start";
152
0
  struct json_writer jw = JSON_WRITER_INIT;
153
0
  double t_abs = (double)us_elapsed_absolute / 1000000.0;
154
155
0
  jw_object_begin(&jw, 0);
156
0
  event_fmt_prepare(event_name, file, line, NULL, &jw);
157
0
  jw_object_double(&jw, "t_abs", 6, t_abs);
158
0
  jw_object_inline_begin_array(&jw, "argv");
159
0
  jw_array_argv(&jw, argv);
160
0
  jw_end(&jw);
161
0
  jw_end(&jw);
162
163
0
  tr2_dst_write_line(&tr2dst_event, &jw.json);
164
0
  jw_release(&jw);
165
0
}
166
167
static void fn_exit_fl(const char *file, int line, uint64_t us_elapsed_absolute,
168
           int code)
169
0
{
170
0
  const char *event_name = "exit";
171
0
  struct json_writer jw = JSON_WRITER_INIT;
172
0
  double t_abs = (double)us_elapsed_absolute / 1000000.0;
173
174
0
  jw_object_begin(&jw, 0);
175
0
  event_fmt_prepare(event_name, file, line, NULL, &jw);
176
0
  jw_object_double(&jw, "t_abs", 6, t_abs);
177
0
  jw_object_intmax(&jw, "code", code);
178
0
  jw_end(&jw);
179
180
0
  tr2_dst_write_line(&tr2dst_event, &jw.json);
181
0
  jw_release(&jw);
182
0
}
183
184
static void fn_signal(uint64_t us_elapsed_absolute, int signo)
185
0
{
186
0
  const char *event_name = "signal";
187
0
  struct json_writer jw = JSON_WRITER_INIT;
188
0
  double t_abs = (double)us_elapsed_absolute / 1000000.0;
189
190
0
  jw_object_begin(&jw, 0);
191
0
  event_fmt_prepare(event_name, __FILE__, __LINE__, NULL, &jw);
192
0
  jw_object_double(&jw, "t_abs", 6, t_abs);
193
0
  jw_object_intmax(&jw, "signo", signo);
194
0
  jw_end(&jw);
195
196
0
  tr2_dst_write_line(&tr2dst_event, &jw.json);
197
0
  jw_release(&jw);
198
0
}
199
200
static void fn_atexit(uint64_t us_elapsed_absolute, int code)
201
0
{
202
0
  const char *event_name = "atexit";
203
0
  struct json_writer jw = JSON_WRITER_INIT;
204
0
  double t_abs = (double)us_elapsed_absolute / 1000000.0;
205
206
0
  jw_object_begin(&jw, 0);
207
0
  event_fmt_prepare(event_name, __FILE__, __LINE__, NULL, &jw);
208
0
  jw_object_double(&jw, "t_abs", 6, t_abs);
209
0
  jw_object_intmax(&jw, "code", code);
210
0
  jw_end(&jw);
211
212
0
  tr2_dst_write_line(&tr2dst_event, &jw.json);
213
0
  jw_release(&jw);
214
0
}
215
216
static void maybe_add_string_va(struct json_writer *jw, const char *field_name,
217
        const char *fmt, va_list ap)
218
0
{
219
0
  if (fmt && *fmt) {
220
0
    va_list copy_ap;
221
0
    struct strbuf buf = STRBUF_INIT;
222
223
0
    va_copy(copy_ap, ap);
224
0
    strbuf_vaddf(&buf, fmt, copy_ap);
225
0
    va_end(copy_ap);
226
227
0
    jw_object_string(jw, field_name, buf.buf);
228
0
    strbuf_release(&buf);
229
0
    return;
230
0
  }
231
0
}
232
233
static void fn_error_va_fl(const char *file, int line, const char *fmt,
234
         va_list ap)
235
0
{
236
0
  const char *event_name = "error";
237
0
  struct json_writer jw = JSON_WRITER_INIT;
238
239
0
  jw_object_begin(&jw, 0);
240
0
  event_fmt_prepare(event_name, file, line, NULL, &jw);
241
0
  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
0
  if (fmt && *fmt)
249
0
    jw_object_string(&jw, "fmt", fmt);
250
0
  jw_end(&jw);
251
252
0
  tr2_dst_write_line(&tr2dst_event, &jw.json);
253
0
  jw_release(&jw);
254
0
}
255
256
static void fn_command_path_fl(const char *file, int line, const char *pathname)
257
0
{
258
0
  const char *event_name = "cmd_path";
259
0
  struct json_writer jw = JSON_WRITER_INIT;
260
261
0
  jw_object_begin(&jw, 0);
262
0
  event_fmt_prepare(event_name, file, line, NULL, &jw);
263
0
  jw_object_string(&jw, "path", pathname);
264
0
  jw_end(&jw);
265
266
0
  tr2_dst_write_line(&tr2dst_event, &jw.json);
267
0
  jw_release(&jw);
268
0
}
269
270
static void fn_command_ancestry_fl(const char *file, int line, const char **parent_names)
271
0
{
272
0
  const char *event_name = "cmd_ancestry";
273
0
  const char *parent_name = NULL;
274
0
  struct json_writer jw = JSON_WRITER_INIT;
275
276
0
  jw_object_begin(&jw, 0);
277
0
  event_fmt_prepare(event_name, file, line, NULL, &jw);
278
0
  jw_object_inline_begin_array(&jw, "ancestry");
279
280
0
  while ((parent_name = *parent_names++))
281
0
    jw_array_string(&jw, parent_name);
282
283
0
  jw_end(&jw); /* 'ancestry' array */
284
0
  jw_end(&jw); /* event object */
285
286
0
  tr2_dst_write_line(&tr2dst_event, &jw.json);
287
0
  jw_release(&jw);
288
0
}
289
290
static void fn_command_name_fl(const char *file, int line, const char *name,
291
             const char *hierarchy)
292
0
{
293
0
  const char *event_name = "cmd_name";
294
0
  struct json_writer jw = JSON_WRITER_INIT;
295
296
0
  jw_object_begin(&jw, 0);
297
0
  event_fmt_prepare(event_name, file, line, NULL, &jw);
298
0
  jw_object_string(&jw, "name", name);
299
0
  if (hierarchy && *hierarchy)
300
0
    jw_object_string(&jw, "hierarchy", hierarchy);
301
0
  jw_end(&jw);
302
303
0
  tr2_dst_write_line(&tr2dst_event, &jw.json);
304
0
  jw_release(&jw);
305
0
}
306
307
static void fn_command_mode_fl(const char *file, int line, const char *mode)
308
0
{
309
0
  const char *event_name = "cmd_mode";
310
0
  struct json_writer jw = JSON_WRITER_INIT;
311
312
0
  jw_object_begin(&jw, 0);
313
0
  event_fmt_prepare(event_name, file, line, NULL, &jw);
314
0
  jw_object_string(&jw, "name", mode);
315
0
  jw_end(&jw);
316
317
0
  tr2_dst_write_line(&tr2dst_event, &jw.json);
318
0
  jw_release(&jw);
319
0
}
320
321
static void fn_alias_fl(const char *file, int line, const char *alias,
322
      const char **argv)
323
0
{
324
0
  const char *event_name = "alias";
325
0
  struct json_writer jw = JSON_WRITER_INIT;
326
327
0
  jw_object_begin(&jw, 0);
328
0
  event_fmt_prepare(event_name, file, line, NULL, &jw);
329
0
  jw_object_string(&jw, "alias", alias);
330
0
  jw_object_inline_begin_array(&jw, "argv");
331
0
  jw_array_argv(&jw, argv);
332
0
  jw_end(&jw);
333
0
  jw_end(&jw);
334
335
0
  tr2_dst_write_line(&tr2dst_event, &jw.json);
336
0
  jw_release(&jw);
337
0
}
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
0
{
343
0
  const char *event_name = "child_start";
344
0
  struct json_writer jw = JSON_WRITER_INIT;
345
346
0
  jw_object_begin(&jw, 0);
347
0
  event_fmt_prepare(event_name, file, line, NULL, &jw);
348
0
  jw_object_intmax(&jw, "child_id", cmd->trace2_child_id);
349
0
  if (cmd->trace2_hook_name) {
350
0
    jw_object_string(&jw, "child_class", "hook");
351
0
    jw_object_string(&jw, "hook_name", cmd->trace2_hook_name);
352
0
  } else {
353
0
    const char *child_class =
354
0
      cmd->trace2_child_class ? cmd->trace2_child_class : "?";
355
0
    jw_object_string(&jw, "child_class", child_class);
356
0
  }
357
0
  if (cmd->dir)
358
0
    jw_object_string(&jw, "cd", cmd->dir);
359
0
  jw_object_bool(&jw, "use_shell", cmd->use_shell);
360
0
  jw_object_inline_begin_array(&jw, "argv");
361
0
  if (cmd->git_cmd)
362
0
    jw_array_string(&jw, "git");
363
0
  jw_array_argv(&jw, cmd->args.v);
364
0
  jw_end(&jw);
365
0
  jw_end(&jw);
366
367
0
  tr2_dst_write_line(&tr2dst_event, &jw.json);
368
0
  jw_release(&jw);
369
0
}
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
0
{
376
0
  const char *event_name = "child_exit";
377
0
  struct json_writer jw = JSON_WRITER_INIT;
378
0
  double t_rel = (double)us_elapsed_child / 1000000.0;
379
380
0
  jw_object_begin(&jw, 0);
381
0
  event_fmt_prepare(event_name, file, line, NULL, &jw);
382
0
  jw_object_intmax(&jw, "child_id", cid);
383
0
  jw_object_intmax(&jw, "pid", pid);
384
0
  jw_object_intmax(&jw, "code", code);
385
0
  jw_object_double(&jw, "t_rel", 6, t_rel);
386
0
  jw_end(&jw);
387
388
0
  tr2_dst_write_line(&tr2dst_event, &jw.json);
389
390
0
  jw_release(&jw);
391
0
}
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
0
{
398
0
  const char *event_name = "child_ready";
399
0
  struct json_writer jw = JSON_WRITER_INIT;
400
0
  double t_rel = (double)us_elapsed_child / 1000000.0;
401
402
0
  jw_object_begin(&jw, 0);
403
0
  event_fmt_prepare(event_name, file, line, NULL, &jw);
404
0
  jw_object_intmax(&jw, "child_id", cid);
405
0
  jw_object_intmax(&jw, "pid", pid);
406
0
  jw_object_string(&jw, "ready", ready);
407
0
  jw_object_double(&jw, "t_rel", 6, t_rel);
408
0
  jw_end(&jw);
409
410
0
  tr2_dst_write_line(&tr2dst_event, &jw.json);
411
412
0
  jw_release(&jw);
413
0
}
414
415
static void fn_thread_start_fl(const char *file, int line,
416
             uint64_t us_elapsed_absolute UNUSED)
417
0
{
418
0
  const char *event_name = "thread_start";
419
0
  struct json_writer jw = JSON_WRITER_INIT;
420
421
0
  jw_object_begin(&jw, 0);
422
0
  event_fmt_prepare(event_name, file, line, NULL, &jw);
423
0
  jw_end(&jw);
424
425
0
  tr2_dst_write_line(&tr2dst_event, &jw.json);
426
0
  jw_release(&jw);
427
0
}
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
0
{
433
0
  const char *event_name = "thread_exit";
434
0
  struct json_writer jw = JSON_WRITER_INIT;
435
0
  double t_rel = (double)us_elapsed_thread / 1000000.0;
436
437
0
  jw_object_begin(&jw, 0);
438
0
  event_fmt_prepare(event_name, file, line, NULL, &jw);
439
0
  jw_object_double(&jw, "t_rel", 6, t_rel);
440
0
  jw_end(&jw);
441
442
0
  tr2_dst_write_line(&tr2dst_event, &jw.json);
443
0
  jw_release(&jw);
444
0
}
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
0
{
450
0
  const char *event_name = "exec";
451
0
  struct json_writer jw = JSON_WRITER_INIT;
452
453
0
  jw_object_begin(&jw, 0);
454
0
  event_fmt_prepare(event_name, file, line, NULL, &jw);
455
0
  jw_object_intmax(&jw, "exec_id", exec_id);
456
0
  if (exe)
457
0
    jw_object_string(&jw, "exe", exe);
458
0
  jw_object_inline_begin_array(&jw, "argv");
459
0
  jw_array_argv(&jw, argv);
460
0
  jw_end(&jw);
461
0
  jw_end(&jw);
462
463
0
  tr2_dst_write_line(&tr2dst_event, &jw.json);
464
0
  jw_release(&jw);
465
0
}
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
0
{
471
0
  const char *event_name = "exec_result";
472
0
  struct json_writer jw = JSON_WRITER_INIT;
473
474
0
  jw_object_begin(&jw, 0);
475
0
  event_fmt_prepare(event_name, file, line, NULL, &jw);
476
0
  jw_object_intmax(&jw, "exec_id", exec_id);
477
0
  jw_object_intmax(&jw, "code", code);
478
0
  jw_end(&jw);
479
480
0
  tr2_dst_write_line(&tr2dst_event, &jw.json);
481
0
  jw_release(&jw);
482
0
}
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
0
{
487
0
  const char *event_name = "def_param";
488
0
  struct json_writer jw = JSON_WRITER_INIT;
489
0
  enum config_scope scope = kvi->scope;
490
0
  const char *scope_name = config_scope_name(scope);
491
492
0
  jw_object_begin(&jw, 0);
493
0
  event_fmt_prepare(event_name, file, line, NULL, &jw);
494
0
  jw_object_string(&jw, "scope", scope_name);
495
0
  jw_object_string(&jw, "param", param);
496
0
  if (value)
497
0
    jw_object_string(&jw, "value", value);
498
0
  jw_end(&jw);
499
500
0
  tr2_dst_write_line(&tr2dst_event, &jw.json);
501
0
  jw_release(&jw);
502
0
}
503
504
static void fn_repo_fl(const char *file, int line,
505
           const struct repository *repo)
506
0
{
507
0
  const char *event_name = "def_repo";
508
0
  struct json_writer jw = JSON_WRITER_INIT;
509
510
0
  jw_object_begin(&jw, 0);
511
0
  event_fmt_prepare(event_name, file, line, repo, &jw);
512
0
  jw_object_string(&jw, "worktree", repo->worktree);
513
0
  jw_end(&jw);
514
515
0
  tr2_dst_write_line(&tr2dst_event, &jw.json);
516
0
  jw_release(&jw);
517
0
}
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
0
{
526
0
  const char *event_name = "region_enter";
527
0
  struct tr2tls_thread_ctx *ctx = tr2tls_get_self();
528
0
  if (ctx->nr_open_regions <= tr2env_event_max_nesting_levels) {
529
0
    struct json_writer jw = JSON_WRITER_INIT;
530
531
0
    jw_object_begin(&jw, 0);
532
0
    event_fmt_prepare(event_name, file, line, repo, &jw);
533
0
    jw_object_intmax(&jw, "nesting", ctx->nr_open_regions);
534
0
    if (category)
535
0
      jw_object_string(&jw, "category", category);
536
0
    if (label)
537
0
      jw_object_string(&jw, "label", label);
538
0
    maybe_add_string_va(&jw, "msg", fmt, ap);
539
0
    jw_end(&jw);
540
541
0
    tr2_dst_write_line(&tr2dst_event, &jw.json);
542
0
    jw_release(&jw);
543
0
  }
544
0
}
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
0
{
551
0
  const char *event_name = "region_leave";
552
0
  struct tr2tls_thread_ctx *ctx = tr2tls_get_self();
553
0
  if (ctx->nr_open_regions <= tr2env_event_max_nesting_levels) {
554
0
    struct json_writer jw = JSON_WRITER_INIT;
555
0
    double t_rel = (double)us_elapsed_region / 1000000.0;
556
557
0
    jw_object_begin(&jw, 0);
558
0
    event_fmt_prepare(event_name, file, line, repo, &jw);
559
0
    jw_object_double(&jw, "t_rel", 6, t_rel);
560
0
    jw_object_intmax(&jw, "nesting", ctx->nr_open_regions);
561
0
    if (category)
562
0
      jw_object_string(&jw, "category", category);
563
0
    if (label)
564
0
      jw_object_string(&jw, "label", label);
565
0
    maybe_add_string_va(&jw, "msg", fmt, ap);
566
0
    jw_end(&jw);
567
568
0
    tr2_dst_write_line(&tr2dst_event, &jw.json);
569
0
    jw_release(&jw);
570
0
  }
571
0
}
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
0
{
578
0
  const char *event_name = "data";
579
0
  struct tr2tls_thread_ctx *ctx = tr2tls_get_self();
580
0
  if (ctx->nr_open_regions <= tr2env_event_max_nesting_levels) {
581
0
    struct json_writer jw = JSON_WRITER_INIT;
582
0
    double t_abs = (double)us_elapsed_absolute / 1000000.0;
583
0
    double t_rel = (double)us_elapsed_region / 1000000.0;
584
585
0
    jw_object_begin(&jw, 0);
586
0
    event_fmt_prepare(event_name, file, line, repo, &jw);
587
0
    jw_object_double(&jw, "t_abs", 6, t_abs);
588
0
    jw_object_double(&jw, "t_rel", 6, t_rel);
589
0
    jw_object_intmax(&jw, "nesting", ctx->nr_open_regions);
590
0
    jw_object_string(&jw, "category", category);
591
0
    jw_object_string(&jw, "key", key);
592
0
    jw_object_string(&jw, "value", value);
593
0
    jw_end(&jw);
594
595
0
    tr2_dst_write_line(&tr2dst_event, &jw.json);
596
0
    jw_release(&jw);
597
0
  }
598
0
}
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
0
{
606
0
  const char *event_name = "data_json";
607
0
  struct tr2tls_thread_ctx *ctx = tr2tls_get_self();
608
0
  if (ctx->nr_open_regions <= tr2env_event_max_nesting_levels) {
609
0
    struct json_writer jw = JSON_WRITER_INIT;
610
0
    double t_abs = (double)us_elapsed_absolute / 1000000.0;
611
0
    double t_rel = (double)us_elapsed_region / 1000000.0;
612
613
0
    jw_object_begin(&jw, 0);
614
0
    event_fmt_prepare(event_name, file, line, repo, &jw);
615
0
    jw_object_double(&jw, "t_abs", 6, t_abs);
616
0
    jw_object_double(&jw, "t_rel", 6, t_rel);
617
0
    jw_object_intmax(&jw, "nesting", ctx->nr_open_regions);
618
0
    jw_object_string(&jw, "category", category);
619
0
    jw_object_string(&jw, "key", key);
620
0
    jw_object_sub_jw(&jw, "value", value);
621
0
    jw_end(&jw);
622
623
0
    tr2_dst_write_line(&tr2dst_event, &jw.json);
624
0
    jw_release(&jw);
625
0
  }
626
0
}
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
0
{
632
0
  const char *event_name = "printf";
633
0
  struct json_writer jw = JSON_WRITER_INIT;
634
0
  double t_abs = (double)us_elapsed_absolute / 1000000.0;
635
636
0
  jw_object_begin(&jw, 0);
637
0
  event_fmt_prepare(event_name, file, line, NULL, &jw);
638
0
  jw_object_double(&jw, "t_abs", 6, t_abs);
639
0
  maybe_add_string_va(&jw, "msg", fmt, ap);
640
0
  jw_end(&jw);
641
642
0
  tr2_dst_write_line(&tr2dst_event, &jw.json);
643
0
  jw_release(&jw);
644
0
}
645
646
static void fn_timer(const struct tr2_timer_metadata *meta,
647
         const struct tr2_timer *timer,
648
         int is_final_data)
649
0
{
650
0
  const char *event_name = is_final_data ? "timer" : "th_timer";
651
0
  struct json_writer jw = JSON_WRITER_INIT;
652
0
  double t_total = NS_TO_SEC(timer->total_ns);
653
0
  double t_min = NS_TO_SEC(timer->min_ns);
654
0
  double t_max = NS_TO_SEC(timer->max_ns);
655
656
0
  jw_object_begin(&jw, 0);
657
0
  event_fmt_prepare(event_name, __FILE__, __LINE__, NULL, &jw);
658
0
  jw_object_string(&jw, "category", meta->category);
659
0
  jw_object_string(&jw, "name", meta->name);
660
0
  jw_object_intmax(&jw, "intervals", timer->interval_count);
661
0
  jw_object_double(&jw, "t_total", 6, t_total);
662
0
  jw_object_double(&jw, "t_min", 6, t_min);
663
0
  jw_object_double(&jw, "t_max", 6, t_max);
664
0
  jw_end(&jw);
665
666
0
  tr2_dst_write_line(&tr2dst_event, &jw.json);
667
0
  jw_release(&jw);
668
0
}
669
670
static void fn_counter(const struct tr2_counter_metadata *meta,
671
           const struct tr2_counter *counter,
672
           int is_final_data)
673
0
{
674
0
  const char *event_name = is_final_data ? "counter" : "th_counter";
675
0
  struct json_writer jw = JSON_WRITER_INIT;
676
677
0
  jw_object_begin(&jw, 0);
678
0
  event_fmt_prepare(event_name, __FILE__, __LINE__, NULL, &jw);
679
0
  jw_object_string(&jw, "category", meta->category);
680
0
  jw_object_string(&jw, "name", meta->name);
681
0
  jw_object_intmax(&jw, "count", counter->value);
682
0
  jw_end(&jw);
683
684
0
  tr2_dst_write_line(&tr2dst_event, &jw.json);
685
0
  jw_release(&jw);
686
0
}
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
};