You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@skywalking.apache.org by ke...@apache.org on 2021/05/13 14:49:57 UTC

[skywalking-kubernetes-event-exporter] branch enhance created (now dfd6050)

This is an automated email from the ASF dual-hosted git repository.

kezhenxu94 pushed a change to branch enhance
in repository https://gitbox.apache.org/repos/asf/skywalking-kubernetes-event-exporter.git.


      at dfd6050  Add Console exporter, source filter

This branch includes the following new commits:

     new dfd6050  Add Console exporter, source filter

The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


[skywalking-kubernetes-event-exporter] 01/01: Add Console exporter, source filter

Posted by ke...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

kezhenxu94 pushed a commit to branch enhance
in repository https://gitbox.apache.org/repos/asf/skywalking-kubernetes-event-exporter.git

commit dfd605022755bf08185f592583ec65d18389ccdf
Author: kezhenxu94 <ke...@apache.org>
AuthorDate: Thu May 13 22:49:21 2021 +0800

    Add Console exporter, source filter
---
 README.md                                         |   4 +
 assets/default-config.yaml                        |   9 +-
 configs/config.go                                 |  17 ++-
 docs/exporters.md                                 |  14 +++
 assets/default-config.yaml => examples/debug.yaml |  14 +--
 pkg/exporter/console.go                           | 121 ++++++++++++++++++++++
 pkg/exporter/skywalking.go                        |   5 +-
 7 files changed, 168 insertions(+), 16 deletions(-)

diff --git a/README.md b/README.md
index eccc635..fd90561 100644
--- a/README.md
+++ b/README.md
@@ -20,6 +20,10 @@ specified in the command line interface nor config map created in Kubernetes.
 All available configuration items and their documentations can be found
 in [the default configuration file](assets/default-config.yaml).
 
+## Exporters
+
+The available exporters are listed [here](docs/exporters.md).
+
 ## Deployments
 
 Go to [the /deployments/release](deployments/release) directory, modify according to your needs, and
diff --git a/assets/default-config.yaml b/assets/default-config.yaml
index 11bde2a..27753d3 100644
--- a/assets/default-config.yaml
+++ b/assets/default-config.yaml
@@ -17,14 +17,15 @@
 #
 
 filters:
-  - reason: ""     # filter events of the specified reason, regular expression like "Killing|Killed" is supported.
+  - reason: "Started|Killing"     # filter events of the specified reason, regular expression like "Killing|Killed" is supported.
     message: ""    # filter events of the specified message, regular expression like "Pulling container.*" is supported.
     minCount: 1    # filter events whose count is >= the specified value.
     type: ""       # filter events of the specified type, regular expression like "Normal|Error" is supported.
     action: ""     # filter events of the specified action, regular expression is supported.
-    kind: ""       # filter events of the specified kind, regular expression like "Pod|Service" is supported.
-    namespace: ""  # filter events from the specified namespace, regular expression like "default|bookinfo" is supported, empty means all namespaces.
-    name: ""       # filter events from the specified namespace, regular expression like ".*bookinfo.*" is supported.
+    kind: "Pod|Service"       # filter events of the specified kind, regular expression like "Pod|Service" is supported.
+    namespace: "default"  # filter events from the specified namespace, regular expression like "default|bookinfo" is supported, empty means all namespaces.
+    name: ""       # filter events of the specified involved object name, regular expression like ".*bookinfo.*" is supported.
+    service: "[^\\s]{1,}"  # filter events belonging to services whose name is not empty.
     exporters:     # events satisfy this filter can be exported into several exporters that are defined in the `exporters` section below.
       - skywalking
 
