diff --git a/config b/config index 36df1fa..b1ee131 100644 --- a/config +++ b/config @@ -52,11 +52,10 @@ LDAPAppend = ou=users,dc=exmaple,dc=dom # created if not present folder = ~/.config/radicale/calendars -[logging] -# Full path of logfile -file = ~/.config/radicale/radicale.log -# Logging messages which are less severe than level will be ignored -# Log level are (debug, info, warning, error, critical) -level = error +[Logging] +# Logging filename +logfile = ~/.config/radicale/radicale.log +# Log facility 10: DEBUG, 20: INFO, 30 WARNING, 40 ERROR, 50 CRITICAL +facility = 50 # vim:ft=cfg diff --git a/radicale/__init__.py b/radicale/__init__.py index 99fcfe0..18b5426 100644 --- a/radicale/__init__.py +++ b/radicale/__init__.py @@ -53,6 +53,7 @@ VERSION = "git" def _check(request, function): """Check if user has sufficient rights for performing ``request``.""" + log.log(10, "Check if user has sufficient rights for performing ``request``.") # ``_check`` decorator can access ``request`` protected functions # pylint: disable=W0212 @@ -69,8 +70,10 @@ def _check(request, function): user = password = None if request.server.acl.has_right(request._calendar.owner, user, password): + log.log(20, "Sufficient rights for performing ``request``.") function(request) else: + log.log(40, "No sufficient rights for performing ``request``.") request.send_response(client.UNAUTHORIZED) request.send_header( "WWW-Authenticate", @@ -87,6 +90,7 @@ class HTTPServer(server.HTTPServer): # pylint: disable=W0231 def __init__(self, address, handler): """Create server.""" + log.log(10, "Create HTTP server.") server.HTTPServer.__init__(self, address, handler) self.acl = acl.load() # pylint: enable=W0231 @@ -98,6 +102,7 @@ class HTTPSServer(HTTPServer): def __init__(self, address, handler): """Create server by wrapping HTTP socket in an SSL socket.""" + log.log(10, "Create server by wrapping HTTP socket in an SSL socket.") # Fails with Python 2.5, import if needed # pylint: disable=F0401 import ssl @@ -116,6 +121,7 @@ class HTTPSServer(HTTPServer): class CalendarHTTPHandler(server.BaseHTTPRequestHandler): """HTTP requests handler for calendars.""" + log.log(10, "HTTP requests handler for calendars.") _encoding = config.get("encoding", "request") # Decorator checking rights before performing request @@ -124,6 +130,7 @@ class CalendarHTTPHandler(server.BaseHTTPRequestHandler): @property def _calendar(self): """The ``ical.Calendar`` object corresponding to the given path.""" + log.log(10, "The ``ical.Calendar`` object corresponding to the given path.") # ``self.path`` must be something like a posix path # ``normpath`` should clean malformed and malicious request paths attributes = posixpath.normpath(self.path.strip("/")).split("/") @@ -133,6 +140,7 @@ class CalendarHTTPHandler(server.BaseHTTPRequestHandler): def _decode(self, text): """Try to decode text according to various parameters.""" + log.log(10, "Try to decode text according to various parameters.") # List of charsets to try charsets = [] @@ -159,6 +167,7 @@ class CalendarHTTPHandler(server.BaseHTTPRequestHandler): def do_GET(self): """Manage GET request.""" + log.log(10, "Manage GET request.") self.do_HEAD() if self._answer: self.wfile.write(self._answer) @@ -166,6 +175,7 @@ class CalendarHTTPHandler(server.BaseHTTPRequestHandler): @check_rights def do_HEAD(self): """Manage HEAD request.""" + log.log(10, "Manage HEAD request.") item_name = xmlutils.name_from_path(self.path) if item_name: # Get calendar item @@ -196,6 +206,7 @@ class CalendarHTTPHandler(server.BaseHTTPRequestHandler): @check_rights def do_DELETE(self): """Manage DELETE request.""" + log.log(10, "Manage DELETE request.") item = self._calendar.get_item(xmlutils.name_from_path(self.path)) if item and self.headers.get("If-Match", item.etag) == item.etag: # No ETag precondition or precondition verified, delete item @@ -217,6 +228,7 @@ class CalendarHTTPHandler(server.BaseHTTPRequestHandler): def do_OPTIONS(self): """Manage OPTIONS request.""" + log.log(10, "Manage OPTIONS request.") self.send_response(client.OK) self.send_header( "Allow", "DELETE, HEAD, GET, MKCALENDAR, " @@ -226,6 +238,7 @@ class CalendarHTTPHandler(server.BaseHTTPRequestHandler): def do_PROPFIND(self): """Manage PROPFIND request.""" + log.log(10, "Manage PROPFIND request.") xml_request = self.rfile.read(int(self.headers["Content-Length"])) self._answer = xmlutils.propfind( self.path, xml_request, self._calendar, @@ -241,6 +254,7 @@ class CalendarHTTPHandler(server.BaseHTTPRequestHandler): @check_rights def do_PUT(self): """Manage PUT request.""" + log.log(10, "Manage PUT request.") item_name = xmlutils.name_from_path(self.path) item = self._calendar.get_item(item_name) if (not item and not self.headers.get("If-Match")) or \ @@ -264,6 +278,7 @@ class CalendarHTTPHandler(server.BaseHTTPRequestHandler): @check_rights def do_REPORT(self): """Manage REPORT request.""" + log.log(10, "Manage REPORT request.") xml_request = self.rfile.read(int(self.headers["Content-Length"])) self._answer = xmlutils.report(self.path, xml_request, self._calendar) @@ -272,4 +287,7 @@ class CalendarHTTPHandler(server.BaseHTTPRequestHandler): self.end_headers() self.wfile.write(self._answer) + def log_message(self, format, *args): + log.log(10, format % (args)) + # pylint: enable=C0103 diff --git a/radicale/acl/authLdap.py b/radicale/acl/authLdap.py index 385528b..b80964a 100644 --- a/radicale/acl/authLdap.py +++ b/radicale/acl/authLdap.py @@ -12,12 +12,15 @@ def has_right(owner, user, password): if owner != user: return False try: + log.log(10, "Open LDAP server connexion") l=ldap.open(LDAPSERVER, 389) - dn="%s%s,%s" % (LDAPPREPEND, user, LDAPAPPEND) - l.simple_bind_s(dn, password); + cn="%s%s,%s" % (LDAPPREPEND, user, LDAPAPPEND) + log.log(10, "LDAP bind with dn: %s" %(cn)) + l.simple_bind_s(cn, password); + log.log(20, "LDAP bind Ok") return True except: - log.error(sys.exc_info()[0]) + log.log(40, "LDAP bind error") return False LDAPSERVER = config.get("authLdap", "LDAPServer") diff --git a/radicale/config.py b/radicale/config.py index 5f2f8fe..74a315e 100644 --- a/radicale/config.py +++ b/radicale/config.py @@ -55,14 +55,13 @@ INITIAL_CONFIG = { "encryption": "crypt"}, "storage": { "folder": os.path.expanduser("~/.config/radicale/calendars")}, + "logging": { + "logfile": os.path.expanduser("~/.config/radicale/radicale.log"), + "facility": 10}, "authLdap": { "LDAPServer": "127.0.0.1", "LDAPPrepend": "uid=", - "LDAPAppend": "ou=users,dc=example,dc=com"}, - "logging": { - "file": os.path.expanduser("~/.config/radicale/radicale.log"), - "level": "error"} - } + "LDAPAppend": "ou=users,dc=example,dc=com"}} # Create a ConfigParser and configure it _CONFIG_PARSER = ConfigParser() diff --git a/radicale/log.py b/radicale/log.py index b188bf7..072857a 100644 --- a/radicale/log.py +++ b/radicale/log.py @@ -1,29 +1,23 @@ # -*- coding: utf-8 -*- -import sys -import logging -import os - +import logging, sys from radicale import config -LEVELS = { 'debug': logging.DEBUG, - 'info': logging.INFO, - 'warning': logging.WARNING, - 'error': logging.ERROR, - 'critical': logging.CRITICAL} - -level=LEVELS.get(config.get("logging", "level"), logging.NOTSET) - -logger=logging.getLogger("radicale") -logger.setLevel(level=level) - -handler=logging.FileHandler(os.path.expanduser(config.get("logging", "file"))) -handler.setLevel(level=level) +class log: + def __init__(self): + self.logger=logging.getLogger("radicale") + self.logger.setLevel(config.get("logging", "facility")) -formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s") + handler=logging.FileHandler(config.get("logging", "logfile")) -handler.setFormatter(formatter) - -logger.addHandler(handler) + formatter = logging.Formatter('%(name)s %(asctime)s %(levelname)s %(message)s') + handler.setFormatter(formatter) + + self.logger.addHandler(handler) + def log(self, level, msg): + self.logger.log(level, msg) + +_LOGGING = log() + +sys.modules[__name__] = _LOGGING -sys.modules[__name__] = logger \ No newline at end of file diff --git a/radicale/xmlutils.py b/radicale/xmlutils.py index 40d7f1e..621b7ac 100644 --- a/radicale/xmlutils.py +++ b/radicale/xmlutils.py @@ -29,7 +29,7 @@ in them for XML requests (all but PUT). import xml.etree.ElementTree as ET -from radicale import client, config, ical +from radicale import client, config, ical, log NAMESPACES = { @@ -45,11 +45,13 @@ def _tag(short_name, local): def _response(code): """Return full W3C names from HTTP status codes.""" + log.log(10, "Return full W3C names from HTTP status codes.") return "HTTP/1.1 %i %s" % (code, client.responses[code]) def name_from_path(path): """Return Radicale item name from ``path``.""" + log.log(10, "Return Radicale item name from ``path``.") path_parts = path.strip("/").split("/") return path_parts[-1] if len(path_parts) > 2 else None @@ -61,6 +63,7 @@ def delete(path, calendar): """ # Reading request + log.log(10, "Read and answer DELETE requests.") calendar.remove(name_from_path(path)) # Writing answer @@ -86,8 +89,9 @@ def propfind(path, xml_request, calendar, depth): """ # Reading request + log.log(10, "Read and answer PROPFIND requests.") root = ET.fromstring(xml_request) - + prop_element = root.find(_tag("D", "prop")) prop_list = prop_element.getchildren() props = [prop.tag for prop in prop_list] @@ -172,6 +176,7 @@ def propfind(path, xml_request, calendar, depth): def put(path, ical_request, calendar): """Read PUT requests.""" + log.log(10, "Read PUT requests.") name = name_from_path(path) if name in (item.name for item in calendar.items): # PUT is modifying an existing item @@ -188,6 +193,7 @@ def report(path, xml_request, calendar): """ # Reading request + log.log(10, "Read and answer REPORT requests.") root = ET.fromstring(xml_request) prop_element = root.find(_tag("D", "prop"))