Add oslo.log library

Add oslo.log lib in application.
Move API related options from refstack/api/config.py
to the oslo_config's configuration file.
Make regeneration of example config file with oslo.log namespace
and with moved API options.

Change-Id: Id0db95fe34eb8faa284e9d716cbeebdf6d25c183
This commit is contained in:
Vladislav Kuzmin 2015-02-11 15:47:59 +04:00
parent d6387efb42
commit 9ac0db3253
10 changed files with 194 additions and 71 deletions

View File

@ -20,12 +20,16 @@ Command-line utility for database manage
import sys import sys
from oslo.config import cfg from oslo_config import cfg
from oslo_log import log
from refstack.db import migration from refstack.db import migration
LOG = log.getLogger(__name__)
CONF = cfg.CONF CONF = cfg.CONF
log.register_options(CONF)
class DatabaseManager(object): class DatabaseManager(object):
@ -91,4 +95,5 @@ CONF.register_cli_opt(command_opt)
if __name__ == '__main__': if __name__ == '__main__':
CONF(sys.argv[1:], project='refstack') CONF(sys.argv[1:], project='refstack')
log.setup(CONF, 'refstack')
CONF.command.func() CONF.command.func()

View File

@ -1,5 +1,91 @@
[DEFAULT] [DEFAULT]
#
# From oslo.log
#
# Print debugging output (set logging level to DEBUG instead of
# default WARNING level). (boolean value)
#debug = false
# Print more verbose output (set logging level to INFO instead of
# default WARNING level). (boolean value)
#verbose = false
# The name of a logging configuration file. This file is appended to
# any existing logging configuration files. For details about logging
# configuration files, see the Python logging module documentation.
# (string value)
# Deprecated group/name - [DEFAULT]/log_config
#log_config_append = <None>
# DEPRECATED. A logging.Formatter log message format string which may
# use any of the available logging.LogRecord attributes. This option
# is deprecated. Please use logging_context_format_string and
# logging_default_format_string instead. (string value)
#log_format = <None>
# Format string for %%(asctime)s in log records. Default: %(default)s
# . (string value)
#log_date_format = %Y-%m-%d %H:%M:%S
# (Optional) Name of log file to output to. If no default is set,
# logging will go to stdout. (string value)
# Deprecated group/name - [DEFAULT]/logfile
#log_file = <None>
# (Optional) The base directory used for relative --log-file paths.
# (string value)
# Deprecated group/name - [DEFAULT]/logdir
#log_dir = <None>
# Use syslog for logging. Existing syslog format is DEPRECATED during
# I, and will change in J to honor RFC5424. (boolean value)
#use_syslog = false
# (Optional) Enables or disables syslog rfc5424 format for logging. If
# enabled, prefixes the MSG part of the syslog message with APP-NAME
# (RFC5424). The format without the APP-NAME is deprecated in I, and
# will be removed in J. (boolean value)
#use_syslog_rfc_format = false
# Syslog facility to receive log lines. (string value)
#syslog_log_facility = LOG_USER
# Log output to standard error. (boolean value)
#use_stderr = true
# Format string to use for log messages with context. (string value)
#logging_context_format_string = %(asctime)s.%(msecs)03d %(process)d %(levelname)s %(name)s [%(request_id)s %(user_identity)s] %(instance)s%(message)s
# Format string to use for log messages without context. (string
# value)
#logging_default_format_string = %(asctime)s.%(msecs)03d %(process)d %(levelname)s %(name)s [-] %(instance)s%(message)s
# Data to append to log format when level is DEBUG. (string value)
#logging_debug_format_suffix = %(funcName)s %(pathname)s:%(lineno)d
# Prefix each line of exception output with this format. (string
# value)
#logging_exception_prefix = %(asctime)s.%(msecs)03d %(process)d TRACE %(name)s %(instance)s
# List of logger=LEVEL pairs. (list value)
#default_log_levels = amqp=WARN,amqplib=WARN,boto=WARN,qpid=WARN,sqlalchemy=WARN,suds=INFO,oslo.messaging=INFO,iso8601=WARN,requests.packages.urllib3.connectionpool=WARN,urllib3.connectionpool=WARN,websocket=WARN,keystonemiddleware=WARN,routes.middleware=WARN,stevedore=WARN
# Enables or disables publication of error events. (boolean value)
#publish_errors = false
# Enables or disables fatal status of deprecations. (boolean value)
#fatal_deprecations = false
# The format for an instance that is passed with the log message.
# (string value)
#instance_format = "[instance: %(uuid)s] "
# The format for an instance UUID that is passed with the log message.
# (string value)
#instance_uuid_format = "[instance: %(uuid)s] "
# #
# From refstack # From refstack
# #
@ -8,6 +94,35 @@
#db_backend = sqlalchemy #db_backend = sqlalchemy
[api]
#
# From refstack
#
# The directory where your static files can be found. Pecan comes with
# middleware that can be used to serve static files (like CSS and
# Javascript files) during development. %(project_root)s is special
# variable that point to the root directory of Refstack project. Value
# of this option must contain %(project_root)s variable. Directory
# with static files specified relative the project root. (string
# value)
#static_root = %(project_root)s/static
# Points to the directory where your template files live.
# %(project_root)s is special variable that point to the root
# directory of Refstack project. Value of this option must contain
# %(project_root)s variable. Directory with template files specified
# relative the project root. (string value)
#template_path = %(project_root)s/templates
# Switch Refstack app into debug mode. Helpful for development. In
# debug mode static file will be served by pecan application. Also,
# server responses will contain some details with debug information.
# (boolean value)
#app_dev_mode = false
[database] [database]
# #

