《scope源码解析4——main.go》

其实前三篇根本算不上源码分析,只是对项目的简单了解和环境的搭建。而从这一篇开始,我们才真正能接触到scope项目的源码。

在go语言中,我们可以用var来定义一组变量,比如:

	var(
		name string
		age int
	)

我们先看main.go中的main函数,一开头用var定义了一组变量。

var (
		flags                            = flags{}
		mode                             string
		debug                            bool
		weaveEnabled                     bool
		weaveHostname                    string
		dryRun                           bool
		containerLabelFilterFlags        = containerLabelFiltersFlag{exclude: false, filterIDPrefix: "containerLabelFilterExclude"}
		containerLabelFilterFlagsExclude = containerLabelFiltersFlag{exclude: true, filterIDPrefix: "containerLabelFilter"}
	)

在go语言中,flag包用于解析命令行参数。其使用方法主要包括三个步骤。

第一步:定义flag参数(有三种形式)

形式1:通过flag.String(),flag.Bool(),flag.Int()等flag.Xxx()方法,该方法返回一个相应的指针。

var help=flag.String("name","jack","main.exe --name \"jack\"")

形式2:通过flag.XxxVar()方法将flag参数绑定到一个变量。

flag.IntVar(&age,"age",18,"--age 17")
在scope中,用到探针和app的flags变量就是采用的这种方法。

// Flags that apply to both probe and app
	flag.StringVar(&mode, "mode", "help", "For internal use.")
	flag.BoolVar(&debug, "debug", false, "Force debug logging.")
	flag.BoolVar(&dryRun, "dry-run", false, "Don't start scope, just parse the arguments.  For internal use only.")
	flag.BoolVar(&weaveEnabled, "weave", true, "Enable Weave Net integrations.")
	flag.StringVar(&weaveHostname, "weave.hostname", app.DefaultHostname, "Hostname to advertise/lookup in WeaveDNS")

形式3:通过flag.Var()方法绑定自定义类型,自定义类型需要实现Value接口。

在scope中,也有用到这种方法。例如:

flag.Var(&containerLabelFilterFlags, "app.container-label-filter", "Add container label-based view filter, specified as title:label. Multiple flags are accepted. Example: --app.container-label-filter='Database Containers:role=db'")
flag.Var(&containerLabelFilterFlagsExclude, "app.container-label-filter-exclude", "Add container label-based view filter that excludes containers with the given label, specified as title:label. Multiple flags are accepted. Example: --app.container-label-filter-exclude='Database Containers:role=db'")
而containerLabelFilterFlags和containerLabelFilterFlagsExclude都是containerLabelFiltersFlag变量,containerLabelFiltersFlag则实现了Value接口,例如:

type containerLabelFiltersFlag struct {
	apiTopologyOptions []app.APITopologyOption
	filterNumber       int
	filterIDPrefix     string
	exclude            bool
}

func (c *containerLabelFiltersFlag) String() string {
	return fmt.Sprint(c.apiTopologyOptions)
}

func (c *containerLabelFiltersFlag) Set(flagValue string) error {
	filterID := fmt.Sprintf(c.filterIDPrefix+"%d", c.filterNumber)
	newAPITopologyOption, err := c.toAPITopologyOption(flagValue, filterID)
	if err != nil {
		return err
	}
	c.filterNumber++

	c.apiTopologyOptions = append(c.apiTopologyOptions, newAPITopologyOption)
	return nil
}

func (c *containerLabelFiltersFlag) toAPITopologyOption(flagValue string, filterID string) (app.APITopologyOption, error) {
	indexRanges := colonFinder.FindAllStringIndex(flagValue, -1)
	if len(indexRanges) != 1 {
		if len(indexRanges) == 0 {
			return app.APITopologyOption{}, fmt.Errorf("No unescaped colon found. This is needed to separate the title from the label")
		}
		return app.APITopologyOption{}, fmt.Errorf("Multiple unescaped colons. Escape colons that are part of the title and label")
	}
	splitIndices := indexRanges[0]
	titleStringEscaped := flagValue[:splitIndices[0]+1]
	labelStringEscaped := flagValue[splitIndices[1]:]
	containerFilterTitle := unescapeBackslashes.ReplaceAllString(titleStringEscaped, `$1`)
	containerFilterLabel := unescapeBackslashes.ReplaceAllString(labelStringEscaped, `$1`)
	labelKeyValuePair := strings.Split(containerFilterLabel, "=")
	if len(labelKeyValuePair) != 2 {
		return app.APITopologyOption{}, fmt.Errorf("Docker label isn't in the correct key=value format")
	}

	filterFunction := render.HasLabel
	if c.exclude {
		filterFunction = render.DoesNotHaveLabel
	}
	return app.MakeAPITopologyOption(filterID, containerFilterTitle, filterFunction(labelKeyValuePair[0], labelKeyValuePair[1]), false), nil
}

第二步:调用flag.Parse()解析命令行参数到定义的flag。

flag.Parse()

第三步:直接使用flag本身或者其绑定的变量。


在scope中的main.go代码的最下面,我们看到经过一系列的命令行参数解析后最终会调用一下方法。

switch mode {
	case "app":
		appMain(flags.app)
	case "probe":
		probeMain(flags.probe, targets)
	case "version":
		fmt.Println("Weave Scope version", version)
	case "help":
		flag.PrintDefaults()
	default:
		fmt.Printf("command '%s' not recognized", mode)
		os.Exit(1)
	}

其中appMain和probeMain是我们应该重点关注的两个方法。接下来我们先跟踪下probeMain这个方法。毕竟它的意思是探针。对于监控数据的收集应该是在这个探针里面。



评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

MXi4oyu

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值