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(vue): Add Pinia plugin #13841

Merged
merged 10 commits into from
Oct 15, 2024
Merged

feat(vue): Add Pinia plugin #13841

merged 10 commits into from
Oct 15, 2024

Conversation

onurtemizkan
Copy link
Collaborator

@onurtemizkan onurtemizkan commented Oct 1, 2024

Resolves: #13279
Depends on: #13840
Sample Event

Docs PR: getsentry/sentry-docs#11516

Adds a Pinia plugin with a feature set similar to the Redux integration.

  • Attaches Pinia state as an attachment to the event (true by default)
  • Provides actionTransformer and stateTransformer to the user for potentially required PII modifications.
  • Adds breadcrumbs for Pinia actions
  • Assigns Pinia state to event contexts.

Copy link

codecov bot commented Oct 1, 2024

❌ 1 Tests Failed:

Tests completed Failed Passed Skipped
626 1 625 31
View the top 1 failed tests by shortest run time
pinia.test.ts sends pinia action breadcrumbs and state context
Stack Traces | 0.316s run time
pinia.test.ts:4:1 sends pinia action breadcrumbs and state context

To view individual test run time comparison to the main branch, go to the Test Analytics Dashboard

Copy link
Contributor

github-actions bot commented Oct 2, 2024

size-limit report 📦

Path Size % Change Change
@sentry/browser 22.73 KB - -
@sentry/browser - with treeshaking flags 21.53 KB - -
@sentry/browser (incl. Tracing) 35.01 KB - -
@sentry/browser (incl. Tracing, Replay) 71.67 KB - -
@sentry/browser (incl. Tracing, Replay) - with treeshaking flags 62.07 KB - -
@sentry/browser (incl. Tracing, Replay with Canvas) 76.01 KB - -
@sentry/browser (incl. Tracing, Replay, Feedback) 88.78 KB - -
@sentry/browser (incl. Tracing, Replay, Feedback, metrics) 90.63 KB - -
@sentry/browser (incl. metrics) 27 KB - -
@sentry/browser (incl. Feedback) 39.87 KB - -
@sentry/browser (incl. sendFeedback) 27.38 KB - -
@sentry/browser (incl. FeedbackAsync) 32.17 KB - -
@sentry/react 25.49 KB - -
@sentry/react (incl. Tracing) 37.97 KB - -
@sentry/vue 26.91 KB - -
@sentry/vue (incl. Tracing) 36.9 KB - -
@sentry/svelte 22.87 KB - -
CDN Bundle 24.11 KB - -
CDN Bundle (incl. Tracing) 36.84 KB - -
CDN Bundle (incl. Tracing, Replay) 71.47 KB - -
CDN Bundle (incl. Tracing, Replay, Feedback) 76.78 KB - -
CDN Bundle - uncompressed 70.7 KB - -
CDN Bundle (incl. Tracing) - uncompressed 109.36 KB - -
CDN Bundle (incl. Tracing, Replay) - uncompressed 221.71 KB - -
CDN Bundle (incl. Tracing, Replay, Feedback) - uncompressed 234.93 KB - -
@sentry/nextjs (client) 37.94 KB - -
@sentry/sveltekit (client) 35.6 KB - -
@sentry/node 124.9 KB - -
@sentry/node - without tracing 94.13 KB - -
@sentry/aws-serverless 103.7 KB - -

View base workflow run

@s1gr1d s1gr1d self-requested a review October 2, 2024 15:12
Copy link
Member

@s1gr1d s1gr1d 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 adding this 🙌

@@ -16,6 +16,7 @@
},
"dependencies": {
"@sentry/vue": "latest || *",
"pinia": "^2.2.3",
Copy link
Member

Choose a reason for hiding this comment

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

Should we add pinia as a peer dependency as well with major v2?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Sure, added pinia as an optional peer dependency. 👍

const options = client && client.getOptions();
const normalizationDepth = (options && options.normalizeDepth) || 3; // default state normalization depth to 3

const newStateContext = { state: { type: 'pinia', value: transformedState } };
Copy link
Member

Choose a reason for hiding this comment

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

H: Currently, the state context needs to be nested twice with state (docs here). This could change in the future as it is a bit confusing, but right now it still has to look that way to be understood by Sentry.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

This is assigned under store key in the context, so I guess it should comply with the current interface.

Copy link
Member

Choose a reason for hiding this comment

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

Ah right, I see it's there: scope.setContext('state', newStateContext);

Comment on lines 32 to 33
filename: 'pinia_state.json',
data: JSON.stringify(store.$state),
Copy link
Member

Choose a reason for hiding this comment

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

L: Can there be multiple files (because the linked event has two)? Users could benefit from having a timestamp in the filename as there can be multiple files in the attachments. Something like hh:mm_pinia_state would be enough.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Looks like these two are two different stores. So, I updated the file name format to include both the store id and the timestamp. Sample Event

Comment on lines 15 to 16
actionTransformer: (action: any) => any;
stateTransformer: (state: any) => any;
Copy link
Member

Choose a reason for hiding this comment

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

I think it would be nice to have tests for those :)

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Added 👍 c7cfa72

