Skip to content

Commit 6cfe78b

Browse files
committed
store server_action_form_data in flattened form
1 parent c5939d2 commit 6cfe78b

File tree

2 files changed

+34
-42
lines changed

2 files changed

+34
-42
lines changed

dev-packages/e2e-tests/test-applications/nextjs-app-dir/tests/transactions.test.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -130,9 +130,9 @@ test('Should send a transaction for instrumented server actions', async ({ page
130130
await page.getByText('Run Action').click();
131131

132132
expect(await serverComponentTransactionPromise).toBeDefined();
133-
expect((await serverComponentTransactionPromise).contexts?.trace?.data?.['server_action_form_data']).toEqual(
134-
expect.objectContaining({ 'some-text-value': 'some-default-value' }),
135-
);
133+
expect(
134+
(await serverComponentTransactionPromise).contexts?.trace?.data?.['server_action_form_data.some-text-value'],
135+
).toEqual('some-default-value');
136136
expect((await serverComponentTransactionPromise).contexts?.trace?.data?.['server_action_result']).toEqual({
137137
city: 'Vienna',
138138
});

packages/nextjs/src/common/withServerActionInstrumentation.ts

Lines changed: 31 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import {
66
handleCallbackErrors,
77
runWithAsyncContext,
88
startSpan,
9-
withScope,
109
} from '@sentry/core';
1110
import { logger, tracingContextFromHeaders } from '@sentry/utils';
1211

@@ -85,48 +84,41 @@ async function withServerActionInstrumentationImplementation<A extends (...args:
8584

8685
let res;
8786
try {
88-
res = await withScope(scope => {
89-
if (options.formData) {
90-
const formDataObject: Record<string, unknown> = {};
91-
options.formData.forEach((value, key) => {
92-
if (typeof value === 'string') {
93-
formDataObject[key] = value;
94-
} else {
95-
formDataObject[key] = '[non-string value]';
96-
}
97-
});
98-
// Since formDataObject is not a primitive, we cannot store it on the span as attributes
99-
// so instead we put it as extra on the scope
100-
scope.setExtra('server_action_form_data', formDataObject);
101-
}
102-
103-
return startSpan(
104-
{
105-
op: 'function.server_action',
106-
name: `serverAction/${serverActionName}`,
107-
status: 'ok',
108-
...traceparentData,
109-
metadata: {
110-
source: 'route',
111-
dynamicSamplingContext: traceparentData && !dynamicSamplingContext ? {} : dynamicSamplingContext,
112-
request: {
113-
headers: fullHeadersObject,
114-
},
87+
res = startSpan(
88+
{
89+
op: 'function.server_action',
90+
name: `serverAction/${serverActionName}`,
91+
status: 'ok',
92+
...traceparentData,
93+
metadata: {
94+
source: 'route',
95+
dynamicSamplingContext: traceparentData && !dynamicSamplingContext ? {} : dynamicSamplingContext,
96+
request: {
97+
headers: fullHeadersObject,
11598
},
11699
},
117-
async span => {
118-
const result = await handleCallbackErrors(callback, error => {
119-
captureException(error, { mechanism: { handled: false } });
120-
});
100+
},
101+
async span => {
102+
const result = await handleCallbackErrors(callback, error => {
103+
captureException(error, { mechanism: { handled: false } });
104+
});
121105

122-
if (options.recordResponse !== undefined ? options.recordResponse : sendDefaultPii) {
123-
span?.setAttribute('server_action_result', result);
124-
}
106+
if (options.recordResponse !== undefined ? options.recordResponse : sendDefaultPii) {
107+
span?.setAttribute('server_action_result', result);
108+
}
125109

126-
return result;
127-
},
128-
);
129-
});
110+
if (options.formData) {
111+
options.formData.forEach((value, key) => {
112+
span?.setAttribute(
113+
`server_action_form_data.${key}`,
114+
typeof value === 'string' ? value : '[non-string value]',
115+
);
116+
});
117+
}
118+
119+
return result;
120+
},
121+
);
130122
} finally {
131123
if (!platformSupportsStreaming()) {
132124
// Lambdas require manual flushing to prevent execution freeze before the event is sent

0 commit comments

Comments
 (0)