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

fix(instr-aws-sdk): @smithy/[email protected] change broke aws-sdk-v3 instrumentation #1913

Merged

Conversation

trentm
Copy link
Contributor

@trentm trentm commented Jan 25, 2024

TAV tests for instrumentation-aws-sdk are currently breaking. E.g.: https://github.com/open-telemetry/opentelemetry-js-contrib/actions/runs/7617703422/job/20747285913

...
 > @opentelemetry/[email protected] test-all-versions
> tav

-- required packages ["@aws-sdk/[email protected]"]
-- installing ["@aws-sdk/[email protected]"]
-- running test "npm run test" with @aws-sdk/client-sqs (env: {})
...
   81 passing (2s)
  7 pending
  3 failing

  1) instrumentation-aws-sdk-v3
       custom service behavior
         SQS
           sqs send add messaging attributes:
     Error: expect(received).toBe(expected) // Object.is equality

Expected: 1
Received: 0
      at Context.<anonymous> (test/aws-sdk-v3.test.ts:308:39)
      at processTicksAndRejections (internal/process/task_queues.js:95:5)

  2) instrumentation-aws-sdk-v3
       custom service behavior
         SQS
           sqs send message batch attributes:
     Error: expect(received).toBe(expected) // Object.is equality

Expected: 1
Received: 0
      at Context.<anonymous> (test/aws-sdk-v3.test.ts:374:39)
      at processTicksAndRejections (internal/process/task_queues.js:95:5)

  3) instrumentation-aws-sdk-v3
       custom service behavior
         SQS
           sqs receive add messaging attributes:
     Error: Timeout of 2000ms exceeded. For async tests and hooks, ensure "done()" is called; if returning a Promise, ensure it resolves. (/home/runner/work/opentelemetry-js-contrib/opentelemetry-js-contrib/plugins/node/opentelemetry-instrumentation-aws-sdk/test/aws-sdk-v3.test.ts)
      at listOnTimeout (internal/timers.js:557:17)
      at processTimers (internal/timers.js:500:7)

details

As of smithy-lang/smithy-typescript#1146
(details at smithy-lang/smithy-typescript#1113)
the CommonJS export for many (all?) @smithy/* packages is now an esbuild
bundle -- all in dist-cjs/index.js. That means that subfile patching like this
no longer works:

    const v3SmithyMiddlewareStackFile = new InstrumentationNodeModuleFile(
      '@smithy/middleware-stack/dist-cjs/MiddlewareStack.js',
      ['>=1.0.1'],
      this.patchV3ConstructStack.bind(this),
      this.unpatchV3ConstructStack.bind(this)
    );

In our case this breaks as of @smithy/[email protected] released
2024-01-17T22:26:42.432Z. This is considered a non-breaking change, so the
dependency ranges for earlier released versions of @smithy/smithy-client will
pick this up.

A fix is to change the @smithy/middleware-stack patching to be on the top-level
module exports. Because the constructStack field is only available as a getter
we cannot use shimmer (InstrumentationBase._wrap). Instead this returns a new
moduleExports object with a new getter that shims the call.

…dk-v3 instrumentation

As of smithy-lang/smithy-typescript#1146
(details at smithy-lang/smithy-typescript#1113)
the CommonJS export for many (all?) `@smithy/*` packages is now an esbuild
bundle -- all in `dist-cjs/index.js`. That means that subfile patching like this
no longer works:

```js
    const v3SmithyMiddlewareStackFile = new InstrumentationNodeModuleFile(
      '@smithy/middleware-stack/dist-cjs/MiddlewareStack.js',
      ['>=1.0.1'],
      this.patchV3ConstructStack.bind(this),
      this.unpatchV3ConstructStack.bind(this)
    );
```

In our case this breaks as of `@smithy/[email protected]` released
2024-01-17T22:26:42.432Z.  This is considered a non-breaking change, so the
dependency ranges for earlier released versions of `@smithy/smithy-client` will
pick this up.

A fix is to change the `@smithy/middleware-stack` patching to be on the top-level
module exports. Because the `constructStack` field is only available as a getter
we cannot use shimmer (InstrumentationBase._wrap). Instead this returns a new
`moduleExports` object with a new getter that shims the call.
Copy link

codecov bot commented Jan 25, 2024

Codecov Report

Merging #1913 (b66545e) into main (84e1a6b) will decrease coverage by 0.49%.
The diff coverage is 16.66%.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1913      +/-   ##
==========================================
- Coverage   91.50%   91.02%   -0.49%     
==========================================
  Files         145      146       +1     
  Lines        7431     7478      +47     
  Branches     1489     1497       +8     
==========================================
+ Hits         6800     6807       +7     
- Misses        631      671      +40     
Files Coverage Δ
...entelemetry-instrumentation-aws-sdk/src/aws-sdk.ts 95.12% <25.00%> (-2.37%) ⬇️
...ntelemetry-instrumentation-aws-sdk/src/propwrap.ts 15.00% <15.00%> (ø)

@trentm trentm marked this pull request as ready for review January 25, 2024 16:44
@trentm trentm requested a review from a team January 25, 2024 16:44
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Note for reviewers: I'm open to suggestions if we want this in a more shareable place. Or perhaps we consider that if/when there is some other instrumentation that requires a similar facility for wrapping.

Copy link
Member

@pichlermarc pichlermarc Jan 26, 2024

Choose a reason for hiding this comment

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

It's definitely useful to have it in a more shareable place. I think if we run into the same problem somewhere else, we can consider moving that to the @opentelemetry/instrumentation package.

}
);
return newExports;
}
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Note for reviewers: There is now no unwrapping. I'm not sure if that has possible adverse effects.

Copy link
Member

Choose a reason for hiding this comment

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

I have to admit i'm not as knowledgeable on this as I'd like. IIUC we use the unwrapping mostly for testing and ensuring we don't double wrap a library (using auto-instrumentations and aws-sdk instrumentation directly and registering the same one twice, or registering it twice, but with different instrumentation versions). It could also be that users want to disable the instrumentation on runtime for some reason (though, I've never seen such a thing done IRL).

Hoping that maybe @blumamir or @dyladan have more insights.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This was discussed in the OTel JS SIG today (https://docs.google.com/document/d/1tCyoQK49WVcE-x8oryZOTTToFm7sIeUhxFPm9g-qL1k/edit#heading=h.7y4kcwttgzlh). Dan suggested not having an unwrap would be fine. In his opinion (I hope I'm not misrepresenting), instrumentation unwrap functionality in general is really there for testing and probably isn't something to rely heavily on for production usage.

Copy link
Member

@pichlermarc pichlermarc left a comment

Choose a reason for hiding this comment

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

Interesting, thanks for tracking this down. 🙂
I'm missing some context on the unwrapping situation so I'm pinging @blumamir or @dyladan to please take a look.

Copy link
Member

@pichlermarc pichlermarc Jan 26, 2024

Choose a reason for hiding this comment

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

It's definitely useful to have it in a more shareable place. I think if we run into the same problem somewhere else, we can consider moving that to the @opentelemetry/instrumentation package.

}
);
return newExports;
}
Copy link
Member

Choose a reason for hiding this comment

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

I have to admit i'm not as knowledgeable on this as I'd like. IIUC we use the unwrapping mostly for testing and ensuring we don't double wrap a library (using auto-instrumentations and aws-sdk instrumentation directly and registering the same one twice, or registering it twice, but with different instrumentation versions). It could also be that users want to disable the instrumentation on runtime for some reason (though, I've never seen such a thing done IRL).

Hoping that maybe @blumamir or @dyladan have more insights.

@trentm
Copy link
Contributor Author

trentm commented Jan 31, 2024

FWIW, here is a test-all-versions run (locally) showing it passing for current versions of @aws-sdk/client-sqs:

% TAV=@aws-sdk/client-sqs npm run test-all-versions -- -q

> @opentelemetry/[email protected] test-all-versions
> tav -q

-- required packages ["@aws-sdk/[email protected]"]
-- installing ["@aws-sdk/[email protected]"]
-- running test "npm run test" with @aws-sdk/client-sqs (env: {})
-- required packages ["@aws-sdk/[email protected]"]
-- installing ["@aws-sdk/[email protected]"]
-- running test "npm run test" with @aws-sdk/client-sqs (env: {})
-- required packages ["@aws-sdk/[email protected]"]
-- installing ["@aws-sdk/[email protected]"]
-- running test "npm run test" with @aws-sdk/client-sqs (env: {})
-- required packages ["@aws-sdk/[email protected]"]
-- installing ["@aws-sdk/[email protected]"]
-- running test "npm run test" with @aws-sdk/client-sqs (env: {})
-- required packages ["@aws-sdk/[email protected]"]
-- installing ["@aws-sdk/[email protected]"]
-- running test "npm run test" with @aws-sdk/client-sqs (env: {})
-- required packages ["@aws-sdk/[email protected]"]
-- installing ["@aws-sdk/[email protected]"]
-- running test "npm run test" with @aws-sdk/client-sqs (env: {})
-- required packages ["@aws-sdk/[email protected]"]
-- installing ["@aws-sdk/[email protected]"]
-- running test "npm run test" with @aws-sdk/client-sqs (env: {})
-- required packages ["@aws-sdk/[email protected]"]
-- installing ["@aws-sdk/[email protected]"]
-- running test "npm run test" with @aws-sdk/client-sqs (env: {})
-- required packages ["@aws-sdk/[email protected]"]
-- installing ["@aws-sdk/[email protected]"]
-- running test "npm run test" with @aws-sdk/client-sqs (env: {})
-- required packages ["@aws-sdk/[email protected]"]
-- installing ["@aws-sdk/[email protected]"]
-- running test "npm run test" with @aws-sdk/client-sqs (env: {})
-- required packages ["@aws-sdk/[email protected]"]
-- installing ["@aws-sdk/[email protected]"]
-- running test "npm run test" with @aws-sdk/client-sqs (env: {})
-- required packages ["@aws-sdk/[email protected]"]
-- installing ["@aws-sdk/[email protected]"]
-- running test "npm run test" with @aws-sdk/client-sqs (env: {})
-- required packages ["@aws-sdk/[email protected]"]
-- installing ["@aws-sdk/[email protected]"]
-- running test "npm run test" with @aws-sdk/client-sqs (env: {})
-- required packages ["@aws-sdk/[email protected]"]
-- installing ["@aws-sdk/[email protected]"]
-- running test "npm run test" with @aws-sdk/client-sqs (env: {})
-- required packages ["@aws-sdk/[email protected]"]
-- installing ["@aws-sdk/[email protected]"]
-- running test "npm run test" with @aws-sdk/client-sqs (env: {})
-- required packages ["@aws-sdk/[email protected]"]
-- installing ["@aws-sdk/[email protected]"]
-- running test "npm run test" with @aws-sdk/client-sqs (env: {})
-- required packages ["@aws-sdk/[email protected]"]
-- installing ["@aws-sdk/[email protected]"]
-- running test "npm run test" with @aws-sdk/client-sqs (env: {})
-- required packages ["@aws-sdk/[email protected]"]
-- installing ["@aws-sdk/[email protected]"]
-- running test "npm run test" with @aws-sdk/client-sqs (env: {})
-- required packages ["@aws-sdk/[email protected]"]
-- installing ["@aws-sdk/[email protected]"]
-- running test "npm run test" with @aws-sdk/client-sqs (env: {})
-- required packages ["@aws-sdk/[email protected]"]
-- installing ["@aws-sdk/[email protected]"]
-- running test "npm run test" with @aws-sdk/client-sqs (env: {})
-- required packages ["@aws-sdk/[email protected]"]
-- installing ["@aws-sdk/[email protected]"]
-- running test "npm run test" with @aws-sdk/client-sqs (env: {})
-- required packages ["@aws-sdk/[email protected]"]
-- installing ["@aws-sdk/[email protected]"]
-- running test "npm run test" with @aws-sdk/client-sqs (env: {})
-- required packages ["@aws-sdk/[email protected]"]
-- installing ["@aws-sdk/[email protected]"]
-- running test "npm run test" with @aws-sdk/client-sqs (env: {})
-- required packages ["@aws-sdk/[email protected]"]
-- installing ["@aws-sdk/[email protected]"]
-- running test "npm run test" with @aws-sdk/client-sqs (env: {})
-- required packages ["@aws-sdk/[email protected]"]
-- installing ["@aws-sdk/[email protected]"]
-- running test "npm run test" with @aws-sdk/client-sqs (env: {})
-- required packages ["@aws-sdk/[email protected]"]
-- installing ["@aws-sdk/[email protected]"]
-- running test "npm run test" with @aws-sdk/client-sqs (env: {})
-- required packages ["@aws-sdk/[email protected]"]
-- installing ["@aws-sdk/[email protected]"]
-- running test "npm run test" with @aws-sdk/client-sqs (env: {})
-- ok

This was before I updated .tav.yml to reduce the number of versions tested.

@trentm
Copy link
Contributor Author

trentm commented Jan 31, 2024

Ready for review again, @pichlermarc PTAL if you have time. Thanks.

@trentm trentm requested a review from pichlermarc January 31, 2024 20:51
Copy link
Member

@pichlermarc pichlermarc left a comment

Choose a reason for hiding this comment

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

Thanks @trentm for taking the time to fix this 👍
Let's get this merged 🙂

@trentm trentm merged commit 7895306 into open-telemetry:main Feb 5, 2024
16 of 17 checks passed
@trentm trentm deleted the tm-fix-aws-sdk-v3-middleware-stack-break branch February 5, 2024 23:58
@dyladan dyladan mentioned this pull request Feb 6, 2024
HenryCorn pushed a commit to HenryCorn/opentelemetry-js-contrib that referenced this pull request Feb 6, 2024
…dk-v3 instrumentation (open-telemetry#1913)

As of smithy-lang/smithy-typescript#1146
(details at smithy-lang/smithy-typescript#1113)
the CommonJS export for many (all?) `@smithy/*` packages is now an esbuild
bundle -- all in `dist-cjs/index.js`. That means that subfile patching like this
no longer works:

```js
    const v3SmithyMiddlewareStackFile = new InstrumentationNodeModuleFile(
      '@smithy/middleware-stack/dist-cjs/MiddlewareStack.js',
      ['>=1.0.1'],
      this.patchV3ConstructStack.bind(this),
      this.unpatchV3ConstructStack.bind(this)
    );
```

In our case this breaks as of `@smithy/[email protected]` released
2024-01-17T22:26:42.432Z.  This is considered a non-breaking change, so the
dependency ranges for earlier released versions of `@smithy/smithy-client` will
pick this up.

A fix is to change the `@smithy/middleware-stack` patching to be on the top-level
module exports. Because the `constructStack` field is only available as a getter
we cannot use shimmer (InstrumentationBase._wrap). Instead this returns a new
`moduleExports` object with a new getter that shims the call

This PR also updates .tav.yml to reduce the number of aws-sdk package versions tested.
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.

3 participants