Thanos源码专题【左扬精讲】——Thanos API 组件(release-0.26)源码阅读和分析(详解 pkg\api\query\v1.go)

Thanos API 组件(release-0.26)源码阅读和分析(详解 pkg\api\query\v1.go)

https://github.com/thanos-io/thanos/blob/v0.26.0/pkg/api/query/v1.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
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
// 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 v1
 
import (
    "context"  // context 用于传递上下文信息,比如取消信号、截止时间等。
    "math"     // math 包提供了基本的数学运算函数,比如加、减、乘、除等。
    "net/http" // net/http 包提供了 HTTP 客户端和服务器的实现。
    "sort"     // sort 包提供了对切片进行排序的函数。
    "strconv"  // strconv 包提供了字符串和基本数据类型之间的转换函数。
    "strings"  // strings 包提供了许多实用的字符串处理函数,比如查找、替换等。
    "time"     // time 包提供了时间的表示、计算和格式化功能。
 
    "github.com/go-kit/log"                                   // log 包提供了日志记录的功能。
    "github.com/opentracing/opentracing-go"                   // opentracing-go 包提供了分布式追踪的功能。
    "github.com/pkg/errors"                                   // errors 包提供了错误处理的功能。
    "github.com/prometheus/client_golang/prometheus"          // prometheus 包提供了 Prometheus 监控指标的收集和暴露功能。
    "github.com/prometheus/client_golang/prometheus/promauto" // promauto 包提供了 Prometheus 监控指标的自动注册功能。
    "github.com/prometheus/common/model"                      // model 包提供了 Prometheus 数据模型的定义和操作功能。
    "github.com/prometheus/common/route"                      // route 包提供了 HTTP 路由的功能。
    "github.com/prometheus/prometheus/model/labels"           // labels 包提供了 Prometheus 标签的定义和操作功能。
    "github.com/prometheus/prometheus/model/timestamp"        // timestamp 包提供了 Prometheus 时间戳的定义和操作功能。
    "github.com/prometheus/prometheus/promql"                 // promql 包提供了 Prometheus 查询语言的解析和执行功能。
    "github.com/prometheus/prometheus/promql/parser"          // parser 包提供了 Prometheus 查询语言的解析功能。
    "github.com/prometheus/prometheus/storage"                // storage 包提供了 Prometheus 数据存储的功能。
 
    "github.com/prometheus/prometheus/util/stats" // stats 包提供了 Prometheus 数据统计的功能。
 
    "github.com/thanos-io/thanos/pkg/api"                      // api 包提供了 Thanos API 的定义和实现功能。
    "github.com/thanos-io/thanos/pkg/exemplars"                // exemplars 包提供了 Thanos 示例数据的功能。
    "github.com/thanos-io/thanos/pkg/exemplars/exemplarspb"    // exemplarspb 包提供了 Thanos 示例数据的序列化功能。
    extpromhttp "github.com/thanos-io/thanos/pkg/extprom/http" // extpromhttp 包提供了 Thanos 扩展 Prometheus 监控指标的功能。
    "github.com/thanos-io/thanos/pkg/gate"                     // gate 包提供了 Thanos 限流的功能。
    "github.com/thanos-io/thanos/pkg/logging"                  // logging 包提供了 Thanos 日志记录的功能。
    "github.com/thanos-io/thanos/pkg/metadata"                 // metadata 包提供了 Thanos 元数据的功能。
    "github.com/thanos-io/thanos/pkg/metadata/metadatapb"      // metadatapb 包提供了 Thanos 元数据的序列化功能。
    "github.com/thanos-io/thanos/pkg/query"                    // query 包提供了 Thanos query 的功能。
    "github.com/thanos-io/thanos/pkg/rules"                    // rules 包提供了 Thanos rules 的功能。
    "github.com/thanos-io/thanos/pkg/rules/rulespb"            // rulespb 包提供了 Thanos rules 的序列化功能。
    "github.com/thanos-io/thanos/pkg/runutil"                  // runutil 包提供了 Thanos runutil 的功能。
    "github.com/thanos-io/thanos/pkg/store/storepb"            // storepb 包提供了 Thanos store 的序列化功能。
    "github.com/thanos-io/thanos/pkg/targets"                  // targets 包提供了 Thanos target 的功能。
    "github.com/thanos-io/thanos/pkg/targets/targetspb"        // targetspb 包提供了 Thanos target 的序列化功能。
    "github.com/thanos-io/thanos/pkg/tracing"                  // tracing 包提供了 Thanos tracing 的功能。
)
 
const (
    DedupParam               = "dedup"                 // DedupParam 是用于去重的参数。
    PartialResponseParam     = "partial_response"      // PartialResponseParam 是用于部分响应的参数。
    MaxSourceResolutionParam = "max_source_resolution" // MaxSourceResolutionParam 是用于最大源分辨率的参数。
    ReplicaLabelsParam       = "replicaLabels[]"       // ReplicaLabelsParam 是用于副本标签的参数。
    MatcherParam             = "match[]"               // MatcherParam 是用于匹配的参数。
    StoreMatcherParam        = "storeMatch[]"          // StoreMatcherParam 是用于存储匹配的参数。
    Step                     = "step"                  // Step 是用于步长的参数。
    Stats                    = "stats"                 // Stats 是用于统计的参数。
)
 
// QueryAPI is an API used by Thanos Querier.
// QueryAPI 类型是用于 Thanos Querier 的 API。
type QueryAPI struct {
    baseAPI         *api.BaseAPI           //   baseAPI 是 QueryAPI 的基础 API。
    logger          log.Logger             // logger 是用于记录日志的对象。
    gate            gate.Gate              // gate 是用于控制访问的对象。
    queryableCreate query.QueryableCreator // queryableCreate 是用于创建查询对象的函数。
    // queryEngine returns appropriate promql.Engine for a query with a given step.
    // queryEngin 返回一个适用于给定步长的 promql.Engine。
    queryEngine func(int64) *promql.Engine // queryEngine 是一个函数,用于根据给定的步长返回一个 promql.Engine。
    ruleGroups  rules.UnaryClient          // ruleGroups 是用于规则组的对象。
    targets     targets.UnaryClient        // targets 是用于目标的对象。
    metadatas   metadata.UnaryClient       // metadatas 是用于元数据的对象。
    exemplars   exemplars.UnaryClient      // exemplars 是用于示例的对象。
 
    enableAutodownsampling              bool // enableAutodownsampling 是用于启用自动降采样的参数。
    enableQueryPartialResponse          bool // enableQueryPartialResponse 是用于启用查询部分响应的参数。
    enableRulePartialResponse           bool // enableRulePartialResponse 是用于启用规则部分响应的参数。
    enableTargetPartialResponse         bool // enableTargetPartialResponse 是用于启用目标部分响应的参数。
    enableMetricMetadataPartialResponse bool // enableMetricMetadataPartialResponse 是用于启用指标元数据部分响应的参数。
    enableExemplarPartialResponse       bool // enableExemplarPartialResponse 是用于启用示例部分响应的参数。
    enableQueryPushdown                 bool // enableQueryPushdown 是用于启用查询下推的参数。
    disableCORS                         bool // disableCORS 是用于禁用 CORS 的参数。
 
    replicaLabels  []string                      // replicaLabels 是用于副本标签的参数。
    endpointStatus func() []query.EndpointStatus // endpointStatus 是用于获取端点状态的函数。
 
    defaultRangeQueryStep                  time.Duration        // defaultRangeQueryStep 是用于默认范围查询步长的参数。
    defaultInstantQueryMaxSourceResolution time.Duration        // defaultInstantQueryMaxSourceResolution 是用于默认即时查询最大源分辨率的参数。
    defaultMetadataTimeRange               time.Duration        // defaultMetadataTimeRange 是用于默认元数据时间范围的参数。
    queryRangeHist                         prometheus.Histogram // queryRangeHist 是用于查询范围直方图的参数。
}
 
// NewQueryAPI returns an initialized QueryAPI type.
// NewQueryAPI 创建并返回一个 QueryAPI 实例。
//
// 参数:
// - logger: 日志记录器
// - endpointStatus: 获取端点状态的函数
// - qe: 创建 PromQL 查询引擎的函数
// - c: 创建可查询实例的函数
// - ruleGroups: 规则组客户端
// - targets: 目标客户端
// - metadatas: 元数据客户端
// - exemplars: 示例客户端
// - enableAutodownsampling: 是否启用自动降采样
// - enableQueryPartialResponse: 是否启用查询部分响应
// - enableRulePartialResponse: 是否启用规则部分响应
// - enableTargetPartialResponse: 是否启用目标部分响应
// - enableMetricMetadataPartialResponse: 是否启用元数据部分响应
// - enableExemplarPartialResponse: 是否启用示例部分响应
// - enableQueryPushdown: 是否启用查询下推
// - replicaLabels: 副本标签列表
// - flagsMap: 标志映射
// - defaultRangeQueryStep: 默认范围查询步长
// - defaultInstantQueryMaxSourceResolution: 默认即时查询最大源分辨率
// - defaultMetadataTimeRange: 默认元数据时间范围
// - disableCORS: 是否禁用 CORS
// - gate: 限流
// - reg: Prometheus 注册中心
//
// 返回值:
// - 返回一个 QueryAPI 实例
func NewQueryAPI(
    logger log.Logger,
    endpointStatus func() []query.EndpointStatus,
    qe func(int64) *promql.Engine,
    c query.QueryableCreator,
    ruleGroups rules.UnaryClient,
    targets targets.UnaryClient,
    metadatas metadata.UnaryClient,
    exemplars exemplars.UnaryClient,
    enableAutodownsampling bool,
    enableQueryPartialResponse bool,
    enableRulePartialResponse bool,
    enableTargetPartialResponse bool,
    enableMetricMetadataPartialResponse bool,
    enableExemplarPartialResponse bool,
    enableQueryPushdown bool,
    replicaLabels []string,
    flagsMap map[string]string,
    defaultRangeQueryStep time.Duration,
    defaultInstantQueryMaxSourceResolution time.Duration,
    defaultMetadataTimeRange time.Duration,
    disableCORS bool,
    gate gate.Gate,
    reg *prometheus.Registry,
) *QueryAPI {
    // 初始化 QueryAPI 结构体并返回
    return &QueryAPI{
        // 创建基础 API
        baseAPI: api.NewBaseAPI(logger, disableCORS, flagsMap),
        // 记录器
        logger: logger,
        // 查询引擎
        queryEngine: qe,
        // 创建可查询实例的函数
        queryableCreate: c,
        // 限流门
        gate: gate,
        // 规则组客户端
        ruleGroups: ruleGroups,
        // 目标客户端
        targets: targets,
        // 元数据客户端
        metadatas: metadatas,
        // 示例客户端
        exemplars: exemplars,
 
        // 自动降采样开关
        enableAutodownsampling: enableAutodownsampling,
        // 查询部分响应开关
        enableQueryPartialResponse: enableQueryPartialResponse,
        // 规则部分响应开关
        enableRulePartialResponse: enableRulePartialResponse,
        // 目标部分响应开关
        enableTargetPartialResponse: enableTargetPartialResponse,
        // 元数据部分响应开关
        enableMetricMetadataPartialResponse: enableMetricMetadataPartialResponse,
        // 示例部分响应开关
        enableExemplarPartialResponse: enableExemplarPartialResponse,
        // 查询下推开关
        enableQueryPushdown: enableQueryPushdown,
        // 副本标签列表
        replicaLabels: replicaLabels,
        // 端点状态获取函数
        endpointStatus: endpointStatus,
        // 默认范围查询步长
        defaultRangeQueryStep: defaultRangeQueryStep,
        // 默认即时查询最大源分辨率
        defaultInstantQueryMaxSourceResolution: defaultInstantQueryMaxSourceResolution,
        // 默认元数据时间范围
        defaultMetadataTimeRange: defaultMetadataTimeRange,
        // 禁用 CORS 开关
        disableCORS: disableCORS,
 
        // 创建查询范围直方图
        queryRangeHist: promauto.With(reg).NewHistogram(prometheus.HistogramOpts{
            Name:    "thanos_query_range_requested_timespan_duration_seconds",
            Help:    "A histogram of the query range window in seconds",
            Buckets: prometheus.ExponentialBuckets(15*60, 2, 12),
        }),
    }
}
 
// Register the API's endpoints in the given router.
// Register 方法用于将 QueryAPI 的各个处理函数注册到路由中。
//
// 参数:
//
//  r *route.Router: 路由实例,用于注册处理函数。
//  tracer opentracing.Tracer: 用于追踪请求的 Tracer 实例。
//  logger log.Logger: 用于记录日志的 Logger 实例。
//  ins extpromhttp.InstrumentationMiddleware: 用于监控 HTTP 请求的中间件。
//  logMiddleware *logging.HTTPServerMiddleware: 用于记录 HTTP 请求日志的中间件。
func (qapi *QueryAPI) Register(r *route.Router, tracer opentracing.Tracer, logger log.Logger, ins extpromhttp.InstrumentationMiddleware, logMiddleware *logging.HTTPServerMiddleware) {
    // 注册基础API
    qapi.baseAPI.Register(r, tracer, logger, ins, logMiddleware)
 
    // 获取API的Instrumentation
    instr := api.GetInstr(tracer, logger, ins, logMiddleware, qapi.disableCORS)
 
    // 注册GET和POST请求处理函数到/query路由
    r.Get("/query", instr("query", qapi.query))  // GET /query
    r.Post("/query", instr("query", qapi.query)) // POST /query
 
    // 注册GET和POST请求处理函数到/query_range路由
    r.Get("/query_range", instr("query_range", qapi.queryRange))  // GET /query_range
    r.Post("/query_range", instr("query_range", qapi.queryRange)) // POST /query_range
 
    // 注册GET请求处理函数到/label/:name/values路由
    r.Get("/label/:name/values", instr("label_values", qapi.labelValues)) // GET /label/:name/values
 
    // 注册GET和POST请求处理函数到/series路由
    r.Get("/series", instr("series", qapi.series))  // GET /series
    r.Post("/series", instr("series", qapi.series)) // POST /series
 
    // 注册GET和POST请求处理函数到/labels路由
    r.Get("/labels", instr("label_names", qapi.labelNames))  // GET /labels
    r.Post("/labels", instr("label_names", qapi.labelNames)) // POST /labels
 
    // 注册GET请求处理函数到/stores路由
    r.Get("/stores", instr("stores", qapi.stores)) // GET /stores
 
    // 注册GET请求处理函数到/rules路由
    r.Get("/rules", instr("rules", NewRulesHandler(qapi.ruleGroups, qapi.enableRulePartialResponse))) // GET /rules
 
    // 注册GET请求处理函数到/targets路由
    r.Get("/targets", instr("targets", NewTargetsHandler(qapi.targets, qapi.enableTargetPartialResponse))) // GET /targets
 
    // 注册GET请求处理函数到/metadata路由
    r.Get("/metadata", instr("metadata", NewMetricMetadataHandler(qapi.metadatas, qapi.enableMetricMetadataPartialResponse))) // GET /metadata
 
    // 注册GET和POST请求处理函数到/query_exemplars路由
    r.Get("/query_exemplars", instr("exemplars", NewExemplarsHandler(qapi.exemplars, qapi.enableExemplarPartialResponse)))  // GET /query_exemplars
    r.Post("/query_exemplars", instr("exemplars", NewExemplarsHandler(qapi.exemplars, qapi.enableExemplarPartialResponse))) // POST /query_exemplars
}
 
type queryData struct {
    ResultType parser.ValueType  `json:"resultType"`      // ResultType 是查询结果的类型,例如 vector、matrix 等。
    Result     parser.Value      `json:"result"`          // Result 是查询结果的详细数据。它的类型取决于 ResultType。
    Stats      *stats.QueryStats `json:"stats,omitempty"` // Stats 是查询的统计信息,例如查询耗时、查询的标签等。
    // Additional Thanos Response field.
    Warnings []error `json:"warnings,omitempty"` // Warnings 是查询过程中可能出现的警告信息。
}
 
// parseEnableDedupParam 解析请求中的去重参数,并返回是否启用去重的布尔值。
//
// 参数:
//
//  r *http.Request: 包含请求参数的 HTTP 请求对象
//
// 返回值:
//
//  enableDeduplication bool: 是否启用去重的布尔值
//  err *api.ApiError: 如果发生错误,则返回错误信息;否则为 nil
func (qapi *QueryAPI) parseEnableDedupParam(r *http.Request) (enableDeduplication bool, _ *api.ApiError) {
    // 默认启用去重
    enableDeduplication = true
 
    // 检查请求中是否包含去重参数
    // r.FormValue 返回请求中指定参数的值,如果参数不存在则返回空字符串
    if val := r.FormValue(DedupParam); val != "" {
        // 将字符串转换为布尔值
        var err error
        // enabelDeduplication 是一个布尔值,表示是否启用去重,strconv.ParseBool 用于将字符串转换为布尔值。
        enableDeduplication, err = strconv.ParseBool(val)
        // 如果转换失败,返回错误
        if err != nil {
            // 返回错误,包括错误类型和错误信息,api.ApiError 是一个自定义的错误类型,用于返回 API 相关的错误信息。
            return false, &api.ApiError{Typ: api.ErrorBadData, Err: errors.Wrapf(err, "'%s' parameter", DedupParam)}
        }
    }
    return enableDeduplication, nil
}
 
// parseReplicaLabelsParam 解析请求表单,并返回replicaLabels参数值列表
//
// 参数:
//
//  r *http.Request: HTTP请求对象
//
// 返回值:
//
//  replicaLabels []string: replicaLabels参数值列表
//  _ *api.ApiError: 如果出现错误,则返回ApiError对象;否则返回nil
func (qapi *QueryAPI) parseReplicaLabelsParam(r *http.Request) (replicaLabels []string, _ *api.ApiError) {
    // 解析请求表单
    if err := r.ParseForm(); err != nil {
        // 解析表单出错时返回ApiError
        return nil, &api.ApiError{Typ: api.ErrorInternal, Err: errors.Wrap(err, "parse form")}
    }
 
    // 初始化replicaLabels为qapi的replicaLabels
    replicaLabels = qapi.replicaLabels
    // 当提供了查询参数时,覆盖cli标志
    // Overwrite the cli flag when provided as a query parameter.
    if len(r.Form[ReplicaLabelsParam]) > 0 {
        // 使用请求表单中的replicaLabels覆盖qapi的replicaLabels
        replicaLabels = r.Form[ReplicaLabelsParam]
    }
 
    return replicaLabels, nil
}
 
// parseStoreDebugMatchersParam 解析请求中的storeDebugMatchers参数
//
// 参数:
//
//  r *http.Request: HTTP请求对象
//
// 返回值:
//
//  [][]*labels.Matcher: 解析后的storeMatchers列表
//  *api.ApiError: 如果发生错误,则返回API错误对象,否则返回nil
//
// 说明:
//
//  该函数解析HTTP请求中的storeDebugMatchers参数,并将其转换为[][]*labels.Matcher类型的storeMatchers列表。
//  如果请求解析失败或参数解析出错,则返回相应的API错误对象。
func (qapi *QueryAPI) parseStoreDebugMatchersParam(r *http.Request) (storeMatchers [][]*labels.Matcher, _ *api.ApiError) {
    // 解析表单,r.ParseForm()会解析URL中的查询参数,并将其存储在r.Form中。
    if err := r.ParseForm(); err != nil {
        // 解析表单出错,返回内部错误。api.ApiError 是一个自定义的错误类型,用于返回 API 相关的错误信息。
        return nil, &api.ApiError{Typ: api.ErrorInternal, Err: errors.Wrap(err, "parse form")}
    }
 
    // 遍历表单中的参数, r.Form[StoreMatcherParam] 获取所有名为 StoreMatcherParam 的参数值列表。
    for _, s := range r.Form[StoreMatcherParam] {
        // 解析指标选择器。parser.ParseMetricSelector 用于解析指标选择器字符串,返回一个匹配器的切片。
        matchers, err := parser.ParseMetricSelector(s)
        if err != nil {
            // 解析出错,返回数据错误
            return nil, &api.ApiError{Typ: api.ErrorBadData, Err: err}
        }
        // 将解析出的匹配器添加到storeMatchers中, storeMatchers 是一个 [][]*labels.Matcher 类型的切片。
        storeMatchers = append(storeMatchers, matchers)
    }
 
    return storeMatchers, nil
}
 
// parseDownsamplingParamMillis 函数从HTTP请求中提取最大源分辨率参数值,并将其转换为毫秒数。
// 如果请求中未提供参数值,或者启用了自动降采样,则使用默认值。
// 如果提供的参数值无法解析为有效的时间间隔,则返回错误。
//
// 参数:
// r *http.Request: 包含请求的HTTP请求对象。
// defaultVal time.Duration: 当启用自动降采样或请求中未提供参数值时要使用的默认值。
//
// 返回值:
// maxResolutionMillis int64: 解析后的最大源分辨率(以毫秒为单位)。
// *api.ApiError: 如果发生错误,则返回API错误对象;否则为nil。
func (qapi *QueryAPI) parseDownsamplingParamMillis(r *http.Request, defaultVal time.Duration) (maxResolutionMillis int64, _ *api.ApiError) {
    // 初始化最大源分辨率为0秒
    maxSourceResolution := 0 * time.Second
 
    // 从请求中获取最大源分辨率参数的值
    val := r.FormValue(MaxSourceResolutionParam)
 
    // 如果启用自动降采样或参数值为"auto",则使用默认值
    if qapi.enableAutodownsampling || (val == "auto") {
        maxSourceResolution = defaultVal
    }
 
    // 如果参数值不为空且不为"auto"
    if val != "" && val != "auto" {
        var err error
        // 解析参数值为时间间隔
        maxSourceResolution, err = parseDuration(val)
        if err != nil {
            // 如果解析失败,返回错误
            return 0, &api.ApiError{Typ: api.ErrorBadData, Err: errors.Wrapf(err, "'%s' parameter", MaxSourceResolutionParam)}
        }
    }
 
    // 如果最大源分辨率小于0,返回错误
    if maxSourceResolution < 0 {
        return 0, &api.ApiError{Typ: api.ErrorBadData, Err: errors.Errorf("negative '%s' is not accepted. Try a positive integer", MaxSourceResolutionParam)}
    }
 
    // 将最大源分辨率转换为毫秒,并返回
    return int64(maxSourceResolution / time.Millisecond), nil
}
 
// parsePartialResponseParam 解析请求中的部分响应参数,并返回是否启用部分响应和错误信息
//
// 参数:
//
//  r *http.Request:HTTP 请求对象
//  defaultEnablePartialResponse bool:默认是否启用部分响应
//
// 返回值:
//
//  enablePartialResponse bool:是否启用部分响应
//  *api.ApiError:错误信息,如果解析失败,则返回错误信息,否则返回 nil
func (qapi *QueryAPI) parsePartialResponseParam(r *http.Request, defaultEnablePartialResponse bool) (enablePartialResponse bool, _ *api.ApiError) {
    // 覆盖作为查询参数提供的cli标志
    // Overwrite the cli flag when provided as a query parameter.
    if val := r.FormValue(PartialResponseParam); val != "" {
        // 解析查询参数
        var err error
        defaultEnablePartialResponse, err = strconv.ParseBool(val)
        if err != nil {
            // 如果解析错误,则返回错误
            // Return an error if parsing fails
            return false, &api.ApiError{Typ: api.ErrorBadData, Err: errors.Wrapf(err, "'%s' parameter", PartialResponseParam)}
        }
    }
    return defaultEnablePartialResponse, nil
}
 
// parseStep 函数用于解析查询参数中的步骤时间,并返回步骤时间和可能发生的错误。
//
// 参数:
// r *http.Request:HTTP 请求对象,用于获取查询参数。
// defaultRangeQueryStep time.Duration:默认的步骤时间。
// rangeSeconds int64:范围秒数,用于计算默认步骤时间。
//
// 返回值:
// time.Duration:解析后的步骤时间。
// *api.ApiError:可能发生的错误。
func (qapi *QueryAPI) parseStep(r *http.Request, defaultRangeQueryStep time.Duration, rangeSeconds int64) (time.Duration, *api.ApiError) {
    // 覆盖作为查询参数提供的cli标志
    // Overwrite the cli flag when provided as a query parameter.
    if val := r.FormValue(Step); val != "" {
        var err error
        defaultRangeQueryStep, err = parseDuration(val)
        if err != nil {
            return 0, &api.ApiError{Typ: api.ErrorBadData, Err: errors.Wrapf(err, "'%s' parameter", Step)}
        }
        return defaultRangeQueryStep, nil
    }
    // 使用默认步骤的方式使其与UI一致
    // Default step is used this way to make it consistent with UI.
    d := time.Duration(math.Max(float64(rangeSeconds/250), float64(defaultRangeQueryStep/time.Second))) * time.Second
    return d, nil
}
 
// query 函数是 QueryAPI 结构体中的一个方法,用于处理 HTTP 请求并返回查询结果。
//
// 参数:
//
//  r *http.Request: HTTP 请求对象。
//
// 返回值:
//
//  interface{}: 查询结果数据。
//  []error: 查询过程中产生的警告信息。
//  *api.ApiError: 查询过程中产生的 API 错误信息。
func (qapi *QueryAPI) query(r *http.Request) (interface{}, []error, *api.ApiError) {
    // 解析时间参数。
    // parseTimeParam 函数用于解析时间参数,并将其转换为 time.Time 类型。
    // qapi.baseAPI.Now() 返回当前时间。
    ts, err := parseTimeParam(r, "time", qapi.baseAPI.Now())
    if err != nil {
        return nil, nil, &api.ApiError{Typ: api.ErrorBadData, Err: err}
    }
 
    // 获取请求上下文
    ctx := r.Context()
    // 解析超时参数。r.FormValue("timeout") 用于获取请求中的 "timeout" 参数,该参数指定了查询的超时时间。
    if to := r.FormValue("timeout"); to != "" {
        var cancel context.CancelFunc
        // 解析超时时间参数, parseDuration 函数用于解析超时时间参数,并将其转换为 time.Duration 类型。
        timeout, err := parseDuration(to)
        if err != nil {
            return nil, nil, &api.ApiError{Typ: api.ErrorBadData, Err: err}
        }
 
        // 设置超时上下文
        ctx, cancel = context.WithTimeout(ctx, timeout)
        defer cancel()
    }
 
    // 解析去重参数, qapi.parseEnableDedupParam 函数用于解析请求中的去重参数,并返回是否启用去重的布尔值和可能发生的 API 错误。
    enableDedup, apiErr := qapi.parseEnableDedupParam(r)
    if apiErr != nil {
        return nil, nil, apiErr
    }
 
    // 解析副本标签参数, qapi.parseReplicaLabelsParam 函数用于解析请求中的副本标签参数,并返回副本标签的字符串切片和可能发生的 API 错误。
    replicaLabels, apiErr := qapi.parseReplicaLabelsParam(r)
    if apiErr != nil {
        return nil, nil, apiErr
    }
 
    // 解析调试匹配器参数, qapi.parseStoreDebugMatchersParam 函数用于解析请求中的调试匹配器参数,并返回是否启用调试匹配器的布尔值和可能发生的 API 错误。
    storeDebugMatchers, apiErr := qapi.parseStoreDebugMatchersParam(r)
    if apiErr != nil {
        return nil, nil, apiErr
    }
 
    // 解析部分响应参数, qapi.parsePartialResponseParam 函数用于解析请求中的部分响应参数,并返回是否启用部分响应的布尔值和可能发生的 API 错误。
    enablePartialResponse, apiErr := qapi.parsePartialResponseParam(r, qapi.enableQueryPartialResponse)
    if apiErr != nil {
        return nil, nil, apiErr
    }
 
    // 解析降采样参数, qapi.parseDownsamplingParamMillis 函数用于解析请求中的降采样参数,并返回最大源分辨率的毫秒数和可能发生的 API 错误。
    maxSourceResolution, apiErr := qapi.parseDownsamplingParamMillis(r, qapi.defaultInstantQueryMaxSourceResolution)
    if apiErr != nil {
        return nil, nil, apiErr
    }
 
    // 获取查询引擎, qapi.queryEngine 函数返回一个查询引擎实例,该实例用于执行即时查询。
    qe := qapi.queryEngine(maxSourceResolution)
 
    // 启动PromQL追踪跨度, tracing.StartSpan 函数用于启动一个PromQL追踪跨度。tracing.StartSpan 函数用于启动一个追踪跨度,该跨度与 PromQL 的即时查询相关联。
    // We are starting promQL tracing span here, because we have no control over promQL code.
    span, ctx := tracing.StartSpan(ctx, "promql_instant_query")
    defer span.Finish()
 
    // 创建即时查询, qe.NewInstantQuery 函数用于创建一个新的即时查询实例。该实例将执行 PromQL 表达式,并返回查询结果。
    qry, err := qe.NewInstantQuery(qapi.queryableCreate(enableDedup, replicaLabels, storeDebugMatchers, maxSourceResolution, enablePartialResponse, qapi.enableQueryPushdown, false), r.FormValue("query"), ts)
    if err != nil {
        return nil, nil, &api.ApiError{Typ: api.ErrorBadData, Err: err}
    }
 
    // tracing.DoInSpan 函数用于在指定的上下文中执行一个操作,并创建一个追踪跨度。tracing.DoInSpan 函数用于在给定的上下文和追踪跨度中执行一个操作。
    tracing.DoInSpan(ctx, "query_gate_ismyturn", func(ctx context.Context) {
        err = qapi.gate.Start(ctx)
    })
    if err != nil {
        return nil, nil, &api.ApiError{Typ: api.ErrorExec, Err: err}
    }
    // qapi.gate.Done 函数用于完成查询操作,释放资源。qapi.gate.Start 在执行查询之前获取锁,确保只有一个查询可以同时运行。
    defer qapi.gate.Done()
 
    res := qry.Exec(ctx) // qry.Exec 函数执行查询,并返回一个包含结果和警告的 Result 对象。
 
    // res.Err 检查查询结果中的错误。如果存在错误,则根据错误的类型返回相应的 API 错误信息。
    if res.Err != nil {
        // res.Err.(type) 是 Go 语言中的类型断言,用于检查 res.Err 的具体类型。
        switch res.Err.(type) {
        case promql.ErrQueryCanceled: // 查询被取消
            return nil, nil, &api.ApiError{Typ: api.ErrorCanceled, Err: res.Err}
        case promql.ErrQueryTimeout: // 查询超时
            return nil, nil, &api.ApiError{Typ: api.ErrorTimeout, Err: res.Err}
        case promql.ErrStorage: // 存储错误
            return nil, nil, &api.ApiError{Typ: api.ErrorInternal, Err: res.Err}
        }
        // 其他错误类型,返回执行错误的 API 错误信息
        return nil, nil, &api.ApiError{Typ: api.ErrorExec, Err: res.Err}
    }
 
    // 如果请求参数中包含"stats",则在响应中包含可选的统计信息字段
    var qs *stats.QueryStats
 
    // r.FormValues(Stats) 返回一个包含请求参数中所有 "stats" 值的切片。如果切片不为空,则创建一个新的 QueryStats 对象。
    // 【问】:为什么要在这种情况下创建一个新的 QueryStats 对象?
    // 【答】:stats.NewQueryStats(qry.Stats()) 创建一个新的 QueryStats 对象,并将查询的统计信息传递给它。QueryStats 对象用于存储查询的统计信息,例如查询的持续时间、查询的执行时间、查询的内存使用情况等。这些信息可以帮助用户了解查询的性能和资源使用情况。
    if r.FormValue(Stats) != "" {
        qs = stats.NewQueryStats(qry.Stats())
    }
    return &queryData{
        ResultType: res.Value.Type(), // 查询结果的类型,例如向量、标量等。
        Result:     res.Value,        // 查询结果,可以是向量、标量等。
        Stats:      qs,               // 可选的统计信息字段,如果请求参数中包含 "stats",则包含查询的统计信息。
    }, res.Warnings, nil // 返回查询结果、警告和错误信息。
}
 
// queryRange 方法用于处理HTTP请求,并返回查询结果、错误列表和API错误。
// 参数 r 表示传入的HTTP请求。
// 返回值包括:
// - interface{} 类型的查询结果。
// - []error 类型的错误列表。
// - *api.ApiError 类型的API错误。
func (qapi *QueryAPI) queryRange(r *http.Request) (interface{}, []error, *api.ApiError) {
    // 解析开始时间
    start, err := parseTime(r.FormValue("start"))
    if err != nil {
        // 如果解析开始时间失败,返回错误
        return nil, nil, &api.ApiError{Typ: api.ErrorBadData, Err: err}
    }
    // 解析结束时间
    end, err := parseTime(r.FormValue("end"))
    if err != nil {
        // 如果解析结束时间失败,返回错误
        return nil, nil, &api.ApiError{Typ: api.ErrorBadData, Err: err}
    }
    // 如果结束时间在开始时间之前,返回错误
    if end.Before(start) {
        err := errors.New("end timestamp must not be before start time")
        return nil, nil, &api.ApiError{Typ: api.ErrorBadData, Err: err}
    }
 
    // 解析查询步长。qapi.parseStep 方法用于解析请求中的步长参数,并返回一个表示查询步长的整数和一个可能的 API 错误。
    // qapi.defaultRangeQueryStep 是一个默认的查询步长,用于在解析请求时如果没有指定步长则使用。默认值是 30 秒。
    // int64(end.Sub(start)/time.Second) 是一个表示查询时间范围内的秒数的整数,用于计算查询步长。
    step, apiErr := qapi.parseStep(r, qapi.defaultRangeQueryStep, int64(end.Sub(start)/time.Second))
    if apiErr != nil {
        // 如果解析步长失败,返回错误
        return nil, nil, apiErr
    }
 
    // 如果步长小于等于0,返回错误
    if step <= 0 {
        // 如果步长小于等于0,返回错误,错误的中文意思是:“不接受零或负查询分辨率步长。尝试一个正整数”
        err := errors.New("zero or negative query resolution step widths are not accepted. Try a positive integer")
        return nil, nil, &api.ApiError{Typ: api.ErrorBadData, Err: err}
    }
 
    // end.Sub(start)/step > 11000 是一个条件,用于检查查询时间范围内返回点的数量是否超过 11,000 个。如果超过,则返回错误。
    if end.Sub(start)/step > 11000 {
        // 如果超过,返回错误,错误的中文意思是:“超出了11,000个点时每个时间序列的最大分辨率。尝试减少查询分辨率(?step=XX)”。
        err := errors.New("exceeded maximum resolution of 11,000 points per timeseries. Try decreasing the query resolution (?step=XX)")
        return nil, nil, &api.ApiError{Typ: api.ErrorBadData, Err: err}
    }
 
    // 获取请求上下文
    ctx := r.Context()
    // 解析请求超时时间
    if to := r.FormValue("timeout"); to != "" {
        var cancel context.CancelFunc
        // parseDuartion(to) 函数用于解析超时时间,如果解析失败,返回错误
        timeout, err := parseDuration(to)
        if err != nil {
            return nil, nil, &api.ApiError{Typ: api.ErrorBadData, Err: err}
        }
 
        // 设置超时上下文
        ctx, cancel = context.WithTimeout(ctx, timeout)
        defer cancel()
    }
 
    // 解析去重参数, qapi.parseEnableDedupParam 方法用于解析请求中的去重参数,并返回一个表示是否启用去重的布尔值和一个可能的 API 错误。
    enableDedup, apiErr := qapi.parseEnableDedupParam(r)
    if apiErr != nil {
        return nil, nil, apiErr
    }
 
    // 解析副本标签参数, qapi.parseReplicaLabelsParam 方法用于解析请求中的副本标签参数,并返回一个表示是否启用副本标签的布尔值和一个可能的 API 错误。
    replicaLabels, apiErr := qapi.parseReplicaLabelsParam(r)
    if apiErr != nil {
        return nil, nil, apiErr
    }
 
    // 解析存储调试匹配器参数, qapi.parseStoreDebugMatchersParam 方法用于解析请求中的存储调试匹配器参数,并返回一个表示是否启用存储调试匹配器的布尔值和一个可能的 API 错误。
    storeDebugMatchers, apiErr := qapi.parseStoreDebugMatchersParam(r)
    if apiErr != nil {
        return nil, nil, apiErr
    }
 
    // 解析下采样参数, qapi.parseDownsamplingParamMillis 方法用于解析请求中的下采样参数,并返回一个表示最大源分辨率的整数和一个可能的 API 错误。
    maxSourceResolution, apiErr := qapi.parseDownsamplingParamMillis(r, step/5)
    if apiErr != nil {
        return nil, nil, apiErr
    }
 
    // 解析部分响应参数, qapi.parsePartialResponseParam 方法用于解析请求中的部分响应参数,并返回一个表示是否启用部分响应的布尔值和一个可能的 API 错误。
    enablePartialResponse, apiErr := qapi.parsePartialResponseParam(r, qapi.enableQueryPartialResponse)
    if apiErr != nil {
        return nil, nil, apiErr
    }
 
    // 获取查询引擎, qe 方法用于获取查询引擎实例。它接受一个表示最大源分辨率的整数作为参数,并返回一个查询引擎接口和一个可能的错误。
    qe := qapi.queryEngine(maxSourceResolution)
 
    // 记录查询范围, qapi.queryRangeHist 是一个用于记录查询范围的直方图,它接受一个表示查询持续时间(以秒为单位)的浮点数作为参数。这里,它记录了查询范围的持续时间。
    qapi.queryRangeHist.Observe(end.Sub(start).Seconds())
 
    // 开始PromQL追踪跨度, tracing.StartSpan 方法用于开始一个新的追踪跨度(span),它接受一个上下文和一个字符串作为参数,并返回该跨度和更新后的上下文。这里,它创建了一个名为 "promql_range_query" 的追踪跨度,并记录了查询的开始时间。这里,它记录了查询的开始时间("start"),并将其作为追踪跨度的标签。
    span, ctx := tracing.StartSpan(ctx, "promql_range_query")
    defer span.Finish()
 
    // 创建新的范围查询, qe.NewRangeQuery 方法用于创建一个新的范围查询,它接受一个表示是否启用去重、副本标签、存储调试匹配器、最大源分辨率、部分响应和查询推送的布尔值,以及查询表达式、开始时间、结束时间和步长作为参数,并返回一个范围查询和一个可能的错误。这里,它创建了一个新的范围查询,并记录了查询的开始时间("start")和结束时间("end")。这里,它记录了查询的开始时间("start")和结束时间("end")。
    qry, err := qe.NewRangeQuery(
        // 启用去重、副本标签、存储调试匹配器、最大源分辨率、部分响应和查询推送的布尔值
        qapi.queryableCreate(
            enableDedup,                      // 启用去重
            replicaLabels,                    // 启用副本标签
            storeDebugMatchers,               // 启用存储调试匹配器
            maxSourceResolution,              // 最大源分辨率
            enablePartialResponse,            // 启用部分响应
            qapi.enableQueryPushdown, false), // 启用查询推送down
        r.FormValue("query"), // query 表单字段中的查询表达式
        start,                // 开始时间
        end,                  // 结束时间
        step,                 // 步长
    )
    if err != nil {
        return nil, nil, &api.ApiError{Typ: api.ErrorBadData, Err: err}
    }
 
    // 执行查询, query_gate_ismyturn 是一个追踪跨度,它用于跟踪查询 gate 是否处于打开状态。这里,它使用 tracing.DoInSpan 方法来执行查询,并在查询完成后关闭查询门。这里,它首先尝试获取查询 gate 的状态,如果成功则执行查询。
    tracing.DoInSpan(ctx, "query_gate_ismyturn", func(ctx context.Context) {
        err = qapi.gate.Start(ctx)
    })
    if err != nil {
        return nil, nil, &api.ApiError{Typ: api.ErrorExec, Err: err}
    }
    defer qapi.gate.Done() // 关闭查询 gate
 
    // 执行查询
    res := qry.Exec(ctx)
    if res.Err != nil {
        switch res.Err.(type) {
        // 如果查询被取消,返回错误
        case promql.ErrQueryCanceled:
            return nil, nil, &api.ApiError{Typ: api.ErrorCanceled, Err: res.Err}
        // 如果查询超时,返回错误
        case promql.ErrQueryTimeout:
            return nil, nil, &api.ApiError{Typ: api.ErrorTimeout, Err: res.Err}
        }
        // 如果查询执行出错,返回错误
        return nil, nil, &api.ApiError{Typ: api.ErrorExec, Err: res.Err}
    }
 
    // 如果请求中包含"stats"参数,则在响应中包含统计信息
    var qs *stats.QueryStats
    if r.FormValue(Stats) != "" {
        qs = stats.NewQueryStats(qry.Stats())
    }
    return &queryData{
        ResultType: res.Value.Type(),
        Result:     res.Value,
        Stats:      qs,
    }, res.Warnings, nil
}
 
// labelValues 函数用于处理获取标签值的HTTP请求
//
// 参数:
//
//  r *http.Request: 传入的HTTP请求
//
// 返回值:
//
//  interface{}: 获取到的标签值切片
//  []error: 错误信息切片(当前未使用)
//  *api.ApiError: API错误对象
func (qapi *QueryAPI) labelValues(r *http.Request) (interface{}, []error, *api.ApiError) {
    // 获取请求上下文
    ctx := r.Context()
    // 从请求上下文中获取参数name
    name := route.Param(ctx, "name")
 
    // 验证name是否符合标签名正则表达式
    if !model.LabelNameRE.MatchString(name) {
        // 如果不符合,返回错误
        return nil, nil, &api.ApiError{Typ: api.ErrorBadData, Err: errors.Errorf("invalid label name: %q", name)}
    }
 
    // 解析请求中的时间范围
    start, end, err := parseMetadataTimeRange(r, qapi.defaultMetadataTimeRange)
    if err != nil {
        // 如果解析失败,返回错误
        return nil, nil, &api.ApiError{Typ: api.ErrorBadData, Err: err}
    }
 
    // 解析请求中的partial_response参数
    enablePartialResponse, apiErr := qapi.parsePartialResponseParam(r, qapi.enableQueryPartialResponse)
    if apiErr != nil {
        // 如果解析失败,返回错误
        return nil, nil, apiErr
    }
 
    // 解析请求中的store_debug_matchers参数
    storeDebugMatchers, apiErr := qapi.parseStoreDebugMatchersParam(r)
    if apiErr != nil {
        // 如果解析失败,返回错误
        return nil, nil, apiErr
    }
 
    // 解析请求中的Matcher参数
    var matcherSets [][]*labels.Matcher
    for _, s := range r.Form[MatcherParam] {
        // 解析每个Matcher参数
        matchers, err := parser.ParseMetricSelector(s)
        if err != nil {
            // 如果解析失败,返回错误
            return nil, nil, &api.ApiError{Typ: api.ErrorBadData, Err: err}
        }
        // 将解析得到的matchers添加到matcherSets中
        matcherSets = append(matcherSets, matchers)
    }
 
    // 创建Querier, qapi.queryableCreate 是一个函数,用于创建一个可查询的实例。这里它被用来创建Querier对象,该对象可以执行标签值查询等操作。
    q, err := qapi.queryableCreate(true, nil, storeDebugMatchers, 0, enablePartialResponse, qapi.enableQueryPushdown, true).
        Querier(ctx, timestamp.FromTime(start), timestamp.FromTime(end))
    if err != nil {
        // 如果创建Querier失败,返回错误
        return nil, nil, &api.ApiError{Typ: api.ErrorExec, Err: err}
    }
    // 关闭Querier时记录日志
    defer runutil.CloseWithLogOnErr(qapi.logger, q, "queryable labelValues")
 
    // 存储标签值的切片和警告信息
    var (
        vals     []string
        warnings storage.Warnings
    )
    // 如果matcherSets不为空
    if len(matcherSets) > 0 {
        // 存储每次调用LabelValues返回的警告信息
        var callWarnings storage.Warnings
        // 存储所有标签值的集合
        labelValuesSet := make(map[string]struct{})
        // 遍历每个matcherSet
        for _, matchers := range matcherSets {
            // 调用LabelValues获取标签值
            vals, callWarnings, err = q.LabelValues(name, matchers...)
            if err != nil {
                // 如果调用失败,返回错误
                return nil, nil, &api.ApiError{Typ: api.ErrorExec, Err: err}
            }
            // 将每次调用返回的警告信息添加到warnings中
            warnings = append(warnings, callWarnings...)
            // 将每个标签值添加到labelValuesSet中
            for _, val := range vals {
                labelValuesSet[val] = struct{}{}
            }
        }
 
        // 将labelValuesSet转换为切片并排序
        vals = make([]string, 0, len(labelValuesSet))
        for val := range labelValuesSet {
            vals = append(vals, val)
        }
        sort.Strings(vals)
    } else {
        // 如果matcherSets为空,直接调用LabelValues获取标签值
        vals, warnings, err = q.LabelValues(name)
        if err != nil {
            // 如果调用失败,返回错误
            return nil, nil, &api.ApiError{Typ: api.ErrorExec, Err: err}
        }
    }
 
    // 如果vals为空,则初始化为空切片
    if vals == nil {
        vals = make([]string, 0)
    }
 
    // 返回标签值切片、警告信息和nil错误
    return vals, warnings, nil
}
 
