Skip to content

Commit 15fcb0c

Browse files
authored
Merge pull request #13 from brettimus/update-docs-20230405
Update documentation (README and examples)
2 parents 04f28c2 + 1627b11 commit 15fcb0c

File tree

7 files changed

+143
-29
lines changed

7 files changed

+143
-29
lines changed

README.md

+14-8
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,12 @@
22

33
A Python decorator that makes it easy to understand the error rate, response time, and production usage of any function in your code. Jump straight from your IDE to live Prometheus charts for each HTTP/RPC handler, database method, or other piece of application logic.
44

5-
Autometrics for Python provides a decorator that can create [Prometheus](https://prometheus.io/) metrics for your functions and class methods throughout your code base, as well as a function that will write corresponding Prometheus queries for you in a Markdown file.
5+
Autometrics for Python provides:
66

7-
[See Why Autometrics?](https://github.com/autometrics-dev#why-autometrics) for more details on the ideas behind autometrics
7+
1. A decorator that can create [Prometheus](https://prometheus.io/) metrics for your functions and class methods throughout your code base.
8+
2. A helper function that will write corresponding Prometheus queries for you in a Markdown file.
9+
10+
See [Why Autometrics?](https://github.com/autometrics-dev#why-autometrics) for more details on the ideas behind autometrics.
811

912
## Features
1013

@@ -21,23 +24,26 @@ Autometrics for Python provides a decorator that can create [Prometheus](https:/
2124

2225
## Using autometrics-py
2326

24-
- Requirement: a running [prometheus instance](https://prometheus.io/download/)
25-
- include a .env file with your prometheus endpoint `PROMETHEUS_URL = your endpoint`, if not defined the default endpoint will be `http://localhost:9090/`
27+
- Set up a [Prometheus instance](https://prometheus.io/download/)
28+
- Configure prometheus to scrape your application ([check our instructions if you need help](https://github.com/autometrics-dev#5-configuring-prometheus))
29+
- Include a .env file with your prometheus endpoint `PROMETHEUS_URL=your endpoint`. If this is not defined, the default endpoint will be `http://localhost:9090/`
2630
- `pip install autometrics`
2731
- Import the library in your code and use the decorator for any function:
2832

29-
```
30-
from autometrics import autometrics
33+
```py
34+
from autometrics.autometrics import autometrics
3135

3236
@autometrics
3337
def sayHello:
3438
return "hello"
3539

3640
```
3741

38-
- If you like to access the queries for your decoraded functions you can run `help(yourfunction)` or `print(yourfunction.__doc__)`
42+
- To access the PromQL queries for your decorated functions, run `help(yourfunction)` or `print(yourfunction.__doc__)`.
43+
44+
- To show tooltips over decorated functions in VSCode, with links to Prometheus queries, try installing [the VSCode extension](https://marketplace.visualstudio.com/items?itemName=Fiberplane.autometrics).
3945

40-
- Unfortunately it is not possible to have the queries in the tooltips due to the [static Analyzer](https://github.com/davidhalter/jedi/issues/1921). We are currently figuring out to build a VS Code PlugIn to make it work.
46+
> Note that we cannot support tooltips without a VSCode extension due to behavior of the [static analyzer](https://github.com/davidhalter/jedi/issues/1921) used in VSCode.
4147
4248
## Development of the package
4349

examples/README.md

+55
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
# autometrics-py examples
2+
3+
You should be able to run each example by executing `python examples/<example>.py` from the root of the repo.
4+
5+
You can change the base url for Prometheus links via the `PROMETHEUS_URL` environment variable. So, if your local Prometheus were on a non-default port, like 9091, you would run:
6+
7+
```sh
8+
PROMETHEUS_URL=http://localhost:9091/ python examples/example.py
9+
```
10+
11+
Read more below about each example, and what kind of features they demonstrate.
12+
13+
Also, for the examples that expose a `/metrics` endpoint, you will need to configure Prometheus to scrape that endpoint. There is an example `prometheus.yaml` file in the root of this project, but here is the relevant part:
14+
15+
```yaml
16+
# Example prometheus.yaml
17+
scrape_configs:
18+
- job_name: "python-autometrics-example"
19+
metrics_path: /metrics
20+
static_configs:
21+
- targets: ["localhost:8080"]
22+
# For a real deployment, you would want the scrape interval to be
23+
# longer but for testing, you want the data to show up quickly
24+
scrape_interval: 500ms
25+
```
26+
27+
## `docs-example.py`
28+
29+
This script shows how the autometrics decorator augments the docstring for a python function.
30+
31+
We simply decorate a function, then print its docstring to the console using the built-in `help` function.
32+
33+
## `example.py`
34+
35+
This script demonstrates the basic usage of the `autometrics` decorator. When you run `python examples/example.py`, it will output links to metrics in your configured prometheus instance.
36+
37+
You can read the script for comments on how it works, but the basic idea is that we have a division function (`div_unhandled`) that occasionally divides by zero and does not catch its errors. We can see its error rate in prometheus via the links in its doc string.
38+
39+
Note that the script starts an HTTP server on port 8080 using the Prometheus client library, which exposes metrics to prometheus (via a `/metrics` endpoint).
40+
41+
Then, it enters into an infinite loop (with a 2 second sleep period), calling methods repeatedly with different input parameters. This should start generating data that you can explore in Prometheus. Just follow the links that are printed to the console!
42+
43+
> Don't forget to configure Prometheus itself to scrape the metrics endpoint. Refer to the example `prometheus.yaml` file in the root of this project on how to set this up.
44+
45+
## `caller-example.py`
46+
47+
Autometrics also tracks a label, `caller`, which is the name of the function that called the decorated function. The `caller-example.py` script shows how to use that label. It uses the same structure as the `example.py` script, but it prints a PromQL query that you can use to explore the caller data yourself.
48+
49+
> Don't forget to configure Prometheus itself to scrape the metrics endpoint. Refer to the example `prometheus.yaml` file in the root of this project on how to set this up.
50+
51+
## `fastapi-example.py`
52+
53+
This is an example that shows you how to use autometrics to get metrics on http handlers with FastAPI. In this case, we're setting up the API ourselves, which means we need to expose a `/metrics` endpoint manually.
54+
55+
> Don't forget to configure Prometheus itself to scrape the metrics endpoint. Refer to the example `prometheus.yaml` file in the root of this project on how to set this up.

examples/caller-example.py

+43-8
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,54 @@
1-
print("hello")
21
from prometheus_client import start_http_server
2+
from autometrics.autometrics import autometrics
3+
import time
4+
import random
35

46

7+
# This is moana, who would rather explore the ocean than prometheus metrics
58
@autometrics
6-
def message():
7-
return "hello"
9+
def moana():
10+
return "surf's up!"
811

912

13+
# This is neo, the one (that we'll end up calling)
1014
@autometrics
11-
def greet(name):
12-
m = message()
13-
greeting = f"hello {name}, {m}"
14-
return greeting
15+
def neo():
16+
return "i know kung fu"
1517

1618

19+
# This is simba. Rawr.
20+
@autometrics
21+
def simba():
22+
return "rawr"
23+
24+
25+
# Define a function that randomly calls `moana`, `neo`, or `simba`
26+
@autometrics
27+
def destiny():
28+
random_int = random.randint(0, 2)
29+
if random_int == 0:
30+
return f"Destiny is calling moana. moana says: {moana()}"
31+
elif random_int == 1:
32+
return f"Destiny is calling neo. neo says: {neo()}"
33+
else:
34+
return f"Destiny is calling simba. simba says: {simba()}"
35+
36+
37+
# Start an HTTP server on port 8080 using the Prometheus client library, which exposes our metrics to prometheus
1738
start_http_server(8080)
39+
40+
print(f"Try this PromQL query in your Prometheus dashboard:\n")
41+
print(
42+
f"# Rate of calls to the `destiny` function per second, averaged over 5 minute windows\n"
43+
)
44+
print(
45+
'sum by (function, module) (rate(function_calls_count_total{caller="destiny"}[5m]))'
46+
)
47+
48+
# Enter an infinite loop (with a 1 second sleep period), calling the `destiny` and `agent_smith` methods.
1849
while True:
19-
greet("john")
50+
destiny()
51+
time.sleep(0.3)
52+
53+
54+
# NOTE - You will want to open prometheus

examples/docs-example.py

+4-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import time
21
from autometrics.autometrics import autometrics
32

43

@@ -8,4 +7,8 @@ def hello():
87
print("Hello")
98

109

10+
# Use the built-in `help` function to print the docstring for `hello`
11+
#
12+
# In your console, you'll see links to prometheus metrics for the `hello` function,
13+
# which were added by the `autometrics` decorator.
1114
help(hello)

examples/example.py

+16-7
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,13 @@
11
from prometheus_client import start_http_server
22
from autometrics.autometrics import autometrics
33
import time
4+
import random
45

56

7+
# Defines a class called `Operations`` that has two methods:
8+
# 1. `add` - Perform addition
9+
# 2. `div_handled` - Perform division and handle errors
10+
#
611
class Operations:
712
def __init__(self, **args):
813
self.args = args
@@ -24,29 +29,33 @@ def div_handled(self, num1, num2):
2429
return result
2530

2631

32+
# Perform division without handling errors
2733
@autometrics
2834
def div_unhandled(num1, num2):
2935
result = num1 / num2
3036
return result
3137

3238

33-
@autometrics
34-
def text_print():
35-
return "hello"
36-
37-
3839
ops = Operations()
3940

41+
# Show the docstring (with links to prometheus metrics) for the `add` method
4042
print(ops.add.__doc__)
43+
44+
# Show the docstring (with links to prometheus metrics) for the `div_unhandled` method
4145
print(div_unhandled.__doc__)
4246

47+
# Start an HTTP server on port 8080 using the Prometheus client library, which exposes our metrics to prometheus
4348
start_http_server(8080)
49+
50+
# Enter an infinite loop (with a 2 second sleep period), calling the "div_handled", "add", and "div_unhandled" methods,
51+
# in order to generate metrics.
4452
while True:
4553
ops.div_handled(2, 0)
4654
ops.add(1, 2)
4755
ops.div_handled(2, 1)
48-
div_unhandled(2, 0)
49-
text_print()
56+
# Randomly call `div_unhandled` with a 50/50 chance of raising an error
57+
div_unhandled(2, random.randint(0, 1))
5058
ops.add(1, 2)
5159
time.sleep(2)
60+
# Call `div_unhandled` such that it raises an error
5261
div_unhandled(2, 0)

examples/fastapi-example.py

+3
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,14 @@
66
app = FastAPI()
77

88

9+
# Set up a metrics endpoint for Prometheus to scrape
10+
# `generate_lates` returns the latest metrics data in the Prometheus text format
911
@app.get("/metrics")
1012
def metrics():
1113
return Response(generate_latest())
1214

1315

16+
# Set up the root endpoint of the API
1417
@app.get("/")
1518
@autometrics
1619
def read_root():

prometheus.yaml

+8-5
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,15 @@ global:
33
evaluation_interval: 15s
44

55
scrape_configs:
6-
- job_name: 'prometheus'
6+
# Use prometheus to scrape prometheus :)
7+
- job_name: "prometheus"
78
scrape_interval: 5s
89
static_configs:
9-
- targets: ['localhost:9090']
10+
- targets: ["localhost:9090"]
1011

11-
- job_name: 'myservice'
12-
scrape_interval: 5s
12+
- job_name: "python-autometrics-example"
13+
# For a real deployment, you would want the scrape interval to be
14+
# longer but for testing, you want the data to show up quickly
15+
scrape_interval: 500ms
1316
static_configs:
14-
- targets: ['localhost:8080']
17+
- targets: ["localhost:8080"]

0 commit comments

Comments
 (0)