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.
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.
The following table shows how common classic query patterns map to Smartscape on Grail.
| Feature | Classic entity store | Smartscape on Grail |
|---|---|---|
Query all entities regardless of their type | Not supported |
|
Query HOST entities |
|
|
Query all relationships regardless of type, source, or target | Not supported |
|
References in Signal data |
|
|
Enrich entity name |
|
|
Enrich any other field (for example, tags) |
|
|
Get a list of entity IDs based on entity selector |
| Not supported |
Get a list of entity IDs based on entity traversal | Not supported |
|
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 type | Description | Approach |
|---|---|---|
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 | Filter on direct dimensions first. See Filter mass data on dimensions first. |
Entity list | The output is a list of entities. | Use |
Apply the changes that match your query. Start with your chosen approach, then apply the signal, event, and tag changes as needed.
When entities only filter mass data, don't change fetch dt.entity.* to smartscapeNodes directly. Use the first approach that applies, in this order.
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.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.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.fieldsSnapshot on that source.fieldsSnapshot on smartscape.nodes. The field used as the node name is also documented in the Semantic Dictionary. For examples, see Kubernetes model.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().
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 }
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 }
managementZone() filter directly.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 Classic | Smartscape on Grail | Notes |
|---|---|---|
|
| Use the uppercase node type. |
|
| Use the direct field when you query nodes. |
|
| Use |
|
| Prefer a direct node field when one exists. |
| Node | Start from the constrained side, then traverse. |
|
|
|
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.
fetch dt.entity.host| filter in(id, classicEntitySelector("type(host),tag([Environment]syn_grail_log:bastion)"))| fields entity.name, id
smartscapeNodes HOST| filter `tags:environment`[syn_grail_log] == "bastion"| fields entity.name = name, id
classicEntitySelector query to a traverse queryThis 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.
classicEntitySelector query to traverse in Classicfetch 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
classicEntitySelector query to traverse in Smartscape on GrailsmartscapeNodes HOST| filter `tags:azure`[dt_owner_email] == "team-ops@example.com"| traverse runs_on, SERVICE, direction:backward| fields id, entity.name = name
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.hostdt.entity.service > dt.smartscape.serviceYou 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.
timeseries avg(dt.service.request.response_time),by:{ dt.entity.service }
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 field | Remarks |
|---|---|---|
|
| An array of records containing |
|
| An array of records containing |
|
| A record containing |
|
| Regular entity tags are no longer copied. Instead, primary tags are available as individual |
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.
Tags are stored differently in Classic and Smartscape on Grail models:
| Classic entity storage | Smartscape on Grail storage | |
|---|---|---|
Structure | One | One field per context, |
Tag format |
|
|
Context name | Bracketed, for example | Part of the field name, in lowercase, for example |
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.
The following table lists the most common mappings. For the full list of node types, see Smartscape model in Semantic Dictionary.
| Classic entity type | Smartscape signal dimension | Smartscape node type |
|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| Multiple workload fields |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
One classic type can map to more than one node type. For example, dt.entity.cloud_application becomes a set of Kubernetes workload types.
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.
These classic group types are no longer standalone nodes in Smartscape on Grail. Instead, they are available as fields on the related node.
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 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 query. There is no standalone container-group node, so we recommend setting a null placeholder when the output requires a container-group field.fetch dt.entity.host| fields id, entity.name, hostGroupName
smartscapeNodes HOST| fields id, entity.name = name, hostGroupName = `dt.host_group.id`
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.
fetch dt.entity.cloud_application| fields entity.name, kubernetesClusterName
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.
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.
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.
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.
In the classic topology, hosts, processes, and services exposed a softwareTechnologies field. Smartscape on Grail changes this for each entity type:
host.software_technologies, an array of records that each contain type, edition, and version.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 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.
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:
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().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.
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.fetch dt.entity.host query still returns these entities.To find containerized workloads, query CONTAINER and the related Kubernetes node types instead of HOST.
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.
Monitoring candidates are another reason smartscapeNodes HOST returns fewer hosts than fetch dt.entity.host, even in environments without containers.