{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# UTelemetry\n", "\n", "Urgap offers standardized way to use opentelementry code-based instrumentation in `urgap.utl`.\n", "The drive behind developing our own class was to be able to span, init and close traces using a \"span_context\" from anywhere in the code. Additionally, the exporter can be configured in urgap so code-based instrumentation does not need to be adjusted and secrets can be handled like all urgap secrets, based on endpoint url, if needed.\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The UTelemetry class is standalone, here are some examples on how to use it. Please note that as soon as metrics or traces are \"set\", they cannot be overwritten. Meaning the moment `urgap.utl.tracer` or `urgap.utl.meter` is accessed, otlp is set. Hence if you change configuration, e.g. the type of exporter, it would require you to restart the python kernel.\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Configurations" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "there are two entries in the .urgap/urgap.json configuration:" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "```json\n", " \"opentelemetry_collector_url\": {\n", " \"value\": null,\n", " \"description\": \"Open Telementry Collector url, e.g. http://localhost:4317\"\n", " },\n", " \"opentelemetry_exporter_type\": {\n", " \"value\": null,\n", " \"description\": \"Open Telementry Exporter Type. Null will disable OTEL.\",\n", " \"options\": [null, \"OTPL\", \"AZ-Insights\", \"Console\"]\n", " }\n", "```" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The collector url defines the endpoint where traces and metrics are collected, for example a OpenTelementryCollector. Logs are currently in beta in the Python SDK so they are not supported. Additionally, logs can be attached to traces (see below).\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "If `opentelemetry_exporter_type` is set to `AZ-Insights`, then a Azure Insight connection string is required to export the metrics. As with all interfaces in Urgap, secrets are extracted based on a url, also known as the cred_key (see 01_credential_manager.ipynb). So if we define:" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "```json\n", " \"opentelemetry_collector_url\": {\n", " \"value\": \"https://eastus2-3.in.applicationinsights.azure.com\",\n", " \"local-value\": \"http://localhost:4317\",\n", " \"description\": \"Open Telementry Collector url, e.g. http://localhost:4317\"\n", " },\n", " \"opentelemetry_exporter_type\": {\n", " \"value\": \"AZ-Insights\",\n", " \"description\": \"Open Telementry Exporter Type\",\n", " \"options\": [\"OTPL\", \"AZ-Insights\", \"Console\", null]\n", " }\n", "```" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Then we need to define where the secrets can be found for `https://eastus2-3.in.applicationinsights.azure.com` in the `~/.urgap/credential_lookup.json`, for example:" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "```json\n", "{\n", " \"description\": \"OpenTelemetry Azure (dsoappinstprod). We store the connection string in password and user is just a dummy.\",\n", " \"scheme\": \"https\",\n", " \"host\": \"eastus2-3.in.applicationinsights.azure.com\",\n", " \"user\": \"U_AZ_INSIGHT_USER\",\n", " \"password\": \"U_AZ_INSIGHT_PASSWORD\",\n", " \"secure\": true,\n", " \"secret_store\": \"env\"\n", "}\n", "```" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Here we say that we stored the Azure Application insight connection string in the `password` env variable.\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Alternatively you can set it to \"Console\" or spin up a local deployment, files can be found below under Local OTLP setup." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Working with counters \n", "(only meter implemented right now...)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import urgap\n", "\n", "urgap.utl.increase_counter(\n", " counter_name=\"co.flowcyto.cell_intensity.rows_ingested\",\n", " # description < not implemented yet (go do PR!)\n", " count=1332, # defaults to 1\n", ")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Working with Traces" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "A trace is defined by a start and an end, better init and close. Additionally, a span can have attributes and can be used to capture events, e.g. logs. Traces can be nested. The UTelemetry class / object takes care of the book keeping, closing of all traces and the ability to modify any trace anywhere in the code.\n", "For example:\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import urgap, time\n", "\n", "span_context = [\"u_the_wild_beaver_is_hungry_for_real\", \"nested_1\", \"nested_2\"]\n", "urgap.utl.init_span(span_context, attributes={\"demo\": True, \"return_code\": 404})\n", "# urgap.utl.add_span_event(span_context[:-1], \"Some log for nested_1\")\n", "urgap.utl.close_span(span_context) # would close recursivly as well!\n", "# time.sleep(1)\n", "# urgap.utl.close_span([\"u_the_wild_beaver_is_hungry\"])\n", "# urgap.utl.end_all_spans()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Debugging time" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import urgap, time\n", "\n", "span_context = [\n", " \"u_the_wild_beaver_is_hungry_for_real\",\n", " # \">><\"\n", "]\n", "urgap.utl.init_span(\n", " span_context,\n", " # attributes={\n", " # \"demo\": True,\n", " # \"return_code\": 404\n", " # } # will be set to last element in the span_context\n", ")\n", "# urgap.utl.add_span_event(span_context[:-1], \"Some log for nested_1\")\n", "urgap.utl.close_span(span_context) # would close recursivly as well!\n", "# time.sleep(1)\n", "# urgap.utl.close_span([\"u_the_wild_beaver_is_hungry\"])\n", "urgap.utl.end_all_spans()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Local OTLP setup" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Docker-compose.yaml" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "```docker\n", "#Docker-compose.yaml\n", "services:\n", "\n", " # Jaeger\n", " jaeger:\n", " container_name: jaeger\n", " image: jaegertracing/all-in-one:latest\n", " platform: linux/amd64\n", " restart: always\n", " ports:\n", " - \"16686:16686\"\n", " - \"14268\"\n", " - \"14250\"\n", "\n", " # Collector\n", " otel-collector:\n", " image: otel/opentelemetry-collector:0.67.0\n", " container_name: otel-collector\n", " platform: linux/amd64\n", " restart: always\n", " command: [\"--config=/etc/otel-collector-config.yaml\"]\n", " volumes:\n", " - ./otel-collector-config.yaml:/etc/otel-collector-config.yaml\n", " - ./logs:/var/log/app # Log directory for Promtail\n", " ports:\n", " - \"1888:1888\" # pprof extension\n", " - \"8888:8888\" # Prometheus metrics exposed by the collector\n", " - \"8889:8889\" # Prometheus exporter metrics\n", " - \"13133:13133\" # health_check extension\n", " - \"4317:4317\" # OTLP gRPC receiver\n", " - \"4318:4318\" # OTLP HTTP receiver\n", " - \"55679:55679\" # zpages extension\n", " depends_on:\n", " - jaeger\n", " # - loki\n", " # - promtail\n", " # - zipkin\n", "\n", " prometheus:\n", " container_name: prometheus\n", " image: prom/prometheus:latest\n", " platform: linux/amd64\n", " restart: always\n", " volumes:\n", " - ./prometheus.yaml:/etc/prometheus/prometheus.yml\n", " ports:\n", " - \"9090:9090\"\n", " depends_on:\n", " - otel-collector\n", " ```" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### otel-collector-config.yaml" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "```yaml\n", "receivers:\n", " otlp:\n", " protocols:\n", " grpc:\n", " http:\n", "\n", "exporters:\n", " prometheus:\n", " endpoint: \"0.0.0.0:8889\"\n", " const_labels:\n", " label1: value1\n", "\n", " logging:\n", "\n", " # zipkin:\n", " # endpoint: \"http://zipkin-all-in-one:9411/api/v2/spans\"\n", " # format: proto\n", "\n", " jaeger:\n", " endpoint: jaeger:14250\n", " tls:\n", " insecure: true\n", "\n", " file:\n", " path: \"/var/log/app/otel-logs.json\"\n", "\n", "\n", "\n", "processors:\n", " batch:\n", "\n", "extensions:\n", " health_check:\n", " pprof:\n", " endpoint: :1888\n", " zpages:\n", " endpoint: :55679\n", "\n", "service:\n", " extensions: [pprof, zpages, health_check]\n", " pipelines:\n", " traces:\n", " receivers: [otlp]\n", " processors: [batch]\n", " exporters: [logging, jaeger]\n", " metrics:\n", " receivers: [otlp]\n", " processors: [batch]\n", " exporters: [logging, prometheus]\n", " logs:\n", " receivers: [otlp]\n", " processors: [batch]\n", " exporters: [logging, file]\n", "```" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### prometheus.yaml" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "```yaml\n", "scrape_configs:\n", " - job_name: 'otel-collector'\n", " scrape_interval: 10s\n", " static_configs:\n", " - targets: ['otel-collector:8889']\n", " - targets: ['otel-collector:8888']\n", "```" ] } ], "metadata": { "kernelspec": { "display_name": "u2_p310", "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.10.11" } }, "nbformat": 4, "nbformat_minor": 2 }