Skip to content

Commit 1759076

Browse files
jeffhostetlergitster
authored andcommitted
structured-logging: add config data facility
Add "config" section to "cmd_exit" event to record important configuration settings in the log. Add the value of "slog.detail", "slog.timers", and "slog.aux" config settings to the log. These values control the filtering of the log. Knowing the filter settings can help post-processors reason about the contents of the log. Signed-off-by: Jeff Hostetler <[email protected]>
1 parent 2254190 commit 1759076

File tree

2 files changed

+145
-0
lines changed

2 files changed

+145
-0
lines changed

structured-logging.c

Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,20 @@ struct child_data_array {
8383
static struct child_data_array my__child_data;
8484
static void free_children(void);
8585

86+
struct config_data {
87+
char *group;
88+
struct json_writer jw;
89+
};
90+
91+
struct config_data_array {
92+
struct config_data **array;
93+
size_t nr, alloc;
94+
};
95+
96+
static struct config_data_array my__config_data;
97+
static void format_config_data(struct json_writer *jw);
98+
static void free_config_data(void);
99+
86100
static uint64_t my__start_time;
87101
static uint64_t my__exit_time;
88102
static int my__is_config_loaded;
@@ -132,6 +146,15 @@ static int want_category(const struct category_filter *cf, const char *category)
132146
return !!strstr(cf->categories, category);
133147
}
134148

149+
static void set_config_data_from_category(const struct category_filter *cf,
150+
const char *key)
151+
{
152+
if (cf->want == 0 || cf->want == 1)
153+
slog_set_config_data_intmax(key, cf->want);
154+
else
155+
slog_set_config_data_string(key, cf->categories);
156+
}
157+
135158
/*
136159
* Compute a new session id for the current process. Build string
137160
* with the start time and PID of the current process and append
@@ -249,6 +272,18 @@ static void emit_exit_event(void)
249272
struct json_writer jw = JSON_WRITER_INIT;
250273
uint64_t atexit_time = getnanotime() / 1000;
251274

275+
/*
276+
* Copy important (and non-obvious) config settings into the
277+
* "config" section of the "cmd_exit" event. The values of
278+
* "slog.detail", "slog.timers", and "slog.aux" are used in
279+
* category want filtering, so post-processors should know the
280+
* filter settings so that they can tell if an event is missing
281+
* because of filtering or an error.
282+
*/
283+
set_config_data_from_category(&my__detail_categories, "slog.detail");
284+
set_config_data_from_category(&my__timer_categories, "slog.timers");
285+
set_config_data_from_category(&my__aux_categories, "slog.aux");
286+
252287
/* close unterminated forms */
253288
if (my__errors.json.len)
254289
jw_end(&my__errors);
@@ -299,6 +334,12 @@ static void emit_exit_event(void)
299334
}
300335
jw_end(&jw);
301336

337+
if (my__config_data.nr) {
338+
jw_object_inline_begin_object(&jw, "config");
339+
format_config_data(&jw);
340+
jw_end(&jw);
341+
}
342+
302343
if (my__timers.nr) {
303344
jw_object_inline_begin_object(&jw, "timers");
304345
format_timers(&jw);
@@ -479,6 +520,7 @@ static void do_final_steps(int in_signal)
479520
free_child_summary_data();
480521
free_timers();
481522
free_children();
523+
free_config_data();
482524
}
483525

484526
static void slog_atexit(void)
@@ -1084,4 +1126,94 @@ static void free_children(void)
10841126
my__child_data.alloc = 0;
10851127
}
10861128

