#############################################################################
# Copyright (c) 2022 Balazs Scheidler <bazsi77@gmail.com>
#
# This program is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License version 2 as published
# by the Free Software Foundation, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
#
# As an additional exemption you are allowed to compile & link against the
# OpenSSL libraries as published by the OpenSSL project. See the file
# COPYING for details.
#
#############################################################################
#
# Integration for Kubernetes container log files as described here
#
#    https://github.com/kubernetes/design-proposals-archive/blob/main/node/kubelet-cri-logging.md
#
# At this point we only support the text based format (JSON is not supported
# but could similarly be added), which is:
#
#     ISODATE space STREAM-NAME space TAG space MSG newline
#
# ISODATE     -- ISO timestamp with nanosecond precision
# STREAM-NAME -- stdout or stderr
# TAG         -- contains 'P' for partial lines, 'F' for full lines.
# MSG         -- is the message
#
#
# Components defined in this SCL:
#
#   kubernetes() source          -- source driver that tails /var/log/containers or /var/log/pods
#                                   (depending on the base-dir() parameter)
#                                   and extracts the container logs using the parsers below.
#
#   kubernetes-file-parser()     -- extract pod log message from log file
#                                   along with kubernetes metadata.
#
#   kubernetes-metadata-parser() -- extract pod related metadata from
#                                   $FILE_NAME
#
#
# Kubernetes meta information is automatically extracted from
# $FILE_NAME, such as:
#
#  - ${.k8s.container_id} or ${.k8s.pod_uuid}
#  - ${.k8s.container_name}
#  - ${.k8s.pod_name}
#  - ${.k8s.namespace_name}
#
# Messages that are written to the log file as multiple chunks are
# automatically decoded, so it becomes a single log entry.
#
# Example log:
#     2022-02-04T18:14:43.219493781+01:00 stdout F Starting up on port 80

# filename format under /var/log/containers
@define kubernetes-log-containers-regexp '.var.log.containers.(?<pod_name>[a-z0-9-]+)_(?<namespace_name>[a-z0-9-]+)_(?<container_name>[a-z0-9-]+)-(?<container_id>[a-z0-9]{64}).log'

# filename format under /var/log/pods
@define kubernetes-log-pods-regexp '.var.log.pods.(?<namespace_name>[^_]+)_(?<pod_name>[^_]+)_(?<pod_uuid>[a-z0-9-]*).(?<container_name>.+)/[^.]+.log'

block parser kubernetes-metadata-parser (prefix() template("$FILE_NAME")) {
    channel {

        parser {
	    regexp-parser(
                patterns("`kubernetes-log-containers-regexp`",
                         "`kubernetes-log-pods-regexp`")
                template(`template`)
                prefix(`prefix`)
            );
        };

        # make the container-id of 12 characters long as usual in cli
	rewrite { set("$(substr ${`prefix`container_id} 0 12)" value("`prefix`container_id")); };
     };
};

block parser kubernetes-file-parser(prefix('.k8s.') cluster-name('k8s')) {
    csv-parser(
	# time, stream, flags, message
        columns("1", "2", "3", "4")
        delimiters(" ")
        flags(greedy)
    );
    date-parser(format("%FT%H:%M:%S.%f%Z") template("$1"));

    # decode multiline
    grouping-by(
        key("$FILE_NAME|$2")
        scope(global)
        trigger("$3" eq "F")
        aggregate(
          value("MESSAGE" "$(implode '' $(list-slice 0:-1 $(context-values $4)))")
	  value("FILE_NAME" "${FILE_NAME}@1")
	  value("`prefix`stream" "${2}@1")
          tags(".tmp.k8s")
          inherit-mode(none))
        inject-mode(aggregate-only)
        timeout(10)
    );

    kubernetes-metadata-parser(prefix(`prefix`));
    channel {
        rewrite {
	    set("`cluster-name`/${`prefix`namespace_name}/${`prefix`pod_name}" value("HOST"));
            set("${`prefix`container_name}" value("PROGRAM"));
            set("$(if ('${`prefix`pod_uuid}' ne '') ${`prefix`pod_uuid} ${`prefix`container_id})/${`prefix`stream}" value("PID"));
        };
    };
};

block source kubernetes(prefix('.k8s.') base-dir("/var/log/containers") cluster-name('k8s')) {
    channel {
        source {
            wildcard-file(
                base-dir(`base-dir`)
                filename-pattern("*.log")
                recursive(yes)
                follow-freq(1)
                flags(no-parse)
            );
        };
        parser { kubernetes-file-parser(prefix(`prefix`) cluster-name(`cluster-name`)); };
    };
};
