Using emojis to identify threads in log messages 2023-12-18

The other day I saw this toot by Stargirl, and it caught my eye:

Lwan, when built in debug mode, will print the thread id (obtained by gettid(2) on Linux) for every log message, so I decided to give this idea a try, by porting the code to C. Here's what I came up with:

static const char *get_thread_emoji(void)
    static const char *emojis[] = {
        "ðŸķ", "ðŸą", "🐭", "ðŸđ", "🐰", "ðŸĶŠ", "ðŸŧ", "🐞", "ðŸĻ", "ðŸŊ", "ðŸĶ", "ðŸŪ",
        "🐷", "ðŸ―", "ðŸļ", "ðŸĩ", "🐔", "🐧", "ðŸĶ", "ðŸĪ", "ðŸĶ†", "ðŸĶ‰", "ðŸĶ‡", "🐚",
        "🐗", "ðŸī", "ðŸĶ„", "🐝", "ðŸŠą", "🐛", "ðŸĶ‹", "🐌", "🐞", "🐜", "🊰", "ðŸŠē",
        "ðŸŠģ", "ðŸĶŸ", "ðŸĶ—", "ðŸĶ‚", "ðŸĒ", "🐍", "ðŸĶŽ", "ðŸĶ–", "ðŸĶ•", "🐙", "ðŸĶ‘", "ðŸĶ",
        "ðŸĶž", "ðŸĶ€", "ðŸĄ", "🐠", "🐟", "🐎", "ðŸģ", "🐋", "ðŸĶˆ", "ðŸĶ­", "🐊", "🐅",
        "🐆", "ðŸĶ“", "ðŸĶ", "ðŸĶ§", "ðŸĶĢ", "🐘", "ðŸĶ›", "ðŸĶ", "🐊", "ðŸŦ", "ðŸĶ’", "ðŸĶ˜",
        "ðŸĶŽ", "🐃", "🐂", "🐄", "🐎", "🐖", "🐏", "🐑", "ðŸĶ™", "🐐", "ðŸĶŒ", "🐕",
        "ðŸĐ", "🐈", "🐓", "ðŸĶƒ", "ðŸĶĪ", "ðŸĶš", "ðŸĶœ", "ðŸĶĒ", "ðŸĶĐ", "🕊", "🐇", "ðŸĶ",
        "ðŸĶĻ", "ðŸĶĄ", "ðŸĶŦ", "ðŸĶĶ", "ðŸĶĨ", "🐁", "🐀", "ðŸŋ", "ðŸĶ”", "🐉", "ðŸē",
    static __thread const char *emoji;
    static unsigned int last_emoji_id;

    if (!emoji) {
        emoji = emojis[ATOMIC_INC(last_emoji_id) % (int)N_ELEMENTS(emojis)];

    return emoji;

This, of course, is only called when $LANG ends with the string .utf8, and the terminal is set to use colors, as determined by this function:

static bool can_use_colors(void)
    const char *term;
    const char *no_color;

    if (!isatty(fileno(stdout)))
        return false;

    /* From "Command-line software which adds ANSI
     * color to its output by default should check for a NO_COLOR
     * environment variable that, when present and not an empty string
     * (regardless of its value), prevents the addition of ANSI color."  */
    no_color = secure_getenv("NO_COLOR");
    if (no_color && no_color[0])
        return false;

    term = secure_getenv("TERM");
    if (term && streq(term, "dumb"))
        return false;

    return true;

While not a 1:1 port from the original Python code, the end result is just as good. Don't take my word for it, though; here's how it looks like:

Screenshot of Lwan showing one different animal emoji per thread ID
🖂 Send me an email about this blog post
If you liked this post, consider getting me a coffee!