github.com/isyscore/isc-gobase@v1.5.3-0.20231218061332-cbc7451899e9/debug/debug_config.go (about) 1 package debug 2 3 import ( 4 "context" 5 "github.com/isyscore/isc-gobase/config" 6 "github.com/isyscore/isc-gobase/logger" 7 baseNet "github.com/isyscore/isc-gobase/system/net" 8 etcdClientV3 "go.etcd.io/etcd/client/v3" 9 "os" 10 "strings" 11 "sync" 12 ) 13 14 const ( 15 DEBUG_ETCD_ENDPOINTS = "debug.etcd.endpoints" 16 DEBUG_ETCD_USER = "debug.etcd.user" 17 DEBUG_ETCD_PASSWORD = "debug.etcd.password" 18 DEFAULT_ETCD_ENDPOINT = "etcd-service:22379" 19 ) 20 21 var etcdClient *etcdClientV3.Client 22 var keyListenerMap map[string][]KeyListener 23 24 var loadLock sync.Mutex 25 type KeyListener func(key string, value string) 26 27 func Init() { 28 if !config.GetValueBoolDefault("debug.enable", true) { 29 return 30 } 31 InitWithParameter(GetEtcdConfig()) 32 } 33 34 func InitWithParameter(endpoints []string, user, password string) { 35 loadLock.Lock() 36 defer loadLock.Unlock() 37 if etcdClient != nil { 38 return 39 } 40 41 for _, endpoint := range endpoints { 42 if !baseNet.IpPortAvailable(endpoint) { 43 // 如果想使用调试模式,请在环境变量里面或者配置文件里面配置如下 44 // debug.etcd.endpoints:多个{ip}:{port}格式,中间以逗号(英文逗号)分隔 45 // debug.etcd.user 46 // debug.etcd.password 47 logger.Warn("调试模式【%v】不可用,调试功能暂时不支持", endpoint) 48 return 49 } 50 } 51 52 _etcdClient := getEtcdClient(endpoints, user, password) 53 if _etcdClient == nil { 54 return 55 } 56 57 etcdClient = _etcdClient 58 } 59 60 func getEtcdClient(etcdPoints []string, user, password string) *etcdClientV3.Client { 61 // 客户端配置 62 etcdCfg := etcdClientV3.Config{ 63 Endpoints: etcdPoints, 64 Username: user, 65 Password: password, 66 } 67 68 etcdClient, err := etcdClientV3.New(etcdCfg) 69 if err != nil { 70 logger.Error("生成etcd-client失败:%v", err.Error()) 71 return nil 72 } 73 74 return etcdClient 75 } 76 77 // 优先级:vm配置 > 环境变量 78 func GetEtcdConfig() ([]string, string, string) { 79 etcdEndpointStr := os.Getenv(DEBUG_ETCD_ENDPOINTS) 80 etcdEndpointStrOfConfig := config.GetValueString(DEBUG_ETCD_ENDPOINTS) 81 if etcdEndpointStrOfConfig != "" { 82 etcdEndpointStr = etcdEndpointStrOfConfig 83 } 84 85 if etcdEndpointStr == "" { 86 etcdEndpointStr = DEFAULT_ETCD_ENDPOINT 87 } 88 89 etcdEndpointsOriginal := strings.Split(etcdEndpointStr, ",") 90 var etcdEndpoints []string 91 for _, etcdEndpoint := range etcdEndpointsOriginal { 92 etcdEndpoint = strings.TrimSpace(etcdEndpoint) 93 if strings.HasPrefix(etcdEndpoint, "http://") { 94 etcdEndpoint = etcdEndpoint[len("http://"):] 95 } 96 97 etcdEndpoints = append(etcdEndpoints, etcdEndpoint) 98 } 99 100 etcdUser := os.Getenv(DEBUG_ETCD_USER) 101 etcdUserOfConfig := config.GetValueString(DEBUG_ETCD_USER) 102 if etcdUserOfConfig != "" { 103 etcdUser = etcdUserOfConfig 104 } 105 106 etcdPassword := os.Getenv(DEBUG_ETCD_PASSWORD) 107 etcdPasswordOfConfig := config.GetValueString(DEBUG_ETCD_PASSWORD) 108 if etcdPasswordOfConfig != "" { 109 etcdPassword = etcdPasswordOfConfig 110 } 111 112 return etcdEndpoints, etcdUser, etcdPassword 113 } 114 115 func AddWatcher(key string, keyListener KeyListener) { 116 if etcdClient == nil { 117 return 118 } 119 120 if keyListenerMap == nil { 121 keyListenerMap = map[string][]KeyListener{} 122 } 123 if eventWatchers, exist := keyListenerMap[key]; exist { 124 eventWatchers = append(eventWatchers, keyListener) 125 keyListenerMap[key] = eventWatchers 126 } else { 127 eventWatchers = []KeyListener{} 128 eventWatchers = append(eventWatchers, keyListener) 129 keyListenerMap[key] = eventWatchers 130 } 131 } 132 133 func Update(key, value string) { 134 ctx := context.Background() 135 _, err := etcdClient.Put(ctx, key, value) 136 if err != nil { 137 logger.Error("更新调试配置报错") 138 return 139 } 140 } 141 142 func StartWatch() { 143 for key, listeners := range keyListenerMap { 144 watchKey := key 145 keyListeners := listeners 146 go func() { 147 var currentVersion int64 = 0 148 ctx := context.Background() 149 150 // 首次启动获取最新的 151 rsp, err := etcdClient.Get(ctx, watchKey) 152 if err != nil { 153 logger.Error("获取etcd的key异常, %v", err.Error()) 154 return 155 } else { 156 for _, kv := range rsp.Kvs { 157 if watchKey == string(kv.Key) { 158 currentVersion = kv.ModRevision 159 go notifyWatcher(watchKey, string(kv.Value), keyListeners) 160 } 161 } 162 } 163 164 // 根据本地保存的最新版本进行watch 165 watchRsp := etcdClient.Watch(ctx, watchKey, etcdClientV3.WithRev(currentVersion)) 166 for res := range watchRsp { 167 for _, event := range res.Events { 168 if watchKey != string(event.Kv.Key) { 169 continue 170 } 171 latestModVersion := event.Kv.ModRevision 172 173 if currentVersion == event.Kv.ModRevision { 174 continue 175 } else if currentVersion < latestModVersion { 176 currentVersion = latestModVersion 177 go notifyWatcher(watchKey, string(event.Kv.Value), keyListeners) 178 } 179 } 180 } 181 }() 182 } 183 } 184 185 func notifyWatcher(key, value string, listeners []KeyListener) { 186 for _, listener := range listeners { 187 listener(key, value) 188 } 189 }