scripts/cranslib/clogger.py
2015-02-21 15:40:52 +01:00

122 lines
4.4 KiB
Python

#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# Basic logger, storing data in /var/log/clogger/*.log
# Author : Pierre-Elliott Bécue <becue@crans.org>
# License : GPLv3
# Date : 27/04/2014
import os
import datetime
import pytz
import logging
TZ = pytz.timezone('Europe/Paris')
LDIRPATH = os.getenv('DBG_CLOGGER_PATH', '/var/log/clogger')
class CLogger(logging.Logger):
"""
Crans logger.
"""
def __init__(self, loggerName, service=None, level="info", debug=False):
"""
Initializes logger. The debug variable is useful to have a print to stdout (when debugging)
"""
super(CLogger, self).__init__(loggerName)
self.c_formatter = None
self.c_file_handler = None
self.c_sh = None
self.c_level = level
# When no service is specified, we don't put the reference in the format.
if service is None:
self.c_format = "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
else:
self.c_format = "%%(asctime)s - %%(name)s - %(service)s - %%(levelname)s - %%(message)s" % {'service': service}
self.create_formatter()
self.apply_file_handler(loggerName)
if debug:
self.apply_stream_handler()
def get_file_handler_path(self):
"""Returns the file handler path"""
if self.__file_handler_path is None:
return ''
return self.__file_handler_path
def create_formatter(self):
"""Creates a formatter based on CFormatter class.
It uses self.format as a source."""
if self.c_formatter is not None:
return
# Creates formatter
self.c_formatter = CFormatter(self.c_format, "%Y-%m-%dT%H:%M:%S.%f%z")
def apply_stream_handler(self):
"""Creates a streamhandler that prints to stdout.
Its level is debug"""
self.c_sh = logging.StreamHandler()
self.c_shlevel = logging.DEBUG
self.c_sh.setLevel(self.c_shlevel)
self.c_sh.setFormatter(self.c_formatter)
self.addHandler(self.c_sh)
def apply_file_handler(self, loggerName):
"""Creates a file handler which level is given by self.c_level"""
if self.c_file_handler is not None:
return
# Computes the file handler name using service name.
self.__file_handler_path = os.path.join(LDIRPATH, "%s.log" % (loggerName,))
# Creates FileHandler
self.c_file_handler = logging.FileHandler(self.__file_handler_path)
# Catches appropriate level in logging.
self.c_file_handler_level = getattr(logging, self.c_level.upper(), logging.INFO)
self.c_file_handler.setLevel(self.c_file_handler_level)
# Adds formatter to FileHandler
self.c_file_handler.setFormatter(self.c_formatter)
# Adds FileHandler to Handlers
self.addHandler(self.c_file_handler)
class CFormatter(logging.Formatter):
"""
This Formatter subclasses the classic formatter to provide a
timezone-aware logging.
"""
converter = datetime.datetime.fromtimestamp
def formatTime(self, record, datefmt=None):
"""
Return the creation time of the specified LogRecord as formatted text.
This method should be called from format() by a formatter which
wants to make use of a formatted time. This method can be overridden
in formatters to provide for any specific requirement, but the
basic behaviour is as follows: if datefmt (a string) is specified,
it is used with time.strftime() to format the creation time of the
record. Otherwise, the ISO8601 format is used. The resulting
string is returned. This function uses a user-configurable function
to convert the creation time to a tuple. By default, time.localtime()
is used; to change this for a particular formatter instance, set the
'converter' attribute to a function with the same signature as
time.localtime() or time.gmtime(). To change it for all formatters,
for example if you want all logging times to be shown in GMT,
set the 'converter' attribute in the Formatter class.
"""
ct = self.converter(record.created, TZ)
ct = ct.replace(microsecond=int(record.msecs * 1000))
if datefmt:
s = ct.strftime(datefmt)
else:
s = ct.strftime("%Y-%m-%d %H:%M:%S.%f")
return s