SiteErrorLog.py :  » Web-Frameworks » Zope » Zope-2.6.0 » lib » python » Products » SiteErrorLog » Python Open Source

Home
Python Open Source
1.3.1.2 Python
2.Ajax
3.Aspect Oriented
4.Blog
5.Build
6.Business Application
7.Chart Report
8.Content Management Systems
9.Cryptographic
10.Database
11.Development
12.Editor
13.Email
14.ERP
15.Game 2D 3D
16.GIS
17.GUI
18.IDE
19.Installer
20.IRC
21.Issue Tracker
22.Language Interface
23.Log
24.Math
25.Media Sound Audio
26.Mobile
27.Network
28.Parser
29.PDF
30.Project Management
31.RSS
32.Search
33.Security
34.Template Engines
35.Test
36.UML
37.USB Serial
38.Web Frameworks
39.Web Server
40.Web Services
41.Web Unit
42.Wiki
43.Windows
44.XML
Python Open Source » Web Frameworks » Zope 
Zope » Zope 2.6.0 » lib » python » Products » SiteErrorLog » SiteErrorLog.py
##############################################################################
#
# 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.
#
##############################################################################
"""Site error log module.

$Id: SiteErrorLog.py,v 1.11.4.1 2002/10/16 21:34:36 chrism Exp $
"""

import os
import sys
import time
from random import random
from thread import allocate_lock
from types import StringType,UnicodeType

import Globals
from Acquisition import aq_base
from AccessControl import ClassSecurityInfo,getSecurityManager,Unauthorized
from OFS.SimpleItem import SimpleItem
from Products.PageTemplates.PageTemplateFile import PageTemplateFile
from zExceptions.ExceptionFormatter import format_exception
from zLOG import LOG,ERROR

# Permission names
use_error_logging = 'Log Site Errors'
log_to_event_log = 'Log to the Event Log'

# We want to restrict the rate at which errors are sent to the Event Log
# because we know that these errors can be generated quick enough to
# flood some zLOG backends. zLOG is used to notify someone of a problem,
# not to record every instance.
# This dictionary maps exception name to a value which encodes when we
# can next send the error with that name into the event log. This dictionary
# is shared between threads and instances. Concurrent access will not
# do much harm.
_rate_restrict_pool = {}

# The number of seconds that must elapse on average between sending two
# exceptions of the same name into the the Event Log. one per minute.
_rate_restrict_period = 60

# The number of exceptions to allow in a burst before the above limit
# kicks in. We allow five exceptions, before limiting them to one per
# minute.
_rate_restrict_burst = 5

_www = os.path.join(os.path.dirname(__file__), 'www')

# temp_logs holds the logs.
temp_logs = {}  # { oid -> [ traceback string ] }

cleanup_lock = allocate_lock()


