DEV Community

Cover image for Palantir Made Ontology Hot — Can APM Troubleshooting Stop at Ontology Alone?
AIdevops2088
AIdevops2088

Posted on

Palantir Made Ontology Hot — Can APM Troubleshooting Stop at Ontology Alone?

"Ontology" is back in fashion. Palantir Foundry is not pitched as yet another data warehouse — it builds an ontology for the enterprise: tables, streams, and sensors become "Customer," "Order," and "Device," with relationships and actions defined so data becomes a world model programs can reason over. LLMs made the pitch louder — models still need to know what exists in the world. Defense, finance, and manufacturing all talk about it.

For our field: what is the APM ontology? And if you build it, does incident triage just work? Two separate questions.

Q1How to build an APM ontology

An APM ontology is two steps: extract entities and relationships from traces, then materialize them into metric tables. Walk through a minimal example.

Setup: service A has instances A-1 and A-2; two endpoints; both call database DB and run the same SQL1. Four traces are reported:

- **#** — service · instance · endpoint · call · sql - **T1** — A · A-1 · ep1 · DB · SQL1 - **T2** — A · A-1 · ep2 · DB · SQL1 - **T3** — A · A-2 · ep1 · DB · SQL1 - **T4** — A · A-2 · ep2 · DB · SQL1

Step 1 — extract. From T1 alone: entities are service A, instance A-1, endpoint ep1, database DB, SQL1. Relationships: A has instance A-1; A exposes ep1; A-1 serves requests on ep1; ep1 calls DB; ep1 executes SQL1; DB has statement SQL1. P99, latency, and call count are not entities — they are observations attached to entities.

All four traces together:

  • Service hasInstance Instance: A → A-1, A-2
  • Service exposes Endpoint: A → ep1, ep2
  • Instance serves request on Endpoint: A-1 / A-2 both serve ep1 and ep2
  • Endpoint calls DB: ep1 → DB; ep2 → DB
  • Endpoint executes SQL: ep1 → SQL1; ep2 → SQL1
  • DB hasStatement SQL: DB → SQL1

Step 2 — materialize. Extracted entities become queryable metric tables. In DataBuff's Doris layer (schema is open source: github.com/databufflabs/databuff), dimension columns are entities; call_count / resp_time are observations:

- **Table** — Dimensions (entities) · Observations (not entities) · Entities covered - **metric_service** — service · call_count / resp_time / error_count · Service - **metric_service_instance** — service + instance · same · Service, Instance - **metric_service_http** — service + instance + endpoint · same · Service, Instance, Endpoint - **metric_service_db** — service + instance + db + sql · db calls / db latency · Service, Instance, DB, SQL

Aggregating the four traces:

  • metric_service: service A → 1 row, 4 entry calls (T1–T4)
  • metric_service_instance: by instance → 2 rows, A-1 and A-2 each 2 calls
  • metric_service_http: by instance + endpoint → 4 rows
  • metric_service_db: by instance + DB + SQL → 2 rows, A-1·DB·SQL1 and A-2·DB·SQL1 each 2 calls

Ontology done: traces tell you what exists and what connects to what; metric tables materialize those entities.

Q2Is ontology enough?

Entities and relationships complete — is troubleshooting solved? Consider how a connection pool actually behaves:

Connection pool: acquire, use/return, and background maintenance branches

Connection pool: acquire branches, use/return, and background maintenance — branches and state transitions an entity-relationship diagram cannot capture.

Even if you add ConnectionPool to the ontology as Service → ConnectionPool → Database, you only label the big boxes. The branches and states in between cannot be covered by adding one more entity — that layer is logic:

Connection pool: branches ER diagrams miss

  1. Acquire: idle available → return; can grow → create; pool full → lock wait; still waiting → timeout error
  2. Use / return: run SQL → return → wake waiters
  3. Background maintenance: heartbeat, evict stale or idle connections

Entity-only reasoning fails most often when an endpoint slows down:

