telem icon indicating copy to clipboard operation
telem copied to clipboard

feat: Graphite output adapter

Open rumblefrog opened this issue 8 months ago • 4 comments

Summary

Change adds Graphite as an output adapter.

Docs for the endpoint here: https://grafana.com/docs/grafana-cloud/send-data/metrics/metrics-graphite/http-api/#endpoints

Motivation

Grafana Cloud doesn't have InfluxDB as a hosted data source, therefore the Grafana output adapter cannot be used with the cloud instance, and I was too lazy to setup my own InfluxDB + Telegraf for a Minecraft survival world.

But Grafana Cloud does support OTLP (Open Telemetry) or Graphite as options for its HTTP metric data connection.

Tests

I minimally tested it locally on my Minecraft survival world, and the metrics are coming in.

Notes

  • Interval is hard-coded to 30 seconds, let me know if there's a way to get the cycle interval, but didn't look that much.

rumblefrog avatar Apr 22 '25 03:04 rumblefrog

@cyberbit Can't request reviewers, so tagging here for vis.

rumblefrog avatar Apr 22 '25 03:04 rumblefrog

I will take a look, thank you for contributing! 💙

At some point, Grafana Cloud changed the HTTP metrics page referenced in Telem docs, so the confusion is understandable. In #92 I started looking into it, and found that you can still use the format in the adapter, but you have to set up through Cloud Portal, not through your instance. I just have not had time to update the docs page yet.

See https://grafana.com/docs/grafana-cloud/send-data/metrics/metrics-influxdb/push-from-telegraf/

cyberbit avatar Apr 22 '25 13:04 cyberbit

Regarding the hard-coded 30 second interval, the only mechanism available to inspect the backplane from within an adapter is setAsyncCycleHandler, which passes the backplane to the function (see SecureModem for an implementation). The major caveat is the cycle rate isn't even stored on the backplane, which I realize only as I'm typing this! I have filed that as something to implement in the next minor release (#99).

As it stands, since interval is required by Graphite, we can either keep the hard-code for now, or add an attribute to the GraphiteOutput constructor and match it with cycle rate in user code. Once I put code together for storing the cycle rate, the adapter could be updated to utilize an async handler to bootstrap the interval in the adapter.

Let me know what you think!

cyberbit avatar May 03 '25 16:05 cyberbit

As of e73d6ab, Backplane now has a cycleInterval property that is populated after calling cycleEvery(). You can access this through an async cycle handler, as these are booted after the interval is set. An implementation might look like this:

function GraphiteOutputAdapter:constructor(endpoint, apiKey)
    self:super('constructor')

    self.endpoint = assert(endpoint, 'Endpoint is required')
    self.apiKey   = assert(apiKey,   'API key is required')

    self.interval = 30

    self:setAsyncCycleHandler(function (backplane)
        -- try to inherit from backplane, otherwise remain at default
        self.interval = backplane.cycleInterval or self.interval

        self:dlog('GraphiteOutputAdapter:asyncCycleHandler :: interval set to ' .. self.interval .. ' seconds')

        -- send coroutine to jail
        while true do
            coroutine.yield()
        end
    end)
end

Then you would reference self.interval in the write handler later.

cyberbit avatar May 03 '25 18:05 cyberbit