[Zope3-checkins] CVS: Zope3/src/zope/server/logger - __init__.py:1.2 filelogger.py:1.2 m_syslog.py:1.2 resolvinglogger.py:1.2 rotatingfilelogger.py:1.2 socketlogger.py:1.2 sysloglogger.py:1.2 taillogger.py:1.2 unresolvinglogger.py:1.2
Jim Fulton
jim@zope.com
Wed, 25 Dec 2002 09:15:58 -0500
Update of /cvs-repository/Zope3/src/zope/server/logger
In directory cvs.zope.org:/tmp/cvs-serv20790/src/zope/server/logger
Added Files:
__init__.py filelogger.py m_syslog.py resolvinglogger.py
rotatingfilelogger.py socketlogger.py sysloglogger.py
taillogger.py unresolvinglogger.py
Log Message:
Grand renaming:
- Renamed most files (especially python modules) to lower case.
- Moved views and interfaces into separate hierarchies within each
project, where each top-level directory under the zope package
is a separate project.
- Moved everything to src from lib/python.
lib/python will eventually go away. I need access to the cvs
repository to make this happen, however.
There are probably some bits that are broken. All tests pass
and zope runs, but I haven't tried everything. There are a number
of cleanups I'll work on tomorrow.
=== Zope3/src/zope/server/logger/__init__.py 1.1 => 1.2 ===
--- /dev/null Wed Dec 25 09:15:57 2002
+++ Zope3/src/zope/server/logger/__init__.py Wed Dec 25 09:15:27 2002
@@ -0,0 +1,2 @@
+#
+# This file is necessary to make this directory a package.
=== Zope3/src/zope/server/logger/filelogger.py 1.1 => 1.2 ===
--- /dev/null Wed Dec 25 09:15:57 2002
+++ Zope3/src/zope/server/logger/filelogger.py Wed Dec 25 09:15:27 2002
@@ -0,0 +1,76 @@
+##############################################################################
+#
+# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""
+
+$Id$
+"""
+from types import StringType
+
+from zope.server.interfaces.logger import IMessageLogger
+
+class FileLogger:
+ """Simple File Logger
+ """
+
+ __implements__ = IMessageLogger
+
+ def __init__(self, file, flush=1, mode='a'):
+ """pass this either a path or a file object."""
+ if type(file) is StringType:
+ if (file == '-'):
+ import sys
+ self.file = sys.stdout
+ else:
+ self.file = open(file, mode)
+ else:
+ self.file = file
+ self.do_flush = flush
+
+
+ def __repr__(self):
+ return '<file logger: %s>' % self.file
+
+
+ def write(self, data):
+ self.file.write(data)
+ self.maybe_flush()
+
+
+ def writeline(self, line):
+ self.file.writeline(line)
+ self.maybe_flush()
+
+
+ def writelines(self, lines):
+ self.file.writelines(lines)
+ self.maybe_flush()
+
+
+ def maybe_flush(self):
+ if self.do_flush:
+ self.file.flush()
+
+ def flush(self):
+ self.file.flush()
+
+ def softspace(self, *args):
+ pass
+
+
+ def logMessage(self, message):
+ 'See IMessageLogger'
+ if message[-1] not in ('\r', '\n'):
+ self.write(message + '\n')
+ else:
+ self.write(message)
=== Zope3/src/zope/server/logger/m_syslog.py 1.1 => 1.2 ===
--- /dev/null Wed Dec 25 09:15:58 2002
+++ Zope3/src/zope/server/logger/m_syslog.py Wed Dec 25 09:15:27 2002
@@ -0,0 +1,180 @@
+# -*- Mode: Python; tab-width: 4 -*-
+
+# ======================================================================
+# Copyright 1997 by Sam Rushing
+#
+# All Rights Reserved
+#
+# Permission to use, copy, modify, and distribute this software and
+# its documentation for any purpose and without fee is hereby
+# granted, provided that the above copyright notice appear in all
+# copies and that both that copyright notice and this permission
+# notice appear in supporting documentation, and that the name of Sam
+# Rushing not be used in advertising or publicity pertaining to
+# distribution of the software without specific, written prior
+# permission.
+#
+# SAM RUSHING DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+# INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
+# NO EVENT SHALL SAM RUSHING BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+# CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
+# OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+# CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+# ======================================================================
+
+"""socket interface to unix syslog.
+On Unix, there are usually two ways of getting to syslog: via a
+local unix-domain socket, or via the TCP service.
+
+Usually "/dev/log" is the unix domain socket. This may be different
+for other systems.
+
+>>> my_client = syslog_client ('/dev/log')
+
+Otherwise, just use the UDP version, port 514.
+
+>>> my_client = syslog_client (('my_log_host', 514))
+
+On win32, you will have to use the UDP version. Note that
+you can use this to log to other hosts (and indeed, multiple
+hosts).
+
+This module is not a drop-in replacement for the python
+<syslog> extension module - the interface is different.
+
+Usage:
+
+>>> c = syslog_client()
+>>> c = syslog_client ('/strange/non_standard_log_location')
+>>> c = syslog_client (('other_host.com', 514))
+>>> c.log ('testing', facility='local0', priority='debug')
+
+"""
+
+# TODO: support named-pipe syslog.
+# [see ftp://sunsite.unc.edu/pub/Linux/system/Daemons/syslog-fifo.tar.z]
+
+# from <linux/sys/syslog.h>:
+# ===========================================================================
+# priorities/facilities are encoded into a single 32-bit quantity, where the
+# bottom 3 bits are the priority (0-7) and the top 28 bits are the facility
+# (0-big number). Both the priorities and the facilities map roughly
+# one-to-one to strings in the syslogd(8) source code. This mapping is
+# included in this file.
+#
+# priorities (these are ordered)
+
+LOG_EMERG = 0 # system is unusable
+LOG_ALERT = 1 # action must be taken immediately
+LOG_CRIT = 2 # critical conditions
+LOG_ERR = 3 # error conditions
+LOG_WARNING = 4 # warning conditions
+LOG_NOTICE = 5 # normal but significant condition
+LOG_INFO = 6 # informational
+LOG_DEBUG = 7 # debug-level messages
+
+# facility codes
+LOG_KERN = 0 # kernel messages
+LOG_USER = 1 # random user-level messages
+LOG_MAIL = 2 # mail system
+LOG_DAEMON = 3 # system daemons
+LOG_AUTH = 4 # security/authorization messages
+LOG_SYSLOG = 5 # messages generated internally by syslogd
+LOG_LPR = 6 # line printer subsystem
+LOG_NEWS = 7 # network news subsystem
+LOG_UUCP = 8 # UUCP subsystem
+LOG_CRON = 9 # clock daemon
+LOG_AUTHPRIV = 10 # security/authorization messages (private)
+
+# other codes through 15 reserved for system use
+LOG_LOCAL0 = 16 # reserved for local use
+LOG_LOCAL1 = 17 # reserved for local use
+LOG_LOCAL2 = 18 # reserved for local use
+LOG_LOCAL3 = 19 # reserved for local use
+LOG_LOCAL4 = 20 # reserved for local use
+LOG_LOCAL5 = 21 # reserved for local use
+LOG_LOCAL6 = 22 # reserved for local use
+LOG_LOCAL7 = 23 # reserved for local use
+
+priority_names = {
+ "alert": LOG_ALERT,
+ "crit": LOG_CRIT,
+ "debug": LOG_DEBUG,
+ "emerg": LOG_EMERG,
+ "err": LOG_ERR,
+ "error": LOG_ERR, # DEPRECATED
+ "info": LOG_INFO,
+ "notice": LOG_NOTICE,
+ "panic": LOG_EMERG, # DEPRECATED
+ "warn": LOG_WARNING, # DEPRECATED
+ "warning": LOG_WARNING,
+ }
+
+facility_names = {
+ "auth": LOG_AUTH,
+ "authpriv": LOG_AUTHPRIV,
+ "cron": LOG_CRON,
+ "daemon": LOG_DAEMON,
+ "kern": LOG_KERN,
+ "lpr": LOG_LPR,
+ "mail": LOG_MAIL,
+ "news": LOG_NEWS,
+ "security": LOG_AUTH, # DEPRECATED
+ "syslog": LOG_SYSLOG,
+ "user": LOG_USER,
+ "uucp": LOG_UUCP,
+ "local0": LOG_LOCAL0,
+ "local1": LOG_LOCAL1,
+ "local2": LOG_LOCAL2,
+ "local3": LOG_LOCAL3,
+ "local4": LOG_LOCAL4,
+ "local5": LOG_LOCAL5,
+ "local6": LOG_LOCAL6,
+ "local7": LOG_LOCAL7,
+ }
+
+import socket
+
+class syslog_client:
+
+ def __init__ (self, address='/dev/log'):
+ self.address = address
+ if type (address) == type(''):
+ try: # APUE 13.4.2 specifes /dev/log as datagram socket
+ self.socket = socket.socket( socket.AF_UNIX
+ , socket.SOCK_DGRAM)
+ self.socket.connect (address)
+ except: # older linux may create as stream socket
+ self.socket = socket.socket( socket.AF_UNIX
+ , socket.SOCK_STREAM)
+ self.socket.connect (address)
+ self.unix = 1
+ else:
+ self.socket = socket.socket( socket.AF_INET
+ , socket.SOCK_DGRAM)
+ self.unix = 0
+
+
+ log_format_string = '<%d>%s\000'
+
+ def log (self, message, facility=LOG_USER, priority=LOG_INFO):
+ message = self.log_format_string % (
+ self.encode_priority (facility, priority),
+ message
+ )
+ if self.unix:
+ self.socket.send (message)
+ else:
+ self.socket.sendto (message, self.address)
+
+ def encode_priority (self, facility, priority):
+ if type(facility) == type(''):
+ facility = facility_names[facility]
+ if type(priority) == type(''):
+ priority = priority_names[priority]
+ return (facility<<3) | priority
+
+ def close (self):
+ if self.unix:
+ self.socket.close()
=== Zope3/src/zope/server/logger/resolvinglogger.py 1.1 => 1.2 ===
--- /dev/null Wed Dec 25 09:15:58 2002
+++ Zope3/src/zope/server/logger/resolvinglogger.py Wed Dec 25 09:15:27 2002
@@ -0,0 +1,52 @@
+##############################################################################
+#
+# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""
+
+$Id$
+"""
+from zope.server.interfaces.logger import IRequestLogger
+
+
+class ResolvingLogger:
+ """Feed (ip, message) combinations into this logger to get a
+ resolved hostname in front of the message. The message will not
+ be logged until the PTR request finishes (or fails)."""
+
+ __implements__ = IRequestLogger
+
+ def __init__(self, resolver, logger):
+ self.resolver = resolver
+ # logger is an IMessageLogger
+ self.logger = logger
+
+
+ class logger_thunk:
+ def __init__(self, message, logger):
+ self.message = message
+ self.logger = logger
+
+ def __call__(self, host, ttl, answer):
+ if not answer:
+ answer = host
+ self.logger.logMessage('%s: %s' % (answer, self.message))
+
+ def logRequest(self, ip, message):
+ 'See IRequestLogger'
+ self.resolver.resolve_ptr(
+ ip,
+ self.logger_thunk(
+ message,
+ self.logger
+ )
+ )
=== Zope3/src/zope/server/logger/rotatingfilelogger.py 1.1 => 1.2 ===
--- /dev/null Wed Dec 25 09:15:58 2002
+++ Zope3/src/zope/server/logger/rotatingfilelogger.py Wed Dec 25 09:15:27 2002
@@ -0,0 +1,94 @@
+##############################################################################
+#
+# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""
+
+$Id$
+"""
+
+import time
+import os
+import stat
+
+from zope.server.logger.filelogger import FileLogger
+
+class RotatingFileLogger(FileLogger):
+ """ If freq is non-None we back up 'daily', 'weekly', or
+ 'monthly'. Else if maxsize is non-None we back up whenever
+ the log gets to big. If both are None we never back up.
+
+ Like a FileLogger, but it must be attached to a filename.
+ When the log gets too full, or a certain time has passed, it
+ backs up the log and starts a new one. Note that backing up
+ the log is done via 'mv' because anything else (cp, gzip)
+ would take time, during which medusa would do nothing else.
+ """
+
+ __implements__ = FileLogger.__implements__
+
+ def __init__(self, file, freq=None, maxsize=None, flush=1, mode='a'):
+ self.filename = file
+ self.mode = mode
+ self.file = open(file, mode)
+ self.freq = freq
+ self.maxsize = maxsize
+ self.rotate_when = self.next_backup(self.freq)
+ self.do_flush = flush
+
+ def __repr__(self):
+ return '<rotating-file logger: %s>' % self.file
+
+ # We back up at midnight every 1) day, 2) monday, or 3) 1st of month
+ def next_backup(self, freq):
+ (yr, mo, day, hr, min, sec, wd, jday, dst) = \
+ time.localtime(time.time())
+ if freq == 'daily':
+ return time.mktime((yr,mo,day+1, 0,0,0, 0,0,-1))
+ elif freq == 'weekly':
+ # wd(monday)==0
+ return time.mktime((yr,mo,day-wd+7, 0,0,0, 0,0,-1))
+ elif freq == 'monthly':
+ return time.mktime((yr,mo+1,1, 0,0,0, 0,0,-1))
+ else:
+ return None # not a date-based backup
+
+ def maybe_flush(self): # rotate first if necessary
+ self.maybe_rotate()
+ if self.do_flush: # from file_logger()
+ self.file.flush()
+
+ def maybe_rotate(self):
+ if self.freq and time.time() > self.rotate_when:
+ self.rotate()
+ self.rotate_when = self.next_backup(self.freq)
+ elif self.maxsize: # rotate when we get too big
+ try:
+ if os.stat(self.filename)[stat.ST_SIZE] > self.maxsize:
+ self.rotate()
+ except os.error: # file not found, probably
+ self.rotate() # will create a new file
+
+ def rotate(self):
+ yr, mo, day, hr, min, sec, wd, jday, dst = time.localtime(time.time())
+ try:
+ self.file.close()
+ newname = '%s.ends%04d%02d%02d' % (self.filename, yr, mo, day)
+ try:
+ open(newname, "r").close() # check if file exists
+ newname = newname + "-%02d%02d%02d" % (hr, min, sec)
+ except IOError: # concatenation of YEAR MO DY is unique
+ pass
+ os.rename(self.filename, newname)
+ self.file = open(self.filename, self.mode)
+ except IOError:
+ pass
=== Zope3/src/zope/server/logger/socketlogger.py 1.1 => 1.2 ===
--- /dev/null Wed Dec 25 09:15:58 2002
+++ Zope3/src/zope/server/logger/socketlogger.py Wed Dec 25 09:15:27 2002
@@ -0,0 +1,46 @@
+##############################################################################
+#
+# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""
+
+$Id$
+"""
+
+import asynchat
+import socket
+
+from zope.server.interfaces.logger import IMessageLogger
+
+class SocketLogger(asynchat.async_chat):
+ """Log to a stream socket, asynchronously."""
+
+ __implements__ = IMessageLogger
+
+ def __init__(self, address):
+ if type(address) == type(''):
+ self.create_socket(socket.AF_UNIX, socket.SOCK_STREAM)
+ else:
+ self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
+
+ self.connect(address)
+ self.address = address
+
+ def __repr__(self):
+ return '<socket logger: address=%s>' % (self.address)
+
+ def logMessage(self, message):
+ 'See IMessageLogger'
+ if message[-2:] != '\r\n':
+ self.socket.push(message + '\r\n')
+ else:
+ self.socket.push(message)
=== Zope3/src/zope/server/logger/sysloglogger.py 1.1 => 1.2 ===
--- /dev/null Wed Dec 25 09:15:58 2002
+++ Zope3/src/zope/server/logger/sysloglogger.py Wed Dec 25 09:15:27 2002
@@ -0,0 +1,59 @@
+##############################################################################
+#
+# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""
+
+$Id$
+"""
+
+import os
+import zope.server.logger.m_syslog
+
+from zope.server.interfaces.logger import IMessageLogger
+
+
+class SyslogLogger(m_syslog.syslog_client):
+ """syslog is a line-oriented log protocol - this class would be
+ appropriate for FTP or HTTP logs, but not for dumping stderr
+ to.
+
+ XXX: a simple safety wrapper that will ensure that the line
+ sent to syslog is reasonable.
+
+ XXX: async version of syslog_client: now, log entries use
+ blocking send()
+ """
+
+ __implements__ = IMessageLogger
+
+ svc_name = 'zope'
+ pid_str = str(os.getpid())
+
+ def __init__ (self, address, facility='user'):
+ m_syslog.syslog_client.__init__ (self, address)
+ self.facility = m_syslog.facility_names[facility]
+ self.address=address
+
+
+ def __repr__ (self):
+ return '<syslog logger address=%s>' % (repr(self.address))
+
+
+ def logMessage(self, message):
+ 'See IMessageLogger'
+ m_syslog.syslog_client.log (
+ self,
+ '%s[%s]: %s' % (self.svc_name, self.pid_str, message),
+ facility=self.facility,
+ priority=m_syslog.LOG_INFO
+ )
=== Zope3/src/zope/server/logger/taillogger.py 1.1 => 1.2 ===
--- /dev/null Wed Dec 25 09:15:58 2002
+++ Zope3/src/zope/server/logger/taillogger.py Wed Dec 25 09:15:27 2002
@@ -0,0 +1,42 @@
+##############################################################################
+#
+# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""
+
+$Id$
+"""
+
+from zope.server.interfaces.logger import IMessageLogger
+
+class TailLogger:
+ """Keep track of the last <size> log messages"""
+
+ __implements__ = IMessageLogger
+
+ def __init__(self, logger, size=500):
+ self.size = size
+ self.logger = logger
+ self.messages = []
+
+ def logMessage(self, message):
+ 'See IMessageLogger'
+ self.messages.append(strip_eol(message))
+ if len(self.messages) > self.size:
+ del self.messages[0]
+ self.logger.logMessage(message)
+
+
+def strip_eol(line):
+ while line and line[-1] in '\r\n':
+ line = line[:-1]
+ return line
=== Zope3/src/zope/server/logger/unresolvinglogger.py 1.1 => 1.2 ===
--- /dev/null Wed Dec 25 09:15:58 2002
+++ Zope3/src/zope/server/logger/unresolvinglogger.py Wed Dec 25 09:15:27 2002
@@ -0,0 +1,30 @@
+##############################################################################
+#
+# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""
+
+$Id$
+"""
+from zope.server.interfaces.logger import IRequestLogger
+
+class UnresolvingLogger:
+ """Just in case you don't want to resolve"""
+
+ __implements__ = IRequestLogger
+
+ def __init__(self, logger):
+ self.logger = logger
+
+ def logRequest(self, ip, message):
+ 'See IRequestLogger'
+ self.logger.logMessage('%s: %s' % (ip, message))