// series 函数用于处理时间序列查询请求。
//
// 参数:
//   - r: *http.Request, HTTP请求对象,包含查询参数和表单数据。
//
// 返回值:
//   - interface{}, 查询结果,具体类型取决于查询结果。
//   - []error, 错误列表,可能包含多个错误。
//   - *api.ApiError, API错误,如果发生API级别的错误则返回此错误。
func (qapi *QueryAPI) series(r *http.Request) (interface{}, []error, *api.ApiError) {
    // 解析请求表单
    if err := r.ParseForm(); err != nil {
        return nil, nil, &api.ApiError{Typ: api.ErrorInternal, Err: errors.Wrap(err, "parse form")}
    }
 
    // 检查请求表单中是否提供了匹配参数
    if len(r.Form[MatcherParam]) == 0 {
        return nil, nil, &api.ApiError{Typ: api.ErrorBadData, Err: errors.New("no match[] parameter provided")}
    }
 
    // 解析时间范围,parseMetadataTimeRange 用于解析请求中的时间范围参数,例如从和到的时间。如果解析失败,则返回错误信息。
    start, end, err := parseMetadataTimeRange(r, qapi.defaultMetadataTimeRange)
    if err != nil {
        return nil, nil, &api.ApiError{Typ: api.ErrorBadData, Err: err}
    }
 
    // 初始化匹配器集合
    var matcherSets [][]*labels.Matcher
    for _, s := range r.Form[MatcherParam] {
        // 解析每个匹配器字符串
        matchers, err := parser.ParseMetricSelector(s)
        if err != nil {
            return nil, nil, &api.ApiError{Typ: api.ErrorBadData, Err: err}
        }
        // 将解析后的匹配器添加到匹配器集合中
        matcherSets = append(matcherSets, matchers)
    }
 
    // 解析去重参数
    enableDedup, apiErr := qapi.parseEnableDedupParam(r)
    if apiErr != nil {
        return nil, nil, apiErr
    }
 
    // 解析副本标签参数
    replicaLabels, apiErr := qapi.parseReplicaLabelsParam(r)
    if apiErr != nil {
        return nil, nil, apiErr
    }
 
    // 解析存储调试匹配器参数
    storeDebugMatchers, apiErr := qapi.parseStoreDebugMatchersParam(r)
    if apiErr != nil {
        return nil, nil, apiErr
    }
 
    // 解析部分响应参数
    enablePartialResponse, apiErr := qapi.parsePartialResponseParam(r, qapi.enableQueryPartialResponse)
    if apiErr != nil {
        return nil, nil, apiErr
    }
 
    // 创建查询器, qapi.queryableCrete 用于创建查询器实例,该函数接受一系列参数并返回一个Querier接口的实现。
    q, err := qapi.queryableCreate(enableDedup, replicaLabels, storeDebugMatchers, math.MaxInt64, enablePartialResponse, qapi.enableQueryPushdown, true).
        Querier(r.Context(), timestamp.FromTime(start), timestamp.FromTime(end))
    if err != nil {
        return nil, nil, &api.ApiError{Typ: api.ErrorExec, Err: err}
    }
    // 确保查询器在函数结束时关闭
    defer runutil.CloseWithLogOnErr(qapi.logger, q, "queryable series")
 
    // 初始化存储指标集合和系列集合
    var (
        metrics = []labels.Labels{}
        sets    []storage.SeriesSet
    )
    // 对每个匹配器集合执行选择操作
    for _, mset := range matcherSets {
        sets = append(sets, q.Select(false, nil, mset...))
    }
 
    // 合并系列集合
    set := storage.NewMergeSeriesSet(sets, storage.ChainedSeriesMerge)
    // 遍历合并后的系列集合
    for set.Next() {
        // 将当前系列的标签添加到指标集合中
        metrics = append(metrics, set.At().Labels())
    }
    // 检查是否有错误发生
    if set.Err() != nil {
        return nil, nil, &api.ApiError{Typ: api.ErrorExec, Err: set.Err()}
    }
    return metrics, set.Warnings(), nil
}
 
// labelNames 函数用于处理HTTP请求,并返回接口、错误列表和ApiError指针。
// 参数 r 表示HTTP请求对象。
//
// 返回结果:
// - 接口:返回标签名称的切片。
// - 错误列表:返回可能发生的错误列表。
// - ApiError指针:如果发生API错误,将返回ApiError指针。
func (qapi *QueryAPI) labelNames(r *http.Request) (interface{}, []error, *api.ApiError) {
    // 解析请求中的时间范围参数,如果解析失败,则返回错误信息。
    start, end, err := parseMetadataTimeRange(r, qapi.defaultMetadataTimeRange)
    if err != nil {
        return nil, nil, &api.ApiError{Typ: api.ErrorBadData, Err: err}
    }
 
    // 解析部分响应参数
    enablePartialResponse, apiErr := qapi.parsePartialResponseParam(r, qapi.enableQueryPartialResponse)
    if apiErr != nil {
        return nil, nil, apiErr
    }
 
    // 解析存储调试匹配器参数
    storeDebugMatchers, apiErr := qapi.parseStoreDebugMatchersParam(r)
    if apiErr != nil {
        return nil, nil, apiErr
    }
 
    var matcherSets [][]*labels.Matcher
    for _, s := range r.Form[MatcherParam] {
        // 解析度量选择器参数
        matchers, err := parser.ParseMetricSelector(s)
        if err != nil {
            return nil, nil, &api.ApiError{Typ: api.ErrorBadData, Err: err}
        }
        matcherSets = append(matcherSets, matchers)
    }
 
    // 创建查询对象
    q, err := qapi.queryableCreate(true, nil, storeDebugMatchers, 0, enablePartialResponse, qapi.enableQueryPushdown, true).
        Querier(r.Context(), timestamp.FromTime(start), timestamp.FromTime(end))
    if err != nil {
        return nil, nil, &api.ApiError{Typ: api.ErrorExec, Err: err}
    }
    // 确保查询器在函数结束时关闭
    defer runutil.CloseWithLogOnErr(qapi.logger, q, "queryable labelNames")
 
    var (
        names    []string
        warnings storage.Warnings
    )
 
    // 如果匹配器集合不为空
    if len(matcherSets) > 0 {
        var callWarnings storage.Warnings
        // 创建标签名集合
        labelNamesSet := make(map[string]struct{})
        for _, matchers := range matcherSets {
            // 获取标签名集合
            names, callWarnings, err = q.LabelNames(matchers...)
            if err != nil {
                return nil, nil, &api.ApiError{Typ: api.ErrorExec, Err: err}
            }
            // 将每次调用返回的警告信息添加到warnings中
            warnings = append(warnings, callWarnings...)
            // 将每个标签名添加到labelNamesSet中
            for _, val := range names {
                labelNamesSet[val] = struct{}{}
            }
        }
 
        // 将标签名集合转换为字符串切片并排序
        names = make([]string, 0, len(labelNamesSet))
        // 遍历标签名集合
        for name := range labelNamesSet {
            names = append(names, name)
        }
        sort.Strings(names) // 对标签名进行排序
    } else {
        // 如果匹配器集合为空,则获取所有标签名
        names, warnings, err = q.LabelNames()
    }
 
    if err != nil {
        return nil, nil, &api.ApiError{Typ: api.ErrorExec, Err: err}
    }
    if names == nil {
        // 如果标签名集合为空,则初始化为空切片
        names = make([]string, 0)
    }
 
    return names, warnings, nil
}
 
// stores 处理函数用于从QueryAPI结构体中获取所有组件类型的状态列表。
//
// 参数:
//
//  _ *http.Request: 请求对象,本函数不使用该参数。
//
// 返回值:
//
//  interface{}: 包含每种组件类型的状态列表的map,键为组件类型字符串,值为对应组件类型的状态列表。
//  []error: 错误列表,本函数始终返回空列表。
//  *api.ApiError: ApiError对象,本函数始终返回nil。
func (qapi *QueryAPI) stores(_ *http.Request) (interface{}, []error, *api.ApiError) {
    // 创建一个map来存储每种组件类型的状态列表
    statuses := make(map[string][]query.EndpointStatus)
 
    // 遍历所有端点状态
    for _, status := range qapi.endpointStatus() {
        // 如果无法获取组件类型,则忽略该端点
        // Don't consider an endpoint if we cannot retrieve component type.
        if status.ComponentType == nil {
            continue
        }
        // 将端点状态添加到对应组件类型的列表中
        statuses[status.ComponentType.String()] = append(statuses[status.ComponentType.String()], status)
    }
    // 返回所有组件类型的状态列表、空错误列表和空ApiError
    return statuses, nil, nil
}
 
