github.com/alibaba/ilogtail/pkg@v0.0.0-20250526110833-c53b480d046c/flags/flags.go (about) 1 // Copyright 2021 iLogtail Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package flags 16 17 import ( 18 "context" 19 "encoding/json" 20 "flag" 21 "fmt" 22 "os" 23 "strconv" 24 "strings" 25 "sync" 26 27 "github.com/alibaba/ilogtail/pkg/logger" 28 "github.com/alibaba/ilogtail/pkg/util" 29 ) 30 31 const ( 32 DeployDaemonset = "daemonset" 33 DeployStatefulSet = "statefulset" 34 DeploySingleton = "singleton" 35 ) 36 37 const ( 38 DefaultGlobalConfig = `{"InputIntervalMs":5000,"AggregatIntervalMs":30,"FlushIntervalMs":30,"DefaultLogQueueSize":11,"DefaultLogGroupQueueSize":12}` 39 DefaultPluginConfig = `{"inputs":[{"type":"metric_mock","detail":{"Tags":{"tag1":"aaaa","tag2":"bbb"},"Fields":{"Content":"xxxxx","time":"2017.09.12 20:55:36"}}}],"flushers":[{"type":"flusher_stdout"}]}` 40 DefaultFlusherConfig = `{"type":"flusher_sls","detail":{}}` 41 LoongcollectorEnvPrefix = "LOONG_" 42 ) 43 44 var ( 45 flusherType string 46 flusherCfg map[string]interface{} 47 flusherLoadOnce sync.Once 48 ) 49 50 type LogType string 51 52 const ( 53 LogTypeInfo LogType = "info" 54 LogTypeDebug LogType = "debug" 55 LogTypeWarning LogType = "warning" 56 LogTypeError LogType = "error" 57 ) 58 59 // LogInfo contains metadata about a log message 60 type LogInfo struct { 61 LogType LogType 62 Content string 63 } 64 65 var ( 66 LogsWaitToPrint = []LogInfo{} 67 ) 68 69 // flags used to control ilogtail. 70 var ( 71 K8sFlag = flag.Bool("ALICLOUD_LOG_K8S_FLAG", false, "alibaba log k8s event config flag, set true if you want to use it") 72 // DockerConfigInitFlag is the alibaba log docker env config flag, set yes if you want to use it. And it is also a special flag to control enable go part in ilogtail. If you just want to 73 // enable logtail plugin and off the env config, set the env called ALICLOUD_LOG_PLUGIN_ENV_CONFIG with false. 74 DockerConfigInitFlag = flag.Bool("ALICLOUD_LOG_DOCKER_ENV_CONFIG", false, "alibaba log docker env config flag, set true if you want to use it") 75 DockerConfigPluginInitFlag = flag.Bool("ALICLOUD_LOG_PLUGIN_ENV_CONFIG", true, "alibaba log docker env config flag, set true if you want to use it") 76 // AliCloudECSFlag set true if your docker is on alicloud ECS, so we can use ECS meta 77 AliCloudECSFlag = flag.Bool("ALICLOUD_LOG_ECS_FLAG", false, "set true if your docker is on alicloud ECS, so we can use ECS meta") 78 79 // DockerConfigPrefix docker env config prefix 80 DockerConfigPrefix = flag.String("ALICLOUD_LOG_DOCKER_CONFIG_PREFIX", "aliyun_logs_", "docker env config prefix") 81 82 // LogServiceEndpoint default project to create config 83 // https://www.alibabacloud.com/help/doc-detail/29008.htm 84 LogServiceEndpoint = flag.String("ALICLOUD_LOG_ENDPOINT", "cn-hangzhou.log.aliyuncs.com", "log service endpoint of your project's region") 85 86 // DefaultLogProject default project to create config 87 DefaultLogProject = flag.String("ALICLOUD_LOG_DEFAULT_PROJECT", "", "default project to create config") 88 89 // DefaultLogMachineGroup default project to create config 90 DefaultLogMachineGroup = flag.String("ALICLOUD_LOG_DEFAULT_MACHINE_GROUP", "", "default project to create config") 91 92 // LogResourceCacheExpireSec log service's resources cache expire seconds 93 LogResourceCacheExpireSec = flag.Int("ALICLOUD_LOG_CACHE_EXPIRE_SEC", 600, "log service's resources cache expire seconds") 94 95 // LogOperationMaxRetryTimes log service's operation max retry times 96 LogOperationMaxRetryTimes = flag.Int("ALICLOUD_LOG_OPERATION_MAX_TRY", 3, "log service's operation max retry times") 97 98 // DefaultAccessKeyID your log service's access key id 99 DefaultAccessKeyID = flag.String("ALICLOUD_LOG_ACCESS_KEY_ID", "xxxxxxxxx", "your log service's access key id") 100 101 // DefaultAccessKeySecret your log service's access key secret 102 DefaultAccessKeySecret = flag.String("ALICLOUD_LOG_ACCESS_KEY_SECRET", "xxxxxxxxx", "your log service's access key secret") 103 104 // DefaultSTSToken your sts token 105 DefaultSTSToken = flag.String("ALICLOUD_LOG_STS_TOKEN", "", "set sts token if you use sts") 106 107 // LogConfigPrefix config prefix 108 LogConfigPrefix = flag.String("ALICLOUD_LOG_CONFIG_PREFIX", "aliyun_logs_", "config prefix") 109 110 // DockerEnvUpdateInterval docker env config update interval seconds 111 DockerEnvUpdateInterval = flag.Int("ALICLOUD_LOG_ENV_CONFIG_UPDATE_INTERVAL", 10, "docker env config update interval seconds") 112 113 // ProductAPIDomain product domain 114 ProductAPIDomain = flag.String("ALICLOUD_LOG_PRODUCT_DOMAIN", "sls.aliyuncs.com", "product domain config") 115 116 // DefaultRegion default log region" 117 DefaultRegion = flag.String("ALICLOUD_LOG_REGION", "", "default log region") 118 119 SelfEnvConfigFlag bool 120 121 EnableContainerdUpperDirDetect = flag.Bool("enable_containerd_upper_dir_detect", false, "if enable containerd upper dir detect when locating rootfs") 122 GlobalConfig = flag.String("global", "./global.json", "global config.") 123 PluginConfig = flag.String("plugin", "./plugin.json", "plugin config.") 124 FlusherConfig = flag.String("flusher", "./default_flusher.json", "the default flusher configuration is used not only in the plugins without flusher but also to transfer the self telemetry data.") 125 ForceSelfCollect = flag.Bool("force-statics", false, "force collect self telemetry data before closing.") 126 AutoProfile = flag.Bool("prof-auto", true, "auto dump prof file when prof-flag is open.") 127 HTTPProfFlag = flag.Bool("prof-flag", false, "http pprof flag.") 128 Cpuprofile = flag.String("cpu-profile", "cpu.prof", "write cpu profile to file.") 129 Memprofile = flag.String("mem-profile", "mem.prof", "write mem profile to file.") 130 HTTPAddr = flag.String("server", ":18689", "http server address.") 131 Doc = flag.Bool("doc", false, "generate plugin docs") 132 DocPath = flag.String("docpath", "./docs/en/plugins", "generate plugin docs") 133 HTTPLoadFlag = flag.Bool("http-load", false, "export http endpoint for load plugin config.") 134 FileIOFlag = flag.Bool("file-io", false, "use file for input or output.") 135 InputFile = flag.String("input-file", "./input.log", "input file") 136 InputField = flag.String("input-field", "content", "input file") 137 InputLineLimit = flag.Int("input-line-limit", 1000, "input file") 138 OutputFile = flag.String("output-file", "./output.log", "output file") 139 StatefulSetFlag = flag.Bool("ALICLOUD_LOG_STATEFULSET_FLAG", false, "alibaba log export ports flag, set true if you want to use it") 140 141 DeployMode = flag.String("DEPLOY_MODE", DeployDaemonset, "alibaba log deploy mode, daemonset or statefulset or singleton") 142 EnableKubernetesMeta = flag.Bool("ENABLE_KUBERNETES_META", false, "enable kubernetes meta") 143 ClusterID = flag.String("GLOBAL_CLUSTER_ID", "", "cluster id") 144 ClusterType = flag.String("GLOBAL_CLUSTER_TYPE", "", "cluster type, supporting ack, one, asi and k8s") 145 ) 146 147 // lookupFlag returns the flag.Flag for the given name, or an error if not found 148 func lookupFlag(name string) (*flag.Flag, error) { 149 if f := flag.Lookup(name); f != nil { 150 return f, nil 151 } 152 return nil, fmt.Errorf("flag %s not found", name) 153 } 154 155 // GetStringFlag returns the string value of the named flag 156 func GetStringFlag(name string) (string, error) { 157 f, err := lookupFlag(name) 158 if err != nil { 159 return "", err 160 } 161 return f.Value.String(), nil 162 } 163 164 // GetBoolFlag returns the bool value of the named flag 165 func GetBoolFlag(name string) (bool, error) { 166 f, err := lookupFlag(name) 167 if err != nil { 168 return false, err 169 } 170 171 if v, ok := f.Value.(flag.Getter); ok { 172 if val, ok := v.Get().(bool); ok { 173 return val, nil 174 } 175 } 176 return false, fmt.Errorf("flag %s is not bool type", name) 177 } 178 179 // GetIntFlag returns the int value of the named flag 180 func GetIntFlag(name string) (int, error) { 181 f, err := lookupFlag(name) 182 if err != nil { 183 return 0, err 184 } 185 186 if v, ok := f.Value.(flag.Getter); ok { 187 if val, ok := v.Get().(int); ok { 188 return val, nil 189 } 190 } 191 return 0, fmt.Errorf("flag %s is not int type", name) 192 } 193 194 // GetFloat64Flag returns the float64 value of the named flag 195 func GetFloat64Flag(name string) (float64, error) { 196 f, err := lookupFlag(name) 197 if err != nil { 198 return 0.0, err 199 } 200 201 if v, ok := f.Value.(flag.Getter); ok { 202 if val, ok := v.Get().(float64); ok { 203 return val, nil 204 } 205 } 206 return 0.0, fmt.Errorf("flag %s is not float64 type", name) 207 } 208 209 // SetStringFlag sets the string value of the named flag 210 func SetStringFlag(name, value string) error { 211 f, err := lookupFlag(name) 212 if err != nil { 213 return err 214 } 215 return f.Value.Set(value) 216 } 217 218 // SetBoolFlag sets the bool value of the named flag 219 func SetBoolFlag(name string, value bool) error { 220 f, err := lookupFlag(name) 221 if err != nil { 222 return err 223 } 224 return f.Value.Set(strconv.FormatBool(value)) 225 } 226 227 // SetIntFlag sets the int value of the named flag 228 func SetIntFlag(name string, value int) error { 229 f, err := lookupFlag(name) 230 if err != nil { 231 return err 232 } 233 return f.Value.Set(strconv.Itoa(value)) 234 } 235 236 // SetFloat64Flag sets the float64 value of the named flag 237 func SetFloat64Flag(name string, value float64) error { 238 f, err := lookupFlag(name) 239 if err != nil { 240 return err 241 } 242 return f.Value.Set(strconv.FormatFloat(value, 'g', -1, 64)) 243 } 244 245 // LoadEnvToFlags loads environment variables into flags 246 func LoadEnvToFlags() { 247 for _, env := range os.Environ() { 248 name, value, found := strings.Cut(env, "=") 249 if !found { 250 continue 251 } 252 var flagName string 253 if strings.HasPrefix(name, LoongcollectorEnvPrefix) { 254 flagName = strings.ToLower(strings.TrimPrefix(name, LoongcollectorEnvPrefix)) 255 } else { 256 flagName = name 257 } 258 259 f := flag.Lookup(flagName) 260 if f == nil { 261 continue 262 } 263 264 oldValue := f.Value.String() 265 getter, ok := f.Value.(flag.Getter) 266 if !ok { 267 LogsWaitToPrint = append(LogsWaitToPrint, LogInfo{ 268 LogType: LogTypeError, 269 Content: fmt.Sprintf("Flag does not support Get operation, flag: %s, value: %s", flagName, oldValue), 270 }) 271 continue 272 } 273 274 actualValue := getter.Get() 275 var err error 276 277 // Validate value type before setting 278 switch actualValue.(type) { 279 case bool: 280 _, err = strconv.ParseBool(value) 281 case int, int64: 282 _, err = strconv.ParseInt(value, 10, 64) 283 case uint, uint64: 284 _, err = strconv.ParseUint(value, 10, 64) 285 case float64: 286 _, err = strconv.ParseFloat(value, 64) 287 case string: 288 // No validation needed 289 default: 290 LogsWaitToPrint = append(LogsWaitToPrint, LogInfo{ 291 LogType: LogTypeError, 292 Content: fmt.Sprintf("Unsupported flag type: %s (%T)", flagName, actualValue), 293 }) 294 continue 295 } 296 297 if err != nil { 298 LogsWaitToPrint = append(LogsWaitToPrint, LogInfo{ 299 LogType: LogTypeError, 300 Content: fmt.Sprintf("Invalid value for flag %s (%T): %s - %v", flagName, actualValue, value, err), 301 }) 302 continue 303 } 304 305 if err := f.Value.Set(value); err != nil { 306 LogsWaitToPrint = append(LogsWaitToPrint, LogInfo{ 307 LogType: LogTypeError, 308 Content: fmt.Sprintf("Failed to set flag %s: %v (old: %s, new: %s)", flagName, err, oldValue, value), 309 }) 310 continue 311 } 312 313 LogsWaitToPrint = append(LogsWaitToPrint, LogInfo{ 314 LogType: LogTypeInfo, 315 Content: fmt.Sprintf("Updated flag %s (%T): %s -> %s", flagName, actualValue, oldValue, f.Value.String()), 316 }) 317 } 318 } 319 320 func init() { 321 _ = util.InitFromEnvBool("ALICLOUD_LOG_K8S_FLAG", K8sFlag, *K8sFlag) 322 _ = util.InitFromEnvBool("ALICLOUD_LOG_DOCKER_ENV_CONFIG", DockerConfigInitFlag, *DockerConfigInitFlag) 323 _ = util.InitFromEnvBool("ALICLOUD_LOG_ECS_FLAG", AliCloudECSFlag, *AliCloudECSFlag) 324 _ = util.InitFromEnvString("ALICLOUD_LOG_DOCKER_CONFIG_PREFIX", DockerConfigPrefix, *DockerConfigPrefix) 325 _ = util.InitFromEnvString("ALICLOUD_LOG_DEFAULT_PROJECT", DefaultLogProject, *DefaultLogProject) 326 _ = util.InitFromEnvString("ALICLOUD_LOG_DEFAULT_MACHINE_GROUP", DefaultLogMachineGroup, *DefaultLogMachineGroup) 327 _ = util.InitFromEnvString("ALICLOUD_LOG_ENDPOINT", LogServiceEndpoint, *LogServiceEndpoint) 328 _ = util.InitFromEnvString("ALICLOUD_LOG_ACCESS_KEY_ID", DefaultAccessKeyID, *DefaultAccessKeyID) 329 _ = util.InitFromEnvString("ALICLOUD_LOG_ACCESS_KEY_SECRET", DefaultAccessKeySecret, *DefaultAccessKeySecret) 330 _ = util.InitFromEnvString("ALICLOUD_LOG_STS_TOKEN", DefaultSTSToken, *DefaultSTSToken) 331 _ = util.InitFromEnvString("ALICLOUD_LOG_CONFIG_PREFIX", LogConfigPrefix, *LogConfigPrefix) 332 _ = util.InitFromEnvString("ALICLOUD_LOG_PRODUCT_DOMAIN", ProductAPIDomain, *ProductAPIDomain) 333 _ = util.InitFromEnvString("ALICLOUD_LOG_REGION", DefaultRegion, *DefaultRegion) 334 _ = util.InitFromEnvBool("ALICLOUD_LOG_PLUGIN_ENV_CONFIG", DockerConfigPluginInitFlag, *DockerConfigPluginInitFlag) 335 336 _ = util.InitFromEnvBool("enable_containerd_upper_dir_detect", EnableContainerdUpperDirDetect, *EnableContainerdUpperDirDetect) 337 _ = util.InitFromEnvBool("LOGTAIL_DEBUG_FLAG", HTTPProfFlag, *HTTPProfFlag) 338 _ = util.InitFromEnvBool("LOGTAIL_AUTO_PROF", AutoProfile, *AutoProfile) 339 _ = util.InitFromEnvBool("LOGTAIL_FORCE_COLLECT_SELF_TELEMETRY", ForceSelfCollect, *ForceSelfCollect) 340 _ = util.InitFromEnvBool("LOGTAIL_HTTP_LOAD_CONFIG", HTTPLoadFlag, *HTTPLoadFlag) 341 _ = util.InitFromEnvBool("ALICLOUD_LOG_STATEFULSET_FLAG", StatefulSetFlag, *StatefulSetFlag) 342 343 _ = util.InitFromEnvString("DEPLOY_MODE", DeployMode, *DeployMode) 344 _ = util.InitFromEnvBool("ENABLE_KUBERNETES_META", EnableKubernetesMeta, *EnableKubernetesMeta) 345 _ = util.InitFromEnvString("GLOBAL_CLUSTER_ID", ClusterID, *ClusterID) 346 _ = util.InitFromEnvString("GLOBAL_CLUSTER_TYPE", ClusterType, *ClusterType) 347 348 if len(*DefaultRegion) == 0 { 349 *DefaultRegion = util.GuessRegionByEndpoint(*LogServiceEndpoint, "cn-hangzhou") 350 LogsWaitToPrint = append(LogsWaitToPrint, LogInfo{ 351 LogType: LogTypeInfo, 352 Content: fmt.Sprintf("guess region by endpoint, endpoint: %s, region: %s", *LogServiceEndpoint, *DefaultRegion), 353 }) 354 } 355 356 _ = util.InitFromEnvInt("ALICLOUD_LOG_ENV_CONFIG_UPDATE_INTERVAL", DockerEnvUpdateInterval, *DockerEnvUpdateInterval) 357 358 if *DockerConfigInitFlag && *DockerConfigPluginInitFlag { 359 _ = util.InitFromEnvBool("ALICLOUD_LOG_DOCKER_ENV_CONFIG_SELF", &SelfEnvConfigFlag, false) 360 } 361 // 最后执行,优先级最高 362 LoadEnvToFlags() 363 } 364 365 // GetFlusherConfiguration returns the flusher category and options. 366 func GetFlusherConfiguration() (flusherCategory string, flusherOptions map[string]interface{}) { 367 flusherLoadOnce.Do(func() { 368 extract := func(cfg []byte) (string, map[string]interface{}, bool) { 369 m := make(map[string]interface{}) 370 err := json.Unmarshal(cfg, &m) 371 if err != nil { 372 logger.Error(context.Background(), "DEFAULT_FLUSHER_ALARM", "err", err) 373 return "", nil, false 374 } 375 c, ok := m["type"].(string) 376 if !ok { 377 return "", nil, false 378 } 379 options, ok := m["detail"].(map[string]interface{}) 380 if !ok { 381 return c, nil, true 382 } 383 return c, options, true 384 } 385 if fCfg, err := os.ReadFile(*FlusherConfig); err == nil { 386 category, options, ok := extract(fCfg) 387 if ok { 388 flusherType = category 389 flusherCfg = options 390 } else { 391 flusherType, flusherCfg, _ = extract([]byte(DefaultFlusherConfig)) 392 } 393 } else { 394 flusherType, flusherCfg, _ = extract([]byte(DefaultFlusherConfig)) 395 } 396 397 }) 398 return flusherType, flusherCfg 399 }