apiVersion: v1 kind: ConfigMap metadata: name: vector-config namespace: {{ .Release.Namespace }} labels: app: vector data: vector.toml: | # Vector config adapted from Log.md [sources.kubernetes_logs] type = "kubernetes_logs" include_namespaces = ["{{ .Values.vector.namespace }}"] # read pod/container logs under /var/log/pods host_path = "/var/log" [transforms.parse_json] type = "remap" inputs = ["kubernetes_logs"] source = ''' parsed = parse_json!(.message) .ts = parsed.ts .level = parsed.level .app = parsed.app .env = parsed.env .traceId = parsed.traceId .uri = parsed.uri .uri_group = parsed.uri_group .duration_ms = to_int!(parsed.duration, 0) .userId = parsed.userId .event = parsed.event .error = parsed.error .status = parsed.status .event_class = parsed.event_class # fallback derive event_class from uri_group if starts_with(.uri_group, "/order") { .event_class = "order" } else if starts_with(.uri_group, "/payment") { .event_class = "payment" } else if !exists(.event_class) { .event_class = "api" } # keep kubernetes metadata as labels fields .k8s_ns = .kubernetes.namespace_name .k8s_pod = .kubernetes.pod_name .k8s_labels = .kubernetes.labels ''' [transforms.filter_services] type = "filter" inputs = ["parse_json"] # keep only selected apps (based on k8s labels.app or parsed .app) condition = '(.kubernetes.labels.app in {{ toJson .Values.vector.logSelector }}) || (.app in {{ toJson .Values.vector.logSelector }})' [transforms.filter_levels] type = "filter" inputs = ["filter_services"] condition = '.level != "DEBUG" && .level != "TRACE"' [sinks.loki] type = "loki" inputs = ["filter_levels"] endpoint = "{{ .Values.vector.loki.endpoint }}" encoding.codec = "json" [sinks.loki.labels] env = "{{ env }}" app = "{{ app }}" level = "{{ level }}" event_class = "{{ event_class }}" uri_group = "{{ uri_group }}" status = "{{ status }}" [transforms.to_metrics] type = "log_to_metric" inputs = ["filter_levels"] # Counter: Total requests per app/uri_group/status [[transforms.to_metrics.metrics]] type = "counter" field = "message" name = "requests_total" tags.app = "{{ app }}" tags.env = "{{ env }}" tags.uri_group = "{{ uri_group }}" # Counter: HTTP request errors [[transforms.to_metrics.metrics]] type = "counter" field = "message" name = "requests_errors_total" filter.condition = '.status == "server_error" || .status == "client_error"' tags.app = "{{ app }}" tags.env = "{{ env }}" tags.status = "{{ status }}" # Histogram: Request duration (latency) [[transforms.to_metrics.metrics]] type = "histogram" field = "duration_ms" name = "request_duration_ms" tags.app = "{{ app }}" tags.uri_group = "{{ uri_group }}" tags.env = "{{ env }}" # Counter: Total orders [[transforms.to_metrics.metrics]] type = "counter" field = "message" name = "orders_total" filter.condition = '.event_class == "order"' tags.app = "{{ app }}" tags.env = "{{ env }}" # Counter: Failed orders [[transforms.to_metrics.metrics]] type = "counter" field = "message" name = "orders_failed_total" filter.condition = '.event_class == "order" && (.status == "server_error" || .status == "client_error")' tags.app = "{{ app }}" tags.env = "{{ env }}" # Counter: Payment events [[transforms.to_metrics.metrics]] type = "counter" field = "message" name = "payment_events_total" filter.condition = '.event_class == "payment"' tags.app = "{{ app }}" tags.env = "{{ env }}" [sinks.prometheus] type = "prometheus_exporter" inputs = ["to_metrics"] address = "{{ .Values.vector.prometheus.exporterAddress }}" default_namespace = "shop_recycle"