@parca/profile 0.19.30 → 0.19.32
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +8 -0
- package/dist/ProfileExplorer/index.d.ts.map +1 -1
- package/dist/ProfileExplorer/index.js +4 -12
- package/dist/ProfileSelector/useAutoQuerySelector.js +2 -2
- package/dist/ProfileSource.js +1 -1
- package/dist/ProfileView/components/ProfileFilters/filterPresets.d.ts +2 -0
- package/dist/ProfileView/components/ProfileFilters/filterPresets.d.ts.map +1 -1
- package/dist/ProfileView/components/ProfileFilters/filterPresets.js +30 -0
- package/dist/ProfileView/components/ProfileFilters/index.d.ts.map +1 -1
- package/dist/ProfileView/components/ProfileFilters/index.js +7 -3
- package/dist/ProfileView/components/ProfileFilters/useProfileFiltersUrlState.js +3 -3
- package/package.json +6 -6
- package/src/ProfileExplorer/index.tsx +4 -19
- package/src/ProfileSelector/useAutoQuerySelector.ts +2 -2
- package/src/ProfileSource.tsx +1 -1
- package/src/ProfileView/components/ProfileFilters/filterPresets.ts +31 -0
- package/src/ProfileView/components/ProfileFilters/index.tsx +8 -3
- package/src/ProfileView/components/ProfileFilters/useProfileFiltersUrlState.ts +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,14 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
## [0.19.32](https://github.com/parca-dev/parca/compare/@parca/profile@0.19.31...@parca/profile@0.19.32) (2025-08-06)
|
|
7
|
+
|
|
8
|
+
**Note:** Version bump only for package @parca/profile
|
|
9
|
+
|
|
10
|
+
## [0.19.31](https://github.com/parca-dev/parca/compare/@parca/profile@0.19.30...@parca/profile@0.19.31) (2025-08-04)
|
|
11
|
+
|
|
12
|
+
**Note:** Version bump only for package @parca/profile
|
|
13
|
+
|
|
6
14
|
## 0.19.30 (2025-07-29)
|
|
7
15
|
|
|
8
16
|
**Note:** Version bump only for package @parca/profile
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/ProfileExplorer/index.tsx"],"names":[],"mappings":"AAiBA,OAAO,EAAC,kBAAkB,EAAC,MAAM,eAAe,CAAC;AAIjD,OAAO,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/ProfileExplorer/index.tsx"],"names":[],"mappings":"AAiBA,OAAO,EAAC,kBAAkB,EAAC,MAAM,eAAe,CAAC;AAIjD,OAAO,EAAwC,KAAK,gBAAgB,EAAC,MAAM,kBAAkB,CAAC;AAU9F,UAAU,oBAAoB;IAC5B,WAAW,EAAE,kBAAkB,CAAC;IAChC,WAAW,EAAE,GAAG,CAAC;IACjB,UAAU,EAAE,gBAAgB,CAAC;CAC9B;AAaD,eAAO,MAAM,sBAAsB,GAAI,YAAY,MAAM,GAAG,EAAE,KAAG,MAGhE,CAAC;AAiBF,eAAO,MAAM,iBAAiB,GAAI,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,KAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAiB5E,CAAC;AA4TF,QAAA,MAAM,eAAe,GAAI,2CAItB,oBAAoB,KAAG,GAAG,CAAC,OAkB7B,CAAC;AAEF,eAAe,eAAe,CAAC"}
|
|
@@ -16,7 +16,7 @@ import { Provider } from 'react-redux';
|
|
|
16
16
|
import { DateTimeRange, KeyDownProvider, useParcaContext } from '@parca/components';
|
|
17
17
|
import { Query } from '@parca/parser';
|
|
18
18
|
import { createStore } from '@parca/store';
|
|
19
|
-
import { capitalizeOnlyFirstLetter,
|
|
19
|
+
import { capitalizeOnlyFirstLetter, safeDecode } from '@parca/utilities';
|
|
20
20
|
import { ProfileSelectionFromParams, SuffixParams } from '..';
|
|
21
21
|
import { useProfileTypes } from '../ProfileSelector';
|
|
22
22
|
import { useResetStateOnNewSearch } from '../ProfileView/hooks/useResetStateOnNewSearch';
|
|
@@ -57,14 +57,6 @@ export const filterEmptyParams = (o) => {
|
|
|
57
57
|
const filterSuffix = (o, suffix) => Object.fromEntries(Object.entries(o)
|
|
58
58
|
.filter(([key]) => !key.endsWith(suffix))
|
|
59
59
|
.map(([key, value]) => {
|
|
60
|
-
if (typeof value === 'string') {
|
|
61
|
-
// Only encode if not already encoded
|
|
62
|
-
return [key, isUrlEncoded(value) ? value : encodeURIComponent(value)];
|
|
63
|
-
}
|
|
64
|
-
if (Array.isArray(value)) {
|
|
65
|
-
// Only encode array values if not already encoded
|
|
66
|
-
return [key, value.map(v => (isUrlEncoded(v) ? v : encodeURIComponent(v)))];
|
|
67
|
-
}
|
|
68
60
|
return [key, value];
|
|
69
61
|
}));
|
|
70
62
|
const swapQueryParameters = (o) => {
|
|
@@ -131,9 +123,9 @@ const ProfileExplorerApp = ({ queryClient, queryParams, navigateTo, }) => {
|
|
|
131
123
|
from_a = sanitizedRange.from_a;
|
|
132
124
|
to_a = sanitizedRange.to_a;
|
|
133
125
|
if ((queryParams?.expression_a ?? '') !== '')
|
|
134
|
-
queryParams.expression_a =
|
|
126
|
+
queryParams.expression_a = safeDecode(expression_a);
|
|
135
127
|
if ((queryParams?.expression_b ?? '') !== '')
|
|
136
|
-
queryParams.expression_b =
|
|
128
|
+
queryParams.expression_b = safeDecode(expression_b);
|
|
137
129
|
const selectProfile = (p, suffix) => {
|
|
138
130
|
return navigateTo('/', {
|
|
139
131
|
...queryParams,
|
|
@@ -209,7 +201,7 @@ const ProfileExplorerApp = ({ queryClient, queryParams, navigateTo, }) => {
|
|
|
209
201
|
? {
|
|
210
202
|
merge_from_a: q.mergeFrom,
|
|
211
203
|
merge_to_a: q.mergeTo,
|
|
212
|
-
selection_a:
|
|
204
|
+
selection_a: q.expression,
|
|
213
205
|
}
|
|
214
206
|
: {};
|
|
215
207
|
return navigateTo('/',
|
|
@@ -39,12 +39,12 @@ export const useAutoQuerySelector = ({ selectedProfileName, profileTypesData, se
|
|
|
39
39
|
const sumBy = queryA.sumBy?.join(',');
|
|
40
40
|
let compareQuery = {
|
|
41
41
|
compare_a: 'true',
|
|
42
|
-
expression_a:
|
|
42
|
+
expression_a: queryA.expression,
|
|
43
43
|
from_a: queryA.from.toString(),
|
|
44
44
|
to_a: queryA.to.toString(),
|
|
45
45
|
time_selection_a: queryA.timeSelection,
|
|
46
46
|
compare_b: 'true',
|
|
47
|
-
expression_b:
|
|
47
|
+
expression_b: queryA.expression,
|
|
48
48
|
from_b: queryA.from.toString(),
|
|
49
49
|
to_b: queryA.to.toString(),
|
|
50
50
|
time_selection_b: queryA.timeSelection,
|
package/dist/ProfileSource.js
CHANGED
|
@@ -4,8 +4,10 @@ export interface FilterPreset {
|
|
|
4
4
|
name: string;
|
|
5
5
|
description: string;
|
|
6
6
|
filters: Array<Omit<ProfileFilter, 'id'>>;
|
|
7
|
+
allowedProfileTypes?: string[];
|
|
7
8
|
}
|
|
8
9
|
export declare const filterPresets: FilterPreset[];
|
|
9
10
|
export declare const isPresetKey: (key: string) => boolean;
|
|
10
11
|
export declare const getPresetByKey: (key: string) => FilterPreset | undefined;
|
|
12
|
+
export declare const getPresetsForProfileType: (profileType?: string) => FilterPreset[];
|
|
11
13
|
//# sourceMappingURL=filterPresets.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"filterPresets.d.ts","sourceRoot":"","sources":["../../../../src/ProfileView/components/ProfileFilters/filterPresets.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAC,aAAa,EAAC,MAAM,qBAAqB,CAAC;AAEvD,MAAM,WAAW,YAAY;IAC3B,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,KAAK,CAAC,IAAI,CAAC,aAAa,EAAE,IAAI,CAAC,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"filterPresets.d.ts","sourceRoot":"","sources":["../../../../src/ProfileView/components/ProfileFilters/filterPresets.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAC,aAAa,EAAC,MAAM,qBAAqB,CAAC;AAEvD,MAAM,WAAW,YAAY;IAC3B,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,KAAK,CAAC,IAAI,CAAC,aAAa,EAAE,IAAI,CAAC,CAAC,CAAC;IAC1C,mBAAmB,CAAC,EAAE,MAAM,EAAE,CAAC;CAChC;AAED,eAAO,MAAM,aAAa,EAAE,YAAY,EAkEvC,CAAC;AAIF,eAAO,MAAM,WAAW,GAAI,KAAK,MAAM,KAAG,OAEzC,CAAC;AAEF,eAAO,MAAM,cAAc,GAAI,KAAK,MAAM,KAAG,YAAY,GAAG,SAE3D,CAAC;AAEF,eAAO,MAAM,wBAAwB,GAAI,cAAc,MAAM,KAAG,YAAY,EAO3E,CAAC"}
|
|
@@ -15,6 +15,7 @@ export const filterPresets = [
|
|
|
15
15
|
key: 'go_runtime_expected_off_cpu',
|
|
16
16
|
name: 'Go Runtime Expected Off-CPU',
|
|
17
17
|
description: 'Excludes expected Go runtime blocking functions',
|
|
18
|
+
allowedProfileTypes: ['parca_agent:wallclock:nanoseconds:samples:count:delta'],
|
|
18
19
|
filters: [
|
|
19
20
|
{
|
|
20
21
|
type: 'stack',
|
|
@@ -34,6 +35,7 @@ export const filterPresets = [
|
|
|
34
35
|
key: 'rust_runtime_expected_off_cpu',
|
|
35
36
|
name: 'Rust Expected Off-CPU',
|
|
36
37
|
description: 'Excludes expected Rust runtime blocking functions',
|
|
38
|
+
allowedProfileTypes: ['parca_agent:wallclock:nanoseconds:samples:count:delta'],
|
|
37
39
|
filters: [
|
|
38
40
|
{
|
|
39
41
|
type: 'stack',
|
|
@@ -55,6 +57,25 @@ export const filterPresets = [
|
|
|
55
57
|
},
|
|
56
58
|
],
|
|
57
59
|
},
|
|
60
|
+
{
|
|
61
|
+
key: 'hide_v8_internals',
|
|
62
|
+
name: 'Hide V8 internals',
|
|
63
|
+
description: 'Excludes Node.js and V8 internal functions from the profile',
|
|
64
|
+
filters: [
|
|
65
|
+
{
|
|
66
|
+
type: 'frame',
|
|
67
|
+
field: 'binary',
|
|
68
|
+
matchType: 'not_contains',
|
|
69
|
+
value: 'node',
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
type: 'frame',
|
|
73
|
+
field: 'function_name',
|
|
74
|
+
matchType: 'not_contains',
|
|
75
|
+
value: 'V8',
|
|
76
|
+
},
|
|
77
|
+
],
|
|
78
|
+
},
|
|
58
79
|
];
|
|
59
80
|
const presetKeys = new Set(filterPresets.map(preset => preset.key));
|
|
60
81
|
export const isPresetKey = (key) => {
|
|
@@ -63,3 +84,12 @@ export const isPresetKey = (key) => {
|
|
|
63
84
|
export const getPresetByKey = (key) => {
|
|
64
85
|
return filterPresets.find(preset => preset.key === key);
|
|
65
86
|
};
|
|
87
|
+
export const getPresetsForProfileType = (profileType) => {
|
|
88
|
+
if (profileType === undefined || profileType === '')
|
|
89
|
+
return filterPresets;
|
|
90
|
+
return filterPresets.filter(preset => {
|
|
91
|
+
if (preset.allowedProfileTypes === undefined)
|
|
92
|
+
return true;
|
|
93
|
+
return preset.allowedProfileTypes.includes(profileType);
|
|
94
|
+
});
|
|
95
|
+
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/ProfileView/components/ProfileFilters/index.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/ProfileView/components/ProfileFilters/index.tsx"],"names":[],"mappings":"AAsBA,OAAO,EAAoB,KAAK,aAAa,EAAC,MAAM,qBAAqB,CAAC;AAE1E,eAAO,MAAM,gBAAgB,GAAI,QAAQ,aAAa,KAAG,OASxD,CAAC;AAyIF,QAAA,MAAM,cAAc,QAAO,GAAG,CAAC,OAmL9B,CAAC;AAEF,eAAe,cAAc,CAAC"}
|
|
@@ -15,7 +15,8 @@ import { useCallback } from 'react';
|
|
|
15
15
|
import { Icon } from '@iconify/react';
|
|
16
16
|
import cx from 'classnames';
|
|
17
17
|
import { Button, Input, Select } from '@parca/components';
|
|
18
|
-
import {
|
|
18
|
+
import { useProfileViewContext } from '../../context/ProfileViewContext';
|
|
19
|
+
import { getPresetByKey, getPresetsForProfileType, isPresetKey } from './filterPresets';
|
|
19
20
|
import { useProfileFilters } from './useProfileFilters';
|
|
20
21
|
export const isFilterComplete = (filter) => {
|
|
21
22
|
// For preset filters, only need type and value
|
|
@@ -25,7 +26,7 @@ export const isFilterComplete = (filter) => {
|
|
|
25
26
|
// For regular filters, need all fields
|
|
26
27
|
return (filter.value !== '' && filter.type != null && filter.field != null && filter.matchType != null);
|
|
27
28
|
};
|
|
28
|
-
const
|
|
29
|
+
const getFilterTypeItems = (currentProfileType) => [
|
|
29
30
|
{
|
|
30
31
|
key: 'stack',
|
|
31
32
|
element: {
|
|
@@ -40,7 +41,7 @@ const filterTypeItems = [
|
|
|
40
41
|
expanded: (_jsxs(_Fragment, { children: [_jsx("span", { children: "Frame Filter" }), _jsx("br", {}), _jsx("span", { className: "text-xs", children: "Filters individual frames" })] })),
|
|
41
42
|
},
|
|
42
43
|
},
|
|
43
|
-
...
|
|
44
|
+
...getPresetsForProfileType(currentProfileType).map(preset => ({
|
|
44
45
|
key: preset.key,
|
|
45
46
|
element: {
|
|
46
47
|
active: _jsx(_Fragment, { children: preset.name }),
|
|
@@ -139,6 +140,9 @@ const numberMatchTypeItems = [
|
|
|
139
140
|
},
|
|
140
141
|
];
|
|
141
142
|
const ProfileFilters = () => {
|
|
143
|
+
const { profileSource } = useProfileViewContext();
|
|
144
|
+
const currentProfileType = profileSource?.ProfileType()?.toString();
|
|
145
|
+
const filterTypeItems = getFilterTypeItems(currentProfileType);
|
|
142
146
|
const { localFilters, appliedFilters, hasUnsavedChanges, onApplyFilters, addFilter, removeFilter, updateFilter, resetFilters, } = useProfileFilters();
|
|
143
147
|
const handleKeyDown = useCallback((e) => {
|
|
144
148
|
if (e.key === 'Enter') {
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
// See the License for the specific language governing permissions and
|
|
12
12
|
// limitations under the License.
|
|
13
13
|
import { useURLStateCustom } from '@parca/components';
|
|
14
|
-
import {
|
|
14
|
+
import { safeDecode } from '@parca/utilities';
|
|
15
15
|
import { isPresetKey } from './filterPresets';
|
|
16
16
|
// Compact encoding mappings
|
|
17
17
|
const TYPE_MAP = {
|
|
@@ -63,8 +63,8 @@ export const decodeProfileFilters = (encoded) => {
|
|
|
63
63
|
if (encoded === '' || encoded === undefined)
|
|
64
64
|
return [];
|
|
65
65
|
try {
|
|
66
|
-
//
|
|
67
|
-
const decodedString =
|
|
66
|
+
// Decode once since we fixed the double encoding issue
|
|
67
|
+
const decodedString = safeDecode(encoded);
|
|
68
68
|
return decodedString.split(',').map((filter, index) => {
|
|
69
69
|
const parts = filter.split(':');
|
|
70
70
|
// Handle preset filters (format: p:presetKey:value)
|
package/package.json
CHANGED
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@parca/profile",
|
|
3
|
-
"version": "0.19.
|
|
3
|
+
"version": "0.19.32",
|
|
4
4
|
"description": "Profile viewing libraries",
|
|
5
5
|
"dependencies": {
|
|
6
6
|
"@floating-ui/react": "^0.27.12",
|
|
7
7
|
"@headlessui/react": "^1.7.19",
|
|
8
8
|
"@iconify/react": "^4.0.0",
|
|
9
9
|
"@parca/client": "0.17.3",
|
|
10
|
-
"@parca/components": "0.16.
|
|
10
|
+
"@parca/components": "0.16.354",
|
|
11
11
|
"@parca/dynamicsize": "0.16.65",
|
|
12
|
-
"@parca/hooks": "0.0.
|
|
12
|
+
"@parca/hooks": "0.0.99",
|
|
13
13
|
"@parca/icons": "0.16.72",
|
|
14
14
|
"@parca/parser": "0.16.79",
|
|
15
|
-
"@parca/store": "0.16.
|
|
16
|
-
"@parca/utilities": "0.0.
|
|
15
|
+
"@parca/store": "0.16.183",
|
|
16
|
+
"@parca/utilities": "0.0.106",
|
|
17
17
|
"@popperjs/core": "^2.11.8",
|
|
18
18
|
"@protobuf-ts/runtime-rpc": "^2.5.0",
|
|
19
19
|
"@storybook/preview-api": "^8.4.3",
|
|
@@ -78,5 +78,5 @@
|
|
|
78
78
|
"access": "public",
|
|
79
79
|
"registry": "https://registry.npmjs.org/"
|
|
80
80
|
},
|
|
81
|
-
"gitHead": "
|
|
81
|
+
"gitHead": "5eb160b1e3617d6add4a82d4b943852485937fbd"
|
|
82
82
|
}
|
|
@@ -19,12 +19,7 @@ import {QueryServiceClient} from '@parca/client';
|
|
|
19
19
|
import {DateTimeRange, KeyDownProvider, useParcaContext} from '@parca/components';
|
|
20
20
|
import {Query} from '@parca/parser';
|
|
21
21
|
import {createStore} from '@parca/store';
|
|
22
|
-
import {
|
|
23
|
-
capitalizeOnlyFirstLetter,
|
|
24
|
-
decodeMultipleEncodings,
|
|
25
|
-
isUrlEncoded,
|
|
26
|
-
type NavigateFunction,
|
|
27
|
-
} from '@parca/utilities';
|
|
22
|
+
import {capitalizeOnlyFirstLetter, safeDecode, type NavigateFunction} from '@parca/utilities';
|
|
28
23
|
|
|
29
24
|
import {ProfileSelection, ProfileSelectionFromParams, SuffixParams} from '..';
|
|
30
25
|
import {QuerySelection, useProfileTypes} from '../ProfileSelector';
|
|
@@ -98,14 +93,6 @@ const filterSuffix = (
|
|
|
98
93
|
Object.entries(o)
|
|
99
94
|
.filter(([key]) => !key.endsWith(suffix))
|
|
100
95
|
.map(([key, value]) => {
|
|
101
|
-
if (typeof value === 'string') {
|
|
102
|
-
// Only encode if not already encoded
|
|
103
|
-
return [key, isUrlEncoded(value) ? value : encodeURIComponent(value)];
|
|
104
|
-
}
|
|
105
|
-
if (Array.isArray(value)) {
|
|
106
|
-
// Only encode array values if not already encoded
|
|
107
|
-
return [key, value.map(v => (isUrlEncoded(v) ? v : encodeURIComponent(v)))];
|
|
108
|
-
}
|
|
109
96
|
return [key, value];
|
|
110
97
|
})
|
|
111
98
|
);
|
|
@@ -227,10 +214,8 @@ const ProfileExplorerApp = ({
|
|
|
227
214
|
from_a = sanitizedRange.from_a;
|
|
228
215
|
to_a = sanitizedRange.to_a;
|
|
229
216
|
|
|
230
|
-
if ((queryParams?.expression_a ?? '') !== '')
|
|
231
|
-
|
|
232
|
-
if ((queryParams?.expression_b ?? '') !== '')
|
|
233
|
-
queryParams.expression_b = decodeMultipleEncodings(expression_b);
|
|
217
|
+
if ((queryParams?.expression_a ?? '') !== '') queryParams.expression_a = safeDecode(expression_a);
|
|
218
|
+
if ((queryParams?.expression_b ?? '') !== '') queryParams.expression_b = safeDecode(expression_b);
|
|
234
219
|
|
|
235
220
|
const selectProfile = (p: ProfileSelection, suffix: string): void => {
|
|
236
221
|
return navigateTo('/', {
|
|
@@ -328,7 +313,7 @@ const ProfileExplorerApp = ({
|
|
|
328
313
|
? {
|
|
329
314
|
merge_from_a: q.mergeFrom,
|
|
330
315
|
merge_to_a: q.mergeTo,
|
|
331
|
-
selection_a:
|
|
316
|
+
selection_a: q.expression,
|
|
332
317
|
}
|
|
333
318
|
: {};
|
|
334
319
|
return navigateTo(
|
|
@@ -72,13 +72,13 @@ export const useAutoQuerySelector = ({
|
|
|
72
72
|
|
|
73
73
|
let compareQuery: Record<string, string> = {
|
|
74
74
|
compare_a: 'true',
|
|
75
|
-
expression_a:
|
|
75
|
+
expression_a: queryA.expression,
|
|
76
76
|
from_a: queryA.from.toString(),
|
|
77
77
|
to_a: queryA.to.toString(),
|
|
78
78
|
time_selection_a: queryA.timeSelection,
|
|
79
79
|
|
|
80
80
|
compare_b: 'true',
|
|
81
|
-
expression_b:
|
|
81
|
+
expression_b: queryA.expression,
|
|
82
82
|
from_b: queryA.from.toString(),
|
|
83
83
|
to_b: queryA.to.toString(),
|
|
84
84
|
time_selection_b: queryA.timeSelection,
|
package/src/ProfileSource.tsx
CHANGED
|
@@ -110,7 +110,7 @@ export class MergedProfileSelection implements ProfileSelection {
|
|
|
110
110
|
return {
|
|
111
111
|
merge_from: this.mergeFrom.toString(),
|
|
112
112
|
merge_to: this.mergeTo.toString(),
|
|
113
|
-
selection:
|
|
113
|
+
selection: this.query.toString(),
|
|
114
114
|
};
|
|
115
115
|
}
|
|
116
116
|
|
|
@@ -18,6 +18,7 @@ export interface FilterPreset {
|
|
|
18
18
|
name: string;
|
|
19
19
|
description: string;
|
|
20
20
|
filters: Array<Omit<ProfileFilter, 'id'>>;
|
|
21
|
+
allowedProfileTypes?: string[];
|
|
21
22
|
}
|
|
22
23
|
|
|
23
24
|
export const filterPresets: FilterPreset[] = [
|
|
@@ -25,6 +26,7 @@ export const filterPresets: FilterPreset[] = [
|
|
|
25
26
|
key: 'go_runtime_expected_off_cpu',
|
|
26
27
|
name: 'Go Runtime Expected Off-CPU',
|
|
27
28
|
description: 'Excludes expected Go runtime blocking functions',
|
|
29
|
+
allowedProfileTypes: ['parca_agent:wallclock:nanoseconds:samples:count:delta'],
|
|
28
30
|
filters: [
|
|
29
31
|
{
|
|
30
32
|
type: 'stack',
|
|
@@ -44,6 +46,7 @@ export const filterPresets: FilterPreset[] = [
|
|
|
44
46
|
key: 'rust_runtime_expected_off_cpu',
|
|
45
47
|
name: 'Rust Expected Off-CPU',
|
|
46
48
|
description: 'Excludes expected Rust runtime blocking functions',
|
|
49
|
+
allowedProfileTypes: ['parca_agent:wallclock:nanoseconds:samples:count:delta'],
|
|
47
50
|
filters: [
|
|
48
51
|
{
|
|
49
52
|
type: 'stack',
|
|
@@ -65,6 +68,25 @@ export const filterPresets: FilterPreset[] = [
|
|
|
65
68
|
},
|
|
66
69
|
],
|
|
67
70
|
},
|
|
71
|
+
{
|
|
72
|
+
key: 'hide_v8_internals',
|
|
73
|
+
name: 'Hide V8 internals',
|
|
74
|
+
description: 'Excludes Node.js and V8 internal functions from the profile',
|
|
75
|
+
filters: [
|
|
76
|
+
{
|
|
77
|
+
type: 'frame',
|
|
78
|
+
field: 'binary',
|
|
79
|
+
matchType: 'not_contains',
|
|
80
|
+
value: 'node',
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
type: 'frame',
|
|
84
|
+
field: 'function_name',
|
|
85
|
+
matchType: 'not_contains',
|
|
86
|
+
value: 'V8',
|
|
87
|
+
},
|
|
88
|
+
],
|
|
89
|
+
},
|
|
68
90
|
];
|
|
69
91
|
|
|
70
92
|
const presetKeys = new Set(filterPresets.map(preset => preset.key));
|
|
@@ -76,3 +98,12 @@ export const isPresetKey = (key: string): boolean => {
|
|
|
76
98
|
export const getPresetByKey = (key: string): FilterPreset | undefined => {
|
|
77
99
|
return filterPresets.find(preset => preset.key === key);
|
|
78
100
|
};
|
|
101
|
+
|
|
102
|
+
export const getPresetsForProfileType = (profileType?: string): FilterPreset[] => {
|
|
103
|
+
if (profileType === undefined || profileType === '') return filterPresets;
|
|
104
|
+
|
|
105
|
+
return filterPresets.filter(preset => {
|
|
106
|
+
if (preset.allowedProfileTypes === undefined) return true;
|
|
107
|
+
return preset.allowedProfileTypes.includes(profileType);
|
|
108
|
+
});
|
|
109
|
+
};
|
|
@@ -18,7 +18,8 @@ import cx from 'classnames';
|
|
|
18
18
|
|
|
19
19
|
import {Button, Input, Select, type SelectItem} from '@parca/components';
|
|
20
20
|
|
|
21
|
-
import {
|
|
21
|
+
import {useProfileViewContext} from '../../context/ProfileViewContext';
|
|
22
|
+
import {getPresetByKey, getPresetsForProfileType, isPresetKey} from './filterPresets';
|
|
22
23
|
import {useProfileFilters, type ProfileFilter} from './useProfileFilters';
|
|
23
24
|
|
|
24
25
|
export const isFilterComplete = (filter: ProfileFilter): boolean => {
|
|
@@ -32,7 +33,7 @@ export const isFilterComplete = (filter: ProfileFilter): boolean => {
|
|
|
32
33
|
);
|
|
33
34
|
};
|
|
34
35
|
|
|
35
|
-
const
|
|
36
|
+
const getFilterTypeItems = (currentProfileType?: string): SelectItem[] => [
|
|
36
37
|
{
|
|
37
38
|
key: 'stack',
|
|
38
39
|
element: {
|
|
@@ -59,7 +60,7 @@ const filterTypeItems: SelectItem[] = [
|
|
|
59
60
|
),
|
|
60
61
|
},
|
|
61
62
|
},
|
|
62
|
-
...
|
|
63
|
+
...getPresetsForProfileType(currentProfileType).map(preset => ({
|
|
63
64
|
key: preset.key,
|
|
64
65
|
element: {
|
|
65
66
|
active: <>{preset.name}</>,
|
|
@@ -168,6 +169,10 @@ const numberMatchTypeItems: SelectItem[] = [
|
|
|
168
169
|
];
|
|
169
170
|
|
|
170
171
|
const ProfileFilters = (): JSX.Element => {
|
|
172
|
+
const {profileSource} = useProfileViewContext();
|
|
173
|
+
const currentProfileType = profileSource?.ProfileType()?.toString();
|
|
174
|
+
const filterTypeItems = getFilterTypeItems(currentProfileType);
|
|
175
|
+
|
|
171
176
|
const {
|
|
172
177
|
localFilters,
|
|
173
178
|
appliedFilters,
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
// limitations under the License.
|
|
13
13
|
|
|
14
14
|
import {useURLStateCustom, type ParamValueSetterCustom} from '@parca/components';
|
|
15
|
-
import {
|
|
15
|
+
import {safeDecode} from '@parca/utilities';
|
|
16
16
|
|
|
17
17
|
import {isPresetKey} from './filterPresets';
|
|
18
18
|
import {type ProfileFilter} from './useProfileFilters';
|
|
@@ -73,8 +73,8 @@ export const decodeProfileFilters = (encoded: string): ProfileFilter[] => {
|
|
|
73
73
|
if (encoded === '' || encoded === undefined) return [];
|
|
74
74
|
|
|
75
75
|
try {
|
|
76
|
-
//
|
|
77
|
-
const decodedString =
|
|
76
|
+
// Decode once since we fixed the double encoding issue
|
|
77
|
+
const decodedString = safeDecode(encoded);
|
|
78
78
|
|
|
79
79
|
return decodedString.split(',').map((filter, index) => {
|
|
80
80
|
const parts = filter.split(':');
|