text: # 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 json
  import os
  
  from rally.common import cfg
  from rally.common import logging
  from rally.common import opts
  from rally.common.plugin import plugin
  from rally.task.processing import charts
  
  
  OPTS = {
      "openstack": [
          cfg.StrOpt(
              "osprofiler_chart_mode",
              default=None,
              help="Mode of embedding OSProfiler's chart. Can be 'text' "
                   "(embed only trace id), 'raw' (embed raw osprofiler's native "
                   "report) or a path to directory (raw osprofiler's native "
                   "reports for each iteration will be saved separately there "
                   "to decrease the size of rally report itself)")
      ]
  }
  
  
  LOG = logging.getLogger(__name__)
  CONF = cfg.CONF
  
  
  def _datetime_json_serialize(obj):
      if hasattr(obj, "isoformat"):
          return obj.isoformat()
      else:
          return obj
  
  
  @plugin.configure(name="OSProfiler")
  class OSProfilerChart(charts.OutputEmbeddedChart,
                        charts.OutputEmbeddedExternalChart,
                        charts.OutputTextArea):
      """Chart for embedding OSProfiler data."""
  
      @classmethod
      def _fetch_osprofiler_data(cls, connection_str, trace_id):
          from osprofiler.drivers import base
          from osprofiler import opts as osprofiler_opts
  
          opts.register_opts(osprofiler_opts.list_opts())  # noqa
  
          try:  # noqa
              engine = base.get_driver(connection_str)
          except Exception:
              msg = "Error while fetching OSProfiler results."
              if logging.is_debug():
                  LOG.exception(msg)
              else:
                  LOG.error(msg)
              return None
  
          return engine.get_report(trace_id)
  
      @classmethod
      def _generate_osprofiler_report(cls, osp_data):
          from osprofiler import cmd
  
          path = "%s/template.html" % os.path.dirname(cmd.__file__)
          with open(path) as f:
              html_obj = f.read()
  
          osp_data = json.dumps(osp_data,
                                indent=4,
                                separators=(",", ": "),
                                default=_datetime_json_serialize)
          return html_obj.replace("$DATA", osp_data).replace("$LOCAL", "false")
  
      @classmethod
      def _return_raw_response_for_complete_data(cls, data):
          return charts.OutputTextArea.render_complete_data({
              "title": data["title"],
              "widget": "TextArea",
              "data": [data["data"]["trace_id"]]
          })
  
      @classmethod
      def render_complete_data(cls, data):
          mode = CONF.openstack.osprofiler_chart_mode
  
          if isinstance(data["data"]["trace_id"], list):
              # NOTE(andreykurilin): it is an adoption for the format that we
              #   used  before rally-openstack 1.5.0 .
              data["data"]["trace_id"] = data["data"]["trace_id"][0]
  
          if data["data"].get("conn_str") and mode != "text":
              osp_data = cls._fetch_osprofiler_data(
                  data["data"]["conn_str"],
                  trace_id=data["data"]["trace_id"]
              )
              if not osp_data:
                  # for some reasons we failed to fetch data from OSProfiler's
                  # backend. in this case we can display just trace ID
                  return cls._return_raw_response_for_complete_data(data)
  
              osp_report = cls._generate_osprofiler_report(osp_data)
              title = "{0} : {1}".format(data["title"],
                                         data["data"]["trace_id"])
  
              if (mode and mode != "raw") and "workload_uuid" in data["data"]:
                  # NOTE(andreykurilin): we need to rework our charts plugin
                  #   mechanism so it is available out of box
                  workload_uuid = data["data"]["workload_uuid"]
                  iteration = data["data"]["iteration"]
                  file_name = "w_%s-%s.html" % (workload_uuid, iteration)
                  path = os.path.join(mode, file_name)
                  with open(path, "w") as f:
                      f.write(osp_report)
                  return charts.OutputEmbeddedExternalChart.render_complete_data(
                      {
                          "title": title,
                          "widget": "EmbeddedChart",
                          "data": path
                      }
                  )
              else:
                  return charts.OutputEmbeddedChart.render_complete_data(
                      {"title": title,
                       "widget": "EmbeddedChart",
                       "data": osp_report}
                  )
  
          return cls._return_raw_response_for_complete_data(data)
  