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())