Skip to content

Replace static parameters in route pattern for telemetry - #5

Open
tomerqodo wants to merge 8 commits into
qodo_only-issues-20260113-qodo-grep-copilot_base_replace_static_parameters_in_route_pattern_for_telemetry_pr20from
qodo_only-issues-20260113-qodo-grep-copilot_head_replace_static_parameters_in_route_pattern_for_telemetry_pr20
Open

tomerqodo wants to merge 8 commits into
qodo_only-issues-20260113-qodo-grep-copilot_base_replace_static_parameters_in_route_pattern_for_telemetry_pr20from
qodo_only-issues-20260113-qodo-grep-copilot_head_replace_static_parameters_in_route_pattern_for_telemetry_pr20

Conversation

@tomerqodo

Copy link
Copy Markdown

Benchmark PR from qodo-benchmark#20

@qodo-code-review

Copy link
Copy Markdown

Code Review by Qodo (Alpha)

🐞 Bugs (4) 📘 Rule Violations (0) 📎 Requirement Gaps (0) 💡 Suggestions (0)

Grey Divider


Action Required

1. Regex compiled in debug 🐞 Bug
Description
• RoutePatternParameterPart.DebuggerToString now formats RegexRouteConstraint by reading
  regexConstraint.Constraint, which forces the lazily-created Regex instance to be created/compiled.
• DebuggerToString is executed during endpoint construction for both RouteEndpoint.DisplayName and
  default IRouteDiagnosticsMetadata, so this can regress startup performance for apps using
  regex-based constraints/policies.

performance

Code

src/Http/Routing/src/Patterns/RoutePatternParameterPart.cs[R106-111]

+            else if (constraint.ParameterPolicy is Constraints.RegexRouteConstraint regexConstraint)
+            {
+                builder.Append("regex(");
+                builder.Append(regexConstraint.Constraint.ToString());
+                builder.Append(')');
+            }
Evidence
RegexRouteConstraint is intentionally lazy to avoid compiling regexes at startup. The new
DebuggerToString path accesses RegexRouteConstraint.Constraint, defeating that optimization.
DebuggerToString is called as part of endpoint construction to set display names and create default
IRouteDiagnosticsMetadata, so this will happen at app startup for each endpoint that includes such
constraints.

src/Http/Routing/src/Patterns/RoutePatternParameterPart.cs[99-116]
src/Http/Routing/src/Constraints/RegexRouteConstraint.cs[51-56]
src/Http/Routing/src/Constraints/RegexRouteConstraint.cs[62-76]
src/Http/Routing/src/RouteEndpointDataSource.cs[132-141]
src/Http/Routing/src/RouteEndpointBuilder.cs[108-112]

Agent Prompt
### Issue description
`RoutePatternParameterPart.DebuggerToString()` accesses `RegexRouteConstraint.Constraint` to print the regex pattern. This forces lazy regex creation/compilation during endpoint build, regressing startup performance and undermining the explicit lazy-init design of `RegexRouteConstraint`.

### Issue Context
`DebuggerToString()` is used beyond the debugger: it feeds `RouteEndpoint.DisplayName` and default `IRouteDiagnosticsMetadata`.

### Fix Focus Areas
- src/Http/Routing/src/Patterns/RoutePatternParameterPart.cs[99-116]
- src/Http/Routing/src/Constraints/RegexRouteConstraint.cs[41-76]
- src/Http/Routing/src/Patterns/RoutePatternFactory.cs[946-963]

### Implementation notes
- If the policy came from text, prefer emitting that text (`constraint.Content`) without materializing the regex.
- For `RegexRouteConstraint` instances created from strings (e.g., `Constraint(object)` converting strings to `RegexRouteConstraint`), consider preserving the original pattern string in the policy reference (or enhancing `RegexRouteConstraint` to expose it) so debug formatting does not require compiling the regex.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation Recommended

2. Drops tilde-slash prefix 🐞 Bug
Description
• When RequiredValues match parameters, RoutePatternDebugStringFormatter rebuilds the string from
  segments and only re-adds a leading '/' (not "~/").
• For patterns whose RawText starts with "~/" (supported by RoutePatternParser), this means the
  returned debug string loses that prefix only in the rebuild/substitution path.

correctness

Code

src/Http/Routing/src/Patterns/RoutePatternDebugStringFormatter.cs[R32-36]

