Skip to content

Fix filtering events by layer on the Elasticsearch storage - #14087

Merged
wu-sheng merged 1 commit into
apache:masterfrom
hope350:fix/es-event-layer-filter
Sep 17, 2026
Merged

wu-sheng merged 1 commit into
apache:masterfrom
hope350:fix/es-event-layer-filter

Conversation

@hope350

@hope350 hope350 commented Sep 17, 2026

Copy link
Copy Markdown
Contributor

Fix filtering events by layer on the Elasticsearch storage

  • Add a unit test to verify that the fix works.
  • Explain briefly why the bug exists and how to fix it.

Why the bug exists

An event's layer is written and read as a number, but the Elasticsearch query filters it with the layer
name:

  • written as a number — Event.Builder#entity2Storage:
    converter.accept(LAYER, layer != null ? layer.value() : Layer.UNDEFINED.value()), and Layer.GENERAL is 2;
  • read back as a number — Event.Builder#storage2Entity (Layer.valueOf(((Number) …).intValue())) and
    ESEventQueryDAO#parseSearchHit (Layer.valueOf(Integer.parseInt(…)));
  • but ESEventQueryDAO#buildMustQueryListByCondition sends the raw string:
    query.must(Query.term(Event.LAYER, condition.getLayer())).

EventQueryCondition#layer is a String (see event.graphqls), and a client always fills it with the
upper-snake layer name — Horizon UI's events feed does layer: body.layer.toUpperCase(). Elasticsearch is
therefore asked for {"term":{"layer":"GENERAL"}} against a numeric field and fails while building the
query
, so the whole request returns 400 number_format_exception: For input string: "GENERAL", on an empty
index just as well. In Horizon UI this makes the per-service events popout fail for every service.

How it is fixed

Convert the name to the value before building the term — which is what the other two storages already do:

  • JDBCEventQueryDAO#buildQuery: parameters.add(String.valueOf(Layer.nameOf(condition.getLayer()).value()));
  • BanyanDBEventQueryDAO#doQuery: group.eq(Event.LAYER, Layer.valueOf(condition.getLayer()).value());

This PR only aligns the Elasticsearch plugin with them:

query.must(Query.term(Event.LAYER, Layer.nameOf(condition.getLayer()).value()));

Layer.nameOf matches the JDBC storage, which maps an unknown name to UNDEFINED instead of throwing.
I am happy to use the stricter Layer.valueOf to match BanyanDB instead, if that is preferred — it is a
one-word change. (Layer is already imported in this file.)

How it was verified

  • The new ESEventQueryDAOTest builds the search body for layer = "GENERAL" and asserts it carries
    "layer":2 and no longer contains the layer name. Run against master (fix reverted) it fails and
    prints the offending body verbatim, which is the whole bug in one line:

    {"from":0,"size":10,"query":{"bool":{"must":[{"term":{"layer":"GENERAL"}}]}},"sort":[{"timestamp":{"order":"desc"}}],"aggregations":null,"_source":null}

    With the fix applied the same test passes (Tests run: 1, Failures: 0, Errors: 0).

  • maven-checkstyle-plugin:3.1.0:check runs on this module as usual (includeTestSourceDirectory=true,
    so the new test is covered too) — BUILD SUCCESS.

  • Against a live Elasticsearch storage, an event query carrying a layer name returns 400
    number_format_exception: For input string: "GENERAL", while the same query with the layer value
    returns the events of that layer. That 400 is what Horizon UI receives from its events popout.

@wu-sheng wu-sheng added bug Something isn't working and you are sure it's a bug! backend OAP backend related. labels Sep 17, 2026
@wu-sheng wu-sheng added this to the 11.1.0 milestone Sep 17, 2026
@wu-sheng
wu-sheng merged commit 029571c into apache:master Sep 17, 2026
467 of 471 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

backend OAP backend related. bug Something isn't working and you are sure it's a bug!

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug] Querying events with a layer filter always fails on Elasticsearch storage: number_format_exception For input string: "GENERAL"

2 participants