Skip to content

fix(render): make graph functions work in non-cairo builds - #944

Merged
npazosmendez merged 5 commits into
mainfrom
njpm/nocairo-graph-functions
Aug 12, 2026
Merged

npazosmendez merged 5 commits into
mainfrom
njpm/nocairo-graph-functions

Conversation

@npazosmendez

@npazosmendez npazosmendez commented Aug 5, 2026 •

Copy link
Copy Markdown
Collaborator

Most Graphite Web's graph functions (color(), threshold() etc) "work" with non-image formats (e.g. format=json) by being mostly no-op (depends on the function). For example, with color(randomWalk('a'), 'red'):

$ docker run -d --name gw -p 8080:80 graphiteapp/graphite-statsd >/dev/null && until curl -sf -o /dev/null "http://localhost:8080/render?target=x&format=json"; do sleep 2; done && curl -sG http://localhost:8080/render --data-urlencode "target=color(randomWalk('a'), 'red')" -d format=json -d from=-5min; echo; docker rm -f gw >/dev/null

[{"target": "a", "tags": {"name": "a"}, "datapoints": [[0, 1785953431], [0.24124975089820433, 1785953491], [-0.03474284243293879, 1785953551], [-0.47080131891509025, 1785953611], [-0.3820169792063769, 1785953671]]}]

This behavior is useful for two reasons: 1) some functions make sense even without image rendering (e.g. threshold), 2) queries don't completely break when switching formats

Carbonapi follows that behavior, but only when built with cairo. When built without cairo, they return no data (or an error in some cases).

This PR changes that, and allows such functions to run correctly in no-cairo builds if possible. Only the image generation bit (which depends on the format= requested) remains under the cairo build tag. If built without cairo, an error is returned, but only when an image is requested explicitly.

Behavior changes:

  • Non-cairo builds: color, stacked, areaBetween, alpha, dashed, drawAsInfinite, secondYAxis, lineWidth, threshold, verticalLine and holtWintersConfidenceArea now evaluate normally and appear in /functions.
  • Non-cairo builds: format=png/svg returns 501 instead of a 200 with an empty body. Notably, since png is the default format, requests without format also get 501 now.

Other changes:

  • CI now runs the existing test_nocairo
  • Perf: because the GraphOptions struct does not depend on the build tag, MetricData type size grows in no-cairo builds from 192 bytes to 272 bytes. I think this is acceptable and will probably be negligible compared to the memory that comes from tags and sample values. Still I wanted to state it explicitly

@npazosmendez npazosmendez changed the title Make graph functions work in non-cairo builds fix(render): make graph functions work in non-cairo builds Aug 5, 2026
Graph-only functions (color, stacked, threshold, verticalLine,
holtWintersConfidenceArea, ...) were either silently returning no series
or erroring in non-cairo builds, because their evaluation was gated
behind the cairo build tag. The gating was only needed because
types.GraphOptions was an empty struct without cairo.

Make GraphOptions build-independent and unify the implementations:
evaluation now behaves identically in both builds, with graph options
simply ignored by data formats. Only PNG/SVG rendering remains behind
the cairo tag.
Image formats previously returned an empty 200 body in binaries built
without cairo (the Marshal stubs return nil). Fail fast with an
explicit 501 and a clear message before any backend fetch.
Also point at the data formats in the error message, since png is the
default format when none is specified.
The non-cairo variant now carries real behavior (graph function
evaluation, the 501 render path) but was never built or tested in CI.
The Makefile target already existed. A separate job keeps the e2e suite
running against the cairo binary.
@npazosmendez
npazosmendez force-pushed the njpm/nocairo-graph-functions branch from 31e5e29 to 6a71bc1 Compare August 10, 2026 18:39
@npazosmendez
npazosmendez marked this pull request as ready for review August 10, 2026 19:04
Comment thread expr/functions/cairo/png/png.go Outdated
@npazosmendez
npazosmendez merged commit 6389a76 into main Aug 12, 2026
10 of 11 checks passed
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