+        // Preserve leading slash from raw text
+        if (pattern.RawText is { Length: > 0 } rt && rt[0] == Separator)
+        {
+            result = Separator + result;
+        }
Evidence
Route templates can start with "~/"; the parser trims this prefix for parsing but retains the
original string in RawText. The formatter rebuild path uses segments and only preserves a leading
'/', so "~/" is not preserved when required value substitution occurs.

src/Http/Routing/src/Patterns/RoutePatternDebugStringFormatter.cs[32-36]
src/Http/Routing/src/Patterns/RoutePatternDebugStringFormatter.cs[15-19]
src/Http/Routing/src/Patterns/RoutePatternParser.cs[457-466]
src/Http/Routing/src/Patterns/RoutePatternParser.cs[61-64]

Agent Prompt
### Issue description
When required-value substitution triggers the rebuild path, `RoutePatternDebugStringFormatter.Format` only preserves a leading `/`. Templates starting with `~/` will lose that prefix in the returned debug string.

### Issue Context
`RoutePatternParser` allows `~/` and strips it for parsing, but `RoutePattern.RawText` retains the original input. The formatter should preserve the same prefix semantics as the original raw template, even when rebuilding.

### Fix Focus Areas
- src/Http/Routing/src/Patterns/RoutePatternDebugStringFormatter.cs[13-45]
- src/Http/Routing/src/Patterns/RoutePatternParser.cs[457-472]
- src/Http/Routing/test/UnitTests/Patterns/RoutePatternDebugStringFormatterTest.cs[197-230]

### Implementation notes
- Add handling like:
 - if `RawText` starts with `"~/"`, prefix the result with `"~/"`
 - else if `RawText` starts with `/`, prefix with `/`
- Add unit test coverage for `template="~/{controller}/{action}"` with required values causing substitution.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


3. Required value culture drift 🐞 Bug
Description
• Required value substitution uses requiredValue.ToString(), which is culture-dependent for
  non-string values and may produce different endpoint display names/route metadata across
  environments.
• Routing already normalizes values with Convert.ToString(..., CultureInfo.InvariantCulture)
  elsewhere; using object.ToString() here is inconsistent and can also surface unexpected ToString()
  exceptions into endpoint construction.

reliability

Code

src/Http/Routing/src/Patterns/RoutePatternDebugStringFormatter.cs[R92-98]

+        if (pattern.RequiredValues.TryGetValue(parameterName, out var requiredValue) &&
+            !RoutePattern.IsRequiredValueAny(requiredValue) &&
+            requiredValue?.ToString() is { Length: > 0 } v)
+        {
+            value = v;
+            return true;
+        }
Evidence
The formatter is used to generate endpoint display names and IRouteDiagnosticsMetadata.Route,
which are produced during endpoint construction. Using ToString() without an invariant culture can
make these values unstable across cultures; routing code documents/uses invariant conversions when
treating values as route strings.

src/Http/Routing/src/Patterns/RoutePatternDebugStringFormatter.cs[90-98]
src/Http/Routing/src/RouteValueEqualityComparer.cs[12-16]
src/Http/Routing/src/RouteValueEqualityComparer.cs[33-35]

Agent Prompt
### Issue description
`TryGetRequiredValue` uses `requiredValue?.ToString()` which is culture-dependent for non-strings and can make endpoint display names and route diagnostics metadata differ across environments.

### Issue Context
Routing already treats non-string values as route strings using `Convert.ToString(..., CultureInfo.InvariantCulture)` (see `RouteValueEqualityComparer`).

### Fix Focus Areas
- src/Http/Routing/src/Patterns/RoutePatternDebugStringFormatter.cs[90-101]
- src/Http/Routing/src/RouteValueEqualityComparer.cs[12-35]

### Implementation notes
- Add `using System.Globalization;`
- Replace `requiredValue?.ToString()` with invariant conversion:
 - `var v = requiredValue as string ?? Convert.ToString(requiredValue, CultureInfo.InvariantCulture);`
- Keep the existing `{ Length: > 0 }` check and RequiredValueAny filtering.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


4. Metrics tag cardinality 🐞 Bug
Description
• The default IRouteDiagnosticsMetadata.Route is used as a metrics tag; substituting RequiredValues
  (controller/action names) changes the tag from a generic template to a per-endpoint value.
• This increases metric label cardinality (bounded by number of endpoints, but can be large in big
  MVC apps) and may increase memory/CPU cost in metrics pipelines/backends.

