8

For example, I normally open mousepad (xfce equivalent of gedit) from the applications menu. However, I know that you can also do this in a terminal by typing mousepad.

Following this example, what I want is whenever I open mousepad via GUI, a new line is written in a log file stating something like Sep 5 15:35:11 lucho@lucho:~$ mousepad. More in general, what I want is to log all GUI activities that are potentially do-able via command-line (like opening programs, changing permissions, modifying a system settings, etc) but written in its alternative command-line execution format. I want this in order to improve my knowledge of how to use the command-line (without going through the man pages). There are many things I do through the GUI which I don't do via command-line (some potentially automatable via a script or via keyboard shortcuts) and having this log file would be a good way to learn them.

I'm aware of the existence of the syslog file in /var/log but that is not what I need. The Activity Log Manager app from Ubuntu repositories does not show command-line format, so far as I know. I need something like the .bash_history file that exist in my home folder but recording my GUI-based activities.

  • you can use a tool like strace to peek into a running program and see what system calls it makes , this will generate vast amounts of data though – Amias Jan 23 '17 at 12:43
  • If you're looking for a program that simply logs the binary name of programs that open in GUI, I can do that in a script. If it's what you want, let me know. Would be better if you clarified what your requirements actually are, so please edit your question. Recording GUI-based activities , such as clicking on buttons or opening new tab in a browser isn't something that can be easily recorded, because these aren't connected to actual shell commands – Sergiy Kolodyazhnyy Jan 24 '17 at 21:16
  • @Serg The log you suggest would be certainly what I am looking for. Something like a "Task Manager" log based on CLI names instead of GLI names, which, as the existing answer suggest, might not coincide. For instance, if I open "Language Support" in Settings, I want to know its CLI equivalent. Etc... – user308164 Jan 25 '17 at 9:57
  • @luchonacho OK, I will begin writing today, will post when it's ready. By the way, "Language Support" in Settings doesn't have cli equivalent of its own. Some of the things, like bluetooth menu or background menu, do - you can specify unity-control-center background or gnome-control-center background (depending on your desktop, Unity or XFCE or GNOME). But the outside world probably only will see gnome-control-center – Sergiy Kolodyazhnyy Jan 25 '17 at 14:48
  • There are many, many ways to find out what task is done by GUI applications, and find out what their cli equivalent is. It seems quite inefficient to me to try to blindly record everything that happens by brute force, being sure that you won't catch all. Better find out in specific cases, using specific tools. – Jacob Vlijm Jan 28 '17 at 14:05
2
+250

Introduction

While it's not possible to log all GUI actions, such things as logging commands that correspond to open windows can be done. Below is the simple python script that does the job. It's still in development, but does 90% of the required task.

Source code

#!/usr/bin/env python3
import gi
gi.require_version('Gtk', '3.0')
gi.require_version('Gdk', '3.0')
from gi.repository import Gdk,Gtk
import time
import os
import subprocess

def run_cmd(cmdlist):
    """ Reusable function for running external commands """
    new_env = dict(os.environ)
    new_env['LC_ALL'] = 'C'
    try:
        stdout = subprocess.check_output(cmdlist, env=new_env)
    except subprocess.CalledProcessError:
        pass
    else:
        if stdout:
            return stdout
def print_info(stack,event):
    base_xprop = ['xprop','-notype']
    for xid in stack:
        pid = None
        check_pid = run_cmd(base_xprop + [ '_NET_WM_PID', '-id',str(xid)])
        if check_pid:
            pid = check_pid.decode().split('=')[1].strip()
        with open('/proc/'+pid+'/cmdline') as fd:
            command = fd.read()
        print(time.strftime("%D %H:%M:%S" + " "*3) + event + pid + " " + command)

def main():
    sc = Gdk.Screen.get_default()
    old_stack = None

    while True:
        stack = [ win.get_xid() for win in sc.get_window_stack() ]
        if old_stack:
            # Difference between current and old stack will show new programs
            diff = set(stack) - set(old_stack)
            if diff:
                print_info(diff," 'New window open' ")
        else:
            print_info(stack," 'Script Started' ")

        old_stack = stack
        time.sleep(2)

