1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143
|
# 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)
|