import ../make-test-python.nix ({ lib, pkgs, ... }:

# Based on https://quickwit.io/docs/log-management/send-logs/using-vector

{
  name = "vector-syslog-quickwit";
  meta.maintainers = [ pkgs.lib.maintainers.happysalada ];

  nodes = {
    quickwit = { config, pkgs, ... }: {
      environment.systemPackages = [ pkgs.jq ];

      networking.firewall.allowedTCPPorts = [ 7280 ];

      services.quickwit = {
        enable = true;
        settings = {
          listen_address = "::";
        };
      };
    };

    syslog = { config, pkgs, ... }: {
      services.vector = {
        enable = true;

        settings = {
          sources = {
            generate_syslog = {
              type = "demo_logs";
              format = "syslog";
              interval = 0.5;
            };
          };

          transforms = {
            remap_syslog = {
              inputs = ["generate_syslog"];
              type = "remap";
              source = ''
                structured = parse_syslog!(.message)
                .timestamp_nanos = to_unix_timestamp!(structured.timestamp, unit: "nanoseconds")
                .body = structured
                .service_name = structured.appname
                .resource_attributes.source_type = .source_type
                .resource_attributes.host.hostname = structured.hostname
                .resource_attributes.service.name = structured.appname
                .attributes.syslog.procid = structured.procid
                .attributes.syslog.facility = structured.facility
                .attributes.syslog.version = structured.version
                .severity_text = if includes(["emerg", "err", "crit", "alert"], structured.severity) {
                  "ERROR"
                } else if structured.severity == "warning" {
                  "WARN"
                } else if structured.severity == "debug" {
                  "DEBUG"
                } else if includes(["info", "notice"], structured.severity) {
                  "INFO"
                } else {
                 structured.severity
                }
                .scope_name = structured.msgid
                del(.message)
                del(.host)
                del(.timestamp)
                del(.service)
                del(.source_type)
              '';
            };
          };

          sinks = {
            #emit_syslog = {
            #  inputs = ["remap_syslog"];
            #  type = "console";
            #  encoding.codec = "json";
            #};
            quickwit_logs = {
              type = "http";
              method = "post";
              inputs = [ "remap_syslog" ];
              encoding.codec = "json";
              framing.method = "newline_delimited";
              uri = "http://quickwit:7280/api/v1/otel-logs-v0_7/ingest";
            };
          };
        };
      };
    };
  };

  testScript =
  let
    aggregationQuery = pkgs.writeText "aggregation-query.json" ''
      {
        "query": "*",
        "max_hits": 0,
        "aggs": {
          "count_per_minute": {
            "histogram": {
                "field": "timestamp_nanos",
                "interval": 60000000
            },
            "aggs": {
              "severity_text_count": {
                "terms": {
                  "field": "severity_text"
                }
              }
            }
          }
        }
      }
    '';
  in
  ''
    quickwit.wait_for_unit("quickwit")
    quickwit.wait_for_open_port(7280)
    quickwit.wait_for_open_port(7281)

    quickwit.wait_until_succeeds(
      "journalctl -o cat -u quickwit.service | grep 'transitioned to ready state'"
    )

    syslog.wait_for_unit("vector")
    syslog.wait_until_succeeds(
      "journalctl -o cat -u vector.service | grep 'Vector has started'"
    )

    quickwit.wait_until_succeeds(
      "journalctl -o cat -u quickwit.service | grep 'publish-new-splits'"
    )

    # Wait for logs to be generated
    # Test below aggregates by the minute
    syslog.sleep(60 * 2)

    quickwit.wait_until_succeeds(
      "curl -sSf -XGET http://127.0.0.1:7280/api/v1/otel-logs-v0_7/search?query=severity_text:ERROR |"
      + " jq '.num_hits' | grep -v '0'"
    )

    quickwit.wait_until_succeeds(
      "journalctl -o cat -u quickwit.service | grep 'SearchRequest'"
    )

    quickwit.wait_until_succeeds(
      "curl -sSf -XPOST -H 'Content-Type: application/json' http://127.0.0.1:7280/api/v1/otel-logs-v0_7/search --data @${aggregationQuery} |"
      + " jq '.num_hits' | grep -v '0'"
    )

    quickwit.wait_until_succeeds(
      "journalctl -o cat -u quickwit.service | grep 'count_per_minute'"
    )
  '';
})
