Grafana Loki API
In my case I wanted to periodically check logs and notify teammates about problems before user does
Here are few samples
kubectl port-forward loki-0 3100:3100
curl -vv -G -s "http://localhost:3100/loki/api/v1/query" \
--data-urlencode \
'query={app="dracula"} |= `Error trying to resolve field`' | jq
which will return something like
{
"status": "success",
"data": {
"resultType": "streams",
"result": [
{
"stream": {
"container": "contoso",
"filename": "/var/log/pods/production_contoso-xxxxxxxx/contoso/0.log",
"job": "production/contoso",
"namespace": "production",
"node_name": "node001",
"pod": "contoso-xxxxxxx-yyyyyy",
"stream": "stdout",
"app": "contoso"
},
"values": [
[
"1667069275158472827",
"{\"level\":\"warn\",\"operation\":\"query\",\"name\":\"sayHi\"}"
]
]
}
]
}
}
with that in place we can wirte some kind of demo:
const http = require('http')
const https = require('https')
const url = new URL('/loki/api/v1/query_range', 'http://localhost:3100')
url.searchParams.set('query', "{app=\"dracula\"} |= `\"isEmployer\":\"1\"` | json | __error__ != `JSONParserErr`")
// url.searchParams.set('query', "{app=\"dracula\"} | json | __error__ != `JSONParserErr`")
// url.searchParams.set('start', '2022-10-03T09:00:00.0Z') // Math.round(new Date(2022, 10, 3, 9, 0, 0) / 1000))
// url.searchParams.set('end', '2022-10-03T10:00:00.0Z') // , Math.round(new Date(2022, 10, 3, 11, 0, 0) / 1000))
url.searchParams.set('start', new Date(Date.now() - 5 * 60 * 1000).toISOString()) // Math.round(new Date(2022, 10, 3, 9, 0, 0) / 1000))
url.searchParams.set('end', new Date().toISOString()) // , Math.round(new Date(2022, 10, 3, 11, 0, 0) / 1000))
// 1664756200
let counter = 0
http.get(url.toString(), res => {
let body = ''
res.on('data', chunk => body += chunk)
res.on('end', () => {
const { data: { result } } = JSON.parse(body)
const events = result.map(r => JSON.parse(r.values[0][1]))
const items = events
.map(e => ({
email: e?.token?.email,
notebook: e?.token?.notebookId,
error: e?.error,
name: e?.name,
}))
.filter(e => !!e.email && !!e.notebook && !!e.error && !!e.name)
// console.log(items)
for(const item of items) {
// console.log(item)
// counter++
// if (counter < 2) {
// continue
// }
const text = `User ${item.email} (${item.notebook}) had troubles while executing '${item.name}' because of '${item.error}' (details are in monitoring) and there is a chance he will complain to CC`
// https.request('https://slack.com/api/chat.postMessage', {
// method: 'POST',
// headers: {
// 'Content-Type': 'application/json',
// 'Authorization': 'Bearer xoxb-xxxxxxx'
// }
// }).end(JSON.stringify({
// channel: '@mac',
// text
// }))
console.log(text)
// if (counter++>5) {
// break
// }
break
}
// console.log(response.status, rest)
// console.log(status, result.map(r => Object.keys(r)))
// console.log(result.map(r => JSON.parse(r.values[0][1])).filter(r => !!r.token))
})
})
console.log(url.toString())