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: restify instrumentation #416

Merged
merged 31 commits into from
Apr 16, 2021

Conversation

rauno56
Copy link
Member

@rauno56 rauno56 commented Apr 8, 2021

Which problem is this PR solving?

This is adding restify instrumentation.

Short description of the changes

Restify has a somewhat similar API to express and is created for the same purpose - building APIs. This instrumentation wraps all handlers to generate a span for each of them.

@codecov
Copy link

codecov bot commented Apr 8, 2021

Codecov Report

Merging #416 (cc1383e) into main (2dceaf3) will not change coverage.
The diff coverage is n/a.

❗ Current head cc1383e differs from pull request most recent head f4f4b08. Consider uploading reports for the commit f4f4b08 to get more accurate results

@@           Coverage Diff           @@
##             main     #416   +/-   ##
=======================================
  Coverage   95.83%   95.83%           
=======================================
  Files          15       15           
  Lines         624      624           
  Branches       94       94           
=======================================
  Hits          598      598           
  Misses         26       26           

@rauno56 rauno56 force-pushed the feat/restify-instrumentation branch 2 times, most recently from 6718f96 to 44607ca Compare April 12, 2021 09:54
// the span, which is created to track work that happens outside of the
// request lifecycle entirely.
const span = tracer.startSpan(`makeRequest to ${path}`);
api.context.with(api.setSpan(api.context.active(), span), () => {
Copy link

Choose a reason for hiding this comment

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

Do we need to include manual span creation in the example? I think we should keep the client as simple as possible for an example focusing on server/restify instrumentation. HTTP instrumentation should generate a client span anyway.

Copy link
Member Author

Choose a reason for hiding this comment

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

True. It would make sense if the HTTP instrumentation was not there. I'll remove that.


const { diag } = api;
const RESTIFY_MW_METHODS = ['use', 'pre'];
const RESTIFY_METHODS = ['del', 'get', 'head', 'opts', 'post', 'put', 'patch'];
Copy link

Choose a reason for hiding this comment

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

Does restify support custom HTTP methods? If so, will this instrumentation be able to work with them?

Copy link
Member Author

Choose a reason for hiding this comment

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

No. Everything that allows adding a handler is listed here. There's a "wildcard"-way of reaching to the API of find-my-way which is mentioned here in restify docs, but even that has to be done through one of these functions.

However, I'm not testing for that shortcut. Will add a test for that.

Copy link
Member Author

Choose a reason for hiding this comment

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

Restify does not support custom HTTP methods, it turns out. It overwrites it with the one specified with function used to register the handler. Added a test to make sure the more verbose API works as expected.

if (this._isDisabled) {
return handler(req, res, next);
}
// const parentSpan = api.getSpan(api?.context?.active());
Copy link
Contributor

Choose a reason for hiding this comment

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

Need to update the name of the parent span here for incoming requests, e.g. as is in express: https://github.com/open-telemetry/opentelemetry-js-contrib/blob/main/plugins/node/opentelemetry-instrumentation-express/src/express.ts#L193-L208

return module;
}

private _middlewarePatcher(original: Function, methodName?: string) {
Copy link
Contributor

Choose a reason for hiding this comment

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

I think middleware spans should have middleware name as the span name (not sure if possibly with restify), e.g. the operation tree looks like this currently, where each middleware operation name is the route name:
image

However the express instrumentation contains middleware names:
image

Also I think middleware spans should have the incoming request span as its parent.

Copy link
Member Author

Choose a reason for hiding this comment

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

Yep, it's possible. Express takes the name of the function it seems, which can be undefined at times, but still better than nothing. Thanks!

Also I think middleware spans should have the incoming request span as its parent.

I generally agree but don't want to change that because there might not be a request span if HTTP instrumentation is not enabled, so the structure would be different between HTTP instrumentation enabled and not.

@seemk
Copy link
Contributor

seemk commented Apr 12, 2021

Seems to work fine with restify 5.2.1

@rauno56 rauno56 marked this pull request as ready for review April 13, 2021 10:44
@rauno56 rauno56 requested a review from a team April 13, 2021 10:44
@rauno56 rauno56 changed the title help-needed: restify instrumentation feat: restify instrumentation Apr 13, 2021
Copy link
Member

@johnbley johnbley left a comment

Choose a reason for hiding this comment

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

In general, LGTM. Thanks for this significant feature contribution!

return original.call(
this,
path,
...instrumentation._handlerPatcher(
Copy link
Member

Choose a reason for hiding this comment

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

I like how cleanly you've kept the reuse between methodPatcher and middlewarePatcher - not too complex but still keeping the essential bits parameterized instead of copied+pasted.

Copy link
Member Author

Choose a reason for hiding this comment

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

Thanks! :)

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.

Looks awesome thanks for contributing

Copy link
Member

@vmarchaud vmarchaud left a comment

Choose a reason for hiding this comment

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

lgtm !

Copy link
Member

@obecny obecny left a comment

Choose a reason for hiding this comment

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

overall lgtm, just few issues

@rauno56
Copy link
Member Author

rauno56 commented Apr 14, 2021

I think I addressed everything except two totally valid points @obecny, brought up, I don't necessarily think are worth changing and would like a second opinion on:

  1. Renaming c to constants. Unnecessarily verbose in such a use-case in my view.
  2. Use of lodash.once. I think we should use quality well-known packages and not reimplement utilities, which would be more costly in the long run, especially in the case where some(most?) distros ship tons of instrumentations, used or not, anyways. We cannot avoid bringing in any 3rd party packages and we have done so in the past(shimmer, require-in-the-middle, etc.).

I don't have a strong technical preference in either of those points, more of a question of how much bikeshedding we want to go through in the long run and for me to calibrate how important maintainers generally think such questions are.

@vmarchaud vmarchaud self-requested a review April 14, 2021 20:11
@vmarchaud
Copy link
Member

vmarchaud commented Apr 14, 2021

I agree with @obecny here on both points:

  • i prefer verbosity for the sake of readability
    • our project is open source, so we expect a lot of people will review our code having constants over c make it easy to understand what the variable is, specially when reading on github and not within an IDE)
  • i prefer to not use a dependency to avoid having few more lines in our code
    • I don't agree with you by comparing lodash.once (which is 5 lines long that anyone could write without specific knowledge) and shimmer/require-in-the-middle which are battle tested with complex problem within NodeJS
    • Specially in this case i don't think its actually needed, the next callback shouldn't be called twice right ? And even if it did, nothing will happens (it will generate a warning log on the diagnostic logger which isn't logged by default) so its safe to remove it altogether

I don't have a strong technical preference in either of those points, more of a question of how much bikeshedding we want to go through in the long run and for me to calibrate how important maintainers generally think such questions are.

I agree with you on this however: that there are both technical preference. I don't like blocking PRs for those kind of choices (so i'll not) but i strongly recommend addressing them.

@rauno56
Copy link
Member Author

rauno56 commented Apr 15, 2021

Specially in this case i don't think its actually needed, the next callback shouldn't be called twice right ?

Yes, it is not supposed to, but restify doesn't error if it is called twice, just ignores it. There are other cases where it's not called at all. That did make me think about the cases with promises. Added checks for those.

Removed lodash.once and renamed c.

Thanks a lot @vmarchaud and @obecny for your input. It's highly appreciated! 🙏

@rauno56
Copy link
Member Author

rauno56 commented Apr 15, 2021

I don't agree with you by comparing lodash.once (which is 5 lines long that anyone could write without specific knowledge) and shimmer/require-in-the-middle which are battle tested with complex problem within NodeJS

I do wonder whether we should come up with another solution than implementing stuff ourselves if we have a utility in 3 instrumentations? 5? 15?

@vmarchaud
Copy link
Member

I do wonder whether we should come up with another solution than implementing stuff ourselves if we have a utility in 3 instrumentations? 5? 15?

We generally have them on the core package (https://github.com/open-telemetry/opentelemetry-js/tree/main/packages/opentelemetry-core/src/utils) or the instrumentation package itself (https://github.com/open-telemetry/opentelemetry-js/blob/main/packages/opentelemetry-instrumentation/src/utils.ts)

Copy link
Member

@vmarchaud vmarchaud left a comment

Choose a reason for hiding this comment

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

thanks taking the time to addressing all feedback :)

@vmarchaud vmarchaud requested a review from obecny April 15, 2021 07:38
@rauno56 rauno56 force-pushed the feat/restify-instrumentation branch from 67184f2 to f8bcb5c Compare April 15, 2021 15:53
Copy link
Member

@obecny obecny left a comment

Choose a reason for hiding this comment

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

lgtm, thx for changes

{
"name": "restify-example",
"private": true,
"version": "0.18.0",
Copy link
Member

Choose a reason for hiding this comment

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

Nit: 0.15.0 in core we have 0.18.x

Copy link
Member

@vmarchaud vmarchaud Apr 16, 2021

Choose a reason for hiding this comment

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

Version in examples are not kept in sync in this repo, i think it would be better to do it with lerna instead

EDit: #428

@obecny obecny added the enhancement New feature or request label Apr 15, 2021
@vmarchaud vmarchaud merged commit b7d84d1 into open-telemetry:main Apr 16, 2021
@rauno56 rauno56 mentioned this pull request Apr 16, 2021
@rauno56 rauno56 deleted the feat/restify-instrumentation branch May 13, 2021 08:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants