Let application decides on how to handle signals.
[laditools.git] / ladi-system-log
blob1dfe9f61b6544e1b90829d8937887e3259775b8c
1 #!/usr/bin/python
3 # LADITools - Linux Audio Desktop Integration Tools
4 # ladi-system-log - A log viewer for your Linux Audio Desktop
5 # Copyright (C) 2011-2012 Alessio Treglia <quadrispro@ubuntu.com>
6 # Copyright (C) 2007-2010, Marc-Olivier Barre <marco@marcochapeau.org>
7 # Copyright (C) 2007-2009, Nedko Arnaudov <nedko@arnaudov.name>
9 # This program is free software: you can redistribute it and/or modify
10 # it under the terms of the GNU General Public License as published by
11 # the Free Software Foundation, either version 3 of the License, or
12 # (at your option) any later version.
14 # This program is distributed in the hope that it will be useful,
15 # but WITHOUT ANY WARRANTY; without even the implied warranty of
16 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 # GNU General Public License for more details.
19 # You should have received a copy of the GNU General Public License
20 # along with this program. If not, see <http://www.gnu.org/licenses/>.
22 import os
23 import sys
24 import signal
25 from subprocess import Popen, PIPE
26 import pty
27 from signal import SIGTERM
28 import termios
29 import tty
30 import gettext
31 import argparse
33 sig_handler = signal.getsignal(signal.SIGTERM)
34 signal.signal(signal.SIGINT, sig_handler)
36 from laditools import _gettext_domain
37 gettext.install(_gettext_domain)
39 from laditools import get_version_string
40 from laditools import LadiConfiguration
41 from laditools import LadiApp
43 from gi.repository import Gtk
44 from gi.repository import GObject
45 from gi.repository import Vte
47 from laditools.gtk import find_data_file
49 timeout_add = GObject.timeout_add
51 # Default configuration
52 max_lines_default = 100
54 # Output the last <lines> lines
55 def read_last(lfile, lines):
56 chunk_size = lines * 60
57 lfile.seek(0, 2)
58 endpos = lfile.tell()
59 pos = endpos - chunk_size
60 if pos < 0:
61 pos = 0
62 backlog = ''
63 backlog_size = 0
64 lines += 1
65 while pos >= 0 and backlog_size <= lines:
66 lfile.seek(pos, 0)
67 s = lfile.read(chunk_size)
68 pos = pos - chunk_size
69 backlog_size += s.count("\n")
70 backlog = s + backlog
71 backlog = backlog.strip().split("\n")
72 if len(backlog) > lines:
73 backlog = backlog[-lines:]
74 lfile.seek(endpos, 0)
75 return backlog
77 class LadiSystemLog(LadiApp):
79 _appname = 'ladi-system-log'
80 _appname_long = _("LADI Log Viewer")
81 _appid = 'org.linuxaudio.ladi.logviewer'
83 _default_config = { 'max_lines' : max_lines_default }
85 def __init__ (self):
86 self.log_files = [
88 'name': 'JACK',
89 'config_name': 'jackdbus_log',
90 'config_default': os.sep.join([os.environ['HOME'], ".log", "jack", "jackdbus.log"])
93 'name': 'LADISH',
94 'config_name': 'ladish_log',
95 'config_default': os.sep.join([os.environ['HOME'], ".log", "ladish", "ladish.log"])
98 'name': 'A2J',
99 'config_name': 'a2j_log',
100 'config_default': os.sep.join([os.environ['HOME'], ".log", "a2j", "a2j.log"])
103 # Handle the configuration
104 for log in self.log_files:
105 self._default_config[log['config_name']] = log['config_default']
106 self.global_config = LadiConfiguration (self.appname, self._default_config)
107 self.param_dict = self.global_config.get_config_section (self.appname)
109 for log in self.log_files[:]:
110 log['logfile_path'] = self.param_dict[log['config_name']]
111 # skip logfiles that dont exist
112 if not os.access(log['logfile_path'], os.R_OK):
113 self.log_files.remove(log)
114 sys.stderr.write( _("Skipping '%s' because it does not exist\n") % log['logfile_path'])
115 else:
116 sys.stderr.write( _("Watching %s\n") % log['logfile_path'])
117 sys.stderr.flush()
119 max_lines_text = self.param_dict['max_lines']
120 self.max_lines = int (max_lines_text)
121 # Load the glade file
122 builder = Gtk.Builder()
123 builder.add_from_file(find_data_file("ladi-system-log.ui"))
124 sys.stderr.write( _("Loading interface from %s\n") % find_data_file("ladilog_ui.ui"))
125 sys.stderr.flush()
126 # Get the ui ready for action
127 self.event_dict = {"on_ladilog_ui_destroy" : self.on_quit,
128 "on_ladilog_ui_delete" : self.on_delete,
129 "on_close_button_clicked" : self.on_quit,
130 "on_clear_button_clicked" : self.on_clear_text,
131 "on_purge_button_clicked" : self.on_purge}
132 builder.connect_signals(self.event_dict)
134 self.ui = ui = builder.get_object("ladilog_ui")
135 self.logview_notebook = builder.get_object ("ladilog_notebook")
136 # Create our terminal and display it
137 for log in self.log_files:
138 log['scrolled_window'] = sw = Gtk.ScrolledWindow()
139 log['term'] = term = Vte.Terminal.new ()
140 sw.set_policy(hscrollbar_policy=Gtk.PolicyType.AUTOMATIC,
141 vscrollbar_policy=Gtk.PolicyType.ALWAYS)
142 sw.add(term)
143 sw.show()
144 term.set_scroll_on_output(True)
145 log["tab_label"] = Gtk.Label(label=log["name"])
147 self.logview_notebook.append_page(log["scrolled_window"],
148 log["tab_label"])
150 # Make it do something...
151 for log in self.log_files:
152 try:
153 log['log_file'] = open(log['logfile_path'], "rb")
154 sys.stderr.write (_("Opening %s...\n") % log['logfile_path'])
155 lines = read_last(log['log_file'], self.max_lines)
156 for line in lines:
157 line = line.strip('\r\n') + '\r\n'
158 log["term"].feed(line, -1)
159 except ValueError:
160 sys.stderr.write( _("You called Popen with invalid arguments... dumbass\n") )
161 except:
162 sys.stderr.write( _("Unexpected error: %s\n") % (sys.exc_info ()[0]))
163 finally:
164 sys.stderr.flush()
166 ui.show_all()
167 self.auto_updater = timeout_add(250, self.update, None)
169 def update(self, user_data = None):
170 # Append latest output to the buffer
171 for log in self.log_files:
172 line = log['log_file'].readline()
173 while line:
174 log["term"].feed(line + '\r', -1)
175 line = log['log_file'].readline()
176 log['log_file'].seek(log['log_file'].tell())
177 return True
179 def on_delete(self, widget=None, data=None):
180 return False
182 def on_quit (self, data=None):
183 Gtk.main_quit ()
185 def on_clear_text (self, data=None):
186 current_view = self.logview_notebook.get_current_page ()
187 self.log_files[current_view]["term"].feed ("\033[2J\033[;f", -1)
189 def on_purge (self, data=None):
190 current_view = self.logview_notebook.get_current_page ()
191 # Opens the file in write anew mode thus clearing the file and close it right away
192 open (self.log_files[current_view]['logfile_path'], "w+")
193 self.log_files[current_view]["term"].feed ("\033[2J\033[;f", -1)
195 def run (self):
196 Gtk.main ()
197 self.global_config.set_config_section (self.appname, self.param_dict)
198 self.global_config.save ()
199 return 0
201 if __name__ == '__main__':
202 parser = argparse.ArgumentParser(description=_('JACK, ladish and a2jmidid log viewer'),
203 epilog=_('This program is part of the LADITools suite.'))
204 parser.add_argument('--version', action='version', version="%(prog)s " + get_version_string())
206 parser.parse_args()
207 LadiSystemLog().run()
208 sys.exit(0)