Commit a548b8d9 authored by Fred Drake's avatar Fred Drake

Change the factory machinery to be a little less ad hoc.

parent 96d42ba1
...@@ -16,7 +16,8 @@ import sys ...@@ -16,7 +16,8 @@ import sys
from logging import Handler, StreamHandler from logging import Handler, StreamHandler
from logging.handlers import SysLogHandler from logging.handlers import SysLogHandler
from logging.handlers import HTTPHandler, SMTPHandler, NTEventLogHandler from logging.handlers import HTTPHandler, SMTPHandler
from logging.handlers import NTEventLogHandler as Win32EventLogHandler
class FileHandler(StreamHandler): class FileHandler(StreamHandler):
""" """
......
...@@ -12,14 +12,14 @@ ...@@ -12,14 +12,14 @@
<key name="level" default="info" datatype=".logging_level"/> <key name="level" default="info" datatype=".logging_level"/>
</sectiontype> </sectiontype>
<sectiontype name="logfile" datatype=".file_handler" <sectiontype name="logfile" datatype=".FileHandlerFactory"
implements="loghandler" extends="base-log-handler"> implements="loghandler" extends="base-log-handler">
<key name="path" required="yes"/> <key name="path" required="yes"/>
<key name="format" default="------\n%(asctime)s %(message)s" <key name="format" default="------\n%(asctime)s %(message)s"
datatype=".log_format"/> datatype=".log_format"/>
</sectiontype> </sectiontype>
<sectiontype name="syslog" datatype=".syslog_handler" <sectiontype name="syslog" datatype=".SyslogHandlerFactory"
implements="loghandler" extends="base-log-handler"> implements="loghandler" extends="base-log-handler">
<key name="facility" default="user" datatype=".syslog_facility"/> <key name="facility" default="user" datatype=".syslog_facility"/>
<key name="address" datatype="socket-address" default="localhost:514"/> <key name="address" datatype="socket-address" default="localhost:514"/>
...@@ -27,14 +27,14 @@ ...@@ -27,14 +27,14 @@
datatype=".log_format"/> datatype=".log_format"/>
</sectiontype> </sectiontype>
<sectiontype name="win32-eventlog" datatype=".nteventlog_handler" <sectiontype name="win32-eventlog" datatype=".Win32EventLogFactory"
implements="loghandler" extends="base-log-handler"> implements="loghandler" extends="base-log-handler">
<key name="appname" default="Zope"/> <key name="appname" default="Zope"/>
<key name="format" default="%(message)s" <key name="format" default="%(message)s"
datatype=".log_format"/> datatype=".log_format"/>
</sectiontype> </sectiontype>
<sectiontype name="http-logger" datatype=".http_handler" <sectiontype name="http-logger" datatype=".HTTPHandlerFactory"
implements="loghandler" extends="base-log-handler"> implements="loghandler" extends="base-log-handler">
<key name="url" default="http://localhost/" datatype=".http_handler_url"/> <key name="url" default="http://localhost/" datatype=".http_handler_url"/>
<key name="method" default="GET" datatype=".get_or_post"/> <key name="method" default="GET" datatype=".get_or_post"/>
...@@ -42,7 +42,7 @@ ...@@ -42,7 +42,7 @@
datatype=".log_format"/> datatype=".log_format"/>
</sectiontype> </sectiontype>
<sectiontype name="email-notifier" datatype=".smtp_handler" <sectiontype name="email-notifier" datatype=".SMTPHandlerFactory"
implements="loghandler" extends="base-log-handler"> implements="loghandler" extends="base-log-handler">
<key name="from" required="yes" attribute="fromaddr"/> <key name="from" required="yes" attribute="fromaddr"/>
<multikey name="to" required="yes" attribute="toaddrs"/> <multikey name="to" required="yes" attribute="toaddrs"/>
......
############################################################################## ##############################################################################
# #
# Copyright (c) 2002, 2003 Zope Corporation and Contributors. # Copyright (c) 2002 Zope Corporation and Contributors.
# All Rights Reserved. # All Rights Reserved.
# #
# This software is subject to the provisions of the Zope Public License, # This software is subject to the provisions of the Zope Public License,
...@@ -75,24 +75,32 @@ def ctrl_char_insert(value): ...@@ -75,24 +75,32 @@ def ctrl_char_insert(value):
value = value.replace(pattern, replacement) value = value.replace(pattern, replacement)
return value return value
def file_handler(section):
path = section.path
def callback(inst, class HandlerFactory(Factory):
format=section.format, def __init__(self, section):
dateformat=section.dateformat, Factory.__init__(self)
level=section.level): self.section = section
def create_logger(self):
raise NotImplementedError("subclasses must override create_logger()")
def create(self):
import logging import logging
inst.setFormatter(logging.Formatter(format, dateformat)) logger = self.create_logger()
inst.setLevel(level) logger.setFormatter(logging.Formatter(self.section.format,
self.section.dateformat))
# XXX should pick up sys.{stderr,stdout} when the factory is invoked logger.setLevel(self.section.level)
if path == "STDERR": return logger
return Factory('zLOG.LogHandlers.StreamHandler', callback, sys.stderr)
elif path == "STDOUT": class FileHandlerFactory(HandlerFactory):
return Factory('zLOG.LogHandlers.StreamHandler', callback, sys.stdout) def create_logger(self):
else: from zLOG.LogHandlers import StreamHandler, FileHandler
return Factory('zLOG.LogHandlers.FileHandler', callback, path) path = self.section.path
if path == "STDERR":
return StreamHandler(sys.stderr)
if path == "STDOUT":
return StreamHandler(sys.stdout)
return FileHandler(path)
_syslog_facilities = { _syslog_facilities = {
"auth": 1, "auth": 1,
...@@ -125,30 +133,16 @@ def syslog_facility(value): ...@@ -125,30 +133,16 @@ def syslog_facility(value):
raise ValueError("Syslog facility must be one of " + ", ".join(L)) raise ValueError("Syslog facility must be one of " + ", ".join(L))
return value return value
def syslog_handler(section): class SyslogHandlerFactory(HandlerFactory):
def callback(inst, def create_logger(self):
format=section.format, from zLOG.LogHandlers import SysLogHandler
dateformat=section.dateformat, return SysLogHandler(self.section.address.address,
level=section.level): self.section.facility)
import logging
inst.setFormatter(logging.Formatter(format, dateformat))
inst.setLevel(level)
return Factory('zLOG.LogHandlers.SysLogHandler', callback,
section.address.address,
section.facility)
def nteventlog_handler(section):
def callback(inst,
format=section.format,
dateformat=section.dateformat,
level=section.level):
import logging
inst.setFormatter(logging.Formatter(format, dateformat))
inst.setLevel(level)
return Factory('zLOG.LogHandlers.NTEventLogHandler', callback, class Win32EventLogFactory(HandlerFactory):
section.appname) def create_logger(self):
from zLOG.LogHandlers import Win32EventLogHandler
return Win32EventLogHandler(self.section.appname)
def http_handler_url(value): def http_handler_url(value):
import urlparse import urlparse
...@@ -178,45 +172,25 @@ def get_or_post(value): ...@@ -178,45 +172,25 @@ def get_or_post(value):
+ repr(value)) + repr(value))
return value return value
def http_handler(section): class HTTPHandlerFactory(HandlerFactory):
def callback(inst, def create_logger(self):
format=section.format, from zLOG.LogHandlers import HTTPHandler
dateformat=section.dateformat, host, selector = self.section.url
level=section.level): return HTTPHandler(host, selector, self.section.method)
import logging
inst.setFormatter(logging.Formatter(format, dateformat)) class SMTPHandlerFactory(HandlerFactory):
inst.setLevel(level) def create_logger(self):
from zLOG.LogHandlers import SMTPHandler
host, selector = section.url host, port = self.section.smtp_server
return Factory('zLOG.LogHandlers.HTTPHandler', if not port:
callback, host, selector, section.method) mailhost = host
else:
def smtp_handler(section): mailhost = host, port
def callback(inst, return SMTPHandler(mailhost, self.section.fromaddr,
format=section.format, self.section.toaddrs, self.section.subject)
dateformat=section.dateformat,
level=section.level):
import logging class EventLogFactory(Factory):
inst.setFormatter(logging.Formatter(format, dateformat))
inst.setLevel(level)
host, port = section.smtp_server
if not port:
mailhost = host
else:
mailhost = host, port
return Factory('zLOG.LogHandlers.SMTPHandler',
callback,
mailhost,
section.fromaddr,
section.toaddrs,
section.subject)
_marker = []
class EventLogFactory:
""" """
A wrapper used to create loggers while delaying actual logger A wrapper used to create loggers while delaying actual logger
instance construction. We need to do this because we may instance construction. We need to do this because we may
...@@ -226,24 +200,22 @@ class EventLogFactory: ...@@ -226,24 +200,22 @@ class EventLogFactory:
logger object. logger object.
""" """
def __init__(self, section): def __init__(self, section):
Factory.__init__(self)
self.level = section.level self.level = section.level
self.handler_factories = section.handlers self.handler_factories = section.handlers
self.resolved = _marker
def create(self):
def __call__(self): # set the logger up
if self.resolved is _marker: import logging
# set the logger up logger = logging.getLogger("event")
import logging logger.handlers = []
logger = logging.getLogger("event") logger.propagate = 0
logger.handlers = [] logger.setLevel(self.level)
logger.propagate = 0 if self.handler_factories:
logger.setLevel(self.level) for handler_factory in self.handler_factories:
if self.handler_factories: handler = handler_factory()
for handler_factory in self.handler_factories: logger.addHandler(handler)
handler = handler_factory() else:
logger.addHandler(handler) from zLOG.LogHandlers import NullHandler
else: logger.addHandler(NullHandler())
from zLOG.LogHandlers import NullHandler return logger
logger.addHandler(NullHandler())
self.resolved = logger
return self.resolved
...@@ -14,45 +14,23 @@ ...@@ -14,45 +14,23 @@
_marker = [] _marker = []
def importer(name):
components = name.split('.')
start = components[0]
g = globals()
package = __import__(start, g, g)
modulenames = [start]
for component in components[1:]:
modulenames.append(component)
try:
package = getattr(package, component)
except AttributeError:
name = '.'.join(modulenames)
package = __import__(name, g, g, component)
return package
class Factory: class Factory:
"""Generic wrapper for instance construction.
Calling the factory causes the instance to be created if it hasn't
already been created, and returns the object. Calling the factory
multiple times returns the same object.
The instance is created using the factory's create() method, which
must be overriden by subclasses.
""" """
A generic wrapper for instance construction and function calling used def __init__(self):
to delay construction/call until necessary. The class path is the dotted
name to the class or function, args are the positional args, kw are the
keyword args. If it is specified, 'callback' is a function which will be
called back after constructing an instance or calling a function. It must
take the instance (or the result of the function) as a single argument.
"""
def __init__(self, class_path, callback, *args, **kw):
self.class_path = class_path
self.callback = callback
self.args = args
self.kw = kw
self.instance = _marker self.instance = _marker
def __repr__(self):
return ('<Factory instance for class "%s" with positional args "%s" '
'and keword args "%s"' % (self.class_path, self.args, self.kw))
def __call__(self): def __call__(self):
if self.instance is _marker: if self.instance is _marker:
constructor = importer(self.class_path) self.instance = self.create()
self.instance = constructor(*self.args, **self.kw)
if self.callback is not None:
self.callback(self.instance)
return self.instance return self.instance
def create(self):
raise NotImplementedError("subclasses need to override create()")
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment