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 <[email protected]> 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)
