141 lines
4.6 KiB
Python
141 lines
4.6 KiB
Python
# w.c.s. - web application for online forms
|
|
# Copyright (C) 2005-2010 Entr'ouvert
|
|
#
|
|
# This program is free software; you can redistribute it and/or modify
|
|
# it under the terms of the GNU General Public License as published by
|
|
# the Free Software Foundation; either version 2 of the License, or
|
|
# (at your option) any later version.
|
|
#
|
|
# This program is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License
|
|
# along with this program; if not, see <http://www.gnu.org/licenses/>.
|
|
|
|
import logging
|
|
import os
|
|
|
|
from django.utils import six
|
|
|
|
from quixote import get_publisher, get_session, get_request
|
|
from quixote.logger import DefaultLogger
|
|
|
|
|
|
class ApplicationLogger(DefaultLogger):
|
|
def log_internal_error(self, error_summary, error_msg, tech_id=None):
|
|
self.log('exception caught')
|
|
self.error_log.write(error_msg)
|
|
if self.error_email:
|
|
from .emails import email
|
|
headers = {}
|
|
if tech_id:
|
|
headers['References'] = '<%s@%s>' % (tech_id, os.path.basename(get_publisher().app_dir))
|
|
email(subject='[ERROR] %s' % error_summary,
|
|
mail_body=error_msg,
|
|
email_from=self.error_email,
|
|
email_rcpt=[self.error_email],
|
|
want_html=False,
|
|
fire_and_forget=True,
|
|
extra_headers=headers)
|
|
|
|
|
|
class BotFilter(logging.Filter):
|
|
def filter(self, record):
|
|
if record.levelno >= logging.ERROR:
|
|
# always log errors
|
|
return 1
|
|
if self.is_bot():
|
|
return 0
|
|
return 1
|
|
|
|
@classmethod
|
|
def is_bot(cls):
|
|
botfile = os.path.join(get_publisher().data_dir, 'webbots')
|
|
if os.path.exists(botfile) and get_request():
|
|
user_agent = get_request().get_environ('HTTP_USER_AGENT', '')
|
|
for bot_ua_string in [x.strip() for x in open(botfile).readlines()]:
|
|
if bot_ua_string in user_agent:
|
|
return True
|
|
return False
|
|
|
|
|
|
class Formatter(logging.Formatter):
|
|
def format(self, record):
|
|
request = get_request()
|
|
if request:
|
|
record.address = request.get_environ('REMOTE_ADDR', '-')
|
|
record.path = request.get_path()
|
|
|
|
user = request.user
|
|
if user:
|
|
if isinstance(user, six.string_types + six.integer_types):
|
|
user_id = user
|
|
else:
|
|
user_id = user.id
|
|
if type(user_id) is str and user_id.startswith('anonymous-'):
|
|
user_id = 'anonymous'
|
|
else:
|
|
user_id = 'unlogged'
|
|
if BotFilter.is_bot():
|
|
user_id = 'bot'
|
|
record.user_id = user_id
|
|
else:
|
|
record.address = '-'
|
|
record.path = '-'
|
|
record.user_id = 'unlogged'
|
|
record.session_id = (get_request() and get_session() and \
|
|
get_session().get_session_id()) or '[nosession]'
|
|
|
|
return logging.Formatter.format(self, record) \
|
|
.replace('\n', '\n ')
|
|
|
|
|
|
def parse_logstream(stream):
|
|
'''
|
|
Parse a stream of lines making a log file, each log line start with a
|
|
non-blank character continue until the lines does not start with a blank
|
|
character
|
|
'''
|
|
line = next(stream)
|
|
while True:
|
|
r = readline(line)
|
|
try:
|
|
# Skip badly formatted lines
|
|
if r is None:
|
|
line = next(stream)
|
|
continue
|
|
while True:
|
|
line = next(stream)
|
|
if line.startswith(' '):
|
|
# Append the line without the first blank
|
|
r['message'] = r['message'] + line[1:]
|
|
continue
|
|
break
|
|
except StopIteration:
|
|
# Ont last line return the current one
|
|
if r is not None:
|
|
r['message'] = r['message'].strip()
|
|
yield r
|
|
break
|
|
r['message'] = r['message'].strip()
|
|
yield r
|
|
|
|
def readline(line):
|
|
if not line:
|
|
return None
|
|
try:
|
|
date, hour, level, ip, session_id, url, user_id, dash, message = line.split(' ', 8)
|
|
except ValueError:
|
|
try:
|
|
date, hour, level, message = line.split(' ', 3)
|
|
except ValueError:
|
|
return None # misformatted line
|
|
del line
|
|
return locals()
|
|
if dash != '-':
|
|
return None
|
|
del line
|
|
return locals()
|