feat: Graphite output adapter
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.
@cyberbit Can't request reviewers, so tagging here for vis.
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/
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!
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.