This is an automated email from the ASF dual-hosted git repository.
wusheng pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/skywalking-satellite.git
The following commit(s) were added to refs/heads/main by this push:
new 456e87a override config by env (#20)
456e87a is described below
commit 456e87aa3014a4121ff0bdcc83877432b29dba8f
Author: Evan <[email protected]>
AuthorDate: Wed Jan 27 15:53:25 2021 +0800
override config by env (#20)
---
configs/satellite_config.yaml | 34 ++--
internal/satellite/config/loader.go | 6 +-
internal/satellite/config/override_by_env.go | 114 +++++++++++++
internal/satellite/config/override_by_env_test.go | 194 ++++++++++++++++++++++
internal/satellite/config/satellite_config.go | 4 +-
5 files changed, 332 insertions(+), 20 deletions(-)
diff --git a/configs/satellite_config.yaml b/configs/satellite_config.yaml
index fc48810..323e945 100644
--- a/configs/satellite_config.yaml
+++ b/configs/satellite_config.yaml
@@ -15,27 +15,31 @@
# limitations under the License.
#
+# The logger configuration.
logger:
- log_pattern: "%time [%level][%field] - %msg"
- time_pattern: "2006-01-02 15:04:05.000"
- level: "info"
+ log_pattern: ${SATELLITE_LOGGER_LOG_PATTERN:%time [%level][%field] - %msg}
+ time_pattern: ${SATELLITE_LOGGER_TIME_PATTERN:2006-01-02 15:04:05.000}
+ level: ${SATELLITE_LOGGER_LEVEL:info}
+# The Satellite self telemetry configuration.
telemetry:
- cluster: cluster1
- service: service1
- instance: instance1
+ cluster: ${SATELLITE_TELEMETRY_CLUSTER:default-cluster}
+ service: ${SATELLITE_TELEMETRY_SERVICE:default-service}
+ instance: ${SATELLITE_TELEMETRY_SERVICE:default-instance}
+# The sharing plugins referenced by the specific plugins in the different
pipes.
sharing:
common_config:
pipe_name: sharing
clients:
- plugin_name: "kafka-client"
- brokers: 127.0.0.1:9092
- version: 2.1.1
+ brokers: ${SATELLITE_KAFKA_CLIENT_BROKERS:127.0.0.1:9092}
+ version: ${SATELLITE_KAFKA_VERSION:"2.1.1"}
servers:
- plugin_name: "grpc-server"
- plugin_name: "prometheus-server"
- address: ":8090"
+ address: ${SATELLITE_PROMETHEUS_ADDRESS:":8090"}
+# The working pipes.
pipes:
- common_config:
pipe_name: pipe1
@@ -45,18 +49,18 @@ pipes:
plugin_name: "grpc-nativelog-receiver"
queue:
plugin_name: "mmap-queue"
- segment_size: 524288
- max_in_mem_segments: 6
+ segment_size: ${SATELLITE_MMAP_QUEUE_SIZE:524288}
+ max_in_mem_segments: ${SATELLITE_MMAP_QUEUE_MAX_IN_MEM_SEGMENTS:6}
queue_dir: "pipe1-log-grpc-receiver-queue"
processor:
filters:
sender:
fallbacker:
plugin_name: none-fallbacker
- flush_time: 1000
- max_buffer_size: 200
- min_flush_events: 100
+ flush_time: ${SATELLITE_PIPE1_SENDER_FLUSH_TIME:1000}
+ max_buffer_size: ${SATELLITE_PIPE1_SENDER_MAX_BUFFER_SIZE:200}
+ min_flush_events: ${SATELLITE_PIPE1_SENDER_MIN_FLUSH_EVENTS:100}
client_name: kafka-client
forwarders:
- plugin_name: nativelog-kafka-forwarder
- topic: log-topic
\ No newline at end of file
+ topic: ${SATELLITE_NATIVELOG-TOPIC:log-topic}
diff --git a/internal/satellite/config/loader.go
b/internal/satellite/config/loader.go
index 21c92f8..11c6032 100644
--- a/internal/satellite/config/loader.go
+++ b/internal/satellite/config/loader.go
@@ -61,14 +61,14 @@ func load(configPath string) (*SatelliteConfig, error) {
return nil, err
}
v := viper.New()
- v.AutomaticEnv()
- v.SetEnvPrefix("satellite")
- v.SetEnvKeyReplacer(strings.NewReplacer(".", "_"))
v.SetConfigType("yaml")
cfg := SatelliteConfig{}
if err := v.ReadConfig(bytes.NewReader(content)); err != nil {
return nil, err
}
+ if err := overrideConfigByEnv(v); err != nil {
+ return nil, fmt.Errorf("cannot override value by env config:
%v", err)
+ }
if err := v.Unmarshal(&cfg); err != nil {
return nil, err
}
diff --git a/internal/satellite/config/override_by_env.go
b/internal/satellite/config/override_by_env.go
new file mode 100644
index 0000000..6ae678f
--- /dev/null
+++ b/internal/satellite/config/override_by_env.go
@@ -0,0 +1,114 @@
+// 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 config
+
+import (
+ "os"
+ "regexp"
+ "strconv"
+ "strings"
+
+ "github.com/spf13/viper"
+)
+
+// ${ENV:defaultVal} pattern is supported to override the default value by the
env config.
+// And the value would be converted to the different types, such as int,
float64 ana string.
+// If you want to keep it as the string value, please decorate it with `"`.
+const RegularExpression = "${_|[A-Z]+:.*}"
+
+func overrideConfigByEnv(v *viper.Viper) error {
+ regex, err := regexp.Compile(RegularExpression)
+ if err != nil {
+ return err
+ }
+ overrideCfg := overrideMapStringInterface(v.AllSettings(), regex)
+ for key, val := range overrideCfg {
+ v.Set(key, val)
+ }
+ return nil
+}
+
+func overrideMapStringInterface(cfg map[string]interface{}, regex
*regexp.Regexp) map[string]interface{} {
+ res := make(map[string]interface{})
+ for key, val := range cfg {
+ switch val := val.(type) {
+ case string:
+ res[key] = overrideString(val, regex)
+ case []interface{}:
+ res[key] = overrideSlice(val, regex)
+ case map[string]interface{}:
+ res[key] = overrideMapStringInterface(val, regex)
+ case map[interface{}]interface{}:
+ res[key] = overrideMapInterfaceInterface(val, regex)
+ default:
+ res[key] = val
+ }
+ }
+ return res
+}
+
+func overrideSlice(m []interface{}, regex *regexp.Regexp) []interface{} {
+ res := make([]interface{}, 0)
+ for _, val := range m {
+ switch val := val.(type) {
+ case map[string]interface{}:
+ res = append(res, overrideMapStringInterface(val,
regex))
+ case map[interface{}]interface{}:
+ res = append(res, overrideMapInterfaceInterface(val,
regex))
+ }
+ }
+ return res
+}
+
+func overrideMapInterfaceInterface(m map[interface{}]interface{}, regex
*regexp.Regexp) interface{} {
+ cfg := make(map[string]interface{})
+ for key, val := range m {
+ cfg[key.(string)] = val
+ }
+ return overrideMapStringInterface(cfg, regex)
+}
+
+func overrideString(s string, regex *regexp.Regexp) interface{} {
+ if regex.MatchString(s) {
+ index := strings.Index(s, ":")
+ envName := s[2:index]
+ defaultVal := s[index+1 : len(s)-1]
+ envVal := os.Getenv(envName)
+ if envVal != "" {
+ defaultVal = envVal
+ }
+ return parseVal(defaultVal)
+ }
+ return s
+}
+
+func parseVal(val string) interface{} {
+ if intVal, err := strconv.Atoi(val); err == nil {
+ return intVal
+ } else if floatVal, err := strconv.ParseFloat(val, 64); err == nil {
+ return floatVal
+ } else if strings.EqualFold(val, "true") {
+ return true
+ } else if strings.EqualFold(val, "false") {
+ return false
+ } else if strings.HasPrefix(val, "\"") && strings.HasSuffix(val, "\"") {
+ return val[1 : len(val)-1]
+ } else {
+ return val
+ }
+}
diff --git a/internal/satellite/config/override_by_env_test.go
b/internal/satellite/config/override_by_env_test.go
new file mode 100644
index 0000000..972579c
--- /dev/null
+++ b/internal/satellite/config/override_by_env_test.go
@@ -0,0 +1,194 @@
+// 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 config
+
+import (
+ "os"
+ "reflect"
+ "regexp"
+ "strings"
+ "testing"
+
+ "github.com/google/go-cmp/cmp"
+)
+
+func Test_overrideString(t *testing.T) {
+ type args struct {
+ expression string
+ env string
+ }
+ tests := []struct {
+ name string
+ args args
+ want interface{}
+ }{
+ {
+ name: "override_string",
+ args: args{
+ expression: "${TEST_OVERRIDE_STRING:test_str}",
+ env:
"TEST_OVERRIDE_STRING=test_override_string",
+ },
+ want: "test_override_string",
+ },
+ {
+ name: "no_override_string",
+ args: args{
+ expression:
"${TEST_NO_OVERRIDE_STRING:test_str}",
+ },
+ want: "test_str",
+ },
+ {
+ name: "no_override_false",
+ args: args{
+ expression: "${TEST_NO_OVERRIDE_FALSE:false}",
+ },
+ want: false,
+ },
+ {
+ name: "no_override_true",
+ args: args{
+ expression: "${TEST_NO_OVERRIDE_TRUE:true}",
+ },
+ want: true,
+ },
+ {
+ name: "override_boolean",
+ args: args{
+ expression: "${TEST_OVERRIDE_BOOLEAN:true}",
+ env: "TEST_OVERRIDE_BOOLEAN=false",
+ },
+ want: false,
+ },
+ {
+ name: "no_override_int",
+ args: args{
+ expression: "${TEST_OVERRIDE_INT:10}",
+ },
+ want: 10,
+ },
+ {
+ name: "override_int",
+ args: args{
+ expression: "${TEST_OVERRIDE_INT:10}",
+ env: "TEST_OVERRIDE_INT=15",
+ },
+ want: 15,
+ },
+ {
+ name: "override_float",
+ args: args{
+ expression: "${TEST_OVERRIDE_FLOAT:10.5}",
+ env: "TEST_OVERRIDE_FLOAT=15.7",
+ },
+ want: 15.7,
+ },
+ {
+ name: "no_override_force_string",
+ args: args{
+ expression:
"${TEST_NO_OVERRIDE_FORCE_STRING:\"10.5\"}",
+ },
+ want: "10.5",
+ },
+ }
+ for _, tt := range tests {
+ if tt.args.env != "" {
+ envArr := strings.Split(tt.args.env, "=")
+ if err := os.Setenv(envArr[0], envArr[1]); err != nil {
+ t.Fatalf("cannot set the env %s config: %v",
tt.args.env, err)
+ }
+ }
+ regex, err := regexp.Compile(RegularExpression)
+ if err != nil {
+ t.Fatalf("cannot generate the regular expression: %s",
RegularExpression)
+ }
+ t.Run(tt.name, func(t *testing.T) {
+ if got := overrideString(tt.args.expression, regex);
!reflect.DeepEqual(got, tt.want) {
+ t.Errorf("overrideString() = %v, want %v", got,
tt.want)
+ }
+ })
+ }
+}
+
+func Test_overrideMapStringInterface(t *testing.T) {
+ type args struct {
+ cfg map[string]interface{}
+ env map[string]string
+ }
+ tests := []struct {
+ name string
+ args args
+ want map[string]interface{}
+ }{
+ {
+ name: "test-overrideByEnv",
+ args: args{
+ cfg: map[string]interface{}{
+ "stringKey":
"${OVERRIDE_STRING_KEY:stringKey}",
+ "intKey": "${OVERRIDE_INT_KEY:10}",
+ "boolKey":
"${OVERRIDE_BOOL_KEY:false}",
+ "mapKey": map[string]interface{}{
+ "mapStringKey":
"${OVERRIDE_STRING_KEY:stringKey}",
+ "mapIntKey":
"${OVERRIDE_INT_KEY:10}",
+ "mapBoolKey":
"${OVERRIDE_BOOL_KEY:false}",
+ "mapInterfaceKey":
map[interface{}]interface{}{
+
"mapinterfaceStringKey": "${OVERRIDE_STRING_KEY:stringKey}",
+ "mapinterfaceIntKey":
"${OVERRIDE_INT_KEY:10}",
+ "mapinterfaceBoolKey":
"${OVERRIDE_BOOL_KEY:false}",
+ },
+ },
+ },
+ env: map[string]string{
+ "OVERRIDE_STRING_KEY": "env-string",
+ "OVERRIDE_INT_KEY": "100",
+ "OVERRIDE_BOOL_KEY": "true",
+ },
+ },
+ want: map[string]interface{}{
+ "stringKey": "env-string",
+ "intKey": 100,
+ "boolKey": true,
+ "mapKey": map[string]interface{}{
+ "mapStringKey": "env-string",
+ "mapIntKey": 100,
+ "mapBoolKey": true,
+ "mapInterfaceKey":
map[string]interface{}{
+ "mapinterfaceStringKey":
"env-string",
+ "mapinterfaceIntKey": 100,
+ "mapinterfaceBoolKey": true,
+ },
+ },
+ },
+ },
+ }
+
+ for _, tt := range tests {
+ for k, v := range tt.args.env {
+ err := os.Setenv(k, v)
+ if err != nil {
+ t.Fatalf("cannot set the env config{%s=%s}:
%v", k, v, err)
+ }
+ }
+ t.Run(tt.name, func(t *testing.T) {
+ regex, _ := regexp.Compile(RegularExpression)
+ got := overrideMapStringInterface(tt.args.cfg, regex)
+ if !cmp.Equal(got, tt.want) {
+ t.Errorf("overrideConfigByEnv() got = %v, want
= %v", got, tt.want)
+ }
+ })
+ }
+}
diff --git a/internal/satellite/config/satellite_config.go
b/internal/satellite/config/satellite_config.go
index 3033692..2828285 100644
--- a/internal/satellite/config/satellite_config.go
+++ b/internal/satellite/config/satellite_config.go
@@ -37,15 +37,15 @@ type SatelliteConfig struct {
// SharingConfig contains some plugins,which could be shared by every
namespace. That is useful to reduce resources cost.
type SharingConfig struct {
- SharingCommonConfig config.CommonFields `mapstructure:"common_config"`
Clients []plugin.Config `mapstructure:"clients"`
Servers []plugin.Config `mapstructure:"servers"`
+ SharingCommonConfig config.CommonFields `mapstructure:"common_config"`
}
// PipeConfig initializes the different module in different namespace.
type PipeConfig struct {
- PipeCommonConfig config.CommonFields
`mapstructure:"common_config"`
Gatherer *gatherer.GathererConfig `mapstructure:"gatherer"`
+ PipeCommonConfig config.CommonFields
`mapstructure:"common_config"`
Processor *processor.ProcessorConfig `mapstructure:"processor"`
Sender *sender.SenderConfig `mapstructure:"sender"`
}