Smartscape on Grail is a Grail-based storage and analytics platform for topological data in Dynatrace. It records monitored entities (called nodes) and their relationships (called edges), enabling you to query, traverse, and analyze your environment with unprecedented flexibility and depth. The service entity is one of the key nodes in Smartscape on Grail: it bridges frontend, backend, and infrastructure, enabling end-to-end topology navigation.
This tutorial provides Dynatrace Query Language (DQL) examples for exploring service nodes, their call relationships, and their underlying infrastructure. We recommend running the DQL queries presented on this page in
Notebooks or
Dashboards. You can also visualize service topology and relationships directly in
Smartscape.
This guide is designed for developers, site reliability engineers, DevOps, and anyone interested in advanced service-centric observability and troubleshooting.
This page introduces the service entity in Smartscape on Grail, explains its relationships, and provides practical and advanced use case examples for analyzing services and their metrics in context.
As a user of Dynatrace Smartscape on Grail, you'll learn how to:
To follow the use cases and examples in this documentation, you need:
Basic familiarity with DQL is helpful but not required, as examples are provided throughout the documentation.
A service entity in Smartscape on Grail represents a logical service, such as a web service, API, or back-end component. Services are connected to each other through call relationships, such as calls or called_by. Services are linked to the infrastructure they run on (such as a process, container, host, or cloud compute node) or to the infrastructure they belong to (such as a Kubernetes cluster, namespace, or managed cloud cluster). This node-centric view enables you to analyze dependencies, performance, and health in a holistic way.
Understanding how a service interacts with other nodes is crucial for troubleshooting and optimization. Smartscape enables you to:
smartscapeNodes "SERVICE"| filter name == "frontend-web"
smartscapeNodes "SERVICE"| filter name == "frontend-web"| traverse {"calls"}, {"SERVICE"}, direction:"forward"
smartscapeEdges "*"| filter source_type == "SERVICE"| fields type, source_id, source_type, target_id, target_type, dt.system.edge_kind| summarize count = count(), by:{type}| sort count desc
The vertical topology shows how a service is deployed and what infrastructure supports it. You can use it to answer one of the following questions:
A service can have two types of vertical relationships:
runs_on: The service runs directly on a compute resource, such as a host, container, Kubernetes pod, or a cloud compute node (for example, an AWS Lambda function, AWS EC2 instance, Azure Functions app, Azure Container App, or a Google Cloud Run service).belongs_to: The service is grouped under a larger node, such as a Kubernetes cluster or namespace, or a managed cloud cluster (for example, Amazon EKS, Azure AKS, or Google GKE).Use the following DQL examples to explore vertical relationships in your environment.
Get an overview of all vertical edges originating from services, including the relationship type and target node.
smartscapeEdges "runs_on", "belongs_to"| filter source_type == "SERVICE"| fields type, source_id, target_id, target_type
Count runs_on relationships across all services, grouped by target node type.
smartscapeEdges runs_on| filter source_type == "SERVICE"| summarize count(), by:{target_type}
Count belongs_to relationships across all services, grouped by target node type.
smartscapeEdges belongs_to| filter source_type == "SERVICE"| summarize count(), by:{target_type}
Find all nodes a service runs on, along with the node type and name.
smartscapeNodes "*"| filter type == "SERVICE"| filter name == "frontend-web"| traverse "runs_on", "*", direction:"forward"| fields id, type, name
Find all nodes a service belongs to, along with the node type and name.
smartscapeNodes "*"| filter type == "SERVICE"| filter name == "frontend-web"| traverse "belongs_to", "*", direction:"forward"| fields id, type, name
Dynatrace automatically establishes runs_on and belongs_to relationships between services and their underlying cloud compute nodes across AWS, Azure, and Google Cloud, based on cloud resource attributes present in the service's span data.
For OpenTelemetry-instrumented services, ensure that the cloud.resource_id attribute or a cloud-specific equivalent (aws.arn, azure.resource.id, or gcp.resource.name) is set on the span emitted by the service.
Retrieve response time for a service from a service node.
smartscapeNodes "SERVICE"| filter name == "frontend-web"| join [timeseries responseTime_p95_timeseries = percentile(dt.service.request.response_time, 95), by:{dt.smartscape.service}, bins: 60], on: { left[id] == right[dt.smartscape.service]}
Retrieve deployment details, such as version, namespace, and cluster, for a service to correlate performance or incidents with recent changes.
smartscapeEdges "belongs_to"| filter source_type == "SERVICE"| fields type, source_id, source_type, target_id, target_type| fieldsAdd service_name = getNodeName(source_id)| filter contains(service_name, "astroshop-currency")| filter target_type == "K8S_DEPLOYMENT"| fieldsAdd result = lookup([smartscapeNodes "K8S_DEPLOYMENT"| fieldsAdd version = tags[`app.kubernetes.io/version`]| fields id, version, k8s.cluster.name, name],sourceField: target_id, lookupField:id )| fieldsAdd version = result[version]| fieldsAdd cluster = result[k8s.cluster.name]| fieldsAdd deployment_name = result[name]| fieldsRemove result, target_type, target_id, source_type, source_id, type
Analyze how issues in downstream services affect the performance of your service. Downstream services are the ones called by your service.
Show the 95th percentile of response times for the service:
timeseries responseTime_p95_timeseries = percentile(dt.service.request.response_time, 95), by:{dt.smartscape.service}, bins: 60, filter: dt.smartscape.service == "SERVICE-55A331C06F22D134"
Join with downstream service response times:
smartscapeEdges "calls"| filter source_type == "SERVICE"| filter source_id == toSmartscapeId("SERVICE-55A331C06F22D134")| fieldsAdd service_name = getNodeName(source_id)| join [timeseries responseTime_p95_timeseries = percentile(dt.service.request.response_time, 95), by:{dt.smartscape.service}, bins: 60], on: { left[target_id] == right[dt.smartscape.service]}
Use the traverse command for multi-hop analysis:
timeseries responseTime_p95_timeseries = percentile(dt.service.request.response_time, 95),filter:dt.smartscape.service in [smartscapeNodes "SERVICE"| filter name == "frontend-web"| traverse {"calls"}, {"SERVICE"}, direction:"forward"| fields id], by:{dt.smartscape.service}, nonempty: true| fieldsAdd metricName = "Response time p95"
Analyze how issues in upstream services affect the performance of your service. Upstream services are those that call your service.
smartscapeEdges "calls"| filter source_type == "SERVICE"| filter target_id == toSmartscapeId("SERVICE-55A331C06F22D134")| fieldsAdd service_name = getNodeName(source_id)| join [timeseries responseTime_p95_timeseries = percentile(dt.service.request.response_time, 95), by:{dt.smartscape.service}, bins: 60], on: { left[source_id] == right[dt.smartscape.service]}
Analyze request volumes between services to identify hotspots or unexpected spikes.
smartscapeEdges "calls"| filter source_type == "SERVICE"| filter source_id == toSmartscapeId("SERVICE-55A331C06F22D134")| fieldsAdd source_name = getNodeName(source_id)| fieldsAdd target_name = getNodeName(target_id)| join [timeseries request_counts_sum = sum(dt.service.request.count), by:{dt.smartscape.service}| summarize request_counts_avg = avg(arrayAvg(request_counts_sum)), by:dt.smartscape.service], on: { left[target_id] == right[dt.smartscape.service]}| sort right.request_counts_avg desc
You've completed this tutorial. You now know how to use Smartscape on Grail and DQL to explore service nodes and their relationships. You can:
As your environment evolves, continue experimenting with DQL queries and Smartscape features to unlock deeper insights from your data.