telegraf icon indicating copy to clipboard operation
telegraf copied to clipboard

persist starlark state for more starlark types

Open gazpachoking opened this issue 1 year ago • 3 comments

Use Case

#15170 added the ability for the starlark processor to persist the global state to the statefile between runs. This is very nice, but it can't store lists, dicts, tuples, or metrics to the state file which severely limits its usefulness. If you try any more complex type you get an error like invalid starlark type *starlark.Metric when it tries to write the state file.

My desired use case is similar to the example for comparing a metric to the previous one. This doesn't work because it stores both a dict and a metric in the global state.

Expected behavior

Starlark standard types (lists, dicts, tuples, and maybe also metrics) can be persisted to the statefile.

Actual behavior

Error when persisting the plugin states.

Additional info

No response

gazpachoking avatar Sep 22 '24 02:09 gazpachoking

Next steps: implement a function to convert starlark values to go-values and vice versa.

srebhan avatar Oct 08 '24 12:10 srebhan

Hi, the statefile saves json, and you can in fact save lists, dicts, strings, numbers, booleans and Nonetype (None, null). (I will call this "simple-type")

To allow for storing arbitrary types could be a problem, because not every object can be stored (Resource handles of any kind (open files, handles for secrets, etc) come to mind).

I would recommend to implement "simple-type"-serializers and deserializers (marshallers and unmarshallers) for every type (or Metric at least) which should be storable.

So have something like Metric.serialize() -> dict # {"name": ..., "tags": { ... }, "fields": { ... }, "time": ...} and Metric.__init__(marsh: dict) -> Metric

Also: state could have an interface which denies everything which isn't a "simple-type", so it would error out before it tries to write it to the statefile.

knollet avatar Oct 09 '24 12:10 knollet

The metric should be serialized as gob and encoded as base64 to be able to distinct integer/float types which is not possible with pure JSON.

srebhan avatar Oct 10 '24 10:10 srebhan

@srebhan, are there any updates on this matter? I also am storing a dictionary of "metrics" in the state of some processors and aggregators.

Upon activating the statefile option my starlark script throws the following error: state item (-2008395481, Metric("Test Modbus", tags={"bucket": "Energy", "internal_connection": "TestPLC", "internal_deadband": "10.0", "internal_replication": "30s", "internal_timeout": "30s"}, fields={"I1": 800.0}, time=1750796883000000000)) has invalid key type starlark.Int

What can I do to make the metric type stringifyable or do I have to do this writing my own function each time I am storing/deepcopying a metric?

JeroenVanHoye avatar Jun 24 '25 20:06 JeroenVanHoye

Just gonna leave this example here in case someone wants to store metrics in the state and recreate them after.

def metricToDict(metric):
  return {"name": metric.name, "tags": metric.tags, "fields": metric.fields, "time": metric.time}

def dictToMetric(dictMetric):
  new_metric = Metric(dictMetric["name"])
  new_metric.tags.update(dictMetric["tags"])
  new_metric.fields.update(dictMetric["fields"])
  new_metric.time = dictMetric["time"]
  return new_metric

JeroenVanHoye avatar Aug 02 '25 12:08 JeroenVanHoye