Coverage Report

Created: 2024-09-08 06:23

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