Commit 125189ea authored by Fred Drake's avatar Fred Drake

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

parent 59fe6f63
...@@ -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
import logging
inst.setFormatter(logging.Formatter(format, dateformat)) def create_logger(self):
inst.setLevel(level) raise NotImplementedError("subclasses must override create_logger()")
# XXX should pick up sys.{stderr,stdout} when the factory is invoked def create(self):
import logging
logger = self.create_logger()
logger.setFormatter(logging.Formatter(self.section.format,
self.section.dateformat))
logger.setLevel(self.section.level)
return logger
class FileHandlerFactory(HandlerFactory):
def create_logger(self):
from zLOG.LogHandlers import StreamHandler, FileHandler
path = self.section.path
if path == "STDERR": if path == "STDERR":
return Factory('zLOG.LogHandlers.StreamHandler', callback, sys.stderr) return StreamHandler(sys.stderr)
elif path == "STDOUT": if path == "STDOUT":
return Factory('zLOG.LogHandlers.StreamHandler', callback, sys.stdout) return StreamHandler(sys.stdout)
else: return FileHandler(path)
return Factory('zLOG.LogHandlers.FileHandler', callback, 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))
inst.setLevel(level)
host, selector = section.url
return Factory('zLOG.LogHandlers.HTTPHandler',
callback, host, selector, section.method)
def smtp_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)
host, port = section.smtp_server class SMTPHandlerFactory(HandlerFactory):
def create_logger(self):
from zLOG.LogHandlers import SMTPHandler
host, port = self.section.smtp_server
if not port: if not port:
mailhost = host mailhost = host
else: else:
mailhost = host, port mailhost = host, port
return SMTPHandler(mailhost, self.section.fromaddr,
self.section.toaddrs, self.section.subject)
return Factory('zLOG.LogHandlers.SMTPHandler',
callback,
mailhost,
section.fromaddr,
section.toaddrs,
section.subject)
_marker = []
class EventLogFactory: class EventLogFactory(Factory):
""" """
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,12 +200,11 @@ class EventLogFactory: ...@@ -226,12 +200,11 @@ 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 __call__(self): def create(self):
if self.resolved is _marker:
# set the logger up # set the logger up
import logging import logging
logger = logging.getLogger("event") logger = logging.getLogger("event")
...@@ -245,5 +218,4 @@ class EventLogFactory: ...@@ -245,5 +218,4 @@ class EventLogFactory:
else: else:
from zLOG.LogHandlers import NullHandler from zLOG.LogHandlers import NullHandler
logger.addHandler(NullHandler()) logger.addHandler(NullHandler())
self.resolved = logger return 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