if __name__ == '__main__': main()

Test run:

$ ./log_open_windows.py                                                                                                
01/25/17 15:33:13    'Script Started' 2915 nautilus-n
01/25/17 15:33:13    'Script Started' 3408 /opt/google/chrome/chrome
01/25/17 15:33:13    'Script Started' 12540 /usr/bin/python/usr/bin/x-terminal-emulator
01/25/17 15:33:13    'Script Started' 2454 compiz
01/25/17 15:33:13    'Script Started' 2454 compiz
01/25/17 15:33:13    'Script Started' 2454 compiz
01/25/17 15:33:13    'Script Started' 2454 compiz
01/25/17 15:33:13    'Script Started' 2454 compiz
01/25/17 15:33:21    'New window open' 15143 /usr/lib/firefox/firefox-new-window
01/25/17 15:33:27    'New window open' 15196 unity-control-center

The script shows timestamp, event type, the window PID, and the corresponding command.

How to use

The standard rules of any script apply. Make sure you store the script in ~/bin directory. If you don't have ~/bin directory , then create one. Save script file there and ensure it is executable with chmod +x ~/bin/log_open_windows.py. After than you can run it from command line at any time you wish by calling ~/log_open_windows.py in command-line.

  • Thanks. Looks promising! Two questions. How to run it? What's the 10% missing? – user308164 Jan 26 '17 at 9:52
  • Nifty! +1 from me! – Fabby Jan 26 '17 at 13:22
  • @luchonacho I added a paragraph on usage. I would recommend you use it manually from command-line as I described. You can make it start automatically on start-up, but I don't recommend doing that. The missing 10% is other few features I wanted to add, but I don't think I'm going to add them. It works well enough for now. But maybe I'll change my mind again – Sergiy Kolodyazhnyy Jan 28 '17 at 16:47
  • This is probably the closest you can get to what I was looking for, knowingly that the perfect solution does not exist. Thanks! – user308164 Jan 28 '17 at 18:34
4

Proposing that kind log file as base for learning is actually a brilliant idea!

Unfourtunately, many actions of GUI programs are implemented in the program itself, not using external commands; And even if it uses external commands, it may be in a different way than one would do it in a shell;
So that does not exist, and is not easy to implement.

But I have a solution for a part of the problem: The program name in the GUI is sometimes differen from the program name one needs to know for a shell command - not only if the GUI name is translated to a local language.

For example, how to start the program Files in the comman line?

We need to look into all *.desktop files for the name. There, we find the command in the Exec line:

locate -b '.desktop' | xargs grep -ls '^Name.*=Files$' | xargs grep '^Exec.*'

lists desktop file names and commands for the GUI program File - replace that with the exact name you look for - even it it's multiple words (for substring search, leave out the = and $).

With the command, I find Files may be nautilus, dolphin or active-filebrowser:

/etc/xdg/autostart/nautilus-autostart.desktop:Exec=nautilus -n
/usr/share/app-install/desktop/nemo:nemo.desktop:Exec=nemo %U
/usr/share/app-install/desktop/plasma-active:kde4__active-filebrowser.desktop:Exec=active-filebrowser -graphicssystem raster %u
/usr/share/applications/nautilus-folder-handler.desktop:Exec=nautilus %U
/usr/share/applications/nautilus.desktop:Exec=nautilus --new-window %U
/usr/share/applications/nautilus.desktop:Exec=nautilus --new-window
  • Mmm, my question underlies a view of linux of a scaled complexity, where more elaborated programs are build upon simpler code, so I thought any GUI application is relying on terminal commands but might not be the case since terminal is based on bash code whereas software could be written in python or c++ or etc. Am I wrong? – user308164 Sep 7 '14 at 21:32
  • The layers of complexity do exist, but in a different way: rougnly, there are system calls, library functions, and on top either a graphical user interface, or a command line interface - they are alternatives. – Volker Siegel Sep 8 '14 at 11:44

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy