Try it free

Transition your queries from classic topology to Smartscape on Grail

  • Latest Dynatrace
  • How-to guide
  • 8-min read

The classic entity store and Smartscape on Grail use different query primitives. In classic queries, you use fetch dt.entity.* to read entities and relationships. In Smartscape on Grail, you use smartscapeNodes, smartscapeEdges, and traverse.

This page shows you how to change your classic queries to Smartscape on Grail.

Prerequisites

Prior knowledge

  • Smartscape on Grail data model
  • Smartscape-specific commands and functions

For the full list of node types and fields, see Smartscape model in Semantic Dictionary.

To transition your queries with AI assistance, use the dt-migration skill from the Dynatrace for AI repository.

Key query differences

The following table shows how common classic query patterns map to Smartscape on Grail.

FeatureClassic entity storeSmartscape on Grail

Query all entities regardless of their type

Not supported

smartscapeNodes "*"

Query HOST entities

fetch dt.entity.host

smartscapeNodes HOST

Query all relationships regardless of type, source, or target

Not supported

smartscapeEdges "*"

References in Signal data

dt.entity.__type__

dt.smartscape.__type__

Enrich entity name

entityName(dt.entity.__type__)

getNodeName(dt.smartscape.__type__)

Enrich any other field (for example, tags)

entityAttr(dt.entity.__type__, "tags")

getNodeField(dt.smartscape.__type__, "tags")

Get a list of entity IDs based on entity selector

classicEntitySelector("type(HOST),toRelationships.runsOn(type(SERVICE),tag("owner:Joe"))")

Not supported

Get a list of entity IDs based on entity traversal

Not supported

smartscapeNodes SERVICE
| filter tags[owner] == "Joe"
| traverse runs_on, HOST
| fields id

Choose your approach

Your query's output determines the core approach. Use the following table to choose between the mass-data approach and the entity-list approach.

The signal and event and tag filter changes apply on top of the approach that you choose. You can use Common type mappings and Entity model differences sections for reference.

Query typeDescriptionApproach

Mass data filtered by entities

The output is metrics, logs, or spans. The entity condition only narrows the data.

Filter on direct dimensions first. See Filter mass data on dimensions first.

Mass data filtered by an entity subquery

The output is mass data. A fetch dt.entity.* subquery in in, lookup, or join filters the result.

Filter on direct dimensions first. See Filter mass data on dimensions first.

Entity list

The output is a list of entities. fetch dt.entity.* is the primary data source.

Use smartscapeNodes. See Transition entity-list queries.

Transition your queries

Apply the changes that match your query. Start with your chosen approach, then apply the signal, event, and tag changes as needed.

Filter mass data on dimensions first

When entities only filter mass data, don't change fetch dt.entity.* to smartscapeNodes directly. Use the first approach that applies, in this order.

  1. Direct dimension filter. Filter mass data on an enriched dimension. The direct dimension filter is the simplest and fastest approach, so we recommend prioritizing its use when you can. For example, when you filter by Kubernetes cluster name, the field k8s.cluster.name is usually already available as a dimension on the mass data. In this case, you don't need getNodeName(dt.smartscape.k8s_cluster), which joins Smartscape nodes and makes the query slower and more expensive.
  2. getNodeField filter. We recommend using getNodeField() or getNodeName() for the node name when the condition is on the same node type as the data dimension, but the attribute is not an enriched dimension.
  3. in [smartscapeNodes ...] subquery. We recommend using this subquery when the condition is on a different node type that isn't directly referenced by the mass data. You can reach such a node by traversing edges.
  • To find available dimensions for a data source, run fieldsSnapshot on that source.
  • To find available attributes on a node type, run fieldsSnapshot on smartscape.nodes. The field used as the node name is also documented in the Semantic Dictionary. For examples, see Kubernetes model.

Examples

The following example filters host CPU metrics by a host group and a source-set tag. The host group is an enriched dimension, so it uses a direct filter. The tag is available on the host node but not as an enriched dimension, so it uses getNodeField().

