From 010b6be150c6e3594004679e5fe0a6ceef733a26 Mon Sep 17 00:00:00 2001 From: mutezebra Date: Sun, 12 Jan 2025 11:16:49 +0800 Subject: [PATCH 1/6] feat: added support for configcenter listening and logger hot-reloading --- configcenter/configclient.go | 7 +- configcenter/load.go | 28 +++++-- configcenter/load_test.go | 7 +- configcenter/nacos_load.go | 121 ++++++++++++++++++------------- configcenter/nacos_load_test.go | 88 ++++++++++++++++++++++ configs/conf_with_nacos.yaml | 118 ++++++++++++++++++++++++++++++ go.mod | 17 +++-- go.sum | 34 ++++++--- pkg/cmd/gateway.go | 12 +++ pkg/common/constant/hotreload.go | 7 ++ pkg/common/yaml/yaml.go | 2 +- pkg/config/config_load.go | 9 ++- pkg/config/xds/lds.go | 2 +- pkg/hotreload/hotreload.go | 111 ++++++++++++++++++++++++++++ pkg/hotreload/logger.go | 99 +++++++++++++++++++++++++ pkg/logger/controller.go | 2 +- pkg/logger/logger.go | 7 ++ pkg/server/listener_manager.go | 2 +- 18 files changed, 585 insertions(+), 88 deletions(-) create mode 100644 configcenter/nacos_load_test.go create mode 100644 configs/conf_with_nacos.yaml create mode 100644 pkg/common/constant/hotreload.go create mode 100644 pkg/hotreload/hotreload.go create mode 100644 pkg/hotreload/logger.go diff --git a/configcenter/configclient.go b/configcenter/configclient.go index 37475ce4a..f03a30e23 100644 --- a/configcenter/configclient.go +++ b/configcenter/configclient.go @@ -17,12 +17,15 @@ package configcenter +import "github.com/apache/dubbo-go-pixiu/pkg/model" + type ( ConfigClient interface { LoadConfig(properties map[string]interface{}) (string, error) ListenConfig(properties map[string]interface{}) (err error) - } - ListenConfig func(data string) + // ViewConfig returns the current remote configuration. + ViewConfig() *model.Bootstrap + } ) diff --git a/configcenter/load.go b/configcenter/load.go index ab579adc9..f16289c30 100644 --- a/configcenter/load.go +++ b/configcenter/load.go @@ -22,7 +22,7 @@ import ( ) import ( - "github.com/ghodss/yaml" + "gopkg.in/yaml.v3" ) import ( @@ -42,6 +42,7 @@ var Parsers = map[string]func(data []byte, v interface{}) error{ type ( Load interface { LoadConfigs(boot *model.Bootstrap, opts ...Option) (v *model.Bootstrap, err error) + ViewRemoteConfig() *model.Bootstrap } Option func(opt *Options) @@ -61,12 +62,14 @@ type DefaultConfigLoad struct { } func NewConfigLoad(bootConfig *model.Bootstrap) *DefaultConfigLoad { - var configClient ConfigClient - + var err error // config center load if strings.EqualFold(bootConfig.Config.Type, KEY_CONFIG_TYPE_NACOS) { - configClient, _ = NewNacosConfig(bootConfig) + configClient, err = NewNacosConfig(bootConfig) + if err != nil { + logger.Errorf("Get new nacos config failed,err: %v", err) + } } if configClient == nil { @@ -81,7 +84,6 @@ func NewConfigLoad(bootConfig *model.Bootstrap) *DefaultConfigLoad { } func (d *DefaultConfigLoad) LoadConfigs(boot *model.Bootstrap, opts ...Option) (v *model.Bootstrap, err error) { - var opt Options for _, o := range opts { o(&opt) @@ -104,7 +106,6 @@ func (d *DefaultConfigLoad) LoadConfigs(boot *model.Bootstrap, opts ...Option) ( } data, err := d.configClient.LoadConfig(m) - if err != nil { return nil, err } @@ -114,11 +115,24 @@ func (d *DefaultConfigLoad) LoadConfigs(boot *model.Bootstrap, opts ...Option) ( return boot, err } - err = Parsers[".yml"]([]byte(data), boot) + if err = Parsers[".yml"]([]byte(data), boot); err != nil { + logger.Errorf("failed to parse the configuration loaded from the remote,err: %v", err) + return boot, err + } + + if err = d.configClient.ListenConfig(m); err != nil { + logger.Errorf("failed to listen the remote configcenter config,err: %v", err) + return boot, err + } return boot, err } +// ViewRemoteConfig returns the current remote configuration. +func (d *DefaultConfigLoad) ViewRemoteConfig() *model.Bootstrap { + return d.configClient.ViewConfig() +} + func ParseYamlBytes(content []byte, v interface{}) error { return yaml.Unmarshal(content, v) } diff --git a/configcenter/load_test.go b/configcenter/load_test.go index 292c1a8e7..4fe85779d 100644 --- a/configcenter/load_test.go +++ b/configcenter/load_test.go @@ -28,7 +28,6 @@ import ( ) func getBootstrap() *model.Bootstrap { - return &model.Bootstrap{ Config: &model.ConfigCenter{ Type: "nacos", @@ -69,7 +68,7 @@ func TestDefaultConfigLoad_LoadConfigs(t *testing.T) { boot *model.Bootstrap opts []Option } - var tests = []struct { + tests := []struct { name string fields fields args args @@ -139,8 +138,8 @@ func TestDefaultConfigLoad_LoadConfigs(t *testing.T) { t.Errorf("LoadConfigs() error = %v, wantErr %v", err, tt.wantErr) return } - //assert.True(t, gotV.Nacos.DataId == DataId, "load config by nacos config center error!") - //assert.True(t, len(gotV.StaticResources.Listeners) > 0, "load config by nacos config center error!") + // assert.True(t, gotV.Nacos.DataId == DataId, "load config by nacos config center error!") + // assert.True(t, len(gotV.StaticResources.Listeners) > 0, "load config by nacos config center error!") conf, _ := json.Marshal(gotV) logger.Infof("config of Bootstrap load by nacos : %v", string(conf)) }) diff --git a/configcenter/nacos_load.go b/configcenter/nacos_load.go index 84681a8e5..41014074b 100644 --- a/configcenter/nacos_load.go +++ b/configcenter/nacos_load.go @@ -18,18 +18,19 @@ package configcenter import ( + "sync" + "github.com/nacos-group/nacos-sdk-go/clients" "github.com/nacos-group/nacos-sdk-go/clients/config_client" "github.com/nacos-group/nacos-sdk-go/common/constant" "github.com/nacos-group/nacos-sdk-go/vo" "github.com/pkg/errors" -) -import ( "github.com/apache/dubbo-go-pixiu/pkg/logger" "github.com/apache/dubbo-go-pixiu/pkg/model" ) +// Constants for configuration keys. const ( KeyDataId = "dataId" KeyGroup = "group" @@ -39,6 +40,7 @@ const ( KeyTenant = "tenant" ) +// Constants for Nacos configuration. const ( DataId = "pixiu.yaml" Group = "DEFAULT_GROUP" @@ -50,29 +52,41 @@ const ( Scheme = "http" ) -type ( - NacosConfig struct { - client config_client.IConfigClient +// NacosConfig represents the Nacos configuration client and its state. +type NacosConfig struct { + client config_client.IConfigClient + remoteConfig *model.Bootstrap + mu sync.Mutex +} - // todo not support now - listenConfigCallback ListenConfig +// NewNacosConfig creates a new NacosConfig instance. +// It returns an error if no Nacos server is configured or if the client cannot be created. +func NewNacosConfig(boot *model.Bootstrap) (ConfigClient, error) { + if len(boot.Nacos.ServerConfigs) == 0 { + return nil, errors.New("no Nacos server configured") } -) - -func NewNacosConfig(boot *model.Bootstrap) (configClient ConfigClient, err error) { - var sc []constant.ServerConfig - if len(boot.Nacos.ServerConfigs) == 0 { - return nil, errors.New("no nacos server be setted") + nacosClient, err := getNacosConfigClient(boot) + if err != nil { + return nil, err } - for _, serveConfig := range boot.Nacos.ServerConfigs { - sc = append(sc, constant.ServerConfig{ - Port: serveConfig.Port, - IpAddr: serveConfig.IpAddr, + + return &NacosConfig{ + client: nacosClient, + }, nil +} + +// getNacosConfigClient initializes and returns a Nacos config client. +func getNacosConfigClient(boot *model.Bootstrap) (config_client.IConfigClient, error) { + var serverConfigs []constant.ServerConfig + for _, serverConfig := range boot.Nacos.ServerConfigs { + serverConfigs = append(serverConfigs, constant.ServerConfig{ + Port: serverConfig.Port, + IpAddr: serverConfig.IpAddr, }) } - cc := constant.ClientConfig{ + clientConfig := constant.ClientConfig{ NamespaceId: boot.Nacos.ClientConfig.NamespaceId, TimeoutMs: boot.Nacos.ClientConfig.TimeoutMs, NotLoadCacheAtStart: boot.Nacos.ClientConfig.NotLoadCacheAtStart, @@ -81,21 +95,15 @@ func NewNacosConfig(boot *model.Bootstrap) (configClient ConfigClient, err error LogLevel: boot.Nacos.ClientConfig.LogLevel, } - pa := vo.NacosClientParam{ - ClientConfig: &cc, - ServerConfigs: sc, - } - nacos, err := clients.NewConfigClient(pa) - if err != nil { - return nil, err - } - configClient = &NacosConfig{ - client: nacos, + clientParam := vo.NacosClientParam{ + ClientConfig: &clientConfig, + ServerConfigs: serverConfigs, } - return configClient, nil + return clients.NewConfigClient(clientParam) } +// LoadConfig retrieves the configuration from Nacos based on the provided parameters. func (n *NacosConfig) LoadConfig(param map[string]interface{}) (string, error) { return n.client.GetConfig(vo.ConfigParam{ DataId: getOrDefault(param[KeyDataId].(string), DataId), @@ -103,34 +111,45 @@ func (n *NacosConfig) LoadConfig(param map[string]interface{}) (string, error) { }) } -func getOrDefault(target string, quiet string) string { +// getOrDefault returns the target value if it is not empty; otherwise, it returns the fallback value. +func getOrDefault(target, fallback string) string { if len(target) == 0 { - target = quiet + return fallback } return target } -func (n *NacosConfig) ListenConfig(param map[string]interface{}) (err error) { - // todo noop, not support - if true { - return nil - } - listen := n.listen(getOrDefault(param[KeyDataId].(string), DataId), getOrDefault(param[KeyGroup].(string), Group)) - return listen() +// ListenConfig listens for configuration changes in Nacos. +func (n *NacosConfig) ListenConfig(param map[string]interface{}) error { + return n.client.ListenConfig(vo.ConfigParam{ + DataId: getOrDefault(param[KeyDataId].(string), DataId), + Group: getOrDefault(param[KeyGroup].(string), Group), + OnChange: n.onChange, + }) } -func (n *NacosConfig) listen(dataId, group string) func() error { - return func() error { - return n.client.ListenConfig(vo.ConfigParam{ - DataId: dataId, - Group: group, - OnChange: func(namespace, group, dataId, data string) { - if len(data) == 0 { - logger.Errorf("nacos listen callback data nil error , namespace : %s,group : %s , dataId : %s , data : %s") - return - } - n.listenConfigCallback(data) - }, - }) +// onChange is the callback function triggered when the configuration changes in Nacos. +func (n *NacosConfig) onChange(namespace, group, dataId, data string) { + n.mu.Lock() + defer n.mu.Unlock() + + if len(data) == 0 { + logger.Errorf("Nacos listen callback data is nil. Namespace: %s, Group: %s, DataId: %s", namespace, group, dataId) + return + } + + boot := new(model.Bootstrap) + if err := Parsers[".yml"]([]byte(data), boot); err != nil { + logger.Errorf("Failed to parse the configuration loaded from the remote. Error: %v", err) + return } + + n.remoteConfig = boot +} + +// ViewConfig returns the current remote configuration. +func (n *NacosConfig) ViewConfig() *model.Bootstrap { + n.mu.Lock() + defer n.mu.Unlock() + return n.remoteConfig } diff --git a/configcenter/nacos_load_test.go b/configcenter/nacos_load_test.go new file mode 100644 index 000000000..e59032251 --- /dev/null +++ b/configcenter/nacos_load_test.go @@ -0,0 +1,88 @@ +package configcenter + +import ( + "fmt" + "io" + "os" + "path" + "strings" + "testing" + + "github.com/apache/dubbo-go-pixiu/pkg/logger" + . "github.com/smartystreets/goconvey/convey" +) + +// isNacosRunning checks whether the Nacos server is running. +// It returns true if Nacos is running, otherwise false. +func isNacosRunning(t *testing.T) bool { + t.Helper() + _, err := getNacosConfigClient(getBootstrap()) + return err == nil +} + +// TestNewNacosConfig tests the creation of a new Nacos configuration. +// If Nacos is not running, the test is skipped. +func TestNewNacosConfig(t *testing.T) { + if !isNacosRunning(t) { + t.Skip("Nacos is not running, skipping the test.") + return + } + + Convey("Test NewNacosConfig", t, func() { + cfg := getBootstrap() + + // Test successful creation of NacosConfig. + _, err := NewNacosConfig(cfg) + So(err, ShouldBeNil) + + // Test creation failure when Nacos server configurations are missing. + cfg.Nacos.ServerConfigs = nil + _, err = NewNacosConfig(cfg) + So(err, ShouldNotBeNil) + }) +} + +// TestNacosConfig_onChange tests the onChange method of NacosConfig. +func TestNacosConfig_onChange(t *testing.T) { + Convey("TestNacosConfig_onChange", t, func() { + cfg := getBootstrap() + c, err := NewNacosConfig(cfg) + So(err, ShouldBeNil) + + client, ok := c.(*NacosConfig) + So(ok, ShouldBeTrue) + + // Verify the current working directory. + wd, err := os.Getwd() + So(err, ShouldBeNil) + + paths := strings.Split(wd, "/") + So(paths[len(paths)-1], ShouldEqual, "configcenter") + + // Open the configuration file for testing. + file, err := os.Open(fmt.Sprintf("/%s/configs/conf.yaml", path.Join(paths[:len(paths)-1]...))) + So(err, ShouldBeNil) + defer func() { So(file.Close(), ShouldBeNil) }() + + conf, err := io.ReadAll(file) + So(err, ShouldBeNil) + + Convey("Test onChange with valid input", func() { + So(client.remoteConfig, ShouldBeNil) + client.onChange(Namespace, Group, DataId, string(conf)) + So(client.remoteConfig, ShouldNotBeNil) + }) + + Convey("Test onChange with empty input", func() { + // Suppress logs during this test. + logger.SetLoggerLevel("fatal") + + client.remoteConfig = nil + client.onChange(Namespace, Group, DataId, "") + So(client.remoteConfig, ShouldBeNil) + + // Restore the logger level. + logger.SetLoggerLevel("info") + }) + }) +} diff --git a/configs/conf_with_nacos.yaml b/configs/conf_with_nacos.yaml new file mode 100644 index 000000000..46037e321 --- /dev/null +++ b/configs/conf_with_nacos.yaml @@ -0,0 +1,118 @@ +# +# Licensed to the 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. The 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. +# +--- +static_resources: + listeners: + - name: "net/http" + protocol_type: "HTTP" + address: + socket_address: + address: "0.0.0.0" + port: 8888 + filter_chains: + filters: + - name: dgp.filter.httpconnectionmanager + config: + route_config: + routes: + - match: + prefix: "/user" + route: + cluster: "user" + cluster_not_found_response_code: 505 + http_filters: + - name: dgp.filter.http.httpproxy + config: + - name: dgp.filter.http.cors + config: + allow_origin: + - api.dubbo.com + allow_methods: "" + allow_headers: "" + expose_headers: "" + max_age: "" + allow_credentials: false + config: + idle_timeout: 5s + read_timeout: 5s + write_timeout: 5s + clusters: + - name: "user" + lb_policy: "lb" + endpoints: + - id: 1 + socket_address: + address: 127.0.0.1 + port: 1314 + shutdown_config: + timeout: "60s" + step_timeout: "10s" + reject_policy: "immediacy" + +config-center: + type: "nacos" + enable: true + +nacos: + server_configs: + - ip_addr: "localhost" + port: 8848 + scheme: "http" + contextPath: "/nacos" + - ip_addr: "localhost" + port: 8848 + scheme: "http" + contextPath: "/nacos" + client-config: + cache_dir: "./.cache" + log_dir: "./.log" + not_load_cache_at_start: true + namespace_id: "dubbo-go-pixiu" + data-id: "pixiu.yaml" + group: "DEFAULT_GROUP" + +log: + level: "debug" + development: true + disableCaller: false + disableStacktrace: false + sampling: + encoding: "console" + + # encoder + encoderConfig: + messageKey: "message" + levelKey: "level" + timeKey: "time" + nameKey: "logger" + callerKey: "caller" + stacktraceKey: "stacktrace" + lineEnding: "" + levelEncoder: "capitalColor" + timeEncoder: "iso8601" + durationEncoder: "seconds" + callerEncoder: "short" + nameEncoder: "" + + outputPaths: + - "stderr" + errorOutputPaths: + - "stderr" + initialFields: + diff --git a/go.mod b/go.mod index e02699fc1..0b4023476 100644 --- a/go.mod +++ b/go.mod @@ -17,7 +17,6 @@ require ( github.com/dubbogo/grpc-go v1.42.10 github.com/dubbogo/triple v1.2.2-rc3 github.com/envoyproxy/go-control-plane v0.11.1-0.20230524094728-9239064ad72f - github.com/ghodss/yaml v1.0.1-0.20190212211648-25d852aebe32 github.com/go-errors/errors v1.0.1 github.com/go-playground/assert/v2 v2.2.0 github.com/goinggo/mapstructure v0.0.0-20140717182941-194205d9b4a9 @@ -31,6 +30,7 @@ require ( github.com/pkg/errors v0.9.1 github.com/prometheus/client_golang v1.14.0 github.com/prometheus/common v0.37.0 + github.com/smartystreets/goconvey v1.7.2 github.com/spf13/cast v1.5.0 github.com/spf13/cobra v1.5.0 github.com/stretchr/testify v1.8.4 @@ -49,7 +49,7 @@ require ( golang.org/x/net v0.17.0 google.golang.org/grpc v1.56.3 google.golang.org/protobuf v1.30.0 - gopkg.in/yaml.v2 v2.4.0 + gopkg.in/yaml.v3 v3.0.1 mosn.io/proxy-wasm-go-host v0.1.0 ) @@ -89,6 +89,7 @@ require ( github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/snappy v0.0.4 // indirect github.com/google/uuid v1.3.0 // indirect + github.com/gopherjs/gopherjs v1.12.80 // indirect github.com/gorilla/websocket v1.4.2 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.11.3 // indirect github.com/grpc-ecosystem/grpc-opentracing v0.0.0-20180507213350-8e809c8a8645 // indirect @@ -107,6 +108,7 @@ require ( github.com/jinzhu/copier v0.3.5 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect github.com/json-iterator/go v1.1.12 // indirect + github.com/jtolds/gls v4.20.0+incompatible // indirect github.com/k0kubun/pp v3.0.1+incompatible // indirect github.com/klauspost/compress v1.13.6 // indirect github.com/knadh/koanf v1.5.0 // indirect @@ -137,6 +139,7 @@ require ( github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect github.com/robfig/cron/v3 v3.0.1 // indirect github.com/shirou/gopsutil/v3 v3.22.2 // indirect + github.com/smartystreets/assertions v1.2.0 // indirect github.com/spaolacci/murmur3 v1.1.0 // indirect github.com/spf13/pflag v1.0.5 // indirect github.com/tklauser/go-sysconf v0.3.10 // indirect @@ -155,15 +158,15 @@ require ( go.opentelemetry.io/proto/otlp v0.19.0 // indirect go.uber.org/atomic v1.10.0 // indirect go.uber.org/multierr v1.8.0 // indirect - golang.org/x/arch v0.0.0-20200826200359-b19915210f00 // indirect + golang.org/x/arch v0.11.0 // indirect golang.org/x/oauth2 v0.7.0 // indirect - golang.org/x/sync v0.1.0 // indirect - golang.org/x/sys v0.13.0 // indirect - golang.org/x/text v0.13.0 // indirect + golang.org/x/sync v0.7.0 // indirect + golang.org/x/sys v0.26.0 // indirect + golang.org/x/text v0.16.0 // indirect golang.org/x/time v0.1.0 // indirect google.golang.org/appengine v1.6.7 // indirect google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 // indirect gopkg.in/ini.v1 v1.66.2 // indirect gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect - gopkg.in/yaml.v3 v3.0.1 // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect ) diff --git a/go.sum b/go.sum index c1ac65ec4..1bfae555d 100644 --- a/go.sum +++ b/go.sum @@ -614,8 +614,6 @@ github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4 github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= github.com/getsentry/raven-go v0.2.0/go.mod h1:KungGk8q33+aIAZUIVWZDr2OfAEBsO49PX4NzFV5kcQ= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= -github.com/ghodss/yaml v1.0.1-0.20190212211648-25d852aebe32 h1:Mn26/9ZMNWSw9C9ERFA1PUxfmGpolnw2v0bKOREu5ew= -github.com/ghodss/yaml v1.0.1-0.20190212211648-25d852aebe32/go.mod h1:GIjDIg/heH5DOkXY3YJ/wNhfHsQHoXGjl8G8amsYQ1I= github.com/go-asn1-ber/asn1-ber v1.3.1/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0= github.com/go-co-op/gocron v1.9.0 h1:+V+DDenw3ryB7B+tK1bAIC5p0ruw4oX9IqAsdRnGIf0= github.com/go-co-op/gocron v1.9.0/go.mod h1:DbJm9kdgr1sEvWpHCA7dFFs/PGHPMil9/97EXCRPr4k= @@ -786,8 +784,9 @@ github.com/googleapis/gax-go/v2 v2.7.0/go.mod h1:TEop28CZZQ2y+c0VxMUmu1lV+fQx57Q github.com/googleapis/go-type-adapters v1.0.0/go.mod h1:zHW75FOG2aur7gAO2B+MLby+cLsWGBF62rFAi7WjWO4= github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= -github.com/gopherjs/gopherjs v0.0.0-20190910122728-9d188e94fb99 h1:twflg0XRTjwKpxb/jFExr4HGq6on2dEOmnL6FV+fgPw= github.com/gopherjs/gopherjs v0.0.0-20190910122728-9d188e94fb99/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gopherjs/gopherjs v1.12.80 h1:aC68NT6VK715WeUapxcPSFq/a3gZdS32HdtghdOIgAo= +github.com/gopherjs/gopherjs v1.12.80/go.mod h1:d55Q4EjGQHeJVms+9LGtXul6ykz5Xzx1E1gaXQXdimY= github.com/gordonklaus/ineffassign v0.0.0-20200309095847-7953dde2c7bf/go.mod h1:cuNKsD1zp2v6XfE/orVX2QE1LC+i254ceGcVeDT3pTU= github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= @@ -1055,6 +1054,8 @@ github.com/nats-io/nats.go v1.9.1/go.mod h1:ZjDU1L/7fJ09jvUSRVBR2e7+RnLiiIQyqyzE github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= github.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= +github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo= +github.com/neelance/sourcemap v0.0.0-20151028013722-8c68805598ab/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/nishanths/predeclared v0.0.0-20200524104333-86fad755b4d3/go.mod h1:nt3d53pc1VYcphSCIaYAJtnPYnr3Zyn8fMq2wvPGPso= github.com/npillmayer/nestext v0.1.3/go.mod h1:h2lrijH8jpicr25dFY+oAJLyzlya6jhnuG+zWp9L0Uk= @@ -1175,6 +1176,7 @@ github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs= github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= +github.com/rogpeppe/go-internal v1.0.1-alpha.1/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8= @@ -1191,18 +1193,23 @@ github.com/shirou/gopsutil v3.20.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMT github.com/shirou/gopsutil/v3 v3.21.6/go.mod h1:JfVbDpIBLVzT8oKbvMg9P3wEIMDDpVn+LwHTKj0ST88= github.com/shirou/gopsutil/v3 v3.22.2 h1:wCrArWFkHYIdDxx/FSfF5RB4dpJYW6t7rcp3+zL8uks= github.com/shirou/gopsutil/v3 v3.22.2/go.mod h1:WapW1AOOPlHyXr+yOyw3uYx36enocrtSoSBy0L5vUHY= +github.com/shurcooL/go v0.0.0-20180423040247-9e1955d9fb6e/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk= +github.com/shurcooL/httpfs v0.0.0-20181222201310-74dc9339e414/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/shurcooL/vfsgen v0.0.0-20180915214035-33ae1944be3f/go.mod h1:TrYk7fJVaAttu97ZZKrO9UbRa8izdowaMIZcxYMbVaw= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE= github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= -github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/assertions v1.2.0 h1:42S6lae5dvLc7BrLu/0ugRtcFVjoJNMC/N3yZFZkDFs= +github.com/smartystreets/assertions v1.2.0/go.mod h1:tcbTF8ujkAEcZ8TElKY+i30BzYlVhC/LOxJk7iOWnoo= github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= -github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= +github.com/smartystreets/goconvey v1.7.2 h1:9RBaZCeXEQ3UselpuwUQHltGVXvdwm6cv1hgR6gDIPg= +github.com/smartystreets/goconvey v1.7.2/go.mod h1:Vw0tHAZW6lzCRk3xgdin6fKYcG+G3Pg9vgXWeJpQFMM= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= github.com/soheilhy/cmux v0.1.5-0.20210205191134-5ec6847320e5 h1:GJTW+uNMIV1RKwox+T4aN0/sQlYRg78uHZf2H0aBcDw= github.com/soheilhy/cmux v0.1.5-0.20210205191134-5ec6847320e5/go.mod h1:T7TcVDs9LWfQgPlPsdngu6I6QIoyIFZDDC6sNE1GqG0= @@ -1382,8 +1389,10 @@ go.uber.org/zap v1.16.0/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ= go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo= go.uber.org/zap v1.21.0 h1:WefMeulhovoZ2sYXz7st6K0sLj7bBhpiFaud4r4zST8= go.uber.org/zap v1.21.0/go.mod h1:wjWOCqI0f2ZZrJF/UufIOkiC8ii6tm1iqIsLo76RfJw= -golang.org/x/arch v0.0.0-20200826200359-b19915210f00 h1:cfd5G6xu8iZTFmjBYVemyBmE/sTf0A3vpE3BmoOuLCI= golang.org/x/arch v0.0.0-20200826200359-b19915210f00/go.mod h1:flIaEI6LNU6xOCD5PaJvn9wGP0agmIOqjrtsKGRguv4= +golang.org/x/arch v0.11.0 h1:KXV8WWKCXm6tRpLirl2szsO5j/oOODwZf4hATmGVNs4= +golang.org/x/arch v0.11.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys= +golang.org/x/crypto v0.0.0-20180807104621-f027049dab0a/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= @@ -1565,8 +1574,10 @@ golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220929204114-8fcdb60fdcc0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= +golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sys v0.0.0-20180807162357-acbc56fc7007/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -1678,8 +1689,8 @@ golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= -golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo= +golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= @@ -1701,8 +1712,8 @@ golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= -golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= -golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4= +golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -1721,6 +1732,7 @@ golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGm golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190206041539-40960b6deb8e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190308142131-b40df0fb21c3/go.mod h1:25r3+/G6/xytQM8iWZKq3Hn0kr0rgFKPUNVEL/dr3z4= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= diff --git a/pkg/cmd/gateway.go b/pkg/cmd/gateway.go index 9dc4ff69e..668286717 100644 --- a/pkg/cmd/gateway.go +++ b/pkg/cmd/gateway.go @@ -19,6 +19,7 @@ package cmd import ( "fmt" + "github.com/apache/dubbo-go-pixiu/pkg/hotreload" "os" "runtime" "strconv" @@ -110,20 +111,29 @@ type DefaultDeployer struct { } func (d *DefaultDeployer) initialize() error { + logger.Info("initialize") err := initLog() if err != nil { logger.Warnf("[startGatewayCmd] failed to init logger, %s", err.Error()) } + logger.Info("initialize log success") // load Bootstrap config d.bootstrap = d.configManger.LoadBootConfig(configPath) + logger.Infof("init boot success") initLogWithConfig(d.bootstrap) + fmt.Println("emmm") + logger.Infof("init log success") err = initLimitCpus() if err != nil { logger.Errorf("[startCmd] failed to get limit cpu number, %s", err.Error()) } + logger.Infof("init cpu ?") + + hotreload.StartHotReload(d.configManger, d.bootstrap) + logger.Infof("have started") return err } @@ -184,7 +194,9 @@ func initLog() error { func initLogWithConfig(boot *model.Bootstrap) { if boot.Log != nil { + fmt.Println("start") logger.InitLogger(boot.Log.Build()) + fmt.Println("end") } } diff --git a/pkg/common/constant/hotreload.go b/pkg/common/constant/hotreload.go new file mode 100644 index 000000000..f2f3b3522 --- /dev/null +++ b/pkg/common/constant/hotreload.go @@ -0,0 +1,7 @@ +package constant + +import "time" + +const ( + CheckConfigInterval = 1 * time.Second +) diff --git a/pkg/common/yaml/yaml.go b/pkg/common/yaml/yaml.go index 2f6281d53..72a35f036 100644 --- a/pkg/common/yaml/yaml.go +++ b/pkg/common/yaml/yaml.go @@ -25,7 +25,7 @@ import ( import ( perrors "github.com/pkg/errors" - "gopkg.in/yaml.v2" + "gopkg.in/yaml.v3" ) // LoadYMLConfig Load yml config byte from file diff --git a/pkg/config/config_load.go b/pkg/config/config_load.go index a004a77d6..64cda0764 100644 --- a/pkg/config/config_load.go +++ b/pkg/config/config_load.go @@ -27,9 +27,9 @@ import ( import ( "github.com/creasty/defaults" - "github.com/ghodss/yaml" "github.com/goinggo/mapstructure" "github.com/imdario/mergo" + "gopkg.in/yaml.v3" ) import ( @@ -84,7 +84,7 @@ func CheckYamlFormat(path string) bool { // LoadYAMLConfig YAMLConfigLoad config load yaml func LoadYAMLConfig(path string) *model.Bootstrap { - log.Println("load config in YAML format from : ", path) + logger.Info("load config in YAML format from : ", path) content, err := os.ReadFile(path) if err != nil { log.Fatalln("[config] [yaml load] load config failed, ", err) @@ -253,6 +253,11 @@ func (m *ConfigManager) loadRemoteBootConfigs() *model.Bootstrap { return configs } +// ViewRemoteConfig returns the current remote configuration. +func (m *ConfigManager) ViewRemoteConfig() *model.Bootstrap { + return m.load.ViewRemoteConfig() +} + func (m *ConfigManager) check() error { return Adapter(config) diff --git a/pkg/config/xds/lds.go b/pkg/config/xds/lds.go index cc455d129..c53058cfc 100644 --- a/pkg/config/xds/lds.go +++ b/pkg/config/xds/lds.go @@ -24,7 +24,7 @@ import ( import ( xdsModel "github.com/dubbo-go-pixiu/pixiu-api/pkg/xds/model" - "gopkg.in/yaml.v2" + "gopkg.in/yaml.v3" ) import ( diff --git a/pkg/hotreload/hotreload.go b/pkg/hotreload/hotreload.go new file mode 100644 index 000000000..0cccf42c5 --- /dev/null +++ b/pkg/hotreload/hotreload.go @@ -0,0 +1,111 @@ +/* + * Licensed to the 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. + * The 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 hotreload + +import ( + "sync" + "time" + + "github.com/apache/dubbo-go-pixiu/pkg/common/constant" + "github.com/apache/dubbo-go-pixiu/pkg/config" + "github.com/apache/dubbo-go-pixiu/pkg/logger" + "github.com/apache/dubbo-go-pixiu/pkg/model" +) + +// HotReloader defines the interface for the HotReload module. +type HotReloader interface { + // CheckUpdate checks if the configuration has changed and needs to be reloaded. + CheckUpdate(oldConfig, newConfig *model.Bootstrap) bool + + // HotReload performs the hot reload of the configuration. + HotReload(oldConfig, newConfig *model.Bootstrap) error +} + +// Coordinator listens for configuration file changes and notifies registered reloaders +// to perform hot reload when the configuration changes. +type Coordinator struct { + reloaders []HotReloader // List of registered reloaders + boot *model.Bootstrap // Current configuration + manager *config.ConfigManager // Configuration manager +} + +var coordinator = Coordinator{reloaders: []HotReloader{&LoggerReloader{}}} + +// StartHotReload initializes the hot reload process. +// It should be called when the project starts, e.g., in cmd/gateway.go. +func StartHotReload(manager *config.ConfigManager, boot *model.Bootstrap) { + if manager == nil || boot == nil { + logger.Warn("ConfigManager or Bootstrap is nil, hot reload will not start") + return + } + + coordinator.manager = manager + coordinator.boot = boot + go coordinator.HotReload() +} + +// HotReload periodically checks for configuration updates and triggers hot reload if changes are detected. +func (c *Coordinator) HotReload() { + for { + time.Sleep(constant.CheckConfigInterval) + + boot := c.manager.ViewRemoteConfig() + if boot == nil { + continue + } + + c.hotReload(boot) + } +} + +// hotReload checks for configuration changes and triggers hot reload for registered reloaders. +func (c *Coordinator) hotReload(newBoot *model.Bootstrap) { + changed := false + wg := &sync.WaitGroup{} + + for _, reloader := range c.reloaders { + if reloader.CheckUpdate(c.boot, newBoot) { + changed = true + wg.Add(1) + go func(r HotReloader) { + defer wg.Done() + if err := r.HotReload(c.boot, newBoot); err != nil { + logger.Errorf("Hot reload failed: %v", err) + } + }(reloader) + } + } + + wg.Wait() + if changed { + c.boot = newBoot + } +} + +// equal checks if two string slices are equal. +func equal(s1, s2 []string) bool { + if len(s1) != len(s2) { + return false + } + for i := range s1 { + if s1[i] != s2[i] { + return false + } + } + return true +} diff --git a/pkg/hotreload/logger.go b/pkg/hotreload/logger.go new file mode 100644 index 000000000..45430cf33 --- /dev/null +++ b/pkg/hotreload/logger.go @@ -0,0 +1,99 @@ +/* + * Licensed to the 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. + * The 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 hotreload + +import ( + "github.com/apache/dubbo-go-pixiu/pkg/logger" + "github.com/apache/dubbo-go-pixiu/pkg/model" +) + +// LoggerReloader implements the HotReloader interface for reloading logger configurations. +type LoggerReloader struct{} + +// CheckUpdate compares the old and new logger configurations to determine if a reload is needed. +func (r *LoggerReloader) CheckUpdate(oldConfig, newConfig *model.Bootstrap) bool { + oc := oldConfig.Log + nc := newConfig.Log + + if oc == nil && nc != nil { + return true + } + + if oc != nil && nc == nil { + return false + } + + // Check if any logger configuration fields have changed. + if oc.Level != nc.Level || + oc.Development != nc.Development || + oc.DisableCaller != nc.DisableCaller || + oc.DisableStacktrace != nc.DisableStacktrace || + oc.Encoding != nc.Encoding { + return false + } + + // Check sampling configuration. + if !r.checkSampling(oc.Sampling, nc.Sampling) { + return false + } + + // Check encoder configuration. + if !r.checkEncoderConfig(oc.EncoderConfig, nc.EncoderConfig) { + return false + } + + // Check output paths. + if !equal(oc.OutputPaths, nc.OutputPaths) { + return false + } + + return true +} + +// HotReload applies the new logger configuration. +func (r *LoggerReloader) HotReload(oldConfig, newConfig *model.Bootstrap) error { + if err := logger.HotReload(newConfig.Log.Build()); err != nil { + logger.Errorf("Failed to reload logger configuration: %v", err) + return err + } + return nil +} + +// checkSampling compares the old and new sampling configurations. +func (r *LoggerReloader) checkSampling(oldSampling, newSampling model.SamplingConfig) bool { + return oldSampling.Initial == newSampling.Initial && oldSampling.Thereafter == newSampling.Thereafter +} + +// checkEncoderConfig compares the old and new encoder configurations. +func (r *LoggerReloader) checkEncoderConfig(oldEncoderConfig, newEncoderConfig model.EncoderConfig) bool { + return oldEncoderConfig.MessageKey == newEncoderConfig.MessageKey && + oldEncoderConfig.LevelKey == newEncoderConfig.LevelKey && + oldEncoderConfig.TimeKey == newEncoderConfig.TimeKey && + oldEncoderConfig.NameKey == newEncoderConfig.NameKey && + oldEncoderConfig.CallerKey == newEncoderConfig.CallerKey && + oldEncoderConfig.FunctionKey == newEncoderConfig.FunctionKey && + oldEncoderConfig.StacktraceKey == newEncoderConfig.StacktraceKey && + oldEncoderConfig.SkipLineEnding == newEncoderConfig.SkipLineEnding && + oldEncoderConfig.LineEnding == newEncoderConfig.LineEnding && + oldEncoderConfig.EncodeLevel == newEncoderConfig.EncodeLevel && + oldEncoderConfig.EncodeTime == newEncoderConfig.EncodeTime && + oldEncoderConfig.EncodeDuration == newEncoderConfig.EncodeDuration && + oldEncoderConfig.EncodeCaller == newEncoderConfig.EncodeCaller && + oldEncoderConfig.EncodeName == newEncoderConfig.EncodeName && + oldEncoderConfig.ConsoleSeparator == newEncoderConfig.ConsoleSeparator +} diff --git a/pkg/logger/controller.go b/pkg/logger/controller.go index ce015429c..28cf24532 100644 --- a/pkg/logger/controller.go +++ b/pkg/logger/controller.go @@ -42,7 +42,7 @@ func (c *logController) setLoggerLevel(level string) bool { } c.logger.config.Level = *lvl - l, _ := c.logger.config.Build() + l, _ := c.logger.config.Build(zap.AddCallerSkip(2)) c.logger = &logger{SugaredLogger: l.Sugar(), config: c.logger.config} return true } diff --git a/pkg/logger/logger.go b/pkg/logger/logger.go index 9cbb49d2f..283f12bc0 100644 --- a/pkg/logger/logger.go +++ b/pkg/logger/logger.go @@ -19,6 +19,7 @@ package logger import ( "fmt" + "log" "os" "path" ) @@ -78,6 +79,7 @@ func InitLog(logConfFile string) error { } func InitLogger(conf *zap.Config) { + log.Println("yes start") var zapLoggerConfig zap.Config if conf == nil { zapLoggerConfig = zap.NewDevelopmentConfig() @@ -107,3 +109,8 @@ func InitLogger(conf *zap.Config) { func SetLoggerLevel(level string) bool { return control.setLoggerLevel(level) } + +func HotReload(conf *zap.Config) error { + InitLogger(conf) + return nil +} diff --git a/pkg/server/listener_manager.go b/pkg/server/listener_manager.go index 1cdccda4b..89e8a463d 100644 --- a/pkg/server/listener_manager.go +++ b/pkg/server/listener_manager.go @@ -28,7 +28,7 @@ import ( import ( "github.com/pkg/errors" - "gopkg.in/yaml.v2" + "gopkg.in/yaml.v3" ) import ( From 9431d5020dcf334e4a61542ff0613f5037524ab6 Mon Sep 17 00:00:00 2001 From: mutezebra Date: Sun, 12 Jan 2025 11:49:49 +0800 Subject: [PATCH 2/6] fix: fix license --- configcenter/nacos_load_test.go | 17 +++++++++++++++++ pkg/cmd/gateway.go | 9 --------- pkg/common/yaml/yaml.go | 2 +- pkg/config/config_load.go | 4 ++++ pkg/config/xds/lds.go | 2 +- pkg/logger/logger.go | 2 -- pkg/server/listener_manager.go | 2 +- 7 files changed, 24 insertions(+), 14 deletions(-) diff --git a/configcenter/nacos_load_test.go b/configcenter/nacos_load_test.go index e59032251..39d13c15e 100644 --- a/configcenter/nacos_load_test.go +++ b/configcenter/nacos_load_test.go @@ -1,3 +1,20 @@ +/* + * Licensed to the 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. + * The 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 configcenter import ( diff --git a/pkg/cmd/gateway.go b/pkg/cmd/gateway.go index 668286717..34b383a76 100644 --- a/pkg/cmd/gateway.go +++ b/pkg/cmd/gateway.go @@ -111,29 +111,22 @@ type DefaultDeployer struct { } func (d *DefaultDeployer) initialize() error { - logger.Info("initialize") err := initLog() if err != nil { logger.Warnf("[startGatewayCmd] failed to init logger, %s", err.Error()) } - logger.Info("initialize log success") // load Bootstrap config d.bootstrap = d.configManger.LoadBootConfig(configPath) - logger.Infof("init boot success") initLogWithConfig(d.bootstrap) - fmt.Println("emmm") - logger.Infof("init log success") err = initLimitCpus() if err != nil { logger.Errorf("[startCmd] failed to get limit cpu number, %s", err.Error()) } - logger.Infof("init cpu ?") hotreload.StartHotReload(d.configManger, d.bootstrap) - logger.Infof("have started") return err } @@ -194,9 +187,7 @@ func initLog() error { func initLogWithConfig(boot *model.Bootstrap) { if boot.Log != nil { - fmt.Println("start") logger.InitLogger(boot.Log.Build()) - fmt.Println("end") } } diff --git a/pkg/common/yaml/yaml.go b/pkg/common/yaml/yaml.go index 72a35f036..2f6281d53 100644 --- a/pkg/common/yaml/yaml.go +++ b/pkg/common/yaml/yaml.go @@ -25,7 +25,7 @@ import ( import ( perrors "github.com/pkg/errors" - "gopkg.in/yaml.v3" + "gopkg.in/yaml.v2" ) // LoadYMLConfig Load yml config byte from file diff --git a/pkg/config/config_load.go b/pkg/config/config_load.go index 64cda0764..25fcae135 100644 --- a/pkg/config/config_load.go +++ b/pkg/config/config_load.go @@ -255,6 +255,10 @@ func (m *ConfigManager) loadRemoteBootConfigs() *model.Bootstrap { // ViewRemoteConfig returns the current remote configuration. func (m *ConfigManager) ViewRemoteConfig() *model.Bootstrap { + if m.load == nil { + return nil + } + return m.load.ViewRemoteConfig() } diff --git a/pkg/config/xds/lds.go b/pkg/config/xds/lds.go index c53058cfc..cc455d129 100644 --- a/pkg/config/xds/lds.go +++ b/pkg/config/xds/lds.go @@ -24,7 +24,7 @@ import ( import ( xdsModel "github.com/dubbo-go-pixiu/pixiu-api/pkg/xds/model" - "gopkg.in/yaml.v3" + "gopkg.in/yaml.v2" ) import ( diff --git a/pkg/logger/logger.go b/pkg/logger/logger.go index 283f12bc0..9fd73af1e 100644 --- a/pkg/logger/logger.go +++ b/pkg/logger/logger.go @@ -19,7 +19,6 @@ package logger import ( "fmt" - "log" "os" "path" ) @@ -79,7 +78,6 @@ func InitLog(logConfFile string) error { } func InitLogger(conf *zap.Config) { - log.Println("yes start") var zapLoggerConfig zap.Config if conf == nil { zapLoggerConfig = zap.NewDevelopmentConfig() diff --git a/pkg/server/listener_manager.go b/pkg/server/listener_manager.go index 89e8a463d..1cdccda4b 100644 --- a/pkg/server/listener_manager.go +++ b/pkg/server/listener_manager.go @@ -28,7 +28,7 @@ import ( import ( "github.com/pkg/errors" - "gopkg.in/yaml.v3" + "gopkg.in/yaml.v2" ) import ( From 53a60d54c10b467cca2b49aeb9f20d0afb1dee6c Mon Sep 17 00:00:00 2001 From: mutezebra Date: Sun, 12 Jan 2025 20:20:57 +0800 Subject: [PATCH 3/6] style: changed the format of import --- configcenter/configclient.go | 4 +++- configcenter/nacos_load.go | 4 ++++ configcenter/nacos_load_test.go | 7 ++++++- pkg/cmd/gateway.go | 2 +- pkg/hotreload/hotreload.go | 2 ++ pkg/logger/controller.go | 2 ++ pkg/model/log.go | 5 ++++- 7 files changed, 22 insertions(+), 4 deletions(-) diff --git a/configcenter/configclient.go b/configcenter/configclient.go index f03a30e23..e74f5710a 100644 --- a/configcenter/configclient.go +++ b/configcenter/configclient.go @@ -17,7 +17,9 @@ package configcenter -import "github.com/apache/dubbo-go-pixiu/pkg/model" +import ( + "github.com/apache/dubbo-go-pixiu/pkg/model" +) type ( ConfigClient interface { diff --git a/configcenter/nacos_load.go b/configcenter/nacos_load.go index 41014074b..b1c26e9d4 100644 --- a/configcenter/nacos_load.go +++ b/configcenter/nacos_load.go @@ -19,13 +19,17 @@ package configcenter import ( "sync" +) +import ( "github.com/nacos-group/nacos-sdk-go/clients" "github.com/nacos-group/nacos-sdk-go/clients/config_client" "github.com/nacos-group/nacos-sdk-go/common/constant" "github.com/nacos-group/nacos-sdk-go/vo" "github.com/pkg/errors" +) +import ( "github.com/apache/dubbo-go-pixiu/pkg/logger" "github.com/apache/dubbo-go-pixiu/pkg/model" ) diff --git a/configcenter/nacos_load_test.go b/configcenter/nacos_load_test.go index 39d13c15e..84ba7a333 100644 --- a/configcenter/nacos_load_test.go +++ b/configcenter/nacos_load_test.go @@ -24,11 +24,16 @@ import ( "path" "strings" "testing" +) - "github.com/apache/dubbo-go-pixiu/pkg/logger" +import ( . "github.com/smartystreets/goconvey/convey" ) +import ( + "github.com/apache/dubbo-go-pixiu/pkg/logger" +) + // isNacosRunning checks whether the Nacos server is running. // It returns true if Nacos is running, otherwise false. func isNacosRunning(t *testing.T) bool { diff --git a/pkg/cmd/gateway.go b/pkg/cmd/gateway.go index 34b383a76..4392d29b6 100644 --- a/pkg/cmd/gateway.go +++ b/pkg/cmd/gateway.go @@ -19,7 +19,6 @@ package cmd import ( "fmt" - "github.com/apache/dubbo-go-pixiu/pkg/hotreload" "os" "runtime" "strconv" @@ -33,6 +32,7 @@ import ( "github.com/apache/dubbo-go-pixiu/pkg/common/constant" pxruntime "github.com/apache/dubbo-go-pixiu/pkg/common/runtime" "github.com/apache/dubbo-go-pixiu/pkg/config" + "github.com/apache/dubbo-go-pixiu/pkg/hotreload" "github.com/apache/dubbo-go-pixiu/pkg/logger" "github.com/apache/dubbo-go-pixiu/pkg/model" "github.com/apache/dubbo-go-pixiu/pkg/server" diff --git a/pkg/hotreload/hotreload.go b/pkg/hotreload/hotreload.go index 0cccf42c5..cd6acce5f 100644 --- a/pkg/hotreload/hotreload.go +++ b/pkg/hotreload/hotreload.go @@ -20,7 +20,9 @@ package hotreload import ( "sync" "time" +) +import ( "github.com/apache/dubbo-go-pixiu/pkg/common/constant" "github.com/apache/dubbo-go-pixiu/pkg/config" "github.com/apache/dubbo-go-pixiu/pkg/logger" diff --git a/pkg/logger/controller.go b/pkg/logger/controller.go index 28cf24532..914493611 100644 --- a/pkg/logger/controller.go +++ b/pkg/logger/controller.go @@ -20,7 +20,9 @@ package logger import ( "strings" "sync" +) +import ( "go.uber.org/zap" "go.uber.org/zap/zapcore" ) diff --git a/pkg/model/log.go b/pkg/model/log.go index 60bb51854..16a8c74fe 100644 --- a/pkg/model/log.go +++ b/pkg/model/log.go @@ -18,11 +18,14 @@ package model import ( - "github.com/apache/dubbo-go-pixiu/pkg/logger" "go.uber.org/zap" "go.uber.org/zap/zapcore" ) +import ( + "github.com/apache/dubbo-go-pixiu/pkg/logger" +) + type Log struct { Level string `json:"level" yaml:"level"` Development bool `json:"development" yaml:"development"` From 66f4e17450738cc8319fa21bb25b08bc58f60900 Mon Sep 17 00:00:00 2001 From: mutezebra Date: Mon, 13 Jan 2025 17:47:41 +0800 Subject: [PATCH 4/6] style: use go fmt --- go.mod | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 0b4023476..f526fb03f 100644 --- a/go.mod +++ b/go.mod @@ -49,6 +49,7 @@ require ( golang.org/x/net v0.17.0 google.golang.org/grpc v1.56.3 google.golang.org/protobuf v1.30.0 + gopkg.in/yaml.v2 v2.4.0 gopkg.in/yaml.v3 v3.0.1 mosn.io/proxy-wasm-go-host v0.1.0 ) @@ -168,5 +169,4 @@ require ( google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 // indirect gopkg.in/ini.v1 v1.66.2 // indirect gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect - gopkg.in/yaml.v2 v2.4.0 // indirect ) From e3727847c348f5d740e4b6d536c81f4e0384b8b7 Mon Sep 17 00:00:00 2001 From: mutezebra Date: Mon, 13 Jan 2025 21:29:22 +0800 Subject: [PATCH 5/6] fix: fix code --- configcenter/nacos_load.go | 12 ++++++------ pkg/common/constant/hotreload.go | 4 +++- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/configcenter/nacos_load.go b/configcenter/nacos_load.go index b1c26e9d4..5f17857c3 100644 --- a/configcenter/nacos_load.go +++ b/configcenter/nacos_load.go @@ -134,21 +134,21 @@ func (n *NacosConfig) ListenConfig(param map[string]interface{}) error { // onChange is the callback function triggered when the configuration changes in Nacos. func (n *NacosConfig) onChange(namespace, group, dataId, data string) { - n.mu.Lock() - defer n.mu.Unlock() - if len(data) == 0 { logger.Errorf("Nacos listen callback data is nil. Namespace: %s, Group: %s, DataId: %s", namespace, group, dataId) return } - boot := new(model.Bootstrap) - if err := Parsers[".yml"]([]byte(data), boot); err != nil { + n.mu.Lock() + defer n.mu.Unlock() + + var boot model.Bootstrap + if err := Parsers[".yml"]([]byte(data), &boot); err != nil { logger.Errorf("Failed to parse the configuration loaded from the remote. Error: %v", err) return } - n.remoteConfig = boot + n.remoteConfig = &boot } // ViewConfig returns the current remote configuration. diff --git a/pkg/common/constant/hotreload.go b/pkg/common/constant/hotreload.go index f2f3b3522..1be359881 100644 --- a/pkg/common/constant/hotreload.go +++ b/pkg/common/constant/hotreload.go @@ -1,6 +1,8 @@ package constant -import "time" +import ( + "time" +) const ( CheckConfigInterval = 1 * time.Second From 261535b35004824a565014850e656b404b51655d Mon Sep 17 00:00:00 2001 From: mutezebra Date: Mon, 13 Jan 2025 22:36:22 +0800 Subject: [PATCH 6/6] style: add license --- pkg/common/constant/hotreload.go | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/pkg/common/constant/hotreload.go b/pkg/common/constant/hotreload.go index 1be359881..9d0d70722 100644 --- a/pkg/common/constant/hotreload.go +++ b/pkg/common/constant/hotreload.go @@ -1,3 +1,20 @@ +/* + * Licensed to the 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. + * The 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 constant import (