Thanos源码专题【左扬精讲】——Thanos Query_frontend 组件(release-0.26)源码阅读和分析(详解 cmd/query_frontend.go )
Thanos Query_frontend 组件(release-0.26)源码阅读和分析(详解 cmd/query_frontend.go )
https://github.com/thanos-io/thanos/blob/v0.26.0/cmd/thanos/query_frontend.go
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 | // Copyright (c) The Thanos Authors. // Licensed under the Apache License 2.0. package main import ( "net/http" "time" "github.com/NYTimes/gziphandler" cortexfrontend "github.com/cortexproject/cortex/pkg/frontend" "github.com/cortexproject/cortex/pkg/frontend/transport" "github.com/cortexproject/cortex/pkg/querier/queryrange" cortexvalidation "github.com/cortexproject/cortex/pkg/util/validation" "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/weaveworks/common/user" "gopkg.in/yaml.v2" extflag "github.com/efficientgo/tools/extkingpin" "github.com/thanos-io/thanos/pkg/api" "github.com/thanos-io/thanos/pkg/component" "github.com/thanos-io/thanos/pkg/exthttp" "github.com/thanos-io/thanos/pkg/extkingpin" "github.com/thanos-io/thanos/pkg/extprom" extpromhttp "github.com/thanos-io/thanos/pkg/extprom/http" "github.com/thanos-io/thanos/pkg/logging" "github.com/thanos-io/thanos/pkg/prober" "github.com/thanos-io/thanos/pkg/queryfrontend" httpserver "github.com/thanos-io/thanos/pkg/server/http" "github.com/thanos-io/thanos/pkg/server/http/middleware" "github.com/thanos-io/thanos/pkg/tracing" ) type queryFrontendConfig struct { http httpConfig // HTTP 服务配置 webDisableCORS bool // 是否禁用CORS queryfrontend.Config // 查询前端配置 orgIdHeaders []string // 组织ID头部 } // registerQueryFrontend 函数用于在 extkingpin 应用中注册查询前端组件的相关配置和命令。 // // 参数: // app: extkingpin.App 类型,表示要注册命令的应用实例。 func registerQueryFrontend(app *extkingpin.App) { // 定义组件名称 comp := component.QueryFrontend // 添加命令,用于启动查询前端服务。 cmd := app.Command(comp.String(), "Query frontend command implements a service deployed in front of queriers to improve query parallelization and caching." ) // 定义配置结构体 cfg := &queryFrontendConfig{ Config: queryfrontend.Config{ // 最大请求体大小为10 MiB // Max body size is 10 MiB. CortexHandlerConfig: &transport.HandlerConfig{ MaxBodySize: 10 * 1024 * 1024, }, // 查询范围配置 QueryRangeConfig: queryfrontend.QueryRangeConfig{ Limits: &cortexvalidation.Limits{}, }, // 查询配置 LabelsConfig: queryfrontend.LabelsConfig{ Limits: &cortexvalidation.Limits{}, }, }, } // 注册HTTP相关标志 cfg.http.registerFlag(cmd) // --web.disable-cors,无论是否禁用CORS,默认都是允许的。 cmd.Flag( "web.disable-cors" , "Whether to disable CORS headers to be set by Thanos. By default Thanos sets CORS headers to be allowed by all." ). Default( "false" ).BoolVar(&cfg.webDisableCORS) // Query range tripperware flags. // --query-range.align-range-with-step, 默认情况下,会将传入的查询范围与其步长对齐以更好地缓存。注意:Grafana仪表板默认会这样做。 cmd.Flag( "query-range.align-range-with-step" , "Mutate incoming queries to align their start and end with their step for better cache-ability. Note: Grafana dashboards do that by default." ). Default( "true" ).BoolVar(&cfg.QueryRangeConfig.AlignRangeWithStep) // --query-range.request-downsampled,默认情况下,查询范围请求将请求原始数据,而不是从缓存中获取。如果请求为空或未完成,则将请求下采样数据。 cmd.Flag( "query-range.request-downsampled" , "Make additional query for downsampled data in case of empty or incomplete response to range request." ). Default( "true" ).BoolVar(&cfg.QueryRangeConfig.RequestDownsampled) // --query-range.split-interval,默认情况下,会将查询范围请求拆分为24小时的间隔并在并行中执行。注意:Grafana仪表板默认会这样做。 cmd.Flag( "query-range.split-interval" , "Split query range requests by an interval and execute in parallel, it should be greater than 0 when query-range.response-cache-config is configured." ). Default( "24h" ).DurationVar(&cfg.QueryRangeConfig.SplitQueriesByInterval) // --query-range.max-retries,默认情况下,查询范围请求将重试3次。注意:Grafana仪表板默认会这样做。 cmd.Flag( "query-range.max-retries-per-request" , "Maximum number of retries for a single query range request; beyond this, the downstream error is returned." ). Default( "5" ).IntVar(&cfg.QueryRangeConfig.MaxRetries) // --query-range.max-query-length,默认情况下,查询范围请求的最大时间范围是1天。注册查询范围请求最大时间范围标志 cmd.Flag( "query-range.max-query-length" , "Limit the query time range (end - start time) in the query-frontend, 0 disables it." ). Default( "0" ).DurationVar((*time.Duration)(&cfg.QueryRangeConfig.Limits.MaxQueryLength)) // --query-range.max-query-parallelism, 默认情况下,查询范围请求将并行执行14个。注册查询范围请求并行执行标志 cmd.Flag( "query-range.max-query-parallelism" , "Maximum number of query range requests will be scheduled in parallel by the Frontend." ). Default( "14" ).IntVar(&cfg.QueryRangeConfig.Limits.MaxQueryParallelism) // --query-range.response-cache-max-freshness, 默认情况下,查询范围请求将重试3次。注意:Grafana仪表板默认会这样做。 cmd.Flag( "query-range.response-cache-max-freshness" , "Most recent allowed cacheable result for query range requests, to prevent caching very recent results that might still be in flux." ). Default( "1m" ).DurationVar((*time.Duration)(&cfg.QueryRangeConfig.Limits.MaxCacheFreshness)) // --query-range.partial-response: 设置查询范围请求的默认部分响应策略。 // 如果未在请求中指定 partial_response 参数,则启用此策略。 // 使用 --no-query-range.partial-response 可禁用该策略。 cmd.Flag( "query-range.partial-response" , "Enable partial response for query range requests if no partial_response param is specified. Use --no-query-range.partial-response to disable." ). Default( "true" ).BoolVar(&cfg.QueryRangeConfig.PartialResponseStrategy) // --query-range.response-cache-config, 注册查询范围请求响应缓存配置标志 cfg.QueryRangeConfig.CachePathOrContent = *extflag.RegisterPathOrContent(cmd, "query-range.response-cache-config" , "YAML file that contains response cache configuration." , extflag.WithEnvSubstitution()) // Labels tripperware flags. // --labels.split-interval,注册标签请求的拆分间隔标志,该标志用于将标签请求按间隔拆分并并行执行。 cmd.Flag( "labels.split-interval" , "Split labels requests by an interval and execute in parallel, it should be greater than 0 when labels.response-cache-config is configured." ). Default( "24h" ).DurationVar(&cfg.LabelsConfig.SplitQueriesByInterval) // --labels.max-retries-per-request, 注册标签请求的最大重试次数标志,默认情况下,标签请求将重试5次。 cmd.Flag( "labels.max-retries-per-request" , "Maximum number of retries for a single label/series API request; beyond this, the downstream error is returned." ). Default( "5" ).IntVar(&cfg.LabelsConfig.MaxRetries) // --labels.max-query-parallelism,注册标签请求最大并行数标志,默认情况下,标签请求将并行执行14个。 cmd.Flag( "labels.max-query-parallelism" , "Maximum number of labels requests will be scheduled in parallel by the Frontend." ). Default( "14" ).IntVar(&cfg.LabelsConfig.Limits.MaxQueryParallelism) // --labels.response-cache-max-freshness,注册标签请求的响应缓存最大新鲜度标志,该标志用于防止缓存非常新鲜的结果,这些结果可能仍在变化。 cmd.Flag( "labels.response-cache-max-freshness" , "Most recent allowed cacheable result for labels requests, to prevent caching very recent results that might still be in flux." ). Default( "1m" ).DurationVar((*time.Duration)(&cfg.LabelsConfig.Limits.MaxCacheFreshness)) // --labels.partial-response, 注册标签请求的局部响应标志,默认情况下,标签请求将返回部分响应。使用 --no-labels.partial-response 可禁用该策略。 cmd.Flag( "labels.partial-response" , "Enable partial response for labels requests if no partial_response param is specified. --no-labels.partial-response for disabling." ). Default( "true" ).BoolVar(&cfg.LabelsConfig.PartialResponseStrategy) // --labels.default-time-range,注册标签请求的默认时间范围标志,该标志用于设置默认的标签请求时间范围。 cmd.Flag( "labels.default-time-range" , "The default metadata time range duration for retrieving labels through Labels and Series API when the range parameters are not specified." ). Default( "24h" ).DurationVar(&cfg.DefaultTimeRange) // --labels.response-cache-config, 注册标签请求的响应缓存配置标志,该标志用于设置标签请求的响应缓存配置。 cfg.LabelsConfig.CachePathOrContent = *extflag.RegisterPathOrContent(cmd, "labels.response-cache-config" , "YAML file that contains response cache configuration." , extflag.WithEnvSubstitution()) // --cache-compression-type,注册缓存压缩类型标志,该标志用于设置在结果缓存中使用的压缩算法。支持的值包括 "snappy" 和 ""(禁用压缩)。 cmd.Flag( "cache-compression-type" , "Use compression in results cache. Supported values are: 'snappy' and '' (disable compression)." ). Default( "" ).StringVar(&cfg.CacheCompression) // --query-frontend.downstream-url,注册查询前端的下游URL标志,该标志用于设置查询前端的下游URL。 cmd.Flag( "query-frontend.downstream-url" , "URL of downstream Prometheus Query compatible API." ). Default( "http://localhost:9090" ).StringVar(&cfg.DownstreamURL) // --query-frontend.downstream-tripper-config,注册查询前端的下游传输器配置标志,该标志用于设置查询前端的下游传输器配置。YAML文件包含传输器配置。如果下游URL是localhost或127.0.0.1,则强烈建议使用此标志。 cfg.DownstreamTripperConfig.CachePathOrContent = *extflag.RegisterPathOrContent(cmd, "query-frontend.downstream-tripper-config" , "YAML file that contains downstream tripper configuration. If your downstream URL is localhost or 127.0.0.1 then it is highly recommended to increase max_idle_conns_per_host to at least 100." , extflag.WithEnvSubstitution()) // --query-frontend.compress-responses, 注册压缩HTTP响应标志 cmd.Flag( "query-frontend.compress-responses" , "Compress HTTP responses." ). Default( "false" ).BoolVar(&cfg.CompressResponses) // --query-frontend.log-queries-longer-than, 日志查询持续时间标志,该标志用于设置日志查询持续时间。设置为0将禁用此功能。设置为小于0的值将在所有查询上启用。 cmd.Flag( "query-frontend.log-queries-longer-than" , "Log queries that are slower than the specified duration. " + "Set to 0 to disable. Set to < 0 to enable on all queries." ).Default( "0" ).DurationVar(&cfg.CortexHandlerConfig.LogQueriesLongerThan) // --query-frontend.org-id-header, 注册组织ID头标志,该标志用于设置查询前端将转发到下游查询器的HTTP头的列表。默认情况下为空。 cmd.Flag( "query-frontend.org-id-header" , "Request header names used to identify the source of slow queries (repeated flag). " + "The values of the header will be added to the org id field in the slow query log. " + "If multiple headers match the request, the first matching arg specified will take precedence. " + "If no headers match 'anonymous' will be used." ).PlaceHolder( "<http-header-name>" ).StringsVar(&cfg.orgIdHeaders) // --query-frontend.forward-headers, 注册转发头标志,该标志用于设置查询前端将转发到下游查询器的HTTP头列表。默认情况下为空。 cmd.Flag( "query-frontend.forward-header" , "List of headers forwarded by the query-frontend to downstream queriers, default is empty" ).PlaceHolder( "<http-header-name>" ).StringsVar(&cfg.ForwardHeaders) // --log.request.decision, 注册请求日志记录决策标志,该标志用于设置查询前端的请求日志记录策略。默认情况下为空。 支持的值为:"LogFinishCall"。 支持的值为:"NoLogCall"、"LogFinishCall"和"LogStartAndFinishCall"。 默认情况下为空。 "NoLogCall": 禁用请求日志记录。"LogFinishCall": 日志请求的完成调用。"LogStartAndFinishCall": 日志请求的开始和结束调用。 cmd.Flag( "log.request.decision" , "Deprecation Warning - This flag would be soon deprecated, and replaced with `request.logging-config`. Request Logging for logging the start and end of requests. By default this flag is disabled. LogFinishCall : Logs the finish call of the requests. LogStartAndFinishCall : Logs the start and finish call of the requests. NoLogCall : Disable request logging." ).Default( "" ).EnumVar(&cfg.RequestLoggingDecision, "NoLogCall" , "LogFinishCall" , "LogStartAndFinishCall" , "" ) // 注册请求日志记录配置 reqLogConfig := extkingpin.RegisterRequestLoggingFlags(cmd) // 设置命令执行逻辑 cmd.Setup( func (g *run.Group, logger log.Logger, reg *prometheus.Registry, tracer opentracing.Tracer, _ <- chan struct {}, _ bool) error { // 解析请求日志记录配置 httpLogOpts, err := logging.ParseHTTPOptions(cfg.RequestLoggingDecision, reqLogConfig) if err != nil { return errors.Wrap(err, "error while parsing config for request logging" ) } // 运行查询前端 return runQueryFrontend(g, logger, reg, tracer, httpLogOpts, cfg, comp) }) } // 定义一个函数parseTransportConfiguration,它接受一个字节切片downstreamTripperConfContentYaml作为输入,并返回一个指向http.Transport的指针和一个error对象。这个函数的作用是解析传输配置。如果downstreamTripperConfContentYaml为空,则直接返回一个默认配置的http.Transport对象。否则,它会尝试将YAML格式的内容解析到tripperConfig结构体中,并使用这个配置创建一个http.Transport对象。如果解析失败,它会返回一个错误。 // parseTransportConfiguration 解析YAML格式的下游传输配置,并返回一个配置好的 http.Transport 对象。 // // 参数: // // downstreamTripperConfContentYaml: YAML格式的下游传输配置内容 // // 返回值: // // *http.Transport: 配置好的 http.Transport 对象 // error: 如果解析过程中出现错误,则返回错误信息 func parseTransportConfiguration(downstreamTripperConfContentYaml []byte) (*http.Transport, error) { // 创建一个新的http.Transport实例,这里假设exthttp.NewTransport()是一个封装或扩展了标准http.NewTransport()的函数,可能添加了一些额外的配置或功能。这个新创建的实例被赋值给downstreamTripper变量。 downstreamTripper := exthttp.NewTransport() // 检查输入的YAML配置内容是否非空。如果为空,则不应用任何配置,直接返回默认配置的http.Transport实例。 if len(downstreamTripperConfContentYaml) > 0 { // 创建一个queryfrontend.DownstreamTripperConfig类型的实例,这个类型是一个结构体,预期包含了一些用于配置http.Transport的字段。这个实例被赋值给tripperConfig变量。 tripperConfig := &queryfrontend.DownstreamTripperConfig{} // 使用yaml.UnmarshalStrict函数将YAML格式的配置内容解析到tripperConfig结构体中。如果解析过程中发生错误,则返回一个错误。 if err := yaml.UnmarshalStrict(downstreamTripperConfContentYaml, tripperConfig); err != nil { // 如果解析YAML文件时出错,则使用errors.Wrap函数包装错误,并返回nil和错误信息。 return nil, errors.Wrap(err, "parsing downstream tripper config YAML file" ) } // 根据tripperConfig中的配置设置downstreamTripper的各项参数 if tripperConfig.IdleConnTimeout > 0 { // 设置空闲连接超时时间 downstreamTripper.IdleConnTimeout = time.Duration(tripperConfig.IdleConnTimeout) } if tripperConfig.ResponseHeaderTimeout > 0 { // 设置响应头超时时间 downstreamTripper.ResponseHeaderTimeout = time.Duration(tripperConfig.ResponseHeaderTimeout) } if tripperConfig.TLSHandshakeTimeout > 0 { // 设置TLS握手超时时间 downstreamTripper.TLSHandshakeTimeout = time.Duration(tripperConfig.TLSHandshakeTimeout) } if tripperConfig.ExpectContinueTimeout > 0 { // 设置期望继续超时时间 downstreamTripper.ExpectContinueTimeout = time.Duration(tripperConfig.ExpectContinueTimeout) } if tripperConfig.MaxIdleConns != nil { // 设置最大空闲连接数 downstreamTripper.MaxIdleConns = *tripperConfig.MaxIdleConns } if tripperConfig.MaxIdleConnsPerHost != nil { // 设置每主机最大空闲连接数 downstreamTripper.MaxIdleConnsPerHost = *tripperConfig.MaxIdleConnsPerHost } if tripperConfig.MaxConnsPerHost != nil { // 设置每主机最大连接数 downstreamTripper.MaxConnsPerHost = *tripperConfig.MaxConnsPerHost } } // 返回配置好的downstreamTripper对象 return downstreamTripper, nil } // runQueryFrontend 函数用于启动查询前端服务 func runQueryFrontend( g *run.Group, // 运行组,用于管理服务的启动和停止 logger log.Logger, // 日志记录器,用于记录日志信息 reg *prometheus.Registry, // Prometheus注册表,用于注册和收集指标数据 tracer opentracing.Tracer, // 链路追踪器,用于追踪请求的执行过程 httpLogOpts []logging.Option, // HTTP日志选项,用于配置HTTP请求的日志记录行为 cfg *queryFrontendConfig, // 查询前端配置,包含各种服务运行所需的参数和选项 comp component.Component, // 组件,用于管理服务的启动和停止 ) error { // 获取查询范围缓存配置内容 queryRangeCacheConfContentYaml, err := cfg.QueryRangeConfig.CachePathOrContent.Content() if err != nil { return err // 如果配置内容不为空,则初始化查询范围缓存配置 } if len(queryRangeCacheConfContentYaml) > 0 { // 初始化查询范围缓存配置 cacheConfig, err := queryfrontend.NewCacheConfig(logger, queryRangeCacheConfContentYaml) if err != nil { return errors.Wrap(err, "initializing the query range cache config" ) } // 设置查询范围缓存配置, cfg.QueryRangeConfig.ResultsCacheConfig 是一个指向 queryrange.ResultsCacheConfig 的指针,它包含了压缩和缓存配置信息。这里将查询范围缓存的压缩选项设置为 cfg.CacheCompression,并将缓存配置设置为 cacheConfig。 cfg.QueryRangeConfig.ResultsCacheConfig = &queryrange.ResultsCacheConfig{ Compression: cfg.CacheCompression, CacheConfig: *cacheConfig, } } // 获取标签缓存配置内容 labelsCacheConfContentYaml, err := cfg.LabelsConfig.CachePathOrContent.Content() if err != nil { return err } if len(labelsCacheConfContentYaml) > 0 { // 初始化标签缓存配置 cacheConfig, err := queryfrontend.NewCacheConfig(logger, labelsCacheConfContentYaml) if err != nil { return errors.Wrap(err, "initializing the labels cache config" ) } // 设置标签缓存配置, cfg.LabelsConfig 是一个指向 queryfrontend.LabelsConfig 的指针,它包含了标签缓存的配置信息。这里将查询范围缓存的压缩选项设置为 cfg.CacheCompression,并将缓存配置设置为 cacheConfig。 cfg.LabelsConfig.ResultsCacheConfig = &queryrange.ResultsCacheConfig{ Compression: cfg.CacheCompression, CacheConfig: *cacheConfig, } } // 验证配置 if err := cfg.Validate(); err != nil { return errors.Wrap(err, "error validating the config" ) } // 初始化tripperware, tripperware 是一个用于处理 HTTP 请求的中间件,它可以将请求传递给下游的 HTTP 服务。这里使用 queryfrontend.NewTripperware 函数初始化 tripperware,传入配置、注册表和日志记录器。这里将 cfg.Config 作为配置参数,reg 和 logger 分别作为注册表和日志记录器的参数。如果初始化失败,则返回错误信息。 tripperWare, err := queryfrontend.NewTripperware(cfg.Config, reg, logger) if err != nil { return errors.Wrap(err, "setup tripperwares" ) } // 获取下游传输配置内容, 获取下游传输配置内容,并将其解析为传输配置。如果解析失败,则返回错误信息。 downstreamTripperConfContentYaml, err := cfg.DownstreamTripperConfig.CachePathOrContent.Content() if err != nil { return err } // 解析下游传输配置, 使用 parseTransportConfiguration 函数将下游传输配置内容解析为 http.Transport 对象。如果解析失败,则返回错误信息。如果下游传输配置内容为空,则直接使用默认的 http.Transport 对象。 downstreamTripper, err := parseTransportConfiguration(downstreamTripperConfContentYaml) if err != nil { return err } // 创建下游往返器 roundTripper, err := cortexfrontend.NewDownstreamRoundTripper(cfg.DownstreamURL, downstreamTripper) if err != nil { return errors.Wrap(err, "setup downstream roundtripper" ) } // 将下游往返器包装到查询前端Tripperware中 roundTripper = tripperWare(roundTripper) // 创建查询前端传输 handler := transport.NewHandler(*cfg.CortexHandlerConfig, roundTripper, logger, nil) if cfg.CompressResponses { handler = gziphandler.GzipHandler(handler) } // 创建HTTP探针 httpProbe := prober.NewHTTP() statusProber := prober.Combine( httpProbe, prober.NewInstrumentation(comp, logger, extprom.WrapRegistererWithPrefix( "thanos_" , reg)), ) // 配置HTTP调用的请求日志记录 logMiddleware := logging.NewHTTPServerMiddleware(logger, httpLogOpts...) ins := extpromhttp.NewInstrumentationMiddleware(reg, nil) // 启动HTTP服务器以收集指标 { srv := httpserver.New(logger, reg, comp, httpProbe, httpserver.WithListen(cfg.http.bindAddress), httpserver.WithGracePeriod(time.Duration(cfg.http.gracePeriod)), httpserver.WithTLSConfig(cfg.http.tlsConfig), ) // 配置HTTP处理函数 instr := func (f http.HandlerFunc) http.HandlerFunc { hf := http.HandlerFunc( func (w http.ResponseWriter, r *http.Request) { orgId := extractOrgId(cfg, r) name := "query-frontend" if !cfg.webDisableCORS { api.SetCORS(w) } tracing.HTTPMiddleware( tracer, name, logger, ins.NewHandler( name, gziphandler.GzipHandler( middleware.RequestID( logMiddleware.HTTPMiddleware(name, f), ), ), ), // Cortex前端中间件需要orgID ).ServeHTTP(w, r.WithContext(user.InjectOrgID(r.Context(), orgId))) }) return hf } srv.Handle( "/" , instr(handler.ServeHTTP)) // 添加服务器启动和关闭逻辑到组中 g.Add( func () error { statusProber.Healthy() return srv.ListenAndServe() }, func (err error) { statusProber.NotReady(err) defer statusProber.NotHealthy(err) srv.Shutdown(err) }) } level.Info(logger).Log( "msg" , "starting query frontend" ) statusProber.Ready() return nil } // extractOrgId 从HTTP请求中提取组织ID // // 参数: // // conf *queryFrontendConfig: 配置结构体指针,包含组织ID头部列表 // r *http.Request: HTTP请求结构体指针 // // 返回值: // // string: 提取的组织ID字符串,如果未找到则返回"anonymous" func extractOrgId(conf *queryFrontendConfig, r *http.Request) string { // 遍历conf.orgIdHeaders切片中的每个元素。每个元素(这里命名为header)都是一个字符串,代表可能包含组织ID的HTTP请求头名称。 for _, header := range conf.orgIdHeaders { // 通过r.Header.Get(header)方法从HTTP请求r的头部中获取名为header的值,并将这个值存储在变量headerVal中。r.Header是一个http.Header类型的映射,它允许通过键(这里是HTTP请求头的名称)来获取对应的值(这里是HTTP请求头的值)。 headerVal := r.Header.Get(header) // 检查变量headerVal是否不为空字符串。如果不为空,意味着在当前的请求头中找到了一个有效的组织ID值。在这种情况下,直接返回这个值作为组织ID。 if headerVal != "" { return headerVal } } // 如果遍历完conf.orgIdHeaders中列出的所有请求头后,没有找到任何有效的组织ID值,函数返回字符串"anonymous"。这表示请求没有明确指定组织ID,因此默认将其视为匿名请求。 return "anonymous" } |
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 在鹅厂做java开发是什么体验
· 百万级群聊的设计实践
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
· 永远不要相信用户的输入:从 SQL 注入攻防看输入验证的重要性
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
2022-02-12 Go从入门到精通——数组(固定大小的连续空间)