Dynatrace can ingest custom metrics via its Metrics API, but the real magic is how it automatically correlates these metrics with existing topology and topology-agnostic data.

Let’s see it in action. Imagine you have a Python application generating a custom metric for request_latency_seconds.

import requests
import time
import json

# Replace with your actual Dynatrace environment ID and API token
TENANT_ID = "YOUR_TENANT_ID"
API_TOKEN = "YOUR_API_TOKEN"
TENANT_URL = f"https://{TENANT_ID}.live.dynatrace.com/api/v2/metrics/ingest"

def send_custom_metric(metric_name, value, timestamp, dimensions=None):
    payload = {
        "metricId": metric_name,
        "value": value,
        "timestamp": timestamp,
        "dimensions": dimensions if dimensions else {}
    }
    headers = {
        "Authorization": f"Api-Token {API_TOKEN}",
        "Content-Type": "application/json"
    }

    try:
        response = requests.post(TENANT_URL, headers=headers, data=json.dumps(payload))
        response.raise_for_status() # Raise an exception for bad status codes
        print(f"Successfully sent metric: {metric_name} = {value}")
    except requests.exceptions.RequestException as e:
        print(f"Error sending metric {metric_name}: {e}")

if __name__ == "__main__":
    start_time = time.time()
    # Simulate some work
    time.sleep(0.1)
    end_time = time.time()
    latency = end_time - start_time

    metric_name = "custom.myapp.request_latency_seconds"
    current_timestamp = int(time.time() * 1000) # Dynatrace expects milliseconds
    dimensions = {
        "service": "user-api",
        "endpoint": "/users",
        "http_method": "GET"
    }

    send_custom_metric(metric_name, latency, current_timestamp, dimensions)

When you run this code, you’re not just sending a number to a time-series database. Dynatrace uses the metricId and the provided dimensions to understand the context of this custom.myapp.request_latency_seconds metric. It knows this latency is associated with a service called user-api, an endpoint of /users, and an http_method of GET. If your application is already monitored by Dynatrace agents, it can even infer and link this metric to the specific process, host, or deployment that generated it, even without explicit configuration. This fusion of custom metrics with automatically discovered topology is what allows Dynatrace to provide rich, correlated insights, enabling you to troubleshoot issues by seeing your custom metrics alongside standard performance metrics, logs, and traces within the same interface.

The key to effectively using the Metrics API is understanding how Dynatrace interprets the metricId and dimensions. The metricId should follow a hierarchical naming convention (e.g., custom.application.component.metric_name). Dimensions are key-value pairs that act as tags, allowing Dynatrace to slice and dice your data. For instance, if you send the same custom.myapp.request_latency_seconds metric with different http_method dimensions (GET, POST), Dynatrace will treat them as distinct series for that metric, enabling you to compare latency across different request types. You can also include dimensions that map to Dynatrace’s internal concepts, like dt.entity.service or dt.entity.host, to explicitly link your metric to monitored entities, though Dynatrace often infers these links automatically if the metric is sent from an instrumented environment.

The ingest endpoint supports a single metric per request by default, but you can send multiple metrics in a single request by structuring your payload as a list of metric objects. This is crucial for efficiency when sending many related metrics, as it reduces network overhead and the number of API calls. The timestamp is expected in milliseconds since the Unix epoch, and if omitted, Dynatrace will assign the current server time, which is generally not recommended for historical data or ensuring precise correlation. For optimal performance and to avoid hitting API rate limits, batching metrics is essential. The API also supports specifying the data type of the metric (e.g., count, gauge, distribution) if you need more control over how Dynatrace processes and aggregates the data, although for simple gauges and counters, Dynatrace’s defaults are usually sufficient.

The most surprising aspect of Dynatrace’s Metrics API is its ability to infer and link your custom metrics to its automatically discovered topology without explicit configuration, provided the metric originates from an environment already monitored by Dynatrace. This means if your custom metric is generated by a process that Dynatrace’s OneAgent is monitoring, Dynatrace can automatically associate that metric with the correct service, host, and other topological entities, making it immediately visible and actionable within the Dynatrace UI alongside your other performance data. You don’t need to pre-define every custom metric or its associated entities in Dynatrace; the API leverages the existing topology context.

Beyond basic ingestion, the API allows for sophisticated data typing and aggregation strategies. For example, instead of sending raw latency values, you could send a distribution metric, which captures the full histogram of latencies. This allows Dynatrace to calculate percentiles (p95, p99) and other statistical measures directly from the ingested data, providing a much richer view of performance than simple averages. This requires careful construction of the payload to include the distribution data, often in a specific format that Dynatrace expects for such metrics.

You’ll next want to explore how to query these custom metrics using the Metrics Query API to build custom dashboards and alerts.

Want structured learning?

Take the full Dynatrace course →