Skip to content

Commit

Permalink
Cluster Events and Node Log Updates (#1016)
Browse files Browse the repository at this point in the history
* Additional Cluster Events Processing

- Extracted default values from Cluster Events using logfmt
- Added static label source=kubernetes-events
- Added labelsToKeep support
- Added structuredMetadata support

* Normalized extraLogProcessingStages

Changed extraProcessingStages to extraLogProcessingStages for consistency across charts

* Additional Cluster Events Processing

- Extracted all systemd unit service discovery labels
- Added static label source=journal
- Added labelsToKeep support
- Added structuredMetadata support
- Determine log level

* Fixed Cluster Events Test and Rebuilt

* Add the ability to use a caFile in tls sections (#1013)

Signed-off-by: Pete Wall <[email protected]>

* Improved validators for OpenCost prometheus URLs and basic auth (#1012)

* Improved validators for OpenCost prometheus URLs and basic auth

Signed-off-by: Pete Wall <[email protected]>

* Sync the helpers template

Signed-off-by: Pete Wall <[email protected]>

---------

Signed-off-by: Pete Wall <[email protected]>

* Additional Cluster Events Processing

- Extracted default values from Cluster Events using logfmt
- Added static label source=kubernetes-events
- Added labelsToKeep support
- Added structuredMetadata support

* Sync'd and Rebuilt

* Scyn'd and Rebuilt

* Resolved Conflicts

* Regenerated Cluster Events Documentation

* Fixed Documentation and Unit Test

---------

Signed-off-by: Pete Wall <[email protected]>
Co-authored-by: Pete Wall <[email protected]>
  • Loading branch information
bentonam and petewall committed Dec 19, 2024
1 parent e72c4e4 commit 4b81a03
Show file tree
Hide file tree
Showing 51 changed files with 2,822 additions and 85 deletions.
4 changes: 3 additions & 1 deletion charts/feature-cluster-events/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,9 @@ Be sure perform actual integration testing in a live environment in the main [k8

| Key | Type | Default | Description |
|-----|------|---------|-------------|
| extraProcessingStages | string | `""` | Stage blocks to be added to the loki.process component for cluster events. ([docs](https://grafana.com/docs/alloy/latest/reference/components/loki/loki.process/#blocks)) This value is templated so that you can refer to other values from this file. |
| extraLogProcessingStages | string | `""` | Stage blocks to be added to the loki.process component for cluster events. ([docs](https://grafana.com/docs/alloy/latest/reference/components/loki/loki.process/#blocks)) This value is templated so that you can refer to other values from this file. |
| labelsToKeep | list | `["job","level","namespace","node","source"]` | The list of labels to keep on the logs, all other pipeline labels will be dropped. |
| structuredMetadata | object | `{}` | The structured metadata mappings to set. To not set any structured metadata, set this to an empty object (e.g. `{}`) Format: `<key>: <extracted_key>`. Example: structuredMetadata: component: component kind: kind name: name |

### General settings

Expand Down
89 changes: 86 additions & 3 deletions charts/feature-cluster-events/templates/_module.alloy.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,96 @@ declare "cluster_events" {
{{- if .Values.namespaces }}
namespaces = {{ .Values.namespaces | toJson }}
{{- end }}
{{- if .Values.extraProcessingStages }}
forward_to = [loki.process.cluster_events.receiver]
}

loki.process "cluster_events" {
{{ .Values.extraProcessingStages | indent 4 }}
{{- end }}
// add a static source label to the logs so they can be differentiated / restricted if necessary
stage.static_labels {
values = {
"source" = "kubernetes-events",
}
}

// extract some of the fields from the log line, these could be used as labels, structured metadata, etc.
{{- if eq .Values.logFormat "json" }}
stage.json {
expressions = {
"component" = "sourcecomponent", // map the sourcecomponent field to component
"kind" = "",
"level" = "type", // most events don't have a level but they do have a "type" i.e. Normal, Warning, Error, etc.
"name" = "",
"node" = "sourcehost", // map the sourcehost field to node
}
}
{{- else }}
stage.logfmt {
mapping = {
"component" = "sourcecomponent", // map the sourcecomponent field to component
"kind" = "",
"level" = "type", // most events don't have a level but they do have a "type" i.e. Normal, Warning, Error, etc.
"name" = "",
"node" = "sourcehost", // map the sourcehost field to node
}
}
{{- end }}
// set these values as labels, they may or may not be used as index labels in Loki as they can be dropped
// prior to being written to Loki, but this makes them available
stage.labels {
values = {
"component" = "",
"kind" = "",
"level" = "",
"name" = "",
"node" = "",
}
}

// if kind=Node, set the node label by copying the instance label
stage.match {
selector = "{kind=\"Node\"}"
stage.labels {
values = {
"node" = "name",
}
}
}

// set the level extracted key value as a normalized log level
stage.match {
selector = "{level=\"Normal\"}"
stage.static_labels {
values = {
level = "Info",
}
}
}

{{- if .Values.extraLogProcessingStages }}
{{ tpl .Values.extraLogProcessingStages $ | indent 4 }}
{{ end }}

{{- /* the stage.structured_metadata block needs to be conditionalized because the support for enabling structured metadata can be disabled */ -}}
{{- /* through the loki limits_conifg on a per-tenant basis, even if there are no values defined or there are values defined but it is disabled */ -}}
{{- /* in Loki, the write will fail. */ -}}
{{- if gt (len (keys .Values.structuredMetadata)) 0 }}
// set the structured metadata values
stage.structured_metadata {
values = {
{{- range $key, $value := .Values.structuredMetadata }}
{{ $key | quote }} = {{ if $value }}{{ $value | quote }}{{ else }}{{ $key | quote }}{{ end }},
{{- end }}
}
}
{{- end }}

// Only keep the labels that are defined in the `keepLabels` list.
stage.label_keep {
values = {{ .Values.labelsToKeep | toJson }}
}
forward_to = argument.logs_destinations.value
}
}
Expand Down
62 changes: 61 additions & 1 deletion charts/feature-cluster-events/tests/default_test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,70 @@ tests:
argument "logs_destinations" {
comment = "Must be a list of log destinations where collected logs should be forwarded to"
}
loki.source.kubernetes_events "cluster_events" {
job_name = "integrations/kubernetes/eventhandler"
log_format = "logfmt"
forward_to = [loki.process.cluster_events.receiver]
}
loki.process "cluster_events" {
// add a static source label to the logs so they can be differentiated / restricted if necessary
stage.static_labels {
values = {
"source" = "kubernetes-events",
}
}
// extract some of the fields from the log line, these could be used as labels, structured metadata, etc.
stage.logfmt {
mapping = {
"component" = "sourcecomponent", // map the sourcecomponent field to component
"kind" = "",
"level" = "type", // most events don't have a level but they do have a "type" i.e. Normal, Warning, Error, etc.
"name" = "",
"node" = "sourcehost", // map the sourcehost field to node
}
}
// set these values as labels, they may or may not be used as index labels in Loki as they can be dropped
// prior to being written to Loki, but this makes them available
stage.labels {
values = {
"component" = "",
"kind" = "",
"level" = "",
"name" = "",
"node" = "",
}
}
// if kind=Node, set the node label by copying the instance label
stage.match {
selector = "{kind=\"Node\"}"
stage.labels {
values = {
"node" = "name",
}
}
}
// set the level extracted key value as a normalized log level
stage.match {
selector = "{level=\"Normal\"}"
stage.static_labels {
values = {
level = "Info",
}
}
}
// Only keep the labels that are defined in the `keepLabels` list.
stage.label_keep {
values = ["job","level","namespace","node","source"]
}
forward_to = argument.logs_destinations.value
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@ suite: Test extra processing stages
templates:
- configmap.yaml
tests:
- it: should create a ConfigMap
- it: should create a ConfigMap with extra processing stages
set:
deployAsConfigMap: true
extraProcessingStages: |-
extraLogProcessingStages: |-
stage.drop {
source = "namespace"
value = "private"
Expand All @@ -21,18 +21,75 @@ tests:
argument "logs_destinations" {
comment = "Must be a list of log destinations where collected logs should be forwarded to"
}
loki.source.kubernetes_events "cluster_events" {
job_name = "integrations/kubernetes/eventhandler"
log_format = "logfmt"
forward_to = [loki.process.cluster_events.receiver]
}
loki.process "cluster_events" {
stage.drop {
// add a static source label to the logs so they can be differentiated / restricted if necessary
stage.static_labels {
values = {
"source" = "kubernetes-events",
}
}
// extract some of the fields from the log line, these could be used as labels, structured metadata, etc.
stage.logfmt {
mapping = {
"component" = "sourcecomponent", // map the sourcecomponent field to component
"kind" = "",
"level" = "type", // most events don't have a level but they do have a "type" i.e. Normal, Warning, Error, etc.
"name" = "",
"node" = "sourcehost", // map the sourcehost field to node
}
}
// set these values as labels, they may or may not be used as index labels in Loki as they can be dropped
// prior to being written to Loki, but this makes them available
stage.labels {
values = {
"component" = "",
"kind" = "",
"level" = "",
"name" = "",
"node" = "",
}
}
// if kind=Node, set the node label by copying the instance label
stage.match {
selector = "{kind=\"Node\"}"
stage.labels {
values = {
"node" = "name",
}
}
}
// set the level extracted key value as a normalized log level
stage.match {
selector = "{level=\"Normal\"}"
stage.static_labels {
values = {
level = "Info",
}
}
}
stage.drop {
source = "namespace"
value = "private"
}
// Only keep the labels that are defined in the `keepLabels` list.
stage.label_keep {
values = ["job","level","namespace","node","source"]
}
forward_to = argument.logs_destinations.value
}
}
92 changes: 92 additions & 0 deletions charts/feature-cluster-events/tests/labels_test.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
# yamllint disable rule:document-start rule:line-length rule:trailing-spaces
suite: Test namespaces
templates:
- configmap.yaml
tests:
- it: should create a ConfigMap that sets custom labels to keep
set:
deployAsConfigMap: true
labelsToKeep:
- job
- namespace
- level
- node
- name
- source
asserts:
- isKind:
of: ConfigMap
- equal:
path: data["module.alloy"]
value: |-
declare "cluster_events" {
argument "logs_destinations" {
comment = "Must be a list of log destinations where collected logs should be forwarded to"
}
loki.source.kubernetes_events "cluster_events" {
job_name = "integrations/kubernetes/eventhandler"
log_format = "logfmt"
forward_to = [loki.process.cluster_events.receiver]
}
loki.process "cluster_events" {
// add a static source label to the logs so they can be differentiated / restricted if necessary
stage.static_labels {
values = {
"source" = "kubernetes-events",
}
}
// extract some of the fields from the log line, these could be used as labels, structured metadata, etc.
stage.logfmt {
mapping = {
"component" = "sourcecomponent", // map the sourcecomponent field to component
"kind" = "",
"level" = "type", // most events don't have a level but they do have a "type" i.e. Normal, Warning, Error, etc.
"name" = "",
"node" = "sourcehost", // map the sourcehost field to node
}
}
// set these values as labels, they may or may not be used as index labels in Loki as they can be dropped
// prior to being written to Loki, but this makes them available
stage.labels {
values = {
"component" = "",
"kind" = "",
"level" = "",
"name" = "",
"node" = "",
}
}
// if kind=Node, set the node label by copying the instance label
stage.match {
selector = "{kind=\"Node\"}"
stage.labels {
values = {
"node" = "name",
}
}
}
// set the level extracted key value as a normalized log level
stage.match {
selector = "{level=\"Normal\"}"
stage.static_labels {
values = {
level = "Info",
}
}
}
// Only keep the labels that are defined in the `keepLabels` list.
stage.label_keep {
values = ["job","namespace","level","node","name","source"]
}
forward_to = argument.logs_destinations.value
}
}
Loading

0 comments on commit 4b81a03

Please sign in to comment.