Segregate Controller And Datapath Logs

Kanister uses structured logging to ensure that its logs can be easily categorized, indexed and searched by downstream log aggregation software.

By default, Kanister logs are output to the controller's stderr in JSON format. Generally, these logs can be categorized into system logs and datapath logs.

System logs are logs emitted by the Kanister to track important controller events like interactions with the Kubernetes APIs, CRUD operations on blueprints and actionsets etc.

Datapath logs, on the other hand, are logs emitted by task pods created by Kanister. These logs are streamed to the Kanister controller before the task pods are terminated to ensure they are not lost inadvertently. Datapath log lines usually include the LogKind field, with its value set to datapath.

The rest of this documentation provides instructions on how to segregate Kanister's system logs from datapath logs using Loki and Grafana.

To run the provided commands, access to a Kubernetes cluster using the kubectl and helm command-line tools is required.

Follow the instructions in the installation page to deploy Kanister on the cluster.

Deployments Setup

The commands and screenshots in this documentation are tested with the following software versions:

  • Loki 2.5.0

  • Grafana 8.5.3

  • Promtail 2.5.0

Let's begin by installing Loki. Loki is a datastore optimized for holding log data. It indexes log data via streams made up of logs, where each stream is associated with a unique set of labels.

helm repo add grafana

helm repo update

helm -n loki install --create-namespace loki grafana/loki \
  --set image.tag=2.5.0

Confirm that the Loki StatefulSet is successfully rolled out:

kubectl -n loki rollout status sts/loki


The Loki configuration used in this installation is meant for demonstration purposes only. The Helm chart deploys a non-HA single instance of Loki, managed by a StatefulSet workload. See the Loki installation documentation for other installation methods that may be more suitable for your requirements.

Use Helm to install Grafana with a pre-configured Loki data source:

svc_url=$(kubectl -n loki get svc loki -ojsonpath='{}.{.metadata.namespace}:{.spec.ports[?("http-metrics")].port}')

cat <<EOF | helm -n grafana install --create-namespace grafana grafana/grafana -f -
    apiVersion: 1
    - name: Loki
      type: loki
      url: http://$svc_url
      access: proxy
      isDefault: true

Confirm that the Grafana Deployment is successfully rolled out:

kubectl -n grafana rollout status deploy/grafana

Set up port-forward to access the Grafana UI:

kubectl -n grafana port-forward svc/grafana 3000:80

Use a web browser to navigate to localhost:3000:


The default login username is admin.

The login password can be retrieved using the following command:

kubectl -n grafana get secret grafana -o jsonpath="{.data.admin-password}" | base64 --decode ; echo

Navigate to the data sources configuration under Configuration > Data Sources using the left-hand panel.

Confirm that the Loki data source has already been added as part of the Grafana installation:


Access the Loki data source configuration page.

Use the Test button near the bottom of the page to test the connectivity between Grafana and Loki:


The final step in the setup involves installing Promtail. Promtail is an agent that can be used to discover log targets and stream their logs to Loki:

svc_url=$(kubectl -n loki get svc loki -ojsonpath='{}.{.metadata.namespace}:{.spec.ports[?("http-metrics")].port}')

helm -n loki upgrade --install --create-namespace promtail grafana/promtail \
  --set image.tag=2.5.0 \
  --set "config.clients[0].url=http://${svc_url}/loki/api/v1/push"

Confirm that the Promtail DaemonSet is successfully rolled out:

kubectl -n loki rollout status ds/promtail

Logs Segregation

To simulate a steady stream of log lines, the next step defines a blueprint that uses flog to generate Apache common and error logs:

cat<<EOF | kubectl apply -f -
kind: Blueprint
  name: stream-apache-logs
  namespace: kanister
    - func: KubeTask
      name: taskApacheLogs
        namespace: "{{ .Namespace.Name }}"
        image: mingrammer/flog:0.4.3
        - flog
        - -f
        - apache_combined
        - -n
        - "120"
        - -s
        - 0.5s

Create the following actionset to invoke the flogTask action in the blueprint:

cat<<EOF | kubectl create -f -
kind: ActionSet
  generateName: stream-apache-logs-task-
  namespace: kanister
  - name: flogTask
    blueprint: stream-apache-logs
      kind: Namespace
      name: default

Head over to the Explore pane in the Grafana UI.

Ensure that the Loki data source is selected.

Enter the following LogQL query in the Log Browser input box to retrieve all Kanister logs:


The log outputs should look similar to this:


Use the next query to select only the datapath logs, replacing ${actionset} with the name of the recently created actionset:

{namespace="kanister"} | json | LogKind="datapath",ActionSet="${actionset}"

The Logs pane should only display Apache log lines generated by flog:


LogQL is a very expressive language inspired by PromQL. There is so much more one can do with it. Be sure to check out its documentation for other use cases that involve more advanced line and label filtering, formatting and parsing.

Wrap Up

As seen in this documentation, Kanister's consistent structured log lines allow one to easily integrate Kanister with more advanced log aggregation solutions to improve ensure better observability within the data protection workflows.

To remove Loki, Grafana and Promtail, use the following helm commands:

helm -n grafana uninstall grafana

helm -n loki uninstall promtail

helm -n loki uninstall loki