simPod/GrafanaJsonDatasource

Query not called when variable changes

Closed this issue · 15 comments

image


anyways, I'm not really able to debug anything there. Can you setup another datasource (official one) and test whether it works for it?

https://fb412151502.grafana.net/goto/WVWpzqQ7k?orgId=1

test account
suochenhe_dev@163.com test111111

The previous account's 14-day trial period expired

umyio commented

@simPod I have the same issue as @suochenhe. Where is no call on my backend whenever variables are changed. Backend is only called on interval or manual refresh.

@suochenhe last link for me and reproduce the issue.

Any ideas?

So far I have nothing to debug. Can you test the behaviour is not the same with other datasources + setup testing dashboard (ideally provide as json dashboard definition) where I can reproduce the issue?

umyio commented

I do not have a publicly accessible GrafanaJsonDataSource-compatible REST endpoint at the moment.

In my dashboard different data sources (PostgreSQL i.e.) are queried on variable changes, but then the dependent variables are explicitly stated in the query.

Is the current supposed behavior that a GrafanaJsonDataSource-query is fired whenever any of the dashboard variables are changed? Or do I have to specify a dependence on a specific variable somehow? The only thing I see in the query editor is "Payload" which awaits a valid json.

I don't know grafana so well because I use it only for visualization.

How are dependent variables stated in your query? Is it different from stating it in jsonDS query payload?

umyio commented

Here's an example of the statement for a PostgreSQL data source:
SELECT ... FROM "Jobs" WHERE $__timeFilter("StartedAt") AND "EnvironmentKey" = ${Env:sqlstring} AND $SqlResults

That way the query knows that it needs to be fired whenever the dashboard time filter or the variables "Env" or "SqlResults" are changed.

I cannot state any explicit dependence on a variable in jsonDS like I can in PostgreSQL. You do provide all the variables configured in the dashboard in the query, but then the query is not fired when any of these variables are changed.

umyio commented

Using suochenhe's dashboard as an example:
image

Whenever the user selects a different value for the "name" variable in the drop box (i.e. var2 -> var7), the expectation is that either:
a) both tables are reloaded as they both use the jsonDS (and return the selected variable value in the query_name column)
or
b) one can state an explicit dependence on 1 or more variables in either table queries, so it only fires when any of the stated dependencies have changed

this is the server

from flask import Blueprint, request, jsonify, make_response, Flask


bp = Blueprint('grafana_test', __name__, url_prefix='/')
print(__name__)


class GrafanaTest:

    def __init__(self, blueprint=None):
        self.blueprint = blueprint

        if blueprint and isinstance(blueprint, Blueprint):
            self.register_blueprint(blueprint)

    def register_blueprint(self, bp: Blueprint):
        self.blueprint = bp
        # 使用simple json ,必须实现的接口
        bp.route('/', methods=['GET'])(self.grafana_index)  # 用来测试datasource
        bp.route('/search', methods=['POST'])(self.grafana_search)  # 查询筛选条件(下拉框)
        bp.route('/variable', methods=['POST'])(self.grafana_variable)  # 查询筛选条件(下拉框)
        bp.route('/query', methods=['POST'])(self.grafana_query)  # 查询数据
        bp.route('/annotations', methods=['POST'])(self.grafana_annotations)  # 某个时间点的注释(可以不用实现)

    def grafana_annotations(self):
        pass

    def grafana_index(self):
        response = make_response(self.blueprint.name)
        return response

    def grafana_search(self):
        return jsonify([f'metric{x}' for x in range(1, 21)])

    def grafana_variable(self):
        params = request.json
        payload = params['payload']

        target: str = payload['target']
        if target == 'name_query':
            return jsonify([{'__text': f'var{x}', 'value': f'var{x}'} for x in range(1, 21)])

        if target == 'name1_query':
            name = payload['name']
            if name:
                return jsonify([{'__text': f'{name}_var1_{x}', 'value': f'{name}_var1_{x}'} for x in range(1, 4)])
            return jsonify([{'__text': f'var1{x}', 'value': f'var1{x}'} for x in range(1, 11)])

    def grafana_query(self):
        params = request.json
        print(params)
        scopedVars: dict = params['scopedVars']
        filter = dict()
        for key, value_dict in scopedVars.items():
            filter[key] = value_dict['value']
        print(filter)

        name = filter.get('name')
        name1 = filter.get('name1')
        targets = params['targets']
        target = targets[0]['target']

        x = {
            "columns": [
                {"text": f"metric", "type": "string"},
                {"text": f"query_name", "type": "string"},
                {"text": f"query_name1", "type": "string"},
            ],
            "rows": [
                [target, name, name1],

            ],
            "type": "table"
        }
        return jsonify([x])


grafana = GrafanaTest(bp)


def create_app():
    app = Flask(__name__)
    app.register_blueprint(grafana.blueprint)

    return app


application = create_app()

if __name__ == '__main__':
    application.run()

In my dashboard different data sources (PostgreSQL i.e.) are queried on variable changes, but then the dependent variables are explicitly stated in the query.

This was a good point. I remember a while ago I debugged similar issue in grafana and the panel had no dependency on the variable.

I believe your panels are missing the dependency on the variable and therefore grafana does not re-query.

There's nothing that can be done in the datasource.

umyio commented

I can confirm that the query is called if one adds references to the dependent variables directly to the panel (i.e. in the description field). IMHO it is not optimal because other data sources work with explicit variable references, but it is still more than workable.

I have just stumbled upon the same issue.

I don't know whether other datasources do it and if so, how. If you have some examples, provide them.

The problem is that this datasource extra adds all variables to the request, even though they're not included in panel definition and therefore the panel is not explicitly dependent on it.

getVariables() {
const variables: { [id: string]: TextValuePair } = {};
Object.values(getTemplateSrv().getVariables()).forEach((variable) => {
if (!supportedVariableTypes.includes(variable.type)) {
console.warn(`Variable of type "${variable.type}" is not supported`);
return;
}
if (variable.type === 'adhoc') {
// These are being added to request.adhocFilters
return;
}
const supportedVariable = variable as MultiValueVariable;
let variableValue = supportedVariable.current.value;
if (variableValue === '$__all' || isEqual(variableValue, ['$__all'])) {
if (supportedVariable.allValue === null || supportedVariable.allValue === '') {
variableValue = supportedVariable.options.slice(1).map((textValuePair) => textValuePair.value);
} else {
variableValue = supportedVariable.allValue;
}
}
variables[supportedVariable.id] = {
text: supportedVariable.current.text,
value: variableValue,
};
});

It's a feature but it has not full support in Grafana since it reloads only those panels whose dependency changed.

image
I don't know why it's not working last time when variables are explicitly dependent
I try it again, The panel reloads . It's puzzling