Skip to content

[ES|QL] PromQL pretty-printing support#247399

Merged
vadimkibana merged 5 commits intoelastic:mainfrom
vadimkibana:promql-printer-2
Jan 5, 2026
Merged

[ES|QL] PromQL pretty-printing support#247399
vadimkibana merged 5 commits intoelastic:mainfrom
vadimkibana:promql-printer-2

Conversation

@vadimkibana
Copy link
Contributor

@vadimkibana vadimkibana commented Dec 23, 2025

Summary

Partially addresses #243932

Adds ability to transforms a PromQL AST back to text: pretty-print. Supports basic pretty printing where the whole PromQL query is printed on a single line with minimal whitespace.

Checklist

@vadimkibana
Copy link
Contributor Author

/ci

@vadimkibana vadimkibana changed the title add promql pretty printing [ES|QL] PromQL pretty-printing support Dec 29, 2025
@vadimkibana vadimkibana marked this pull request as ready for review December 29, 2025 09:05
@vadimkibana vadimkibana requested a review from a team as a code owner December 29, 2025 09:05
@vadimkibana vadimkibana added the Team:ESQL ES|QL related features in Kibana t// label Dec 29, 2025
@elasticmachine
Copy link
Contributor

Pinging @elastic/kibana-esql (Team:ESQL)

@vadimkibana vadimkibana added review backport:skip This PR does not require backporting Feature:ES|QL ES|QL related features in Kibana v9.4.0 release_note:skip Skip the PR/issue when compiling release notes labels Dec 29, 2025
Copy link
Contributor

@sddonne sddonne left a comment

Choose a reason for hiding this comment

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

Nice!
Code looks correct, left some suggestions and some doubts, feel free to decide if they makes sense or not :)


return PromQLBuilder.expression.literal.string(ctx.getText(), '', this.getParserFields(ctx));
const text = ctx.getText();
return PromQLBuilder.expression.literal.string('', text, this.getParserFields(ctx));
Copy link
Contributor

Choose a reason for hiding this comment

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

What's the reason for the value unquoted to be empty string?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Because PromQLBuilder can construct the AST node from two patterns: (1) parsed from source text; (2) created programmatically without the source text. In the first case the second argument text is passed and the "unquoted" version is figured out by the builder. In the second case, the actual string (the unquoted version) is passed and the pretty-printer later figures out how to quote it, if at all.

});
});

