gst-stats: Add argument for a custom regexp

This is to use gst-stats against GStreamer logs that went through
some other logging system.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3935>
This commit is contained in:
Olivier Crête 2023-02-10 13:04:26 -05:00 committed by GStreamer Marge Bot
parent ff435c80a2
commit e2d7fbe94f

View file

@ -30,6 +30,7 @@
#include "tools.h" #include "tools.h"
/* log parser */ /* log parser */
static GRegex *custom_log = NULL;
static GRegex *raw_log = NULL; static GRegex *raw_log = NULL;
static GRegex *ansi_log = NULL; static GRegex *ansi_log = NULL;
@ -909,25 +910,36 @@ process_leaf_bins (gpointer key, gpointer value, gpointer user_data)
/* main */ /* main */
static gboolean static gboolean
init (void) init (const gchar * tracer_regexp)
{ {
/* compile the parser regexps */ /* compile the parser regexps */
if (tracer_regexp) {
GError *gerr = NULL;
custom_log = g_regex_new (tracer_regexp, 0, 0, &gerr);
if (!custom_log) {
g_warning ("Could not compile tracer regexp: %s\n", gerr->message);
g_clear_error (&gerr);
return FALSE;
}
}
/* 0:00:00.004925027 31586 0x1c5c600 DEBUG GST_REGISTRY gstregistry.c:463:gst_registry_add_plugin:<registry0> adding plugin 0x1c79160 for filename "/usr/lib/gstreamer-1.0/libgstxxx.so" /* 0:00:00.004925027 31586 0x1c5c600 DEBUG GST_REGISTRY gstregistry.c:463:gst_registry_add_plugin:<registry0> adding plugin 0x1c79160 for filename "/usr/lib/gstreamer-1.0/libgstxxx.so"
* 0:00:02.719599000 35292 000001C031A49C60 DEBUG GST_TRACER gsttracer.c:162:gst_tracer_register:<registry0> update existing feature 000001C02F9843C0 (latency) * 0:00:02.719599000 35292 000001C031A49C60 DEBUG GST_TRACER gsttracer.c:162:gst_tracer_register:<registry0> update existing feature 000001C02F9843C0 (latency)
*/ */
raw_log = g_regex_new ( raw_log = g_regex_new (
/* 1: ts */ /* 1: ts */
"^([0-9:.]+) +" "^[0-9:.]+ +"
/* 2: pid */ /* 2: pid */
"([0-9]+) +" "[0-9]+ +"
/* 3: thread */ /* 3: thread */
"(0?x?[0-9a-fA-F]+) +" "0?x?[0-9a-fA-F]+ +"
/* 4: level */ /* 4: level */
"([A-Z]+) +" "TRACE +"
/* 5: category */ /* 5: category */
"([a-zA-Z_-]+) +" "[a-zA-Z_-]+ +"
/* 6: file:line:func: */ /* 6: file:line:func: */
"([^:]*:[0-9]+:[^:]*:) +" "[^:]*:[0-9]+:[^:]*: +"
/* 7: (obj)? log-text */ /* 7: (obj)? log-text */
"(.*)$", 0, 0, NULL); "(.*)$", 0, 0, NULL);
if (!raw_log) { if (!raw_log) {
@ -937,20 +949,20 @@ init (void)
ansi_log = g_regex_new ( ansi_log = g_regex_new (
/* 1: ts */ /* 1: ts */
"^([0-9:.]+) +" "^[0-9:.]+ +"
/* 2: pid */ /* 2: pid */
"\\\x1b\\[[0-9;]+m *([0-9]+)\\\x1b\\[00m +" "\\\x1b\\[[0-9;]+m *[0-9]+\\\x1b\\[00m +"
/* 3: thread */ /* 3: thread */
"(0x[0-9a-fA-F]+) +" "0x[0-9a-fA-F]+ +"
/* 4: level */ /* 4: level */
"(?:\\\x1b\\[[0-9;]+m)?([A-Z]+) +\\\x1b\\[00m +" "(?:\\\x1b\\[[0-9;]+m)?TRACE +\\\x1b\\[00m +"
/* 5: category */ /* 5: category */
"\\\x1b\\[[0-9;]+m +([a-zA-Z_-]+) +" "\\\x1b\\[[0-9;]+m +[a-zA-Z_-]+ +"
/* 6: file:line:func: */ /* 6: file:line:func: */
"([^:]*:[0-9]+:[^:]*:)(?:\\\x1b\\[00m)? +" "[^:]*:[0-9]+:[^:]*:?:\\\x1b\\[00m? +"
/* 7: (obj)? log-text */ /* 7: (obj)? log-text */
"(.*)$", 0, 0, NULL); "(.*)$", 0, 0, NULL);
if (!raw_log) { if (!ansi_log) {
GST_WARNING ("failed to compile the 'ansi' parser"); GST_WARNING ("failed to compile the 'ansi' parser");
return FALSE; return FALSE;
} }
@ -1000,6 +1012,8 @@ done (void)
g_regex_unref (raw_log); g_regex_unref (raw_log);
if (ansi_log) if (ansi_log)
g_regex_unref (ansi_log); g_regex_unref (ansi_log);
if (custom_log)
g_regex_unref (custom_log);
} }
static gint static gint
@ -1177,9 +1191,12 @@ collect_stats (const gchar * filename)
GRegex *parser; GRegex *parser;
GstStructure *s; GstStructure *s;
guint lnr = 0; guint lnr = 0;
gchar *level, *data; gchar *data;
if (strchr (line, 27)) { if (custom_log) {
parser = custom_log;
GST_INFO ("format is 'custom'");
} else if (strchr (line, 27)) {
parser = ansi_log; parser = ansi_log;
GST_INFO ("format is 'ansi'"); GST_INFO ("format is 'ansi'");
} else { } else {
@ -1192,50 +1209,45 @@ collect_stats (const gchar * filename)
while (!feof (log)) { while (!feof (log)) {
if (fgets (line, 5000, log)) { if (fgets (line, 5000, log)) {
if (g_regex_match (parser, line, 0, &match_info)) { if (g_regex_match (parser, line, 0, &match_info)) {
/* filter by level */ data = g_match_info_fetch (match_info, 1);
level = g_match_info_fetch (match_info, 4); if ((s = gst_structure_from_string (data, NULL))) {
if (!strcmp (level, "TRACE")) { const gchar *name = gst_structure_get_name (s);
data = g_match_info_fetch (match_info, 7);
if ((s = gst_structure_from_string (data, NULL))) {
const gchar *name = gst_structure_get_name (s);
if (!strcmp (name, "new-pad")) { if (!strcmp (name, "new-pad")) {
new_pad_stats (s); new_pad_stats (s);
} else if (!strcmp (name, "new-element")) { } else if (!strcmp (name, "new-element")) {
new_element_stats (s); new_element_stats (s);
} else if (!strcmp (name, "buffer")) { } else if (!strcmp (name, "buffer")) {
do_buffer_stats (s); do_buffer_stats (s);
} else if (!strcmp (name, "event")) { } else if (!strcmp (name, "event")) {
do_event_stats (s); do_event_stats (s);
} else if (!strcmp (name, "message")) { } else if (!strcmp (name, "message")) {
do_message_stats (s); do_message_stats (s);
} else if (!strcmp (name, "query")) { } else if (!strcmp (name, "query")) {
do_query_stats (s); do_query_stats (s);
} else if (!strcmp (name, "thread-rusage")) { } else if (!strcmp (name, "thread-rusage")) {
do_thread_rusage_stats (s); do_thread_rusage_stats (s);
} else if (!strcmp (name, "proc-rusage")) { } else if (!strcmp (name, "proc-rusage")) {
do_proc_rusage_stats (s); do_proc_rusage_stats (s);
} else if (!strcmp (name, "latency")) { } else if (!strcmp (name, "latency")) {
do_latency_stats (s); do_latency_stats (s);
} else if (!strcmp (name, "element-latency")) { } else if (!strcmp (name, "element-latency")) {
do_element_latency_stats (s); do_element_latency_stats (s);
} else if (!strcmp (name, "element-reported-latency")) { } else if (!strcmp (name, "element-reported-latency")) {
do_element_reported_latency (s); do_element_reported_latency (s);
} else if (!strcmp (name, "factory-used")) { } else if (!strcmp (name, "factory-used")) {
do_factory_used (s); do_factory_used (s);
} else {
// TODO(ensonic): parse the xxx.class log lines
if (!g_str_has_suffix (data, ".class")) {
GST_WARNING ("unknown log entry: '%s'", data);
}
}
gst_structure_free (s);
} else { } else {
GST_WARNING ("unknown log entry: '%s'", data); // TODO(ensonic): parse the xxx.class log lines
if (!g_str_has_suffix (data, ".class")) {
GST_WARNING ("unknown log entry: '%s'", data);
}
} }
g_free (data); gst_structure_free (s);
} else {
GST_WARNING ("unknown log entry: '%s'", data);
} }
g_free (level); g_free (data);
} else { } else {
if (*line) { if (*line) {
GST_WARNING ("foreign log entry: %s:%d:'%s'", filename, lnr, GST_WARNING ("foreign log entry: %s:%d:'%s'", filename, lnr,
@ -1263,6 +1275,7 @@ gint
main (gint argc, gchar * argv[]) main (gint argc, gchar * argv[])
{ {
gchar **filenames = NULL; gchar **filenames = NULL;
gchar *tracer_regexp = NULL;
guint num; guint num;
GError *err = NULL; GError *err = NULL;
GOptionContext *ctx; GOptionContext *ctx;
@ -1270,6 +1283,8 @@ main (gint argc, gchar * argv[])
GST_TOOLS_GOPTION_VERSION, GST_TOOLS_GOPTION_VERSION,
// TODO(ensonic): add a summary flag, if set read the whole thing, print // TODO(ensonic): add a summary flag, if set read the whole thing, print
// stats once, and exit // stats once, and exit
{"tracer-regexp", 't', 0, G_OPTION_ARG_STRING, &tracer_regexp,
"Custom Perl regular expression to extract tracer data", "regexp"},
{G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_FILENAME_ARRAY, &filenames, NULL} {G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_FILENAME_ARRAY, &filenames, NULL}
, ,
{NULL} {NULL}
@ -1318,7 +1333,7 @@ main (gint argc, gchar * argv[])
return 1; return 1;
} }
if (init ()) { if (init (tracer_regexp)) {
collect_stats (filenames[0]); collect_stats (filenames[0]);
print_stats (); print_stats ();
} }