######################################################################
# This program 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 3 of the License, or
# (at your option) any later version.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
#
# Copyright 2007 Petteri Aimonen
#
'''Log keeper for import and upkeep events, and log rendering'''
from pymisc import _
class LogCategory:
'''Base class for log categories'''
name = 'baselog'
priority = 0
class ListLogCategory(LogCategory):
'''Base class for list based log categories'''
header = ''
cols = []
formatstring = ''
sortbyindex = 0
sortreverse = False
separator = '
'
def __init__(self):
self.entries = []
def haslog(self):
return bool(self.entries)
def log(self, *args):
self.entries.append(args)
def format(self):
pars = {'count': len(self.entries)}
msg = '' + self.header % pars + '
'
self.entries.sort(key = lambda r, i = self.sortbyindex: r[i],
reverse = self.sortreverse)
rows = []
for entry in self.entries:
pars = {}
for i, colname in enumerate(self.cols):
pars[colname] = entry[i]
rows.append(self.formatstring % pars)
msg += self.separator.join(rows)
return msg
class BooleanLogCategory(LogCategory):
'''Base class for boolean state log categories'''
message = ''
def __init__(self):
self.state = False
def haslog(self):
return self.state
def log(self):
self.state = True
def format(self):
if self.state:
return self.message
else:
return ''
class AidListLogCategory(ListLogCategory):
'''Simple list of animalids'''
cols = ['aid']
separator = ', '
formatstring = _('%(aid)d')
# Log categories
class LC_Animals(AidListLogCategory):
name = 'new_animal'
priority = 1
header = _('Added %(count)d new animals to database:')
class LC_Moves(ListLogCategory):
name = 'moved_animal'
priority = 2
cols = ['aid', 'from', 'to']
header = _('Moved %(count)d animals:')
formatstring = _('Animal %(aid)d ' \
'from %(from)d ' \
'to %(to)d')
class LC_ReadFail(ListLogCategory):
name = 'readfail'
priority = 5
cols = ['file', 'exc']
header = _('Reading following files failed:')
formatstring = _('File %(file)s: %(exc)s
')
class LC_InactiveHasFeeds(AidListLogCategory):
name = 'inactivehasfeeds'
priority = 2
header = _('Following animals have feed data despite marked inactive:')
class LC_MarkedInactive(AidListLogCategory):
name = 'markedinactive'
priority = 1
header = _('Following animals were marked inactive:')
class LC_RemovedAnimal(AidListLogCategory):
name = 'removedanimal'
priority = 1
header = _('Following animals were removed from database:')
format = _('%(aid)s') # No link for removed animals
class LC_UpkeepCheckFail(ListLogCategory):
name = 'upkeep_checkfail'
priority = 5
header = _('Following upkeep checks failed:')
cols = ['desc', 'exc']
formatstring = _('%(desc)s: %(exc)s
')
class LC_SkippedAfeed(ListLogCategory):
name = 'skipped_afeed'
priority = 5
header = _('Parsing following lines in per-animal data failed:')
cols = ['file', 'line']
formatstring = _('%(file)s: %(line)s')
class LC_SkippedGfeed(ListLogCategory):
name = 'skipped_gfeed'
priority = 5
header = _('Parsing following lines in groupfeed data failed:')
cols = ['line']
formatstring = _('%(line)s')
class LC_MissingGfeed(BooleanLogCategory):
name = 'missing_gfeed'
priority = 5
message = _('Days are missing from groupfeed data')
class LC_FilledInGfeed(BooleanLogCategory):
name = 'filledin_gfeed'
priority = 3
message = _('Missing days in groupfeed data have been filled in ' \
'with averages')
class LC_SmallFeed(ListLogCategory):
name = 'smallfeed'
priority = 2
sortbyindex = 1
header = _('Following animals have low feed amounts:')
cols = ['aid', 'grams']
formatstring = _('%(aid)d: %(grams)d grams')
class LC_FeedDelta(ListLogCategory):
name = 'feeddelta'
priority = 2
sortbyindex = 1
sortreverse = True
header = _('Following animals have high deviations in feed amounts:')
cols = ['aid', 'delta']
formatstring = _('%(aid)d: %(delta)0.1f %%')
def get_lclist():
'''Gather list of LogCategories'''
r = []
for name, value in globals().items():
if not name.startswith('LC_'):
continue
if not issubclass(value, LogCategory):
continue
r.append(value)
return r
class ImportLogger:
'''Keeps track of import events'''
def __init__(self):
self.categories = dict([(c.name, c()) for c in get_lclist()])
def haslog(self):
for c in self.categories:
if c.haslog():
return True
return False
# Log formatting
def format(self):
'''Format all messages as html'''
msgs = []
categories = self.categories.values()
categories.sort(key = lambda c: c.priority, reverse = True)
for c in categories:
if c.haslog():
msgs.append(c.format())
return '
'.join(msgs)
# Logging, like Logger.log_smallfeed(...)
def __getattr__(self, name):
if name.startswith('log_') and self.categories.has_key(name[4:]):
return self.categories[name[4:]].log
else:
raise AttributeError, name