View File

@ -20,24 +20,64 @@ import logging
import os import os
from oslo_config import cfg from oslo_config import cfg
from oslo_log import log
from oslo_log import loggers
import pecan import pecan
from pecan import hooks from pecan import hooks
import webob import webob
from refstack import utils LOG = log.getLogger(__name__)
logger = logging.getLogger(__name__) PROJECT_ROOT = os.path.join(os.path.dirname(os.path.abspath(__file__)),
os.pardir)
API_OPTS = [
cfg.StrOpt('static_root',
default='%(project_root)s/static',
help='The directory where your static files can '
'be found. Pecan comes with middleware that can be used '
'to serve static files (like CSS and Javascript files) '
'during development. %(project_root)s is special variable '
'that point to the root directory of Refstack project. '
'Value of this option must contain %(project_root)s '
'variable. Directory with static files specified relative '
'the project root.'
),
cfg.StrOpt('template_path',
default='%(project_root)s/templates',
help='Points to the directory where your template files live. '
'%(project_root)s is special variable that point to the '
'root directory of Refstack project. Value of this option '
'must contain %(project_root)s variable. Directory with '
'template files specified relative the project root.'
),
cfg.BoolOpt('app_dev_mode',
default=False,
help='Switch Refstack app into debug mode. Helpful for '
'development. In debug mode static file will be served '
'by pecan application. Also, server responses will '
'contain some details with debug information.'
),
]
CONF = cfg.CONF CONF = cfg.CONF
opt_group = cfg.OptGroup(name='api',
title='Options for the Refstack API')
CONF.register_group(opt_group)
CONF.register_opts(API_OPTS, opt_group)
log.register_options(CONF)
class JSONErrorHook(hooks.PecanHook): class JSONErrorHook(hooks.PecanHook):
""" """
A pecan hook that translates webob HTTP errors into a JSON format. A pecan hook that translates webob HTTP errors into a JSON format.
""" """
def __init__(self, app_config): def __init__(self):
"""Hook init.""" """Hook init."""
self.debug = app_config.get('debug', False) self.debug = CONF.api.app_dev_mode
def on_error(self, state, exc): def on_error(self, state, exc):
"""Request error handler.""" """Request error handler."""
@ -52,7 +92,7 @@ class JSONErrorHook(hooks.PecanHook):
content_type='application/json' content_type='application/json'
) )
else: else:
logger.exception(exc) LOG.exception(exc)
body = {'code': 500, body = {'code': 500,
'title': 'Internal Server Error'} 'title': 'Internal Server Error'}
if self.debug: if self.debug:
@ -66,18 +106,6 @@ class JSONErrorHook(hooks.PecanHook):
def setup_app(config): def setup_app(config):
"""App factory.""" """App factory."""
app_conf = dict(config.app)
app = pecan.make_app(
app_conf.pop('root'),
logging=getattr(config, 'logging', {}),
hooks=[JSONErrorHook(app_conf), hooks.RequestViewerHook(
{'items': ['status', 'method', 'controller', 'path', 'body']},
headers=False, writer=utils.LogWriter(logger, logging.DEBUG)
)],
**app_conf
)
# By default we expect path to oslo config file in environment variable # By default we expect path to oslo config file in environment variable
# REFSTACK_OSLO_CONFIG (option for testing and development) # REFSTACK_OSLO_CONFIG (option for testing and development)
# If it is empty we look up those config files # If it is empty we look up those config files
@ -86,14 +114,30 @@ def setup_app(config):
# ~/ # ~/
# /etc/${project}/ # /etc/${project}/
# /etc/ # /etc/
default_config_files = ((os.getenv('REFSTACK_OSLO_CONFIG'), ) default_config_files = ((os.getenv('REFSTACK_OSLO_CONFIG'), )
if os.getenv('REFSTACK_OSLO_CONFIG') if os.getenv('REFSTACK_OSLO_CONFIG')
else cfg.find_config_files('refstack')) else cfg.find_config_files('refstack'))
CONF('', CONF('',
project='refstack', project='refstack',
default_config_files=default_config_files) default_config_files=default_config_files)
CONF.log_opt_values(logger, logging.DEBUG) log.setup(CONF, 'refstack')
CONF.log_opt_values(LOG, logging.DEBUG)
template_path = CONF.api.template_path % {'project_root': PROJECT_ROOT}
static_root = CONF.api.static_root % {'project_root': PROJECT_ROOT}
app_conf = dict(config.app)
app = pecan.make_app(
app_conf.pop('root'),
debug=CONF.api.app_dev_mode,
static_root=static_root,
template_path=template_path,
hooks=[JSONErrorHook(), hooks.RequestViewerHook(
{'items': ['status', 'method', 'controller', 'path', 'body']},
headers=False, writer=loggers.WritableLogger(LOG, logging.DEBUG)
)]
)
return app return app

