github.com/thanos-io/thanos@v0.32.5/pkg/api/query/grpc.go (about) 1 // Copyright (c) The Thanos Authors. 2 // Licensed under the Apache License 2.0. 3 4 package v1 5 6 import ( 7 "context" 8 "time" 9 10 "github.com/prometheus/prometheus/promql" 11 v1 "github.com/prometheus/prometheus/web/api/v1" 12 "google.golang.org/grpc" 13 "google.golang.org/grpc/codes" 14 "google.golang.org/grpc/status" 15 16 "github.com/thanos-io/thanos/pkg/api/query/querypb" 17 "github.com/thanos-io/thanos/pkg/query" 18 "github.com/thanos-io/thanos/pkg/store/labelpb" 19 "github.com/thanos-io/thanos/pkg/store/storepb/prompb" 20 ) 21 22 type GRPCAPI struct { 23 now func() time.Time 24 replicaLabels []string 25 queryableCreate query.QueryableCreator 26 engineFactory *QueryEngineFactory 27 defaultEngine querypb.EngineType 28 lookbackDeltaCreate func(int64) time.Duration 29 defaultMaxResolutionSeconds time.Duration 30 } 31 32 func NewGRPCAPI( 33 now func() time.Time, 34 replicaLabels []string, 35 creator query.QueryableCreator, 36 engineFactory *QueryEngineFactory, 37 defaultEngine querypb.EngineType, 38 lookbackDeltaCreate func(int64) time.Duration, 39 defaultMaxResolutionSeconds time.Duration, 40 ) *GRPCAPI { 41 return &GRPCAPI{ 42 now: now, 43 replicaLabels: replicaLabels, 44 queryableCreate: creator, 45 engineFactory: engineFactory, 46 defaultEngine: defaultEngine, 47 lookbackDeltaCreate: lookbackDeltaCreate, 48 defaultMaxResolutionSeconds: defaultMaxResolutionSeconds, 49 } 50 } 51 52 func RegisterQueryServer(queryServer querypb.QueryServer) func(*grpc.Server) { 53 return func(s *grpc.Server) { 54 querypb.RegisterQueryServer(s, queryServer) 55 } 56 } 57 58 func (g *GRPCAPI) Query(request *querypb.QueryRequest, server querypb.Query_QueryServer) error { 59 ctx := server.Context() 60 var ts time.Time 61 if request.TimeSeconds == 0 { 62 ts = g.now() 63 } else { 64 ts = time.Unix(request.TimeSeconds, 0) 65 } 66 67 if request.TimeoutSeconds != 0 { 68 var cancel context.CancelFunc 69 timeout := time.Duration(request.TimeoutSeconds) * time.Second 70 ctx, cancel = context.WithTimeout(ctx, timeout) 71 defer cancel() 72 } 73 74 maxResolution := request.MaxResolutionSeconds 75 if request.MaxResolutionSeconds == 0 { 76 maxResolution = g.defaultMaxResolutionSeconds.Milliseconds() / 1000 77 } 78 79 lookbackDelta := g.lookbackDeltaCreate(maxResolution * 1000) 80 if request.LookbackDeltaSeconds > 0 { 81 lookbackDelta = time.Duration(request.LookbackDeltaSeconds) * time.Second 82 } 83 84 storeMatchers, err := querypb.StoreMatchersToLabelMatchers(request.StoreMatchers) 85 if err != nil { 86 return err 87 } 88 89 replicaLabels := g.replicaLabels 90 if len(request.ReplicaLabels) != 0 { 91 replicaLabels = request.ReplicaLabels 92 } 93 94 queryable := g.queryableCreate( 95 request.EnableDedup, 96 replicaLabels, 97 storeMatchers, 98 maxResolution, 99 request.EnablePartialResponse, 100 request.EnableQueryPushdown, 101 false, 102 request.ShardInfo, 103 query.NoopSeriesStatsReporter, 104 ) 105 106 var engine v1.QueryEngine 107 engineParam := request.Engine 108 if engineParam == querypb.EngineType_default { 109 engineParam = g.defaultEngine 110 } 111 112 switch engineParam { 113 case querypb.EngineType_prometheus: 114 engine = g.engineFactory.GetPrometheusEngine() 115 case querypb.EngineType_thanos: 116 engine = g.engineFactory.GetThanosEngine() 117 default: 118 return status.Error(codes.InvalidArgument, "invalid engine parameter") 119 } 120 qry, err := engine.NewInstantQuery(ctx, queryable, promql.NewPrometheusQueryOpts(false, lookbackDelta), request.Query, ts) 121 if err != nil { 122 return err 123 } 124 defer qry.Close() 125 126 result := qry.Exec(ctx) 127 if result.Err != nil { 128 return status.Error(codes.Aborted, result.Err.Error()) 129 } 130 131 if len(result.Warnings) != 0 { 132 if err := server.Send(querypb.NewQueryWarningsResponse(result.Warnings...)); err != nil { 133 return err 134 } 135 } 136 137 switch vector := result.Value.(type) { 138 case promql.Scalar: 139 series := &prompb.TimeSeries{ 140 Samples: []prompb.Sample{{Value: vector.V, Timestamp: vector.T}}, 141 } 142 if err := server.Send(querypb.NewQueryResponse(series)); err != nil { 143 return err 144 } 145 case promql.Vector: 146 for _, sample := range vector { 147 floats, histograms := prompb.SamplesFromPromqlSamples(sample) 148 series := &prompb.TimeSeries{ 149 Labels: labelpb.ZLabelsFromPromLabels(sample.Metric), 150 Samples: floats, 151 Histograms: histograms, 152 } 153 if err := server.Send(querypb.NewQueryResponse(series)); err != nil { 154 return err 155 } 156 } 157 return nil 158 } 159 160 return nil 161 } 162 163 func (g *GRPCAPI) QueryRange(request *querypb.QueryRangeRequest, srv querypb.Query_QueryRangeServer) error { 164 ctx := srv.Context() 165 if request.TimeoutSeconds != 0 { 166 var cancel context.CancelFunc 167 timeout := time.Duration(request.TimeoutSeconds) * time.Second 168 ctx, cancel = context.WithTimeout(ctx, timeout) 169 defer cancel() 170 } 171 172 maxResolution := request.MaxResolutionSeconds 173 if request.MaxResolutionSeconds == 0 { 174 maxResolution = g.defaultMaxResolutionSeconds.Milliseconds() / 1000 175 } 176 177 lookbackDelta := g.lookbackDeltaCreate(maxResolution * 1000) 178 if request.LookbackDeltaSeconds > 0 { 179 lookbackDelta = time.Duration(request.LookbackDeltaSeconds) * time.Second 180 } 181 182 storeMatchers, err := querypb.StoreMatchersToLabelMatchers(request.StoreMatchers) 183 if err != nil { 184 return err 185 } 186 187 replicaLabels := g.replicaLabels 188 if len(request.ReplicaLabels) != 0 { 189 replicaLabels = request.ReplicaLabels 190 } 191 192 queryable := g.queryableCreate( 193 request.EnableDedup, 194 replicaLabels, 195 storeMatchers, 196 maxResolution, 197 request.EnablePartialResponse, 198 request.EnableQueryPushdown, 199 false, 200 request.ShardInfo, 201 query.NoopSeriesStatsReporter, 202 ) 203 204 startTime := time.Unix(request.StartTimeSeconds, 0) 205 endTime := time.Unix(request.EndTimeSeconds, 0) 206 interval := time.Duration(request.IntervalSeconds) * time.Second 207 208 var engine v1.QueryEngine 209 engineParam := request.Engine 210 if engineParam == querypb.EngineType_default { 211 engineParam = g.defaultEngine 212 } 213 214 switch engineParam { 215 case querypb.EngineType_prometheus: 216 engine = g.engineFactory.GetPrometheusEngine() 217 case querypb.EngineType_thanos: 218 engine = g.engineFactory.GetThanosEngine() 219 default: 220 return status.Error(codes.InvalidArgument, "invalid engine parameter") 221 } 222 qry, err := engine.NewRangeQuery(ctx, queryable, promql.NewPrometheusQueryOpts(false, lookbackDelta), request.Query, startTime, endTime, interval) 223 if err != nil { 224 return err 225 } 226 defer qry.Close() 227 228 result := qry.Exec(ctx) 229 if result.Err != nil { 230 return status.Error(codes.Aborted, result.Err.Error()) 231 } 232 233 if len(result.Warnings) != 0 { 234 if err := srv.Send(querypb.NewQueryRangeWarningsResponse(result.Warnings...)); err != nil { 235 return err 236 } 237 } 238 239 switch value := result.Value.(type) { 240 case promql.Matrix: 241 for _, series := range value { 242 floats, histograms := prompb.SamplesFromPromqlSeries(series) 243 series := &prompb.TimeSeries{ 244 Labels: labelpb.ZLabelsFromPromLabels(series.Metric), 245 Samples: floats, 246 Histograms: histograms, 247 } 248 if err := srv.Send(querypb.NewQueryRangeResponse(series)); err != nil { 249 return err 250 } 251 } 252 case promql.Vector: 253 for _, sample := range value { 254 floats, histograms := prompb.SamplesFromPromqlSamples(sample) 255 series := &prompb.TimeSeries{ 256 Labels: labelpb.ZLabelsFromPromLabels(sample.Metric), 257 Samples: floats, 258 Histograms: histograms, 259 } 260 if err := srv.Send(querypb.NewQueryRangeResponse(series)); err != nil { 261 return err 262 } 263 } 264 return nil 265 case promql.Scalar: 266 series := &prompb.TimeSeries{ 267 Samples: []prompb.Sample{{Value: value.V, Timestamp: value.T}}, 268 } 269 return srv.Send(querypb.NewQueryRangeResponse(series)) 270 } 271 272 return nil 273 }