1129+
/*
1130+
* Split <key> into <group>.<sub_key> (for example "slog.path" into "slog" and "path")
1131+
* Find or insert <group> in config_data_array[].
1132+
*
1133+
* Return config_data_arary[<group>].
1134+
*/
1135+
static struct config_data *find_config_data(const char *key, const char **sub_key)
1136+
{
1137+
struct config_data *cd;
1138+
char *dot;
1139+
size_t group_len;
1140+
int k;
1141+
1142+
dot = strchr(key, '.');
1143+
if (!dot)
1144+
return NULL;
1145+
1146+
*sub_key = dot + 1;
1147+
1148+
group_len = dot - key;
1149+
1150+
for (k = 0; k < my__config_data.nr; k++) {
1151+
cd = my__config_data.array[k];
1152+
if (!strncmp(key, cd->group, group_len))
1153+
return cd;
1154+
}
1155+
1156+
cd = xcalloc(1, sizeof(struct config_data));
1157+
cd->group = xstrndup(key, group_len);
1158+
1159+
jw_object_begin(&cd->jw, my__is_pretty);
1160+
/* leave per-group object unterminated for now */
1161+
1162+
ALLOC_GROW(my__config_data.array, my__config_data.nr + 1,
1163+
my__config_data.alloc);
1164+
my__config_data.array[my__config_data.nr++] = cd;
1165+
1166+
return cd;
1167+
}
1168+
1169+
void slog_set_config_data_string(const char *key, const char *value)
1170+
{
1171+
const char *sub_key;
1172+
struct config_data *cd = find_config_data(key, &sub_key);
1173+
1174+
if (cd)
1175+
jw_object_string(&cd->jw, sub_key, value);
1176+
}
1177+
1178+
void slog_set_config_data_intmax(const char *key, intmax_t value)
1179+
{
1180+
const char *sub_key;
1181+
struct config_data *cd = find_config_data(key, &sub_key);
1182+
1183+
if (cd)
1184+
jw_object_intmax(&cd->jw, sub_key, value);
1185+
}
1186+
1187+
static void format_config_data(struct json_writer *jw)
1188+
{
1189+
int k;
1190+
1191+
for (k = 0; k < my__config_data.nr; k++) {
1192+
struct config_data *cd = my__config_data.array[k];
1193+
1194+
/* termminate per-group form */
1195+
jw_end(&cd->jw);
1196+
1197+
/* insert per-category form into containing "config" form */
1198+
jw_object_sub_jw(jw, cd->group, &cd->jw);
1199+
}
1200+
}
1201+
1202+
static void free_config_data(void)
1203+
{
1204+
int k;
1205+
1206+
for (k = 0; k < my__config_data.nr; k++) {
1207+
struct config_data *cd = my__config_data.array[k];
1208+
1209+
jw_release(&cd->jw);
1210+
free(cd->group);
1211+
free(cd);
1212+
}
1213+
1214+
FREE_AND_NULL(my__config_data.array);
1215+
my__config_data.nr = 0;
1216+
my__config_data.alloc = 0;
1217+
}
1218+
10871219
#endif

structured-logging.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ static inline void slog_stop_timer(int tid) { };
3434
#define slog_aux_jw(c, k, v) do { } while (0)
3535
#define slog_child_starting(cmd) (SLOG_UNDEFINED_CHILD_ID)
3636
#define slog_child_ended(i, p, ec) do { } while (0)
37+
#define slog_set_config_data_string(k, v) do { } while (0)
38+
#define slog_set_config_data_intmax(k, v) do { } while (0)
3739

3840
#else
3941

@@ -162,5 +164,16 @@ void slog_aux_jw(const char *category, const char *key,
162164
int slog_child_starting(const struct child_process *cmd);
163165
void slog_child_ended(int child_id, int child_pid, int child_exit_code);
164166

167+
/*
168+
* Add an important config key/value pair to the "cmd_event". Keys
169+
* are assumed to be of the form <group>.<name>, such as "slog.path".
170+
* The pair will appear under the "config" object in the resulting JSON
171+
* as "config.<group>.<name>:<value>".
172+
*
173+
* This should only be used for important config settings.
174+
*/
175+
void slog_set_config_data_string(const char *key, const char *value);
176+
void slog_set_config_data_intmax(const char *key, intmax_t value);
177+
165178
#endif /* STRUCTURED_LOGGING */
166179
#endif /* STRUCTURED_LOGGING_H */

0 commit comments

Comments
 (0)