View File

@ -34,33 +34,4 @@ server = {
app = { app = {
'root': 'refstack.api.controllers.root.RootController', 'root': 'refstack.api.controllers.root.RootController',
'modules': ['refstack.api'], 'modules': ['refstack.api'],
'static_root': '%(confdir)s/../static',
'template_path': '%(confdir)s/../templates',
# The 'debug' option should be false in production servers, but needs to be
# true in development in order to allow the static_root option to work.
'debug': False,
'errors': {
'404': '/error/404',
'__force_dict__': True
}
}
logging = {
'loggers': {
'root': {'level': 'INFO', 'handlers': ['console']},
'refstack': {'level': 'DEBUG', 'handlers': ['console']}
},
'handlers': {
'console': {
'level': 'DEBUG',
'class': 'logging.StreamHandler',
'formatter': 'simple'
}
},
'formatters': {
'simple': {
'format': ('%(asctime)s %(levelname)-5.5s [%(name)s]'
'[%(threadName)s] %(message)s')
}
}
} }

View File

@ -14,15 +14,14 @@
# under the License. # under the License.
"""Version 1 of the API.""" """Version 1 of the API."""
import logging from oslo_log import log
import pecan import pecan
from pecan import rest from pecan import rest
from refstack import db from refstack import db
from refstack.common import validators from refstack.common import validators
logger = logging.getLogger(__name__) LOG = log.getLogger(__name__)
class RestControllerWithValidation(rest.RestController): class RestControllerWithValidation(rest.RestController):

View File

@ -14,13 +14,11 @@
# under the License. # under the License.
"""Utilities for database.""" """Utilities for database."""
import logging
from oslo_config import cfg from oslo_config import cfg
from oslo_log import log
CONF = cfg.CONF CONF = cfg.CONF
LOG = logging.getLogger(__name__) LOG = log.getLogger(__name__)
class PluggableBackend(object): class PluggableBackend(object):

View File

@ -31,6 +31,7 @@
] ]
... ...
""" """
import refstack.api.app
import refstack.db.api import refstack.db.api
@ -38,4 +39,5 @@ def list_opts():
return [ return [
# Keep a list in alphabetical order # Keep a list in alphabetical order
('DEFAULT', refstack.db.api.db_opts), ('DEFAULT', refstack.db.api.db_opts),
('api', refstack.api.app.API_OPTS),
] ]

View File

@ -20,7 +20,6 @@
from datetime import datetime from datetime import datetime
import os import os
import random import random
import re
import string import string
@ -61,18 +60,6 @@ SEX_TYPE = {
STRING_LEN = 64 STRING_LEN = 64
class LogWriter(object):
"""Stream-like API to logger"""
def __init__(self, logger, level):
self.logger = logger
self.level = level
def write(self, s):
if re.sub('[\n ]', '', s):
self.logger.log(self.level, '\n' + s)
def get_current_time(): def get_current_time():
return datetime.utcnow() return datetime.utcnow()

View File

@ -4,8 +4,9 @@ alembic==0.5.0
gunicorn==18 gunicorn==18
oslo.config>=1.6.0 # Apache-2.0 oslo.config>=1.6.0 # Apache-2.0
oslo.db>=1.4.1 # Apache-2.0 oslo.db>=1.4.1 # Apache-2.0
oslo.log
pecan>=0.8.2 pecan>=0.8.2
pyOpenSSL==0.13 pyOpenSSL==0.13
pycrypto==2.6 pycrypto==2.6
requests==1.2.3 requests==1.2.3
jsonschema>=2.0.0,<3.0.0 jsonschema>=2.0.0,<3.0.0

View File

@ -40,7 +40,8 @@ distribute = false
commands = commands =
oslo-config-generator --output-file etc/refstack.conf.sample \ oslo-config-generator --output-file etc/refstack.conf.sample \
--namespace refstack \ --namespace refstack \
--namespace oslo.db --namespace oslo.db \
--namespace oslo.log
[testenv:venv] [testenv:venv]
commands = {posargs} commands = {posargs}