Ctrl K
ComunidadGuías…

constructor/queries.go

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
package constructor

import (
	"fmt"
	"net"
	"slices"
	"strconv"
	"strings"
	"time"

	"github.com/coroot/coroot/db"
	"github.com/coroot/coroot/model"
	"github.com/coroot/coroot/timeseries"
	"github.com/coroot/coroot/utils"
	promModel "github.com/prometheus/common/model"
	"golang.org/x/exp/maps"
	"k8s.io/klog"
)

const (
	qApplicationCustomSLI = "application_custom_sli"

	qRecordingRuleApplicationLogMessages         = "rr_application_log_messages"
	qRecordingRuleApplicationTCPSuccessful       = "rr_connection_tcp_successful"
	qRecordingRuleApplicationTCPActive           = "rr_connection_tcp_active"
	qRecordingRuleApplicationTCPFailed           = "rr_connection_tcp_failed"
	qRecordingRuleApplicationTCPConnectionTime   = "rr_connection_tcp_connection_time"
	qRecordingRuleApplicationTCPBytesSent        = "rr_connection_tcp_bytes_sent"
	qRecordingRuleApplicationTCPBytesReceived    = "rr_connection_tcp_bytes_received"
	qRecordingRuleApplicationTCPRetransmissions  = "rr_connection_tcp_retransmissions"
	qRecordingRuleApplicationNetLatency          = "rr_connection_net_latency"
	qRecordingRuleApplicationL7Requests          = "rr_connection_l7_requests"
	qRecordingRuleApplicationL7Latency           = "rr_connection_l7_latency"
	qRecordingRuleApplicationTraffic             = "rr_application_traffic"
	qRecordingRuleApplicationL7Histogram         = "rr_application_l7_histogram"
	qRecordingRuleApplicationL7InboundRequests   = "rr_application_l7_inbound_requests"
	qRecordingRuleApplicationL7InboundHistogram  = "rr_application_l7_inbound_histogram"
	qRecordingRuleApplicationLLMInboundHistogram = "rr_application_llm_inbound_histogram"
	qRecordingRuleApplicationCategories          = "rr_application_categories"
	qRecordingRuleApplicationSLO                 = "rr_application_slo"
	qRecordingRuleApplicationExternalEndpoint    = "rr_connection_external_endpoints"
	qRecordingRuleApplicationDNSRequests         = "rr_application_dns_requests"
	qRecordingRuleApplicationDNSLatency          = "rr_application_dns_latency"
)

var applicationAnnotations = maps.Keys(model.ApplicationAnnotationLabels)

var qConnectionAggregations = []string{
	qRecordingRuleApplicationTCPSuccessful,
	qRecordingRuleApplicationTCPActive,
	qRecordingRuleApplicationTCPFailed,
	qRecordingRuleApplicationTCPConnectionTime,
	qRecordingRuleApplicationTCPBytesSent,
	qRecordingRuleApplicationTCPBytesReceived,
	qRecordingRuleApplicationTCPRetransmissions,
	qRecordingRuleApplicationNetLatency,
	qRecordingRuleApplicationL7Requests,
	qRecordingRuleApplicationL7Latency,
	qRecordingRuleApplicationTraffic,
	qRecordingRuleApplicationExternalEndpoint,
	qRecordingRuleApplicationDNSRequests,
	qRecordingRuleApplicationDNSLatency,
}

var (
	possibleNamespaceLabels  = []string{"namespace", "ns", "kubernetes_namespace", "kubernetes_ns", "k8s_namespace", "k8s_ns"}
	possiblePodLabels        = []string{"pod", "pod_name", "kubernetes_pod", "k8s_pod"}
	possibleDBInstanceLabels = []string{"address", "instance", "rds_instance_id", "ec_instance_id"}
)

type Query struct {
	Name   string
	Query  string
	Labels *utils.StringSet

	InstanceToInstance bool
	FillFunc           timeseries.FillFunc
}

func (q Query) WithFillFunc(f timeseries.FillFunc) Query {
	q.FillFunc = f
	return q
}

func Q(name, query string, labels ...string) Query {
	ls := utils.NewStringSet(model.LabelMachineId, model.LabelSystemUuid, model.LabelContainerId, model.LabelDestination, model.LabelDestinationIP, model.LabelActualDestination)
	ls.Add(labels...)
	return Query{Name: name, Query: query, Labels: ls}
}

func qItoI(name, query string, labels ...string) Query {
	q := Q(name, query, append(labels, "app_id")...)
	q.InstanceToInstance = true
	return q
}

func qPod(name, query string, labels ...string) Query {
	return Q(name, query, slices.Concat([]string{"uid"}, labels)...)
}

func qRDS(name, query string, labels ...string) Query {
	return Q(name, query, slices.Concat([]string{"rds_instance_id"}, labels)...)
}

func qCloudSQL(name, query string, labels ...string) Query {
	return Q(name, query, slices.Concat([]string{"cloudsql_instance_id"}, labels)...)
}

func qMemorystore(name, query string, labels ...string) Query {
	return Q(name, query, slices.Concat([]string{"memorystore_instance_id"}, labels)...)
}

func qOCIDB(name, query string, labels ...string) Query {
	return Q(name, query, slices.Concat([]string{"oci_db_id"}, labels)...)
}

func qOCICache(name, query string, labels ...string) Query {
	return Q(name, query, slices.Concat([]string{"oci_cache_id"}, labels)...)
}

func qDB(name, query string, labels ...string) Query {
	return Q(name, query, slices.Concat(possibleDBInstanceLabels, possibleNamespaceLabels, possiblePodLabels, labels)...)
}

func qJVM(name, query string, labels ...string) Query {
	return Q(name, query, slices.Concat([]string{"jvm"}, labels)...)
}

func qDotNet(name, query string, labels ...string) Query {
	return Q(name, query, slices.Concat([]string{"application"}, labels)...)
}

func qFargateContainer(name, query string, labels ...string) Query {
	return Q(name, query, slices.Concat([]string{"kubernetes_io_hostname", "namespace", "pod", "container"}, labels)...)
}

func l7Req(metric string) string {
	return fmt.Sprintf(`sum by(app_id, destination, actual_destination, status) (rate(%s{app_id!=""}[$RANGE])) or rate(%s{app_id=""}[$RANGE])`, metric, metric)
}

func l7ReqWithMethod(metric string) string {
	return fmt.Sprintf(`sum by(app_id, destination, actual_destination, status, method) (rate(%s{app_id!=""}[$RANGE])) or rate(%s{app_id=""}[$RANGE])`, metric, metric)
}

func l7Latency(metric string) string {
	return fmt.Sprintf(`sum by(app_id, destination, actual_destination) (rate(%s{app_id!="", type!="llm"}[$RANGE])) or rate(%s{app_id="", type!="llm"}[$RANGE])`, metric, metric)
}

func l7Histogram(metric string) string {
	return fmt.Sprintf(`sum by(app_id, destination, actual_destination, le) (rate(%s{app_id!="", type!="llm"}[$RANGE])) or rate(%s{app_id="", type!="llm"}[$RANGE])`, metric, metric)
}

func l7InboundReq(metric string) string {
	return fmt.Sprintf(`sum by(app_id, status) (rate(%s{app_id!=""}[$RANGE])) or rate(%s{app_id=""}[$RANGE])`, metric, metric)
}

func l7InboundHistogram(metric string) string {
	return fmt.Sprintf(`sum by(app_id, le) (rate(%s{app_id!=""}[$RANGE])) or rate(%s{app_id=""}[$RANGE])`, metric, metric)
}

