Update manpage.
[laditools.git] / ladi-system-log
blobc5a987d4923ac995c647ee11adc5389b803bed51
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 import termios
28 import tty
29 import gettext
30 import argparse
32 from laditools import _gettext_domain
33 gettext.install(_gettext_domain)
35 from laditools import get_version_string
36 from laditools import LadiConfiguration
37 from laditools import LadiApp
39 from gi.repository import Gtk
40 from gi.repository import GObject
41 from gi.repository import Vte
43 from laditools.gtk import find_data_file
45 timeout_add = GObject.timeout_add
47 # Default configuration
48 max_lines_default = 100
50 # Output the last <lines> lines
51 def read_last(lfile, lines):
52 chunk_size = lines * 60
53 lfile.seek(0, 2)
54 endpos = lfile.tell()
55 pos = endpos - chunk_size
56 if pos < 0:
57 pos = 0
58 backlog = ''
59 backlog_size = 0
60 lines += 1
61 while pos >= 0 and backlog_size <= lines:
62 lfile.seek(pos, 0)
63 s = lfile.read(chunk_size)
64 pos = pos - chunk_size
65 backlog_size += s.count("\n")
66 backlog = s + backlog
67 backlog = backlog.strip().split("\n")
68 if len(backlog) > lines:
69 backlog = backlog[-lines:]
70 lfile.seek(endpos, 0)
71 return backlog
73 class LadiSystemLog(LadiApp):
75 _appname = 'ladi-system-log'
76 _appname_long = _("LADI Log Viewer")
77 _appid = 'org.linuxaudio.ladi.logviewer'
79 _default_config = { 'max_lines' : max_lines_default }
81 def __init__ (self):
82 LadiApp.__init__(self)
84 self.log_files = [
86 'name': 'JACK',
87 'config_name': 'jackdbus_log',
88 'config_default': os.sep.join([os.environ['HOME'], ".log", "jack", "jackdbus.log"])
91 'name': 'LADISH',
92 'config_name': 'ladish_log',
93 'config_default': os.sep.join([os.environ['HOME'], ".log", "ladish", "ladish.log"])
96 'name': 'A2J',
97 'config_name': 'a2j_log',
98 'config_default': os.sep.join([os.environ['HOME'], ".log", "a2j", "a2j.log"])
102 # Handle the configuration
103 for log in self.log_files:
104 self._default_config[log['config_name']] = log['config_default']
105 self.global_config = LadiConfiguration (self.appname, self._default_config)
106 self.param_dict = self.global_config.get_config_section (self.appname)
108 self.connect_signals_quit()
110 for log in self.log_files[:]:
111 log['logfile_path'] = self.param_dict[log['config_name']]
112 # skip logfiles that dont exist
113 if not os.access(log['logfile_path'], os.R_OK):
114 self.log_files.remove(log)
115 sys.stderr.write( _("Skipping '%s' because it does not exist\n") % log['logfile_path'])
116 else:
117 sys.stderr.write( _("Watching %s\n") % log['logfile_path'])
118 sys.stderr.flush()
120 max_lines_text = self.param_dict['max_lines']
121 self.max_lines = int (max_lines_text)
123 # Load the glade file
124 uifile = find_data_file('ladi-system-log.ui')
125 builder = Gtk.Builder()
126 builder.add_from_file(uifile)
127 sys.stderr.write( _("Loading interface from %s\n") % uifile)
128 sys.stderr.flush()
130 # Get the ui ready for action
131 self.event_dict = {"on_ladilog_ui_destroy" : self.quit,
132 "on_ladilog_ui_delete" : self.on_delete,
133 "on_close_button_clicked" : self.quit,
134 "on_clear_button_clicked" : self.on_clear_text,
135 "on_purge_button_clicked" : self.on_purge}
136 builder.connect_signals(self.event_dict)
138 self.ui = ui = builder.get_object("ladilog_ui")
139 self.logview_notebook = builder.get_object ("ladilog_notebook")
141 # Create our terminal and display it
142 for log in self.log_files:
143 log['scrolled_window'] = sw = Gtk.ScrolledWindow()
144 log['term'] = term = Vte.Terminal.new ()
145 sw.set_policy(hscrollbar_policy=Gtk.PolicyType.AUTOMATIC,
146 vscrollbar_policy=Gtk.PolicyType.ALWAYS)
147 sw.add(term)
148 sw.show()
149 term.set_scroll_on_output(True)
150 log["tab_label"] = Gtk.Label(label=log["name"])
152 self.logview_notebook.append_page(log["scrolled_window"],
153 log["tab_label"])
155 # Make it do something...
156 for log in self.log_files:
157 try:
158 log['log_file'] = open(log['logfile_path'], "rb")
159 sys.stderr.write (_("Opening %s...\n") % log['logfile_path'])
160 lines = read_last(log['log_file'], self.max_lines)
161 for line in lines:
162 line = line.strip('\r\n') + '\r\n'
163 log["term"].feed(line, -1)
164 except ValueError:
165 sys.stderr.write( _("You called Popen with invalid arguments... dumbass\n") )
166 except:
167 sys.stderr.write( _("Unexpected error: %s\n") % (sys.exc_info ()[0]))
168 finally:
169 sys.stderr.flush()
171 self.auto_updater = timeout_add(250, self.update, None)
173 def update(self, user_data = None):
174 # Append latest output to the buffer
175 for log in self.log_files:
176 line = log['log_file'].readline()
177 while line:
178 log["term"].feed(line + '\r', -1)
179 line = log['log_file'].readline()
180 log['log_file'].seek(log['log_file'].tell())
181 return True
183 def on_delete(self, widget=None, data=None):
184 return False
186 def quit (self, *args, **kwargs):
187 self.global_config.set_config_section (self.appname, self.param_dict)
188 self.global_config.save ()
189 Gtk.main_quit ()
191 def on_clear_text (self, data=None):
192 current_view = self.logview_notebook.get_current_page ()
193 self.log_files[current_view]["term"].feed ("\033[2J\033[;f", -1)
195 def on_purge (self, data=None):
196 current_view = self.logview_notebook.get_current_page ()
197 # Opens the file in write anew mode thus clearing the file and close it right away
198 open (self.log_files[current_view]['logfile_path'], "w+")
199 self.log_files[current_view]["term"].feed ("\033[2J\033[;f", -1)
201 def run (self):
202 self.ui.show_all()
203 Gtk.main ()
205 if __name__ == '__main__':
206 parser = argparse.ArgumentParser(description=_('JACK, ladish and a2jmidid log viewer'),
207 epilog=_('This program is part of the LADITools suite.'))
208 parser.add_argument('--version', action='version', version="%(prog)s " + get_version_string())
209 parser.parse_args()
211 Gtk.init(None)
213 LadiSystemLog().run()
215 sys.exit(0)