Thanos源码专题【左扬精讲】——Thanos API 组件(release-0.26)源码阅读和分析(详解 pkg\api\api.go)
Thanos API 组件(release-0.26)源码阅读和分析(详解 pkg\api\api.go)
https://github.com/thanos-io/thanos/blob/v0.26.0/pkg/api/api.go
// Copyright (c) The Thanos Authors.
// Licensed under the Apache License 2.0.
// Copyright 2016 The Prometheus Authors
// Licensed 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.
// This package is a modified copy from
// github.com/prometheus/prometheus/web/api/v1@2121b4628baa7d9d9406aa468712a6a332e77aff.
package api
import (
"encoding/json" // for json.Marshal
"fmt" // for fmt.Errorf
"net/http" // for http.Server
"os" // for os.Exit
"runtime" // for runtime.NumCPU
"time" // for time.Duration
"github.com/NYTimes/gziphandler" // for gziphandler.GzipHandler
"github.com/go-kit/log" // for log.Logger
"github.com/go-kit/log/level" // for level.Info
"github.com/opentracing/opentracing-go" // for opentracing.Tracer
"github.com/prometheus/common/route" // for route.NewRoute
"github.com/prometheus/common/version" // for version.Version
extpromhttp "github.com/thanos-io/thanos/pkg/extprom/http" // for extpromhttp.MetricsHandler
"github.com/thanos-io/thanos/pkg/logging" // for logging.WithContext
"github.com/thanos-io/thanos/pkg/server/http/middleware" // for middleware.Tracing
"github.com/thanos-io/thanos/pkg/tracing" // for tracing.Tracer
)
type status string
const (
StatusSuccess status = "success"
StatusError status = "error"
)
type ErrorType string
const (
ErrorNone ErrorType = ""
ErrorTimeout ErrorType = "timeout" // 超时错误
ErrorCanceled ErrorType = "canceled" // 取消错误
ErrorExec ErrorType = "execution" // 执行错误
ErrorBadData ErrorType = "bad_data" // 错误数据
ErrorInternal ErrorType = "internal" // 内部错误
)
// corsHeaders 是 CORS 头部的默认值。
var corsHeaders = map[string]string{
"Access-Control-Allow-Headers": "Accept, Accept-Encoding, Authorization, Content-Type, Origin",
"Access-Control-Allow-Methods": "GET, OPTIONS",
"Access-Control-Allow-Origin": "*",
"Access-Control-Expose-Headers": "Date",
}
// ThanosVersion contains build information about Thanos.
// ThanosVersion 包含构建信息。比如版本号、修订版、分支、构建用户、构建日期、Go版本。
type ThanosVersion struct {
Version string `json:"version"` // 版本号
Revision string `json:"revision"` // 修订版
Branch string `json:"branch"` // 分支
BuildUser string `json:"buildUser"` // 构建用户
BuildDate string `json:"buildDate"` // 构建日期
GoVersion string `json:"goVersion"` // Go版本号
}
// BuildInfo 是初始化的 ThanosVersion 对象。
var BuildInfo = &ThanosVersion{
Version: version.Version, // 版本号,比如 v0.18.0
Revision: version.Revision, // 修订版,比如 123456789abcdef0
Branch: version.Branch, // 分支,比如 master
BuildUser: version.BuildUser, // 构建用户,比如 root@localhost
BuildDate: version.BuildDate, // 构建日期,比如 2020-01-01T00:00:00Z
GoVersion: version.GoVersion, // Go的版本号,比如 go-v1.24.0
}
type ApiError struct {
Typ ErrorType
Err error
}
// Error 返回API错误的字符串表示。
// 使用fmt.Sprintf格式化字符串,将e.Typ和e.Err拼接成一个错误消息。
func (e *ApiError) Error() string {
// 使用fmt.Sprintf格式化字符串,将e.Typ和e.Err拼接成一个错误消息
return fmt.Sprintf("%s: %s", e.Typ, e.Err)
}
// RuntimeInfo contains runtime information about Thanos.
type RuntimeInfo struct {
StartTime time.Time `json:"startTime"` // 启动时间
CWD string `json:"CWD"` // 当前工作目录
GoroutineCount int `json:"goroutineCount"` // 协程数量
GOMAXPROCS int `json:"GOMAXPROCS"` // GOMAXPROCS的值,表示可以同时运行的协程数量
GOGC string `json:"GOGC"` // GOGC的值,表示垃圾回收的目标百分比
GODEBUG string `json:"GODEBUG"` // GODEBUG的值,表示调试标志
}
// RuntimeInfoFn returns updated runtime information about Thanos.
// 返回一个RuntimeInfo结构体,包含Thanos的运行时信息。
type RuntimeInfoFn func() RuntimeInfo
type response struct {
Status status `json:"status"` // 状态,比如 "success" 或 "error"
Data interface{} `json:"data,omitempty"` // 数据,比如查询结果
ErrorType ErrorType `json:"errorType,omitempty"` // 错误类型,比如 "timeout" 或 "internal"
Error string `json:"error,omitempty"` // 错误信息,比如 "timeout: context canceled"
Warnings []string `json:"warnings,omitempty"` // 警告信息,比如 "some warning"
}
// SetCORS enables cross-site script calls.
// SetCORS 函数用于设置跨源资源共享(CORS)相关的响应头。
//
// 参数:
// w http.ResponseWriter: 用于写入响应的HTTP响应写入器。
func SetCORS(w http.ResponseWriter) {
// 遍历 corsHeaders 映射
for h, v := range corsHeaders {
// 设置响应头,键为 h,值为 v
w.Header().Set(h, v)
}
}
// ApiFunc 是一个函数类型,用于处理HTTP请求,并返回响应数据、警告信息以及可能的错误。
type ApiFunc func(r *http.Request) (interface{}, []error, *ApiError)
// BaseAPI 是一个HTTP API的基础类型,用于处理HTTP请求,并返回响应数据、警告信息以及可能的错误。
type BaseAPI struct {
logger log.Logger // 日志记录器,用于记录日志信息。
flagsMap map[string]string // 标志映射,用于存储命令行标志的值。
runtimeInfo RuntimeInfoFn // 运行时信息获取函数,用于获取Thanos的当前运行状态。
buildInfo *ThanosVersion // 构建信息,包含Thanos的版本、修订版等信息。
Now func() time.Time // 当前时间的获取函数,用于记录请求处理的时间。
disableCORS bool // 是否禁用CORS,如果为true,则不会设置CORS相关的响应头。
}
// NewBaseAPI returns a new initialized BaseAPI type.
// NewBaseAPI 创建一个新的 BaseAPI 实例
//
// 参数:
//
// logger: 日志记录器
// disableCORS: 是否禁用CORS
// flagsMap: 标志映射
//
// 返回值:
//
// 返回一个指向 BaseAPI 实例的指针
func NewBaseAPI(logger log.Logger, disableCORS bool, flagsMap map[string]string) *BaseAPI {
// 初始化BaseAPI结构体
return &BaseAPI{
// 日志记录器
logger: logger,
// 标志映射
flagsMap: flagsMap,
// 运行时信息获取函数
runtimeInfo: GetRuntimeInfoFunc(logger),
// 构建信息
buildInfo: BuildInfo,
// 是否禁用CORS
disableCORS: disableCORS,
// 获取当前时间函数
Now: time.Now,
}
}
// Register registers the common API endpoints.
// Register 方法用于注册HTTP路由处理函数
//
// 参数:
//
// r: HTTP路由对象
// tracer: OpenTracing的Tracer对象
// logger: 日志记录器对象
// ins: 仪器化中间件
// logMiddleware: HTTP服务器日志中间件
//
// 说明:
//
// 该方法会将不同的HTTP请求路径和处理函数绑定到HTTP路由对象上。
// 通过仪器化中间件对请求进行监控和日志记录。
func (api *BaseAPI) Register(r *route.Router, tracer opentracing.Tracer, logger log.Logger, ins extpromhttp.InstrumentationMiddleware, logMiddleware *logging.HTTPServerMiddleware) {
// 获取仪器化中间件
instr := GetInstr(tracer, logger, ins, logMiddleware, api.disableCORS)
// 注册 OPTIONS 方法处理函数
r.Options("/*path", instr("options", api.options))
// 注册获取状态标志的方法处理函数
r.Get("/status/flags", instr("status_flags", api.flags))
// 注册获取运行时信息的方法处理函数
r.Get("/status/runtimeinfo", instr("status_runtime", api.serveRuntimeInfo))
// 注册获取构建信息的方法处理函数
r.Get("/status/buildinfo", instr("status_build", api.serveBuildInfo))
}
// options 方法目前不执行任何操作,直接返回三个空值
//
// 参数:
//
// r *http.Request: 传入的HTTP请求
//
// 返回值:
//
// interface{}: 返回的接口类型的值,此处为空
// []error: 返回的错误列表,此处为空
// *ApiError: 返回的API错误信息,此处为空
func (api *BaseAPI) options(r *http.Request) (interface{}, []error, *ApiError) {
// 此函数目前不执行任何操作,直接返回三个空值
return nil, nil, nil
}
// flags 函数用于获取 BaseAPI 实例的 flagsMap。
//
// 参数:
//
// r *http.Request: HTTP 请求对象,此参数在本函数中未被使用。
//
// 返回值:
//
// interface{}: 返回 api 的 flagsMap。
// []error: 返回错误信息列表,本函数始终返回 nil。
// *ApiError: 返回 ApiError 对象,本函数始终返回 nil。
func (api *BaseAPI) flags(r *http.Request) (interface{}, []error, *ApiError) {
// 直接返回api的flagsMap,错误信息列表为空,ApiError为空
return api.flagsMap, nil, nil
}
// serveRuntimeInfo 处理HTTP请求,返回运行时信息
//
// 参数:
//
// r *http.Request: HTTP请求对象
//
// 返回值:
//
// interface{}: 返回的运行时信息
// []error: 错误列表,如果没有错误则返回nil
// *ApiError: Api错误对象,如果没有错误则返回nil
func (api *BaseAPI) serveRuntimeInfo(r *http.Request) (interface{}, []error, *ApiError) {
// 调用api的runtimeInfo方法获取运行时信息
return api.runtimeInfo(), nil, nil
}
// serveBuildInfo 是 BaseAPI 结构体的方法,用于处理 HTTP 请求并返回构建信息。
//
// 参数:
//
// r *http.Request: 传入的 HTTP 请求对象。
//
// 返回值:
//
// interface{}: 返回的构建信息,类型为 BaseAPI 结构体中的 buildInfo 字段。
// []error: 错误列表,本方法直接返回 nil,表示无错误。
// *ApiError: ApiError 指针,本方法直接返回 nil,表示无 ApiError。
func (api *BaseAPI) serveBuildInfo(r *http.Request) (interface{}, []error, *ApiError) {
// 直接返回buildInfo信息,无错误,也无ApiError
return api.buildInfo, nil, nil
}
// GetRuntimeInfoFunc 返回一个返回 RuntimeInfo 类型的函数,该函数包含有关运行时信息。
//
// 参数:
//
// logger: log.Logger 类型,用于记录日志
//
// 返回值:
//
// RuntimeInfoFn 类型,一个返回 RuntimeInfo 类型的函数
func GetRuntimeInfoFunc(logger log.Logger) RuntimeInfoFn {
// 获取当前工作目录
CWD, err := os.Getwd()
if err != nil {
// 如果获取当前工作目录失败,则将CWD设置为错误信息
CWD = "<error retrieving current working directory>"
// 记录警告日志
level.Warn(logger).Log("msg", "failed to retrieve current working directory", "err", err)
}
// 记录程序启动时间
birth := time.Now()
// 返回获取运行时信息的函数
return func() RuntimeInfo {
return RuntimeInfo{
// 程序启动时间
StartTime: birth,
// 当前工作目录
CWD: CWD,
// 当前 Goroutine 数量
GoroutineCount: runtime.NumGoroutine(),
// GOMAXPROCS 的值
GOMAXPROCS: runtime.GOMAXPROCS(0),
// GOGC 的值
GOGC: os.Getenv("GOGC"),
// GODEBUG 的值
GODEBUG: os.Getenv("GODEBUG"),
}
}
}
// InstrFunc 是一个函数类型,它接收一个字符串和一个 ApiFunc 作为参数,并返回一个 http.HandlerFunc。
type InstrFunc func(name string, f ApiFunc) http.HandlerFunc
// GetInstr returns a http HandlerFunc with the instrumentation middleware.
func GetInstr(
tracer opentracing.Tracer, // OpenTracing的Tracer对象
logger log.Logger, // 日志记录器
ins extpromhttp.InstrumentationMiddleware, // Prometheus的InstrumentationMiddleware
logMiddleware *logging.HTTPServerMiddleware, // 日志中间件
disableCORS bool, // 是否禁用CORS
) InstrFunc {
instr := func(name string, f ApiFunc) http.HandlerFunc {
// 定义HTTP处理函数
hf := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// 如果不禁用CORS,则设置CORS响应头
if !disableCORS {
// 设置CORS响应头
SetCORS(w)
}
// 调用ApiFunc处理请求
if data, warnings, err := f(r); err != nil {
// 如果发生错误,返回错误响应
RespondError(w, err, data)
} else if data != nil {
// 如果返回数据不为空,返回正常响应
Respond(w, data, warnings)
} else {
// 如果没有返回数据,返回204 No Content状态码
w.WriteHeader(http.StatusNoContent)
}
})
// 返回带有追踪功能的HTTP中间件
return tracing.HTTPMiddleware(tracer, name, logger,
ins.NewHandler(name,
// 使用gzip压缩处理
gziphandler.GzipHandler(
// 使用RequestID中间件
middleware.RequestID(
// 使用日志中间件处理
logMiddleware.HTTPMiddleware(name, hf),
),
),
),
)
}
return instr
}
// Respond 函数处理 HTTP 响应,将给定数据编码为 JSON 并返回给客户端。
//
// 参数:
//
// w http.ResponseWriter: HTTP 响应写入器,用于发送响应数据。
// data interface{}: 要返回给客户端的数据。
// warnings []error: 警告信息列表,如果列表不为空,将设置 Cache-Control 为 no-store。
func Respond(w http.ResponseWriter, data interface{}, warnings []error) {
// 设置响应头,指定内容类型为 application/json
w.Header().Set("Content-Type", "application/json")
// 如果存在警告信息,设置缓存控制为 no-store
if len(warnings) > 0 {
w.Header().Set("Cache-Control", "no-store")
}
// 设置 HTTP 状态码为 200 OK
w.WriteHeader(http.StatusOK)
// 初始化响应结构体
resp := &response{
Status: StatusSuccess,
Data: data,
}
// 遍历警告信息,将其添加到响应结构体的警告列表中
for _, warn := range warnings {
resp.Warnings = append(resp.Warnings, warn.Error())
}
// 将响应结构体编码为 JSON 并写入响应体
_ = json.NewEncoder(w).Encode(resp)
}
// RespondError 函数用于处理错误响应
//
// 参数:
// - w http.ResponseWriter: HTTP 响应写入器
// - apiErr *ApiError: 封装了错误信息的结构体指针
// - data interface{}: 其他需要返回的数据
func RespondError(w http.ResponseWriter, apiErr *ApiError, data interface{}) {
// 设置响应头的内容类型为 JSON
w.Header().Set("Content-Type", "application/json")
// 设置响应头禁止缓存
w.Header().Set("Cache-Control", "no-store")
var code int
switch apiErr.Typ {
case ErrorBadData:
// 数据错误,返回400 Bad Request
code = http.StatusBadRequest
case ErrorExec:
// 执行错误,返回422 Unprocessable Entity
code = 422
case ErrorCanceled, ErrorTimeout:
// 请求被取消或超时,返回503 Service Unavailable
code = http.StatusServiceUnavailable
case ErrorInternal:
// 内部错误,返回500 Internal Server Error
code = http.StatusInternalServerError
default:
// 默认情况,返回500 Internal Server Error
code = http.StatusInternalServerError
}
// 设置响应状态码
w.WriteHeader(code)
// 使用 JSON 编码将响应数据写入响应体
_ = json.NewEncoder(w).Encode(&response{
// 状态码
Status: StatusError,
// 错误类型
ErrorType: apiErr.Typ,
// 错误信息
Error: apiErr.Err.Error(),
// 其他数据
Data: data,
})
}

浙公网安备 33010602011771号