Filter on mass data with classic entities
timeseries series = avg(dt.host.cpu.usage),
filter:{
in(dt.host_group.id, array("my-host-group"))
and in(dt.entity.host, classicEntitySelector("type(host),tag(\"Stage:production\")"))
},
by:{ dt.entity.host }
Filter on mass data in Smartscape on Grail
timeseries series = avg(dt.host.cpu.usage),
filter:{
in(dt.host_group.id, array("my-host-group"))
and getNodeField(dt.smartscape.host, "tags")[Stage] == "production"
},
by:{ dt.smartscape.host }
  • Rule-based tags are not available on Smartscape nodes. For instructions on how to migrate a tag filter, see Transition tag filters.
  • Management zones control access. They have no attribute equivalent. You cannot migrate a managementZone() filter directly.

Transition entity-list queries

When the query lists entities, you can just change fetch dt.entity.X to smartscapeNodes X. Node types need to be uppercase and unquoted, for example smartscapeNodes HOST.

When transitioning queries to Smartscape on Grail, make sure to change the classic query commands, functions, and attributes to the Smartscape equivalents. Use the table below for reference.

Dynatrace ClassicSmartscape on GrailNotes

fetch dt.entity.X

smartscapeNodes X

Use the uppercase node type.

entity.name

name

Use the direct field when you query nodes.

entityName(id)

getNodeName(id)

Use getNodeName() when you only have an ID. The getNodeName() function takes no type: argument.

entityAttr(id, "field")

getNodeField(id, "field")

Prefer a direct node field when one exists.

classicEntitySelector(...)

Node filter plus traverse

Start from the constrained side, then traverse.

belongs_to[...], runs[...], instance_of[...]

traverse or references[...]

references works for static edges only.

Example: List hosts filtered by tags

The following example lists hosts filtered by a tag. To learn how tag filters change from Classic to Smartscape on Grail, see Transition tag filters.

List hosts filtered by tags in Classic
fetch dt.entity.host
| filter in(id, classicEntitySelector("type(host),tag([Environment]syn_grail_log:bastion)"))
| fields entity.name, id
List hosts filtered by tags in Smartscape on Grail
smartscapeNodes HOST
| filter `tags:environment`[syn_grail_log] == "bastion"
| fields entity.name = name, id

Example: Transition a relationship-based classicEntitySelector query to a traverse query

This example shows how to transition a relationship-based classicEntitySelector to a traverse query. The Smartscape on Grail query starts from the constrained host and traverses to the service, instead of fetching the service first.

Transition a relationship-based classicEntitySelector query to traverse in Classic
fetch dt.entity.service
| filter in(id, classicEntitySelector("type(service), fromRelationship.runsOnHost(type(host), tag([Azure]dt_owner_email:team-ops@example.com))"))
| fields id, entity.name
Transition a relationship-based classicEntitySelector query to traverse in Smartscape on Grail
smartscapeNodes HOST
| filter `tags:azure`[dt_owner_email] == "team-ops@example.com"
| traverse runs_on, SERVICE, direction:backward
| fields id, entity.name = name

Transition signal and event queries

When transitioning signal queries, make sure to change every classic entity dimension to its Smartscape dimension equivalent. Apply this change everywhere (for example, in by, filter, fieldsAdd, and expand).

  • dt.entity.host > dt.smartscape.host
  • dt.entity.service > dt.smartscape.service

You should also change the signal source field: dt.source_entity > dt.smartscape_source.id.

For the full list of classic entity dimensions and their Smartscape replacements, see Fields referencing classic entities.

Query a signal dimension query in Classic

timeseries avg(dt.service.request.response_time),
by:{ dt.entity.service }

Query a signal dimension query in Smartscape on Grail

timeseries avg(dt.service.request.response_time),
by:{ dt.smartscape.service }

