text: # Copyright 2016 Mirantis 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 contextlib
  import json
  
  from django.conf import settings
  from osprofiler import _utils as utils
  from osprofiler.drivers.base import get_driver as profiler_get_driver
  from osprofiler import notifier
  from osprofiler import profiler
  from osprofiler import web
  import six
  from six.moves.urllib.parse import urlparse
  
  
  ROOT_HEADER = 'PARENT_VIEW_TRACE_ID'
  PROFILER_SETTINGS = settings.OPENSTACK_PROFILER
  
  
  def init_notifier(connection_str, host="localhost"):
      _notifier = notifier.create(
          connection_str, project='horizon', service='horizon', host=host)
      notifier.set(_notifier)
  
  
  @contextlib.contextmanager
  def traced(request, name, info=None):
      if info is None:
          info = {}
      profiler_instance = profiler.get()
      if profiler_instance is not None:
          trace_id = profiler_instance.get_base_id()
          info['user_id'] = request.user.id
          with profiler.Trace(name, info=info):
              yield trace_id
      else:
          yield
  
  
  def _get_engine_kwargs(request, connection_str):
      from openstack_dashboard.api import base
      engines_kwargs = {
          # NOTE(tsufiev): actually Horizon doesn't use ceilometer backend (too
          # slow for UI), but since osprofiler still supports it (due to API
          # deprecation cycle limitations), Horizon also should support this
          # option
          'ceilometer': lambda req: {
              'endpoint': base.url_for(req, 'metering'),
              'insecure': settings.OPENSTACK_SSL_NO_VERIFY,
              'cacert': settings.OPENSTACK_SSL_CACERT,
              'token': (lambda: req.user.token.id),
              'ceilometer_api_version': '2'
          }
      }
  
      engine = urlparse(connection_str).scheme
      return engines_kwargs.get(engine, lambda req: {})(request)
  
  
  def _get_engine(request):
      connection_str = PROFILER_SETTINGS['receiver_connection_string']
      kwargs = _get_engine_kwargs(request, connection_str)
      return profiler_get_driver(connection_str, **kwargs)
  
  
  def list_traces(request):
      engine = _get_engine(request)
      fields = ['base_id', 'timestamp', 'info.request.path', 'info']
      traces = engine.list_traces(fields)
      return [{'id': trace['base_id'],
               'timestamp': trace['timestamp'],
               'origin': trace['info']['request']['path']} for trace in traces]
  
  
  def get_trace(request, trace_id):
      def rec(_data, level=0):
          _data['level'] = level
          _data['is_leaf'] = not _data['children']
          _data['visible'] = True
          _data['childrenVisible'] = True
          finished = _data['info']['finished']
          for child in _data['children']:
              __, child_finished = rec(child, level + 1)
              # NOTE(tsufiev): in case of async requests the root request usually
              # finishes before the dependent requests do so, to we need to
              # normalize the duration of all requests by the finishing time of
              # the one which took longest
              if child_finished > finished:
                  finished = child_finished
          return _data, finished
  
      engine = _get_engine(request)
      trace = engine.get_report(trace_id)
      data, max_finished = rec(trace)
      data['info']['max_finished'] = max_finished
      return data
  
  
  def update_trace_headers(keys, **kwargs):
      trace_headers = web.get_trace_id_headers()
      trace_info = utils.signed_unpack(
          trace_headers[web.X_TRACE_INFO], trace_headers[web.X_TRACE_HMAC],
          keys)
      trace_info.update(kwargs)
      p = profiler.get()
      trace_data = utils.signed_pack(trace_info, p.hmac_key)
      if six.PY3:
          trace_data = [key.decode() if isinstance(key, six.binary_type)
                        else key for key in trace_data]
      return json.dumps({web.X_TRACE_INFO: trace_data[0],
                         web.X_TRACE_HMAC: trace_data[1]})
  
  
  if not PROFILER_SETTINGS['enabled']:
      def trace(function):
          return function
  else:
      def trace(function):
          func_name = function.__module__ + '.' + function.__name__
          decorator = profiler.trace(func_name)
          return decorator(function)
  