...(hint.attachments || []),
{
filename,
data: JSON.stringify(store.$state),
Copy link
Member

Choose a reason for hiding this comment

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

M: What just came to my mind: the store can contain PII, especially when pinia is used in forms. What do you think of adding the type of the value as the value? Like this:

name: string
likes: object

Copy link
Member

Choose a reason for hiding this comment

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

Since the pinia plugin needs to be added manually I would argue it is fine. Just having the type is basically useless for debugging.

Copy link

Choose a reason for hiding this comment

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

Stringifying the state as JSON will only work in some scenarios and fail in many others like Dates, Errors, Maps, Sets, and custom classes. I would recommend using https://github.com/Rich-Harris/devalue like Nuxt does to allow users to provide serializer and revivers. I would even recommend adding a custom one that uses a toJSON() method if it exists by default as a convention. I think, but I'm not sure, that Nuxt has something similar.

Copy link
Member

Choose a reason for hiding this comment

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

Hi, we are on a tight bundle-size budget so we need to be a bit careful what we pull in as deps.

What we definitely should do is wrap the stringify call in a try-catch because it can throw in certain situations.

Non-serializable data is tricky and I would recommend we do it in a follow-up if at all. Dates get serialized properly with ordinary JSON.stringify, errors, maps, and sets, will become objects (which is fine for now), and stringify already supports toJSON natively.

Copy link

Choose a reason for hiding this comment

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

The toJSON() was specific to devalue ofc. If users can opt-in to a fully compatible serializable solution, they would be able to put their app in a similar state with the serialized state and debug in dev mode, so I think it's nice to advocate for that! Since Map and Sets are common, it would be a shame to lose them fully by using JSON.stringify()`

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

So, this event processor logic is already in try-catch, so we're safe on that part. We can do a follow-up for serializing. Thanks for the review @posva!

Comment on lines 13 to 16
type SentryPiniaPluginOptions = {
attachPiniaState?: boolean;
actionTransformer: (action: any) => any;
stateTransformer: (state: any) => any;
Copy link
Member

Choose a reason for hiding this comment

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

In addition to having the entire options object be optional, I think all of the options individually should probably also be optional.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Updated: c8482b9

...(hint.attachments || []),
{
filename,
data: JSON.stringify(store.$state),
Copy link
Member

Choose a reason for hiding this comment

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

Since the pinia plugin needs to be added manually I would argue it is fine. Just having the type is basically useless for debugging.

const transformedAction = options.actionTransformer(context.name);

if (typeof transformedAction !== 'undefined' && transformedAction !== null) {
addBreadcrumb({
Copy link
Member

Choose a reason for hiding this comment

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

I would add an option to turn off creating breadcrumbs. From experience, some apps have a lot of state updates and breadcrumbs might be very spammy.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Updated: ea7ba22


scope.setContext('state', newStateContext);
} else {
scope.setContext('state', null);
Copy link
Member

Choose a reason for hiding this comment

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

Is there a way for us not to nuke the entire state context here but only the pinia state 🤔 I know it could be tricky and is a bit edge-casy but may be worth it.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Does this update make sense? 4a78c04

Copy link
Member

Choose a reason for hiding this comment

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

yes! perfect

Copy link
Member

@s1gr1d s1gr1d left a comment

Choose a reason for hiding this comment

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

LGTM 🙌

@s1gr1d s1gr1d merged commit ecf84e0 into develop Oct 15, 2024
147 checks passed
@s1gr1d s1gr1d deleted the onur/pinia-plugin branch October 15, 2024 08:44
@github-actions github-actions bot mentioned this pull request Oct 15, 2024
billyvg pushed a commit that referenced this pull request Oct 17, 2024
Resolves: #13279
Depends on: #13840 
[Sample
Event](https://sentry-sdks.sentry.io/issues/5939879614/?project=5429219&query=is%3Aunresolved%20issue.priority%3A%5Bhigh%2C%20medium%5D&referrer=issue-stream&sort=date&statsPeriod=1h&stream_index=0)

Docs PR: getsentry/sentry-docs#11516
 

Adds a Pinia plugin with a feature set similar to the Redux integration.

- Attaches Pinia state as an attachment to the event (`true` by default)
- Provides `actionTransformer` and `stateTransformer` to the user for
potentially required PII modifications.
- Adds breadcrumbs for Pinia actions
- Assigns Pinia state to event contexts.
alexandresoro pushed a commit to alexandresoro/ouca that referenced this pull request Oct 21, 2024
This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
| [@sentry/node](https://github.com/getsentry/sentry-javascript/tree/master/packages/node) ([source](https://github.com/getsentry/sentry-javascript)) | dependencies | minor | [`8.34.0` -> `8.35.0`](https://renovatebot.com/diffs/npm/@sentry%2fnode/8.34.0/8.35.0) |
| [@sentry/react](https://github.com/getsentry/sentry-javascript/tree/master/packages/react) ([source](https://github.com/getsentry/sentry-javascript)) | dependencies | minor | [`8.34.0` -> `8.35.0`](https://renovatebot.com/diffs/npm/@sentry%2freact/8.34.0/8.35.0) |

---

### Release Notes

<details>
<summary>getsentry/sentry-javascript (@&#8203;sentry/node)</summary>

### [`v8.35.0`](https://github.com/getsentry/sentry-javascript/blob/HEAD/CHANGELOG.md#8350)

[Compare Source](getsentry/sentry-javascript@8.34.0...8.35.0)

##### Beta release of the official Nuxt Sentry SDK

This release marks the beta release of the `@sentry/nuxt` Sentry SDK. For details on how to use it, check out the
[Sentry Nuxt SDK README](https://github.com/getsentry/sentry-javascript/tree/develop/packages/nuxt). Please reach out on
[GitHub](https://github.com/getsentry/sentry-javascript/issues/new/choose) if you have any feedback or concerns.

-   **feat(nuxt): Make dynamic import() wrapping default
    ([#&#8203;13958](getsentry/sentry-javascript#13958 (BREAKING)
-   **feat(nuxt): Add Rollup plugin to wrap server entry with `import()`
    ([#&#8203;13945](getsentry/sentry-javascript#13945

**It is no longer required to add a Node `--import` flag. Please update your start command to avoid initializing Sentry
twice (BREAKING CHANGE).** The SDK will now apply modifications during the build of your application to allow for
patching of libraries during runtime. If run into issues with this change, you can disable this behavior in your
`nuxt.config.ts` and use the `--import` flag instead:

```js
sentry: {
  dynamicImportForServerEntry: false;
}
```

-   **feat(nuxt): Respect user-provided source map generation settings
    ([#&#8203;14020](getsentry/sentry-javascript#14020

We now require you to explicitly enable sourcemaps for the clientside so that Sentry can un-minify your errors. We made
this change so source maps aren't accidentally leaked to the public. Enable source maps on the client as follows:

```js
export default defineNuxtConfig({
  sourcemap: {
    client: true,
  },
});
```

-   feat(nuxt): Log server instrumentation might not work in dev
    ([#&#8203;14021](getsentry/sentry-javascript#14021))
-   feat(nuxt): Add Http `responseHook` with `waitUntil`
    ([#&#8203;13986](getsentry/sentry-javascript#13986))

##### Important Changes

-   **feat(vue): Add Pinia plugin ([#&#8203;13841](getsentry/sentry-javascript#13841

Support for [Pinia](https://pinia.vuejs.org/) is added in this release for `@sentry/vue`. To capture Pinia state data,
add `createSentryPiniaPlugin()` to your Pinia store:

```javascript
import { createPinia } from 'pinia';
import { createSentryPiniaPlugin } from '@&#8203;sentry/vue';

const pinia = createPinia();

pinia.use(createSentryPiniaPlugin());
```

-   **feat(node): Implement Sentry-specific http instrumentation
    ([#&#8203;13763](getsentry/sentry-javascript#13763

This change introduces a new `SentryHttpInstrumentation` to handle non-span related HTTP instrumentation, allowing it to
run side-by-side with OTel's `HttpInstrumentation`. This improves support for custom OTel setups and avoids conflicts
with Sentry's instrumentation. Additionally, the `spans: false` option is reintroduced for `httpIntegration` to disable
span emission while still allowing custom `HttpInstrumentation` instances (`httpIntegration({ spans: false })`).

-   **feat(core): Make stream instrumentation opt-in
    ([#&#8203;13951](getsentry/sentry-javascript#13951

This change adds a new option `trackFetchStreamPerformance` to the browser tracing integration. Only when set to `true`,
Sentry will instrument streams via fetch.

##### Other Changes

-   feat(node): Expose `suppressTracing` API ([#&#8203;13875](getsentry/sentry-javascript#13875))
-   feat(replay): Do not log "timeout while trying to read resp body" as exception
    ([#&#8203;13965](getsentry/sentry-javascript#13965))
-   chore(node): Bump `@opentelemetry/instrumentation-express` to `0.43.0`
    ([#&#8203;13948](getsentry/sentry-javascript#13948))
-   chore(node): Bump `@opentelemetry/instrumentation-fastify` to `0.40.0`
    ([#&#8203;13983](getsentry/sentry-javascript#13983))
-   fix: Ensure type for `init` is correct in meta frameworks
    ([#&#8203;13938](getsentry/sentry-javascript#13938))
-   fix(core): `.set` the `sentry-trace` header instead of `.append`ing in fetch instrumentation
    ([#&#8203;13907](getsentry/sentry-javascript#13907))
-   fix(module): keep version for node ESM package ([#&#8203;13922](getsentry/sentry-javascript#13922))
-   fix(node): Ensure `ignoreOutgoingRequests` of `httpIntegration` applies to breadcrumbs
    ([#&#8203;13970](getsentry/sentry-javascript#13970))
-   fix(replay): Fix onError sampling when loading an expired buffered session
    ([#&#8203;13962](getsentry/sentry-javascript#13962))
-   fix(replay): Ignore older performance entries when starting manually
    ([#&#8203;13969](getsentry/sentry-javascript#13969))
-   perf(node): Truncate breadcrumb messages created by console integration
    ([#&#8203;14006](getsentry/sentry-javascript#14006))

Work in this release was contributed by [@&#8203;ZakrepaShe](https://github.com/ZakrepaShe) and [@&#8203;zhiyan114](https://github.com/zhiyan114). Thank you for your contributions!

</details>

---

### Configuration

📅 **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined).

🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about these updates again.

---

 - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box

---

This PR has been generated by [Renovate Bot](https://github.com/renovatebot/renovate).
<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiIzOC4xMjguNiIsInVwZGF0ZWRJblZlciI6IjM4LjEyOC42IiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6WyJkZXBlbmRlbmNpZXMiXX0=-->

Reviewed-on: https://git.tristess.app/alexandresoro/ouca/pulls/251
Reviewed-by: Alexandre Soro <code@soro.dev>
Co-authored-by: renovate <renovate@git.tristess.app>
Co-committed-by: renovate <renovate@git.tristess.app>
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.

Plugin for Pinia 🍍
4 participants