Classic dt.entity.* fields use string data type in entity-ID format. Smartscape dimensions, such as dt.smartscape.host, use the smartscapeId type. To filter a Smartscape dimension against a specific ID, convert the string literal with toSmartscapeId(). For more information, see Classic entity IDs.

In Davis problem and event queries, the classic affected entity fields are deprecated. We recommend using the Smartscape entity fields instead. Each Smartscape entity field is a record, or a list of records, that contains the following node attributes: id, type, and name.

Classic field (deprecated)Smartscape on Grail fieldRemarks

affected_entity_ids, affected_entity_names, affected_entity_types

smartscape.affected_entities

An array of records containing id, type, and name.

related_entity_ids, related_entity_names

smartscape.related_entities

An array of records containing id, type, and name.

root_cause_entity_id, root_cause_entity_name

root_cause.smartscape_entity

A record containing id, type, and name.

entity_tags

primary_tags.*

Regular entity tags are no longer copied. Instead, primary tags are available as individual primary_tags.* fields.

The intermediate smartscape.affected_entity.ids and smartscape.affected_entity.types fields are also deprecated. We recommend using smartscape.affected_entities instead. For the full field reference, see Davis model in Semantic Dictionary.

Transition tag filters

Tags are stored differently in Classic and Smartscape on Grail models:

Classic entity storageSmartscape on Grail storage

Structure

One tags field: an array of strings

One field per context, tags:<context>: a record of key-value pairs

Tag format

"[CONTEXT]key:value"

`tags:context`[key] == "value"

Context name

Bracketed, for example [AWS]

Part of the field name, in lowercase, for example tags:aws

Classic contexts don't always map one-to-one to Smartscape contexts. For the Smartscape notation of cloud tags and Kubernetes labels and annotations, see Supported Smartscape tags.

Smartscape nodes store only tags set at the data source, such as cloud tags, Kubernetes labels and annotations, and OneAgent tags. Rule-based tags from auto-tagging rules are not stored. To migrate a filter on a rule-based tag, filter on the attribute or condition that the rule is based on.

If you filter on AWS, Azure, or GCP tags, OneAgent DT_TAGS, or Kubernetes labels and annotations, promote them to primary Grail tags with an ingest enrichment configuration. You can then filter directly on primary_tags.<key> instead of looking up tags:<context> on the node. See Best practices for cloud enrichment and Migrate to central configuration for Kubernetes telemetry enrichment.

Common type mappings

The following table lists the most common mappings. For the full list of node types, see Smartscape model in Semantic Dictionary.

Classic entity typeSmartscape signal dimensionSmartscape node type

dt.entity.host

dt.smartscape.host

HOST

dt.entity.service

dt.smartscape.service

SERVICE

dt.entity.process_group_instance

dt.smartscape.process

PROCESS

dt.entity.container_group_instance

dt.smartscape.container

CONTAINER

dt.entity.application

dt.smartscape.frontend

FRONTEND

dt.entity.cloud_application

Multiple workload fields

K8S_DEPLOYMENT, K8S_DAEMONSET, K8S_STATEFULSET, and other workload types

dt.entity.cloud_application_instance

dt.smartscape.k8s_pod

K8S_POD

dt.entity.cloud_application_namespace

dt.smartscape.k8s_namespace

K8S_NAMESPACE

dt.entity.kubernetes_cluster

dt.smartscape.k8s_cluster

K8S_CLUSTER

dt.entity.kubernetes_node

dt.smartscape.k8s_node

K8S_NODE

dt.entity.ec2_instance

dt.smartscape.aws_ec2_instance

AWS_EC2_INSTANCE

dt.entity.aws_lambda_function

dt.smartscape.aws_lambda_function

AWS_LAMBDA_FUNCTION

One classic type can map to more than one node type. For example, dt.entity.cloud_application becomes a set of Kubernetes workload types.

Entity model differences

There are a number of differences between classic topology and Smartscape model entity attributes, such as groups, services, or entity IDs. This section explains changes and differences per attribute. We recommend that you avoid changing attributes described in any of the subsections as one-to-one patterns.

Host group, process group, and container group

These classic group types are no longer standalone nodes in Smartscape on Grail. Instead, they are available as fields on the related node.

  • Host group: HOST query. The dt.host_group.id field holds the host-group name, which is the value of the classic entity.name. The classic host-group entity ID (HOST_GROUP-XXX) has no Smartscape equivalent, so we recommend mapping the classic entity.name to dt.host_group.id instead.
  • Process group: PROCESS query. We recommend using dt.process_group.id for the ID and dt.process_group.detected_name for the name. The dt.process_group.id is a string data type field that currently holds a classic entity ID value, such as PROCESS_GROUP-1234, even though no process-group node exists in Smartscape on Grail.
  • Container group: CONTAINER query. There is no standalone container-group node, so we recommend setting a null placeholder when the output requires a container-group field.

Query host groups in Classic

fetch dt.entity.host
| fields id, entity.name, hostGroupName

Query host groups in Smartscape on Grail

smartscapeNodes HOST
| fields id, entity.name = name, hostGroupName = `dt.host_group.id`

Kubernetes workloads

The classic dt.entity.cloud_application type grouped several Kubernetes workload concepts under one type. Smartscape on Grail models each workload type explicitly, so there is no single one-to-one replacement. We recommend querying the relevant workload types directly and using Kubernetes fields, such as k8s.cluster.name.

Query Kubernetes workloads in Classic

fetch dt.entity.cloud_application
| fields entity.name, kubernetesClusterName

Query Kubernetes workloads in Smartscape on Grail

smartscapeNodes K8S_DEPLOYMENT, K8S_DAEMONSET, K8S_STATEFULSET, K8S_REPLICASET, K8S_REPLICATIONCONTROLLER, K8S_JOB, K8S_DEPLOYMENTCONFIG
| fields entity.name = name, kubernetesClusterName = k8s.cluster.name

In Smartscape on Grail, a classic dt.entity.cloud_application_instance becomes K8S_POD, and a dt.entity.cloud_application_namespace becomes K8S_NAMESPACE.

Services

A SERVICE node comes from service detection and intentionally contains only the base fields, such as id, name, and dt.security_context. We recommend using service nodes to traverse the service flow and connect other topologies.

Because service detection rules are flexible, SERVICE nodes don't contain primary Grail fields, such as cloud or Kubernetes fields. To read those fields, you can query the service metrics with the metrics command. For more information, see DQL metric commands.

For example, to get the host groups for each service:

metrics
| filter metric.key == "dt.service.request.count" and isNotNull(dt.host_group.id) and dt.host_group.id != ""
| summarize by: id = dt.smartscape.service, dt.host_group.id = collectDistinct(dt.host_group.id)

For more about the service entity in Smartscape on Grail, see Explore the service entity in Smartscape on Grail.

Cloud entities

Monitoring for AWS, Azure, and GCP in Smartscape on Grail introduces significant changes compared to classic topology. Smartscape on Grail reports new cloud nodes with a richer model, new metrics, new entities, and new relationships. There is no one-to-one mapping to the classic cloud entities, and the new nodes have no id_classic field. To onboard and work with cloud resources, see the onboarding guides for Amazon Web Services, Microsoft Azure, and Google Cloud Platform.

Custom devices

Extensions and custom entity extraction in classic monitoring created CUSTOM_DEVICE entities. Each device had a subtype that contained a colon, for example f5lb:instance, f5:pool, or network:device.

Extensions and extraction rules in Smartscape on Grail create regular node types instead. Dynatrace-provided extensions can create types without the CUSTOM_ or EXT_ prefix, for example the classic dt.entity.f5:pool now becomes F5_LTM_POOL. All other extensions and extraction rules must prefix their types with CUSTOM_ or EXT_.

