[Concept,18/27] expo: Add scene_chklog() for filtered logging

Message ID 20260119204130.3972647-19-sjg@u-boot.org
State New
Headers
Series Expo debugging and textedit improvements (part E) |

Commit Message

Simon Glass Jan. 19, 2026, 8:41 p.m. UTC
  From: Simon Glass <simon.glass@canonical.com>

Add a helper function that checks the 'expo_log_filter' environment
variable. If not set, all objects are logged. If set, it contains a
comma-separated list of filters; only objects whose name contains one
of the filter strings are logged.

The feature is controlled by CONFIG_EXPO_LOG_FILTER, which is enabled
by default for sandbox.

Co-developed-by: Claude Opus 4.5 <noreply@anthropic.com>
Signed-off-by: Simon Glass <simon.glass@canonical.com>
---

 boot/Kconfig          | 10 ++++++++++
 boot/scene.c          | 32 ++++++++++++++++++++++++++++++++
 boot/scene_internal.h | 12 ++++++++++++
 doc/develop/expo.rst  | 27 +++++++++++++++++++++++++++
 test/boot/expo.c      | 37 +++++++++++++++++++++++++++++++++++++
 5 files changed, 118 insertions(+)
  

Patch

diff --git a/boot/Kconfig b/boot/Kconfig
index 7ff0dedb748..14b7ed573c9 100644
--- a/boot/Kconfig
+++ b/boot/Kconfig
@@ -1002,6 +1002,16 @@  config EXPO_TEST
 	  variable is set to 1. This is useful for debugging and performance
 	  analysis.
 
+config EXPO_LOG_FILTER
+	bool "Enable expo log filter"
+	depends on EXPO
+	default y if SANDBOX
+	help
+	  Enable the expo log filter. When enabled, the 'expo_log_filter'
+	  environment variable can be set to filter log output by object name.
+	  Only objects whose name contains the filter string are logged. This
+	  is useful for debugging specific expo objects.
+
 config BOOTMETH_SANDBOX
 	def_bool y
 	depends on SANDBOX
diff --git a/boot/scene.c b/boot/scene.c
index 3565bfd77de..9cade9aad41 100644
--- a/boot/scene.c
+++ b/boot/scene.c
@@ -10,6 +10,7 @@ 
 
 #include <alist.h>
 #include <dm.h>
+#include <env.h>
 #include <expo.h>
 #include <malloc.h>
 #include <mapmem.h>
@@ -42,6 +43,37 @@  static const char *const scene_obj_type_names[] = {
 	"textline",
 };
 
+bool scene_chklog(const char *name)
+{
+	const char *filter, *end, *p;
+	int len;
+
+	if (!CONFIG_IS_ENABLED(EXPO_LOG_FILTER))
+		return true;
+
+	filter = env_get("expo_log_filter");
+	if (!filter)
+		return true;
+
+	/* Check each comma-separated filter */
+	while (*filter) {
+		end = strchrnul(filter, ',');
+		len = end - filter;
+
+		/* Check if this filter segment appears in name */
+		for (p = name; *p; p++) {
+			if (!strncmp(p, filter, len))
+				return true;
+		}
+
+		if (!*end)
+			break;
+		filter = end + 1;
+	}
+
+	return false;
+}
+
 int scene_new(struct expo *exp, const char *name, uint id, struct scene **scnp)
 {
 	struct scene *scn;
diff --git a/boot/scene_internal.h b/boot/scene_internal.h
index db11f9c0f60..d3c67777cb1 100644
--- a/boot/scene_internal.h
+++ b/boot/scene_internal.h
@@ -613,6 +613,18 @@  int scene_calc_arrange(struct scene *scn, struct expo_arrange_info *arr);
 int scene_txt_generic_init(struct expo *exp, struct scene_txt_generic *gen,
 			   const char *name, uint str_id, const char *str);
 
+/**
+ * scene_chklog() - Check if logging is enabled for an object
+ *
+ * This checks the 'expo_log_filter' environment variable. If not set, all
+ * objects are logged. If set, it contains a comma-separated list of filters;
+ * only objects whose name contains one of the filter strings are logged.
+ *
+ * @name: Object name to check
+ * Return: true if logging should happen, false to skip
+ */
+bool scene_chklog(const char *name);
+
 /**
  * scene_flag_name() - Get the name of a scene flag
  *
diff --git a/doc/develop/expo.rst b/doc/develop/expo.rst
index fc642ed3696..7ef714be3da 100644
--- a/doc/develop/expo.rst
+++ b/doc/develop/expo.rst
@@ -605,6 +605,33 @@  These metrics help identify performance bottlenecks and verify that expo is
 operating efficiently. The timing information is particularly useful when
 optimizing display drivers or debugging slow rendering issues.
 
+Log filter
+~~~~~~~~~~
+
+Expo supports filtering log output by object name, which is useful when
+debugging specific objects. Set the ``expo_log_filter`` environment variable
+to a substring that matches the object names you want to log.
+
+To enable log filtering::
+
+   => setenv expo_log_filter texted
+   => log filter-add -d console -A -c expo -l debug
+
+This shows debug logs only for objects whose name contains "texted".
+
+Multiple filters can be specified as a comma-separated list::
+
+   => setenv expo_log_filter menu,text
+
+This logs objects matching either "menu" or "text".
+
+Remove the filter to see all objects::
+
+   => setenv expo_log_filter
+
+This feature requires ``CONFIG_EXPO_LOG_FILTER`` which is enabled by default
+for sandbox.
+
 Writing expo tests
 ------------------
 
diff --git a/test/boot/expo.c b/test/boot/expo.c
index 97b9bf82bb7..4febdf87cde 100644
--- a/test/boot/expo.c
+++ b/test/boot/expo.c
@@ -1260,6 +1260,43 @@  static int expo_scene_obj_type_name(struct unit_test_state *uts)
 }
 BOOTSTD_TEST(expo_scene_obj_type_name, 0);
 
+/* Test scene_chklog() */
+static int expo_scene_chklog(struct unit_test_state *uts)
+{
+	/* Without filter, all objects should be logged */
+	env_set("expo_log_filter", NULL);
+	ut_assert(scene_chklog("my-menu"));
+	ut_assert(scene_chklog("textline"));
+
+	/* With a single filter, only matching objects should be logged */
+	env_set("expo_log_filter", "menu");
+	ut_assert(scene_chklog("my-menu"));
+	ut_assert(scene_chklog("menu-item"));
+	ut_assert(!scene_chklog("textline"));
+	ut_assert(!scene_chklog("other"));
+
+	/* With comma-separated filters, any match should pass */
+	env_set("expo_log_filter", "menu,text");
+	ut_assert(scene_chklog("my-menu"));
+	ut_assert(scene_chklog("textline"));
+	ut_assert(scene_chklog("textedit"));
+	ut_assert(!scene_chklog("other"));
+	ut_assert(!scene_chklog("image"));
+
+	/* Test with three filters */
+	env_set("expo_log_filter", "menu,text,img");
+	ut_assert(scene_chklog("my-menu"));
+	ut_assert(scene_chklog("textline"));
+	ut_assert(scene_chklog("img-logo"));
+	ut_assert(!scene_chklog("other"));
+
+	/* Clear the filter */
+	env_set("expo_log_filter", NULL);
+
+	return 0;
+}
+BOOTSTD_TEST(expo_scene_chklog, 0);
+
 /* Test scene_find_obj_within() */
 static int expo_find_obj_within(struct unit_test_state *uts)
 {