describe('synthetic AST (Builder-constructed)', () => {
Copy link
Contributor

Choose a reason for hiding this comment

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

Aren't this set of tests more related to the builder inner workings than the pretty printer?
I understand the usage of the pretty printer here is just to check the builder created the correct query, anyway these ones seems different from the rest of the tests in the file so maybe could be good to move them into another one, with these large files it could become difficult to find the correct place to add a new test.
Could be /builder/builder.test.ts to match the ES|QL scaffolding or /pretty_print/__tests__/print_from_builder.test.ts if you prefer to keep them here.

How do you see it?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

My idea was to test also the pretty-printing of queries that are not parsed, but constructed programmatically using the PromqlBuilder. I've put them now into a separate test suite to separate the two AST construction patterns.

case 'unknown':
return '<unknown>';
default:
return '';
Copy link
Contributor

Choose a reason for hiding this comment

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

Just for my understanding, why is it better to ignore unsupported expression types and return '' rather than return the raw text?

Copy link
Contributor Author

@vadimkibana vadimkibana Jan 5, 2026

Choose a reason for hiding this comment

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

It is just one way of doing it. The default clause should not ever execute, so what we put there should not matter that much. Could also be the .text field, I don't have a strong opinion.

With printing the raw text there are few issues to be solved:

The raw source text is available only if we parsed the original query. If we constructed it using a builder programmatically, it would not have raw text version. Also, the way the pretty-printer is set up now, it receives only the AST node for printing, it does not receive the source text where to cut the nodes from, we would need to change the API of it to accept source text (and make it optional as programmatically constructed queries don't have the source text).

Some other issues with raw text: the .text field on AST nodes is stripped of hidden channel tokens (whitespace), so we cannot use that. But if we were to use the actual source text an cut out text from it we would have another whitespace issue: this "basic" pretty printer is setup to print everything on one line with a single space as separator, but the original source whitespace could have more than one space and more complex whitespace characters, line newline \n.

Copy link
Contributor

Choose a reason for hiding this comment

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

Clear, thank you for the explanation 🙏


protected formatOperator(op: string): string {
// Set operators (and, or, unless) might need case formatting
if (op === 'and' || op === 'or' || op === 'unless') {
Copy link
Contributor

@sddonne sddonne Dec 29, 2025

Choose a reason for hiding this comment

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

We have these defined here , maybe we can define them as

export const promQLOperators = ['and', 'or', 'unless'] as const;
export type PromQLSetOperator = (typeof promQLOperators)[number];

To re-use them here.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We could put them in an array, once we need them in an array.

One thing I don't understand, is why would we infer the type from a runtime variable? If (as you mentioned) the type PromQLSetOperator is already defined, we can just use the type:

export const promQLOperators: PromQLSetOperator[] = ['and', 'or', 'unless'];

Copy link
Contributor

Choose a reason for hiding this comment

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

It's a way of only listing them once,

export const promQLOperators = ['and', 'or', 'unless'] as const;
export type PromQLSetOperator = (typeof promQLOperators)[number];

vs

export type PromQLSetOperator = 'and' | 'or' | 'unless';
export const promQLOperators: PromQLSetOperator[] = ['and', 'or', 'unless'];

then you could do
if (promQLOperators.inlcudes(op) {... instead of
if (op === 'and' || op === 'or' || op === 'unless') {

@vadimkibana vadimkibana enabled auto-merge (squash) January 5, 2026 09:54
@vadimkibana vadimkibana merged commit 492c9f0 into elastic:main Jan 5, 2026
13 checks passed
@elasticmachine
Copy link
Contributor

💛 Build succeeded, but was flaky

Failed CI Steps

Test Failures

  • [job] [logs] FTR Configs #6 / Cloud Security Posture POST /internal/cloud_security_posture/graph Happy flows Enrich graph with entity metadata "before all" hook for "should contain entity data when asset inventory is enabled"
  • [job] [logs] FTR Configs #64 / Cloud Security Posture Security Network Page - Graph visualization ECS fields only expanded flyout - entity enrichment for multiple actors and targets

Metrics [docs]

✅ unchanged

History

CAWilson94 pushed a commit to CAWilson94/kibana that referenced this pull request Jan 6, 2026
## Summary

Partially addresses elastic#243932

Adds ability to transforms a PromQL AST back to text: pretty-print.
Supports basic pretty printing where the whole PromQL query is printed
on a single line with minimal whitespace.


### Checklist

- [x] [Unit or functional
tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)
were updated or added to match the most common scenarios
dej611 pushed a commit to dej611/kibana that referenced this pull request Jan 8, 2026
## Summary

Partially addresses elastic#243932

Adds ability to transforms a PromQL AST back to text: pretty-print.
Supports basic pretty printing where the whole PromQL query is printed
on a single line with minimal whitespace.


### Checklist

- [x] [Unit or functional
tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)
were updated or added to match the most common scenarios
devamanv pushed a commit to devamanv/kibana that referenced this pull request Jan 12, 2026
## Summary

Partially addresses elastic#243932

Adds ability to transforms a PromQL AST back to text: pretty-print.
Supports basic pretty printing where the whole PromQL query is printed
on a single line with minimal whitespace.


### Checklist

- [x] [Unit or functional
tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)
were updated or added to match the most common scenarios
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

backport:skip This PR does not require backporting Feature:ES|QL ES|QL related features in Kibana release_note:skip Skip the PR/issue when compiling release notes review Team:ESQL ES|QL related features in Kibana t// v9.4.0

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants