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