Thanos源码专题【左扬精讲】——Thanos Tools 组件(release-0.26)源码阅读和分析(详解 cmd/tools.go)

Thanos Tools 组件(release-0.26)源码阅读和分析(详解 cmd/tools.go)

https://github.com/thanos-io/thanos/blob/v0.26.0/cmd/thanos/tools.go

// Copyright (c) The Thanos Authors.
// Licensed under the Apache License 2.0.

package main

import (
	"os"
	"path/filepath"

	"github.com/go-kit/log"
	"github.com/go-kit/log/level"
	"github.com/oklog/run"
	"github.com/opentracing/opentracing-go"
	"github.com/pkg/errors"
	"github.com/prometheus/client_golang/prometheus"

	"github.com/thanos-io/thanos/pkg/errutil"
	"github.com/thanos-io/thanos/pkg/extkingpin"
	"github.com/thanos-io/thanos/pkg/rules"
)

type checkRulesConfig struct {
	rulesFiles []string
}

// registerTools 注册各种工具命令到给定的应用实例中
//
// 参数:
//
//	app:指向extkingpin.App类型的指针,表示需要注册命令的应用实例
func registerTools(app *extkingpin.App) {
	// 创建一个名为"tools"的命令,描述为"Tools utility commands"
	cmd := app.Command("tools", "Tools utility commands")

	// 注册Bucket相关的命令
	registerBucket(cmd)
	// 注册CheckRules相关的命令
	registerCheckRules(cmd)
}

// registerFlag 注册一个名为 "rules" 的命令行标志,并返回 tc 对象
// 参数:
// cmd - extkingpin.FlagClause 类型,表示命令行标志的上下文
// 返回值:
// *checkRulesConfig - 返回 tc 对象
func (tc *checkRulesConfig) registerFlag(cmd extkingpin.FlagClause) *checkRulesConfig {
	// 注册一个名为 "rules" 的命令行标志
	cmd.Flag("rules", "要检查的规则文件glob模式(可重复)").Required().StringsVar(&tc.rulesFiles)
	// 返回 tc 对象
	return tc
}

// registerCheckRules 在给定的extkingpin.AppClause上注册 "rules-check" 命令,用于检查规则文件是否有效。
func registerCheckRules(app extkingpin.AppClause) {
	// 注册命令 "rules-check"
	cmd := app.Command("rules-check", "Check if the rule files are valid or not.")
	// 初始化 checkRulesConfig 结构体实例
	crc := &checkRulesConfig{}
	// 注册命令参数
	crc.registerFlag(cmd)
	// 设置命令执行逻辑
	cmd.Setup(func(g *run.Group, logger log.Logger, reg *prometheus.Registry, _ opentracing.Tracer, _ <-chan struct{}, _ bool) error {
		// 添加一个虚拟的 actor,在 run 函数返回后立即终止 group
		// Dummy actor to immediately kill the group after the run function returns.
		g.Add(func() error { return nil }, func(error) {})
		// 检查规则文件
		return checkRulesFiles(logger, &crc.rulesFiles)
	})
}

// checkRulesFiles 函数根据提供的模式列表检查规则文件,并返回错误。
//
// 参数:
// logger: log.Logger类型的日志记录器,用于记录日志信息。
// patterns: *[]string类型的指针,指向包含模式列表的切片。
//
// 返回值:
// error类型的返回值,如果所有模式都成功匹配并验证了文件,则返回nil;否则返回一个包含所有错误的MultiError对象。
func checkRulesFiles(logger log.Logger, patterns *[]string) error {
	var failed errutil.MultiError

	for _, p := range *patterns {
		// 记录日志,表示正在检查模式
		level.Info(logger).Log("msg", "checking", "pattern", p)
		matches, err := filepath.Glob(p)
		if err != nil || matches == nil {
			// 如果匹配文件未找到,则记录错误日志并添加到失败列表中
			err = errors.New("matching file not found")
			level.Error(logger).Log("result", "FAILED", "error", err)
			level.Info(logger).Log()
			failed.Add(err)
			continue
		}
		for _, fn := range matches {
			// 记录日志,表示正在检查文件
			level.Info(logger).Log("msg", "checking", "filename", filepath.Clean(fn))
			f, er := os.Open(fn)
			if er != nil {
				// 如果打开文件失败,则记录错误日志并添加到失败列表中
				level.Error(logger).Log("result", "FAILED", "error", er)
				level.Info(logger).Log()
				failed.Add(err)
				continue
			}
			// 确保文件在函数结束时关闭
			defer func() { _ = f.Close() }()

			n, errs := rules.ValidateAndCount(f)
			if errs.Err() != nil {
				// 如果验证失败,则记录错误日志并添加到失败列表中
				level.Error(logger).Log("result", "FAILED")
				for _, e := range errs {
					level.Error(logger).Log("error", e.Error())
					failed.Add(e)
				}
				level.Info(logger).Log()
				continue
			}
			// 记录日志,表示验证成功并输出找到的规则数量
			level.Info(logger).Log("result", "SUCCESS", "rules found", n)
		}
	}
	return failed.Err()
}
posted @ 2025-02-12 20:34  左扬  阅读(24)  评论(0)    收藏  举报