github.com/go-graphite/carbonapi@v0.17.0/expr/functions/aggregate/function.go (about) 1 package aggregate 2 3 import ( 4 "context" 5 "fmt" 6 "strings" 7 8 "github.com/go-graphite/carbonapi/expr/consolidations" 9 fconfig "github.com/go-graphite/carbonapi/expr/functions/config" 10 "github.com/go-graphite/carbonapi/expr/helper" 11 "github.com/go-graphite/carbonapi/expr/interfaces" 12 "github.com/go-graphite/carbonapi/expr/types" 13 "github.com/go-graphite/carbonapi/pkg/parser" 14 ) 15 16 type aggregate struct{} 17 18 func GetOrder() interfaces.Order { 19 return interfaces.Any 20 } 21 22 func New(configFile string) []interfaces.FunctionMetadata { 23 f := &aggregate{} 24 res := make([]interfaces.FunctionMetadata, 0) 25 for _, n := range []string{"aggregate"} { 26 res = append(res, interfaces.FunctionMetadata{Name: n, F: f}) 27 } 28 29 // Also register aliases for each and every summarizer 30 for _, n := range consolidations.AvailableSummarizers { 31 res = append(res, 32 interfaces.FunctionMetadata{Name: n, F: f}, 33 interfaces.FunctionMetadata{Name: n + "Series", F: f}, 34 ) 35 } 36 return res 37 } 38 39 // aggregate(*seriesLists) 40 func (f *aggregate) Do(ctx context.Context, eval interfaces.Evaluator, e parser.Expr, from, until int64, values map[parser.MetricRequest][]*types.MetricData) ([]*types.MetricData, error) { 41 var args []*types.MetricData 42 var xFilesFactor float64 43 isAggregateFunc := true 44 45 callback, err := e.GetStringArg(1) 46 if err != nil { 47 if e.Target() == "aggregate" { 48 return nil, err 49 } else { 50 args, err = helper.GetSeriesArgsAndRemoveNonExisting(ctx, eval, e, from, until, values) 51 if err != nil { 52 return nil, err 53 } 54 if len(args) == 0 { 55 return []*types.MetricData{}, nil 56 } 57 callback = strings.Replace(e.Target(), "Series", "", 1) 58 isAggregateFunc = false 59 xFilesFactor = -1 // xFilesFactor is not used by the ...Series functions 60 } 61 } else { 62 args, err = helper.GetSeriesArg(ctx, eval, e.Arg(0), from, until, values) 63 if err != nil { 64 return nil, err 65 } 66 if len(args) == 0 { 67 return []*types.MetricData{}, nil 68 } 69 70 xFilesFactor, err = e.GetFloatArgDefault(2, float64(args[0].XFilesFactor)) // If set by setXFilesFactor, all series in a list will have the same value 71 if err != nil { 72 return nil, err 73 } 74 } 75 76 aggFunc, ok := consolidations.ConsolidationToFunc[callback] 77 if !ok { 78 return nil, fmt.Errorf("unsupported consolidation function %s", callback) 79 } 80 target := callback + "Series" 81 82 e.SetTarget(target) 83 if isAggregateFunc { 84 e.SetRawArgs(e.Arg(0).Target()) 85 } 86 87 results, err := helper.AggregateSeries(e, args, aggFunc, xFilesFactor, fconfig.Config.ExtractTagsFromArgs) 88 if err != nil { 89 return nil, err 90 } 91 92 for _, result := range results { 93 result.Tags["aggregatedBy"] = callback 94 } 95 96 return results, nil 97 } 98 99 // Description is auto-generated description, based on output of https://github.com/graphite-project/graphite-web 100 func (f *aggregate) Description() map[string]types.FunctionDescription { 101 // TODO(Civil): this should be reworked. Graphite do not provide consistent mappings for some of the consolidation 102 // functions. Also it's very easy to miss something obvious here. 103 return map[string]types.FunctionDescription{ 104 "aggregate": { 105 Name: "aggregate", 106 Function: "aggregate(seriesList, func, xFilesFactor=None)", 107 Description: "Aggregate series using the specified function.\n\nExample:\n\n.. code-block:: none\n\n &target=aggregate(host.cpu-[0-7}.cpu-{user,system}.value, \"sum\")\n\nThis would be the equivalent of\n\n.. code-block:: none\n\n &target=sumSeries(host.cpu-[0-7}.cpu-{user,system}.value)\n\nThis function can be used with aggregation functions ``average``, ``median``, ``sum``, ``min``,\n``max``, ``diff``, ``stddev``, ``count``, ``range``, ``multiply`` & ``last``.", 108 Module: "graphite.render.functions", 109 Group: "Combine", 110 Params: []types.FunctionParam{ 111 { 112 Name: "seriesList", 113 Type: types.SeriesList, 114 Required: true, 115 }, 116 { 117 Name: "func", 118 Type: types.AggFunc, 119 Required: true, 120 Options: types.StringsToSuggestionList(consolidations.AvailableConsolidationFuncs()), 121 }, 122 { 123 124 Name: "xFilesFactor", 125 Type: types.Float, 126 Required: false, 127 }, 128 }, 129 SeriesChange: true, // function aggregate metrics or change series items count 130 NameChange: true, // name changed 131 TagsChange: true, // name tag changed 132 ValuesChange: true, // values changed 133 }, 134 "averageSeries": { 135 Description: "Short Alias: avg()\n\nTakes one metric or a wildcard seriesList.\nDraws the average value of all metrics passed at each time.\n\nExample:\n\n.. code-block:: none\n\n &target=averageSeries(company.server.*.threads.busy)\n\nThis is an alias for :py:func:`aggregate <aggregate>` with aggregation ``average``.", 136 Function: "averageSeries(*seriesLists)", 137 Group: "Combine", 138 Module: "graphite.render.functions", 139 Name: "averageSeries", 140 Params: []types.FunctionParam{ 141 { 142 Multiple: true, 143 Name: "seriesLists", 144 Required: true, 145 Type: types.SeriesList, 146 }, 147 }, 148 SeriesChange: true, // function aggregate metrics or change series items count 149 NameChange: true, // name changed 150 TagsChange: true, // name tag changed 151 ValuesChange: true, // values changed 152 }, 153 "avg": { 154 Description: "Short Alias: avg()\n\nTakes one metric or a wildcard seriesList.\nDraws the average value of all metrics passed at each time.\n\nExample:\n\n.. code-block:: none\n\n &target=averageSeries(company.server.*.threads.busy)\n\nThis is an alias for :py:func:`aggregate <aggregate>` with aggregation ``average``.", 155 Function: "avg(*seriesLists)", 156 Group: "Combine", 157 Module: "graphite.render.functions", 158 Name: "avg", 159 Params: []types.FunctionParam{ 160 { 161 Multiple: true, 162 Name: "seriesLists", 163 Required: true, 164 Type: types.SeriesList, 165 }, 166 }, 167 SeriesChange: true, // function aggregate metrics or change series items count 168 NameChange: true, // name changed 169 TagsChange: true, // name tag changed 170 ValuesChange: true, // values changed 171 }, 172 "max": { 173 Description: "Takes one metric or a wildcard seriesList.\nFor each datapoint from each metric passed in, pick the maximum value and graph it.\n\nExample:\n\n.. code-block:: none\n\n &target=maxSeries(Server*.connections.total)\n\nThis is an alias for :py:func:`aggregate <aggregate>` with aggregation ``max``.", 174 Function: "maxSeries(*seriesLists)", 175 Group: "Combine", 176 Module: "graphite.render.functions", 177 Name: "maxSeries", 178 Params: []types.FunctionParam{ 179 { 180 Multiple: true, 181 Name: "seriesLists", 182 Required: true, 183 Type: types.SeriesList, 184 }, 185 }, 186 SeriesChange: true, // function aggregate metrics or change series items count 187 NameChange: true, // name changed 188 TagsChange: true, // name tag changed 189 ValuesChange: true, // values changed 190 }, 191 "maxSeries": { 192 Description: "Takes one metric or a wildcard seriesList.\nFor each datapoint from each metric passed in, pick the maximum value and graph it.\n\nExample:\n\n.. code-block:: none\n\n &target=maxSeries(Server*.connections.total)\n\nThis is an alias for :py:func:`aggregate <aggregate>` with aggregation ``max``.", 193 Function: "maxSeries(*seriesLists)", 194 Group: "Combine", 195 Module: "graphite.render.functions", 196 Name: "maxSeries", 197 Params: []types.FunctionParam{ 198 { 199 Multiple: true, 200 Name: "seriesLists", 201 Required: true, 202 Type: types.SeriesList, 203 }, 204 }, 205 SeriesChange: true, // function aggregate metrics or change series items count 206 NameChange: true, // name changed 207 TagsChange: true, // name tag changed 208 ValuesChange: true, // values changed 209 }, 210 "min": { 211 Description: "Takes one metric or a wildcard seriesList.\nFor each datapoint from each metric passed in, pick the minimum value and graph it.\n\nExample:\n\n.. code-block:: none\n\n &target=minSeries(Server*.connections.total)\n\nThis is an alias for :py:func:`aggregate <aggregate>` with aggregation ``min``.", 212 Function: "minSeries(*seriesLists)", 213 Group: "Combine", 214 Module: "graphite.render.functions", 215 Name: "minSeries", 216 Params: []types.FunctionParam{ 217 { 218 Multiple: true, 219 Name: "seriesLists", 220 Required: true, 221 Type: types.SeriesList, 222 }, 223 }, 224 SeriesChange: true, // function aggregate metrics or change series items count 225 NameChange: true, // name changed 226 TagsChange: true, // name tag changed 227 ValuesChange: true, // values changed 228 }, 229 "minSeries": { 230 Description: "Takes one metric or a wildcard seriesList.\nFor each datapoint from each metric passed in, pick the minimum value and graph it.\n\nExample:\n\n.. code-block:: none\n\n &target=minSeries(Server*.connections.total)\n\nThis is an alias for :py:func:`aggregate <aggregate>` with aggregation ``min``.", 231 Function: "minSeries(*seriesLists)", 232 Group: "Combine", 233 Module: "graphite.render.functions", 234 Name: "minSeries", 235 Params: []types.FunctionParam{ 236 { 237 Multiple: true, 238 Name: "seriesLists", 239 Required: true, 240 Type: types.SeriesList, 241 }, 242 }, 243 SeriesChange: true, // function aggregate metrics or change series items count 244 NameChange: true, // name changed 245 TagsChange: true, // name tag changed 246 ValuesChange: true, // values changed 247 }, 248 "sum": { 249 Description: "Short form: sum()\n\nThis will add metrics together and return the sum at each datapoint. (See\nintegral for a sum over time)\n\nExample:\n\n.. code-block:: none\n\n &target=sum(company.server.application*.requestsHandled)\n\nThis would show the sum of all requests handled per minute (provided\nrequestsHandled are collected once a minute). If metrics with different\nretention rates are combined, the coarsest metric is graphed, and the sum\nof the other metrics is averaged for the metrics with finer retention rates.\n\nThis is an alias for :py:func:`aggregate <aggregate>` with aggregation ``sum``.", 250 Function: "sum(*seriesLists)", 251 Group: "Combine", 252 Module: "graphite.render.functions", 253 Name: "sum", 254 Params: []types.FunctionParam{ 255 { 256 Multiple: true, 257 Name: "seriesLists", 258 Required: true, 259 Type: types.SeriesList, 260 }, 261 }, 262 SeriesChange: true, // function aggregate metrics or change series items count 263 NameChange: true, // name changed 264 TagsChange: true, // name tag changed 265 ValuesChange: true, // values changed 266 }, 267 "sumSeries": { 268 Description: "Short form: sum()\n\nThis will add metrics together and return the sum at each datapoint. (See\nintegral for a sum over time)\n\nExample:\n\n.. code-block:: none\n\n &target=sum(company.server.application*.requestsHandled)\n\nThis would show the sum of all requests handled per minute (provided\nrequestsHandled are collected once a minute). If metrics with different\nretention rates are combined, the coarsest metric is graphed, and the sum\nof the other metrics is averaged for the metrics with finer retention rates.\n\nThis is an alias for :py:func:`aggregate <aggregate>` with aggregation ``sum``.", 269 Function: "sumSeries(*seriesLists)", 270 Group: "Combine", 271 Module: "graphite.render.functions", 272 Name: "sumSeries", 273 Params: []types.FunctionParam{ 274 { 275 Multiple: true, 276 Name: "seriesLists", 277 Required: true, 278 Type: types.SeriesList, 279 }, 280 }, 281 SeriesChange: true, // function aggregate metrics or change series items count 282 NameChange: true, // name changed 283 TagsChange: true, // name tag changed 284 ValuesChange: true, // values changed 285 }, 286 "stddev": { 287 Description: "Short form: stddev()\n\nTakes one metric or a wildcard seriesList.\nDraws the standard deviation of all metrics passed at each time.\n\nExample:\n\n.. code-block:: none\n\n &target=stddevSeries(company.server.*.threads.busy)\n\nThis is an alias for :py:func:`aggregate <aggregate>` with aggregation ``stddev``.", 288 Function: "stddev(*seriesLists)", 289 Group: "Combine", 290 Module: "graphite.render.functions", 291 Name: "stddev", 292 Params: []types.FunctionParam{ 293 { 294 Multiple: true, 295 Name: "seriesLists", 296 Required: true, 297 Type: types.SeriesList, 298 }, 299 }, 300 SeriesChange: true, // function aggregate metrics or change series items count 301 NameChange: true, // name changed 302 TagsChange: true, // name tag changed 303 ValuesChange: true, // values changed 304 }, 305 "stddevSeries": { 306 Description: "Short form: stddev()\n\nTakes one metric or a wildcard seriesList.\nDraws the standard deviation of all metrics passed at each time.\n\nExample:\n\n.. code-block:: none\n\n &target=stddevSeries(company.server.*.threads.busy)\n\nThis is an alias for :py:func:`aggregate <aggregate>` with aggregation ``stddev``.", 307 Function: "stddevSeries(*seriesLists)", 308 Group: "Combine", 309 Module: "graphite.render.functions", 310 Name: "stddevSeries", 311 Params: []types.FunctionParam{ 312 { 313 Multiple: true, 314 Name: "seriesLists", 315 Required: true, 316 Type: types.SeriesList, 317 }, 318 }, 319 SeriesChange: true, // function aggregate metrics or change series items count 320 NameChange: true, // name changed 321 TagsChange: true, // name tag changed 322 ValuesChange: true, // values changed 323 }, 324 "count": { 325 Description: "Draws a horizontal line representing the number of nodes found in the seriesList.\n\n.. code-block:: none\n\n &target=count(carbon.agents.*.*)", 326 Function: "count(*seriesLists)", 327 Group: "Combine", 328 Module: "graphite.render.functions", 329 Name: "count", 330 Params: []types.FunctionParam{ 331 { 332 Multiple: true, 333 Name: "seriesLists", 334 Required: true, 335 Type: types.SeriesList, 336 }, 337 }, 338 SeriesChange: true, // function aggregate metrics or change series items count 339 NameChange: true, // name changed 340 TagsChange: true, // name tag changed 341 ValuesChange: true, // values changed 342 }, 343 "countSeries": { 344 Description: "Draws a horizontal line representing the number of nodes found in the seriesList.\n\n.. code-block:: none\n\n &target=countSeries(carbon.agents.*.*)", 345 Function: "countSeries(*seriesLists)", 346 Group: "Combine", 347 Module: "graphite.render.functions", 348 Name: "countSeries", 349 Params: []types.FunctionParam{ 350 { 351 Multiple: true, 352 Name: "seriesLists", 353 Required: true, 354 Type: types.SeriesList, 355 }, 356 }, 357 SeriesChange: true, // function aggregate metrics or change series items count 358 NameChange: true, // name changed 359 TagsChange: true, // name tag changed 360 ValuesChange: true, // values changed 361 }, 362 "diff": { 363 Description: "Subtracts series 2 through n from series 1.\n\nExample:\n\n.. code-block:: none\n\n &target=diff(service.connections.total,service.connections.failed)\n\nTo diff a series and a constant, one should use offset instead of (or in\naddition to) diffSeries\n\nExample:\n\n.. code-block:: none\n\n &target=offset(service.connections.total,-5)\n\n &target=offset(diffSeries(service.connections.total,service.connections.failed),-4)\n\nThis is an alias for :py:func:`aggregate <aggregate>` with aggregation ``diff``.", 364 Function: "diff(*seriesLists)", 365 Group: "Combine", 366 Module: "graphite.render.functions", 367 Name: "diff", 368 Params: []types.FunctionParam{ 369 { 370 Multiple: true, 371 Name: "seriesLists", 372 Required: true, 373 Type: types.SeriesList, 374 }, 375 }, 376 SeriesChange: true, // function aggregate metrics or change series items count 377 NameChange: true, // name changed 378 TagsChange: true, // name tag changed 379 ValuesChange: true, // values changed 380 }, 381 "diffSeries": { 382 Description: "Subtracts series 2 through n from series 1.\n\nExample:\n\n.. code-block:: none\n\n &target=diffSeries(service.connections.total,service.connections.failed)\n\nTo diff a series and a constant, one should use offset instead of (or in\naddition to) diffSeries\n\nExample:\n\n.. code-block:: none\n\n &target=offset(service.connections.total,-5)\n\n &target=offset(diffSeries(service.connections.total,service.connections.failed),-4)\n\nThis is an alias for :py:func:`aggregate <aggregate>` with aggregation ``diff``.", 383 Function: "diffSeries(*seriesLists)", 384 Group: "Combine", 385 Module: "graphite.render.functions", 386 Name: "diffSeries", 387 Params: []types.FunctionParam{ 388 { 389 Multiple: true, 390 Name: "seriesLists", 391 Required: true, 392 Type: types.SeriesList, 393 }, 394 }, 395 SeriesChange: true, // function aggregate metrics or change series items count 396 NameChange: true, // name changed 397 TagsChange: true, // name tag changed 398 ValuesChange: true, // values changed 399 }, 400 "multiply": { 401 Description: "Takes two or more series and multiplies their points. A constant may not be\nused. To multiply by a constant, use the scale() function.\n\nExample:\n\n.. code-block:: none\n\n &target=multiplySeries(Series.dividends,Series.divisors)\n\nThis is an alias for :py:func:`aggregate <aggregate>` with aggregation ``multiply``.", 402 Function: "multiply(*seriesLists)", 403 Group: "Combine", 404 Module: "graphite.render.functions", 405 Name: "multiply", 406 Params: []types.FunctionParam{ 407 { 408 Multiple: true, 409 Name: "seriesLists", 410 Required: true, 411 Type: types.SeriesList, 412 }, 413 }, 414 SeriesChange: true, // function aggregate metrics or change series items count 415 NameChange: true, // name changed 416 TagsChange: true, // name tag changed 417 ValuesChange: true, // values changed 418 }, 419 "multiplySeries": { 420 Description: "Takes two or more series and multiplies their points. A constant may not be\nused. To multiply by a constant, use the scale() function.\n\nExample:\n\n.. code-block:: none\n\n &target=multiplySeries(Series.dividends,Series.divisors)\n\nThis is an alias for :py:func:`aggregate <aggregate>` with aggregation ``multiply``.", 421 Function: "multiplySeries(*seriesLists)", 422 Group: "Combine", 423 Module: "graphite.render.functions", 424 Name: "multiplySeries", 425 Params: []types.FunctionParam{ 426 { 427 Multiple: true, 428 Name: "seriesLists", 429 Required: true, 430 Type: types.SeriesList, 431 }, 432 }, 433 SeriesChange: true, // function aggregate metrics or change series items count 434 NameChange: true, // name changed 435 TagsChange: true, // name tag changed 436 ValuesChange: true, // values changed 437 }, 438 } 439 }