What are best practices for making Metrics that include "constant" values?


#1

Can folks please chime in with their thoughts on these options laid out below, as well as alternative options you have used or seen?

Let’s say I want to make a metric that tells me when a certain time series is above a threshold set-point.

SimpleMetric:

{
id: "SimpleMetricName_TypeName",
name: "SimpleMetricName",
srcType: "TypeA",
path: "a.b.c",
expression: "avg(avg(normalized.data.value))"
}

CompoundMetric:

{
id: "CompoundMetricName",
name: "CompoundMetricName",
expression: "SimpleMetricName > X"
}

There are multiple ways to produce X in a metric on the C3 Platform…

I could hardcode X in the CompoundMetric expression, if X is ALWAYS one value, but this is quite static:
expression: "SimpleMetricName > 7"

<<<<<<

I could create an enum type that defines X, if X is the same across the entire application, but I use it in multiple places and want to simplify future code revisions in the unlikely event that X does change.

enum type CustomerConfiguration {
  X = "7"
}

Then my CompoundMetric expression reads as follows:
expression: "SimpleMetricName > number(CustomerConfiguration.X)"
(where number() converts the string “7” to an integer.)

<<<<

I could define X on TypeA and create an identity() SimpleMetric around it. This is good if the value changes often between instances of TypeA:

type TypeA {
  fieldForX: int post default 7

SimpleMetric:

{
id: "IdentityMetric_TypeName",
name: "IdentityMetric",
srcType: "TypeA",
expression: "identity(fieldForX)"
}

then my CompoundMetric expression looks like this:
expression: "SimpleMetricName > IdentityMetric"

<<<<<

I could make a TimedValueHistory field on TypeA if X changes over time within the same TypeA object. (XValueHistory mixes a TimedValueHistory, and XValue mixes TimedValue)

type TypeA {
  @db(timedValueHistoryField = "fieldForXHistory")
  fieldForX: XValue
  @db(order="descending(timestamp)")
  fieldForXHistory: XValueHistory

Then make a tsDecl metric using PREVIOUS Treatment to identify the threshold at a given time:

{
id: "TsDeclMetric_TypeName",
name: "TsDeclMetric",
srcType: "TypeA",
tsDecl: {
  data: "fieldForXHistory",
  treatment: "PREVIOUS",
  start: "timestamp",
  value: "value"
}

then my CompoundMetric expression looks like this:
expression: "SimpleMetricName > TsDeclMetric"

<<<<<

I could also pass in X as a binding variable to the metric, if the value of X can’t really be tied to TypeA and comes from a far away place, maybe the result of some function/api call I am making in my application:
Then my CompoundMetric looks like this

{
    "id": "CompoundBindingMetric",
    "name": "CompoundBindingMetric",
    "variables": [
        {
            "name": "x",
            "dataType": "int"
        }
    ],
    "expression": "SimpleMetricName > x""
}

passed in the metric call through the bindings field on the EvalMetric(s)Spec Type.