diff --git a/01.getting-started/13.enable-app-insights/13.enable-app-insights-in-production-service.ipynb b/01.getting-started/13.enable-app-insights/13.enable-app-insights-in-production-service.ipynb new file mode 100644 index 00000000..11ce5383 --- /dev/null +++ b/01.getting-started/13.enable-app-insights/13.enable-app-insights-in-production-service.ipynb @@ -0,0 +1,410 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Enabling App Insights for Services in Production\n", + "With this notebook, you can learn how to enable App Insights for standard service monitoring, plus, we provide examples for doing custom logging within a scoring files in a model. \n", + "\n", + "\n", + "## What does Application Insights monitor?\n", + "It monitors request rates, response times, failure rates, etc. For more information visit [App Insights docs.](https://docs.microsoft.com/en-us/azure/application-insights/app-insights-overview)\n", + "\n", + "\n", + "## What is different compared to standard production deployment process?\n", + "If you want to enable generic App Insights for a service run:\n", + "```python\n", + "aks_service= Webservice(ws, \"aks-w-dc2\")\n", + "aks_service.update(enable_app_insights=True)```\n", + "Where \"aks-w-dc2\" is your service name. You can also do this from the Azure Portal under your Workspace--> deployments--> Select deployment--> Edit--> Advanced Settings--> Select \"Enable AppInsights diagnostics\"\n", + "\n", + "If you want to log custom traces, you will follow the standard deplyment process for AKS and you will:\n", + "1. Update scoring file.\n", + "2. Update aks configuration.\n", + "3. Build new image and deploy it. " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 1. Import your dependencies" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from azureml.core import Workspace, Run\n", + "from azureml.core.compute import AksCompute, ComputeTarget\n", + "from azureml.core.webservice import Webservice, AksWebservice\n", + "from azureml.core.image import Image\n", + "from azureml.core.model import Model\n", + "\n", + "import azureml.core\n", + "print(azureml.core.VERSION)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 2. Set up your configuration and create a workspace\n", + "Follow Notebook 00 instructions to do this.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "ws = Workspace.from_config()\n", + "print(ws.name, ws.resource_group, ws.location, ws.subscription_id, sep = '\\n')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 3. Register Model\n", + "Register an existing trained model, add descirption and tags." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "#Register the model\n", + "from azureml.core.model import Model\n", + "model = Model.register(model_path = \"sklearn_regression_model.pkl\", # this points to a local file\n", + " model_name = \"sklearn_regression_model.pkl\", # this is the name the model is registered as\n", + " tags = {'area': \"diabetes\", 'type': \"regression\"},\n", + " description = \"Ridge regression model to predict diabetes\",\n", + " workspace = ws)\n", + "\n", + "print(model.name, model.description, model.version)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 4. *Update your scoring file with custom print statements*\n", + "Here is an example:\n", + "### a. In your init function add:\n", + "```python\n", + "print (\"model initialized\" + time.strftime(\"%H:%M:%S\"))```\n", + "\n", + "### b. In your run function add:\n", + "```python\n", + "print (\"saving input data\" + time.strftime(\"%H:%M:%S\"))\n", + "print (\"saving prediction data\" + time.strftime(\"%H:%M:%S\"))```" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "%%writefile score.py\n", + "import pickle\n", + "import json\n", + "import numpy \n", + "from sklearn.externals import joblib\n", + "from sklearn.linear_model import Ridge\n", + "from azureml.core.model import Model\n", + "from azureml.monitoring import ModelDataCollector\n", + "import time\n", + "\n", + "def init():\n", + " global model\n", + " #Print statement for appinsights custom traces:\n", + " print (\"model initialized\" + time.strftime(\"%H:%M:%S\"))\n", + " \n", + " # note here \"sklearn_regression_model.pkl\" is the name of the model registered under the workspace\n", + " # this call should return the path to the model.pkl file on the local disk.\n", + " model_path = Model.get_model_path(model_name = 'sklearn_regression_model.pkl')\n", + " \n", + " # deserialize the model file back into a sklearn model\n", + " model = joblib.load(model_path)\n", + " \n", + " global inputs_dc, prediction_dc\n", + " \n", + " # this setup will help us save our inputs under the \"inputs\" path in our Azure Blob\n", + " inputs_dc = ModelDataCollector(model_name=\"sklearn_regression_model\", identifier=\"inputs\", feature_names=[\"feat1\", \"feat2\"]) \n", + " \n", + " # this setup will help us save our ipredictions under the \"predictions\" path in our Azure Blob\n", + " prediction_dc = ModelDataCollector(\"sklearn_regression_model\", identifier=\"predictions\", feature_names=[\"prediction1\", \"prediction2\"]) \n", + " \n", + "# note you can pass in multiple rows for scoring\n", + "def run(raw_data):\n", + " global inputs_dc, prediction_dc\n", + " try:\n", + " data = json.loads(raw_data)['data']\n", + " data = numpy.array(data)\n", + " result = model.predict(data)\n", + " \n", + " #Print statement for appinsights custom traces:\n", + " print (\"saving input data\" + time.strftime(\"%H:%M:%S\"))\n", + " \n", + " #this call is saving our input data into our blob\n", + " inputs_dc.collect(data) \n", + " #this call is saving our prediction data into our blob\n", + " prediction_dc.collect(result)\n", + " \n", + " #Print statement for appinsights custom traces:\n", + " print (\"saving prediction data\" + time.strftime(\"%H:%M:%S\"))\n", + " \n", + " return json.dumps({\"result\": result.tolist()})\n", + " \n", + " except Exception as e:\n", + " result = str(e)\n", + " print (result + time.strftime(\"%H:%M:%S\"))\n", + " return json.dumps({\"error\": result})" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 5. *Create myenv.yml file*" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from azureml.core.conda_dependencies import CondaDependencies \n", + "\n", + "myenv = CondaDependencies.create(conda_packages=['numpy','scikit-learn'])\n", + "\n", + "with open(\"myenv.yml\",\"w\") as f:\n", + " f.write(myenv.serialize_to_string())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 6. Create your new Image" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from azureml.core.image import ContainerImage\n", + "\n", + "image_config = ContainerImage.image_configuration(execution_script = \"score.py\",\n", + " runtime = \"python\",\n", + " conda_file = \"myenv.yml\",\n", + " description = \"Image with ridge regression model\",\n", + " tags = {'area': \"diabetes\", 'type': \"regression\"}\n", + " )\n", + "\n", + "image = ContainerImage.create(name = \"myimage1\",\n", + " # this is the model object\n", + " models = [model],\n", + " image_config = image_config,\n", + " workspace = ws)\n", + "\n", + "image.wait_for_creation(show_output = True)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 7. Deploy to AKS service" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Create AKS compute if you haven't done so (Notebook 11)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Use the default configuration (can also provide parameters to customize)\n", + "prov_config = AksCompute.provisioning_configuration()\n", + "\n", + "aks_name = 'my-aks-test1' \n", + "# Create the cluster\n", + "aks_target = ComputeTarget.create(workspace = ws, \n", + " name = aks_name, \n", + " provisioning_configuration = prov_config)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "%%time\n", + "aks_target.wait_for_completion(show_output = True)\n", + "print(aks_target.provisioning_state)\n", + "print(aks_target.provisioning_errors)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "If you already have a cluster you can attach the service to it:" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "```python \n", + "%%time\n", + "resource_id = '/subscriptions//resourcegroups//providers/Microsoft.ContainerService/managedClusters/'\n", + "create_name= 'myaks4'\n", + "aks_target = AksCompute.attach(workspace = ws, \n", + " name = create_name, \n", + " #esource_id=resource_id)\n", + "## Wait for the operation to complete\n", + "aks_target.wait_for_provisioning(True)```" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### a. *Activate App Insights through updating AKS Webservice configuration*\n", + "In order to enable App Insights in your service you will need to update your AKS configuration file:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "#Set the web service configuration\n", + "aks_config = AksWebservice.deploy_configuration(enable_app_insights=True)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### b. Deploy your service" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "%%time\n", + "aks_service_name ='aks-w-dc3'\n", + "\n", + "aks_service = Webservice.deploy_from_image(workspace = ws, \n", + " name = aks_service_name,\n", + " image = image,\n", + " deployment_config = aks_config,\n", + " deployment_target = aks_target\n", + " )\n", + "aks_service.wait_for_deployment(show_output = True)\n", + "print(aks_service.state)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 8. Test your service " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "%%time\n", + "import json\n", + "\n", + "test_sample = json.dumps({'data': [\n", + " [1,28,13,45,54,6,57,8,8,10], \n", + " [101,9,8,37,6,45,4,3,2,41]\n", + "]})\n", + "test_sample = bytes(test_sample,encoding = 'utf8')\n", + "\n", + "prediction = aks_service.run(input_data = test_sample)\n", + "print(prediction)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 9. See your service telemetry in App Insights\n", + "1. Go to the [Azure Portal](https://portal.azure.com/)\n", + "2. All resources--> Select the subscription/resource group where you created your Workspace--> Select the App Insights type\n", + "3. Click on the AppInsights resource. You'll see a highlevel dashboard with information on Requests, Server response time and availability.\n", + "4. Click on the top banner \"Analytics\"\n", + "5. In the \"Schema\" section select \"traces\" and run your query.\n", + "6. Voila! All your custom traces should be there." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Disable App Insights" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "aks_service.update(enable_app_insights=False)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3.6", + "language": "python", + "name": "python36" + }, + "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.6.6" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} \ No newline at end of file