Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(instrumentation-express): Support non-string routes #2008

Merged

Conversation

onurtemizkan
Copy link
Contributor

@onurtemizkan onurtemizkan commented Mar 13, 2024

Which problem is this PR solving?

This came up while migrating @sentry/node to OpenTelemetry. (Related issue: getsentry/sentry-javascript#10168).

This PR adds support for:

  • Routes that are defined as regular expressions.
  • Multiple routes provided as an array.

The current behaviour falls back to / as the layerPath when the Express route argument is not a string, which does not cover all uses (Express docs).

@sentry/node already has a test suite to cover these uses, so this PR migrates them to OpenTelemetry for validation.

Short description of the changes

  • Adds getLayerPath utility to extract multiple route arguments, including regular expressions.
  • Adds new ESM tests to validate this use. (Migrated from sentry-javascript)

@onurtemizkan onurtemizkan requested a review from a team March 13, 2024 13:01
Copy link

linux-foundation-easycla bot commented Mar 13, 2024

CLA Signed

The committers listed above are authorized under a signed CLA.

const port = server.address().port;

await new Promise(resolve => {
http.get(`http://localhost:${port}/test/arr/requiredPath/optionalPath/lastParam`, (res) => {
Copy link
Member

Choose a reason for hiding this comment

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

next();
});

app.get(['/test/arr/:id', /\/test\/arr[0-9]*\/required(path)?(\/optionalPath)?\/(lastParam)?/], (_req, res) => {
Copy link
Member

Choose a reason for hiding this comment

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

@onurtemizkan onurtemizkan changed the title feat(instrumentation-express): Support multiple routes with RegExp. feat(instrumentation-express): Support RegExp routes Mar 15, 2024
@onurtemizkan onurtemizkan changed the title feat(instrumentation-express): Support RegExp routes feat(instrumentation-express): Support non-string routes Mar 15, 2024
Copy link
Member

@JamieDanielson JamieDanielson left a comment

Choose a reason for hiding this comment

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

Thanks for this! Overall I think this looks good - I am trying to confirm if there is specific guidance on when to approve the workflows. In the meantime I think this will also require an npm run lint:fix. Can you update that on your side and push, along with an explicit return type for the getLayerPath function?

@trentm
Copy link
Contributor

trentm commented Mar 19, 2024

I am trying to confirm if there is specific guidance on when to approve the workflows.

FWIW, I've tended to "Approve and run" after a sanity check that the PR doesn't add a bitcoin miner, credentials exfil or somethign like that. :)

@onurtemizkan
Copy link
Contributor Author

@JamieDanielson, thanks for reviewing. I updated the PR.

Copy link

codecov bot commented Mar 20, 2024

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 90.36%. Comparing base (dfb2dff) to head (63a79c2).
Report is 102 commits behind head on main.

❗ Current head 63a79c2 differs from pull request most recent head 5f607ce. Consider uploading reports for the commit 5f607ce to get more accurate results

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #2008      +/-   ##
==========================================
- Coverage   90.97%   90.36%   -0.62%     
==========================================
  Files         146      147       +1     
  Lines        7492     7687     +195     
  Branches     1502     1576      +74     
==========================================
+ Hits         6816     6946     +130     
- Misses        676      741      +65     
Files Coverage Δ
...try-instrumentation-express/src/instrumentation.ts 100.00% <100.00%> (ø)
...opentelemetry-instrumentation-express/src/utils.ts 98.11% <100.00%> (+0.49%) ⬆️

... and 9 files with indirect coverage changes

@dyladan
Copy link
Member

dyladan commented Mar 25, 2024

I am trying to confirm if there is specific guidance on when to approve the workflows.

FWIW, I've tended to "Approve and run" after a sanity check that the PR doesn't add a bitcoin miner, credentials exfil or somethign like that. :)

That's also my strategy

Copy link
Member

@dyladan dyladan left a comment

Choose a reason for hiding this comment

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

Overall looks ok to me but I have a little bit of concern that getLayerPath is not resilient to strings and regexes that have the same stringified represenation.

* @param args - Arguments of the route
* @returns The layer path
*/
export const getLayerPath = (args: unknown[]): string | undefined => {
Copy link
Member

Choose a reason for hiding this comment

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

This seems a bit fragile to me in the sense that it would be pretty easy to get the same output from a regexp that it would be to get from a string path with a trailing slash. Is there any guardrail against this situation, is this an acceptable risk, or is this not actually an issue if it happens? I'm not an expert in this instrumentation and I'm not 100% sure what the layer path is used for.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

IMHO it would be an acceptable risk. I'm not sure how to work around this without breaking the path pattern.

Copy link
Member

Choose a reason for hiding this comment

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

Is this still an open question? I'm not sure I'm following the specific concern here, can you provide an example of what we are considering guarding against?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

My understanding is, that as this PR converts regexp path definitions to a string representation, it may collide with an exact string path which can make both end up under the same transaction name.

Something like:

  • /\/test\/regex/ and
  • /test/regex/ can end up as
  • /test/regex/

This seems possible, but l don't think it is a common pattern when people define routes.

Copy link

Choose a reason for hiding this comment

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

Just a thought since I am also following this PR: There is always the possibility for collisions when coercing anything into a string. In my opinion this is worth it. If we want to reduce the likelihood of collisions, we could transform regular expressions like const re = /\/test\/regex\/ with const coerced = `RegEx(${re.toString()})`;. 🤔

Copy link
Member

Choose a reason for hiding this comment

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

Hmm... I think I'm in agreement here that this is an acceptable risk as-is, as we are otherwise guarding against edge cases that are unlikely to occur, and if it does occur it is a fairly minimal impact. Especially compared to the current state, this gets us to a much better place. If we find ourselves getting issues related to this we can reconsider, but it might even just end up being a documentation thing at that point.

@AbhiPrasad
Copy link
Member

@dyladan @JamieDanielson could you take another look at this when you get the time? Thanks!

Copy link
Member

@JamieDanielson JamieDanielson left a comment

Choose a reason for hiding this comment

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

Thank you for the details and adding all the tests. I'm curious if anyone has final objections we haven't addressed but this looks good to me.

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

Successfully merging this pull request may close these issues.

8 participants