PRO TIP - Global request naming for REST services

Dynatrace does a pretty good job at request naming for common frameworks. Unfortunately, for some generic REST services, it may require request naming rules or URL cleanup rules, so requests are properly identified.

For example if your requests have names in Dynatrace such as:

  • /api/v1/client/123/data
  • /customers/812345/shopping-cart

instead of

  • /api/v1/client/[ID]/data
  • /customers/[ID]/shopping-cart

then you probably know you need to use the request naming rules. The request naming rules can be defined at a particular service. However, if you have many different request URL patterns, it’s not efficient to define a rule for each one. There are even more challenges if you need to define such patterns on many services across multiple Dynatrace environments.

In such cases, it’s worth considering Request naming rules API and defining a pattern to remove the numbers in requests names.

For the example from above to remove a number from an URL, we need to extract the prefix and postfix. Let’s use regular expressions for that:

Prefix extraction pattern ^(.*?/)\d+
Postfix extraction pattern /\d++(/[^/]*+)$
Condition pattern /\d++

So our rule will be applied only if the Request URL matches the condition - a forward slash followed by a sequence of numbers. Additionally, we want to define a scope for this rule to apply. This can be accomplished for example by using tags or management zones in the conditions as well as other conditions.

In our case, the request naming rule payload for the API will look like the example below and it will be applied to a set of services tagged by the tag “REST Cleanup”. Since this is a JSON payload, the regex patterns must be correctly escaped:

{
 "conditions": [
  {
   "attribute": "WEBREQUEST_URL_PATH",
   "comparisonInfo": {
    "caseSensitive": false,
    "comparison": "REGEX_MATCHES",
    "negate": false,
    "type": "STRING",
    "value": "/\\d++",
    "values": null
   }
  },
  {
   "attribute": "SERVICE_TAG",
   "comparisonInfo": {
    "comparison": "TAG_KEY_EQUALS",
    "negate": false,
    "type": "TAG",
    "value": {
     "context": "CONTEXTLESS",
     "key": "REST Cleanup"
    },
    "values": null
   }
  }
 ],
 "enabled": true,
 "order": "REST 10",
 "managementZones": [],
 "metadata": {
  "clusterVersion": "1.220.96.20210701-171424",
  "configurationVersions": [
   0
  ]
 },
 "namingPattern": "{prefix}[ID]{postfix}",
 "placeholders": [
  {
   "aggregation": null,
   "attribute": "WEBREQUEST_URL_PATH",   
   "delimiterOrRegex": "^(.*?/)\\d+",
   "endDelimiter": null,
   "kind": "REGEX_EXTRACTION",
   "name": "prefix",
   "normalization": "ORIGINAL",
   "requestAttribute": null,
   "source": null,
   "useFromChildCalls": false
  },
  {
   "aggregation": null,
   "attribute": "WEBREQUEST_URL_PATH",
   "delimiterOrRegex": "\/\\d++(\/[^\/]*+)$",
   "endDelimiter": null,
   "kind": "REGEX_EXTRACTION",
   "name": "postfix",
   "normalization": "ORIGINAL",
   "requestAttribute": null,
   "source": null,
   "useFromChildCalls": false
  }
 ]
}

After this rule is applied using the Request naming rules API you can see it also on your service in the Request naming settings section :

Now any future request for this service will have the desired naming with numbers removed.

If you have REST requests which have two numbers similarly you will need also another rule preceding the rule above and extracting prefix, infix and postfix parts of the URL and then constructing a new request name:

{
 "conditions": [
  {
   "attribute": "WEBREQUEST_URL_PATH",
   "comparisonInfo": {
    "caseSensitive": false,
    "comparison": "REGEX_MATCHES",
    "negate": false,
    "type": "STRING",
    "value": "\/\\d++\/[\/\\D-]*+\\d++",
    "values": null
   }
  },
  {
   "attribute": "SERVICE_TAG",
   "comparisonInfo": {
    "comparison": "TAG_KEY_EQUALS",
    "negate": false,
    "type": "TAG",
    "value": {
     "context": "CONTEXTLESS",
     "key": "REST Cleanup"
    },
    "values": null
   }
  }
 ],
 "enabled": true,
 "order": "REST 00",
 "managementZones": [],
 "metadata": {
  "clusterVersion": "1.220.96.20210701-171424",
  "configurationVersions": [
   0
  ]
 },
 "namingPattern": "{prefix}[ID]{infix}[ID]{postfix}",
 "placeholders": [
  {
   "aggregation": null,
   "attribute": "WEBREQUEST_URL_PATH",   
   "delimiterOrRegex": "^(.*?/)\\d+",
   "endDelimiter": null,
   "kind": "REGEX_EXTRACTION",
   "name": "prefix",
   "normalization": "ORIGINAL",
   "requestAttribute": null,
   "source": null,
   "useFromChildCalls": false
  },
  {
    "aggregation": null,
    "attribute": "WEBREQUEST_URL_PATH",   
    "delimiterOrRegex": "\/\\d++(\/[\/\\D-]*+)\\d++",
    "endDelimiter": null,
    "kind": "REGEX_EXTRACTION",
    "name": "infix",
    "normalization": "ORIGINAL",
    "requestAttribute": null,
    "source": null,
    "useFromChildCalls": false
   },
   {
   "aggregation": null,
   "attribute": "WEBREQUEST_URL_PATH",
   "delimiterOrRegex": "\/\\d++(\/[^\/]*+)$",
   "endDelimiter": null,
   "kind": "REGEX_EXTRACTION",
   "name": "postfix",
   "normalization": "ORIGINAL",
   "requestAttribute": null,
   "source": null,
   "useFromChildCalls": false
  }
 ]
}