var QUERIES = []Query{
	Q("node_agent_info", `node_agent_info`, "version"),

	Q("up", `up`, "job", "instance"),

	Q("node_info", `node_info`, "hostname", "kernel_version"),
	Q("node_cloud_info", `node_cloud_info`, "provider", "region", "availability_zone", "instance_type", "instance_life_cycle"),
	Q("node_uptime_seconds", `node_uptime_seconds`),
	Q("node_cpu_cores", `node_resources_cpu_logical_cores`),
	Q("node_cpu_usage_percent", `sum(rate(node_resources_cpu_usage_seconds_total{mode!="idle"}[$RANGE])) without(mode) /sum(rate(node_resources_cpu_usage_seconds_total[$RANGE])) without(mode)*100`),
	Q("node_cpu_usage_by_mode", `rate(node_resources_cpu_usage_seconds_total{mode!="idle"}[$RANGE]) / ignoring(mode) group_left sum(rate(node_resources_cpu_usage_seconds_total[$RANGE])) without(mode)*100`, "mode"),
	Q("node_memory_total_bytes", `node_resources_memory_total_bytes`),
	Q("node_memory_available_bytes", `node_resources_memory_available_bytes`),
	Q("node_memory_free_bytes", `node_resources_memory_free_bytes`),
	Q("node_memory_cached_bytes", `node_resources_memory_cached_bytes`),
	Q("node_disk_read_time", `rate(node_resources_disk_read_time_seconds_total[$RANGE])`, "device"),
	Q("node_disk_write_time", `rate(node_resources_disk_write_time_seconds_total[$RANGE])`, "device"),
	Q("node_disk_reads", `rate(node_resources_disk_reads_total[$RANGE])`, "device"),
	Q("node_disk_writes", `rate(node_resources_disk_writes_total[$RANGE])`, "device"),
	Q("node_disk_read_bytes", `rate(node_resources_disk_read_bytes_total[$RANGE])`, "device"),
	Q("node_disk_written_bytes", `rate(node_resources_disk_written_bytes_total[$RANGE])`, "device"),
	Q("node_disk_io_time", `rate(node_resources_disk_io_time_seconds_total[$RANGE])`, "device"),
	Q("node_net_up", `node_net_interface_up`, "interface"),
	Q("node_net_ip", `node_net_interface_ip`, "interface", "ip"),
	Q("node_net_rx_bytes", `rate(node_net_received_bytes_total[$RANGE])`, "interface"),
	Q("node_net_tx_bytes", `rate(node_net_transmitted_bytes_total[$RANGE])`, "interface"),
	Q("node_gpu_info", `node_gpu_info`, "gpu_uuid", "name", "driver_version"),
	Q("node_gpu_memory_total_bytes", `node_resources_gpu_memory_total_bytes`, "gpu_uuid"),
	Q("node_gpu_memory_used_bytes", `node_resources_gpu_memory_used_bytes`, "gpu_uuid"),
	Q("node_gpu_memory_utilization_percent_avg", `node_resources_gpu_memory_utilization_percent_avg`, "gpu_uuid"),
	Q("node_gpu_memory_utilization_percent_peak", `node_resources_gpu_memory_utilization_percent_peak`, "gpu_uuid"),
	Q("node_gpu_utilization_percent_avg", `node_resources_gpu_utilization_percent_avg`, "gpu_uuid"),
	Q("node_gpu_utilization_percent_peak", `node_resources_gpu_utilization_percent_peak`, "gpu_uuid"),
	Q("node_gpu_temperature_celsius", `node_resources_gpu_temperature_celsius`, "gpu_uuid"),
	Q("node_gpu_power_usage_watts", `node_resources_gpu_power_usage_watts`, "gpu_uuid"),

	Q("ip_to_fqdn", `sum by(fqdn, ip) (ip_to_fqdn)`, "ip", "fqdn"),

	Q("fargate_node_machine_cpu_cores", `machine_cpu_cores{eks_amazonaws_com_compute_type="fargate"}`, "eks_amazonaws_com_compute_type", "kubernetes_io_hostname", "topology_kubernetes_io_region", "topology_kubernetes_io_zone"),
	Q("fargate_node_machine_memory_bytes", `machine_memory_bytes{eks_amazonaws_com_compute_type="fargate"}`, "eks_amazonaws_com_compute_type", "kubernetes_io_hostname", "topology_kubernetes_io_region", "topology_kubernetes_io_zone"),

	qFargateContainer("fargate_container_spec_cpu_limit_cores", `container_spec_cpu_quota{eks_amazonaws_com_compute_type="fargate"}/container_spec_cpu_period{eks_amazonaws_com_compute_type="fargate"}`),
	qFargateContainer("fargate_container_cpu_usage_seconds", `rate(container_cpu_usage_seconds_total{eks_amazonaws_com_compute_type="fargate"}[$RANGE])`),
	qFargateContainer("fargate_container_cpu_cfs_throttled_seconds", `rate(container_cpu_cfs_throttled_seconds_total{eks_amazonaws_com_compute_type="fargate"}[$RANGE])`),
	qFargateContainer("fargate_container_spec_memory_limit_bytes", `container_spec_memory_limit_bytes{eks_amazonaws_com_compute_type="fargate"}`),
	qFargateContainer("fargate_container_memory_rss", `container_memory_rss{eks_amazonaws_com_compute_type="fargate"}`),
	qFargateContainer("fargate_container_memory_cache", `container_memory_cache{eks_amazonaws_com_compute_type="fargate"}`),
	qFargateContainer("fargate_container_oom_events_total", `container_oom_events_total{eks_amazonaws_com_compute_type="fargate"}`, "job", "instance"),

	Q("kube_node_info", `kube_node_info`, "node", "kernel_version"),
	Q("kube_service_info", `kube_service_info`, "namespace", "service", "cluster_ip"),
	Q("kube_service_port", `kube_service_port`, "namespace", "service", "port", "node_port"),
	Q("kube_service_spec_type", `kube_service_spec_type`, "namespace", "service", "type"),
	Q("kube_endpoint_address", `kube_endpoint_address`, "namespace", "endpoint", "ip", "port_number"),
	Q("kube_service_status_load_balancer_ingress", `kube_service_status_load_balancer_ingress`, "namespace", "service", "ip"),
	Q("kube_deployment_spec_replicas", `kube_deployment_spec_replicas`, "namespace", "deployment"),
	Q("kube_daemonset_status_desired_number_scheduled", `kube_daemonset_status_desired_number_scheduled`, "namespace", "daemonset"),
	Q("kube_statefulset_replicas", `kube_statefulset_replicas`, "namespace", "statefulset"),
	Q("kube_deployment_annotations", `kube_deployment_annotations`, append(applicationAnnotations, "namespace", "deployment")...),
	Q("kube_statefulset_annotations", `kube_statefulset_annotations`, append(applicationAnnotations, "namespace", "statefulset")...),
	Q("kube_daemonset_annotations", `kube_daemonset_annotations`, append(applicationAnnotations, "namespace", "daemonset")...),
	Q("kube_cronjob_annotations", `kube_cronjob_annotations`, append(applicationAnnotations, "namespace", "cronjob")...),
	Q("kube_job_owner", `kube_job_owner`, "namespace", "job_name", "owner_kind", "owner_name", "owner_is_controller"),

	qPod("kube_pod_info", `kube_pod_info`, "namespace", "pod", "created_by_name", "created_by_kind", "node", "pod_ip", "host_ip"),
	qPod("kube_pod_owner", `kube_pod_owner{owner_is_controller="false"}`, "owner_kind", "owner_name"),
	qPod("kube_pod_annotations", `kube_pod_annotations`, applicationAnnotations...),
	qPod("kube_pod_labels", `kube_pod_labels`,
		"label_postgres_operator_crunchydata_com_cluster", "label_postgres_operator_crunchydata_com_role",
		"label_cluster_name", "label_team", "label_application", "label_spilo_role",
		"label_role",
		"label_cnpg_io_cluster",
		"label_stackgres_io_cluster_name",
		"label_app_kubernetes_io_managed_by",
		"label_app_kubernetes_io_instance",
		"label_helm_sh_chart",
		"label_app_kubernetes_io_name",
		"label_app_kubernetes_io_component", "label_app_kubernetes_io_part_of",
		"label_valkey_io_cluster",
		"label_project_runner_gitlab_com_name",
		"label_serving_kserve_io_inferenceservice", "label_component",
		"label_nvidia_com_dynamo_graph_deployment_name", "label_nvidia_com_dynamo_component_type",
		"label_disaggregatedset_x_k8s_io_name", "label_disaggregatedset_x_k8s_io_role",
		"label_leaderworkerset_sigs_k8s_io_name", "label_leaderworkerset_sigs_k8s_io_worker_index",
	),
	qPod("kube_pod_status_phase", `kube_pod_status_phase > 0`, "phase"),
	qPod("kube_pod_status_ready", `kube_pod_status_ready{condition="true"}`),
	qPod("kube_pod_status_scheduled", `kube_pod_status_scheduled{condition="true"} > 0`),
	qPod("kube_pod_init_container_info", `kube_pod_init_container_info`, "namespace", "pod", "container"),
	qPod("kube_pod_container_resource_requests", `kube_pod_container_resource_requests`, "namespace", "pod", "container", "resource"),
	qPod("kube_pod_container_status_ready", `kube_pod_container_status_ready > 0`, "namespace", "pod", "container"),
	qPod("kube_pod_container_status_running", `kube_pod_container_status_running > 0`, "namespace", "pod", "container"),
	qPod("kube_pod_container_status_waiting", `kube_pod_container_status_waiting > 0`, "namespace", "pod", "container"),
	qPod("kube_pod_container_status_waiting_reason", `kube_pod_container_status_waiting_reason > 0`, "namespace", "pod", "container", "reason"),
	qPod("kube_pod_container_status_terminated", `kube_pod_container_status_terminated > 0`, "namespace", "pod", "container"),
	qPod("kube_pod_container_status_terminated_reason", `kube_pod_container_status_terminated_reason > 0`, "namespace", "pod", "container", "reason"),
	qPod("kube_pod_container_status_last_terminated_reason", `kube_pod_container_status_last_terminated_reason`, "namespace", "pod", "container", "reason"),

	Q("container_info", `container_info`, "image", "systemd_triggered_by", "systemd_type"),
	Q("container_application_type", `container_application_type`, "application_type"),
	Q("container_cpu_limit", `container_resources_cpu_limit_cores`),
	Q("container_cpu_usage", `rate(container_resources_cpu_usage_seconds_total[$RANGE])`),
	Q("container_cpu_delay", `rate(container_resources_cpu_delay_seconds_total[$RANGE])`),
	Q("container_throttled_time", `rate(container_resources_cpu_throttled_seconds_total[$RANGE])`),
	Q("container_memory_limit", `container_resources_memory_limit_bytes`),
	Q("container_memory_rss", `container_resources_memory_rss_bytes`),
	Q("container_memory_cache", `container_resources_memory_cache_bytes`),
	Q("container_memory_pressure", `rate(container_resources_memory_pressure_waiting_seconds_total[$RANGE])`, "kind"),
	Q("container_io_pressure", `rate(container_resources_io_pressure_waiting_seconds_total[$RANGE])`, "kind"),
	Q("container_oom_kills_total", `container_oom_kills_total % 10000000`, "job", "instance"),
	Q("container_restarts", `container_restarts_total % 10000000`, "job", "instance"),
	Q("container_volume_size", `container_resources_disk_size_bytes`, "mount_point", "volume", "device"),
	Q("container_volume_used", `container_resources_disk_used_bytes`, "mount_point", "volume", "device"),
	Q("container_gpu_usage_percent", `container_resources_gpu_usage_percent`, "gpu_uuid"),
	Q("container_gpu_memory_usage_percent", `container_resources_gpu_memory_usage_percent`, "gpu_uuid"),
	Q("container_net_tcp_listen_info", `container_net_tcp_listen_info`, "listen_addr", "proxy"),

	qItoI("container_net_latency", `avg by(app_id, destination_ip) (container_net_latency_seconds{app_id!=""}) or container_net_latency_seconds{app_id=""}`),
	qItoI("container_net_tcp_successful_connects", `sum by(app_id, destination, actual_destination) (rate(container_net_tcp_successful_connects_total{app_id!=""}[$RANGE])) or rate(container_net_tcp_successful_connects_total{app_id=""}[$RANGE])`),
	qItoI("container_net_tcp_failed_connects", `sum by(app_id, destination, actual_destination) (rate(container_net_tcp_failed_connects_total{app_id!=""}[$RANGE])) or rate(container_net_tcp_failed_connects_total{app_id=""}[$RANGE])`),
	qItoI("container_net_tcp_active_connections", `sum by(app_id, destination, actual_destination) (container_net_tcp_active_connections{app_id!=""}) or container_net_tcp_active_connections{app_id=""}`),
	qItoI("container_net_tcp_connection_time_seconds", `sum by(app_id, destination, actual_destination) (rate(container_net_tcp_connection_time_seconds_total{app_id!=""}[$RANGE])) or rate(container_net_tcp_connection_time_seconds_total{app_id=""}[$RANGE])`),
	qItoI("container_net_tcp_bytes_sent", `sum by(app_id, destination, actual_destination, az, region) (rate(container_net_tcp_bytes_sent_total{app_id!=""}[$RANGE])) or rate(container_net_tcp_bytes_sent_total{app_id=""}[$RANGE])`, "region", "az"),
	qItoI("container_net_tcp_bytes_received", `sum by(app_id, destination, actual_destination, az, region) (rate(container_net_tcp_bytes_received_total{app_id!=""}[$RANGE])) or rate(container_net_tcp_bytes_received_total{app_id=""}[$RANGE])`, "region", "az"),
	qItoI("container_net_tcp_retransmits", `sum by(app_id, destination, actual_destination) (rate(container_net_tcp_retransmits_total{app_id!=""}[$RANGE])) or rate(container_net_tcp_retransmits_total{app_id=""}[$RANGE])`),

	Q("container_log_messages", `container_log_messages_total % 10000000`, "level", "pattern_hash", "sample", "job", "instance"),

	qItoI("container_http_requests_count", l7Req("container_http_requests_total"), "status"),
	qItoI("container_http_requests_latency_total", l7Latency("container_http_requests_duration_seconds_total_sum")),
	qItoI("container_http_requests_histogram", l7Histogram("container_http_requests_duration_seconds_total_bucket"), "le"),
	qItoI("container_postgres_queries_count", l7Req("container_postgres_queries_total"), "status"),
	qItoI("container_postgres_queries_latency_total", l7Latency("container_postgres_queries_duration_seconds_total_sum")),
	qItoI("container_postgres_queries_histogram", l7Histogram("container_postgres_queries_duration_seconds_total_bucket"), "le"),
	qItoI("container_redis_queries_count", l7Req("container_redis_queries_total"), "status"),
	qItoI("container_redis_queries_latency_total", l7Latency("container_redis_queries_duration_seconds_total_sum")),
	qItoI("container_redis_queries_histogram", l7Histogram("container_redis_queries_duration_seconds_total_bucket"), "le"),
	qItoI("container_memcached_queries_count", l7Req("container_memcached_queries_total"), "status"),
	qItoI("container_memcached_queries_latency_total", l7Latency("container_memcached_queries_duration_seconds_total_sum")),
	qItoI("container_memcached_queries_histogram", l7Histogram("container_memcached_queries_duration_seconds_total_bucket"), "le"),
	qItoI("container_mysql_queries_count", l7Req("container_mysql_queries_total"), "status"),
	qItoI("container_mysql_queries_latency_total", l7Latency("container_mysql_queries_duration_seconds_total_sum")),
	qItoI("container_mysql_queries_histogram", l7Histogram("container_mysql_queries_duration_seconds_total_bucket"), "le"),
	qItoI("container_mongo_queries_count", l7Req("container_mongo_queries_total"), "status"),
	qItoI("container_mongo_queries_latency_total", l7Latency("container_mongo_queries_duration_seconds_total_sum")),
	qItoI("container_mongo_queries_histogram", l7Histogram("container_mongo_queries_duration_seconds_total_bucket"), "le"),
	qItoI("container_kafka_requests_count", l7Req("container_kafka_requests_total"), "status"),
	qItoI("container_kafka_requests_latency_total", l7Latency("container_kafka_requests_duration_seconds_total_sum")),
	qItoI("container_kafka_requests_histogram", l7Histogram("container_kafka_requests_duration_seconds_total_bucket"), "le"),
	qItoI("container_cassandra_queries_count", l7Req("container_cassandra_queries_total"), "status"),
	qItoI("container_cassandra_queries_latency_total", l7Latency("container_cassandra_queries_duration_seconds_total_sum")),
	qItoI("container_cassandra_queries_histogram", l7Histogram("container_cassandra_queries_duration_seconds_total_bucket"), "le"),
	qItoI("container_clickhouse_queries_count", l7Req("container_clickhouse_queries_total"), "status"),
	qItoI("container_clickhouse_queries_latency_total", l7Latency("container_clickhouse_queries_duration_seconds_total_sum")),
	qItoI("container_clickhouse_queries_histogram", l7Histogram("container_clickhouse_queries_duration_seconds_total_bucket"), "le"),
	qItoI("container_zookeeper_requests_count", l7Req("container_zookeeper_requests_total"), "status"),
	qItoI("container_zookeeper_requests_latency_total", l7Latency("container_zookeeper_requests_duration_seconds_total_sum")),
	qItoI("container_zookeeper_requests_histogram", l7Histogram("container_zookeeper_requests_duration_seconds_total_bucket"), "le"),
	qItoI("container_foundationdb_requests_count", l7Req("container_foundationdb_requests_total"), "status"),
	qItoI("container_foundationdb_requests_latency_total", l7Latency("container_foundationdb_requests_duration_seconds_total_sum")),
	qItoI("container_foundationdb_requests_histogram", l7Histogram("container_foundationdb_requests_duration_seconds_total_bucket"), "le"),
	qItoI("container_rabbitmq_messages", l7ReqWithMethod("container_rabbitmq_messages_total"), "status", "method"),
	qItoI("container_nats_messages", l7ReqWithMethod("container_nats_messages_total"), "status", "method"),

	qItoI("container_http_inbound_requests_count", l7InboundReq("container_http_inbound_requests_total"), "status"),
	qItoI("container_http_inbound_requests_histogram", l7InboundHistogram("container_http_inbound_requests_duration_seconds_total_bucket"), "le"),
	qItoI("container_llm_inbound_requests_count", l7InboundReq("container_llm_inbound_requests_total"), "status"),
	qItoI("container_llm_inbound_requests_histogram", l7InboundHistogram("container_llm_inbound_requests_duration_seconds_total_bucket"), "le"),
	qItoI("container_postgres_inbound_queries_count", l7InboundReq("container_postgres_inbound_queries_total"), "status"),
	qItoI("container_postgres_inbound_queries_histogram", l7InboundHistogram("container_postgres_inbound_queries_duration_seconds_total_bucket"), "le"),
	qItoI("container_redis_inbound_queries_count", l7InboundReq("container_redis_inbound_queries_total"), "status"),
	qItoI("container_redis_inbound_queries_histogram", l7InboundHistogram("container_redis_inbound_queries_duration_seconds_total_bucket"), "le"),
	qItoI("container_memcached_inbound_queries_count", l7InboundReq("container_memcached_inbound_queries_total"), "status"),
	qItoI("container_memcached_inbound_queries_histogram", l7InboundHistogram("container_memcached_inbound_queries_duration_seconds_total_bucket"), "le"),
	qItoI("container_mysql_inbound_queries_count", l7InboundReq("container_mysql_inbound_queries_total"), "status"),
	qItoI("container_mysql_inbound_queries_histogram", l7InboundHistogram("container_mysql_inbound_queries_duration_seconds_total_bucket"), "le"),
	qItoI("container_mongo_inbound_queries_count", l7InboundReq("container_mongo_inbound_queries_total"), "status"),
	qItoI("container_mongo_inbound_queries_histogram", l7InboundHistogram("container_mongo_inbound_queries_duration_seconds_total_bucket"), "le"),
	qItoI("container_kafka_inbound_requests_count", l7InboundReq("container_kafka_inbound_requests_total"), "status"),
	qItoI("container_kafka_inbound_requests_histogram", l7InboundHistogram("container_kafka_inbound_requests_duration_seconds_total_bucket"), "le"),
	qItoI("container_cassandra_inbound_queries_count", l7InboundReq("container_cassandra_inbound_queries_total"), "status"),
	qItoI("container_cassandra_inbound_queries_histogram", l7InboundHistogram("container_cassandra_inbound_queries_duration_seconds_total_bucket"), "le"),
	qItoI("container_clickhouse_inbound_queries_count", l7InboundReq("container_clickhouse_inbound_queries_total"), "status"),
	qItoI("container_clickhouse_inbound_queries_histogram", l7InboundHistogram("container_clickhouse_inbound_queries_duration_seconds_total_bucket"), "le"),
	qItoI("container_zookeeper_inbound_requests_count", l7InboundReq("container_zookeeper_inbound_requests_total"), "status"),
	qItoI("container_zookeeper_inbound_requests_histogram", l7InboundHistogram("container_zookeeper_inbound_requests_duration_seconds_total_bucket"), "le"),
	qItoI("container_foundationdb_inbound_requests_count", l7InboundReq("container_foundationdb_inbound_requests_total"), "status"),
	qItoI("container_foundationdb_inbound_requests_histogram", l7InboundHistogram("container_foundationdb_inbound_requests_duration_seconds_total_bucket"), "le"),

	Q("l7_requests_by_dest", "sum by(actual_destination, status) (rate(container_mongo_queries_total[$RANGE]) or rate(container_mysql_queries_total[$RANGE]))", "status"),
	Q("l7_total_latency_by_dest", "sum by(actual_destination) (rate(container_mongo_queries_duration_seconds_total_sum[$RANGE]) or rate(container_mysql_queries_duration_seconds_total_sum[$RANGE]))"),

	qItoI("container_dns_requests_total", `sum by(app_id, request_type, domain, status) (rate(container_dns_requests_total{app_id!=""}[$RANGE])) or rate(container_dns_requests_total{app_id=""}[$RANGE])`, "request_type", "domain", "status"),
	qItoI("container_dns_requests_latency", `sum by(app_id, le) (rate(container_dns_requests_duration_seconds_total_bucket{app_id!=""}[$RANGE])) or rate(container_dns_requests_duration_seconds_total_bucket{app_id=""}[$RANGE]) `, "le"),

	Q("aws_discovery_error", `aws_discovery_error`, "error"),
	Q("gcp_discovery_error", `gcp_discovery_error`, "error"),
	Q("oci_discovery_error", `oci_discovery_error`, "error"),
	qRDS("aws_rds_info", `aws_rds_info`, "cluster_id", "ipv4", "port", "engine", "engine_version", "instance_type", "storage_type", "region", "availability_zone", "multi_az"),
	qRDS("aws_rds_status", `aws_rds_status`, "status"),
	qRDS("aws_rds_cpu_cores", `aws_rds_cpu_cores`),
	qRDS("aws_rds_cpu_usage_percent", `aws_rds_cpu_usage_percent`, "mode"),
	qRDS("aws_rds_memory_total_bytes", `aws_rds_memory_total_bytes`),
	qRDS("aws_rds_memory_cached_bytes", `aws_rds_memory_cached_bytes`),
	qRDS("aws_rds_memory_free_bytes", `aws_rds_memory_free_bytes`),
	qRDS("aws_rds_storage_provisioned_iops", `aws_rds_storage_provisioned_iops`),
	qRDS("aws_rds_allocated_storage_gibibytes", `aws_rds_allocated_storage_gibibytes`),
	qRDS("aws_rds_fs_total_bytes", `aws_rds_fs_total_bytes{mount_point="/rdsdbdata"}`),
	qRDS("aws_rds_fs_used_bytes", `aws_rds_fs_used_bytes{mount_point="/rdsdbdata"}`),
	qRDS("aws_rds_io_util_percent", `aws_rds_io_util_percent`, "device"),
	qRDS("aws_rds_io_ops_per_second", `aws_rds_io_ops_per_second`, "device", "operation"),
	qRDS("aws_rds_io_await_seconds", `aws_rds_io_await_seconds`, "device"),
	qRDS("aws_rds_net_rx_bytes_per_second", `aws_rds_net_rx_bytes_per_second`, "interface"),
	qRDS("aws_rds_net_tx_bytes_per_second", `aws_rds_net_tx_bytes_per_second`, "interface"),
	qRDS("aws_rds_log_messages_total", `aws_rds_log_messages_total % 10000000`, "level", "pattern_hash", "sample", "job", "instance"),

	Q("aws_elasticache_info", `aws_elasticache_info`, "ec_instance_id", "cluster_id", "ipv4", "port", "engine", "engine_version", "instance_type", "region", "availability_zone"),
	Q("aws_elasticache_status", `aws_elasticache_status`, "ec_instance_id", "status"),

	qCloudSQL("gcp_cloudsql_info", `gcp_cloudsql_info`, "project", "region", "zone", "ipv4", "port", "engine", "engine_version", "tier", "availability_type", "connection_name", "instance_type", "primary_instance"),
	qCloudSQL("gcp_cloudsql_status", `gcp_cloudsql_status`, "status"),
	// the GCP metrics are loaded in this order: the totals first, then the metrics derived from them
	qCloudSQL("gcp_cloudsql_cpu_usage_percent", `gcp_cloudsql_cpu_usage_percent`),
	qCloudSQL("gcp_cloudsql_cpu_cores", `gcp_cloudsql_cpu_cores`),
	qCloudSQL("gcp_cloudsql_cpu_usage_cores", `gcp_cloudsql_cpu_usage_cores`),
	qCloudSQL("gcp_cloudsql_memory_total_bytes", `gcp_cloudsql_memory_total_bytes`),
	qCloudSQL("gcp_cloudsql_memory_components_percent", `gcp_cloudsql_memory_components_percent`, "component"),
	qCloudSQL("gcp_cloudsql_memory_used_bytes", `gcp_cloudsql_memory_used_bytes`),
	qCloudSQL("gcp_cloudsql_disk_total_bytes", `gcp_cloudsql_disk_total_bytes`),
	qCloudSQL("gcp_cloudsql_disk_used_bytes", `gcp_cloudsql_disk_used_bytes`),
	qCloudSQL("gcp_cloudsql_network_bytes_per_second", `gcp_cloudsql_network_bytes_per_second`, "direction"),
	qCloudSQL("gcp_cloudsql_io_ops_per_second", `gcp_cloudsql_io_ops_per_second`, "operation"),
	qCloudSQL("gcp_cloudsql_io_bytes_per_second", `gcp_cloudsql_io_bytes_per_second`, "operation"),
	qCloudSQL("gcp_cloudsql_log_messages_total", `gcp_cloudsql_log_messages_total % 10000000`, "level", "pattern_hash", "sample", "job", "instance"),
	qMemorystore("gcp_memorystore_info", `gcp_memorystore_info`, "project", "region", "zone", "ipv4", "port", "engine", "engine_version", "tier", "memory_size_gb", "instance"),
	qMemorystore("gcp_memorystore_status", `gcp_memorystore_status`, "status"),
	qMemorystore("gcp_memorystore_cpu_cores", `gcp_memorystore_cpu_cores`),
	qMemorystore("gcp_memorystore_cpu_usage_percent", `gcp_memorystore_cpu_usage_percent`),
	qMemorystore("gcp_memorystore_cpu_usage_cores", `gcp_memorystore_cpu_usage_cores`),
	qMemorystore("gcp_memorystore_memory_total_bytes", `gcp_memorystore_memory_total_bytes`),
	qMemorystore("gcp_memorystore_memory_used_bytes", `gcp_memorystore_memory_used_bytes`),
	qMemorystore("gcp_memorystore_network_bytes_per_second", `gcp_memorystore_network_bytes_per_second`, "direction"),
	// OCI: the totals come before the metrics derived from them
	qOCIDB("oci_db_info", `oci_db_info`, "name", "compartment", "region", "availability_domain", "ipv4", "port", "engine", "engine_version", "shape", "high_availability", "primary"),
	qOCIDB("oci_db_status", `oci_db_status`, "status"),
	qOCIDB("oci_db_cpu_cores", `oci_db_cpu_cores`),
	qOCIDB("oci_db_cpu_usage_percent", `oci_db_cpu_usage_percent`),
	qOCIDB("oci_db_cpu_usage_cores", `oci_db_cpu_usage_cores`),
	qOCIDB("oci_db_memory_total_bytes", `oci_db_memory_total_bytes`),
	qOCIDB("oci_db_memory_used_bytes", `oci_db_memory_used_bytes`),
	qOCIDB("oci_db_memory_usage_percent", `oci_db_memory_usage_percent`),
	qOCIDB("oci_db_disk_total_bytes", `oci_db_disk_total_bytes`),
	qOCIDB("oci_db_disk_used_bytes", `oci_db_disk_used_bytes`),
	qOCIDB("oci_db_network_bytes_per_second", `oci_db_network_bytes_per_second`, "direction"),
	qOCIDB("oci_db_io_ops_per_second", `oci_db_io_ops_per_second`, "operation"),
	qOCIDB("oci_db_io_bytes_per_second", `oci_db_io_bytes_per_second`, "operation"),
	qOCIDB("oci_db_io_latency_seconds", `oci_db_io_latency_seconds`, "operation"), // after the ops it is multiplied by
	qOCIDB("oci_db_log_messages_total", `oci_db_log_messages_total % 10000000`, "level", "pattern_hash", "sample", "job", "instance"),
	qOCICache("oci_cache_info", `oci_cache_info`, "name", "compartment", "region", "ipv4", "port", "engine", "engine_version", "node_count", "node_memory_gb"),
	qOCICache("oci_cache_status", `oci_cache_status`, "status"),
	qOCICache("oci_cache_memory_total_bytes", `oci_cache_memory_total_bytes`),
	qOCICache("oci_cache_cpu_usage_percent", `oci_cache_cpu_usage_percent`),
	qOCICache("oci_cache_memory_used_bytes", `oci_cache_memory_used_bytes`),
	qOCICache("oci_cache_network_bytes_per_second", `oci_cache_network_bytes_per_second`, "direction"),
	qOCICache("oci_cache_log_messages_total", `oci_cache_log_messages_total % 10000000`, "level", "pattern_hash", "sample", "job", "instance"),

	qDB("pg_up", `pg_up`),
	qDB("pg_scrape_error", `pg_scrape_error`, "error", "warning"),
	qDB("pg_info", `pg_info`, "server_version"),
	qDB("pg_setting", `pg_setting`, "name", "unit"),
	qDB("pg_connections", `pg_connections{db!="postgres"}`, "db", "user", "state", "query", "wait_event_type"),
	qDB("pg_lock_awaiting_queries", `pg_lock_awaiting_queries`, "db", "user", "blocking_query"),
	qDB("pg_latency_seconds", `pg_latency_seconds`, "summary"),
	qDB("pg_top_query_calls_per_second", `pg_top_query_calls_per_second`, "db", "user", "query"),
	qDB("pg_top_query_time_per_second", `pg_top_query_time_per_second`, "db", "user", "query"),
	qDB("pg_top_query_io_time_per_second", `pg_top_query_io_time_per_second`, "db", "user", "query"),
	qDB("pg_db_queries_per_second", `pg_db_queries_per_second`, "db"),
	qDB("pg_wal_current_lsn", `pg_wal_current_lsn`),
	qDB("pg_wal_throughput", `rate(pg_wal_current_lsn[$RANGE]) or rate(pg_wal_receive_lsn[$RANGE])`),
	qDB("pg_wal_receive_lsn", `pg_wal_receive_lsn`),
	qDB("pg_wal_reply_lsn", `pg_wal_reply_lsn`),
	qDB("pg_wal_replay_paused", `pg_wal_replay_paused`),
	qDB("pg_wal_receiver_status", `pg_wal_receiver_status`),
	qDB("pg_wal_size_bytes", `pg_wal_size_bytes`),
	qDB("pg_replication_slot_retained_wal_bytes", `pg_replication_slot_retained_wal_bytes`, "slot", "active", "wal_status"),
	qDB("pg_wal_archived_segments_total", `pg_wal_archived_segments_total`, "job"),
	qDB("pg_wal_archive_failures_total", `pg_wal_archive_failures_total`, "job"),
	qDB("pg_wal_archiving_status", `pg_wal_archiving_status`),
	qDB("pg_xid_age", `pg_xid_age`, "db"),
	qDB("pg_multixact_age", `pg_multixact_age`, "db"),
	qDB("pg_oldest_xmin_age", `pg_oldest_xmin_age`, "holder"),
	qDB("pg_transaction_seconds", `pg_transaction_seconds`, "db", "user", "query"),
	qDB("pg_database_size_bytes", `pg_database_size_bytes`, "db"),
	qDB("pg_table_size_bytes", `pg_table_size_bytes`, "db", "table"),
	qDB("pg_table_size_growth_bytes_per_second", `pg_table_size_growth_bytes_per_second`, "db", "table"),
	qDB("pg_db_table_bloat_bytes", `pg_db_table_bloat_bytes`, "db"),
	qDB("pg_db_index_bloat_bytes", `pg_db_index_bloat_bytes`, "db"),
	qDB("pg_table_bloat_bytes", `pg_table_bloat_bytes`, "db", "table"),
	qDB("pg_index_bloat_bytes", `pg_index_bloat_bytes`, "db", "table", "index"),
	qDB("pg_table_dead_tuple_bytes", `pg_table_dead_tuple_bytes`, "db", "table"),
	qDB("pg_table_dead_tuples", `pg_table_dead_tuples`, "db", "table"),
	qDB("pg_table_live_tuples", `pg_table_live_tuples`, "db", "table"),
	qDB("pg_table_seconds_since_last_autovacuum", `pg_table_seconds_since_last_autovacuum`, "db", "table"),
	qDB("pg_table_setting", `pg_table_setting`, "db", "table", "autovacuum_disabled", "autovacuum_vacuum_scale_factor", "autovacuum_vacuum_threshold", "autovacuum_vacuum_cost_delay", "autovacuum_vacuum_cost_limit", "autovacuum_analyze_scale_factor", "autovacuum_analyze_threshold"),
	qDB("pg_autovacuum_workers", `pg_autovacuum_workers`),
	qDB("pg_table_vacuum_in_progress", `pg_table_vacuum_in_progress`, "db", "table"),
	qDB("pg_table_vacuum_throttled", `pg_table_vacuum_throttled`, "db", "table"),
	qDB("pg_table_mods_since_analyze", `pg_table_mods_since_analyze`, "db", "table"),
	qDB("pg_table_reltuples", `pg_table_reltuples`, "db", "table"),
	qDB("pg_table_seconds_since_last_analyze", `pg_table_seconds_since_last_analyze`, "db", "table"),
	qDB("pg_checkpoints_scheduled_total", `pg_checkpoints_scheduled_total`, "type", "job"),
	qDB("pg_checkpoints_total", `pg_checkpoints_total`, "job"),
	qDB("pg_restartpoints_total", `pg_restartpoints_total`, "job"),
	qDB("pg_buffers_written_total", `rate(pg_buffers_written_total[$RANGE])`, "source"),
	qDB("pg_time_since_last_checkpoint_seconds", `pg_time_since_last_checkpoint_seconds`),
	qDB("pg_wal_since_last_checkpoint_bytes", `pg_wal_since_last_checkpoint_bytes`),

	qDB("mysql_up", `mysql_up`),
	qDB("mysql_scrape_error", `mysql_scrape_error`, "error", "warning"),
	qDB("mysql_info", `mysql_info`, "server_uuid", "server_version"),
	qDB("mysql_performance_schema_enabled", `mysql_performance_schema_enabled`),
	qDB("mysql_top_query_calls_per_second", `mysql_top_query_calls_per_second`, "schema", "query"),
	qDB("mysql_top_query_time_per_second", `mysql_top_query_time_per_second`, "schema", "query"),
	qDB("mysql_top_query_lock_time_per_second", `mysql_top_query_lock_time_per_second`, "schema", "query"),
	qDB("mysql_locked_queries", `mysql_locked_queries`, "schema", "query"),
	qDB("mysql_lock_awaiting_queries", `mysql_lock_awaiting_queries`, "schema", "blocking_query"),
	qDB("mysql_replication_io_status", `mysql_replication_io_status`, "source_server_uuid", "last_error", "state"),
	qDB("mysql_replication_sql_status", `mysql_replication_sql_status`, "source_server_uuid", "last_error", "state"),
	qDB("mysql_replication_lag_seconds", `mysql_replication_lag_seconds`, "source_server_uuid"),
	qDB("mysql_connections_max", `mysql_connections_max`),
	qDB("mysql_connections_current", `mysql_connections_current`),
	qDB("mysql_connections_total", `rate(mysql_connections_total[$RANGE])`),
	qDB("mysql_connections_aborted_total", `rate(mysql_connections_aborted_total[$RANGE])`),
	qDB("mysql_traffic_received_bytes_total", `rate(mysql_traffic_received_bytes_total[$RANGE])`),
	qDB("mysql_traffic_sent_bytes_total", `rate(mysql_traffic_sent_bytes_total[$RANGE])`),
	qDB("mysql_queries_total", `rate(mysql_queries_total[$RANGE])`),
	qDB("mysql_slow_queries_total", `rate(mysql_slow_queries_total[$RANGE])`),
	qDB("mysql_top_table_io_wait_time_per_second", `mysql_top_table_io_wait_time_per_second`, "schema", "table", "operation"),
	qDB("mysql_database_size_bytes", `mysql_database_size_bytes`, "db"),
	qDB("mysql_table_size_bytes", `mysql_table_size_bytes`, "db", "table"),
	qDB("mysql_table_size_growth_bytes_per_second", `mysql_table_size_growth_bytes_per_second`, "db", "table"),
	qDB("mysql_connection_errors_max_connections_total", `rate(mysql_connection_errors_max_connections_total[$RANGE])`),
	qDB("mysql_threads_running", `mysql_threads_running`),
	qDB("mysql_innodb_transaction_seconds", `mysql_innodb_transaction_seconds`, "query"),
	qDB("mysql_top_query_rows_examined_per_second", `mysql_top_query_rows_examined_per_second`, "schema", "query"),
	qDB("mysql_top_query_rows_sent_per_second", `mysql_top_query_rows_sent_per_second`, "schema", "query"),
	qDB("mysql_created_tmp_disk_tables_total", `rate(mysql_created_tmp_disk_tables_total[$RANGE])`),
	qDB("mysql_wsrep_cluster_size", `mysql_wsrep_cluster_size`),
	qDB("mysql_wsrep_cluster_status", `mysql_wsrep_cluster_status`, "status"),
	qDB("mysql_wsrep_local_state", `mysql_wsrep_local_state`, "state"),
	qDB("mysql_wsrep_ready", `mysql_wsrep_ready`),
	qDB("mysql_wsrep_connected", `mysql_wsrep_connected`),
	qDB("mysql_wsrep_flow_control_paused_seconds_total", `rate(mysql_wsrep_flow_control_paused_seconds_total[$RANGE])`),
	qDB("mysql_wsrep_local_recv_queue", `mysql_wsrep_local_recv_queue`),
	qDB("mysql_wsrep_local_send_queue", `mysql_wsrep_local_send_queue`),
	qDB("mysql_wsrep_local_cert_failures_total", `rate(mysql_wsrep_local_cert_failures_total[$RANGE])`),
	qDB("mysql_wsrep_local_bf_aborts_total", `rate(mysql_wsrep_local_bf_aborts_total[$RANGE])`),
	qDB("mysql_group_replication_cluster_size", `mysql_group_replication_cluster_size`),
	qDB("mysql_group_replication_members_online", `mysql_group_replication_members_online`),
	qDB("mysql_group_replication_member_state", `mysql_group_replication_member_state`, "state"),
	qDB("mysql_group_replication_transactions_in_queue", `mysql_group_replication_transactions_in_queue`),
	qDB("mysql_group_replication_transactions_remote_in_applier_queue", `mysql_group_replication_transactions_remote_in_applier_queue`),
	qDB("mysql_group_replication_conflicts_detected_total", `rate(mysql_group_replication_conflicts_detected_total[$RANGE])`),
	qDB("mysql_innodb_buffer_pool_read_requests_total", `rate(mysql_innodb_buffer_pool_read_requests_total[$RANGE])`),
	qDB("mysql_innodb_buffer_pool_reads_total", `rate(mysql_innodb_buffer_pool_reads_total[$RANGE])`),
	qDB("mysql_innodb_buffer_pool_write_requests_total", `rate(mysql_innodb_buffer_pool_write_requests_total[$RANGE])`),
	qDB("mysql_innodb_buffer_pool_pages_total", `mysql_innodb_buffer_pool_pages_total`),
	qDB("mysql_innodb_buffer_pool_pages_free", `mysql_innodb_buffer_pool_pages_free`),
	qDB("mysql_innodb_buffer_pool_pages_dirty", `mysql_innodb_buffer_pool_pages_dirty`),
	qDB("mysql_innodb_buffer_pool_pages_data", `mysql_innodb_buffer_pool_pages_data`),
	qDB("mysql_innodb_buffer_pool_wait_free_total", `rate(mysql_innodb_buffer_pool_wait_free_total[$RANGE])`),
	qDB("mysql_innodb_buffer_pool_pages_flushed_total", `rate(mysql_innodb_buffer_pool_pages_flushed_total[$RANGE])`),
	qDB("mysql_innodb_page_size_bytes", `mysql_innodb_page_size_bytes`),
	qDB("mysql_innodb_rows_read_total", `rate(mysql_innodb_rows_read_total[$RANGE])`),
	qDB("mysql_innodb_rows_inserted_total", `rate(mysql_innodb_rows_inserted_total[$RANGE])`),
	qDB("mysql_innodb_rows_updated_total", `rate(mysql_innodb_rows_updated_total[$RANGE])`),
	qDB("mysql_innodb_rows_deleted_total", `rate(mysql_innodb_rows_deleted_total[$RANGE])`),
	qDB("mysql_innodb_row_lock_waits_total", `rate(mysql_innodb_row_lock_waits_total[$RANGE])`),
	qDB("mysql_innodb_row_lock_time_seconds_total", `rate(mysql_innodb_row_lock_time_seconds_total[$RANGE])`),
	qDB("mysql_innodb_row_lock_current_waits", `mysql_innodb_row_lock_current_waits`),
	qDB("mysql_innodb_data_reads_total", `rate(mysql_innodb_data_reads_total[$RANGE])`),
	qDB("mysql_innodb_data_writes_total", `rate(mysql_innodb_data_writes_total[$RANGE])`),
	qDB("mysql_innodb_data_read_bytes_total", `rate(mysql_innodb_data_read_bytes_total[$RANGE])`),
	qDB("mysql_innodb_data_written_bytes_total", `rate(mysql_innodb_data_written_bytes_total[$RANGE])`),
	qDB("mysql_innodb_data_fsyncs_total", `rate(mysql_innodb_data_fsyncs_total[$RANGE])`),
	qDB("mysql_innodb_log_waits_total", `rate(mysql_innodb_log_waits_total[$RANGE])`),
	qDB("mysql_innodb_os_log_written_bytes_total", `rate(mysql_innodb_os_log_written_bytes_total[$RANGE])`),
	qDB("mysql_sort_merge_passes_total", `rate(mysql_sort_merge_passes_total[$RANGE])`),
	qDB("mysql_commit_total", `rate(mysql_commit_total[$RANGE])`),
	qDB("mysql_rollback_total", `rate(mysql_rollback_total[$RANGE])`),
	qDB("mysql_innodb_deadlocks_total", `rate(mysql_innodb_deadlocks_total[$RANGE])`),
	qDB("mysql_innodb_lock_wait_timeouts_total", `rate(mysql_innodb_lock_wait_timeouts_total[$RANGE])`),
	qDB("mysql_innodb_history_list_length", `mysql_innodb_history_list_length`),
	qDB("mysql_binlog_size_bytes", `mysql_binlog_size_bytes`),
	qDB("mysql_binlog_files", `mysql_binlog_files`),
	qDB("mysql_binlog_expire_seconds", `mysql_binlog_expire_seconds`),
	qDB("mysql_undo_size_bytes", `mysql_undo_size_bytes`),
	qDB("mysql_table_locks_waited_total", `rate(mysql_table_locks_waited_total[$RANGE])`),
	qDB("mysql_table_locks_immediate_total", `rate(mysql_table_locks_immediate_total[$RANGE])`),

	qDB("redis_up", `redis_up`),
	qDB("redis_scrape_error", `redis_exporter_last_scrape_error`, "err"),
	qDB("redis_instance_info", `redis_instance_info`, "redis_version", "role"),
	qDB("redis_commands_duration_seconds_total", `rate(redis_commands_duration_seconds_total[$RANGE])`, "cmd"),
	qDB("redis_commands_total", `rate(redis_commands_total[$RANGE])`, "cmd"),
	qDB("redis_db_keys", `redis_db_keys`, "db"),
	qDB("redis_db_keys_expiring", `redis_db_keys_expiring`, "db"),

	qDB("mongo_up", `mongo_up`),
	qDB("mongo_scrape_error", `mongo_scrape_error`, "error", "warning"),
	qDB("mongo_info", `mongo_info`, "server_version", "flavor"),
	qDB("mongo_rs_status", `mongo_rs_status`, "rs", "role"),
	qDB("mongo_rs_last_applied_timestamp_ms", `timestamp(mongo_rs_last_applied_timestamp_ms) - mongo_rs_last_applied_timestamp_ms/1000`),
	qDB("mongo_rs_member_status", `mongo_rs_member_status`, "rs", "member", "state"),
	qDB("mongo_rs_member_replication_lag_seconds", `mongo_rs_member_replication_lag_seconds`, "rs", "member"),
	qDB("mongo_rs_member_config_info", `mongo_rs_member_config_info`, "rs", "member", "arbiter", "votes"),
	qDB("mongo_rs_config_info", `mongo_rs_config_info`, "rs", "write_concern_majority_journal_default"),
	qDB("mongo_profiling_level", `mongo_profiling_level`, "db"),
	qDB("mongo_oplog_window_seconds", `mongo_oplog_window_seconds`),
	qDB("mongo_oplog_size_bytes", `mongo_oplog_size_bytes`),
	qDB("mongo_oplog_max_size_bytes", `mongo_oplog_max_size_bytes`),
	qDB("mongo_connections_current", `mongo_connections_current`),
	qDB("mongo_connections_active", `mongo_connections_active`),
	qDB("mongo_connections_max", `mongo_connections_max`),
	qDB("mongo_connections_created_total", `rate(mongo_connections_created_total[$RANGE])`),
	qDB("mongo_connections_rejected_total", `rate(mongo_connections_rejected_total[$RANGE])`),
	qDB("mongo_connections_by_app", `mongo_connections_by_app`, "app"),
	qDB("mongo_open_transactions", `mongo_open_transactions`, "app"),
	qDB("mongo_opcounters_total", `rate(mongo_opcounters_total[$RANGE])`, "op"),
	qDB("mongo_documents_returned_total", `rate(mongo_documents_returned_total[$RANGE])`),
	qDB("mongo_op_latency_seconds_total", `rate(mongo_op_latency_seconds_total[$RANGE])`, "type"),
	qDB("mongo_op_latency_ops_total", `rate(mongo_op_latency_ops_total[$RANGE])`, "type"),
	qDB("mongo_queued_operations", `mongo_queued_operations`, "type"),
	qDB("mongo_wt_tickets_available", `mongo_wt_tickets_available`, "type"),
	qDB("mongo_wt_cache_used_bytes", `mongo_wt_cache_used_bytes`),
	qDB("mongo_wt_cache_dirty_bytes", `mongo_wt_cache_dirty_bytes`),
	qDB("mongo_wt_cache_max_bytes", `mongo_wt_cache_max_bytes`),
	qDB("mongo_wt_pages_evicted_by_app_threads_total", `rate(mongo_wt_pages_evicted_by_app_threads_total[$RANGE])`),
	qDB("mongo_wt_app_threads_evicting_seconds_total", `rate(mongo_wt_app_threads_evicting_seconds_total[$RANGE])`),
	qDB("mongo_wt_checkpoints_total", `rate(mongo_wt_checkpoints_total[$RANGE])`),
	qDB("mongo_wt_checkpoint_seconds_total", `rate(mongo_wt_checkpoint_seconds_total[$RANGE])`),
	qDB("mongo_wt_journal_bytes_written_total", `rate(mongo_wt_journal_bytes_written_total[$RANGE])`),
	qDB("mongo_wt_journal_bytes_since_checkpoint", `mongo_wt_journal_bytes_since_checkpoint`),
	qDB("mongo_time_since_last_checkpoint_seconds", `mongo_time_since_last_checkpoint_seconds`),
	qDB("mongo_scanned_keys_total", `rate(mongo_scanned_keys_total[$RANGE])`),
	qDB("mongo_scanned_documents_total", `rate(mongo_scanned_documents_total[$RANGE])`),
	qDB("mongo_collection_scans_total", `rate(mongo_collection_scans_total[$RANGE])`),
	qDB("mongo_scan_and_order_total", `rate(mongo_scan_and_order_total[$RANGE])`),
	qDB("mongo_ttl_deleted_documents_total", `rate(mongo_ttl_deleted_documents_total[$RANGE])`),
	qDB("mongo_flow_control_time_acquiring_seconds_total", `rate(mongo_flow_control_time_acquiring_seconds_total[$RANGE])`),
	qDB("mongo_write_conflicts_total", `rate(mongo_write_conflicts_total[$RANGE])`),
	qDB("mongo_wt_cache_bytes_read_into_total", `rate(mongo_wt_cache_bytes_read_into_total[$RANGE])`),
	qDB("mongo_repl_apply_ops_total", `rate(mongo_repl_apply_ops_total[$RANGE])`),
	qDB("mongo_repl_buffer_operations", `mongo_repl_buffer_operations`),
	qDB("mongo_repl_buffer_bytes", `mongo_repl_buffer_bytes`),
	qDB("mongo_cursors_open", `mongo_cursors_open`),
	qDB("mongo_cursors_open_no_timeout", `mongo_cursors_open_no_timeout`),
	qDB("mongo_cursors_timed_out_total", `rate(mongo_cursors_timed_out_total[$RANGE])`),
	qDB("mongo_fsync_locked", `mongo_fsync_locked`),
	qDB("mongo_prepared_transactions", `mongo_prepared_transactions`),
	qDB("mongo_top_query_calls_per_second", `mongo_top_query_calls_per_second`, "db", "collection", "query"),
	qDB("mongo_top_query_time_per_second", `mongo_top_query_time_per_second`, "db", "collection", "query"),
	qDB("mongo_top_query_docs_returned_per_second", `mongo_top_query_docs_returned_per_second`, "db", "collection", "query"),
	qDB("mongo_top_query_docs_examined_per_second", `mongo_top_query_docs_examined_per_second`, "db", "collection", "query"),
	qDB("mongo_top_query_keys_examined_per_second", `mongo_top_query_keys_examined_per_second`, "db", "collection", "query"),
	qDB("mongo_operations_waiting_for_lock", `mongo_operations_waiting_for_lock`, "db"),
	qDB("mongo_long_running_operations", `mongo_long_running_operations`, "db", "collection", "query", "plan"),
	qDB("mongo_database_size_bytes", `mongo_database_size_bytes`, "db"),
	qDB("mongo_collection_size_bytes", `mongo_collection_size_bytes`, "db", "collection"),
	qDB("mongo_collection_storage_size_bytes", `mongo_collection_storage_size_bytes`, "db", "collection"),
	qDB("mongo_collection_size_growth_bytes_per_second", `mongo_collection_size_growth_bytes_per_second`, "db", "collection"),
	qDB("mongo_collection_free_storage_bytes", `mongo_collection_free_storage_bytes`, "db", "collection"),
	qDB("mongo_collection_documents", `mongo_collection_documents`, "db", "collection"),

	qDB("memcached_up", `memcached_up`),
	qDB("memcached_version", `memcached_version`, "version"),
	qDB("memcached_limit_bytes", `memcached_limit_bytes`),
	qDB("memcached_items_evicted_total", `rate(memcached_items_evicted_total[$RANGE])`),
	qDB("memcached_commands_total", `rate(memcached_commands_total[$RANGE])`, "command", "status"),

	qJVM("container_jvm_info", `container_jvm_info`, "java_version"),
	qJVM("container_jvm_heap_used_bytes", `container_jvm_heap_used_bytes`),
	qJVM("container_jvm_gc_time_seconds", `rate(container_jvm_gc_time_seconds[$RANGE])`, "gc"),
	qJVM("container_jvm_safepoint_time_seconds", `rate(container_jvm_safepoint_time_seconds[$RANGE])`),
	qJVM("container_jvm_safepoint_sync_time_seconds", `rate(container_jvm_safepoint_sync_time_seconds[$RANGE])`),
	qJVM("container_jvm_heap_max_size_bytes", `container_jvm_heap_max_size_bytes`),
	qJVM("container_jvm_alloc_bytes_total", `rate(container_jvm_alloc_bytes_total[$RANGE])`).WithFillFunc(timeseries.FillAvg),
	qJVM("container_jvm_alloc_objects_total", `rate(container_jvm_alloc_objects_total[$RANGE])`).WithFillFunc(timeseries.FillAvg),
	qJVM("container_jvm_lock_contentions_total", `rate(container_jvm_lock_contentions_total[$RANGE])`).WithFillFunc(timeseries.FillAvg),
	qJVM("container_jvm_lock_time_seconds_total", `rate(container_jvm_lock_time_seconds_total[$RANGE])`).WithFillFunc(timeseries.FillAvg),
	qJVM("container_jvm_profiling_status", `container_jvm_profiling_status`),

	Q("container_go_alloc_bytes_total", `rate(container_go_alloc_bytes_total[$RANGE])`).WithFillFunc(timeseries.FillAvg),
	Q("container_go_alloc_objects_total", `rate(container_go_alloc_objects_total[$RANGE])`).WithFillFunc(timeseries.FillAvg),

	qDotNet("container_dotnet_info", `container_dotnet_info`, "runtime_version"),
	qDotNet("container_dotnet_memory_allocated_bytes_total", `rate(container_dotnet_memory_allocated_bytes_total[$RANGE])`),
	qDotNet("container_dotnet_exceptions_total", `rate(container_dotnet_exceptions_total[$RANGE])`),
	qDotNet("container_dotnet_memory_heap_size_bytes", `container_dotnet_memory_heap_size_bytes`, "generation"),
	qDotNet("container_dotnet_gc_count_total", `rate(container_dotnet_gc_count_total[$RANGE])`, "generation"),
	qDotNet("container_dotnet_heap_fragmentation_percent", `container_dotnet_heap_fragmentation_percent`),
	qDotNet("container_dotnet_monitor_lock_contentions_total", `rate(container_dotnet_monitor_lock_contentions_total[$RANGE])`),
	qDotNet("container_dotnet_thread_pool_completed_items_total", `rate(container_dotnet_thread_pool_completed_items_total[$RANGE])`),
	qDotNet("container_dotnet_thread_pool_queue_length", `container_dotnet_thread_pool_queue_length`),
	qDotNet("container_dotnet_thread_pool_size", `container_dotnet_thread_pool_size`),

	Q("container_python_thread_lock_wait_time_seconds", `rate(container_python_thread_lock_wait_time_seconds[$RANGE])`),
	Q("container_nodejs_event_loop_blocked_time_seconds", `rate(container_nodejs_event_loop_blocked_time_seconds_total[$RANGE])`),

	qPod("fluxcd_git_repository_info", `fluxcd_git_repository_info`, "name", "namespace", "suspended", "url", "interval"),
	qPod("fluxcd_git_repository_status", `fluxcd_git_repository_status`, "name", "namespace", "type", "reason"),
	qPod("fluxcd_oci_repository_info", `fluxcd_oci_repository_info`, "name", "namespace", "suspended", "url", "interval"),
	qPod("fluxcd_oci_repository_status", `fluxcd_oci_repository_status`, "name", "namespace", "type", "reason"),
	qPod("fluxcd_helm_repository_info", `fluxcd_helm_repository_info`, "name", "namespace", "suspended", "url", "interval"),
	qPod("fluxcd_helm_repository_status", `fluxcd_helm_repository_status`, "name", "namespace", "type", "reason"),
	qPod("fluxcd_helm_chart_info", `fluxcd_helm_chart_info`, "name", "namespace", "suspended", "chart", "interval", "version", "source_kind", "source_name", "source_namespace"),
	qPod("fluxcd_helm_chart_status", `fluxcd_helm_chart_status`, "name", "namespace", "type", "reason"),
	qPod("fluxcd_helm_release_info", `fluxcd_helm_release_info`, "name", "namespace", "suspended", "chart", "interval", "version", "source_kind", "source_name", "source_namespace", "chart_ref_kind", "chart_ref_name", "chart_ref_namespace", "target_namespace"),
	qPod("fluxcd_helm_release_status", `fluxcd_helm_release_status`, "name", "namespace", "type", "reason"),
	qPod("fluxcd_kustomization_info", `fluxcd_kustomization_info`, "name", "namespace", "suspended", "interval", "path", "source_kind", "source_name", "source_namespace", "target_namespace", "last_applied_revision", "last_attempted_revision"),
	qPod("fluxcd_kustomization_status", `fluxcd_kustomization_status`, "name", "namespace", "type", "reason"),
	qPod("fluxcd_kustomization_dependency_info", `fluxcd_kustomization_dependency_info`, "name", "namespace", "depends_on_name", "depends_on_namespace"),
	qPod("fluxcd_kustomization_inventory_entry_info", `fluxcd_kustomization_inventory_entry_info`, "name", "namespace", "entry_id"),
	qPod("fluxcd_resourceset_info", `fluxcd_resourceset_info`, "name", "namespace", "last_applied_revision"),
	qPod("fluxcd_resourceset_status", `fluxcd_resourceset_status`, "name", "namespace", "type", "reason"),
	qPod("fluxcd_resourceset_dependency_info", `fluxcd_resourceset_dependency_info`, "name", "namespace", "depends_on_name", "depends_on_namespace", "depends_on_kind"),
	qPod("fluxcd_resourceset_inventory_entry_info", `fluxcd_resourceset_inventory_entry_info`, "name", "namespace", "entry_id"),

	qPod("argocd_application_info", `argocd_application_info`, "name", "namespace", "project", "source_type", "repo", "path", "chart", "dest_server", "dest_name", "dest_namespace"),
	qPod("argocd_application_sync_status", `argocd_application_sync_status`, "name", "namespace", "sync_status"),
	qPod("argocd_application_health_status", `argocd_application_health_status`, "name", "namespace", "health_status"),
	qPod("argocd_application_operation_status", `argocd_application_operation_status`, "name", "namespace", "operation_phase"),
	qPod("argocd_application_operation_finished_timestamp_seconds", `argocd_application_operation_finished_timestamp_seconds`, "name", "namespace"),
	qPod("argocd_application_resource_info", `argocd_application_resource_info`, "name", "namespace", "resource_group", "resource_kind", "resource_namespace", "resource_name"),
	qPod("argocd_application_resource_sync_status", `argocd_application_resource_sync_status`, "name", "namespace", "resource_group", "resource_kind", "resource_namespace", "resource_name", "sync_status"),
	qPod("argocd_application_resource_status", `argocd_application_resource_status`, "name", "namespace", "resource_group", "resource_kind", "resource_namespace", "resource_name", "status"),
	qPod("argocd_application_resource_health_status", `argocd_application_resource_health_status`, "name", "namespace", "resource_group", "resource_kind", "resource_namespace", "resource_name", "health_status"),

	qPod("pg_backup_target_info", `pg_backup_target_info`, "name", "namespace", "operator", "method", "path", "endpoint", "s3_bucket", "s3_endpoint", "gcs_bucket", "azure_container", "schedule", "retention_policy"),
	qPod("pg_cluster_status", `pg_cluster_status`, "name", "namespace", "operator", "type", "status", "reason"),
	qPod("pg_backup_last_successful_timestamp_seconds", `pg_backup_last_successful_timestamp_seconds`, "name", "namespace", "operator", "method"),
	qPod("pg_backup_first_recoverability_point_timestamp_seconds", `pg_backup_first_recoverability_point_timestamp_seconds`, "name", "namespace", "operator", "method"),
	qPod("pg_backup_last_failed_timestamp_seconds", `pg_backup_last_failed_timestamp_seconds`, "name", "namespace", "operator"),
	qPod("pg_backup_schedule_info", `pg_backup_schedule_info`, "name", "namespace", "operator", "cluster", "schedule"),
	qPod("pg_backup_next_scheduled_timestamp_seconds", `pg_backup_next_scheduled_timestamp_seconds`, "name", "namespace", "operator", "cluster"),
	qPod("pg_backup_info", `pg_backup_info`, "name", "namespace", "operator", "cluster", "method", "kind", "path"),
	qPod("pg_backup_status", `pg_backup_status`, "name", "namespace", "operator", "status"),
	qPod("pg_backup_completed_timestamp_seconds", `pg_backup_completed_timestamp_seconds`, "name", "namespace", "operator", "cluster"),

	qPod("mongo_backup_target_info", `mongo_backup_target_info`, "name", "namespace", "operator", "method", "s3_bucket", "s3_endpoint", "s3_prefix", "azure_container"),
	qPod("mongo_backup_schedule_info", `mongo_backup_schedule_info`, "name", "namespace", "operator", "task", "schedule", "method", "kind", "enabled"),
	qPod("mongo_backup_pitr_info", `mongo_backup_pitr_info`, "name", "namespace", "operator", "enabled"),
	qPod("mongo_cluster_status", `mongo_cluster_status`, "name", "namespace", "operator", "status"),
	qPod("mongo_backup_info", `mongo_backup_info`, "name", "namespace", "operator", "cluster", "method", "kind", "path"),
	qPod("mongo_backup_status", `mongo_backup_status`, "name", "namespace", "operator", "status"),
	qPod("mongo_backup_completed_timestamp_seconds", `mongo_backup_completed_timestamp_seconds`, "name", "namespace", "operator"),

	qPod("mysql_backup_target_info", `mysql_backup_target_info`, "name", "namespace", "operator", "method", "s3_bucket", "s3_endpoint", "s3_prefix", "azure_container"),
	qPod("mysql_backup_schedule_info", `mysql_backup_schedule_info`, "name", "namespace", "operator", "task", "schedule", "method"),
	qPod("mysql_backup_pitr_info", `mysql_backup_pitr_info`, "name", "namespace", "operator", "enabled"),
	qPod("mysql_cluster_status", `mysql_cluster_status`, "name", "namespace", "operator", "status"),
	qPod("mysql_backup_info", `mysql_backup_info`, "name", "namespace", "operator", "cluster", "method", "kind", "path"),
	qPod("mysql_backup_status", `mysql_backup_status`, "name", "namespace", "operator", "status"),
	qPod("mysql_backup_completed_timestamp_seconds", `mysql_backup_completed_timestamp_seconds`, "name", "namespace", "operator"),
}

var RecordingRules = map[string]func(db *db.DB, p *db.Project, w *model.World) []*model.MetricValues{
	qRecordingRuleApplicationLogMessages: func(db *db.DB, p *db.Project, w *model.World) []*model.MetricValues {
		var res []*model.MetricValues
		for _, app := range w.Applications {
			appId := app.Id.String()
			for severity, msgs := range app.LogMessages {
				if len(msgs.Patterns) == 0 {
					if msgs.Messages.Reduce(timeseries.NanSum) > 0 {
						ls := model.Labels{"application": appId, "level": severity.String()}
						res = append(res, &model.MetricValues{Labels: ls, LabelsHash: promModel.LabelsToSignature(ls), Values: msgs.Messages})
					}
				} else {
					for _, pattern := range msgs.Patterns {
						if pattern.Messages.Reduce(timeseries.NanSum) > 0 {
							ls := model.Labels{"application": appId, "level": severity.String()}
							ls["multiline"] = strconv.FormatBool(pattern.Multiline)
							ls["similar"] = strings.Join(pattern.SimilarPatternHashes.Items(), " ")
							ls["sample"] = pattern.Sample
							ls["words"] = pattern.Pattern.String()
							res = append(res, &model.MetricValues{Labels: ls, LabelsHash: promModel.LabelsToSignature(ls), Values: pattern.Messages})
						}
					}
				}
			}
		}
		return res
	},
	qRecordingRuleApplicationTCPSuccessful: func(db *db.DB, p *db.Project, w *model.World) []*model.MetricValues {
		return aggConnections(w, func(c *model.Connection) *timeseries.TimeSeries { return c.SuccessfulConnections })
	},
	qRecordingRuleApplicationTCPActive: func(db *db.DB, p *db.Project, w *model.World) []*model.MetricValues {
		return aggConnections(w, func(c *model.Connection) *timeseries.TimeSeries { return c.Active })
	},
	qRecordingRuleApplicationTCPFailed: func(db *db.DB, p *db.Project, w *model.World) []*model.MetricValues {
		return aggConnections(w, func(c *model.Connection) *timeseries.TimeSeries { return c.FailedConnections })
	},
	qRecordingRuleApplicationTCPConnectionTime: func(db *db.DB, p *db.Project, w *model.World) []*model.MetricValues {
		return aggConnections(w, func(c *model.Connection) *timeseries.TimeSeries { return c.ConnectionTime })
	},
	qRecordingRuleApplicationTCPBytesSent: func(db *db.DB, p *db.Project, w *model.World) []*model.MetricValues {
		return aggConnections(w, func(c *model.Connection) *timeseries.TimeSeries { return c.BytesSent })
	},
	qRecordingRuleApplicationTCPBytesReceived: func(db *db.DB, p *db.Project, w *model.World) []*model.MetricValues {
		return aggConnections(w, func(c *model.Connection) *timeseries.TimeSeries { return c.BytesReceived })
	},
	qRecordingRuleApplicationTCPRetransmissions: func(db *db.DB, p *db.Project, w *model.World) []*model.MetricValues {
		return aggConnections(w, func(c *model.Connection) *timeseries.TimeSeries { return c.Retransmissions })
	},

	qRecordingRuleApplicationNetLatency: func(db *db.DB, p *db.Project, w *model.World) []*model.MetricValues {
		var res []*model.MetricValues

		for _, app := range w.Applications {
			byDest := map[*model.Application][]*timeseries.TimeSeries{}
			for _, instance := range app.Instances {
				for _, u := range instance.Upstreams {
					dest := u.RemoteApplication()
					if dest == nil {
						continue
					}
					if !u.Rtt.IsEmpty() {
						byDest[dest] = append(byDest[dest], u.Rtt)
					}
				}
			}
			appId := app.Id.String()
			for dest, rtts := range byDest {
				sum := timeseries.NewAggregate(timeseries.NanSum).Add(rtts...).Get()
				count := timeseries.NewAggregate(timeseries.NanSum)
				for _, rtt := range rtts {
					count.Add(rtt.Map(timeseries.Defined))
				}
				ls := model.Labels{"app": appId, "dest": dest.Id.String(), "agg": "avg"}
				res = append(res, &model.MetricValues{Labels: ls, LabelsHash: promModel.LabelsToSignature(ls), Values: timeseries.Div(sum, count.Get())})
			}
		}
		return res
	},

	qRecordingRuleApplicationL7Requests: func(db *db.DB, p *db.Project, w *model.World) []*model.MetricValues {
		var res []*model.MetricValues
		type key struct {
			status   string
			protocol model.Protocol
			dest     *model.Application
		}

		for _, app := range w.Applications {
			byProtoStatus := map[key]*timeseries.Aggregate{}
			for _, instance := range app.Instances {
				for _, u := range instance.Upstreams {
					dest := u.RemoteApplication()
					if dest == nil {
						continue
					}
					for proto, byStatus := range u.RequestsCount {
						for status, ts := range byStatus {
							bucket := "ok"
							if model.IsRequestStatusFailed(status) {
								bucket = "failed"
							}
							k := key{dest: dest, status: bucket, protocol: proto}
							agg := byProtoStatus[k]
							if agg == nil {
								agg = timeseries.NewAggregate(timeseries.NanSum)
								byProtoStatus[k] = agg
							}
							agg.Add(ts)

						}
					}
				}
			}
			appId := app.Id.String()
			for k, agg := range byProtoStatus {
				ts := agg.Get()
				if !ts.IsEmpty() {
					ls := model.Labels{"app": appId, "dest": k.dest.Id.String(), "proto": string(k.protocol), "status": k.status}
					res = append(res, &model.MetricValues{Labels: ls, LabelsHash: promModel.LabelsToSignature(ls), Values: ts})
				}
			}
		}
		return res
	},

	qRecordingRuleApplicationL7Latency: func(db *db.DB, p *db.Project, w *model.World) []*model.MetricValues {
		var res []*model.MetricValues
		type key struct {
			protocol model.Protocol
			dest     *model.Application
		}

		for _, app := range w.Applications {
			byProto := map[key]*timeseries.Aggregate{}
			for _, instance := range app.Instances {
				for _, u := range instance.Upstreams {
					dest := u.RemoteApplication()
					if dest == nil {
						continue
					}
					for proto, ts := range u.RequestsLatency {
						k := key{dest: dest, protocol: proto}
						agg := byProto[k]
						if agg == nil {
							agg = timeseries.NewAggregate(timeseries.NanSum)
							byProto[k] = agg
						}
						agg.Add(ts)

					}
				}
			}
			appId := app.Id.String()
			for k, agg := range byProto {
				ts := agg.Get()
				if !ts.IsEmpty() {
					ls := model.Labels{"app": appId, "dest": k.dest.Id.String(), "proto": string(k.protocol)}
					res = append(res, &model.MetricValues{Labels: ls, LabelsHash: promModel.LabelsToSignature(ls), Values: ts})
				}
			}
		}
		return res
	},

	qRecordingRuleApplicationL7Histogram: func(db *db.DB, p *db.Project, w *model.World) []*model.MetricValues {
		var res []*model.MetricValues
		type key struct {
			le   float32
			dest *model.Application
		}
		sum := map[key]*timeseries.Aggregate{}
		for _, app := range w.Applications {
			for _, instance := range app.Instances {
				for _, u := range instance.Upstreams {
					dest := u.RemoteApplication()
					if dest == nil {
						continue
					}
					if !dest.Category.Auxiliary() && app.Category.Auxiliary() {
						continue
					}
					for _, byLe := range u.RequestsHistogram {
						for le, ts := range byLe {
							k := key{dest: dest, le: le}
							agg := sum[k]
							if agg == nil {
								agg = timeseries.NewAggregate(timeseries.NanSum)
								sum[k] = agg
							}
							agg.Add(ts)
						}
					}
				}
			}
		}
		for k, agg := range sum {
			ts := agg.Get()
			if !ts.IsEmpty() {
				ls := model.Labels{"app": k.dest.Id.String(), "le": fmt.Sprintf("%f", k.le)}
				res = append(res, &model.MetricValues{Labels: ls, LabelsHash: promModel.LabelsToSignature(ls), Values: ts})
			}
		}
		return res
	},

	qRecordingRuleApplicationL7InboundRequests: func(db *db.DB, p *db.Project, w *model.World) []*model.MetricValues {
		var res []*model.MetricValues
		for _, app := range w.Applications {
			appId := app.Id.String()
			byBucket := map[string]*timeseries.Aggregate{}
			for status, ts := range app.InboundRequestsCount {
				if ts.IsEmpty() {
					continue
				}
				bucket := "ok"
				if model.IsRequestStatusFailed(status) {
					bucket = "failed"
				}
				agg := byBucket[bucket]
				if agg == nil {
					agg = timeseries.NewAggregate(timeseries.NanSum)
					byBucket[bucket] = agg
				}
				agg.Add(ts)
			}
			for bucket, agg := range byBucket {
				ts := agg.Get()
				if ts.IsEmpty() {
					continue
				}
				ls := model.Labels{"app": appId, "status": bucket}
				res = append(res, &model.MetricValues{Labels: ls, LabelsHash: promModel.LabelsToSignature(ls), Values: ts})
			}
		}
		return res
	},

	qRecordingRuleApplicationL7InboundHistogram: func(db *db.DB, p *db.Project, w *model.World) []*model.MetricValues {
		var res []*model.MetricValues
		for _, app := range w.Applications {
			appId := app.Id.String()
			for le, ts := range app.InboundRequestsHistogram {
				if ts.IsEmpty() {
					continue
				}
				ls := model.Labels{"app": appId, "le": fmt.Sprintf("%f", le)}
				res = append(res, &model.MetricValues{Labels: ls, LabelsHash: promModel.LabelsToSignature(ls), Values: ts})
			}
		}
		return res
	},

	qRecordingRuleApplicationLLMInboundHistogram: func(db *db.DB, p *db.Project, w *model.World) []*model.MetricValues {
		var res []*model.MetricValues
		for _, app := range w.Applications {
			appId := app.Id.String()
			for le, ts := range app.InboundLLMRequestsHistogram {
				if ts.IsEmpty() {
					continue
				}
				ls := model.Labels{"app": appId, "le": fmt.Sprintf("%f", le)}
				res = append(res, &model.MetricValues{Labels: ls, LabelsHash: promModel.LabelsToSignature(ls), Values: ts})
			}
		}
		return res
	},

	qRecordingRuleApplicationDNSRequests: func(db *db.DB, p *db.Project, w *model.World) []*model.MetricValues {
		var res []*model.MetricValues
		for _, app := range w.Applications {
			appId := app.Id.String()
			for r, byStatus := range app.DNSRequests {
				for status, ts := range byStatus {
					if ts.IsEmpty() {
						continue
					}
					ls := model.Labels{"app": appId, "request_type": r.Type, "domain": r.Domain, "status": status}
					res = append(res, &model.MetricValues{Labels: ls, LabelsHash: promModel.LabelsToSignature(ls), Values: ts})
				}
			}
		}
		return res
	},

	qRecordingRuleApplicationDNSLatency: func(db *db.DB, p *db.Project, w *model.World) []*model.MetricValues {
		var res []*model.MetricValues
		for _, app := range w.Applications {
			appId := app.Id.String()
			for le, ts := range app.DNSRequestsHistogram {
				if ts.IsEmpty() {
					continue
				}
				ls := model.Labels{"app": appId, "le": fmt.Sprintf("%f", le)}
				res = append(res, &model.MetricValues{Labels: ls, LabelsHash: promModel.LabelsToSignature(ls), Values: ts})
			}
		}
		return res
	},

	qRecordingRuleApplicationTraffic: func(db *db.DB, p *db.Project, w *model.World) []*model.MetricValues {
		var res []*model.MetricValues

		for _, app := range w.Applications {
			appId := app.Id.String()
			if ts := app.TrafficStats.InternetEgress.Get(); !ts.IsEmpty() {
				ls := model.Labels{"app": appId, "kind": string(model.TrafficKindInternetEgress)}
				res = append(res, &model.MetricValues{Labels: ls, LabelsHash: promModel.LabelsToSignature(ls), Values: ts})
			}
			if ts := app.TrafficStats.CrossAZEgress.Get(); !ts.IsEmpty() {
				ls := model.Labels{"app": appId, "kind": string(model.TrafficKindCrossAZEgress)}
				res = append(res, &model.MetricValues{Labels: ls, LabelsHash: promModel.LabelsToSignature(ls), Values: ts})
			}
			if ts := app.TrafficStats.CrossAZIngress.Get(); !ts.IsEmpty() {
				ls := model.Labels{"app": appId, "kind": string(model.TrafficKindCrossAZIngress)}
				res = append(res, &model.MetricValues{Labels: ls, LabelsHash: promModel.LabelsToSignature(ls), Values: ts})
			}
		}
		return res
	},

	qRecordingRuleApplicationCategories: func(database *db.DB, p *db.Project, w *model.World) []*model.MetricValues {
		var needSave bool
		for _, app := range w.Applications {
			if _, ok := p.Settings.ApplicationCategorySettings[app.Category]; !ok {
				if p.Settings.ApplicationCategorySettings == nil {
					p.Settings.ApplicationCategorySettings = map[model.ApplicationCategory]*db.ApplicationCategorySettings{}
				}
				p.Settings.ApplicationCategorySettings[app.Category] = nil
				needSave = true
			}
		}
		if needSave {
			if err := database.SaveProjectSettings(p); err != nil {
				klog.Errorln("failed to save project settings:", err)
			}
		}
		return nil
	},

	qRecordingRuleApplicationSLO: func(database *db.DB, p *db.Project, w *model.World) []*model.MetricValues {
		for _, app := range w.Applications {
			updateAvailabilitySLOFromAnnotations(database, p, w, app)
			latencyCfg, _ := w.CheckConfigs.GetLatency(app.Id, app.Category)
			updateLatencySLOFromAnnotations(database, p, app, model.Checks.SLOLatency, latencyCfg, model.ApplicationAnnotationSLOLatencyObjective, model.ApplicationAnnotationSLOLatencyThreshold, model.DefaultHistogramBuckets)
			llmLatencyCfg, _ := w.CheckConfigs.GetLLMLatency(app.Id)
			updateLatencySLOFromAnnotations(database, p, app, model.Checks.SLOLLMLatency, llmLatencyCfg, model.ApplicationAnnotationSLOLLMLatencyObjective, model.ApplicationAnnotationSLOLLMLatencyThreshold, model.LLMHistogramBuckets)
		}
		return nil
	},
	qRecordingRuleApplicationExternalEndpoint: func(db *db.DB, p *db.Project, w *model.World) []*model.MetricValues {
		var res []*model.MetricValues
		if w.Ctx.PointsCount() < 1 {
			return res
		}
		values := make([]float32, w.Ctx.PointsCount())
		for i := range values {
			values[i] = 1
		}
		ts := timeseries.NewWithData(w.Ctx.From, w.Ctx.Step, values)
		for _, app := range w.Applications {
			byDest := map[model.ApplicationId]*utils.StringSet{}
			for _, instance := range app.Instances {
				for _, u := range instance.Upstreams {
					dest := u.RemoteApplication()
					if dest == nil || dest.Id.Kind != model.ApplicationKindExternalService {
						continue
					}

					endpoints := byDest[dest.Id]
					if endpoints == nil {
						endpoints = utils.NewStringSet()
						byDest[dest.Id] = endpoints
					}
					if u.ActualRemoteIP != "" {
						endpoints.Add(net.JoinHostPort(u.ActualRemoteIP, u.ActualRemotePort))
					} else if u.ServiceRemoteIP != "" { // failed connections have no actual destination
						endpoints.Add(net.JoinHostPort(u.ServiceRemoteIP, u.ServiceRemotePort))
					}
				}
			}
			appId := app.Id.String()
			for destId, endpoints := range byDest {
				for _, ep := range endpoints.Items() {
					ls := model.Labels{"app": appId, "dest": destId.String(), model.LabelActualDestination: ep}
					res = append(res, &model.MetricValues{Labels: ls, LabelsHash: promModel.LabelsToSignature(ls), Values: ts})
				}
			}
		}
		return res
	},
}