observability

Code

src/Http/Routing/src/Patterns/RoutePattern.cs[158]

+    internal string DebuggerToString() => RoutePatternDebugStringFormatter.Format(this);
Evidence
Endpoint construction adds default IRouteDiagnosticsMetadata based on
routePattern.DebuggerToString(). Endpoint routing uses this Route string as a metrics tag. Since
DebuggerToString now substitutes required values, the tag becomes more specific and can grow in
cardinality in proportion to distinct endpoints (e.g., per action).

src/Http/Routing/src/Patterns/RoutePattern.cs[154-159]
src/Http/Routing/src/RouteEndpointBuilder.cs[108-112]
src/Http/Routing/src/EndpointRoutingMiddleware.cs[129-133]
src/Http/Routing/src/Patterns/RoutePatternDebugStringFormatter.cs[21-28]

Agent Prompt
### Issue description
`IRouteDiagnosticsMetadata.Route` is used as a metrics tag. With required-value substitution, the value becomes more endpoint-specific (e.g., controller/action names), increasing tag cardinality.

### Issue Context
This is a trade-off: better per-endpoint readability vs higher cardinality. Cardinality is bounded by endpoint count but can be large for big apps.

### Fix Focus Areas
- src/Http/Routing/src/Patterns/RoutePattern.cs[154-159]
- src/Http/Routing/src/RouteEndpointBuilder.cs[108-112]
- src/Http/Routing/src/EndpointRoutingMiddleware.cs[129-133]
- src/Http/Routing/src/Patterns/RoutePatternDebugStringFormatter.cs[13-45]

### Implementation notes
Options to consider:
- Keep the substituted formatter for `DisplayName`, but use `RoutePattern.RawText` (or a template-only formatter) for default `IRouteDiagnosticsMetadata.Route`.
- Alternatively add a second API (e.g., `GetDiagnosticsRouteString()` vs `GetDebuggerDisplayString()`) and use the lower-cardinality one for metrics.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Qodo Logo

Comment on lines +106 to +111
else if (constraint.ParameterPolicy is Constraints.RegexRouteConstraint regexConstraint)
{
builder.Append("regex(");
builder.Append(regexConstraint.Constraint.ToString());
builder.Append(')');
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action Required

1. Regex compiled in debug 🐞 Bug

• RoutePatternParameterPart.DebuggerToString now formats RegexRouteConstraint by reading
  regexConstraint.Constraint, which forces the lazily-created Regex instance to be created/compiled.
• DebuggerToString is executed during endpoint construction for both RouteEndpoint.DisplayName and
  default IRouteDiagnosticsMetadata, so this can regress startup performance for apps using
  regex-based constraints/policies.
Agent Prompt
### Issue description
`RoutePatternParameterPart.DebuggerToString()` accesses `RegexRouteConstraint.Constraint` to print the regex pattern. This forces lazy regex creation/compilation during endpoint build, regressing startup performance and undermining the explicit lazy-init design of `RegexRouteConstraint`.

### Issue Context
`DebuggerToString()` is used beyond the debugger: it feeds `RouteEndpoint.DisplayName` and default `IRouteDiagnosticsMetadata`.

### Fix Focus Areas
- src/Http/Routing/src/Patterns/RoutePatternParameterPart.cs[99-116]
- src/Http/Routing/src/Constraints/RegexRouteConstraint.cs[41-76]
- src/Http/Routing/src/Patterns/RoutePatternFactory.cs[946-963]

### Implementation notes
- If the policy came from text, prefer emitting that text (`constraint.Content`) without materializing the regex.
- For `RegexRouteConstraint` instances created from strings (e.g., `Constraint(object)` converting strings to `RegexRouteConstraint`), consider preserving the original pattern string in the policy reference (or enhancing `RegexRouteConstraint` to expose it) so debug formatting does not require compiling the regex.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment on lines +32 to +36
// Preserve leading slash from raw text
if (pattern.RawText is { Length: > 0 } rt && rt[0] == Separator)
{
result = Separator + result;
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remediation Recommended

2. Drops tilde-slash prefix 🐞 Bug

• When RequiredValues match parameters, RoutePatternDebugStringFormatter rebuilds the string from
  segments and only re-adds a leading '/' (not "~/").
• For patterns whose RawText starts with "~/" (supported by RoutePatternParser), this means the
  returned debug string loses that prefix only in the rebuild/substitution path.
Agent Prompt
### Issue description
When required-value substitution triggers the rebuild path, `RoutePatternDebugStringFormatter.Format` only preserves a leading `/`. Templates starting with `~/` will lose that prefix in the returned debug string.

### Issue Context
`RoutePatternParser` allows `~/` and strips it for parsing, but `RoutePattern.RawText` retains the original input. The formatter should preserve the same prefix semantics as the original raw template, even when rebuilding.

### Fix Focus Areas
- src/Http/Routing/src/Patterns/RoutePatternDebugStringFormatter.cs[13-45]
- src/Http/Routing/src/Patterns/RoutePatternParser.cs[457-472]
- src/Http/Routing/test/UnitTests/Patterns/RoutePatternDebugStringFormatterTest.cs[197-230]

### Implementation notes
- Add handling like:
  - if `RawText` starts with `"~/"`, prefix the result with `"~/"`
  - else if `RawText` starts with `/`, prefix with `/`
- Add unit test coverage for `template="~/{controller}/{action}"` with required values causing substitution.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment on lines +92 to +98
if (pattern.RequiredValues.TryGetValue(parameterName, out var requiredValue) &&
!RoutePattern.IsRequiredValueAny(requiredValue) &&
requiredValue?.ToString() is { Length: > 0 } v)
{
value = v;
return true;
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remediation Recommended

3. Required value culture drift 🐞 Bug

• Required value substitution uses requiredValue.ToString(), which is culture-dependent for
  non-string values and may produce different endpoint display names/route metadata across
  environments.
• Routing already normalizes values with Convert.ToString(..., CultureInfo.InvariantCulture)
  elsewhere; using object.ToString() here is inconsistent and can also surface unexpected ToString()
  exceptions into endpoint construction.
Agent Prompt
### Issue description
`TryGetRequiredValue` uses `requiredValue?.ToString()` which is culture-dependent for non-strings and can make endpoint display names and route diagnostics metadata differ across environments.

### Issue Context
Routing already treats non-string values as route strings using `Convert.ToString(..., CultureInfo.InvariantCulture)` (see `RouteValueEqualityComparer`).

### Fix Focus Areas
- src/Http/Routing/src/Patterns/RoutePatternDebugStringFormatter.cs[90-101]
- src/Http/Routing/src/RouteValueEqualityComparer.cs[12-35]

### Implementation notes
- Add `using System.Globalization;`
- Replace `requiredValue?.ToString()` with invariant conversion:
  - `var v = requiredValue as string ?? Convert.ToString(requiredValue, CultureInfo.InvariantCulture);`
- Keep the existing `{ Length: > 0 }` check and RequiredValueAny filtering.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

{
return RawText ?? string.Join(SeparatorString, PathSegments.Select(s => s.DebuggerToString()));
}
internal string DebuggerToString() => RoutePatternDebugStringFormatter.Format(this);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remediation Recommended

4. Metrics tag cardinality 🐞 Bug

• The default IRouteDiagnosticsMetadata.Route is used as a metrics tag; substituting RequiredValues
  (controller/action names) changes the tag from a generic template to a per-endpoint value.
• This increases metric label cardinality (bounded by number of endpoints, but can be large in big
  MVC apps) and may increase memory/CPU cost in metrics pipelines/backends.
Agent Prompt
### Issue description
`IRouteDiagnosticsMetadata.Route` is used as a metrics tag. With required-value substitution, the value becomes more endpoint-specific (e.g., controller/action names), increasing tag cardinality.

### Issue Context
This is a trade-off: better per-endpoint readability vs higher cardinality. Cardinality is bounded by endpoint count but can be large for big apps.

### Fix Focus Areas
- src/Http/Routing/src/Patterns/RoutePattern.cs[154-159]
- src/Http/Routing/src/RouteEndpointBuilder.cs[108-112]
- src/Http/Routing/src/EndpointRoutingMiddleware.cs[129-133]
- src/Http/Routing/src/Patterns/RoutePatternDebugStringFormatter.cs[13-45]

### Implementation notes
Options to consider:
- Keep the substituted formatter for `DisplayName`, but use `RoutePattern.RawText` (or a template-only formatter) for default `IRouteDiagnosticsMetadata.Route`.
- Alternatively add a second API (e.g., `GetDiagnosticsRouteString()` vs `GetDebuggerDisplayString()`) and use the lower-cardinality one for metrics.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants