I often define metrics and graphs for many perfomance values. With the old metric/graphing API (up to cmk 2.2) it was possible to loop over some list in the metric plugin, like so:
_perfdata = [
('id1', 'Title 1'),
('id2', 'Title 2'),
('id3', 'Title 3'),
# ...
]
for id, title in _perfdata:
metric_info[id] = {
'title': title,
'unit': 'count',
# ...
}
This was especially useful if we had a lot of very similar performance data and it also worked for graphs.
With the new API it is required to create a variable whose name starts with metric_ (who came up with such an idea?) and we have to use some Python tricks to achieve that in a loop. I tried this:
for id, title in _perfdata:
varname = 'metric_' + id
globals()[varname] = metrics.Metric(
name=id,
title=Title(title),
unit=UNIT_COUNTER,
# ...
)
and it worked, i.e. the metrics appear in the GUI.
Is that the right approach or does it work by accident?
I also tried to manipulate locals() instead of globals() in the same way. That worked as well but the Python documentation says that it depends on the implementation while for globals() it is guaranteed that manipulating the dict actually manipulates the variable name space. How does checkmk get aware of my metric definitions? Does it iterate globals() and pick everything that starts with metric_?
Second question: which ID matters? Is it the name of the variable or the attribute name of the metrics.Metric() when referring to a metric (for example in a graph definition)? Could I name the variables completely randomly, like metric_dsfsdkje, metric_qwe234 etc. and it would still work if only the name attribute of the metric was “proper”?
That is not possible any more. The converter script in $OMD_ROOT/share/doc/check_mk/treasures/migration_helpers/graphing_v0_v1.py will execute the loop and generate the variables once. After that it’s all static.
Yes it is. Indeed, the script graphing_v0_v1.py unrolled the (old) loop and defined 45 metrics for me where I previously had two nested loops 1…9 and 1…5.
But I didn’t like that and re-introduced the loops and manipulated the globals() dictionary as shown above. That does work. I just wanted to know whether I was simply lucky and/or unknowingly took advantage of some side effect or whether this is the correct approach.
Scanning variables instead of providing old-school functions such as register_graph(…) is what’s really bonkers about this API, in my opinion. The 2.3 API is no better than the pre-2.3 API in this regard; in both cases you modify a global variable. Pre-2.3 it was the metric_info dict, in 2.3 it’s the globals() dict. Same difference, really.
Agreed. I don’t know why they did that variable name thing. I would probably have done some “auto self registration” so that each Graph() or Metric() object could register itself from its init() function automatically. But it is as it is and probably there was a reason for the decision.
I did this recently. Manipulating globals() did do the trick to add the metrics, but it caused weird spammy messages in web.log. These disappeared after getting rid of the globals() hack.
In the end, naming individual variables did not involve more lines, but the lines were longer.
Thank you very much for sharing your code and your thoughts. Nice idea to create the Metrics in a function and then just define the variables explicitely without a loop.
I am not sure if it’s good news or bad news but I didn’t notice any logmessages in ~/var/log/web.log when I manipulated globals(). It just works flawlessly.
Perhaps one day the checkmk developers will shed some light on this .
I don’t get messages for all metrics added with globals(), but for some, and I have not precisely identified the triggering event. An apache restart resulted in some, but I’m not sure this always works.
On a practical level, I’m happy with my somewhat more verbose solution, but I would very much be curious where this comes from.