Dynatrace-provided extensions on Dynatrace Hub, such as F5, are migrated. These extensions still create classic entities, and they also create Smartscape nodes. For example, the classic f5lb:instance and network:device types become the EXT_NETWORK_DEVICE node, and f5lb:interface and network:interface become EXT_NETWORK_INTERFACE. The EXT_NETWORK_DEVICE type is also intended for third-party extensions to reuse. For more information, see Smartscape - Extensions - Networking.

In signal queries, the classic custom-device field is deprecated. We recommend using the matching Smartscape dimension instead (for example, dt.smartscape.f5_ltm_pool). Types created by third-party extensions use a dt.smartscape.custom_<type> or dt.smartscape.ext_<type> dimension.

For information about migrating an extension's topology, see Network topology.

Software technologies

In the classic topology, hosts, processes, and services exposed a softwareTechnologies field. Smartscape on Grail changes this for each entity type:

  • Host: we recommend using host.software_technologies, an array of records that each contain type, edition, and version.
  • Process: the technologies are split by the OneAgent module into separate fields, such as process.software_technologies.os, process.software_technologies.java, and process.software_technologies.nodejs. You can combine them with arrayConcat() to get the list with complete information. A PROCESS node has no technology-type field, so we recommend deriving the type from the detected technologies.
  • Service: a SERVICE node has no software technologies field. To get information about the service's software technologies, traverse to the processes that the service runs on, then read the process technologies.

The following example reads the technologies of a service from its processes.

smartscapeNodes SERVICE
| traverse runs_on, PROCESS, fieldsKeep:{name}
| summarize by:{id = dt.traverse.history[-1][id], name = dt.traverse.history[-1][name], type = "SERVICE"}, process.software_technologies = arrayDistinct(arrayFlatten(collectArray(process.software_technologies.os)))

For more query examples, see Smartscape core entities in the Semantic Dictionary.

Classic entity IDs

Smartscape on Grail uses its own IDs, which don't match classic entity IDs. Both classic and Smartscape IDs should be kept separately. You can do so by following the recommendations below:

  • Use the Smartscape id field. The id field and the dt.smartscape.* signal dimensions have the smartscapeId type instead of a string. To compare them with a specific ID, wrap the literal with toSmartscapeId().
  • Do not mix classic and Smartscape IDs. The two can look similar, but they're not interchangeable, so you should avoid comparing them to one another.

To help you compare results during migration, Smartscape nodes that have a classic counterpart (core entities, Kubernetes entities, and services) carry an id_classic field with the matching classic entity ID. The id_classic field is deprecated and is not generated for new entities, so you should treat it as a temporary migration aid and avoid using it in queries.

Hosts that represent containers

In the classic topology, a code module in a container can appear as a HOST entity. The operating system that the agent observes is the interior of a container, so the entity looks like a host.

In Smartscape on Grail, a code module that runs in a container doesn't create a HOST node. The container is represented as a CONTAINER node and related to Kubernetes nodes, such as K8S_POD.

As a result, the migrated query returns a result that differs from classic topology:

  • smartscapeNodes HOST returns fewer hosts than fetch dt.entity.host, because it excludes containers.
  • The classic fetch dt.entity.host query still returns these entities.

To find containerized workloads, query CONTAINER and the related Kubernetes node types instead of HOST.

Monitoring candidates

In the classic topology, a monitoring candidate is a host that communicates with monitored hosts but doesn't have OneAgent installed. Classic represented each monitoring candidate as a HOST entity.

Smartscape on Grail doesn't support the monitoring candidate concept. To discover and manage hosts without OneAgent, use Discovery & Coverage Discovery & Coverage.

Monitoring candidates are another reason smartscapeNodes HOST returns fewer hosts than fetch dt.entity.host, even in environments without containers.

Related topics

  • Smartscape on Grail
  • Explore the service entity in Smartscape on Grail
  • Smartscape
  • DQL Smartscape commands
Related tags
Dynatrace Platform