diff --git a/configs/config.go b/configs/config.go
index 04558dd..7243776 100644
--- a/configs/config.go
+++ b/configs/config.go
@@ -21,7 +21,9 @@ package configs
 
 import (
 	"regexp"
+	"strings"
 
+	"github.com/apache/skywalking-kubernetes-event-exporter/pkg/k8s"
 	"gopkg.in/yaml.v3"
 	v1 "k8s.io/api/core/v1"
 
@@ -46,6 +48,8 @@ type FilterConfig struct {
 	namespaceRegExp *regexp.Regexp
 	Name            string `yaml:"name"`
 	nameRegExp      *regexp.Regexp
+	Service         string `yaml:"service"`
+	serviceRegExp   *regexp.Regexp
 
 	Exporters []string `yaml:"exporters"`
 }
@@ -60,6 +64,7 @@ func (filter *FilterConfig) Init() {
 	filter.kindRegExp = regexp.MustCompile(filter.Kind)
 	filter.namespaceRegExp = regexp.MustCompile(filter.Namespace)
 	filter.nameRegExp = regexp.MustCompile(filter.Name)
+	filter.serviceRegExp = regexp.MustCompile(filter.Service)
 }
 
 // Filter the given event with this filter instance.
@@ -83,15 +88,21 @@ func (filter *FilterConfig) Filter(event *v1.Event) bool {
 	if filter.Action != "" && !filter.actionRegExp.MatchString(event.Action) {
 		return true
 	}
-	if filter.Kind != "" && !filter.kindRegExp.MatchString(event.Kind) {
+	if filter.Kind != "" && !filter.kindRegExp.MatchString(event.InvolvedObject.Kind) {
 		return true
 	}
-	if filter.Namespace != "" && !filter.namespaceRegExp.MatchString(event.Namespace) {
+	if filter.Namespace != "" && !filter.namespaceRegExp.MatchString(event.InvolvedObject.Namespace) {
 		return true
 	}
-	if filter.Name != "" && !filter.nameRegExp.MatchString(event.Name) {
+	if filter.Name != "" && !filter.nameRegExp.MatchString(event.InvolvedObject.Name) {
 		return true
 	}
+	if filter.Service != "" {
+		context := k8s.Registry.GetContext(event)
+		if svcName := strings.TrimSpace(context.Service.Name); !filter.serviceRegExp.MatchString(svcName) {
+			return true
+		}
+	}
 	return false
 }
 
diff --git a/docs/exporters.md b/docs/exporters.md
new file mode 100644
index 0000000..b0fedd3
--- /dev/null
+++ b/docs/exporters.md
@@ -0,0 +1,14 @@
+# Exporters
+
+## SkyWalking
+
+[SkyWalking Exporter](../pkg/exporter/skywalking.go) exports the events into Apache SkyWalking OAP server.
+
+The configurations of SkyWalking Exporter can be found [here](../assets/default-config.yaml).
+
+## Console
+
+[Console Exporter](../pkg/exporter/console.go) exports the events into console logs, this exporter is typically used for
+debugging.
+
+The configurations of Console Exporter can be found [here](../assets/default-config.yaml).
diff --git a/assets/default-config.yaml b/examples/debug.yaml
similarity index 71%
copy from assets/default-config.yaml
copy to examples/debug.yaml
index 11bde2a..603867d 100644
--- a/assets/default-config.yaml
+++ b/examples/debug.yaml
@@ -17,19 +17,20 @@
 #
 
 filters:
-  - reason: ""     # filter events of the specified reason, regular expression like "Killing|Killed" is supported.
+  - reason: "Started|Killing"     # filter events of the specified reason, regular expression like "Killing|Killed" is supported.
     message: ""    # filter events of the specified message, regular expression like "Pulling container.*" is supported.
     minCount: 1    # filter events whose count is >= the specified value.
     type: ""       # filter events of the specified type, regular expression like "Normal|Error" is supported.
     action: ""     # filter events of the specified action, regular expression is supported.
-    kind: ""       # filter events of the specified kind, regular expression like "Pod|Service" is supported.
-    namespace: ""  # filter events from the specified namespace, regular expression like "default|bookinfo" is supported, empty means all namespaces.
-    name: ""       # filter events from the specified namespace, regular expression like ".*bookinfo.*" is supported.
+    kind: "Pod|Service"       # filter events of the specified kind, regular expression like "Pod|Service" is supported.
+    namespace: "default"  # filter events from the specified namespace, regular expression like "default|bookinfo" is supported, empty means all namespaces.
+    name: ""       # filter events of the specified involved object name, regular expression like ".*bookinfo.*" is supported.
+    service: "[^\\s]{1,}"  # filter events belonging to services whose name is not empty.
     exporters:     # events satisfy this filter can be exported into several exporters that are defined in the `exporters` section below.
-      - skywalking
+      - console
 
 exporters:         # defines and configures the exporters that can be used in the `filters` section above.
-  skywalking:      # the exporter name, which is declared in the struct type `Exporter`'s Name function.
+  console:      # the exporter name, which is declared in the struct type `Exporter`'s Name function.
     # Below are exporter-specific configurations, different exporter may have different configuration contents.
     template:      # the event template of SkyWalking exporter, it can be composed of metadata like Event, Pod, and Service.
       source:
@@ -37,4 +38,3 @@ exporters:         # defines and configures the exporters that can be used in th
         serviceInstance: "{{ .Pod.Name }}"
         endpoint: ""
       message: "{{ .Event.Message }}" # this is default, just to demonstrate the context
-    address: "127.0.0.1:11800" # the SkyWalking backend address where this exporter will export to.
diff --git a/pkg/exporter/console.go b/pkg/exporter/console.go
new file mode 100644
index 0000000..05a5b1f
--- /dev/null
+++ b/pkg/exporter/console.go
@@ -0,0 +1,121 @@
+/*
+ * Licensed to Apache Software Foundation (ASF) under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Apache Software Foundation (ASF) licenses this file to you under
+ * the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package exporter
+
+import (
+	"encoding/json"
+	"fmt"
+	sw "skywalking.apache.org/repo/goapi/collect/event/v3"
+
+	k8score "k8s.io/api/core/v1"
+
+	"github.com/apache/skywalking-kubernetes-event-exporter/configs"
+	"github.com/apache/skywalking-kubernetes-event-exporter/internal/pkg/logger"
+	"github.com/apache/skywalking-kubernetes-event-exporter/pkg/event"
+)
+
+// Console Exporter exports the events into console logs, this exporter is typically
+// used for debugging.
+type Console struct {
+	config  ConsoleConfig
+	stopper chan struct{}
+}
+
+type ConsoleConfig struct {
+	Template *EventTemplate `mapstructure:"template"`
+}
+
+func init() {
+	s := &Console{
+		stopper: make(chan struct{}),
+	}
+	RegisterExporter(s.Name(), s)
+}
+
+func (exporter *Console) Init() error {
+	config := ConsoleConfig{}
+
+	if c := configs.GlobalConfig.Exporters[exporter.Name()]; c == nil {
+		return fmt.Errorf("configs of %+v exporter cannot be empty", exporter.Name())
+	} else if marshal, err := json.Marshal(c); err != nil {
+		return err
+	} else if err := json.Unmarshal(marshal, &config); err != nil {
+		return err
+	}
+
+	if err := config.Template.Init(); err != nil {
+		return err
+	}
+
+	exporter.config = config
+
+	return nil
+}
+
+func (exporter *Console) Name() string {
+	return "console"
+}
+
+func (exporter *Console) Export(events chan *k8score.Event) {
+	logger.Log.Debugf("exporting events into %+v", exporter.Name())
+
+	func() {
+		for {
+			select {
+			case <-exporter.stopper:
+				drain(events)
+				return
+			case kEvent := <-events:
+				if kEvent == event.Stopper {
+					return
+				}
+				logger.Log.Debugf("exporting event to %v: %v", exporter.Name(), kEvent)
+
+				t := sw.Type_Normal
+				if kEvent.Type == "Warning" {
+					t = sw.Type_Error
+				}
+				swEvent := &sw.Event{
+					Uuid:      string(kEvent.UID),
+					Source:    &sw.Source{},
+					Name:      kEvent.Reason,
+					Type:      t,
+					Message:   kEvent.Message,
+					StartTime: kEvent.FirstTimestamp.UnixNano() / 1000000,
+					EndTime:   kEvent.LastTimestamp.Unix() / 1000000,
+				}
+				if exporter.config.Template != nil {
+					exporter.config.Template.render(swEvent, kEvent)
+					logger.Log.Debugf("rendered event is: %+v", swEvent)
+				}
+				if bytes, err := json.Marshal(swEvent); err != nil {
+					logger.Log.Errorf("failed to send event to %+v, %+v", exporter.Name(), err)
+				} else {
+					logger.Log.Infoln(string(bytes))
+				}
+			}
+		}
+	}()
+}
+
+func (exporter *Console) Stop() {
+	exporter.stopper <- struct{}{}
+	close(exporter.stopper)
+}
diff --git a/pkg/exporter/skywalking.go b/pkg/exporter/skywalking.go
index 015408b..7319bf4 100644
--- a/pkg/exporter/skywalking.go
+++ b/pkg/exporter/skywalking.go
@@ -39,6 +39,7 @@ import (
 	"github.com/apache/skywalking-kubernetes-event-exporter/pkg/event"
 )
 
+// SkyWalking Exporter exports the events into Apache SkyWalking OAP server.
 type SkyWalking struct {
 	config     SkyWalkingConfig
 	client     sw.EventServiceClient
@@ -138,7 +139,7 @@ func (exporter *SkyWalking) Export(events chan *k8score.Event) {
 					EndTime:   kEvent.LastTimestamp.Unix() / 1000000,
 				}
 				if exporter.config.Template != nil {
-					exporter.config.Template.Render(swEvent, kEvent)
+					exporter.config.Template.render(swEvent, kEvent)
 					logger.Log.Debugf("rendered event is: %+v", swEvent)
 				}
 				if err := stream.Send(swEvent); err != nil {
@@ -149,7 +150,7 @@ func (exporter *SkyWalking) Export(events chan *k8score.Event) {
 	}()
 }
 
-func (tmplt *EventTemplate) Render(swEvent *sw.Event, kEvent *k8score.Event) {
+func (tmplt *EventTemplate) render(swEvent *sw.Event, kEvent *k8score.Event) {
 	templateCtx := k8s.Registry.GetContext(kEvent)
 
 	logger.Log.Debugf("template context %+v", templateCtx)