// NewTargetsHandler created handler compatible with HTTP /api/v1/targets https://prometheus.io/docs/prometheus/latest/querying/api/#targets
// which uses gRPC Unary Targets API.
// NewTargetsHandler 函数用于创建一个新的目标处理器。
// 该处理器根据请求中的参数,从客户端获取目标列表,并返回这些目标、警告信息和API错误(如果有的话)。
//
// 参数:
//
//  client targets.UnaryClient: 用于获取目标列表的客户端。
//  enablePartialResponse bool: 是否启用部分响应。如果启用,则在获取目标时,如果某些目标无法获取,则返回这些目标的警告信息,而不是直接返回错误。
//
// 返回值:
//
//  func(*http.Request) (interface{}, []error, *api.ApiError): 一个函数,该函数接受一个HTTP请求,并返回一个接口(表示获取到的目标列表),一个错误切片(表示警告信息),以及一个API错误(如果有的话)。
func NewTargetsHandler(client targets.UnaryClient, enablePartialResponse bool) func(*http.Request) (interface{}, []error, *api.ApiError) {
    // 定义部分响应策略,默认为ABORT
    ps := storepb.PartialResponseStrategy_ABORT
    // 如果启用部分响应,则将策略更改为WARN
    if enablePartialResponse {
        ps = storepb.PartialResponseStrategy_WARN
    }
 
    return func(r *http.Request) (interface{}, []error, *api.ApiError) {
        // 从请求URL中获取state参数
        stateParam := r.URL.Query().Get("state")
        // 将state参数转换为大写,并尝试从targetspb.TargetsRequest_State_value中查找对应的枚举值
        state, ok := targetspb.TargetsRequest_State_value[strings.ToUpper(stateParam)]
        // 如果未找到对应的枚举值
        if !ok {
            // 如果state参数不为空且未找到对应的枚举值,则返回错误信息
            if stateParam != "" {
                return nil, nil, &api.ApiError{Typ: api.ErrorBadData, Err: errors.Errorf("invalid targets parameter state='%v'", stateParam)}
            }
            // 如果state参数为空,则默认使用ANY状态
            state = int32(targetspb.TargetsRequest_ANY)
        }
 
        // 构造TargetsRequest请求
        req := &targetspb.TargetsRequest{
            State:                   targetspb.TargetsRequest_State(state),
            PartialResponseStrategy: ps,
        }
 
        // 调用客户端的Targets方法获取目标列表
        t, warnings, err := client.Targets(r.Context(), req)
        // 如果发生错误,则返回错误信息
        if err != nil {
            return nil, nil, &api.ApiError{Typ: api.ErrorInternal, Err: errors.Wrap(err, "retrieving targets")}
        }
 
        // 返回获取到的目标列表和警告信息
        return t, warnings, nil
    }
}
 
// NewRulesHandler created handler compatible with HTTP /api/v1/rules https://prometheus.io/docs/prometheus/latest/querying/api/#rules
// which uses gRPC Unary Rules API.
// NewRulesHandler 创建一个处理HTTP请求的函数,该函数用于处理与规则相关的请求。
// 参数:
//
//  client:rules.UnaryClient接口的实现,用于处理与规则相关的请求。
//  enablePartialResponse:布尔值,表示是否启用部分响应。
//
// 返回值:
//
//  返回的函数接受一个*http.Request类型的参数,返回一个interface{}类型的响应,一个[]error类型的错误列表,以及一个*api.ApiError类型的API错误。
func NewRulesHandler(client rules.UnaryClient, enablePartialResponse bool) func(*http.Request) (interface{}, []error, *api.ApiError) {
    // 设置部分响应策略
    ps := storepb.PartialResponseStrategy_ABORT
    if enablePartialResponse {
        ps = storepb.PartialResponseStrategy_WARN
    }
 
    return func(r *http.Request) (interface{}, []error, *api.ApiError) {
        // 开始追踪HTTP请求处理过程
        span, ctx := tracing.StartSpan(r.Context(), "receive_http_request")
        defer span.Finish()
 
        // 声明变量
        var (
            groups   *rulespb.RuleGroups
            warnings storage.Warnings
            err      error
        )
 
        // 获取请求参数
        typeParam := r.URL.Query().Get("type")
        // 将 typeParam 转换为大写,并尝试从 rulespb.RulesRequest_Type_value 中查找对应的枚举值
        typ, ok := rulespb.RulesRequest_Type_value[strings.ToUpper(typeParam)]
        if !ok {
            // 如果参数类型无效
            if typeParam != "" {
                return nil, nil, &api.ApiError{Typ: api.ErrorBadData, Err: errors.Errorf("invalid rules parameter type='%v'", typeParam)}
            }
            // 默认为ALL类型
            typ = int32(rulespb.RulesRequest_ALL)
        }
 
        // 解析表单数据
        if err := r.ParseForm(); err != nil {
            return nil, nil, &api.ApiError{Typ: api.ErrorInternal, Err: errors.Errorf("error parsing request form='%v'", MatcherParam)}
        }
 
        // TODO(bwplotka): Allow exactly the same functionality as query API: passing replica, dedup and partial response as HTTP params as well.
        // 创建RulesRequest请求
        req := &rulespb.RulesRequest{
            Type:                    rulespb.RulesRequest_Type(typ), // 设置规则类型
            PartialResponseStrategy: ps,                             // 设置部分响应策略
            MatcherString:           r.Form[MatcherParam],           // 设置匹配器字符串
        }
        // 在追踪上下文中执行获取规则操作
        tracing.DoInSpan(ctx, "retrieve_rules", func(ctx context.Context) {
            groups, warnings, err = client.Rules(ctx, req)
        })
        if err != nil {
            // 如果获取规则失败
            return nil, nil, &api.ApiError{Typ: api.ErrorInternal, Err: errors.Errorf("error retrieving rules: %v", err)}
        }
        return groups, warnings, nil
    }
}
 
// NewExemplarsHandler creates handler compatible with HTTP /api/v1/query_exemplars https://prometheus.io/docs/prometheus/latest/querying/api/#querying-exemplars
// which uses gRPC Unary Exemplars API.
// NewExemplarsHandler 创建一个处理Exemplars请求的处理器。
// 该处理器返回一个函数,该函数接收一个http.Request对象,并返回一个接口、错误列表和ApiError指针。
//
// 参数:
// - client: exemplars.UnaryClient接口,用于与存储层进行通信。
// - enablePartialResponse: bool类型,表示是否启用部分响应。
//
// 返回值:
//   - func(*http.Request) (interface{}, []error, *api.ApiError): 接收http.Request对象的函数,
//     返回一个接口、错误列表和ApiError指针。
func NewExemplarsHandler(client exemplars.UnaryClient, enablePartialResponse bool) func(*http.Request) (interface{}, []error, *api.ApiError) {
    // storepb.PartialResponseStrategy_ABORT 是部分响应策略的默认值,表示在部分响应策略中,如果遇到错误,则直接返回错误。
    ps := storepb.PartialResponseStrategy_ABORT
    if enablePartialResponse {
        // 如果启用部分响应,则设置为警告策略
        ps = storepb.PartialResponseStrategy_WARN
    }
 
    return func(r *http.Request) (interface{}, []error, *api.ApiError) {
        // 创建跟踪跨度
        span, ctx := tracing.StartSpan(r.Context(), "exemplar_query_request")
        defer span.Finish()
 
        // 声明存储返回数据的变量
        var (
            data     []*exemplarspb.ExemplarData
            warnings storage.Warnings
            err      error
        )
 
        // 解析请求中的起始时间参数
        start, err := parseTimeParam(r, "start", infMinTime)
        if err != nil {
            // 如果解析起始时间参数出错,则返回错误
            return nil, nil, &api.ApiError{Typ: api.ErrorBadData, Err: err}
        }
        // 解析请求中的结束时间参数
        end, err := parseTimeParam(r, "end", infMaxTime)
        if err != nil {
            // 如果解析结束时间参数出错,则返回错误
            return nil, nil, &api.ApiError{Typ: api.ErrorBadData, Err: err}
        }
 
        // 创建请求
        req := &exemplarspb.ExemplarsRequest{
            Start:                   timestamp.FromTime(start),
            End:                     timestamp.FromTime(end),
            Query:                   r.FormValue("query"),
            PartialResponseStrategy: ps,
        }
 
        // 在跨度内执行获取示例的操作
        tracing.DoInSpan(ctx, "retrieve_exemplars", func(ctx context.Context) {
            data, warnings, err = client.Exemplars(ctx, req)
        })
 
        if err != nil {
            // 如果获取示例出错,则返回内部错误
            return nil, nil, &api.ApiError{Typ: api.ErrorInternal, Err: errors.Wrap(err, "retrieving exemplars")}
        }
        return data, warnings, nil
    }
}
 
var (
    infMinTime = time.Unix(math.MinInt64/1000+62135596801, 0)
    infMaxTime = time.Unix(math.MaxInt64/1000-62135596801, 999999999)
)
 
