# Loki Setup for httplog
three components:
- promtail: it forwards the log to loki
- loki
- grafana
first, we need to extract the httplog entries from the kube-apiserver log file.
## Prepare httplog
extract all httplog entries from kube-apiserver log into a file:
```
cat kube-apiserver.log | grep 'httplog.go' > httplog.log
```
httplog entry does not conform to a `logfmt` format, so i had to do some `sed` magic:
```
cat httplog.log | \
sed -E 's/^I//; s/([0-9]{2})([0-9]{2}) ([0-9]{2}:[0-9]{2}:[0-9]{2}).([0-9]{6})(.*"HTTP")/ts="\1\2 \3.\4"/'\
> httplog.logfmt
```
httplog entries are out of order, so sort the file by log timestamp
```
sort -k 1 httplog.log > http.log
rm httplog.log
```
## Prepare audit
collect audit logs from all master nodes and cat to one file
```
oc adm node-logs {server url} --path=/kube-apiserver/audit.log > audit-0.log
cat audit-0.log audit-1.log audit-2.log > audit.log
for file in *; do cat $file >> audit.log; done
//
by received timestamp
cat audit.log | jq '[.] | sort_by(.requestReceivedTimestamp) | .[]' | jq -c . > audit-sorted.log
jq -sc 'sort_by(.requestReceivedTimestamp)|.[]' audit.jq
```
## Loki Setup
i prepared a custom image for `loki` since i wanted to have a custom value for `max_entries_limit_per_query`. the loki query i have retuns more than `5000` lines.
extend the official docker image with your own:
```
FROM grafana/loki:2.3.0
COPY my-loki-local-config.yaml /etc/loki/my-local-config.yaml
ENTRYPOINT [ "/usr/bin/loki" ]
CMD ["-config.file=/etc/loki/my-local-config.yaml"]
```
`my-loki-local-config.yaml` is a copy of the official with the following change:
```
limits_config:
max_entries_limit_per_query: 0
```
build the loki image
```
docker build -t tohinkashem/myloki:dev -f Dockerfile .
```
## PromTail Setup
This is the promtail config file to ingest the httplog entries
```
server:
http_listen_port: 9080
grpc_listen_port: 0
positions:
filename: /tmp/positions.yaml
clients:
- url: http://loki:3100/loki/api/v1/push
scrape_configs:
- job_name: httplog
static_configs:
- targets:
- localhost
labels:
job: httplogs
__path__: /httplog/*log
pipeline_stages:
- regex:
expression: '^ts="(?P<arrivaltime>\d{4} \d{2}:\d{2}:\d{2}\.\d{6})".*$'
- timestamp:
source: arrivaltime
format: '0102 15:04:05.000000'
- job_name: audit
static_configs:
- targets:
- localhost
labels:
job: audit
__path__: /audit/*log
pipeline_stages:
- json:
expressions:
timestamp: requestReceivedTimestamp
- timestamp:
source: timestamp
format: '2006-01-02T15:04:05.999999Z'
```
note that i am using `pipeline_stages` to read the timestamp from the httplog entry, otherwise promtail will assign the timestamp when it forwards the log line.
we also need to create my own promtail image
```
FROM grafana/promtail:2.3.0
COPY promtail-docker-config.yaml /etc/promtail/my-config.yml
ENTRYPOINT ["/usr/bin/promtail"]
CMD ["-config.file=/etc/promtail/my-config.yml"]
```
build promtail docker image:
```
docker build -t tohinkashem/mypromtail:dev -f Dockerfile .
```
## Run Grafana/Loki/PromTail
I used the following docker-compose file to run these components:
```
version: "3"
networks:
loki:
services:
loki:
image: tohinkashem/myloki:dev
restart: always
ports:
- "3100:3100"
command: -config.file=/etc/loki/my-local-config.yaml
networks:
- loki
promtail:
image: tohinkashem/mypromtail:dev
restart: always
volumes:
- /home/akashem/httplog:/httplog
command: --inspect -config.file=/etc/promtail/my-config.yml
networks:
- loki
grafana:
image: grafana/grafana:latest
environment:
- GF_AUTH_ANONYMOUS_ENABLED=true
- GF_AUTH_DISABLE_LOGIN_FORM=true
- GF_AUTH_ANONYMOUS_ORG_ROLE=Admin
ports:
- "3000:3000"
networks:
- loki
```
`home/akashem/httplog` is the directory where i stored the processed httplog file.
- run the suite `docker-compose up`.
- open a browser window, type in `http://localhost:3000` to open grafana.
- go to settings, and create a new data soure for `Loki`, provide the url `http://loki:3100`
- go to explore and choose Loki data source
## Loki Query
```
$ curl -v -o output.log "http://localhost:3000/api/datasources/proxy/1/loki/api/v1/query_range?direction=BACKWARD&limit=1000000&start=1634817600000000000&end=1634842800000000000" --data-urlencode 'query={job="httplogs"} | logfmt | verb="DELETE" and apf_f_seatss > 10'
cat output.log | jq '.data.result | .[]' | jq -r '.stream.apf_f_seatss + " " + .stream.apf_pl + " " + .stream.apf_fs + " " + .stream.verb + " " + .stream.URI + " " + .stream.userAgent' | sort | uniq -c > delete.txt
```