From 45d9974926d7b9f340be33b59e2319ebec07d010 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=82=E3=81=A7?= Date: Thu, 26 Oct 2023 17:29:36 +0200 Subject: [PATCH] Update examples, add docker compose / tilt setup --- .codesandbox/docker-compose.yml | 2 + Tiltfile | 10 +- configs/compose/examples.yaml | 44 ++ configs/compose/infra.yaml | 48 ++ configs/docker/base.Dockerfile | 17 + configs/grafana/config.ini | 4 + .../Autometrics Function Explorer.json | 392 ++++++++++ .../dashboards/Autometrics Overview.json | 356 +++++++++ ...trics Service Level Objectives (SLOs).json | 712 ++++++++++++++++++ .../provisioning/dashboards/dashboards.yml | 24 + .../provisioning/datasources/datasource.yml | 12 + docker-compose.yaml | 38 +- examples/caller-example.py | 8 +- .../django_example/django_example/settings.py | 9 + examples/django_example/run_example.sh | 13 +- examples/docs-example.py | 4 +- examples/example.py | 8 +- examples/export_metrics/otlp-http.py | 26 + examples/fastapi-example.py | 7 +- examples/fastapi-with-fly-io/README.md | 8 +- examples/fastapi-with-fly-io/app.py | 10 +- examples/starlette-otel-exemplars.py | 4 +- 22 files changed, 1691 insertions(+), 65 deletions(-) create mode 100644 .codesandbox/docker-compose.yml create mode 100644 configs/compose/examples.yaml create mode 100644 configs/compose/infra.yaml create mode 100644 configs/docker/base.Dockerfile create mode 100644 configs/grafana/config.ini create mode 100644 configs/grafana/dashboards/Autometrics Function Explorer.json create mode 100644 configs/grafana/dashboards/Autometrics Overview.json create mode 100644 configs/grafana/dashboards/Autometrics Service Level Objectives (SLOs).json create mode 100644 configs/grafana/provisioning/dashboards/dashboards.yml create mode 100644 configs/grafana/provisioning/datasources/datasource.yml create mode 100644 examples/export_metrics/otlp-http.py diff --git a/.codesandbox/docker-compose.yml b/.codesandbox/docker-compose.yml new file mode 100644 index 0000000..bbf2861 --- /dev/null +++ b/.codesandbox/docker-compose.yml @@ -0,0 +1,2 @@ +include: + - ../docker-compose.yaml diff --git a/Tiltfile b/Tiltfile index 70e0b30..a3b93a7 100644 --- a/Tiltfile +++ b/Tiltfile @@ -1 +1,9 @@ -docker_compose('docker-compose.yaml') +docker_compose(['configs/compose/infra.yaml', 'configs/compose/examples.yaml']) + +dc_resource('am', labels=["infra"]) +dc_resource('grafana', labels=["infra"]) +dc_resource('otel-collector', labels=["infra"]) +dc_resource('push-gateway', labels=["infra"]) +dc_resource('django', labels=["examples"]) +dc_resource('fastapi', labels=["examples"]) +dc_resource('starlette', labels=["examples"]) \ No newline at end of file diff --git a/configs/compose/examples.yaml b/configs/compose/examples.yaml new file mode 100644 index 0000000..d0b047d --- /dev/null +++ b/configs/compose/examples.yaml @@ -0,0 +1,44 @@ +version: "3.8" + +services: + django: + container_name: django + build: + context: ../.. + dockerfile: configs/docker/base.Dockerfile + args: + PORT: 9464 + COPY_PATH: examples/django_example + COMMAND: ./run_example.sh + ports: + - "9464:9464" + fastapi: + container_name: fastapi + build: + context: ../.. + dockerfile: configs/docker/base.Dockerfile + args: + PORT: 8080 + COPY_PATH: examples/fastapi-example.py + COMMAND: poetry run python3 fastapi-example.py + ports: + - "9465:8080" + starlette: + container_name: starlette + build: + context: ../.. + dockerfile: configs/docker/base.Dockerfile + args: + PORT: 8080 + COPY_PATH: examples/starlette-otel-exemplars.py + COMMAND: poetry run python3 starlette-otel-exemplars.py + ports: + - "9466:8080" + otlp: + container_name: otlp + build: + context: ../.. + dockerfile: configs/docker/base.Dockerfile + args: + COPY_PATH: examples/export_metrics/otlp-http.py + COMMAND: poetry run python3 otlp-http.py diff --git a/configs/compose/infra.yaml b/configs/compose/infra.yaml new file mode 100644 index 0000000..abbdc63 --- /dev/null +++ b/configs/compose/infra.yaml @@ -0,0 +1,48 @@ +version: "3.8" + +volumes: + app-logs: {} + grafana-storage: {} + +services: + am: + container_name: am + image: autometrics/am:latest + extra_hosts: + - host.docker.internal:host-gateway + ports: + - "6789:6789" + - "9090:9090" + command: "start http://otel-collector:9464/metrics host.docker.internal:9464 host.docker.internal:9465 host.docker.internal:9466" + environment: + - LISTEN_ADDRESS=0.0.0.0:6789 + restart: unless-stopped + volumes: + - app-logs:/var/log + otel-collector: + container_name: otel-collector + image: otel/opentelemetry-collector-contrib:latest + command: ["--config=/etc/otel-collector-config.yaml"] + volumes: + - ../otel-collector-config.yaml:/etc/otel-collector-config.yaml + ports: + - "4317:4317" + - "4318:4318" + - "8888:8888" # expose container metrics in prometheus format + - "55680:55680" + - "55679:55679" + restart: unless-stopped + push-gateway: + container_name: push-gateway + image: ghcr.io/zapier/prom-aggregation-gateway:latest + grafana: + container_name: grafana + image: grafana/grafana-oss + restart: unless-stopped + ports: + - "3000:3000" + volumes: + - grafana-storage:/var/lib/grafana + - ../grafana/config.ini:/etc/grafana/grafana.ini + - ../grafana/dashboards:/var/lib/grafana/dashboards + - ../grafana/provisioning:/etc/grafana/provisioning diff --git a/configs/docker/base.Dockerfile b/configs/docker/base.Dockerfile new file mode 100644 index 0000000..ff4dab6 --- /dev/null +++ b/configs/docker/base.Dockerfile @@ -0,0 +1,17 @@ + +FROM python:latest +ARG COPY_PATH +ARG COMMAND +ARG PORT +WORKDIR /app +RUN apt-get update +RUN pip install poetry +COPY pyproject.toml poetry.lock src ./ +RUN poetry config virtualenvs.create false +RUN poetry install --no-interaction --no-root --with examples --extras "exporter-otlp-proto-http" +COPY $COPY_PATH ./ +ENV OTEL_EXPORTER_OTLP_ENDPOINT http://host.docker.internal:4318 +ENV COMMAND $COMMAND +ENV PORT $PORT +EXPOSE $PORT +CMD ["sh", "-c", "$COMMAND"] \ No newline at end of file diff --git a/configs/grafana/config.ini b/configs/grafana/config.ini new file mode 100644 index 0000000..38e6cbc --- /dev/null +++ b/configs/grafana/config.ini @@ -0,0 +1,4 @@ +[auth.anonymous] +disable_login_form = true +enabled = true +org_role = Admin \ No newline at end of file diff --git a/configs/grafana/dashboards/Autometrics Function Explorer.json b/configs/grafana/dashboards/Autometrics Function Explorer.json new file mode 100644 index 0000000..d6cd30a --- /dev/null +++ b/configs/grafana/dashboards/Autometrics Function Explorer.json @@ -0,0 +1,392 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": { + "type": "datasource", + "uid": "grafana" + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "target": { + "limit": 100, + "matchAny": false, + "tags": [], + "type": "dashboard" + }, + "type": "dashboard" + } + ] + }, + "description": "", + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 0, + "id": 19, + "links": [], + "liveNow": false, + "panels": [ + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "Calls per Second", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 4, + "options": { + "legend": { + "calcs": [ + "lastNotNull", + "max" + ], + "displayMode": "table", + "placement": "right", + "showLegend": true, + "sortBy": "Max", + "sortDesc": true + }, + "tooltip": { + "mode": "multi", + "sort": "desc" + } + }, + "pluginVersion": "9.4.1", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "editorMode": "code", + "expr": "sum by (function, module, service_name, version, commit) (\n rate(\n {\n __name__=~\"function_calls(_count)?(_total)?\",\n function=~\"${function}\"\n }[$__rate_interval]\n )\n * on(instance, job) group_left(version, commit) (last_over_time(build_info[$__rate_interval]) or on (instance, job) up)\n)", + "format": "time_series", + "instant": false, + "interval": "", + "legendFormat": "", + "refId": "A" + } + ], + "title": "Request Rate", + "transformations": [], + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic", + "seriesBy": "max" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "% of Function Calls That Errored", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "percentunit" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 24, + "x": 0, + "y": 8 + }, + "id": 2, + "options": { + "legend": { + "calcs": [ + "lastNotNull", + "max" + ], + "displayMode": "table", + "placement": "right", + "showLegend": true, + "sortBy": "Max", + "sortDesc": true + }, + "tooltip": { + "mode": "multi", + "sort": "desc" + } + }, + "pluginVersion": "9.4.1", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "editorMode": "code", + "expr": "(\n sum by(function, module, service_name, version, commit) (\n rate(\n {\n __name__=~\"function_calls(_count)?(_total)?\",\n result=\"error\", \n function=~\"${function}\"\n }[$__rate_interval]\n )\n * on(instance, job) group_left(version, commit) (last_over_time(build_info[$__rate_interval]) or on (instance, job) up)\n )) / (\n sum by(function, module, service_name, version, commit) (\n rate(\n {\n __name__=~\"function_calls(_count)?(_total)?\",\n function=~\"${function}\"\n }[$__rate_interval]\n )\n * on(instance, job) group_left(version, commit) (last_over_time(build_info[$__rate_interval]) or on (instance, job) up)\n ))", + "interval": "", + "legendFormat": "", + "range": true, + "refId": "A" + } + ], + "title": "Error Ratio", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "description": "This shows the 99th and 95th percentile latency or response time for the given function.\n\nFor example, if the 99th percentile latency is 500 milliseconds, that means that 99% of calls to the function are handled within 500ms or less.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic", + "seriesBy": "max" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "Function Call Duration", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "s" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 24, + "x": 0, + "y": 16 + }, + "id": 5, + "options": { + "legend": { + "calcs": [ + "lastNotNull", + "max" + ], + "displayMode": "table", + "placement": "right", + "showLegend": true, + "sortBy": "Max", + "sortDesc": true + }, + "tooltip": { + "mode": "multi", + "sort": "desc" + } + }, + "pluginVersion": "9.4.1", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "editorMode": "code", + "expr": "label_replace(\n histogram_quantile(0.99, \n sum by (le, function, module, service_name, commit, version) (\n rate({__name__=~\"function_calls_duration(_seconds)?_bucket\", function=~\"$function\"}[$__rate_interval])\n # Attach the `version` and `commit` labels from the `build_info` metric \n * on(instance, job) group_left(version, commit) (last_over_time(build_info[$__rate_interval]) or on (instance, job) up)\n )\n ),\n # Add the label {percentile_latency=\"99\"} to the time series\n \"percentile_latency\", \"99\", \"\", \"\"\n)\nor\nlabel_replace(\n histogram_quantile(0.95, \n sum by (le, function, module, service_name, commit, version) (\n rate({__name__=~\"function_calls_duration(_seconds)?_bucket\", function=~\"$function\"}[$__rate_interval])\n # Attach the `version` and `commit` labels from the `build_info` metric \n * on(instance, job) group_left(version, commit) (last_over_time(build_info[$__rate_interval]) or on (instance, job) up)\n )\n ),\n # Add the label {percentile_latency=\"95\"} to the time series\n \"percentile_latency\", \"95\", \"\", \"\"\n)", + "interval": "", + "legendFormat": "", + "range": true, + "refId": "A" + } + ], + "title": "Latency (95th and 99th Percentile)", + "type": "timeseries" + } + ], + "refresh": "5m", + "revision": 1, + "schemaVersion": 38, + "style": "dark", + "tags": [ + "autometrics" + ], + "templating": { + "list": [ + { + "allValue": "__none__", + "current": {}, + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "definition": "label_values({__name__=~\"function_calls(_count)?(_total)?\"}, function)", + "hide": 0, + "includeAll": false, + "label": "Show Function(s)", + "multi": true, + "name": "function", + "options": [], + "query": { + "query": "label_values({__name__=~\"function_calls(_count)?(_total)?\"}, function)", + "refId": "StandardVariableQuery" + }, + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 1, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + } + ] + }, + "time": { + "from": "now-6h", + "to": "now" + }, + "timepicker": {}, + "timezone": "", + "title": "Autometrics Function Explorer", + "uid": "autometrics-function-explorer", + "version": 1, + "weekStart": "" + } \ No newline at end of file diff --git a/configs/grafana/dashboards/Autometrics Overview.json b/configs/grafana/dashboards/Autometrics Overview.json new file mode 100644 index 0000000..09dca94 --- /dev/null +++ b/configs/grafana/dashboards/Autometrics Overview.json @@ -0,0 +1,356 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": { + "type": "datasource", + "uid": "grafana" + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "target": { + "limit": 100, + "matchAny": false, + "tags": [], + "type": "dashboard" + }, + "type": "dashboard" + } + ] + }, + "description": "", + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 0, + "id": 20, + "links": [], + "liveNow": false, + "panels": [ + { + "collapsed": false, + "datasource": { + "type": "prometheus", + "uid": "Sc9Taxa4z" + }, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 8, + "panels": [], + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "Sc9Taxa4z" + }, + "refId": "A" + } + ], + "title": "Autometrics-Instrumented Functions", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "description": "Calls per second is calculated as the average over a 5-minute window", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "Calls per Second", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 24, + "x": 0, + "y": 1 + }, + "id": 4, + "options": { + "legend": { + "calcs": [ + "lastNotNull", + "max" + ], + "displayMode": "table", + "placement": "right", + "showLegend": true, + "sortBy": "Max", + "sortDesc": true + }, + "tooltip": { + "mode": "multi", + "sort": "desc" + } + }, + "pluginVersion": "9.4.1", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "editorMode": "code", + "expr": "sum by (function, module, service_name, version, commit) (\n rate(\n {\n __name__=~\"function_calls(_count)?(_total)?\", \n function=~\"${functions_top_request_rate}\"\n }[5m]\n )\n * on(instance, job) group_left(version, commit) (last_over_time(build_info[$__rate_interval]) or on (instance, job) up)\n)", + "format": "time_series", + "instant": false, + "interval": "", + "legendFormat": "", + "refId": "A" + } + ], + "title": "Request Rate (Top $num_function_limit)", + "transformations": [], + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic", + "seriesBy": "max" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "Error Rate", + "axisPlacement": "auto", + "axisSoftMax": 1, + "axisSoftMin": 0, + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "percentunit" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 24, + "x": 0, + "y": 9 + }, + "id": 2, + "options": { + "legend": { + "calcs": [ + "lastNotNull", + "max" + ], + "displayMode": "table", + "placement": "right", + "showLegend": true, + "sortBy": "Max", + "sortDesc": true + }, + "tooltip": { + "mode": "multi", + "sort": "desc" + } + }, + "pluginVersion": "9.4.1", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "editorMode": "code", + "expr": "(\n sum by(function, module, service_name, version, commit) (\n rate(\n {\n __name__=~\"function_calls(_count)?(_total)?\", \n result=\"error\", \n function=~\"${functions_top_error_rate}\"\n }[5m]\n )\n * on(instance, job) group_left(version, commit) (last_over_time(build_info[$__rate_interval]) or on (instance, job) up)\n )) / (\n sum by(function, module, service_name, version, commit) (\n rate(\n {\n __name__=~\"function_calls(_count)?(_total)?\", \n function=~\"${functions_top_error_rate}\"\n }[5m]\n )\n * on(instance, job) group_left(version, commit) (last_over_time(build_info[$__rate_interval]) or on (instance, job) up)\n ))", + "interval": "", + "legendFormat": "", + "range": true, + "refId": "A" + } + ], + "title": "Error Rate (Top $num_function_limit)", + "type": "timeseries" + } + ], + "refresh": "5m", + "revision": 1, + "schemaVersion": 38, + "style": "dark", + "tags": [ + "autometrics" + ], + "templating": { + "list": [ + { + "allValue": "", + "current": {}, + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "definition": "query_result(topk($num_function_limit, sum by (function, module, service_name) (rate({__name__=~\"function_calls(_count)?(_total)?\"}[$__range]))))\n", + "hide": 2, + "includeAll": true, + "multi": true, + "name": "functions_top_request_rate", + "options": [], + "query": { + "query": "query_result(topk($num_function_limit, sum by (function, module, service_name) (rate({__name__=~\"function_calls(_count)?(_total)?\"}[$__range]))))\n", + "refId": "StandardVariableQuery" + }, + "refresh": 2, + "regex": "/function=\"(\\w+)\"/", + "skipUrlSync": false, + "sort": 4, + "type": "query" + }, + { + "current": { + "selected": false, + "text": "10", + "value": "10" + }, + "hide": 0, + "label": "Top Functions to Display", + "name": "num_function_limit", + "options": [ + { + "selected": true, + "text": "10", + "value": "10" + } + ], + "query": "10", + "skipUrlSync": false, + "type": "textbox" + }, + { + "allValue": "", + "current": {}, + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "definition": "query_result(topk($num_function_limit, sum by (function, module, service_name) (rate({__name__=~\"function_calls(_count)?(_total)?\", result=\"error\"}[$__range])) / (sum by (function, module, service_name) (rate({__name__=~\"function_calls(_count)?(_total)?\"}[$__range])))))\n", + "hide": 2, + "includeAll": true, + "multi": true, + "name": "functions_top_error_rate", + "options": [], + "query": { + "query": "query_result(topk($num_function_limit, sum by (function, module, service_name) (rate({__name__=~\"function_calls(_count)?(_total)?\", result=\"error\"}[$__range])) / (sum by (function, module, service_name) (rate({__name__=~\"function_calls(_count)?(_total)?\"}[$__range])))))\n", + "refId": "StandardVariableQuery" + }, + "refresh": 2, + "regex": "/function=\"(\\w+)\"/", + "skipUrlSync": false, + "sort": 4, + "type": "query" + } + ] + }, + "time": { + "from": "now-6h", + "to": "now" + }, + "timepicker": {}, + "timezone": "", + "title": "Autometrics Overview", + "uid": "autometrics-overview", + "version": 1, + "weekStart": "" + } \ No newline at end of file diff --git a/configs/grafana/dashboards/Autometrics Service Level Objectives (SLOs).json b/configs/grafana/dashboards/Autometrics Service Level Objectives (SLOs).json new file mode 100644 index 0000000..34c95ec --- /dev/null +++ b/configs/grafana/dashboards/Autometrics Service Level Objectives (SLOs).json @@ -0,0 +1,712 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": { + "type": "datasource", + "uid": "grafana" + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "target": { + "limit": 100, + "matchAny": false, + "tags": [], + "type": "dashboard" + }, + "type": "dashboard" + } + ] + }, + "description": "", + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 0, + "id": 21, + "links": [], + "liveNow": false, + "panels": [ + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 10, + "panels": [], + "repeat": "success_rate_objective", + "repeatDirection": "h", + "title": "`$success_rate_objective` Success Rate Objective (Target: $success_rate_objective_percentile%)", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "max": 1, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "red", + "value": null + }, + { + "color": "semi-dark-orange", + "value": 0.9 + }, + { + "color": "semi-dark-yellow", + "value": 0.95 + }, + { + "color": "semi-dark-green", + "value": 0.99 + } + ] + }, + "unit": "percentunit" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 7, + "x": 0, + "y": 1 + }, + "id": 12, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "/^Value$/", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "10.1.5", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "editorMode": "code", + "exemplar": false, + "expr": "1 - (\n sum(\n rate(\n {\n __name__=~\"function_calls(_count)?(_total)?\", \n objective_name=\"$success_rate_objective\", \n result=\"error\"\n }[$__range])\n ) or on() vector(0)\n ) / (\n sum(\n rate(\n {\n __name__=~\"function_calls(_count)?(_total)?\", \n objective_name=\"$success_rate_objective\"\n }[$__range]\n )\n ) )", + "format": "table", + "hide": false, + "instant": true, + "legendFormat": "__auto", + "range": false, + "refId": "A" + } + ], + "title": "Success Rate", + "transformations": [], + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "red", + "value": null + }, + { + "color": "semi-dark-yellow", + "value": 0.9 + }, + { + "color": "semi-dark-orange", + "value": 0.95 + }, + { + "color": "semi-dark-green", + "value": 0.99 + } + ] + }, + "unit": "percentunit" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 7, + "x": 7, + "y": 1 + }, + "id": 16, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "/^Value$/", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "10.1.5", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "editorMode": "code", + "exemplar": false, + "expr": "1 - (\n sum(\n rate(\n {\n __name__=~\"function_calls(_count)?(_total)?\", \n objective_name=\"$success_rate_objective\", \n result=\"error\"\n }[$__range]\n )\n ) or on() vector(0)\n) / (\n sum(\n rate(\n {\n __name__=~\"function_calls(_count)?(_total)?\", \n objective_name=\"$success_rate_objective\"\n }[$__range]\n )\n ))", + "format": "table", + "instant": true, + "legendFormat": "__auto", + "range": false, + "refId": "A" + } + ], + "timeFrom": "30d", + "title": "30-day Success Rate", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "continuous-GrYlRd", + "seriesBy": "max" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "noValue": "0", + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "percentunit" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 10, + "x": 14, + "y": 1 + }, + "id": 15, + "options": { + "legend": { + "calcs": [ + "min", + "max" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true, + "sortBy": "Max", + "sortDesc": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "editorMode": "code", + "expr": "(\n sum by (function, module, service_name, version, commit) (\n rate(\n {\n __name__=~\"function_calls(_count)?(_total)?\", \n objective_name=\"$success_rate_objective\", \n result=\"error\"\n }[$__rate_interval]\n )\n * on(instance, job) group_left(version, commit) (last_over_time(build_info[$__rate_interval]) or on (instance, job) up)\n ) >= 0\n) / (\n sum by (function, module, service_name, version, commit) (\n rate(\n {\n __name__=~\"function_calls(_count)?(_total)?\", \n objective_name=\"$success_rate_objective\"\n }[$__rate_interval]\n )\n * on(instance, job) group_left(version, commit) (last_over_time(build_info[$__rate_interval]) or on (instance, job) up)\n ))", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Error Rate by Function", + "type": "timeseries" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 9 + }, + "id": 18, + "panels": [], + "repeat": "latency_objective", + "repeatDirection": "h", + "title": "`$latency_objective` Latency Objective (Target: $latency_objective_percentile% ≤ $latency_objective_latency_threshold sec)", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "max": 1, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "red", + "value": null + }, + { + "color": "semi-dark-yellow", + "value": 0.9 + }, + { + "color": "semi-dark-orange", + "value": 0.95 + }, + { + "color": "semi-dark-green", + "value": 0.99 + } + ] + }, + "unit": "percentunit" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 7, + "x": 0, + "y": 10 + }, + "id": 20, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "10.1.5", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "editorMode": "code", + "exemplar": false, + "expr": "(\n sum(\n rate(\n {__name__=~\"function_calls_duration(_seconds)?_bucket\", \n objective_name=\"$latency_objective\", \n le=\"$latency_objective_latency_threshold\"\n }[$__range]\n )\n ) or on() vector(0)\n) / (\n sum(\n rate(\n {__name__=~\"function_calls_duration(_seconds)?_count\", \n objective_name=\"$latency_objective\"\n }[$__range]\n )\n ))", + "format": "table", + "instant": true, + "legendFormat": "__auto", + "range": false, + "refId": "A" + } + ], + "title": "% of requests under ${latency_objective_latency_threshold}s", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "max": 1, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "red", + "value": null + }, + { + "color": "semi-dark-yellow", + "value": 0.9 + }, + { + "color": "semi-dark-orange", + "value": 0.95 + }, + { + "color": "semi-dark-green", + "value": 0.99 + } + ] + }, + "unit": "percentunit" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 7, + "x": 7, + "y": 10 + }, + "id": 23, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "10.1.5", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "editorMode": "code", + "exemplar": false, + "expr": "(\n sum(\n rate(\n {__name__=~\"function_calls_duration(_seconds)?_bucket\", \n objective_name=\"$latency_objective\", \n le=\"$latency_objective_latency_threshold\"\n }[$__range]\n )\n ) or on() vector(0)\n) / (\n sum(\n rate(\n {__name__=~\"function_calls_duration(_seconds)?_count\", \n objective_name=\"$latency_objective\"\n }[$__range]\n )\n ))", + "format": "table", + "instant": true, + "legendFormat": "__auto", + "range": false, + "refId": "A" + } + ], + "timeFrom": "30d", + "title": "30-day % of requests under ${latency_objective_latency_threshold}s", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "continuous-GrYlRd", + "seriesBy": "max" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "axisSoftMax": 1, + "axisSoftMin": 0, + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "noValue": "0", + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "percentunit" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 10, + "x": 14, + "y": 10 + }, + "id": 22, + "options": { + "legend": { + "calcs": [ + "max" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true, + "sortBy": "Max", + "sortDesc": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "editorMode": "code", + "expr": "(\n 1 - (\n sum by (function, module, service_name, version, commit) (\n rate(\n {__name__=~\"function_calls_duration(_seconds)?_bucket\", \n objective_name=\"$latency_objective\", \n le=\"$latency_objective_latency_threshold\"\n }[$__rate_interval]\n )\n * on(instance, job) group_left(version, commit) (last_over_time(build_info[$__rate_interval]) or on (instance, job) up)\n ) / (\n sum by (function, module, service_name, version, commit) (\n rate(\n {__name__=~\"function_calls_duration(_seconds)?_count\", \n objective_name=\"$latency_objective\"\n }[$__rate_interval]\n )\n * on(instance, job) group_left(version, commit) (last_over_time(build_info[$__rate_interval]) or on (instance, job) up)\n ) )\n )\n)", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "% of requests exceeding ${latency_objective_latency_threshold}s", + "type": "timeseries" + } + ], + "refresh": "5m", + "revision": 1, + "schemaVersion": 38, + "style": "dark", + "tags": [ + "autometrics" + ], + "templating": { + "list": [ + { + "current": {}, + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "definition": "label_values({__name__=~\"function_calls(_count)?(_total)?\"}, objective_name)", + "hide": 2, + "includeAll": false, + "label": "", + "multi": false, + "name": "success_rate_objective", + "options": [], + "query": { + "query": "label_values({__name__=~\"function_calls(_count)?(_total)?\"}, objective_name)", + "refId": "StandardVariableQuery" + }, + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "type": "query" + }, + { + "current": {}, + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "definition": "label_values(function_calls_duration_count, objective_name)", + "hide": 2, + "includeAll": false, + "multi": false, + "name": "latency_objective", + "options": [], + "query": { + "query": "label_values(function_calls_duration_count, objective_name)", + "refId": "StandardVariableQuery" + }, + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "type": "query" + }, + { + "current": {}, + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "definition": "label_values({__name__=~\"function_calls(_count)?(_total)?\", objective_name=\"$success_rate_objective\"}, objective_percentile)", + "hide": 2, + "includeAll": false, + "multi": false, + "name": "success_rate_objective_percentile", + "options": [], + "query": { + "query": "label_values({__name__=~\"function_calls(_count)?(_total)?\", objective_name=\"$success_rate_objective\"}, objective_percentile)", + "refId": "StandardVariableQuery" + }, + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "type": "query" + }, + { + "current": {}, + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "definition": "label_values({__name__=~\"function_calls_duration(_seconds)?_bucket\", objective_name=\"$latency_objective\"}, objective_percentile)", + "hide": 2, + "includeAll": false, + "multi": false, + "name": "latency_objective_percentile", + "options": [], + "query": { + "query": "label_values({__name__=~\"function_calls_duration(_seconds)?_bucket\", objective_name=\"$latency_objective\"}, objective_percentile)", + "refId": "StandardVariableQuery" + }, + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "type": "query" + }, + { + "current": { + "selected": false, + "text": "0.25", + "value": "0.25" + }, + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "definition": "label_values({__name__=~\"function_calls_duration(_seconds)?_bucket\", objective_name=\"$latency_objective\"}, objective_latency_threshold)", + "hide": 2, + "includeAll": false, + "multi": false, + "name": "latency_objective_latency_threshold", + "options": [], + "query": { + "query": "label_values({__name__=~\"function_calls_duration(_seconds)?_bucket\", objective_name=\"$latency_objective\"}, objective_latency_threshold)", + "refId": "StandardVariableQuery" + }, + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "type": "query" + } + ] + }, + "time": { + "from": "now-6h", + "to": "now" + }, + "timepicker": {}, + "timezone": "", + "title": "Autometrics Service-Level Objectives (SLOs)", + "uid": "autometrics-objectives", + "version": 1, + "weekStart": "" + } \ No newline at end of file diff --git a/configs/grafana/provisioning/dashboards/dashboards.yml b/configs/grafana/provisioning/dashboards/dashboards.yml new file mode 100644 index 0000000..8c87469 --- /dev/null +++ b/configs/grafana/provisioning/dashboards/dashboards.yml @@ -0,0 +1,24 @@ +apiVersion: 1 + +providers: + # an unique provider name. Required + - name: ${DS_PROMETHEUS} + # Org id. Default to 1 + orgId: 1 + # name of the dashboard folder. + folder: 'Autometrics' + # folder UID. will be automatically generated if not specified + folderUid: '' + # provider type. Default to 'file' + type: file + # disable dashboard deletion + disableDeletion: false + # how often Grafana will scan for changed dashboards + updateIntervalSeconds: 10 + # allow updating provisioned dashboards from the UI + allowUiUpdates: false + options: + # path to dashboard files on disk. Required when using the 'file' type + path: /var/lib/grafana/dashboards + # use folder names from filesystem to create folders in Grafana + foldersFromFilesStructure: true \ No newline at end of file diff --git a/configs/grafana/provisioning/datasources/datasource.yml b/configs/grafana/provisioning/datasources/datasource.yml new file mode 100644 index 0000000..96709f2 --- /dev/null +++ b/configs/grafana/provisioning/datasources/datasource.yml @@ -0,0 +1,12 @@ +apiVersion: 1 + +datasources: + - name: Prometheus + type: prometheus + access: proxy + orgId: 1 + # Use the name and container port from docker compose + url: http://am:9090/prometheus + basicAuth: false + isDefault: true + editable: true diff --git a/docker-compose.yaml b/docker-compose.yaml index dcc7482..759ad20 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -1,35 +1,3 @@ -version: "3.9" - -volumes: - app-logs: - -services: - am: - image: autometrics/am:latest - extra_hosts: - - host.docker.internal:host-gateway - ports: - - "6789:6789" - - "9090:9090" - container_name: am - command: "start http://otel-collector:9464/metrics host.docker.internal:9464" - environment: - - LISTEN_ADDRESS=0.0.0.0:6789 - restart: unless-stopped - volumes: - - app-logs:/var/log - otel-collector: - image: otel/opentelemetry-collector-contrib:latest - container_name: otel-collector - command: ["--config=/etc/otel-collector-config.yaml"] - volumes: - - ./configs/otel-collector-config.yaml:/etc/otel-collector-config.yaml - ports: - - "4317:4317" - - "4318:4318" - - "8888:8888" # expose container metrics in prometheus format - - "55680:55680" - - "55679:55679" - restart: unless-stopped - push-gateway: - image: ghcr.io/zapier/prom-aggregation-gateway:latest +include: + - configs/compose/infra.yaml + - configs/compose/examples.yaml \ No newline at end of file diff --git a/examples/caller-example.py b/examples/caller-example.py index b782267..2d93143 100644 --- a/examples/caller-example.py +++ b/examples/caller-example.py @@ -1,5 +1,4 @@ -from prometheus_client import start_http_server -from autometrics import autometrics +from autometrics import autometrics, init import time import random @@ -34,8 +33,9 @@ def destiny(): return f"Destiny is calling simba. simba says: {simba()}" -# Start an HTTP server on port 8080 using the Prometheus client library, which exposes our metrics to prometheus -start_http_server(8080) +# Initialize autometrics and start an HTTP server on port 8080 using +# the Prometheus client library, which exposes our metrics to prometheus +init(exporter={"type": "prometheus", "port": 8080}) print(f"Try this PromQL query in your Prometheus dashboard:\n") print( diff --git a/examples/django_example/django_example/settings.py b/examples/django_example/django_example/settings.py index 6431504..cdad66f 100644 --- a/examples/django_example/django_example/settings.py +++ b/examples/django_example/django_example/settings.py @@ -11,6 +11,15 @@ """ from pathlib import Path +from autometrics import init + +init( + branch="main", + commit="67a1b3a", + version="0.1.0", + tracker="prometheus", + service_name="django-example", +) # Build paths inside the project like this: BASE_DIR / 'subdir'. BASE_DIR = Path(__file__).resolve().parent.parent diff --git a/examples/django_example/run_example.sh b/examples/django_example/run_example.sh index 4f5fd10..89c268a 100755 --- a/examples/django_example/run_example.sh +++ b/examples/django_example/run_example.sh @@ -1,15 +1,10 @@ #!/bin/sh -export AUTOMETRICS_COMMIT=67a1b3a -export AUTOMETRICS_VERSION=0.1.0 -export AUTOMETRICS_BRANCH=main -export AUTOMETRICS_TRACKER=prometheus - # run the server itself -poetry run python manage.py runserver 8080 & -# run the locust load test and pipe stdout to dev/null -poetry run locust --host=http://localhost:8080 --users=100 --headless & +poetry run python manage.py runserver 0.0.0.0:9464 & +# run the locust load test +poetry run locust --host=http://localhost:9464 --users=100 --headless --skip-log-setup & # kill all child processes on exit -trap "trap - SIGTERM && kill -- -$$" SIGINT SIGTERM EXIT +trap "trap - SIGTERM && kill -- -$$" INT TERM EXIT wait \ No newline at end of file diff --git a/examples/docs-example.py b/examples/docs-example.py index 3bd8f0a..3abd55f 100644 --- a/examples/docs-example.py +++ b/examples/docs-example.py @@ -1,4 +1,6 @@ -from autometrics import autometrics +from autometrics import autometrics, init + +init() @autometrics diff --git a/examples/example.py b/examples/example.py index bf74181..ab308ed 100644 --- a/examples/example.py +++ b/examples/example.py @@ -1,7 +1,6 @@ import time import random -from prometheus_client import start_http_server -from autometrics import autometrics +from autometrics import autometrics, init from autometrics.objectives import Objective, ObjectiveLatency, ObjectivePercentile @@ -63,8 +62,9 @@ def random_error(): # Show the docstring (with links to prometheus metrics) for the `div_unhandled` method print(div_unhandled.__doc__) -# Start an HTTP server on port 8080 using the Prometheus client library, which exposes our metrics to prometheus -start_http_server(8080) +# Initialize autometrics and start an HTTP server on port 8080 using +# the Prometheus client library, which exposes our metrics to prometheus +init(exporter={"type": "prometheus", "port": 8080}) # Enter an infinite loop (with a 2 second sleep period), calling the "div_handled", "add", and "div_unhandled" methods, # in order to generate metrics. diff --git a/examples/export_metrics/otlp-http.py b/examples/export_metrics/otlp-http.py new file mode 100644 index 0000000..f5ab00c --- /dev/null +++ b/examples/export_metrics/otlp-http.py @@ -0,0 +1,26 @@ +import time +from autometrics import autometrics, init + +# Autometrics supports exporting metrics to OTLP collectors via gRPC and HTTP transports. +# This example uses the HTTP transport, available settings are similar to the OpenTelemetry +# Python SDK. By default, the OTLP exporter will send metrics to localhost:4318. +# If you don't have an OTLP collector running, you can run Tilt or Docker Compose +# to start one up. + +init( + exporter={ + "type": "otlp-proto-http", + "push_interval": 1000, + }, + service_name="my-service", +) + + +@autometrics +def my_function(): + pass + + +while True: + my_function() + time.sleep(1) diff --git a/examples/fastapi-example.py b/examples/fastapi-example.py index bcb3f0c..7ad978c 100644 --- a/examples/fastapi-example.py +++ b/examples/fastapi-example.py @@ -1,7 +1,7 @@ import asyncio import uvicorn -from autometrics import autometrics +from autometrics import autometrics, init from fastapi import FastAPI, Response from fastapi.responses import JSONResponse from prometheus_client import generate_latest @@ -86,5 +86,8 @@ def get_pretty_flower(flower_name: str): return f"A {flower_name} is pretty" +init(service_name="fastapi-example") + + if __name__ == "__main__": - uvicorn.run(app, host="localhost", port=8080) + uvicorn.run(app, host="0.0.0.0", port=8080) diff --git a/examples/fastapi-with-fly-io/README.md b/examples/fastapi-with-fly-io/README.md index e03408b..81975c4 100644 --- a/examples/fastapi-with-fly-io/README.md +++ b/examples/fastapi-with-fly-io/README.md @@ -54,7 +54,7 @@ After this we're ready to add some code. Create a file named `app.py` in your fa ```python import time -from autometrics import autometrics +from autometrics import autometrics, init # Import below is needed for the service level objective (SLO) support from autometrics.objectives import Objective, ObjectiveLatency, ObjectivePercentile from fastapi import FastAPI, Response @@ -104,11 +104,13 @@ def do_something(): # This function doesn't do much print("done") -# In order for prometheus to get the data we'll set +# Before starting the server, we need to initialize the autometrics +# by calling init(). In order for prometheus to get the data +# we'll also pass the configuration that will set # up a separate endpoint that exposes data in a format # that prometheus can understand. # This metrics server will run on port 8008 -start_http_server(8008) +init(exporter={"type": "prometheus", "port": 8008}) # If the app is not run by fly.io in a container but using python # directly we enter this flow and it is run on port 8080 diff --git a/examples/fastapi-with-fly-io/app.py b/examples/fastapi-with-fly-io/app.py index 98ee333..9e39306 100644 --- a/examples/fastapi-with-fly-io/app.py +++ b/examples/fastapi-with-fly-io/app.py @@ -1,8 +1,7 @@ import time -from autometrics import autometrics +from autometrics import autometrics, init from autometrics.objectives import Objective, ObjectiveLatency, ObjectivePercentile from fastapi import FastAPI, Response -from prometheus_client import start_http_server import uvicorn app = FastAPI() @@ -50,11 +49,14 @@ def do_something(): print("done") -# In order for prometheus to get the data we'll set +# Before starting the server, we need to initialize the autometrics +# by calling init(). In order for prometheus to get the data +# we'll also pass the configuration that will set # up a separate endpoint that exposes data in a format # that prometheus can understand. # This metrics server will run on port 8008 -start_http_server(8008) +init(exporter={"type": "prometheus", "port": 8008}) + # If the app is not run by fly.io in a container but using python # directly we enter this flow and it is run on port 8080 diff --git a/examples/starlette-otel-exemplars.py b/examples/starlette-otel-exemplars.py index f06b11d..d32ae4e 100644 --- a/examples/starlette-otel-exemplars.py +++ b/examples/starlette-otel-exemplars.py @@ -24,7 +24,7 @@ # Exemplars support requires some additional configuration on autometrics, # so we need to initialize it with the proper settings -init(tracker="prometheus", enable_exemplars=True) +init(tracker="prometheus", enable_exemplars=True, service_name="starlette-example") # We need to add tracer decorator before autometrics so that we see the spans @@ -54,7 +54,7 @@ def metrics(request): ) if __name__ == "__main__": - uvicorn.run(app, port=8080) + uvicorn.run(app, host="0.0.0.0", port=8080) # Start the app and make some requests to http://127.0.0.1:8080/, you should see the spans in the console. # With autometrics extension installed, you can now hover over the hello handler