- **** — Ontology only · With logic - **Reasoning** — endpoint → DB, slow endpoint ⇒ slow DB · stuck in lock wait, SQL never ran - **Symptom** — endpoint latency up · DB execution may be fine; timeouts often surface as errors - **Conclusion** — root cause is DB · root cause is waiting for a connection, not executing SQL

First principles: program = data + logic. In troubleshooting they split work:

- **** — Ontology (entities + relations) · Logic - **Manages** — what exists, who connects to whom · how requests flow, where they stall - **Locks onto** — target entities (ep1 / A-1 / DB) · last-mile root cause (wait for conn / execute SQL / timeout) - **Without it** — no drill-down target · stuck at "something is wrong", never the why

Entities and relationships are easy to abstract into topology and metric tables; connection-pool branches mostly live in senior engineers' heads and rarely get written down. If ontology alone made everyone an on-call expert, they would be everywhere — the gap is this logic layer.

Connection pool is one slice: it shows entity-only is not enough, but not how to model logic for a whole app. See how DataBuff breaks down latency for one endpoint, then scale to the full application.

Q3How to model logic

The "endpoint" from Q1 is one kind of entry. DataBuff's logic model for an endpoint does not stop at total response time — it splits latency by downstream operation: HTTP, RPC, DB, Redis, MQ, and the endpoint itself:

DataBuff endpoint response time and latency breakdown by HTTP, RPC, DB, Redis, MQ

DataBuff: endpoint response time (top) + latency breakdown (bottom). Total latency is no longer a black box — you see which operation types consume time.

From the chart: entry average ~240ms; breakdown shows HTTP service-b ~100ms, RPC service-b ~80ms, remainder in MySQL, ES, Redis, Kafka, etc. That is logic modeling for one entry — track entry latency and state, then track latency and state for each operation type after the entry.

Scale to a real app: containers exposing RPC / HTTP, depending on other apps plus DB, Redis, MQ. Full health on the logic side still comes down to two things:

  • Latency and state for every entry of the app
  • Latency and state for each operation type after every entry

Entries are not only HTTP. Common ones:

  • RPC service entry
  • HTTP service entry
  • MQ message consumer entry
  • Scheduled job entry
  • Other entry types

After a request enters, it typically lands in 5 operation types + 1 behavior (often with a datacenter dimension). The breakdown chart above is how those operations appear in telemetry; DB / SQL from Q1 is just the "DB remote operation" row:

- **Type** — Key attributes (dimensions) - **DB remote operation** — dal group / table / operation (select, update, insert…) / sql - **Redis remote operation** — command - **MQ remote operation (publish)** — exchange / routingKey / vhost - **RPC remote operation** — downstream service / remote method - **Local operation (non-remote)** — no extra attributes yet - **Thrown exception (behavior)** — exception name

Logic-side statistics: latency and state per entry, per operation type after each entry, plus exception counts — same shape as Q1's entity-to-metric tables, but dimensions shift from "who" to "how the request flows."

For remote operations, total latency is not enough — split into three parts:

Three parts of remote operation latency

  1. Client: connect, send request, receive response
  2. Network: transport between client and server
  3. Server: actual execution on the peer

With these three, you can tell where remote time goes. Q2's connection pool lives here: pool-full lock wait accrues on the client; SQL may never reach the server — so waiting for a connection ≠ slow SQL. You may not collect all three in production, but the model must exist; at minimum split entry latency from remote execution latency instead of one blended number.

Once the model stands, incidents follow one drill-down chain:

Coarse-to-fine incident conclusions

  1. Which entries are affected?
  2. Are local operations on affected entries abnormal?
  3. Which remote operations are abnormal — down to table, SQL, method?
  4. Client → server network or server side?
  5. Which exceptions did affected entries throw?

Both sides align: ontology answers "what entities exist and how they connect"; logic answers "which entry, which operations, which segment of remote latency." Together you find the object and the cause.

Ontology locks entities; logic locks root cause. Logic is not more entities — it models how requests flow as entry → operation → (remote) three-part latency → exception, with latency and state at each layer. For AI to separate "waiting for a connection" from "slow SQL," it must land on entities via ontology, then walk this logic chain to the actual reason.

Top comments (0)