cryptonas/plugins/logs/logs.py
lars 794998f950 broken interface fixed in 'partition' plugin for ie
rendering bug of volume_properties fixed for ie
fixed screen width in a mozilla/ie compatible way
added german translation: 'log', 'network', 'volume_automount' and 'volume_details'
fixed config management of 'plugin_manager' plugin
fixed filtering of log level messages for 'logs' plugin
updated documentation for ssl configurations
changed default installation destinations in setup.py
added nice background images to environment and help messages
replaced message 'div' with 'fieldset'
moved stylesheet data of plugins to html header (as required by spec)
removed obsolete css definitions
removed obsolete old perl/bash code
improved 'update_po_files': remove obsolete msgids
functionality of 'update_english.sh' moved to 'update_po_files'
omit 'weblang' link attribute if it does not change the default setting
changed default language from 'de' to 'en'
fixed template bug that prevented the translation of plugin links
fixed invalid html
implement filecheck overriding for unittests
2006-12-18 13:37:08 +00:00

194 lines
6 KiB
Python

#
# Copyright 2006 sense.lab e.V.
#
# This file is part of the CryptoBox.
#
# The CryptoBox is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# The CryptoBox is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with the CryptoBox; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
"""The logs feature of the CryptoBox.
"""
__revision__ = "$Id"
import cryptobox.plugins.base
import os
import re
import datetime
LOG_LEVELS = [ 'DEBUG', 'INFO', 'NOTICE', 'WARNING', 'ERROR' ]
LINE_REGEX = re.compile(r"(?P<year>\d{4})-(?P<month>\d{2})-(?P<day>\d{2}) " \
+ r"(?P<hour>\d{2}):(?P<minute>\d{2}):\d{2},\d{3} (?P<level>" \
+ "|".join([ "(?:%s)" % e for e in LOG_LEVELS]) + r"): (?P<text>.*)$")
class logs(cryptobox.plugins.base.CryptoBoxPlugin):
"""The logs feature of the CryptoBox.
"""
plugin_capabilities = [ "system" ]
plugin_visibility = [ "preferences" ]
request_auth = False
rank = 90
def do_action(self, lines=50, size=3000, level=None):
"""Show the latest part of the log file.
"""
## filter input
try:
lines = int(lines)
if lines <= 0:
raise(ValueError)
except ValueError:
self.cbox.log.info("[logs] invalid line number: %s" % str(lines))
lines = 50
try:
size = int(size)
if size <= 0:
raise(ValueError)
except ValueError:
self.cbox.log.info("[logs] invalid log size: %s" % str(size))
size = 3000
if not level is None:
level = str(level)
if not level in LOG_LEVELS:
self.cbox.log.info("[logs] invalid log level: %s" % str(level))
level = None
for (index, line) in enumerate(self.__filter_log_content(lines, size, level)):
self.__set_line_hdf_data(self.hdf_prefix + "Content.%d" % index, line)
self.hdf[self.hdf_prefix + "Destination"] = self.cbox.prefs["Log"]["Destination"].lower()
return "show_log"
def get_status(self):
"""The current status includes the log configuration details.
"""
return "%s:%s:%s" % (
self.cbox.prefs["Log"]["Level"],
self.cbox.prefs["Log"]["Destination"],
self.cbox.prefs["Log"]["Details"])
def __filter_log_content(self, lines, max_size, level):
"""Filter, sort and shorten the log content.
"""
if level and level in LOG_LEVELS:
filtered_levels = LOG_LEVELS[:]
## only the given and higher levels are accepted
while filtered_levels[0] != level:
del filtered_levels[0]
content = []
current_length = 0
for line in self.__get_log_data():
## search for matching lines for the given log level
for one_level in filtered_levels:
if line.find(" %s: " % one_level) != -1:
break
else:
## the line does not contain an appropriate level name
continue
## we found a line that fits
content.append(line)
current_length += len(line)
if lines and len(content) >= lines:
break
if max_size and current_length >= max_size:
break
else:
content = self.__get_log_data(lines, max_size)
return content
def __set_line_hdf_data(self, hdf_prefix, line):
"""Parse the log line for time and log level.
If parsing fails, then the output line is simply displayed without
meta information.
"""
self.hdf[hdf_prefix + ".Text"] = line.strip()
match = LINE_REGEX.match(line)
if not match:
## we could not parse the line - just return the text without meta info
return
## matching was successfully - we can parse the line for details
## calculate time difference of log line (aka: age of event)
try:
(year, month, day, hour, minute) = match.group(
'year', 'month', 'day', 'hour', 'minute')
(year, month, day, hour, minute) = \
(int(year), int(month), int(day), int(hour), int(minute))
## timediff is a timedelta object
timediff = datetime.datetime.today() - \
datetime.datetime(year, month, day, hour, minute)
## the time units (see below) correspond to the names within the language
## file: Text.TimeUnits.Days ...
if timediff.days >= 1:
self.hdf[hdf_prefix + ".TimeDiff.Unit"] = 'Days'
self.hdf[hdf_prefix + ".TimeDiff.Value"] = timediff.days
elif timediff.seconds >= 3600:
self.hdf[hdf_prefix + ".TimeDiff.Unit"] = 'Hours'
self.hdf[hdf_prefix + ".TimeDiff.Value"] = timediff.seconds / 3600
elif timediff.seconds >= 60:
self.hdf[hdf_prefix + ".TimeDiff.Unit"] = 'Minutes'
self.hdf[hdf_prefix + ".TimeDiff.Value"] = timediff.seconds / 60
else:
self.hdf[hdf_prefix + ".TimeDiff.Unit"] = 'Seconds'
self.hdf[hdf_prefix + ".TimeDiff.Value"] = timediff.seconds
except (OverflowError, TypeError, ValueError, IndexError), err_msg:
pass
## retrieve the level
try:
self.hdf[hdf_prefix + ".Level"] = match.group('level')
except IndexError:
pass
try:
self.hdf[hdf_prefix + ".Text"] = match.group('text').strip()
except IndexError:
pass
def __get_log_data(self, lines=None, max_size=None):
"""get the most recent log entries of the log file
the maximum number and size of these entries can be limited by
'lines' and 'max_size'
"""
# return nothing if the currently selected log output is not a file
try:
if self.cbox.prefs["Log"]["Destination"].upper() != "FILE":
return []
log_file = self.cbox.prefs["Log"]["Details"]
except KeyError:
self.cbox.log.error(
"could not evaluate one of the following config settings: "
+ "[Log]->Destination or [Log]->Details")
return []
try:
fdesc = open(log_file, "r")
if max_size:
fdesc.seek(-max_size, 2) # seek relative to the end of the file
content = fdesc.readlines()
fdesc.close()
except IOError:
self.cbox.log.warn("failed to read the log file (%s)" % log_file)
return []
if lines:
content = content[-lines:]
content.reverse()
return content