Skip to content
This repository has been archived by the owner on Jan 21, 2022. It is now read-only.

Create a Plan

PlamenDoychev edited this page Dec 5, 2018 · 26 revisions

Measures and metrics are grouped into a single entity called a plan. Plans provide Resource providers with a way to express the relationship between the measures and metrics. For example, if one needs two measures in order to be able to calculate the value of a metric, it is possible to group the two measures and the metric into a metering plan.

Based on what the plan is responsible for, there are three plan categories: metering, rating, and pricing.

Metering Plan

The metering plan defines the metering part of the calculations that Abacus will execute. meter, accumulate, and aggregate functions can be used with a metering plan. For example, consider the object storage metering plan.

Rating Plan

The rating plan defines the rating calculations. The charge and rate functions can be used with a metering plan. For example, see object storage rating plan.

Pricing Plan

The pricing plan defines the pricing on per-measure basis. For example, check the object storage pricing plan.

Sample Plans

There are a few predefined plans available in Abacus. You can find the examples with the metrics contained for each plan below:

Note: The basic analytics metrics use deprecated formulas and you can use them as a reference on how to migrate from the formulas to the new functions format.

Default Plan Functions

By default Abacus defines default functions. You can choose to override them by defining your own function with the same name or to work with the default one.

Metering

const meter = (metricName) => (measures) => measures[metricName];
const accumulate = (a, qty, start, end, from, to, twCell) =>
  end < from || end >= to ? null : new BigNumber(a || 0).add(qty || 0).toNumber();
const aggregate = (a, prev, curr, aggTwCell, accTwCell) =>
  new BigNumber(a || 0)
    .add(curr)
    .sub(prev || 0)
    .toNumber();
const summarize = (t, qty) => qty ? qty : 0;

By default the meter function uses measure with the same name. The accumulate and aggregate functions do simple sum. summarize returns the sum.

Rating

const rate = (p, qty) => new BigNumber(p || 0).mul(qty).toNumber();
const charge = (t, cost) => cost ? cost : 0;

Plan Snippets

Max Value

Calculates Max value of agent_count measure.

{
  "plan_id": "max_value",
  "measures": [
    {
      "name": "agent_count",
      "unit": "number"
    }
  ],
  "metrics": [
    {
      "name": "users",
      "unit": "users",
      "type": "discrete",
      "meter": "(m) => new BigNumber(m.agent_count || 0).toNumber()",
      "accumulate": "((a, qty, start, end, from, to, twCell) => end < from || end >= to ? null : Math.max(a, qty))"
    }
  ]
}

Average sum

Abacus does not support average out of the box, but this is easily implemented by keeping the sum and the count of elements in compound object. This also increases the accuracy of the result.

{
  "plan_id": "average_value",
  "measures": [
    {
      "name": "store",
      "unit": "BYTE"
    }
  ],
  "metrics": [
    {
      "name": "store",
      "unit": "GIGABYTE",
      "type": "discrete",
      "meter": "(m) => new BigNumber(m.store || 0).div(1073741824).toNumber()",
      "accumulate": "(a, current) => a ? { sum: a.sum + current, count: a.count + 1 } : { sum: current, count: 1 }",
      "aggregate": "(a, previous, current) => current",
      "summarize": "(t, qty) => qty ? new BigNumber(qty.sum).div(qty.count).toNumber() : 0"
    }
  ]
}

🚨 Note that this plan bypasses the aggregation. If the resource is used by applications in different spaces, we'll not take this into account. Usually this is the case for DB or storage solutions.

Multiple measures and metrics

Multiple measures in one metric

Here we are summing several kinds of transactions (charges, refunds, others) into individual metrics. Then we have a global sum transactions that count the number of all operations. We want to keep a breakdown of the individual components, plus the total count of operations.

{
  plan_id: 'transactions-plan',
  measures: [
    {
      name: 'charges',
      unit: 'NUMBER'
    },
    {
      name: 'refunds',
      unit: 'NUMBER'
    },
    {
      name: 'others',
      unit: 'NUMBER'
    }
  ],
  metrics: [{
    name: 'transactions',
    unit: 'NUMBER',
    type: 'discrete',
    meter: (m) => ({
      charges: new BigNumber(m.charges || 0).toNumber(),
      refunds: new BigNumber(m.refunds || 0).toNumber(),
      others: new BigNumber(m.others || 0).toNumber()
    }),
    accumulate: (a, c) => {
      const charges = a ? new BigNumber(a.charges).add(c.charges) : c.charges
      const refunds = a ? new BigNumber(a.refunds).add(c.refunds) : c.refunds;
      const others = a ? new BigNumber(a.others).add(c.others) : c.others;
      
      const transactions = a ?
        a.transactions.add(charges).add(refunds).add(others) :
        new BigNumber(0).add(charges).add(refunds).add(others);

      return {
        charges: charges.toNumber(),
        refunds: refunds.toNumber(),
        others: others.toNumber(),
        transactions: transactions.toNumber()
      };
    }
  }]
}

Multiple metrics using one measure

{
  "plan_id": "average_and_sum",
  "measures": [
    {
      "name": "storage",
      "unit": "GIGABYTE"
    }
  ],
  "metrics": [
    {
       "meter" : "(m) => new BigNumber(m.storage || 0).toNumber()",
       "accumulate" : "(a, current) => a ? { sum: a.sum + current, count: a.count + 1 } : { sum: current, count: 1 }",
       "aggregate" : "(a, previous, current) => current",
       "summarize" : "(t, qty) => qty ? new BigNumber(qty.sum).div(qty.count).toNumber() : 0",
       "type" : "discrete",
       "name" : "average",
       "unit" : "GIGABYTE"
    },
    {
       "meter" : "(m) => new BigNumber(m.storage || 0).toNumber()",
       "type" : "discrete",
       "name" : "sum",
       "unit" : "GIGABYTE"
    }
  ]
}
<< Create a Resource Provider Upload Plan >>

Related Links:

Clone this wiki locally