[IMP] Add a new Logging Handler, where we will store in the database of OpenERP.
this database can be overrided via the --log-pgsql-database bzr revid: stw@openerp.com-20140228161147-s9nnrfq2tc94vq5p
This commit is contained in:
parent
3f779a5cae
commit
047d071a48
|
@ -111,15 +111,9 @@ def dispatch_rpc(service_name, method, params):
|
|||
log(rpc_request, logging.DEBUG, logline, replace_request_password(params), depth=1)
|
||||
|
||||
return result
|
||||
except openerp.osv.orm.except_orm:
|
||||
raise
|
||||
except openerp.exceptions.AccessError:
|
||||
raise
|
||||
except openerp.exceptions.AccessDenied:
|
||||
raise
|
||||
except openerp.exceptions.Warning:
|
||||
raise
|
||||
except openerp.exceptions.RedirectWarning:
|
||||
except (openerp.osv.orm.except_orm, openerp.exceptions.AccessError, \
|
||||
openerp.exceptions.AccessDenied, openerp.exceptions.Warning, \
|
||||
openerp.exceptions.RedirectWarning):
|
||||
raise
|
||||
except openerp.exceptions.DeferredException, e:
|
||||
_logger.exception(openerp.tools.exception_to_unicode(e))
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
from handlers import PostgreSQLHandler
|
|
@ -0,0 +1,100 @@
|
|||
##############################################################################
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2014 OpenERP SA (<http://www.openerp.com>)
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as
|
||||
# published by the Free Software Foundation, either version 3 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 Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
import contextlib
|
||||
import datetime
|
||||
import logging
|
||||
import threading
|
||||
|
||||
import psycopg2
|
||||
|
||||
from openerp import tools
|
||||
|
||||
# The PostgreSQL Handler for the logging module, will be used by OpenERP to store the logs
|
||||
# in the database, --log-pgsql-database=YOUR_DBNAME
|
||||
# By default the system will use the current database
|
||||
|
||||
class PostgreSQLHandler(logging.Handler):
|
||||
@contextlib.contextmanager
|
||||
def create_connection(self):
|
||||
db_name = None
|
||||
|
||||
db_name_from_cli = tools.config['log_pgsql_database']
|
||||
if not db_name_from_cli:
|
||||
# If there is no database, and only in this case, we are going to use the database
|
||||
# from the current thread and create a connection to this database.
|
||||
|
||||
current_thread = threading.current_thread()
|
||||
|
||||
db_name_from_thread = getattr(current_thread, 'dbname', None)
|
||||
if isinstance(db_name_from_thread, basestring):
|
||||
db_name = db_name_from_thread
|
||||
else:
|
||||
db_name = db_name_from_cli
|
||||
|
||||
if not db_name:
|
||||
return
|
||||
|
||||
parameters = {
|
||||
'user': tools.config['db_user'] or None,
|
||||
'password': tools.config['db_password'] or None,
|
||||
'host': tools.config['db_host'] or None,
|
||||
'port': tools.config['db_port'] or None,
|
||||
'database': db_name,
|
||||
}
|
||||
try:
|
||||
connection = psycopg2.connect(**parameters)
|
||||
|
||||
if connection:
|
||||
yield connection
|
||||
except Exception, ex: # Use a specific exception
|
||||
print ex
|
||||
|
||||
def emit(self, record):
|
||||
# We use a context manager to be tolerant to the errors (error of connections,...)
|
||||
with self.create_connection() as conn:
|
||||
exception = False
|
||||
if record.exc_info:
|
||||
exception = record.exc_text
|
||||
|
||||
now = datetime.datetime.utcnow()
|
||||
|
||||
current_thread = threading.current_thread()
|
||||
uid = getattr(current_thread, 'uid', False)
|
||||
dbname = getattr(current_thread, 'dbname', False)
|
||||
|
||||
parameters = (
|
||||
now, uid, now, uid, 'server', dbname, record.name,
|
||||
logging.getLevelName(record.levelno), record.msg, exception,
|
||||
record.filename, record.funcName, record.lineno
|
||||
)
|
||||
|
||||
with conn.cursor() as cursor:
|
||||
cursor.execute("""
|
||||
INSERT INTO ir_logging(
|
||||
create_date, create_uid, write_date, write_uid,
|
||||
type, dbname, name, level, message, exception, path, func,
|
||||
line
|
||||
)
|
||||
VALUES(%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)
|
||||
""",
|
||||
parameters
|
||||
)
|
||||
conn.commit()
|
|
@ -29,6 +29,7 @@ import threading
|
|||
|
||||
import tools
|
||||
import openerp
|
||||
import openerp.loggers
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
|
@ -85,6 +86,19 @@ class ColoredFormatter(DBFormatter):
|
|||
record.levelname = COLOR_PATTERN % (30 + fg_color, 40 + bg_color, record.levelname)
|
||||
return DBFormatter.format(self, record)
|
||||
|
||||
import platform
|
||||
def is_posix_operating_system():
|
||||
return os.name == 'posix'
|
||||
|
||||
def is_windows_operating_system():
|
||||
return os.name == 'nt'
|
||||
|
||||
def is_linux_operating_system():
|
||||
return is_posix_operating_system() and platform.system() == 'Linux'
|
||||
|
||||
def is_macosx_operating_system():
|
||||
return is_posix_operating_system() and platform.system() == 'Darwin'
|
||||
|
||||
def init_logger():
|
||||
from tools.translate import resetlocale
|
||||
resetlocale()
|
||||
|
@ -94,24 +108,32 @@ def init_logger():
|
|||
|
||||
if tools.config['syslog']:
|
||||
# SysLog Handler
|
||||
if os.name == 'nt':
|
||||
if is_windows_operating_system():
|
||||
handler = logging.handlers.NTEventLogHandler("%s %s" % (release.description, release.version))
|
||||
else:
|
||||
elif is_linux_operating_system():
|
||||
handler = logging.handlers.SysLogHandler('/dev/log')
|
||||
format = '%s %s' % (release.description, release.version) \
|
||||
+ ':%(dbname)s:%(levelname)s:%(name)s:%(message)s'
|
||||
elif is_macosx_operating_system(): # There is no /dev/log on OSX
|
||||
handler = logging.handlers.SysLogHandler('/var/run/log')
|
||||
else:
|
||||
raise Exception("There is no syslog handler for this Operating System: %s", platform.system())
|
||||
|
||||
format = '%s %s' % (release.description, release.version) + ':%(dbname)s:%(levelname)s:%(name)s:%(message)s'
|
||||
|
||||
elif tools.config['logfile']:
|
||||
# LogFile Handler
|
||||
logf = tools.config['logfile']
|
||||
try:
|
||||
# We check we have the right location for the log files
|
||||
dirname = os.path.dirname(logf)
|
||||
if dirname and not os.path.isdir(dirname):
|
||||
os.makedirs(dirname)
|
||||
|
||||
if tools.config['logrotate'] is not False:
|
||||
handler = logging.handlers.TimedRotatingFileHandler(logf,'D',1,30)
|
||||
elif os.name == 'posix':
|
||||
handler = logging.handlers.TimedRotatingFileHandler(filename=logf, when='D', interval=1, backupCount=30)
|
||||
|
||||
elif is_posix_operating_system():
|
||||
handler = logging.handlers.WatchedFileHandler(logf)
|
||||
|
||||
else:
|
||||
handler = logging.handlers.FileHandler(logf)
|
||||
except Exception:
|
||||
|
@ -125,12 +147,14 @@ def init_logger():
|
|||
# behind Apache with mod_wsgi, handler.stream will have type mod_wsgi.Log,
|
||||
# which has no fileno() method. (mod_wsgi.Log is what is being bound to
|
||||
# sys.stderr when the logging.StreamHandler is being constructed above.)
|
||||
if isinstance(handler, logging.StreamHandler) \
|
||||
and hasattr(handler.stream, 'fileno') \
|
||||
and os.isatty(handler.stream.fileno()):
|
||||
def has_fileno(stream):
|
||||
return hasattr(stream, 'fileno') and os.isatty(stream.fileno())
|
||||
|
||||
if isinstance(handler, logging.StreamHandler) and has_fileno(handler.stream):
|
||||
formatter = ColoredFormatter(format)
|
||||
else:
|
||||
formatter = DBFormatter(format)
|
||||
|
||||
handler.setFormatter(formatter)
|
||||
|
||||
# Configure handlers
|
||||
|
@ -141,7 +165,9 @@ def init_logger():
|
|||
logging_configurations = DEFAULT_LOG_CONFIGURATION + pseudo_config + logconfig
|
||||
for logconfig_item in logging_configurations:
|
||||
loggername, level = logconfig_item.split(':')
|
||||
|
||||
level = getattr(logging, level, logging.INFO)
|
||||
|
||||
logger = logging.getLogger(loggername)
|
||||
logger.handlers = []
|
||||
logger.setLevel(level)
|
||||
|
@ -149,6 +175,13 @@ def init_logger():
|
|||
if loggername != '':
|
||||
logger.propagate = False
|
||||
|
||||
# magic ;-)
|
||||
# we manage the connection in the postgresqlhandler
|
||||
postgresqlHandler = openerp.loggers.handlers.PostgreSQLHandler()
|
||||
postgresqlHandler.setLevel(logging.WARNING)
|
||||
logger = logging.getLogger()
|
||||
logger.addHandler(postgresqlHandler)
|
||||
|
||||
for logconfig_item in logging_configurations:
|
||||
_logger.debug('logger level set: "%s"', logconfig_item)
|
||||
|
||||
|
|
|
@ -72,9 +72,10 @@ class configmanager(object):
|
|||
}
|
||||
|
||||
# Not exposed in the configuration file.
|
||||
self.blacklist_for_save = set(
|
||||
['publisher_warranty_url', 'load_language', 'root_path',
|
||||
'init', 'save', 'config', 'update', 'stop_after_init'])
|
||||
self.blacklist_for_save = set([
|
||||
'publisher_warranty_url', 'load_language', 'root_path',
|
||||
'init', 'save', 'config', 'update', 'stop_after_init'
|
||||
])
|
||||
|
||||
# dictionary mapping option destination (keys in self.options) to MyOptions.
|
||||
self.casts = {}
|
||||
|
@ -83,7 +84,10 @@ class configmanager(object):
|
|||
self.config_file = fname
|
||||
self.has_ssl = check_ssl()
|
||||
|
||||
self._LOGLEVELS = dict([(getattr(loglevels, 'LOG_%s' % x), getattr(logging, x)) for x in ('CRITICAL', 'ERROR', 'WARNING', 'INFO', 'DEBUG', 'NOTSET')])
|
||||
self._LOGLEVELS = dict([
|
||||
(getattr(loglevels, 'LOG_%s' % x), getattr(logging, x))
|
||||
for x in ('CRITICAL', 'ERROR', 'WARNING', 'INFO', 'DEBUG', 'NOTSET')
|
||||
])
|
||||
|
||||
version = "%s %s" % (release.description, release.version)
|
||||
self.parser = parser = optparse.OptionParser(version=version, option_class=MyOption)
|
||||
|
@ -176,12 +180,16 @@ class configmanager(object):
|
|||
group.add_option('--log-response', action="append_const", dest="log_handler", const="openerp.netsvc.rpc.response:DEBUG", help='shortcut for --log-handler=openerp.netsvc.rpc.response:DEBUG')
|
||||
group.add_option('--log-web', action="append_const", dest="log_handler", const="openerp.addons.web.http:DEBUG", help='shortcut for --log-handler=openerp.addons.web.http:DEBUG')
|
||||
group.add_option('--log-sql', action="append_const", dest="log_handler", const="openerp.sql_db:DEBUG", help='shortcut for --log-handler=openerp.sql_db:DEBUG')
|
||||
group.add_option('--log-pgsql-database', dest='log_pgsql_database', help="database where OpenERP will store the exceptions", my_default=False)
|
||||
# For backward-compatibility, map the old log levels to something
|
||||
# quite close.
|
||||
levels = ['info', 'debug_rpc', 'warn', 'test', 'critical',
|
||||
'debug_sql', 'error', 'debug', 'debug_rpc_answer', 'notset']
|
||||
group.add_option('--log-level', dest='log_level', type='choice', choices=levels,
|
||||
my_default='info', help='specify the level of the logging. Accepted values: ' + str(levels) + ' (deprecated option).')
|
||||
levels = [
|
||||
'info', 'debug_rpc', 'warn', 'test', 'critical',
|
||||
'debug_sql', 'error', 'debug', 'debug_rpc_answer', 'notset'
|
||||
]
|
||||
group.add_option('--log-level', dest='log_level', type='choice',
|
||||
choices=levels, my_default='info',
|
||||
help='specify the level of the logging. Accepted values: %s (deprecated option).' % (levels,))
|
||||
|
||||
parser.add_option_group(group)
|
||||
|
||||
|
|
Loading…
Reference in New Issue