|
4 | 4 | #include "json-writer.h"
|
5 | 5 | #include "sigchain.h"
|
6 | 6 | #include "argv-array.h"
|
| 7 | +#include "run-command.h" |
7 | 8 |
|
8 | 9 | #if !defined(STRUCTURED_LOGGING)
|
9 | 10 | /*
|
@@ -48,6 +49,23 @@ struct aux_data_array {
|
48 | 49 | static struct aux_data_array my__aux_data;
|
49 | 50 | static void format_and_free_aux_data(struct json_writer *jw);
|
50 | 51 |
|
| 52 | +struct child_data { |
| 53 | + uint64_t start_ns; |
| 54 | + uint64_t end_ns; |
| 55 | + struct json_writer jw_argv; |
| 56 | + unsigned int is_running:1; |
| 57 | + unsigned int is_git_cmd:1; |
| 58 | + unsigned int use_shell:1; |
| 59 | +}; |
| 60 | + |
| 61 | +struct child_data_array { |
| 62 | + struct child_data **array; |
| 63 | + size_t nr, alloc; |
| 64 | +}; |
| 65 | + |
| 66 | +static struct child_data_array my__child_data; |
| 67 | +static void free_children(void); |
| 68 | + |
51 | 69 | static uint64_t my__start_time;
|
52 | 70 | static uint64_t my__exit_time;
|
53 | 71 | static int my__is_config_loaded;
|
@@ -283,10 +301,11 @@ static void emit_exit_event(void)
|
283 | 301 | }
|
284 | 302 |
|
285 | 303 | static void emit_detail_event(const char *category, const char *label,
|
| 304 | + uint64_t clock_ns, |
286 | 305 | const struct json_writer *data)
|
287 | 306 | {
|
288 | 307 | struct json_writer jw = JSON_WRITER_INIT;
|
289 |
| - uint64_t clock_us = getnanotime() / 1000; |
| 308 | + uint64_t clock_us = clock_ns / 1000; |
290 | 309 |
|
291 | 310 | /* build "detail" event */
|
292 | 311 | jw_object_begin(&jw, my__is_pretty);
|
@@ -435,6 +454,7 @@ static void do_final_steps(int in_signal)
|
435 | 454 | jw_release(&my__errors);
|
436 | 455 | strbuf_release(&my__session_id);
|
437 | 456 | free_timers();
|
| 457 | + free_children(); |
438 | 458 | }
|
439 | 459 |
|
440 | 460 | static void slog_atexit(void)
|
@@ -580,7 +600,7 @@ void slog_emit_detail_event(const char *category, const char *label,
|
580 | 600 | BUG("unterminated slog.detail data: '%s' '%s' '%s'",
|
581 | 601 | category, label, data->json.buf);
|
582 | 602 |
|
583 |
| - emit_detail_event(category, label, data); |
| 603 | + emit_detail_event(category, label, getnanotime(), data); |
584 | 604 | }
|
585 | 605 |
|
586 | 606 | int slog_start_timer(const char *category, const char *name)
|
@@ -815,4 +835,134 @@ static void format_and_free_aux_data(struct json_writer *jw)
|
815 | 835 | my__aux_data.alloc = 0;
|
816 | 836 | }
|
817 | 837 |
|
| 838 | +static struct child_data *alloc_child_data(const struct child_process *cmd) |
| 839 | +{ |
| 840 | + struct child_data *cd = xcalloc(1, sizeof(struct child_data)); |
| 841 | + |
| 842 | + cd->start_ns = getnanotime(); |
| 843 | + cd->is_running = 1; |
| 844 | + cd->is_git_cmd = cmd->git_cmd; |
| 845 | + cd->use_shell = cmd->use_shell; |
| 846 | + |
| 847 | + jw_init(&cd->jw_argv); |
| 848 | + |
| 849 | + jw_array_begin(&cd->jw_argv, my__is_pretty); |
| 850 | + { |
| 851 | + jw_array_argv(&cd->jw_argv, cmd->argv); |
| 852 | + } |
| 853 | + jw_end(&cd->jw_argv); |
| 854 | + |
| 855 | + return cd; |
| 856 | +} |
| 857 | + |
| 858 | +static int insert_child_data(struct child_data *cd) |
| 859 | +{ |
| 860 | + int child_id = my__child_data.nr; |
| 861 | + |
| 862 | + ALLOC_GROW(my__child_data.array, my__child_data.nr + 1, |
| 863 | + my__child_data.alloc); |
| 864 | + my__child_data.array[my__child_data.nr++] = cd; |
| 865 | + |
| 866 | + return child_id; |
| 867 | +} |
| 868 | + |
| 869 | +int slog_child_starting(const struct child_process *cmd) |
| 870 | +{ |
| 871 | + struct child_data *cd; |
| 872 | + int child_id; |
| 873 | + |
| 874 | + if (!slog_is_enabled()) |
| 875 | + return SLOG_UNDEFINED_CHILD_ID; |
| 876 | + |
| 877 | + /* |
| 878 | + * If we have not yet written a cmd_start event (and even if |
| 879 | + * we do not emit this child_start event), force the cmd_start |
| 880 | + * event now so that it appears in the log before any events |
| 881 | + * that the child process itself emits. |
| 882 | + */ |
| 883 | + if (!my__wrote_start_event) |
| 884 | + emit_start_event(); |
| 885 | + |
| 886 | + cd = alloc_child_data(cmd); |
| 887 | + child_id = insert_child_data(cd); |
| 888 | + |
| 889 | + /* build data portion for a "detail" event */ |
| 890 | + if (slog_want_detail_event("child")) { |
| 891 | + struct json_writer jw_data = JSON_WRITER_INIT; |
| 892 | + |
| 893 | + jw_object_begin(&jw_data, my__is_pretty); |
| 894 | + { |
| 895 | + jw_object_intmax(&jw_data, "child_id", child_id); |
| 896 | + jw_object_bool(&jw_data, "git_cmd", cd->is_git_cmd); |
| 897 | + jw_object_bool(&jw_data, "use_shell", cd->use_shell); |
| 898 | + jw_object_sub_jw(&jw_data, "child_argv", &cd->jw_argv); |
| 899 | + } |
| 900 | + jw_end(&jw_data); |
| 901 | + |
| 902 | + emit_detail_event("child", "child_starting", cd->start_ns, |
| 903 | + &jw_data); |
| 904 | + jw_release(&jw_data); |
| 905 | + } |
| 906 | + |
| 907 | + return child_id; |
| 908 | +} |
| 909 | + |
| 910 | +void slog_child_ended(int child_id, int child_pid, int child_exit_code) |
| 911 | +{ |
| 912 | + struct child_data *cd; |
| 913 | + |
| 914 | + if (!slog_is_enabled()) |
| 915 | + return; |
| 916 | + if (child_id == SLOG_UNDEFINED_CHILD_ID) |
| 917 | + return; |
| 918 | + if (child_id >= my__child_data.nr || child_id < 0) |
| 919 | + BUG("Invalid slog.child id '%d'", child_id); |
| 920 | + |
| 921 | + cd = my__child_data.array[child_id]; |
| 922 | + if (!cd->is_running) |
| 923 | + BUG("slog.child '%d' already stopped", child_id); |
| 924 | + |
| 925 | + cd->end_ns = getnanotime(); |
| 926 | + cd->is_running = 0; |
| 927 | + |
| 928 | + /* build data portion for a "detail" event */ |
| 929 | + if (slog_want_detail_event("child")) { |
| 930 | + struct json_writer jw_data = JSON_WRITER_INIT; |
| 931 | + |
| 932 | + jw_object_begin(&jw_data, my__is_pretty); |
| 933 | + { |
| 934 | + jw_object_intmax(&jw_data, "child_id", child_id); |
| 935 | + jw_object_bool(&jw_data, "git_cmd", cd->is_git_cmd); |
| 936 | + jw_object_bool(&jw_data, "use_shell", cd->use_shell); |
| 937 | + jw_object_sub_jw(&jw_data, "child_argv", &cd->jw_argv); |
| 938 | + |
| 939 | + jw_object_intmax(&jw_data, "child_pid", child_pid); |
| 940 | + jw_object_intmax(&jw_data, "child_exit_code", |
| 941 | + child_exit_code); |
| 942 | + jw_object_intmax(&jw_data, "child_elapsed_us", |
| 943 | + (cd->end_ns - cd->start_ns) / 1000); |
| 944 | + } |
| 945 | + jw_end(&jw_data); |
| 946 | + |
| 947 | + emit_detail_event("child", "child_ended", cd->end_ns, &jw_data); |
| 948 | + jw_release(&jw_data); |
| 949 | + } |
| 950 | +} |
| 951 | + |
| 952 | +static void free_children(void) |
| 953 | +{ |
| 954 | + int k; |
| 955 | + |
| 956 | + for (k = 0; k < my__child_data.nr; k++) { |
| 957 | + struct child_data *cd = my__child_data.array[k]; |
| 958 | + |
| 959 | + jw_release(&cd->jw_argv); |
| 960 | + free(cd); |
| 961 | + } |
| 962 | + |
| 963 | + FREE_AND_NULL(my__child_data.array); |
| 964 | + my__child_data.nr = 0; |
| 965 | + my__child_data.alloc = 0; |
| 966 | +} |
| 967 | + |
818 | 968 | #endif
|
0 commit comments