summary |
shortlog |
log |
commit | commitdiff |
tree
raw |
patch |
inline | side by side (from parent 1:
c873b2d)
Start using the python logging module to handle output and log
messages. A single logger named 'time-slider' is used from the
main program and all modules.
All direct calls to sys.stderr.write are moved to .error
calls on the respective logger.
When running in foreground mode all log messages are sent to
stdout, when running in background mode all log messages are
sent to syslog.
import calendar
import signal
import argparse
import calendar
import signal
import argparse
+import logging
+from logging.handlers import SysLogHandler
import glib
import gobject
import glib
import gobject
self._zpools = []
self._poolstatus = {}
self._destroyedsnaps = []
self._zpools = []
self._poolstatus = {}
self._destroyedsnaps = []
+ self.logger = logging.getLogger('time-slider')
# This is also checked during the refresh() method but we need
# to know it sooner for instantiation of the PluginManager
# This is also checked during the refresh() method but we need
# to know it sooner for instantiation of the PluginManager
try:
self.verbose = self._smf.get_verbose()
except RuntimeError,message:
try:
self.verbose = self._smf.get_verbose()
except RuntimeError,message:
- sys.stderr.write("Error determing whether debugging is enabled\n")
+ self.logger.error("Error determing whether debugging is enabled")
self.verbose = False
self._dbus = dbussvc.AutoSnap(bus,
self.verbose = False
self._dbus = dbussvc.AutoSnap(bus,
self._conditionLock.wait(_MINUTE * 15)
except OSError, message:
self._conditionLock.wait(_MINUTE * 15)
except OSError, message:
- sys.stderr.write("Caught OSError exception in snapshot" +
- " manager thread\n")
- sys.stderr.write("Error details:\n" + \
+ self.logger.error("Caught OSError exception in snapshot" +
+ " manager thread")
+ self.logger.error("Error details:\n" + \
"--------BEGIN ERROR MESSAGE--------\n" + \
str(message) + \
"--------BEGIN ERROR MESSAGE--------\n" + \
str(message) + \
- "\n--------END ERROR MESSAGE--------\n")
+ "\n--------END ERROR MESSAGE--------")
self.exitCode = smf.SMF_EXIT_ERR_FATAL
# Exit this thread
break
except RuntimeError,message:
self.exitCode = smf.SMF_EXIT_ERR_FATAL
# Exit this thread
break
except RuntimeError,message:
- sys.stderr.write("Caught RuntimeError exception in snapshot" +
- " manager thread\n")
- sys.stderr.write("Error details:\n" + \
+ self.logger.error("Caught RuntimeError exception in snapshot" +
+ " manager thread")
+ self.logger.error("Error details:\n" + \
"--------BEGIN ERROR MESSAGE--------\n" + \
str(message) + \
"--------BEGIN ERROR MESSAGE--------\n" + \
str(message) + \
- "\n--------END ERROR MESSAGE--------\n")
+ "\n--------END ERROR MESSAGE--------")
try:
self.verbose = self._smf.get_verbose()
except RuntimeError,message:
try:
self.verbose = self._smf.get_verbose()
except RuntimeError,message:
- sys.stderr.write("Error determing whether debugging is enabled\n")
+ self.logger.error("Error determing whether debugging is enabled")
self.verbose = False
try:
self.verbose = False
try:
emer = self._smf.get_cleanup_level("emergency")
util.debug("Emergency level value is: %d%%" % emer, self.verbose)
except RuntimeError,message:
emer = self._smf.get_cleanup_level("emergency")
util.debug("Emergency level value is: %d%%" % emer, self.verbose)
except RuntimeError,message:
- sys.stderr.write("Failed to determine cleanup threshhold levels\n")
- sys.stderr.write("Details:\n" + \
+ self.logger.error("Failed to determine cleanup threshhold levels")
+ self.logger.error("Details:\n" + \
"--------BEGIN ERROR MESSAGE--------\n" + \
str(message) + \
"\n---------END ERROR MESSAGE---------\n")
"--------BEGIN ERROR MESSAGE--------\n" + \
str(message) + \
"\n---------END ERROR MESSAGE---------\n")
- sys.stderr.write("Using factory defaults of 80%, 90% and 95%\n")
+ self.logger.error("Using factory defaults of 80%, 90% and 95%")
#Go with defaults
#FIXME - this would be an appropriate case to mark svc as degraded
self._remedialCleanup = True
#Go with defaults
#FIXME - this would be an appropriate case to mark svc as degraded
self._remedialCleanup = True
self._keepEmpties = self._smf.get_keep_empties()
except RuntimeError,message:
# Not fatal, just assume we delete them (default configuration)
self._keepEmpties = self._smf.get_keep_empties()
except RuntimeError,message:
# Not fatal, just assume we delete them (default configuration)
- sys.stderr.write("Can't determine whether to keep empty snapshots\n")
- sys.stderr.write("Details:\n" + \
+ self.logger.error("Can't determine whether to keep empty snapshots")
+ self.logger.error("Details:\n" + \
"--------BEGIN ERROR MESSAGE--------\n" + \
str(message) + \
"--------BEGIN ERROR MESSAGE--------\n" + \
str(message) + \
- "\n---------END ERROR MESSAGE---------\n")
- sys.stderr.write("Assuming default value: False\n")
+ "\n---------END ERROR MESSAGE---------")
+ self.logger.error("Assuming default value: False")
self._keepEmpties = False
# Previously, snapshot labels used the ":" character was used as a
self._keepEmpties = False
# Previously, snapshot labels used the ":" character was used as a
self._zpools.append(zpool)
util.debug(str(zpool), self.verbose)
except RuntimeError,message:
self._zpools.append(zpool)
util.debug(str(zpool), self.verbose)
except RuntimeError,message:
- sys.stderr.write("Could not list Zpools\n")
+ self.logger.error("Could not list Zpools")
self.exitCode = smf.SMF_EXIT_ERR_FATAL
# Propogate exception up to thread's run() method
raise RuntimeError,message
self.exitCode = smf.SMF_EXIT_ERR_FATAL
# Propogate exception up to thread's run() method
raise RuntimeError,message
schedule))
except RuntimeError,message:
self.exitCode = smf.SMF_EXIT_ERR_FATAL
schedule))
except RuntimeError,message:
self.exitCode = smf.SMF_EXIT_ERR_FATAL
- sys.stderr.write("Failed to list snapshots during schedule update\n")
+ self.logger.error("Failed to list snapshots during schedule update")
#Propogate up to the thread's run() method
raise RuntimeError,message
#Propogate up to the thread's run() method
raise RuntimeError,message
totalinterval = intervals[interval] * period
except KeyError:
self.exitCode = smf.SMF_EXIT_ERR_CONFIG
totalinterval = intervals[interval] * period
except KeyError:
self.exitCode = smf.SMF_EXIT_ERR_CONFIG
- sys.stderr.write(schedule + \
+ self.logger.error(schedule + \
" schedule has invalid interval: " + \
" schedule has invalid interval: " + \
#Propogate up to thread's run() method
raise RuntimeError
if [schedule,interval,period,keep] in self._defaultSchedules:
#Propogate up to thread's run() method
raise RuntimeError
if [schedule,interval,period,keep] in self._defaultSchedules:
except RuntimeError, message:
# Write an error message, set the exit code and pass it up the
# stack so the thread can terminate
except RuntimeError, message:
# Write an error message, set the exit code and pass it up the
# stack so the thread can terminate
- sys.stderr.write("Failed to create snapshots for schedule: %s\n" \
+ self.logger.error("Failed to create snapshots for schedule: %s" \
% (schedule))
self.exitCode = smf.SMF_EXIT_MON_DEGRADE
raise RuntimeError,message
% (schedule))
self.exitCode = smf.SMF_EXIT_MON_DEGRADE
raise RuntimeError,message
# while iterating through it.
remainingsnaps = snaps[:]
except RuntimeError,message:
# while iterating through it.
remainingsnaps = snaps[:]
except RuntimeError,message:
- sys.stderr.write("Failed to list snapshots during snapshot cleanup\n")
+ self.logger.error("Failed to list snapshots during snapshot cleanup")
self.exitCode = smf.SMF_EXIT_ERR_FATAL
raise RuntimeError,message
self.exitCode = smf.SMF_EXIT_ERR_FATAL
raise RuntimeError,message
try:
snapshot = zfs.Snapshot(snapname)
except Exception,message:
try:
snapshot = zfs.Snapshot(snapname)
except Exception,message:
- sys.stderr.write(str(message))
+ self.logger.error(str(message))
# Not fatal, just skip to the next snapshot
continue
# Not fatal, just skip to the next snapshot
continue
try:
snapshot.destroy()
except RuntimeError,message:
try:
snapshot.destroy()
except RuntimeError,message:
- sys.stderr.write("Failed to destroy snapshot: " +
- snapname + "\n")
+ self.logger.error("Failed to destroy snapshot: " +
+ snapname)
self.exitCode = smf.SMF_EXIT_MON_DEGRADE
# Propogate exception so thread can exit
raise RuntimeError,message
remainingsnaps.remove(snapname)
except RuntimeError,message:
self.exitCode = smf.SMF_EXIT_MON_DEGRADE
# Propogate exception so thread can exit
raise RuntimeError,message
remainingsnaps.remove(snapname)
except RuntimeError,message:
- sys.stderr.write("Can not determine used size of: " + \
- snapname + "\n")
+ self.logger.error("Can not determine used size of: " + \
+ snapname)
self.exitCode = smf.SMF_EXIT_MON_DEGRADE
#Propogate the exception to the thead run() method
raise RuntimeError,message
self.exitCode = smf.SMF_EXIT_MON_DEGRADE
#Propogate the exception to the thead run() method
raise RuntimeError,message
try:
snapshot = zfs.Snapshot(remainingsnaps[counter])
except Exception,message:
try:
snapshot = zfs.Snapshot(remainingsnaps[counter])
except Exception,message:
- sys.stderr.write(str(message))
+ self.logger.error(str(message))
# Not fatal, just skip to the next snapshot
counter += 1
continue
try:
snapshot.destroy()
except RuntimeError,message:
# Not fatal, just skip to the next snapshot
counter += 1
continue
try:
snapshot.destroy()
except RuntimeError,message:
- sys.stderr.write("Failed to destroy snapshot: " +
- snapshot.name + "\n")
+ self.logger.error("Failed to destroy snapshot: " +
+ snapshot.name)
self.exitCode = smf.SMF_EXIT_ERR_FATAL
# Propogate exception so thread can exit
raise RuntimeError,message
self.exitCode = smf.SMF_EXIT_ERR_FATAL
# Propogate exception so thread can exit
raise RuntimeError,message
dataset = zfs.ReadWritableDataset(name)
self._prune_snapshots(dataset, schedule)
except RuntimeError,message:
dataset = zfs.ReadWritableDataset(name)
self._prune_snapshots(dataset, schedule)
except RuntimeError,message:
- sys.stderr.write("Error listing datasets during " + \
- "removal of expired snapshots\n")
+ self.logger.error("Error listing datasets during " + \
+ "removal of expired snapshots")
self.exitCode = smf.SMF_EXIT_ERR_FATAL
# Propogate up to thread's run() method
raise RuntimeError,message
self.exitCode = smf.SMF_EXIT_ERR_FATAL
# Propogate up to thread's run() method
raise RuntimeError,message
self._cleanupLock.release()
return True
except RuntimeError, message:
self._cleanupLock.release()
return True
except RuntimeError, message:
- sys.stderr.write("Error checking zpool capacity of: " + \
- zpool.name + "\n")
+ self.logger.error("Error checking zpool capacity of: " + \
+ zpool.name)
self._cleanupLock.release()
self.exitCode = smf.SMF_EXIT_ERR_FATAL
# Propogate up to thread's run() mehod.
self._cleanupLock.release()
self.exitCode = smf.SMF_EXIT_ERR_FATAL
# Propogate up to thread's run() mehod.
# This also catches exceptions thrown from _run_<level>_cleanup()
# and _run_cleanup() in methods called by _perform_cleanup()
except RuntimeError,message:
# This also catches exceptions thrown from _run_<level>_cleanup()
# and _run_cleanup() in methods called by _perform_cleanup()
except RuntimeError,message:
- sys.stderr.write("Remedial space cleanup failed because " + \
+ self.logger.error("Remedial space cleanup failed because " + \
"of failure to determinecapacity of: " + \
"of failure to determinecapacity of: " + \
self.exitCode = smf.SMF_EXIT_ERR_FATAL
self._cleanupLock.release()
# Propogate up to thread's run() method.
self.exitCode = smf.SMF_EXIT_ERR_FATAL
self._cleanupLock.release()
# Propogate up to thread's run() method.
# Avoid needless list iteration for non-debug mode
if self.verbose == True and len(self._destroyedsnaps) > 0:
for snap in self._destroyedsnaps:
# Avoid needless list iteration for non-debug mode
if self.verbose == True and len(self._destroyedsnaps) > 0:
for snap in self._destroyedsnaps:
- sys.stderr.write("\t%s\n" % snap)
+ self.logger.error("\t%s" % snap)
self._cleanupLock.release()
def _run_warning_cleanup(self, zpool):
self._cleanupLock.release()
def _run_warning_cleanup(self, zpool):
try:
clonedsnaps = self._datasets.list_cloned_snapshots()
except RuntimeError,message:
try:
clonedsnaps = self._datasets.list_cloned_snapshots()
except RuntimeError,message:
- sys.stderr.write("Error (non-fatal) listing cloned snapshots" +
- " while recovering pool capacity\n")
- sys.stderr.write("Error details:\n" + \
+ self.logger.error("Error (non-fatal) listing cloned snapshots" +
+ " while recovering pool capacity")
+ self.logger.error("Error details:\n" + \
"--------BEGIN ERROR MESSAGE--------\n" + \
str(message) + \
"--------BEGIN ERROR MESSAGE--------\n" + \
str(message) + \
- "\n--------END ERROR MESSAGE--------\n")
+ "\n--------END ERROR MESSAGE--------")
# Build a list of snapshots in the given schedule, that are not
# cloned, and sort the result in reverse chronological order.
# Build a list of snapshots in the given schedule, that are not
# cloned, and sort the result in reverse chronological order.
if not s in clonedsnaps]
snapshots.reverse()
except RuntimeError,message:
if not s in clonedsnaps]
snapshots.reverse()
except RuntimeError,message:
- sys.stderr.write("Error listing snapshots" +
- " while recovering pool capacity\n")
+ self.logger.error("Error listing snapshots" +
+ " while recovering pool capacity")
self.exitCode = smf.SMF_EXIT_ERR_FATAL
# Propogate the error up to the thread's run() method.
raise RuntimeError,message
while zpool.get_capacity() > threshold:
if len(snapshots) == 0:
self.exitCode = smf.SMF_EXIT_ERR_FATAL
# Propogate the error up to the thread's run() method.
raise RuntimeError,message
while zpool.get_capacity() > threshold:
if len(snapshots) == 0:
- syslog.syslog(syslog.LOG_NOTICE,
"No more %s snapshots left" \
% schedule)
return
"No more %s snapshots left" \
% schedule)
return
# Would be nice to be able to mark service as degraded here
# but it's better to try to continue on rather than to give
# up alltogether (SMF maintenance state)
# Would be nice to be able to mark service as degraded here
# but it's better to try to continue on rather than to give
# up alltogether (SMF maintenance state)
- sys.stderr.write("Warning: Cleanup failed to destroy: %s\n" % \
+ self.logger.error("Warning: Cleanup failed to destroy: %s" % \
- sys.stderr.write("Details:\n%s\n" % (str(message)))
+ self.logger.error("Details:\n%s" % (str(message)))
else:
self._destroyedsnaps.append(snapname)
# Give zfs some time to recalculate.
else:
self._destroyedsnaps.append(snapname)
# Give zfs some time to recalculate.
for zpool in self._zpools:
status = self._poolstatus[zpool.name]
if status == 4:
for zpool in self._zpools:
status = self._poolstatus[zpool.name]
if status == 4:
- syslog.syslog(syslog.LOG_EMERG,
- "%s is over %d%% capacity. " \
+ self.logger.critical( \
"All automatic snapshots were destroyed" \
% (zpool.name, self._emergencyLevel))
elif status == 3:
"All automatic snapshots were destroyed" \
% (zpool.name, self._emergencyLevel))
elif status == 3:
- syslog.syslog(syslog.LOG_ALERT,
"%s exceeded %d%% capacity. " \
"Automatic snapshots over 1 hour old were destroyed" \
% (zpool.name, self._emergencyLevel))
elif status == 2:
"%s exceeded %d%% capacity. " \
"Automatic snapshots over 1 hour old were destroyed" \
% (zpool.name, self._emergencyLevel))
elif status == 2:
- syslog.syslog(syslog.LOG_CRIT,
+ self.logger.critical( \
"%s exceeded %d%% capacity. " \
"Weekly, hourly and daily automatic snapshots were destroyed" \
% (zpool.name, self._criticalLevel))
elif status == 1:
"%s exceeded %d%% capacity. " \
"Weekly, hourly and daily automatic snapshots were destroyed" \
% (zpool.name, self._criticalLevel))
elif status == 1:
- syslog.syslog(syslog.LOG_WARNING,
"%s exceeded %d%% capacity. " \
"Hourly and daily automatic snapshots were destroyed" \
% (zpool.name, self._warningLevel))
if len(self._destroyedsnaps) > 0:
"%s exceeded %d%% capacity. " \
"Hourly and daily automatic snapshots were destroyed" \
% (zpool.name, self._warningLevel))
if len(self._destroyedsnaps) > 0:
- syslog.syslog(syslog.LOG_NOTICE,
"%d automatic snapshots were destroyed" \
% len(self._destroyedsnaps))
"%d automatic snapshots were destroyed" \
% len(self._destroyedsnaps))
def monitor_threads(snapthread):
def monitor_threads(snapthread):
+ logger = logging.getLogger('time-slider')
if snapthread.is_alive():
return True
else:
if snapthread.is_alive():
return True
else:
- sys.stderr.write("Snapshot monitor thread exited.\n")
+ logger.error("Snapshot monitor thread exited.")
if snapthread.exitCode == smf.SMF_EXIT_MON_DEGRADE:
# FIXME - it would be nicer to mark the service as degraded than
# go into maintenance state for some situations such as a
if snapthread.exitCode == smf.SMF_EXIT_MON_DEGRADE:
# FIXME - it would be nicer to mark the service as degraded than
# go into maintenance state for some situations such as a
sys.exit(smf.SMF_EXIT_ERR_FATAL)
return False
else:
sys.exit(smf.SMF_EXIT_ERR_FATAL)
return False
else:
- sys.stderr.write("Snapshot monitor thread exited abnormally\n")
- sys.stderr.write("Exit code: %d\n" % (snapthread.exitCode))
+ logger.error("Snapshot monitor thread exited abnormally")
+ logger.error("Exit code: %d" % (snapthread.exitCode))
#subprocess.call(["/usr/sbin/svcadm", "mark", "maintenance",
# os.getenv("SMF_FMRI")])
sys.exit(smf.SMF_EXIT_ERR_FATAL)
#subprocess.call(["/usr/sbin/svcadm", "mark", "maintenance",
# os.getenv("SMF_FMRI")])
sys.exit(smf.SMF_EXIT_ERR_FATAL)
parser.add_argument('--configdump', action='store_true', help='Dump default values in config file format', default=False)
args, _ = parser.parse_known_args()
parser.add_argument('--configdump', action='store_true', help='Dump default values in config file format', default=False)
args, _ = parser.parse_known_args()
+ logger = logging.getLogger('time-slider')
+ logger.setLevel(logging.DEBUG)
+ if args.foreground:
+ handler = logging.StreamHandler()
+ else:
+ handler = SysLogHandler(address='/dev/log')
+ handler.setLevel(logging.DEBUG)
+ handler.setFormatter(logging.Formatter('%(asctime)s %(levelname)s: %(message)s', '%b %d %H:%M:%S time-sliderd:'))
+ logger.addHandler(handler)
+
if args.configdump:
timesliderconfig.configdump()
sys.exit(smf.SMF_EXIT_OK)
if args.configdump:
timesliderconfig.configdump()
sys.exit(smf.SMF_EXIT_OK)
# The user security attributes checked are the following:
# Note that UID == 0 will match any profile search so
# no need to check it explicitly.
# The user security attributes checked are the following:
# Note that UID == 0 will match any profile search so
# no need to check it explicitly.
- syslog.openlog("time-sliderd", 0, syslog.LOG_DAEMON)
rbacp = RBACprofile()
if rbacp.has_profile("ZFS File System Management"):
rbacp = RBACprofile()
if rbacp.has_profile("ZFS File System Management"):
mainloop.quit()
sys.exit(smf.SMF_EXIT_OK)
else:
mainloop.quit()
sys.exit(smf.SMF_EXIT_OK)
else:
- syslog.syslog(syslog.LOG_ERR,
"%s has insufficient privileges to run time-sliderd!" \
% rbacp.name)
"%s has insufficient privileges to run time-sliderd!" \
% rbacp.name)
sys.exit(smf.SMF_EXIT_ERR_PERM)
sys.exit(smf.SMF_EXIT_ERR_PERM)
sys.exit(smf.SMF_EXIT_OK)
sys.exit(smf.SMF_EXIT_OK)