Skip to content

LogQL Plugins

akvlad edited this page Oct 14, 2021 · 11 revisions

cLoki Plugins

  • WORK IN PROGRESS!

Missing a LogQL function in cLoki? Extend functionality in in no time using cLoki Plugins

Custom Unwrapped Range Aggregation

For example you need to add a unwrapped range aggregator derivative:

derivative=(last_unwrapped_value_in_range - first_unwrapped_value_in_range) / (last_time_in_range - first_time_in_range)

You need to add a js module into /plugins/unwrap_registry directory with the next API:

/**
 * @returns {{run: (function(*, number, number): *), approx: (function(*): number)}}
 */
module.exports.derivative = () => {}

So module.exports.<range aggregator name> is a function returning an object with two methods: run and approx.

The run method is called every time new unwrapped value accepted by the stream processor. Its declaration is:

        /**
         *
         * @param sum {any} previous value for the current time bucket
         * @param val {{unwrapped: number}} current values
         * @param time {number} timestamp in ms for the current value
         * @returns {any}
         */
        const run = (sum, val, time) => {
            sum = sum || {};
            sum.first = sum && sum.first && time > sum.first.time ? sum.first : {time: time, val: val.unwrapped};
            sum.last = sum && sum.last && time < sum.last ? sum.last : {time: time, val: val.unwrapped};
            return sum;
        }

So the run function accepts the previous aggregated value. The initial value is 0. The second is an object with current unwrapped value. And the time when the unwrapped value appeared in the database. The run function should return the new sum. Data immutability is preferred but optional.

The approx method is called for each bucket at the end of processing. Its declaration is:

        /**
         * @param sum {any} sum of the time bucket you have created during "run"
         * @returns {number}
         */
        const approx = (sum) => {
            return sum && sum.last && sum.first && sum.last.time > sum.first.time ?
                (sum.last.val - sum.first.val) / (sum.last.time - sum.first.time) * 1000 : 0;
        }

The only argument is the result of the latest run call for the bucket. The function should return number as result of the operator calculation for the provided time bucket.

Example

The full code of the derivative function:

/**
 * @returns {{run: (function(*, number, number): *), approx: (function(*): number)}}
 */
module.exports.derivative = () => {
    return {
        /**
         *
         * @param sum {any} previous value for the current time bucket
         * @param val {{unwrapped: number}} current values
         * @param time {number} timestamp in ms for the current value
         * @returns {any}
         */
        run: (sum, val, time) => {
            sum = sum || {};
            sum.first = sum && sum.first && time > sum.first.time ? sum.first : {time: time, val: val.unwrapped};
            sum.last = sum && sum.last && time < sum.last ? sum.last : {time: time, val: val.unwrapped};
            return sum;
        },
        /**
         * @param sum {any} sum of the time bucket you have created during "run"
         * @returns {number}
         */
        approx: (sum) => {
            return sum && sum.last && sum.first && sum.last.time > sum.first.time ?
                (sum.last.val - sum.first.val) / (sum.last.time - sum.first.time) * 1000 : 0;
        }
    }

}
Clone this wiki locally