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/>.
25 from subprocess
import Popen
, PIPE
27 from signal
import SIGTERM
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
59 pos
= endpos
- chunk_size
65 while pos
>= 0 and backlog_size
<= lines
:
67 s
= lfile
.read(chunk_size
)
68 pos
= pos
- chunk_size
69 backlog_size
+= s
.count("\n")
71 backlog
= backlog
.strip().split("\n")
72 if len(backlog
) > lines
:
73 backlog
= backlog
[-lines
:]
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
}
89 'config_name': 'jackdbus_log',
90 'config_default': os
.sep
.join([os
.environ
['HOME'], ".log", "jack", "jackdbus.log"])
94 'config_name': 'ladish_log',
95 'config_default': os
.sep
.join([os
.environ
['HOME'], ".log", "ladish", "ladish.log"])
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'])
116 sys
.stderr
.write( _("Watching %s\n") % log
['logfile_path'])
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"))
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
)
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"],
150 # Make it do something...
151 for log
in self
.log_files
:
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
)
157 line
= line
.strip('\r\n') + '\r\n'
158 log
["term"].feed(line
, -1)
160 sys
.stderr
.write( _("You called Popen with invalid arguments... dumbass\n") )
162 sys
.stderr
.write( _("Unexpected error: %s\n") % (sys
.exc_info ()[0]))
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()
174 log
["term"].feed(line
+ '\r', -1)
175 line
= log
['log_file'].readline()
176 log
['log_file'].seek(log
['log_file'].tell())
179 def on_delete(self
, widget
=None, data
=None):
182 def on_quit (self
, data
=None):
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)
197 self
.global_config
.set_config_section (self
.appname
, self
.param_dict
)
198 self
.global_config
.save ()
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())
207 LadiSystemLog().run()