func aggConnections(w *model.World, tsF func(c *model.Connection) *timeseries.TimeSeries) []*model.MetricValues {
	var res []*model.MetricValues
	for _, app := range w.Applications {
		byDest := map[*model.Application]*timeseries.Aggregate{}
		for _, instance := range app.Instances {
			for _, u := range instance.Upstreams {
				dest := u.RemoteApplication()
				if dest == nil {
					continue
				}
				agg := byDest[dest]
				if agg == nil {
					agg = timeseries.NewAggregate(timeseries.NanSum)
					byDest[dest] = agg
				}
				agg.Add(tsF(u))
			}
		}
		appId := app.Id.String()
		for dest, agg := range byDest {
			ts := agg.Get()
			if !ts.IsEmpty() {
				ls := model.Labels{"app": appId, "dest": dest.Id.String()}
				res = append(res, &model.MetricValues{Labels: ls, LabelsHash: promModel.LabelsToSignature(ls), Values: ts})
			}
		}
	}
	return res
}

func updateAvailabilitySLOFromAnnotations(database *db.DB, p *db.Project, w *model.World, app *model.Application) {
	objectiveStr := app.GetAnnotation(model.ApplicationAnnotationSLOAvailabilityObjective)
	cfg, _ := w.CheckConfigs.GetAvailability(app.Id)
	if objectiveStr == "" {
		return
	}
	cfgSaved := cfg
	cfg.Source = model.CheckConfigSourceKubernetesAnnotations
	cfg.Custom = false
	cfg.Error = ""
	objective, err := parseObjective(objectiveStr)
	if err != nil {
		cfg.Error = fmt.Sprintf("Invalid annotation 'coroot.com/slo-availability-objective': %s", err)
	}
	if cfg.Error != "" {
		cfg.ObjectivePercentage = 0 // disable
	} else {
		cfg.ObjectivePercentage = objective
	}
	if cfg == cfgSaved {
		return
	}
	if err = database.SaveCheckConfig(p.Id, app.Id, model.Checks.SLOAvailability.Id, []model.CheckConfigSLOAvailability{cfg}); err != nil {
		klog.Errorln(err)
	}
}

