47324171d4
*) Add osprofiler wsgi middleware This middleware is used for 2 things: 1) It checks that person who want to trace is trusted and knows secret HMAC key. 2) It start tracing in case of proper trace headers and add first wsgi trace point, with info about HTTP request. *) Add initialization of osprofiler at start of server Initialize and set an oslo.messaging based notifier instance to osprofiler which be used to send notifications to Ceilometer. *) Enable profile on existing useful storage backends Change controller creation logic of data and control panel for mongodb, redis and sqlalchemy storage backends, as well as an aggregative pooling driver. *) Add options to allow operator control profiles separately NOTE to test this: 1) You have to enable necessary profiler option(s) base on your needed. 2) You need to enable follow services in localrc for devstack: CEILOMETER_NOTIFICATION_TOPICS=notifications,profiler ENABLED_SERVICES+=,ceilometer-acompute,ceilometer-acentral ENABLED_SERVICES+=,ceilometer-anotification,ceilometer-collector ENABLED_SERVICES+=,ceilometer-alarm-evaluator,ceilometer-alarm-notifier ENABLED_SERVICES+=,ceilometer-api 3) You should use python-zaqarclient with this change: I880c003511e9e4ef99806ba5b19d0ef6996be80b Run any command with --os-profile <SECRET_KEY> $ openstack --os-profile <SECRET_KEY> queue list # it will print <Trace ID> Get pretty HTML with traces: $ osprofiler trace show --html <Trace ID> note that osprofiler should be run from admin user name & tenant. DocImpact Partially-implements BP: osprofiler Change-Id: I32565de6c447cd5e95a0ef54a9fbd4e571c2d820 Co-Authored-By: wangxiyuan <wangxiyuan@huawei.com>
117 lines
4.6 KiB
Python
117 lines
4.6 KiB
Python
# Copyright 2016 OpenStack, Inc.
|
|
# All Rights Reserved.
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
# not use this file except in compliance with the License. You may obtain
|
|
# a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
# License for the specific language governing permissions and limitations
|
|
# under the License.
|
|
|
|
import six
|
|
import six.moves.urllib.parse as urlparse
|
|
import webob
|
|
|
|
from oslo_log import log
|
|
from osprofiler import _utils as utils
|
|
from osprofiler import notifier
|
|
from osprofiler import profiler
|
|
from osprofiler import web
|
|
from zaqar.i18n import _LW
|
|
|
|
LOG = log.getLogger(__name__)
|
|
|
|
|
|
def setup(conf, binary, host):
|
|
if conf.profiler.enabled:
|
|
|
|
# Note(wangxiyuan): OSprofiler now support some kind of backends, such
|
|
# as Ceilometer, ElasticSearch, Messaging and MongoDB.
|
|
# 1. Ceilometer is only used for data collection, and Messaging is only
|
|
# used for data transfer. So Ceilometer only works when Messaging is
|
|
# enabled.
|
|
# 2. ElasticSearch and MongoDB support both data collection and
|
|
# transfer. So they can be used standalone.
|
|
# 3. Choose which backend depends on the config option
|
|
# "connection_string" , and the default value is "messaging://".
|
|
backend_uri = conf.profiler.connection_string
|
|
if "://" not in backend_uri:
|
|
backend_uri += "://"
|
|
parsed_connection = urlparse.urlparse(backend_uri)
|
|
backend_type = parsed_connection.scheme
|
|
if backend_type == "messaging":
|
|
import oslo_messaging
|
|
_notifier = notifier.create(backend_uri, oslo_messaging, {},
|
|
oslo_messaging.get_transport(conf),
|
|
"Zaqar", binary, host)
|
|
else:
|
|
_notifier = notifier.create(backend_uri, project="Zaqar",
|
|
service=binary, host=host)
|
|
notifier.set(_notifier)
|
|
LOG.warning(_LW("OSProfiler is enabled.\nIt means that person who "
|
|
"knows any of hmac_keys that are specified in "
|
|
"/etc/zaqar/zaqar.conf can trace his requests. \n In "
|
|
"real life only operator can read this file so there "
|
|
"is no security issue. Note that even if person can "
|
|
"trigger profiler, only admin user can retrieve trace "
|
|
"information.\n"
|
|
"To disable OSprofiler set in zaqar.conf:\n"
|
|
"[profiler]\nenabled=false"))
|
|
web.enable(conf.profiler.hmac_keys)
|
|
else:
|
|
web.disable()
|
|
|
|
|
|
class ProfileWSGIMiddleware(object):
|
|
|
|
def __init__(self, application, hmac_keys=None, enabled=False):
|
|
self.application = application
|
|
self.name = "wsgi"
|
|
self.enabled = enabled
|
|
self.hmac_keys = utils.split(hmac_keys or "")
|
|
|
|
def _trace_is_valid(self, trace_info):
|
|
if not isinstance(trace_info, dict):
|
|
return False
|
|
trace_keys = set(six.iterkeys(trace_info))
|
|
if not all(k in trace_keys for k in web._REQUIRED_KEYS):
|
|
return False
|
|
if trace_keys.difference(web._REQUIRED_KEYS + web._OPTIONAL_KEYS):
|
|
return False
|
|
return True
|
|
|
|
def __call__(self, environ, start_response):
|
|
request = webob.Request(environ)
|
|
trace_info = utils.signed_unpack(request.headers.get(web.X_TRACE_INFO),
|
|
request.headers.get(web.X_TRACE_HMAC),
|
|
self.hmac_keys)
|
|
|
|
if not self._trace_is_valid(trace_info):
|
|
return self.application(environ, start_response)
|
|
|
|
profiler.init(**trace_info)
|
|
info = {
|
|
"request": {
|
|
"path": request.path,
|
|
"query": request.query_string,
|
|
"method": request.method,
|
|
"scheme": request.scheme
|
|
}
|
|
}
|
|
with profiler.Trace(self.name, info=info):
|
|
return self.application(environ, start_response)
|
|
|
|
|
|
def install_wsgi_tracer(app, conf):
|
|
enabled = conf.profiler.enabled and conf.profiler.trace_wsgi_transport
|
|
|
|
if enabled:
|
|
LOG.debug(u'Installing osprofiler\'s wsgi tracer')
|
|
|
|
return ProfileWSGIMiddleware(app, conf.profiler.hmac_keys, enabled=enabled)
|