Skip to content

Commit 83571a5

Browse files
authored
docs: backport python examples 3.6 (#21517)
1 parent 44b4d48 commit 83571a5

1 file changed

Lines changed: 98 additions & 8 deletions

File tree

docs/sources/reference/python-client-examples.md

Lines changed: 98 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ pip install httpx
2525

2626
## Authentication
2727

28-
The examples on this page connect to a local Loki instance without authentication. To use these examples with a multi-tenant or Grafana Cloud deployment, add the appropriate authentication as shown below.
28+
The examples on this page connect to a local Loki instance without authentication. To use these examples with a multi-tenant or Grafana Cloud deployment, add the appropriate authentication as shown below. All functions defined on this page accept `headers`, `auth`, and `verify` parameters for this purpose.
2929

3030
### Multi-tenant mode
3131

@@ -36,6 +36,18 @@ headers = {"X-Scope-OrgID": "my-tenant"}
3636
resp = requests.get(url, params=params, headers=headers)
3737
```
3838

39+
Using the functions defined on this page:
40+
41+
```python
42+
results = query_range(
43+
url="http://localhost:3100",
44+
query='{job="varlogs"}',
45+
start=datetime.now() - timedelta(hours=1),
46+
end=datetime.now(),
47+
headers={"X-Scope-OrgID": "my-tenant"},
48+
)
49+
```
50+
3951
To query across multiple tenants, separate tenant names with the pipe (`|`) character:
4052

4153
```python
@@ -50,6 +62,18 @@ For Grafana Cloud, use basic authentication with your Grafana Cloud user and an
5062
resp = requests.get(url, params=params, auth=("<user>", "<API_TOKEN>"))
5163
```
5264

65+
Using the functions defined on this page:
66+
67+
```python
68+
results = query_range(
69+
url="https://logs-prod-us-central1.grafana.net",
70+
query='{job="varlogs"}',
71+
start=datetime.now() - timedelta(hours=1),
72+
end=datetime.now(),
73+
auth=("<user>", "<API_TOKEN>"),
74+
)
75+
```
76+
5377
You can find the **User** and **URL** values in the Loki logging service details of your [Grafana Cloud stack](https://grafana.com/docs/grafana-cloud/account-management/cloud-portal/#your-grafana-cloud-stack).
5478

5579
### Self-signed certificates
@@ -66,6 +90,18 @@ For production use, pass the path to your CA bundle instead:
6690
resp = requests.get(url, params=params, verify="/path/to/ca-bundle.crt")
6791
```
6892

93+
Using the functions defined on this page:
94+
95+
```python
96+
results = query_range(
97+
url="https://loki.internal:3100",
98+
query='{job="varlogs"}',
99+
start=datetime.now() - timedelta(hours=1),
100+
end=datetime.now(),
101+
verify="/path/to/ca-bundle.crt",
102+
)
103+
```
104+
69105
## Query logs within a range of time
70106

71107
[`GET /loki/api/v1/query_range`](../loki-http-api/#query-logs-within-a-range-of-time) queries logs over a time range. This is the most common query operation.
@@ -83,6 +119,9 @@ def query_range(
83119
start: datetime,
84120
end: datetime,
85121
limit: int = 1000,
122+
headers: dict[str, str] | None = None,
123+
auth: tuple[str, str] | None = None,
124+
verify: bool | str = True, # False to skip TLS, or path to CA bundle
86125
) -> list:
87126
"""Query Loki for log entries within a time range."""
88127
resp = requests.get(
@@ -94,6 +133,9 @@ def query_range(
94133
"limit": limit,
95134
"direction": "backward",
96135
},
136+
headers=headers,
137+
auth=auth,
138+
verify=verify,
97139
)
98140
resp.raise_for_status()
99141
return resp.json()["data"]["result"]
@@ -125,6 +167,9 @@ def query_range(
125167
start: datetime,
126168
end: datetime,
127169
limit: int = 1000,
170+
headers: dict[str, str] | None = None,
171+
auth: tuple[str, str] | None = None,
172+
verify: bool | str = True, # False to skip TLS, or path to CA bundle; httpx also accepts ssl.SSLContext
128173
) -> list:
129174
"""Query Loki for log entries within a time range."""
130175
resp = httpx.get(
@@ -136,6 +181,9 @@ def query_range(
136181
"limit": limit,
137182
"direction": "backward",
138183
},
184+
headers=headers,
185+
auth=auth,
186+
verify=verify,
139187
)
140188
resp.raise_for_status()
141189
return resp.json()["data"]["result"]
@@ -163,14 +211,23 @@ import requests
163211
from datetime import datetime
164212

165213

166-
def query_instant(url: str, query: str) -> list:
214+
def query_instant(
215+
url: str,
216+
query: str,
217+
headers: dict[str, str] | None = None,
218+
auth: tuple[str, str] | None = None,
219+
verify: bool | str = True, # False to skip TLS, or path to CA bundle
220+
) -> list:
167221
"""Run an instant metric query against Loki."""
168222
resp = requests.get(
169223
f"{url}/loki/api/v1/query",
170224
params={
171225
"query": query,
172226
"time": str(int(datetime.now().timestamp() * 1e9)),
173227
},
228+
headers=headers,
229+
auth=auth,
230+
verify=verify,
174231
)
175232
resp.raise_for_status()
176233
return resp.json()["data"]["result"]
@@ -199,6 +256,9 @@ def push_logs(
199256
url: str,
200257
labels: dict[str, str],
201258
entries: list[tuple[str, str]],
259+
headers: dict[str, str] | None = None,
260+
auth: tuple[str, str] | None = None,
261+
verify: bool | str = True, # False to skip TLS, or path to CA bundle
202262
) -> None:
203263
"""Push log entries to Loki.
204264
@@ -216,10 +276,13 @@ def push_logs(
216276
}
217277
]
218278
}
279+
req_headers = {**(headers or {}), "Content-Type": "application/json"}
219280
resp = requests.post(
220281
f"{url}/loki/api/v1/push",
221-
headers={"Content-Type": "application/json"},
282+
headers=req_headers,
222283
data=json.dumps(payload),
284+
auth=auth,
285+
verify=verify,
223286
)
224287
resp.raise_for_status()
225288

@@ -243,16 +306,37 @@ push_logs(
243306
import requests
244307

245308

246-
def get_labels(url: str) -> list[str]:
309+
def get_labels(
310+
url: str,
311+
headers: dict[str, str] | None = None,
312+
auth: tuple[str, str] | None = None,
313+
verify: bool | str = True, # False to skip TLS, or path to CA bundle
314+
) -> list[str]:
247315
"""List all known label names."""
248-
resp = requests.get(f"{url}/loki/api/v1/labels")
316+
resp = requests.get(
317+
f"{url}/loki/api/v1/labels",
318+
headers=headers,
319+
auth=auth,
320+
verify=verify,
321+
)
249322
resp.raise_for_status()
250323
return resp.json()["data"]
251324

252325

253-
def get_label_values(url: str, label: str) -> list[str]:
326+
def get_label_values(
327+
url: str,
328+
label: str,
329+
headers: dict[str, str] | None = None,
330+
auth: tuple[str, str] | None = None,
331+
verify: bool | str = True, # False to skip TLS, or path to CA bundle
332+
) -> list[str]:
254333
"""List values for a specific label."""
255-
resp = requests.get(f"{url}/loki/api/v1/label/{label}/values")
334+
resp = requests.get(
335+
f"{url}/loki/api/v1/label/{label}/values",
336+
headers=headers,
337+
auth=auth,
338+
verify=verify,
339+
)
256340
resp.raise_for_status()
257341
return resp.json()["data"]
258342

@@ -270,7 +354,7 @@ for label in labels:
270354
Loki returns standard HTTP status codes. Common errors include:
271355

272356
| Status | Meaning | Typical cause |
273-
|--------|---------|---------------|
357+
| ------ | ------- | ------------- |
274358
| 400 | Bad Request | Invalid LogQL syntax |
275359
| 429 | Too Many Requests | Rate limit exceeded |
276360
| 5xx | Server Error | Loki is unavailable or overloaded |
@@ -287,12 +371,18 @@ def query_with_retry(
287371
query: str,
288372
max_retries: int = 3,
289373
backoff: float = 1.0,
374+
headers: dict[str, str] | None = None,
375+
auth: tuple[str, str] | None = None,
376+
verify: bool | str = True, # False to skip TLS, or path to CA bundle
290377
) -> dict:
291378
"""Query Loki with simple retry logic for rate limits."""
292379
for attempt in range(max_retries):
293380
resp = requests.get(
294381
f"{url}/loki/api/v1/query",
295382
params={"query": query},
383+
headers=headers,
384+
auth=auth,
385+
verify=verify,
296386
)
297387
if resp.status_code == 429:
298388
wait = backoff * (2 ** attempt)

0 commit comments

Comments
 (0)