To make it more simple to deploy, you can use the attached monaco project which makes those rules easily deployable.
generic-rest.zip (3.76 KB)

36 Likes

Thanks so much @Julius_Loman

Question:

{prefix}, {infix}, and {postfix} should be replaced by the values from the table or we can declare them as a variables somewhere?

Have a good day.

@Malaik the placeholders {prefix}, {infix}, and {postfix} are extracted from the URL with regular expressions. See the placeholders section of the rule.

2 Likes

Thanks @Julius_Loman right, my question was gone too quickly.

Have a good day.

Thank you for sharing this, @Julius_Loman .

It’s an almost constant need for all build projects.

It’s really unfortunate that the overall management of placeholders and request naming rules is still not available at the interface level (your article dates back to 2021!). It would be so much better for the client adoption by non-technical people.

Thx.

2 Likes

Great Tip!

1 Like

@Julius_Loman I’ve discovered the same issue where it would be great if the Clean URL rule would let you specify the replacement text instead of just deleting the values.  The example I’m trying to solve is a bit more complex and I’m running into dynatrace not allowing quantified groups in the regex here.

Example Request Names:

/api/clients/[UUID]/plans/d9be25d0-1a9c-4970-985f-59102adf6884+796edda1-2292-4228-912c-6ea66ca6c573/projection/subroute1/subroute2
/api/clients/[UUID]/plans/d9be25d0-1a9c-4970-985f-59102adf6884+796edda1-2292-4228-912c-6ea66ca6c573+d9be25d0-1a9c-4970-985f-59102adf6884+796edda1-2292-4228-912c-6ea66ca6c573/projection/subroute1/subroute2/subroute3

So dynatrace has already seen that our client id is a guid and replaced it correctly, but another id in the path is actually 1 or more UUIDs together, joined with + if there is more than one.  If there is only 1 it correctly matches and replaces it with [UUID] but when there are multiple, it does not.

Basic GUID Regex: [0-9A-Fa-f]{8}-?([0-9A-Fa-f]{4}-?){3}[0-9A-Fa-f]{12}

Multi GUID ID Match Regex: ([0-9A-Fa-f]{8}-?([0-9A-Fa-f]{4}-?){3}[0-9A-Fa-f]{12}\+?)++

OR A more explicit version since a single GUID plan id will already be correctly replaced: ([0-9A-Fa-f]{8}-?([0-9A-Fa-f]{4}-?){3}[0-9A-Fa-f]{12}\+)++[0-9A-Fa-f]{8}-?([0-9A-Fa-f]{4}-?){3}[0-9A-Fa-f]{12}

But I’m struggling to apply your prefix and postfix methods to this more complex example in a way that dynatrace will accept. Primarily that it says Quantified groups are not allowed.

Any guidance you can give would be great

1 Like

Is anyone using this solution in 2026? We’ve been using something like this for years. Now we’re getting prodded towards Endpoint-level metrics for SDv1. But I’ve just turned it on for some services and the endpoints that it ends up with are “{prefix}[ID]{postfix}” and “{prefix}[ID]{infix}[ID]{postfix}”… not those strings with the values swapped out… those EXACT strings. Presumably because of “volatile placeholders” in the extraction rules.

But this means that the enhanced endpoint detection is entirely unusable to us. Trying to figure out the path forward.

@NeJoyerPB  - Yes, some customers are still using it. It really depends if you are on SaaS and Managed. For Managed, this solution is still valid for Service Detection v1 services (OpenTelemetry services is Service Detection v2)

For SaaS it depends - it’s not applicable for Service Detection v2 services too. That means: Services from OpenTelemetry-ingested data, OneAgent on K8S (Preview, opt-in), and FaaS (Preview, opt-in). Rest of the services are still from Service Detection v1. Even if you opt-in to the Endpoint-level metrics for SDv1 , request naming rules still apply (as of today). However, opting in to Endpoint-level metrics may have several implications.

We’re on SaaS and our services are all SDv1. The request naming rules are still working fine without Endpoint-level metrics. But it seems like one of the implications of turning on Endpoint-level metrics when using a rule set like this is that the Endpoints get named with the placeholder names, rather than the values. (eg. “{prefix}[ID]{infix}[ID]{postfix}” and “{prefix}[ID]{postfix}”). Trying to figure out the best path forward. Right now I just had to turn off Endpoint-level metrics, but it seems like something I should be headed towards.

@mreider do global request naming rules supposed to be broken with endpoint-level metrics?