func updateLatencySLOFromAnnotations(database *db.DB, p *db.Project, app *model.Application, check model.CheckConfig, cfg model.CheckConfigSLOLatency,
	objectiveAnnotation, thresholdAnnotation model.ApplicationAnnotation, buckets []float32) {
	objectiveStr := app.GetAnnotation(objectiveAnnotation)
	thresholdStr := app.GetAnnotation(thresholdAnnotation)
	if objectiveStr == "" && thresholdStr == "" {
		return
	}
	cfgSaved := cfg
	cfg.Source = model.CheckConfigSourceKubernetesAnnotations
	cfg.Custom = false
	cfg.Error = ""
	var err error
	objective := cfg.ObjectivePercentage
	threshold := cfg.ObjectiveBucket
	if objectiveStr != "" {
		objective, err = parseObjective(objectiveStr)
		if err != nil {
			cfg.Error = fmt.Sprintf("Invalid annotation 'coroot.com/%s': %s", strings.ReplaceAll(string(objectiveAnnotation), "_", "-"), err)
		}
	}
	if objective > 0 && thresholdStr != "" {
		threshold, err = parseThreshold(thresholdStr, buckets)
		if err != nil && cfg.Error == "" {
			cfg.Error = fmt.Sprintf("Invalid annotation 'coroot.com/%s': %s", strings.ReplaceAll(string(thresholdAnnotation), "_", "-"), err)
		}
	}
	if cfg.Error != "" {
		cfg.ObjectivePercentage = 0 // disable
	} else {
		cfg.ObjectivePercentage = objective
		cfg.ObjectiveBucket = threshold
	}
	if cfg == cfgSaved {
		return
	}
	if err = database.SaveCheckConfig(p.Id, app.Id, check.Id, []model.CheckConfigSLOLatency{cfg}); err != nil {
		klog.Errorln(err)
	}
}

func parseObjective(s string) (float32, error) {
	s = strings.TrimSpace(strings.TrimRight(strings.TrimSpace(s), "%"))
	v, err := strconv.ParseFloat(s, 32)
	return float32(v), err
}

func parseThreshold(s string, buckets []float32) (float32, error) {
	d, err := time.ParseDuration(strings.TrimSpace(s))
	if err != nil {
		return 0, err
	}
	v := model.RoundUpToBucket(float32(d.Seconds()), buckets)
	return v, err
}