16

I keep getting very strange notifications which go away before I can read them, they are long, and appear at random times, the most recently one came up was during a kernel upgrade, it had a strange icon, and was long, but I didn't manage to read it because it was on the screen so briefly.

So I am wondering if there is any log which logs all calls to notify-send which logs the program calling it, and all the parameters given? Or if I can set up such a log to find out what these notifications are about? I am running Ubuntu GNOME 15.10 with GNOME 3.18.

Jacob Vlijm
  • 85,675
  • 1
    As far as i know notify-send does not support a forced logging. I do have a really ugly workaround in mind which should be the last option/resort: Start a screen-recording and record as long as needed until the message appears. Stop the recording, start playback, jump to related section & pause. Using screenshots might as well be an option if you can trigger them fast enough (i.e. print-screen-key) – dufte May 10 '16 at 11:22
  • @dufte: Is there not a way with aliases or something which would mean that a script is called instead of it which logs and then passes on the arguments to the real notify-send? –  May 10 '16 at 11:25
  • http://askubuntu.com/questions/105566/is-there-a-way-to-view-notification-history ? – DK Bose May 10 '16 at 11:34
  • 1
    I would think that a simple python script that listens on DBus for the correct messages, and writes them to a log file, would do very well. Not that I'm offering to write one :-D – Jos May 10 '16 at 11:37
  • If you are using Gnome, aren't they logged in then notifications menu? – Wilf May 10 '16 at 12:26

2 Answers2

16

Even didn't need a full script...
...but put it in the form of a script:

#!/bin/bash

file=$1

dbus-monitor "interface='org.freedesktop.Notifications'" |\
 grep --line-buffered "string" |\
 grep --line-buffered -e method -e ":" -e '""' -e urgency -e notify -v |\
 grep --line-buffered '.*(?=string)|(?<=string).*' -oPi |\
 grep --line-buffered -v '^\s*$' |\
 xargs -I '{}' echo {} >> $file

To run it

  • Copy the "script" into an empty file, save it as keep_log.sh
  • Run it with the logfile as argument with the command

    /bin/bash /path/to/keep_log.sh /path/to/log.txt
    

The answer was retrieved from an earlier answer (not a dupe), in which this application of the method was mentioned as an example.

The answer I gave there, on its own turn, was based on this very nice answer, in which is explained that the method uses dbus-monitor to intercept the contents of notify-send. By editing the example there, we can make it write notify-send messages to a (log-) file.

Or, more elegant

...would be to add the date to the logfile, producing a logfile like:

---di 10 mei 2016 17:37:20 CEST---
SOme kind of a message!
---di 10 mei 2016 17:37:20 CEST---
The last message was misspelled so here i9s another one

In that case, the script would be:

#!/bin/bash

logfile=$1

dbus-monitor "interface='org.freedesktop.Notifications'" |\
grep --line-buffered "string" |\
grep --line-buffered -e method -e ":" -e '""' -e urgency -e notify -v |\
grep --line-buffered '.*(?=string)|(?<=string).*' -oPi |\
grep --line-buffered -v '^\s*$' |\
xargs -I '{}' \
printf "---$( date )---\n"{}"\n" >> $logfile
Jacob Vlijm
  • 85,675
  • 1
    Wait, sorry, I'm not sure I fully understand, where is the log stored? –  May 10 '16 at 12:27
  • 1
    @ParanoidPanda you can define your own path. I used /home/jacob/desktop/log.txt in my test. The file is created if it doesn't exist. – Jacob Vlijm May 10 '16 at 12:29
  • @ParanoidPanda ah, sorry, sorry, too much in a hurry... See update. – Jacob Vlijm May 10 '16 at 12:31
  • 1
    Ok, I see now sender=:1.918 -> destination=:1.16 serial=7 path=/org/freedesktop/Notifications; ... etc., but how can I determine who is sending it? – vladkras Dec 11 '17 at 11:26
  • @vladkras install d-feet and run it (a GUI app). It shows me, e.g., that org.freedesktop.Notifications on the Session Bus is associated with gnome-shell itself. And the notification I wanted to track down (an obvious one to log and get a timestamp for - ephemeral warnings that The volume “Filesystem root” has only xxx MB disk space remaining!) came from 1.49 which is gsd-housekeeping on the Session Bus. So now the question for gnome-shell is how to log notifications, like notify-osd did, I guess? – nealmcb Nov 04 '18 at 03:14
  • 1
    I'm getting this sometimes: Error: xargs: unmatched double quote; by default quotes are special to xargs unless you use the -0 option – nealmcb Nov 05 '18 at 14:06
  • 1
    @nealmcb see https://askubuntu.com/questions/842935/how-can-i-solve-unmatched-double-quote-error-using-dbus-monitor-in-combination – Jacob Vlijm Nov 05 '18 at 14:14
  • Thanks, @JacobVlijm. Can you make the change to fix this here? I.e. use xargs -d '\n' -I '{} – nealmcb Nov 05 '18 at 14:56
  • Thanks for the answer. I want to run one more command after the printf. Tried printf "---$( date )---\n"{}"\n" >> $logfile && echo hi and tried the echo in the new line. Neither worked. – Andrew Jan 17 '19 at 18:28
  • IIUC there's a problem: the dbus-monitor process runs only once but it handles multiple messages. As a result 1. the date is the same for all messages and 2. @Andrew your echo hi never appears. An idea to solve both problems could be to replace xargs with sth like while read msg; do date +"---%Y-%m-%d %H:%M:%S---"; echo "$msg"; done – user829755 Feb 06 '24 at 11:07
