{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# The Plan\n", "Everything we know about the plan.\n", "\n", "### Instructions\n", "1. Run all cells! (click on Menu > Cell > Run All Cells)\n", "1. View report at the bottom." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "inputHidden": false, "outputHidden": false, "tags": [ "parameters" ] }, "outputs": [], "source": [ "#planId = \"98db70e2-cee5-4e2d-ae15-dca389fa8f41\"\n", "planId = \"f38f1a4b-49d7-4f08-a9b9-c81b2c39aff6\"" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "inputHidden": false, "outputHidden": false }, "outputs": [], "source": [ "%%capture \n", "# install packages, setup workspace root\n", "!pip install azure-kusto-notebooks plotly\n", "import os\n", "from azure.kusto.notebooks import utils as akn\n", "import pandas as pd\n", "pd.options.display.html.table_schema = True\n", "\n", "# cwd should be workspace root\n", "if os.path.basename(os.getcwd()) == 'devops-pipelines':\n", " os.chdir(os.pardir)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "inputHidden": false, "outputHidden": false }, "outputs": [], "source": [ "# authenticate kusto client\n", "# you will need to copy the token into a browser window for AAD auth. \n", "client = akn.get_client('https://vso.kusto.windows.net')" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "inputHidden": false, "outputHidden": false }, "outputs": [], "source": [ "# collect basic plan info\n", "plan_info = akn.Query(\n", " client, 'VSO', \n", " path=os.path.join('devops-pipelines', 'queries', 'run', 'PlanInfo.csl'), \n", " params={'OrchestrationId': akn.quote(planId)})\n", "\n", "# collect full plan history\n", "what_happened = akn.Query(client, 'VSO',\n", " path=os.path.join('devops-pipelines', 'queries', 'run', 'WhatHappened.csl'),\n", " params={'OrchestrationId': akn.quote(planId)})\n", "\n", "# fetch data in parallel\n", "akn.run((plan_info, what_happened))" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "inputHidden": false, "outputHidden": false }, "outputs": [], "source": [ "# draw basic info\n", "\n", "# compute relative time stamps\n", "history = what_happened.dataframe\n", "t0 = history['PreciseTimeStamp'].iloc[0]\n", "history['Time'] = history.apply(lambda row: row['PreciseTimeStamp'] - t0, axis=1)\n", "history.OrchestrationId = history.apply(lambda row: row.OrchestrationId[37:], axis=1)\n", "\n", "# record critical times\n", "def find_time(message):\n", " r = history[history.Message.str.startswith(message)]\n", " if len(r.index) > 0:\n", " return r['PreciseTimeStamp'].iloc[0]\n", "\n", "create_time = find_time('Created plan')\n", "start_time = find_time('Started plan')\n", "end_time = find_time('Completed orchestration with result')\n", "total_duration = end_time - start_time if end_time and start_time else None\n", "\n", "import importlib\n", "importlib.reload(akn)\n", "# info will only exist if the plan has started at least one job :(\n", "d = akn.pandas_row_to_dictionary(plan_info.dataframe)\n", "d['create time'] = create_time\n", "d['start time'] = start_time\n", "d['end time'] = end_time\n", "d['total duration'] = total_duration\n", "r = akn.Report()\n", "r.write(akn.to_md_table(d))\n", "\n", "from IPython.display import Markdown\n", "Markdown(r.content)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "inputHidden": false, "outputHidden": false }, "outputs": [], "source": [ "# SLA analysis\n", "su = akn.quote(d.get('ScaleUnit', ''))\n", "oids = [akn.quote(joid) for joid in d.get('JobOrchestrationIds', [])]\n", "slas = [akn.Query(client, 'VSO', \n", " os.path.join('devops-pipelines', 'queries', 'sla', 'SLAVisualization.csl'),\n", " params=dict(ScaleUnit=su, OrchestrationId=oid)) \n", " for oid in oids]\n", "akn.run(slas)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "inputHidden": false, "outputHidden": false }, "outputs": [], "source": [ "# draw all slas\n", "from _plotly_future_ import v4_subplots\n", "from plotly.subplots import make_subplots\n", "import plotly.graph_objects as go\n", "import math\n", "if not slas:\n", " print(\"There are no jobs associated with this plan.\")\n", "else:\n", " number_of_graphs = min(25, len(slas))\n", " names = [n[37:] for n in d.get('JobOrchestrationIds',[])]\n", " fig = make_subplots(cols=2, rows=int(math.ceil(number_of_graphs / 2)), \n", " subplot_titles=names,\n", " shared_xaxes=True, \n", " vertical_spacing=0.1)\n", "\n", " for i in range(len(slas)):\n", " df = slas[i].dataframe\n", " row = int(i / 2) + 1\n", " col = int(i % 2) + 1\n", " name = names[i]\n", " \n", " df = slas[0].dataframe\n", " fig.add_trace(go.Bar(x=df.PhaseName, y=df.PercentDifference, name=name), \n", " row=row, col=col)\n", " fig.update_xaxes(showgrid=False, tickangle=-60, automargin=True)\n", " fig.update_xaxes(showgrid=True, zeroline=True, automargin=True)\n", " fig.update_layout(height=150 * number_of_graphs, \n", " width=1000, showlegend=False,\n", " title_text=\"Analysis!\")\n", "\n", " fig.show()" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "inputHidden": false, "outputHidden": false }, "outputs": [], "source": [ "# draw full history\n", "columns_to_ignore = ('source_', 'PreciseTimeStamp')\n", "columns = ['Time'] + [c for c in history.columns if c not in columns_to_ignore and c != 'Time']\n", "\n", "from IPython.display import HTML\n", "HTML(history[columns].to_html(index=False))" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "inputHidden": false, "outputHidden": false }, "outputs": [], "source": [] } ], "metadata": { "kernel_info": { "name": "python3" }, "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.7.4" }, "nteract": { "version": "0.14.5" } }, "nbformat": 4, "nbformat_minor": 2 }