class SiteErrorLog (SimpleItem):
    """Site error log class.  You can put an error log anywhere in the tree
    and exceptions in that area will be posted to the site error log.
    """
    meta_type = 'Site Error Log'
    id = 'error_log'

    keep_entries = 20
    copy_to_zlog = 0

    security = ClassSecurityInfo()

    manage_options = (
        {'label': 'Log', 'action': 'manage_main'},
        ) + SimpleItem.manage_options

    security.declareProtected(use_error_logging, 'getProperties')
    manage_main = PageTemplateFile('main.pt', _www)

    security.declareProtected(use_error_logging, 'showEntry')
    showEntry = PageTemplateFile('showEntry.pt', _www)

    security.declarePrivate('manage_beforeDelete')
    def manage_beforeDelete(self, item, container):
        if item is self:
            try:
                del container.__error_log__
            except AttributeError:
                pass

    security.declarePrivate('manage_afterAdd')
    def manage_afterAdd(self, item, container):
        if item is self:
            container.__error_log__ = aq_base(self)

    def _setId(self, id):
        if id != self.id:
            raise Globals.MessageDialog(
                title='Invalid Id',
                message='Cannot change the id of a SiteErrorLog',
                action ='./manage_main',)

    def _getLog(self):
        """Returns the log for this object.

        Careful, the log is shared between threads.
        """
        log = temp_logs.get(self._p_oid, None)
        if log is None:
            log = []
            temp_logs[self._p_oid] = log
        return log

    # Exceptions that happen all the time, so we dont need
    # to log them. Eventually this should be configured
    # through-the-web.
    _ignored_exceptions = ( 'Unauthorized', )

    security.declarePrivate('raising')
    def raising(self, info):
        """Log an exception.

        Called by SimpleItem's exception handler.
        Returns the url to view the error log entry
        """
        try:
            now = time.time()
            try:
                tb_text = None
                tb_html = None

                strtype = str(getattr(info[0], '__name__', info[0]))
                if strtype in self._ignored_exceptions:
                    return

                if not isinstance(info[2], StringType) and not isinstance(
                    info[2], UnicodeType):
                    tb_text = ''.join(
                        format_exception(*info, **{'as_html': 0}))
                    tb_html = ''.join(
                        format_exception(*info, **{'as_html': 1}))
                else:
                    tb_text = info[2]

                request = getattr(self, 'REQUEST', None)
                url = None
                username = None
                userid   = None
                req_html = None
                if request:
                    url = request.get('URL', '?')
                    usr = getSecurityManager().getUser()
                    username = usr.getUserName()
                    userid = usr.getId()
                    try:
                        req_html = str(request)
                    except:
                        pass

                try:
                    strv = str(info[1])
                except:
                    strv = '<unprintable %s object>' % str(type(info[1]).__name__)

                log = self._getLog()
                entry_id = str(now) + str(random()) # Low chance of collision
                log.append({
                    'type': strtype,
                    'value': strv,
                    'time': now,
                    'id': entry_id,
                    'tb_text': tb_text,
                    'tb_html': tb_html,
                    'username': username,
                    'userid': userid,
                    'url': url,
                    'req_html': req_html,
                    })

                cleanup_lock.acquire()
                try:
                    if len(log) >= self.keep_entries:
                        del log[:-self.keep_entries]
                finally:
                    cleanup_lock.release()
            except:
                LOG('SiteError', ERROR, 'Error while logging',
                    error=sys.exc_info())
            else:
                if self.copy_to_zlog:
                    self._do_copy_to_zlog(now,strtype,str(url),info)
                return '%s/showEntry?id=%s' % (self.absolute_url(), entry_id)
        finally:
            info = None

    def _do_copy_to_zlog(self,now,strtype,url,info):
        when = _rate_restrict_pool.get(strtype,0)
        if now>when:
            next_when = max(when, now-_rate_restrict_burst*_rate_restrict_period)
            next_when += _rate_restrict_period
            _rate_restrict_pool[strtype] = next_when
            LOG('SiteError', ERROR, str(url), error=info)

    security.declareProtected(use_error_logging, 'getProperties')
    def getProperties(self):
        return {
            'keep_entries': self.keep_entries,
            'copy_to_zlog': self.copy_to_zlog,
            'ignored_exceptions': self._ignored_exceptions,
            }

    security.declareProtected(log_to_event_log, 'checkEventLogPermission')
    def checkEventLogPermission(self):
        if not getSecurityManager().checkPermission(log_to_event_log, self):
            raise Unauthorized, ('You do not have the "%s" permission.' %
                                 log_to_event_log)
        return 1

    security.declareProtected(use_error_logging, 'setProperties')
    def setProperties(self, keep_entries, copy_to_zlog=0,
                      ignored_exceptions=(), RESPONSE=None):
        """Sets the properties of this site error log.
        """
        copy_to_zlog = not not copy_to_zlog
        if copy_to_zlog and not self.copy_to_zlog:
            # Before turning on event logging, check the permission.
            self.checkEventLogPermission()
        self.keep_entries = int(keep_entries)
        self.copy_to_zlog = copy_to_zlog
        self._ignored_exceptions = tuple(
            filter(None, map(str, ignored_exceptions)))
        if RESPONSE is not None:
            RESPONSE.redirect(
                '%s/manage_main?manage_tabs_message=Changed+properties.' %
                self.absolute_url())

    security.declareProtected(use_error_logging, 'getLogEntries')
    def getLogEntries(self):
        """Returns the entries in the log, most recent first.

        Makes a copy to prevent changes.
        """
        # List incomprehension ;-)
        res = [entry.copy() for entry in self._getLog()]
        res.reverse()
        return res

    security.declareProtected(use_error_logging, 'getLogEntryById')
    def getLogEntryById(self, id):
        """Returns the specified log entry.

        Makes a copy to prevent changes.  Returns None if not found.
        """
        for entry in self._getLog():
            if entry['id'] == id:
                return entry.copy()
        return None

    security.declareProtected(use_error_logging, 'getLogEntryAsText')
    def getLogEntryAsText(self, id, RESPONSE=None):
        """Returns the specified log entry.

        Makes a copy to prevent changes.  Returns None if not found.
        """
        entry = self.getLogEntryById(id)
        if entry is None:
            return 'Log entry not found or expired'
        if RESPONSE is not None:
            RESPONSE.setHeader('Content-Type', 'text/plain')
        return entry['tb_text']

Globals.InitializeClass(SiteErrorLog)


def manage_addErrorLog(dispatcher, RESPONSE=None):
    """Add a site error log to a container."""
    log = SiteErrorLog()
    dispatcher._setObject(log.id, log)
    if RESPONSE is not None:
        RESPONSE.redirect(
            dispatcher.DestinationURL() +
            '/manage_main?manage_tabs_message=Error+Log+Added.' )
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.