// parseMetadataTimeRange 从HTTP请求中解析时间范围,并返回起始时间和结束时间
//
// 参数:
//
//  r: *http.Request, HTTP请求对象
//  defaultMetadataTimeRange: time.Duration, 默认的时间范围
//
// 返回值:
//
//  time.Time, 起始时间
//  time.Time, 结束时间
//  error, 错误信息
//
// 说明:
//
//  如果请求参数中未指定起始时间和结束时间,则默认从时间开始处获取时间范围。
//  如果defaultMetadataTimeRange为0,则默认时间范围为时间开始到时间结束。
func parseMetadataTimeRange(r *http.Request, defaultMetadataTimeRange time.Duration) (time.Time, time.Time, error) {
    // 如果未指定查询参数中的开始时间和结束时间,则默认获取从时间起点到当前时间的范围
    // If start and end time not specified as query parameter, we get the range from the beginning of time by default.
    var defaultStartTime, defaultEndTime time.Time
    if defaultMetadataTimeRange == 0 {
        defaultStartTime = infMinTime
        defaultEndTime = infMaxTime
    } else {
        now := time.Now()
        defaultStartTime = now.Add(-defaultMetadataTimeRange)
        defaultEndTime = now
    }
 
    // 解析查询参数中的开始时间
    // Parse the start time from the query parameter
    start, err := parseTimeParam(r, "start", defaultStartTime)
    if err != nil {
        return time.Time{}, time.Time{}, &api.ApiError{Typ: api.ErrorBadData, Err: err}
    }
    // 解析查询参数中的结束时间
    // Parse the end time from the query parameter
    end, err := parseTimeParam(r, "end", defaultEndTime)
    if err != nil {
        return time.Time{}, time.Time{}, &api.ApiError{Typ: api.ErrorBadData, Err: err}
    }
    // 如果结束时间在开始时间之前,则抛出错误
    // If the end time is before the start time, throw an error
    if end.Before(start) {
        return time.Time{}, time.Time{}, &api.ApiError{
            Typ: api.ErrorBadData,
            Err: errors.New("end timestamp must not be before start time"),
        }
    }
 
    return start, end, nil
}
 
// parseTimeParam 从HTTP请求中解析时间参数,并返回时间
//
// 参数:
//
//  r: *http.Request, HTTP请求对象
//  paramName: string, 参数名称
//  defaultValue: time.Time, 默认时间
//
// 返回值:
//
//  time.Time, 时间
//  error, 错误信息
//
// parseTimeParam 从HTTP请求中解析时间参数,并返回时间
//
// 参数:
//
//  r: *http.Request, HTTP请求对象
//  paramName: string, 参数名称
//  defaultValue: time.Time, 默认时间
//
// 返回值:
//
//  time.Time, 时间
//  error, 错误信息
func parseTimeParam(r *http.Request, paramName string, defaultValue time.Time) (time.Time, error) {
    // 从请求中获取参数值
    val := r.FormValue(paramName)
    // 如果参数值为空,则返回默认值
    if val == "" {
        return defaultValue, nil
    }
    // 解析时间值
    result, err := parseTime(val)
    // 如果解析过程中出现错误,则返回错误信息
    if err != nil {
        // 封装错误信息
        return time.Time{}, errors.Wrapf(err, "Invalid time value for '%s'", paramName)
    }
    // 返回解析后的时间值和错误信息
    return result, nil
}
 
// parseTime 函数尝试将字符串 s 解析为 time.Time 类型的时间对象,并返回该对象以及错误信息。
// 如果解析成功,则返回 time.Time 对象和 nil 错误信息。
// 如果解析失败,则返回 time.Time{} 和错误信息。
//
// 参数:
//
//  s string:需要解析的时间字符串
//
// 返回值:
//
//  time.Time:解析得到的时间对象
//  error:错误信息,如果解析成功则为 nil
func parseTime(s string) (time.Time, error) {
    // 尝试将字符串转换为浮点数
    if t, err := strconv.ParseFloat(s, 64); err == nil {
        // 分离秒和纳秒部分
        s, ns := math.Modf(t)
        // 对纳秒部分进行四舍五入并转换为整数
        ns = math.Round(ns*1000) / 1000
        // 使用秒和纳秒部分构造时间对象
        return time.Unix(int64(s), int64(ns*float64(time.Second))), nil
    }
    // 尝试按照RFC3339Nano格式解析时间字符串
    if t, err := time.Parse(time.RFC3339Nano, s); err == nil {
        // 解析成功,返回时间对象
        return t, nil
    }
    // 如果以上两种方式都失败,返回错误
    return time.Time{}, errors.Errorf("cannot parse %q to a valid timestamp", s)
}
 
// parseDuration 函数将字符串解析为 time.Duration 类型。
// 如果字符串可以成功转换为浮点数,则将其转换为秒数,并返回对应的 time.Duration。
// 如果转换后的秒数超出了 int64 的范围,则返回错误。
// 如果字符串无法转换为浮点数,则尝试使用 model.ParseDuration 函数解析。
// 如果解析成功,则返回对应的 time.Duration;否则返回错误。
func parseDuration(s string) (time.Duration, error) {
    // 尝试将字符串转换为浮点数
    if d, err := strconv.ParseFloat(s, 64); err == nil {
        // 将浮点数转换为秒数
        ts := d * float64(time.Second)
        // 检查转换后的秒数是否溢出int64范围
        if ts > float64(math.MaxInt64) || ts < float64(math.MinInt64) {
            // 如果溢出,则返回错误
            return 0, errors.Errorf("cannot parse %q to a valid duration. It overflows int64", s)
        }
        // 返回转换后的time.Duration
        return time.Duration(ts), nil
    }
    // 使用自定义的模型解析函数尝试解析字符串
    if d, err := model.ParseDuration(s); err == nil {
        // 返回解析后的time.Duration
        return time.Duration(d), nil
    }
    // 如果以上解析都失败,则返回错误
    return 0, errors.Errorf("cannot parse %q to a valid duration", s)
}
 
// NewMetricMetadataHandler creates handler compatible with HTTP /api/v1/metadata https://prometheus.io/docs/prometheus/latest/querying/api/#querying-metric-metadata
// which uses gRPC Unary Metadata API.
// NewMetricMetadataHandler 创建一个处理指标元数据请求的函数。
// client: 元数据 UnaryClient 接口。
// enablePartialResponse: 是否启用部分响应。
// 返回值: 一个函数,该函数接受一个 *http.Request 参数,并返回一个 interface{} 类型的指标元数据、一个 []error 类型的错误列表,以及一个 *api.ApiError 类型的 API 错误。
func NewMetricMetadataHandler(client metadata.UnaryClient, enablePartialResponse bool) func(*http.Request) (interface{}, []error, *api.ApiError) {
    // 设置部分响应策略
    ps := storepb.PartialResponseStrategy_ABORT
    if enablePartialResponse {
        ps = storepb.PartialResponseStrategy_WARN
    }
 
    return func(r *http.Request) (interface{}, []error, *api.ApiError) {
        // 开始追踪HTTP请求
        span, ctx := tracing.StartSpan(r.Context(), "metadata_http_request")
        defer span.Finish()
 
        var (
            // 存储指标元数据
            t map[string][]metadatapb.Meta
            // 存储警告信息
            warnings storage.Warnings
            // 存储错误信息
            err error
        )
 
        // 构建指标元数据请求
        req := &metadatapb.MetricMetadataRequest{
            // 默认情况下,我们使用-1,表示没有限制。
            Limit:                   -1,
            Metric:                  r.URL.Query().Get("metric"),
            PartialResponseStrategy: ps,
        }
 
        // 获取URL中的limit参数
        limitStr := r.URL.Query().Get("limit")
        if limitStr != "" {
            // 将limit参数转换为整数
            limit, err := strconv.ParseInt(limitStr, 10, 32)
            if err != nil {
                // 返回API错误
                return nil, nil, &api.ApiError{Typ: api.ErrorBadData, Err: errors.Errorf("invalid metric metadata limit='%v'", limit)}
            }
            req.Limit = int32(limit)
        }
 
        // 在span中执行获取元数据操作
        tracing.DoInSpan(ctx, "retrieve_metadata", func(ctx context.Context) {
            // 从客户端获取指标元数据
            t, warnings, err = client.MetricMetadata(ctx, req)
        })
        if err != nil {
            // 返回API错误
            return nil, nil, &api.ApiError{Typ: api.ErrorInternal, Err: errors.Wrap(err, "retrieving metadata")}
        }
 
        // 返回指标元数据、警告信息和错误信息
        return t, warnings, nil
    }
}

 

  

 

 

posted @   左扬  阅读(0)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 在鹅厂做java开发是什么体验
· 百万级群聊的设计实践
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
· 永远不要相信用户的输入:从 SQL 注入攻防看输入验证的重要性
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
历史上的今天:
2022-02-14 Go从入门到精通——映射(map)——建立事物关联的容器
2022-02-14 Go从入门到精通——切片(slice)(动态分配大小的连续空间)
levels of contents
点击右上角即可分享
微信分享提示