diff --git a/src/main.rs b/src/main.rs
index 9ab9bafa12c255eb5516edd5ddf38f03c5c224d3..4b7e95a83d82f7000e4ab7c47615483747d6f03e 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -114,6 +114,35 @@ fn picolib_setup(args: &args::Run) {
                 .propose_and_wait(traft::OpReturnOne, Duration::from_secs_f64(timeout))
         }),
     );
+    luamod.set("log", &[()]);
+    #[rustfmt::skip]
+    l.exec_with(
+        "picolib.log.highlight_key = ...",
+        tlua::function2(|key: String, color: Option<String>| -> Result<(), String> {
+            let color = match color.as_deref() {
+                None            => None,
+                Some("red")     => Some(tlog::Color::Red),
+                Some("green")   => Some(tlog::Color::Green),
+                Some("blue")    => Some(tlog::Color::Blue),
+                Some("cyan")    => Some(tlog::Color::Cyan),
+                Some("yellow")  => Some(tlog::Color::Yellow),
+                Some("magenta") => Some(tlog::Color::Magenta),
+                Some("white")   => Some(tlog::Color::White),
+                Some("black")   => Some(tlog::Color::Black),
+                Some(other) => {
+                    return Err(format!("unknown color: {other:?}"))
+                }
+            };
+            tlog::highlight_key(key, color);
+            Ok(())
+        }),
+    )
+    .unwrap();
+    l.exec_with(
+        "picolib.log.clear_highlight = ...",
+        tlua::function0(tlog::clear_highlight),
+    )
+    .unwrap();
     {
         l.exec(
             r#"
diff --git a/src/tlog.rs b/src/tlog.rs
index c7b3911896cf2d2b8bb14776c43365d0574fc02a..4f78cb7204b6b28ee62a1fcd751c1c0e945548fb 100644
--- a/src/tlog.rs
+++ b/src/tlog.rs
@@ -1,3 +1,5 @@
+use std::collections::HashMap;
+
 pub struct Drain;
 
 pub fn root() -> slog::Logger {
@@ -54,10 +56,49 @@ struct StrSerializer {
     pub str: String,
 }
 
+#[rustfmt::skip]
+#[repr(u8)]
+#[derive(Clone, Copy)]
+pub enum Color {
+    Red     = 1,
+    Green   = 2,
+    Blue    = 4,
+    Cyan    = 6,
+    Yellow  = 3,
+    Magenta = 5,
+    White   = 7,
+    Black   = 0,
+}
+
+pub static mut HIGHLIGHT: Option<HashMap<String, Color>> = None;
+
+#[inline]
+pub fn clear_highlight() {
+    unsafe {
+        HIGHLIGHT = None;
+    }
+}
+
+#[inline]
+pub fn highlight_key(key: impl Into<String> + AsRef<str>, color: Option<Color>) {
+    let hi = unsafe { HIGHLIGHT.get_or_insert_with(HashMap::new) };
+    if let Some(color) = color {
+        hi.insert(key.into(), color);
+    } else {
+        hi.remove(key.as_ref());
+    }
+}
+
 impl slog::Serializer for StrSerializer {
     fn emit_arguments(&mut self, key: slog::Key, val: &std::fmt::Arguments) -> slog::Result {
         use std::fmt::Write;
-        write!(&mut self.str, ", {key}: {val}").unwrap();
+        match unsafe { HIGHLIGHT.as_ref() }.and_then(|h| h.get(key)) {
+            Some(&color) => {
+                let color = color as u8;
+                write!(&mut self.str, ", \x1b[3{color}m{key}: {val}\x1b[0m").unwrap();
+            }
+            _ => write!(&mut self.str, ", {key}: {val}").unwrap(),
+        }
         Ok(())
     }
 }