2

I've always wanted this myself, and tried the suggestions here to no great avail, the output of the dbus-monitor being too complex for such simple handling. So I whipped up a small solution I'm using now, having finally bitten the bullet. It's just an extension of the existing solution but implements far more rigorous processing and add some ease of use tools.

https://github.com/bernd-wechner/Linux-Tools/tree/master/nlog

The script for the record right now is:

#!/bin/bash

Output function to handle printing to either stdout or a file

output() { if [ -n "$logfile" ]; then echo -e "$1" >> "$logfile" else echo -e "$1" fi }

Check if a filename argument is provided

logfile="" if [ -n "$1" ]; then logfile="$1" # Create the directory if it doesn't exist logdir=$(dirname "$logfile") mkdir -p "$logdir" touch $logfile fi

Monitor DBus for notification events

dbus-monitor "interface='org.freedesktop.Notifications'" | while read -r line; do # Check for the start of a "Notify" method call if [[ "$line" == "member=Notify" ]]; then app_name="" icon="" title="" body="" hints="" capturing_body=false

    # Read subsequent lines for details
    while read -r line; do
        # Capture app name, icon, title, or start capturing body
        if [[ &quot;$line&quot; == *&quot;string \&quot;&quot;* ]]; then
            value=$(echo &quot;$line&quot; | sed 's/^.*string &quot;\(.*\)&quot;/\1/')
            
            if [ -z &quot;$app_name&quot; ]; then
                app_name=&quot;$value&quot;
            elif [ -z &quot;$icon&quot; ]; then
                icon=&quot;$value&quot;
            elif [ -z &quot;$title&quot; ]; then
                title=&quot;$value&quot;
            else
                capturing_body=true
                body=&quot;$value&quot;
            fi
        elif $capturing_body; then
            # Continue capturing body text if we're in the body section
            if [[ &quot;$line&quot; == *&quot;array [&quot;* ]]; then
                capturing_body=false
            else
                # Strip leading spaces and trailing quotes from the body
                line=$(echo &quot;$line&quot; | sed -e 's/^ *//' -e 's/&quot;$//')
                body+=&quot; $line&quot;
            fi
        elif [[ &quot;$line&quot; == *&quot;dict entry(&quot;* ]]; then
            capturing_body=false
            hint_key=&quot;&quot;
            hint_value=&quot;&quot;
        elif [[ &quot;$line&quot; == *&quot;string \&quot;&quot;* ]]; then
            if [ -z &quot;$hint_key&quot; ]; then
                hint_key=$(echo &quot;$line&quot; | sed 's/.*string &quot;\(.*\)&quot;/\1/')
            else
                hint_value=$(echo &quot;$line&quot; | sed 's/.*string &quot;\(.*\)&quot;/\1/')
                hints+=&quot;$hint_key: $hint_value\n&quot;
            fi
        elif [[ &quot;$line&quot; == *&quot;]&quot;* ]]; then
            break
        fi
    done

    # Remove the `string &quot;` prefix and trailing `&quot;` from the body, and trim leading/trailing whitespace
    body=&quot;${body#string \&quot;}&quot;
    body=&quot;${body%\&quot;}&quot;
    body=&quot;$(echo -e &quot;${body}&quot; | sed -e 's/^[[:space:]]*//')&quot;

    # Prepare the formatted notification summary
    notification=&quot;----------------------------------\n&quot;
    notification+=&quot;App Name: $app_name\n&quot;
    notification+=&quot;Icon: $icon\n&quot;
    notification+=&quot;Title: $title\n&quot;
    notification+=&quot;Body: \n$body\n&quot;
    notification+=&quot;Hints:\n$hints\n&quot;

    # Output the notification summary
    output &quot;$notification&quot;
fi

done

  • Nice. Having read the rest of the answers, I was just about to write my own script. But then I saw your answer. Works for me! – AdvApp Apr 09 '25 at 02:24