Skip to content

Commit 30ec1aa

Browse files
tylergraffTyler Graff
andauthored
Programmatic Loki access example (#518)
* Add Grafana programmatic access example * Add Grafana / Loki log query example code * Code organization and clarity * fixed format by using yarn run format:fix * fix codeblock syntax --------- Co-authored-by: Tyler Graff <[email protected]>
1 parent a89fe3f commit 30ec1aa

File tree

1 file changed

+71
-0
lines changed

1 file changed

+71
-0
lines changed

docs/docs/how-tos/access-logs-loki.md

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,77 @@ To see the logs from **all deployed apps**, use the label filter `container` = `
7070

7171
To see **logs from a specific app**, use the `pod` label and begin typing either the name of the user running the app or the app name to find the correct pod. App pods are named with the convention `jupyter-[username]--[app_name]-[pod_id]`.
7272

73+
## Programmatic Access to Logs
74+
75+
Grafana logs can be accessed programmatically from within a Jupyter Notebook or JupyterHub App running in Nebari:
76+
77+
- Create a Grafana Service Account and API token by following Grafana docs: https://grafana.com/docs/grafana/latest/administration/service-accounts/
78+
- Use example code below to retrieve logs from a specific Loki Data Source UID:
79+
80+
```python
81+
import requests
82+
from datetime import datetime, timedelta
83+
import requests
84+
import json
85+
86+
NEBARI_BASE_URL = "<URL>" # Your Nebari URL e.g. https://nebari.local
87+
GRAFANA_TOKEN = "<Token>" # e.g. "glsa_4QWcA...", See Grafana Documentation
88+
89+
headers = { "Authorization": f"Bearer {GRAFANA_TOKEN}" }
90+
91+
url = f'{NEBARI_BASE_URL}/monitoring/api/datasources/'
92+
response = requests.get(url, headers=headers)
93+
assert response.status_code == 200
94+
print(response.json())
95+
# Example output: [{'id': 2, 'uid': 'alertmanager', 'orgId': 1, 'name': 'Alertmanager', 'type': 'alertmanager', ...
96+
97+
# Specify a Loki Data Source UID:
98+
def get_loki_uid(datasources):
99+
for datasource in datasources:
100+
if datasource["name"] == "Loki":
101+
return datasource["uid"]
102+
103+
loki_datasource_uid = get_loki_uid(response.json())
104+
print(f"Loki data source uid: {loki_datasource_uid}")
105+
# Example output: Loki data source uid: P8E80F9AEF21F6940
106+
107+
# Set Up and Execute a Grafana Query:
108+
grafana_url = f'{NEBARI_BASE_URL}/monitoring'
109+
api_key = GRAFANA_TOKEN
110+
loki_data_source_uid = loki_datasource_uid
111+
112+
# Query parameters
113+
query = '{app="jupyterhub"}'
114+
query_url = f'{grafana_url}/api/ds/query'
115+
116+
headers = { 'Authorization': f'Bearer {api_key}', 'Content-Type': 'application/json' }
117+
118+
# Data payload
119+
payload = {
120+
'queries': [
121+
{
122+
'datasource': {'uid': loki_data_source_uid},
123+
'expr': query,
124+
'refId': 'A',
125+
'intervalMs': 100,
126+
'maxDataPoints': 1
127+
}
128+
],
129+
"from":"now-5m",
130+
"to":"now"
131+
}
132+
133+
# Send the request
134+
response = requests.post(query_url, headers=headers, data=json.dumps(payload))
135+
136+
# Print the response
137+
if response.status_code == 200:
138+
data = response.json()
139+
print(json.dumps(data["results"]["A"], indent=2))
140+
else:
141+
print(f'Error: {response.status_code}, {response.text}')
142+
```
143+
73144
## Additional Information
74145

75146
- [Understand Log Query Structure](https://grafana.com/docs/loki/latest/query/log_queries/)

0 commit comments

Comments
 (0)