Skip to content

Conversation

@rumblefrog
Copy link

@rumblefrog rumblefrog commented Apr 22, 2025

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
Copy link
Author

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

@cyberbit cyberbit self-requested a review April 22, 2025 13:07
@cyberbit
Copy link
Owner

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/

Copy link
Owner

@cyberbit cyberbit left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am interested in the use case for metric.time, otherwise lgtm!

interval = 30,
value = metric.value,
tags = tags,
time = metric.time or now,
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is metric.time this something that you are using on your end? This isn't a standard Metric attribute, though it is something I have considered as part of a larger normalization. I don't mind it being here, just curious.

@cyberbit
Copy link
Owner

cyberbit commented May 3, 2025

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
Copy link
Owner

cyberbit commented May 3, 2025

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants