Compare commits

...

235 Commits
v0.6 ... v0.7

Author SHA1 Message Date
Prashant Shahi
f4cc2a3a05 Merge branch 'develop' into release/v0.7.5 2022-04-07 15:32:44 +05:30
palash-signoz
041a5249b3 feat: onClick is added in the row (#966) 2022-04-07 13:11:27 +05:30
palash-signoz
a767697a86 Merge pull request #965 from palash-signoz/trace-filter-fix-incoming-from-metrics-page
Bug: Trace filter fix incoming from metrics page
2022-04-07 12:59:37 +05:30
palash-signoz
71cb70c62c Merge pull request #958 from palash-signoz/style-trace-search
bug: style-trace-search is fixed
2022-04-07 11:03:40 +05:30
Pranshu Chittora
647cabc4f4 feat: migrated trace detail to use query (#963)
* feat: migrated trace detail to use query

* fix: remove unused imports

* chore: useQuery config is updated

Co-authored-by: Palash gupta <palash@signoz.io>
2022-04-07 10:48:09 +05:30
Palash gupta
e864e33ad3 bug: value is updated on selection 2022-04-06 22:01:42 +05:30
Palash gupta
5bdbe792f5 chore: selected filter is not removed when user close panel 2022-04-06 21:28:17 +05:30
Palash gupta
399efb0fb2 bug: trace filter bug are collapsed 2022-04-06 21:19:12 +05:30
palash-signoz
4b72de6884 Merge pull request #959 from pranshuchittora/pranshuchittora/fix/ttl-enhancements
fix: general setting TTL enhancements
2022-04-06 16:34:07 +05:30
palash-signoz
9f1473e7de Merge pull request #957 from palash-signoz/trace-table-current-page
bug: current page is updated in redux to see the updated values
2022-04-06 16:33:11 +05:30
Palash gupta
7150971dc0 chore: style is updated 2022-04-06 16:28:39 +05:30
Pranshu Chittora
d0846b8dd2 fix: general setting TTL enhancements 2022-04-06 12:40:14 +05:30
Palash gupta
ead6885b29 bug: style-trace-search is fixed 2022-04-06 11:33:56 +05:30
Palash gupta
d72dacdc1f bug: current page is updated in redux to see the updated values 2022-04-06 10:52:46 +05:30
Prashant Shahi
1d6ddd4890 chore(install-script): 🩹 fix email condition
Signed-off-by: Prashant Shahi <prashant@signoz.io>
2022-04-06 01:37:07 +05:30
Prashant Shahi
58daca1579 chore(docker-compose): 🔧 add restart policy and frontend dependency
Signed-off-by: Prashant Shahi <prashant@signoz.io>
2022-04-06 00:52:48 +05:30
Prashant Shahi
1e522ad8f1 chore(release): 📌 pin 0.7.5 SigNoz version and 0.6.1 Alertmanager version
Signed-off-by: Prashant Shahi <prashant@signoz.io>
2022-04-06 00:19:13 +05:30
Prashant Shahi
8809105a8d Prashant/deploy changes (#955)
- set information log level in clickhouse logger config
- maximum logs size 150m (3 files each of 50m)

Signed-off-by: Prashant Shahi <prashant@signoz.io>
2022-04-06 00:05:05 +05:30
palash-signoz
064c3e0449 chore: default text is updated (#954)
* text and title is updated
2022-04-05 23:13:12 +05:30
palash-signoz
2a348e916c feat: version page is added (#924)
* feat👔 : getLatestVersion api is added

* chore: VERSION page is added

* feat:  version page is added

* chore: all string is grabbed from locale

* chore: warning is removed

* chore: translation json is added

* chore: feedback about version is added

* chore: made two different functions

* unused import is removed

* feat: version changes are updated

* chore: if current version is present then it is displayed
2022-04-05 18:21:25 +05:30
palash-signoz
5744193f50 Merge pull request #953 from pranshuchittora/pranshuchittora/fix/trace-detail-error-span-color
fix: error color for spans having error on trace detail page
2022-04-05 18:00:08 +05:30
Pranshu Chittora
ccf352f2db fix: error color for spans having error on trace detail page 2022-04-05 17:02:39 +05:30
palash-signoz
6e446dc0ab Merge pull request #949 from pranshuchittora/pranshuchittora/feat/ttl-s3
feat(FE): TTL/s3 integration
2022-04-05 16:28:41 +05:30
Pranshu Chittora
566c2becdf feat: dynamic step size for the data for graphs (#929)
* feat: dynamic step size for the data for graphs

* fix: remove console.log

* chore: add jest globals

* feat: add step size for dashboard

* chore: undo .eslintignore
2022-04-05 16:09:57 +05:30
Pranshu Chittora
3b3fd2b3a9 chore: update type 2022-04-05 16:09:04 +05:30
Pranshu Chittora
eae53d9eff feat: condition changes 2022-04-05 16:05:46 +05:30
Pranshu Chittora
42842b6b17 feat: i18n support for setting route names 2022-04-05 15:51:38 +05:30
Pranshu Chittora
95f8dfb4bc feat: i18n support for settings page 2022-04-05 15:44:01 +05:30
palash-signoz
a8c5934fc5 fix: Fix jest (#945)
* bug: jest is now fixed

* chore: files are included for the eslint

* chore: build is fixed

* test: jest test are fixed
2022-04-05 14:47:37 +05:30
palash-signoz
3f2a4d6eac bug: Trace filter page fixes (#846)
* order is added in the url
* local min max duration is kept in memory to show min and max even after filtering by duration
* checkbox ordering does not change when the user selects or un-selects a checkbox
2022-04-05 13:23:08 +05:30
Pranshu Chittora
170609a81f chore: type changes 2022-04-05 12:26:43 +05:30
Pranshu Chittora
76fccbbba4 fix: styling changes 2022-04-05 12:19:54 +05:30
palash-signoz
147ed9f24b chore: editor config is added (#818) 2022-04-05 11:19:06 +05:30
palash-signoz
a69bc321a9 Merge pull request #935 from pranshuchittora/pranshuchittora/feat/graph-memory-issue
feat: FE memory fixes and UX enhancements
2022-04-05 10:35:08 +05:30
Pranshu Chittora
c9e02a8b25 feat: final touches to the ttl 2022-04-05 00:06:13 +05:30
Pranshu Chittora
24d6a1e7b2 feat: s3 ttl validation 2022-04-04 19:38:23 +05:30
Nishidh Jain
a0efa63185 Fix(FE) : Ask for confirmation before deleting any dashboard from dashboard list (#534)
* A confirmation dialog will pop up before deleting any dashboard

Co-authored-by: Palash gupta <palash@signoz.io>
2022-04-04 17:35:44 +05:30
Ankit Nayan
fd83cea9a0 chore: removing version api from being tracked (#950) 2022-04-04 17:07:21 +05:30
Pranshu Chittora
5be1eb58b2 feat: ttl api integration 2022-04-04 15:26:29 +05:30
Pranshu Chittora
8367c106bc Merge branch 'develop' of github.com:SigNoz/signoz into pranshuchittora/feat/ttl-s3 2022-04-04 15:06:33 +05:30
Pranshu Chittora
8064ae1f37 feat: ttl api integration 2022-04-04 15:06:06 +05:30
palash-signoz
ab4d9af442 Merge pull request #928 from palash-signoz/tag-value-suggestion
feat: Tag value suggestion
2022-04-04 12:52:34 +05:30
Palash gupta
eb0d3374d5 Merge branch 'develop' into tag-value-suggestion 2022-04-04 12:35:50 +05:30
palash-signoz
6c4c814b3f bug: pathname check is added (#948) 2022-04-04 10:25:15 +05:30
Palash gupta
32e8e48928 chore: behaviour for dropdown is updated 2022-04-04 08:24:28 +05:30
Naman Jain
53e7037f48 fix: run go vet to fix some issues with json tag (#936)
Co-authored-by: Naman Jain <jain_n@apple.com>
2022-04-02 16:15:03 +05:30
palash-signoz
a566b5dc97 bug: no service and loading check are added (#934) 2022-04-01 17:59:44 +05:30
Pranshu Chittora
4dc668fd13 fix: remove unused props 2022-04-01 17:43:56 +05:30
palash-signoz
d085506d3e bug: logged in check is added in the useEffect (#921) 2022-04-01 15:47:39 +05:30
palash-signoz
1b28a4e6f5 chore: links are updated for all dashboard and promql (#908) 2022-04-01 15:43:58 +05:30
Pranshu Chittora
20e924b116 feat: S3 TTL support 2022-04-01 15:12:30 +05:30
Ahsan Barkati
1d28ceb3d7 feat(query-service): Add cold storage support in getTTL API (#922)
* Add cold storage support in getTTL API
2022-04-01 11:22:25 +05:30
Prashant Shahi
1002ab553e chore(release): 📌 pin 0.7.4 SigNoz version and deployment changes
Signed-off-by: Prashant Shahi <prashant@signoz.io>
2022-03-29 22:59:32 +05:30
Amol Umbark
3dc94c8da7 (fix): Duplicate alerts in triggered alerts (#932)
* (fix): Duplicate alerts in triggered alerts fixed by changing source api from /alert/groups to /alerts

* (fix): added comments for removed lines of group api call

* (fix): restored all getGroup
2022-03-29 19:59:40 +05:30
Pranshu Chittora
5a5aca2113 chore: remove unused code 2022-03-29 16:06:27 +05:30
Pranshu Chittora
cb22117a0f Merge branch 'develop' of github.com:SigNoz/signoz into pranshuchittora/feat/graph-memory-issue 2022-03-29 16:05:49 +05:30
Pranshu Chittora
739946fa47 fix: over memory allocation on Graph on big time range 2022-03-29 16:05:08 +05:30
Pranshu Chittora
7939902f03 fix: dashboard table element overflow (#930) 2022-03-29 12:24:03 +05:30
palash-signoz
d34e08fa3d chore: build.yml file is updated for more strict frontend checks (#906)
chore: build.yml file is updated for more strict frontend checks
2022-03-29 11:13:26 +05:30
Palash gupta
5556d1d6fc feat: tag value suggestion is updated 2022-03-29 09:59:50 +05:30
Palash gupta
d4d1104a53 WIP: value suggestion is added 2022-03-29 00:02:56 +05:30
Palash gupta
225a345baa chore: getTagValue api is added 2022-03-29 00:02:16 +05:30
Amol Umbark
0efb901863 feat: Amol/webhook (#868)
webhook receiver enabled for alerts

Co-authored-by: Palash gupta <palash@signoz.io>
2022-03-28 21:01:57 +05:30
palash-signoz
e7ba5f9f33 bug 🐛 : on click tag filter is now fixed (#916) 2022-03-25 19:16:07 +05:30
palash-signoz
995232e057 Merge pull request #914 from palash-signoz/tsc-fix
chore: tsc fix are updated over frontend
2022-03-25 15:39:27 +05:30
Palash gupta
cc5d47e3ee chore: updated the type any 2022-03-25 12:39:26 +05:30
Palash gupta
b1de6c1d7d chore: link is reverted 2022-03-25 12:35:38 +05:30
Palash gupta
84bfe11285 chore: tsc error are fixed 2022-03-25 12:33:52 +05:30
Pranshu Chittora
ca78947a55 fix: save unit on dashboard without hitting apply (#912) 2022-03-25 12:29:40 +05:30
palash-signoz
ac49f84982 Merge pull request #3 from pranshuchittora/pranshuchittora/fix/tsc-fixes
fix: tsc fixes
2022-03-25 12:12:08 +05:30
Pranshu Chittora
cc47f02ebf fix: tsc fixes 2022-03-25 12:03:57 +05:30
Palash gupta
ac70240b72 chore: some tsc fix 2022-03-24 15:39:33 +05:30
palash-signoz
78b1a750fa husky: pre-commit hook is added (#904) 2022-03-24 15:06:57 +05:30
palash-signoz
d5a6336239 Merge pull request #903 from pranshuchittora/pranshuchittora/feat/transformed-labels-on-tooltips
feat(FE): unit label on graph tooltip
2022-03-24 14:23:47 +05:30
palash-signoz
01bad0f18a chore: eslint fix (#884)
* chore: eslint is updated

* chore: some eslint fixes are made

* chore: some more eslint fix are updated

* chore: some eslint fix is made

* chore: styled components type is added

* chore: some more eslint fix are made

* chore: some more eslint fix are updated

* chore: some more eslint fix are updated

* fix: eslint fixes

Co-authored-by: Pranshu Chittora <pranshu@signoz.io>
2022-03-24 12:06:57 +05:30
Pranshu Chittora
1b79a9bf35 feat: unit label on graph tooltip 2022-03-24 11:44:38 +05:30
Prashant Shahi
3d8354fb99 chore(release): 📌 pin 0.7.3 SigNoz version
Signed-off-by: Prashant Shahi <prashant@signoz.io>
2022-03-24 00:52:32 +05:30
Prashant Shahi
696241b962 chore(install-script): 🔧 amazon-linux improvements and fixes (#900)
Signed-off-by: Prashant Shahi <prashant@signoz.io>
2022-03-24 00:46:43 +05:30
Pranshu Chittora
8a883f1b5e feat: unit selection for value graph on dashboard (#898) 2022-03-23 22:03:57 +05:30
palash-signoz
7765cee610 feat: onClick feature is updated (#895) 2022-03-23 19:44:26 +05:30
Ankit Nayan
b958bad81f Merge pull request #897 from palash-signoz/896-monaco-editor-change
chore: onChange event is added
2022-03-23 19:43:59 +05:30
Palash gupta
deff5d5e17 chore: onChange event is added 2022-03-23 19:03:05 +05:30
Ankit Nayan
44d3f35a5f Merge branch 'release/v0.7.2' into develop 2022-03-23 12:41:13 +05:30
Prashant Shahi
565dfd5b52 chore(release): 📌 pin 0.7.2 SigNoz version
Signed-off-by: Prashant Shahi <prashant@signoz.io>
2022-03-23 12:06:14 +05:30
palash-signoz
897c5d2371 Merge pull request #890 from pranshuchittora/pranshuchittora/fix/832
fix: top endpoints table overflow
2022-03-23 11:48:09 +05:30
Pranshu Chittora
f22d5f0fbd fix: top endpoints table overflow 2022-03-23 11:44:37 +05:30
Prashant Shahi
8c56d04988 chore(test-framework): 🔧 expose query service port 2022-03-23 10:31:35 +05:30
Prashant Shahi
18cfc40982 chore(Makefile): 🔧 include missed slash and formatting
Signed-off-by: Prashant Shahi <prashant@signoz.io>
2022-03-23 01:25:13 +05:30
Prashant Shahi
3c66f9d2dd chore(test-framework): 🔧 remove frontend service and use latest tag from arm env
Signed-off-by: Prashant Shahi <prashant@signoz.io>
2022-03-23 01:04:31 +05:30
Prashant Shahi
4f3bb95a77 chore(makefile): 🔧 add down-x86 and down-arm targets (#887)
Signed-off-by: Prashant Shahi <prashant@signoz.io>
2022-03-23 00:51:24 +05:30
Prashant Shahi
8aa5eb78b2 chore: 🔧 set dimensions_cache_size in signozspanmetrics processor (#885)
* chore: 🔧  set dimensions_cache_size in signozspanmetrics processor
- add example usage of limit_percentage and spike_limit_percentage

Signed-off-by: Prashant Shahi <prashant@signoz.io>
2022-03-23 00:03:47 +05:30
Prashant Shahi
79a1f79b7c chore: 🔧 Add targets to clear docker standalone and swarm data (#886)
- remove sudo from run-arm and run-x86 targets

Signed-off-by: Prashant Shahi <prashant@signoz.io>
2022-03-23 00:02:50 +05:30
palash-signoz
1c5c65ddf7 bug: useHistory is removed and dashboard loading component is removed (#802)
* bug: useHistory is removed and dashboard loading component is removed

* chore: new dashboard is updated

* chore: new dashboard is updated

* chore: sidenav is updated

* chore: getX console is removed

* chore: sidenav is updated with correct pathname
2022-03-22 21:56:12 +05:30
palash-signoz
b2e78b9358 Merge pull request #883 from pranshuchittora/pranshuchittora/fix/trace-filter-group-by
fix: trace filter groupby selection is breaking the FE
2022-03-22 17:15:17 +05:30
Pranshu Chittora
5e02bfe2e4 fix: trace filter groupby selection is breaking the FE 2022-03-22 17:12:03 +05:30
palash-signoz
02d89a3a04 feat(FE): react-i18next is added (#789)
* chore: packages are added

* feat: i18next is added

* feat: translation for the signup is updated

* chore: package.json is updated
2022-03-22 16:22:41 +05:30
Pranshu Chittora
3ab0e1395a feat: data time, UI and graph label consistency across FE (#878)
* feat: data time and graph label consistency across FE

* feat: saved state of sidebar and horizontal scroll fix for trace filter page

* feat: add Y-Axis unit for missing metrics graphs

* chore: update node version from 12.18 to 12.22

* fix: 24hr time unit on graph
2022-03-22 16:22:02 +05:30
palash-signoz
f1f606844a chore: Eslint fix config (#882)
* chore: eslint config is updated

* chore: eslint auto fix is added
2022-03-22 12:10:31 +05:30
Ahsan Barkati
4e335054fb chore(tests): Add end-to-end testing system for query service (#867)
* Initial work on s3

* some more work

* Add policy api

* Cleanup

* Add multi-tier TTL and remove storagePolicy API

* Cleanup

* Typo fix

* Revert constants

* Cleanup

* Add API to get disks

* Add more validations

* Initial work on e2e tests

* Basic ttl test

* Add test which checks for objects in Minio

* Address comments

Co-authored-by: Ankit Nayan <ankit@signoz.io>
2022-03-22 00:03:20 +05:30
Ahsan Barkati
c902a6bac8 feat(query-service): Add cold storage support (#837)
* Initial work on s3

* some more work

* Add policy api

* Cleanup

* Add multi-tier TTL and remove storagePolicy API

* Cleanup

* Typo fix

* Revert constants

* Cleanup

* Add API to get disks

* Add more validations

* Cleanup
2022-03-21 23:58:56 +05:30
palash-signoz
c00f0f159b fix: save layout bug is resolved (#840)
* fix: save layout bug is resolved

* chore: onClick is also added in the component slider

* chore: dashboard Id is added

* chore: non dashboard widget is filtered out

* chore: panel layout stack issue is resolved
2022-03-21 21:04:32 +05:30
Prashant Shahi
86bdb9a5ad chore: deployment config changes (#869)
* chore(install-script): 🔧 include missed sudo_cmd variable

Signed-off-by: Prashant Shahi <prashant@signoz.io>

* chore: 🔧 add .gitkeep in folders to mount

Signed-off-by: Prashant Shahi <prashant@signoz.io>

* chore(docker-swarm): 🔧 Update deploy configurations

Signed-off-by: Prashant Shahi <prashant@signoz.io>

* chore(compose-yaml): 🔧 expose otlp ports and restart on failure policy

Signed-off-by: Prashant Shahi <prashant@signoz.io>

Co-authored-by: Ankit Nayan <ankit@signoz.io>
2022-03-21 20:43:43 +05:30
Ankit Nayan
044f02c7c7 chore: version bumped for forked prometheus with clickhouse storage (#870) 2022-03-21 20:40:43 +05:30
Prashant Shahi
561d18efec chore(telemetry): add deployment type (#875)
Signed-off-by: Prashant Shahi <prashant@signoz.io>
2022-03-21 20:39:53 +05:30
palash-signoz
ab10a699b1 feat: timestamp is updated for selected start time (#852)
* feat: timestamp is updated for selected start time

* feat: startTime for the tree is updated
2022-03-17 11:56:25 +05:30
palash-signoz
e28733d246 feat: onClick in new tab is added (#842) 2022-03-16 23:26:45 +05:30
palash-signoz
a238123eb2 feat: monaco editor is updated (#851) 2022-03-16 23:24:27 +05:30
Prashant Shahi
4337ab5cd0 chore(install-script): remove mandatory sudo and digest improvement (#836)
* chore(install-script):  add fallback sha1sum command

Signed-off-by: Prashant Shahi <prashant@signoz.io>

* chore(install-script):  remove mandatory sudo and digest improvement

Signed-off-by: Prashant Shahi <prashant@signoz.io>

* chore(install-script): 🔧 use sudo_cmd variable

Signed-off-by: Prashant Shahi <prashant@signoz.io>

* chore(install-script): 🔧 remove depreciated druid section

Signed-off-by: Prashant Shahi <prashant@signoz.io>

* chore(install-script): 🔧 sudo prompt changes

Signed-off-by: Prashant Shahi <prashant@signoz.io>
2022-03-16 22:59:20 +05:30
palash-signoz
7a3a3b8d89 bug: edit channel is fixed (#855) 2022-03-16 22:35:13 +05:30
palash-signoz
a9cbd12330 Merge pull request #861 from palash-signoz/trace-filter-fix-selected
chore: styled tab is updated to Tab from antd
2022-03-16 17:32:40 +05:30
Palash gupta
c320c20280 chore: styled tab is updated to Tab from antd 2022-03-16 17:09:27 +05:30
palash-signoz
b3c2fe75d3 Merge pull request #858 from palash-signoz/857-channels-dropdown
bug: global time selection dropdown is removed in the all channels page
2022-03-16 16:51:15 +05:30
Pranshu Chittora
95d3a27769 Merge pull request #845 from pranshuchittora/pranshuchittora/fix/trace-detail/events-error-handling
fix(FE): trace detail events error handling
2022-03-16 16:44:29 +05:30
palash-signoz
67f09c6def Merge pull request #860 from pranshuchittora/pranshuchittora/feat/y-axis-unit-selection
feat: y-axis units for pre-defined and dashboard graphs
2022-03-16 16:36:09 +05:30
Pranshu Chittora
eaeba43179 Merge pull request #835 from pranshuchittora/pc/feat/shared-styles-for-styled-components
feat(FE): new trace detail page code cleanup and enhancements
2022-03-16 16:29:50 +05:30
Pranshu Chittora
daadc584ea feat: update ts type 2022-03-16 16:28:11 +05:30
Pranshu Chittora
da8b16f588 feat: Updates TS type 2022-03-16 16:27:06 +05:30
Pranshu Chittora
17738a58a2 Merge branch 'develop' of github.com:SigNoz/signoz into pranshuchittora/feat/y-axis-unit-selection 2022-03-16 16:24:40 +05:30
Pranshu Chittora
3ebffae1c6 chore: revert eslint --debug flag 2022-03-16 16:16:20 +05:30
Pranshu Chittora
2ca67f1017 Merge pull request #844 from pranshuchittora/pranshuchittora/feat/x-axis-adaptive-lables
feat(FE): adaptive x axis time labels
2022-03-16 16:14:49 +05:30
Pranshu Chittora
00c7eccb0c fix: remove any type 2022-03-16 16:14:27 +05:30
Pranshu Chittora
7f3d9e2e35 feat: PR review changes 2022-03-16 16:05:21 +05:30
Pranshu Chittora
a95656b3a0 fix: x axis label when the time stamp is not parsed 2022-03-16 15:29:23 +05:30
Pranshu Chittora
9404768f9d Merge branch 'develop' of github.com:SigNoz/signoz into pc/feat/shared-styles-for-styled-components 2022-03-16 13:28:55 +05:30
Pranshu Chittora
7559445ebe Merge branch 'develop' of github.com:SigNoz/signoz into pranshuchittora/fix/trace-detail/events-error-handling 2022-03-16 13:10:26 +05:30
Pranshu Chittora
112766b265 Merge branch 'pranshuchittora/fix/trace-detail/events-error-handling' of github.com:pranshuchittora/signoz into pranshuchittora/fix/trace-detail/events-error-handling 2022-03-16 13:08:43 +05:30
Pranshu Chittora
ccf5af089d Merge pull request #856 from palash-signoz/eslint-fix
BUG(UI): eslint fixes are updated
2022-03-16 11:52:46 +05:30
Pranshu Chittora
0b6f31420b feat: y-axis units for pre-defined and dashboard graphs 2022-03-15 15:18:33 +05:30
Palash gupta
b4ce805c6f bug: global time selection dropdown is removed in the all channels page 2022-03-15 10:09:32 +05:30
Palash gupta
08f24fbdff chore: function is made async 2022-03-14 21:34:22 +05:30
Palash gupta
191925b418 Merge branch 'develop' into eslint-fix 2022-03-14 20:15:21 +05:30
Palash gupta
84b70c970f chore: eslint fixes are updated 2022-03-14 20:12:42 +05:30
Pranay Prateek
988ce36047 Update README.md 2022-03-11 18:54:28 +05:30
Pranay Prateek
24a4177a73 Update README.md 2022-03-11 18:53:37 +05:30
Pranshu Chittora
08ca3b7849 bug: timeline interval is updated
fix: add if condition for timeline interval

chore: remove mock response
2022-03-11 16:40:58 +05:30
Pranshu Chittora
d0723207c3 chore: remove mock response 2022-03-11 16:38:13 +05:30
Pranshu Chittora
16cf829ec3 Merge branch 'develop' of github.com:SigNoz/signoz into pranshuchittora/fix/trace-detail/events-error-handling 2022-03-11 16:37:15 +05:30
Pranshu Chittora
23f9949fad fix: trace detail events error handling 2022-03-11 16:32:11 +05:30
Pranshu Chittora
fafdd4b87f Merge pull request #828 from palash-signoz/timeline-fix
bug(FE): timeline interval is updated
2022-03-11 16:30:40 +05:30
Pranshu Chittora
f2ace729fd fix: linting fixes 2022-03-11 13:42:05 +05:30
Pranshu Chittora
f0c627eebe chore: add unit tests 2022-03-11 13:39:04 +05:30
Pranshu Chittora
1bf8e6bef6 feat: better x-axis labels 2022-03-11 11:20:52 +05:30
Ankit Nayan
f37e6ef1d1 Merge pull request #831 from SigNoz/prashant/e2e-k3s-changes
ci: 💚 fix e2e-k3s workflow as needed with the chart changes
2022-03-09 20:00:28 +05:30
Pranshu Chittora
c3ebbfa8ca feat: new trace detail page code enhancemenets and cleanup 2022-03-09 10:43:02 +05:30
Pranay Prateek
12970d6975 Update README.md 2022-03-08 20:56:59 +05:30
Vishal Sharma
1112ff7e7a Remove gitpod support temporarily (#834)
Gitpod environment has issues which has to be resolved before adding to contributing docs.
2022-03-08 19:55:19 +05:30
palash-signoz
09fd877b2a Merge pull request #1 from pranshuchittora/pc/fix/pr-828
fix: add if condition for timeline interval
2022-03-07 16:32:42 +05:30
Pranshu Chittora
c04c0284dc fix: add if condition for timeline interval 2022-03-07 16:08:37 +05:30
Prashant Shahi
239cdad57b ci: 💚 fix e2e-k3s workflow with chart changes
Signed-off-by: Prashant Shahi <prashant@signoz.io>
2022-03-07 16:07:38 +05:30
Pranshu Chittora
314f95a914 feat(FE): shared styled for custom styled components 2022-03-07 14:32:17 +05:30
Pranay Prateek
e070ba61cd Update repo-stats.yml 2022-03-06 13:23:49 +05:30
Pranay Prateek
79576b476f Create repo-stats.yml (#829) 2022-03-06 13:22:37 +05:30
Palash gupta
8e4f987cf6 bug: timeline interval is updated 2022-03-06 12:02:21 +05:30
Axay sagathiya
3fe3bde0c7 Fix: Update Documentation to configure front-end and run back-end. (#815)
* fix: add all the steps to run query-service

* fix: add step to add configuration to run frontend
2022-03-05 23:51:48 +05:30
Ankit Nayan
b8a6a27fad release: v0.7.1 2022-03-04 13:23:30 +05:30
Ankit Nayan
fb3dbcf662 Merge pull request #819 from pranshuchittora/pc/feat/trace-detail/eclear
fix: expand and unexpand on active span path
2022-03-04 13:16:46 +05:30
Ankit Nayan
cb04979bb7 Merge pull request #823 from pranshuchittora/pc/fix/yarn-install-node-gyp-error
fix: install deps node-gyp error
2022-03-04 13:16:20 +05:30
Ankit Nayan
967b83a5d0 Merge pull request #824 from palash-signoz/dashboard-fixes
bug(dashboard): useCallback is removed
2022-03-04 13:16:02 +05:30
Palash gupta
3fd086db4d dashboard: useCallback is removed 2022-03-04 13:10:40 +05:30
Pranshu Chittora
9aedcc1777 fix: install deps node-gyp error 2022-03-04 12:49:13 +05:30
Pranshu Chittora
e7d2bb13dc fix: expand and unexpand on active span path 2022-03-04 11:34:33 +05:30
palash-signoz
39c3f67d86 Merge pull request #816 from palash-signoz/eslint
feat(eslint): eslint-plugin-react-hooks is added
2022-03-04 11:33:00 +05:30
palash-signoz
49d1015a72 Merge pull request #817 from palash-signoz/sonar-eslint-plugin
feat(eslint): sonar js plugin for eslint is added
2022-03-04 11:32:45 +05:30
Palash gupta
f3b2f30c82 feat(eslint): sonar js plugin for eslint is added 2022-03-04 10:07:52 +05:30
Palash gupta
ff9d81aefc feat: eslint-plugin-react-hooks is added 2022-03-04 10:04:06 +05:30
Prashant Shahi
c9b07ee5dd chore(release): 📌 pin SigNoz and OtelCollector versions
Signed-off-by: Prashant Shahi <prashant@signoz.io>
2022-03-03 19:59:55 +05:30
Prashant Shahi
bda8ddc0e4 chore: ️ add hotrod template and install/delete scripts (#801)
* chore: ️ add hotrod template and scripts

Signed-off-by: Prashant Shahi <prashant@signoz.io>

* refactor:  conditionally compute image

Signed-off-by: Prashant Shahi <prashant@signoz.io>

* fix: 🩹 add signoz namespace

Signed-off-by: Prashant Shahi <prashant@signoz.io>

* chore: 🔨  fix namespace template in scripts

Signed-off-by: Prashant Shahi <prashant@signoz.io>

* docs(hotrod): 📝 Add README for hotrod k8s

Signed-off-by: Prashant Shahi <prashant@signoz.io>

Co-authored-by: Ankit Nayan <ankit@signoz.io>
2022-03-03 19:48:50 +05:30
palash-signoz
540a682bf0 bug: Trace search bug is resolved (#741)
* bug: Trace search bug is resolved

* bug: Trace search bug is resolved

* chore: parseTagsToQuery is updated

* chore: parseTagsToQuery is updated

* chore: parseTagsToQuery is updated

* chore: parseTagsToQuery is updated
2022-03-03 19:10:51 +05:30
palash-signoz
9f7c60d2c1 Fe: Feat/trace detail (#764)
* feat: new trace detail page flame graph

* feat: new trace detail page layout

* test: trace detail is wip

* chore: trace details in wip

* feat: trace detail page timeline component

* chore: spantoTree is updated

* chore: gantchart is updated

* chore: onClick is added

* chore: isSpanPresentInSearchString util is added

* chore: trace graph is updated

* chore: added the hack to work

* feat: is span present util is added

* chore: in span ms is added

* chore: tooltip is updated

* WIP: chore: trace details changes are updated

* feat: getTraceItem is added

* feat: trace detail page is updated

* feat: trace detail styling changes

* feat: trace detail page is updated

* feat: implement span hover, select, focus and reset

* feat: reset focus

* feat: spanId as query table and unfurling

* feat: trace details is updated

* chore: remove lodash

* chore: remove lodash

* feat: trace details is updated

* feat: new trace detail page styling changes

* feat: new trace detail page styling changes

* feat: improved styling

* feat: remove horizontal scrolling

* feat: new trace detail page modify caret icon

* chore styles are updated

* Revert "chore: Trace styles"

* chore styles are updated

* feat: timeline normalisation

* chore: remove mock data

* chore: sort tree data util is added and selected span component is updated

* chore: trace changes are updated

* chore: trace changes are updated

* chore: trace changes are updated

* feat: refactored time units for new trace detail page

* chore: remove mockdata

* feat: new trace detail page themeing and interval loop fix

* chore: error tag is updated

* chore: error tag is updated

* chore: error tag is updated

* chore: error tag is updated

* chore: console is removed

* fix: error tag expand button

* chore: expanded panel is updated

* feat: scroll span from gantt chart intoview

* chore: trace detail is removed

Co-authored-by: Pranshu Chittora <pranshu@signoz.io>
2022-03-03 19:04:23 +05:30
palash-signoz
80a06300ff Merge pull request #703 from SigNoz/pranshuchittora/feat/dynamic-step-size
feat(FE): Dynamic step size of metrics page
2022-03-03 18:52:15 +05:30
Ankit Nayan
7fae5207d1 Merge pull request #718 from palash-signoz/716-sorting
bug(FE): sorting of date is fixed
2022-03-03 18:28:50 +05:30
Ankit Nayan
b4f781ad47 Merge pull request #800 from palash-signoz/not-found-button-style
chore: styles is updated for the not found button
2022-03-03 18:25:13 +05:30
Ankit Nayan
d9468d438d Merge pull request #791 from palash-signoz/782-typo
chore: typo is fixed
2022-03-03 18:24:35 +05:30
Ankit Nayan
25559c8781 Merge pull request #796 from SigNoz/feat/support-custom-events
feat(backend): support custom events in span
2022-03-03 18:23:44 +05:30
Ankit Nayan
aa760336d0 Merge pull request #803 from SigNoz/chore/update-otelcollector-0.43.0
chore: update otel-collector to 0.43.0
2022-03-03 18:23:03 +05:30
Ankit Nayan
46aaa8199d Merge pull request #811 from ankitnayan/fix/na-telemetry
fix: set userId as distinctId if failed to fetch IP
2022-03-03 18:14:58 +05:30
Ankit Nayan
10faa6f42b fix: set userId as distinctId if failed to fetch IP 2022-03-03 18:11:23 +05:30
makeavish
2d5ad346a6 fix: remove encoding 2022-03-03 14:45:43 +05:30
makeavish
207360e074 chore: update otel-collector to 0.43.0 2022-03-03 13:23:49 +05:30
Palash gupta
a4b954e304 chore: styles is updated for the not found button 2022-03-02 18:32:24 +05:30
makeavish
3e24e371f4 fix: encode event string to fix parsing at frontend 2022-03-01 16:16:45 +05:30
makeavish
bdeadaeff6 feat(backend): support custom events in span 2022-02-28 16:51:58 +05:30
Palash gupta
43b39f1a7c chore: typo is fixed 2022-02-28 09:39:30 +05:30
Palash gupta
6ab7fea8de feat: soring filter is added 2022-02-27 16:56:18 +05:30
Palash gupta
05371085f9 Merge branch 'develop' into 716-sorting 2022-02-27 16:30:44 +05:30
Ankit Nayan
938f42bd4f release: v0.6.2 2022-02-25 22:05:30 +05:30
Ankit Nayan
1652f35f1a release: v0.6.2 2022-02-25 21:28:12 +05:30
Ankit Nayan
3a67d0237c Merge pull request #769 from ankitnayan/feat/opt-out
feat: adding org name and adding opt-out
2022-02-25 20:42:27 +05:30
Ankit Nayan
7888865ddc feat: adding org name and adding opt-out 2022-02-25 20:40:38 +05:30
Ankit Nayan
25fb0deb8d Merge pull request #572 from palash-signoz/remove-duplicate-condition-bundle-analyser
fix: webpack config is updated
2022-02-25 20:10:05 +05:30
Ankit Nayan
b067db633a Merge pull request #568 from palash-signoz/toggle-setting-tabs
Feat(UI): toggle tabs is updated in the setting tab
2022-02-25 20:09:01 +05:30
Ankit Nayan
9094f20070 Merge pull request #567 from palash-signoz/fix-external-link
fix: code vulnerability is fixed
2022-02-25 20:08:03 +05:30
Ankit Nayan
9129704a93 Merge pull request #731 from palash-signoz/clear-all-with-user-filter
bug: clear all now moves with selected filter rather than user selected filter
2022-02-25 18:44:37 +05:30
Ankit Nayan
fc244edc50 Update CODEOWNERS 2022-02-25 18:07:07 +05:30
Ankit Nayan
cbe635bc94 Merge pull request #733 from palash-signoz/trace-test
test(Trace): Trace page test are added
2022-02-25 18:04:38 +05:30
Ankit Nayan
bb0a7a956a Merge pull request #705 from palash-signoz/bug-useDebouncedFunction
bug: useDebounce function is fixed
2022-02-25 17:59:48 +05:30
Ankit Nayan
2800b021e6 Merge pull request #689 from SigNoz/feat/tagValueSuggestion
feat: tag value suggestion API
2022-02-25 17:44:49 +05:30
Ankit Nayan
74170ffb4a Merge pull request #750 from SigNoz/fix/telemetry-bug
fix: avoid panic by handling getOutboundIP() error
2022-02-25 17:16:29 +05:30
Vishal Sharma
ab72e92fc6 return string(ip) instead of empty string on error 2022-02-25 17:11:45 +05:30
Ankit Nayan
8b224dd59c Merge pull request #753 from udasitharani/749-feedback-fab
Removing Feedback FAB
2022-02-25 17:06:46 +05:30
Ankit Nayan
ce77a3cd80 Merge pull request #758 from SigNoz/makeavish-patch-1
Add section for CPU architecture
2022-02-25 17:06:08 +05:30
Ankit Nayan
79fa4e7b74 Merge pull request #762 from axaysagathiya/issue-740
Fix: update documentation for query-service.
2022-02-25 17:05:45 +05:30
Ankit Nayan
90e97856a9 Merge pull request #755 from palash-signoz/bug-trace-table
bug: onClick cursor is added and display date is converted to minutes and 12hr format
2022-02-25 14:10:13 +05:30
Ankit Nayan
61fb11a232 Merge pull request #756 from SigNoz/feat/addHasErrorColumn
feat: add hasError tag in searchTraces response
2022-02-25 14:07:47 +05:30
axaysagathiya
729ea586a8 fix the spelling mistakes. 2022-02-24 17:27:22 +05:30
axaysagathiya
eb28459847 Fix: update documentation for query-service.
fixes #740
2022-02-24 15:10:52 +05:30
Vishal Sharma
10fc3bf456 Add section for CPU architecture 2022-02-24 09:57:03 +05:30
makeavish
244a07aef8 feat: add hasError tag in searchTraces response 2022-02-23 12:13:13 +05:30
Palash gupta
92cf617a53 bug: onClick cursor is added and display date is converted to minutes and 12hr format 2022-02-23 08:22:23 +05:30
Udasi Tharani
1eb333a890 fixing collapse button background 2022-02-22 22:52:12 +05:30
Udasi Tharani
ebc280db0e Merge branch '678-slack-community' of https://github.com/palash-signoz/signoz into 749-feedback-fab 2022-02-22 22:35:57 +05:30
Udasi Tharani
3beb7f1843 removing feedback fab button 2022-02-22 22:35:29 +05:30
makeavish
56c9ea5430 fix: avoid panic by handling getOutboundIP() error 2022-02-22 17:49:02 +05:30
Pranay Prateek
05c79b7119 Update .gitpod.yml 2022-02-20 18:03:54 +05:30
Palash gupta
a6da00f801 test: trace test is updated 2022-02-16 15:36:20 +05:30
Palash gupta
0514c5035e test: trace test is updated 2022-02-16 14:20:48 +05:30
Palash gupta
2df058825a Merge branch 'develop' into toggle-setting-tabs 2022-02-16 09:30:57 +05:30
Palash gupta
a07b8999c0 test: initial test is updated 2022-02-16 09:27:06 +05:30
Palash gupta
5405f0d9ed chore: initial response for the trace api is added 2022-02-16 09:00:41 +05:30
Palash gupta
00cefe2306 bug: clear all now moves with selected filter rather than user selected filter 2022-02-16 08:13:54 +05:30
Ankit Nayan
5aa46c7e96 Merge pull request #723 from SigNoz/prashant/hotrod-yaml
chore: 🔧 update default jaeger endpoint in hotrod manifest
2022-02-15 17:25:39 +05:30
Ankit Nayan
c367f928c5 Merge pull request #581 from siddhantparekh/issue-561
fix(FE) Removed refresh time filter from trace-detail page
2022-02-14 12:13:13 +05:30
Prashant Shahi
4c2f287e06 chore: 🔧 update default jaeger endpoint in hotrod manifest
Signed-off-by: Prashant Shahi <prashant@signoz.io>
2022-02-14 05:00:48 +05:30
Palash gupta
567c81c0f9 chore:button text is updated 2022-02-13 12:05:20 +05:30
Palash gupta
31f0a9f0b6 feat: slack community link is updated 2022-02-12 15:17:40 +05:30
Palash gupta
bad14a7d09 feat: slack community link is updated 2022-02-12 15:01:38 +05:30
Palash gupta
28e8cffeaa bug: sorting of date is fixed 2022-02-12 14:26:03 +05:30
Pranshu Chittora
baba0c389c chore(tests): migrate to dayjs for generating timestamp 2022-02-11 16:08:54 +05:30
Palash gupta
0d98a4fd0c bug: useDebounce function is fixed 2022-02-10 22:00:35 +05:30
Pranshu Chittora
09344cfb44 feat(FE): dynamic step size of metrics page 2022-02-10 17:46:33 +05:30
Vishal Sharma
9a00dca749 feat: tag value suggestion API 2022-02-08 23:05:50 +05:30
Siddhant Parekh
e7253b7ca6 fix(FE) Removed refresh time filter from trace-detail page 2022-01-04 13:40:03 +05:30
Palash gupta
dddba68bfd fix: webpack config is updated 2021-12-28 20:51:36 +05:30
Palash gupta
40c287028b toggle tabs is updated 2021-12-27 23:55:38 +05:30
Palash gupta
30124de409 fix: code vunbretality is fixed 2021-12-27 13:07:10 +05:30
397 changed files with 14318 additions and 8344 deletions

33
.editorconfig Normal file
View File

@@ -0,0 +1,33 @@
# EditorConfig is awesome: https://EditorConfig.org
# top-most EditorConfig file
root = true
# Unix-style newlines with a newline ending every file
[*]
end_of_line = lf
insert_final_newline = true
# Matches multiple files with brace expansion notation
# Set default charset
[*.{js,py}]
charset = utf-8
# 4 space indentation
[*.py]
indent_style = space
indent_size = 4
# Tab indentation (no size specified)
[Makefile]
indent_style = tab
# Indentation override for all JS under lib directory
[lib/**.js]
indent_style = space
indent_size = 2
# Matches the exact files either package.json or .travis.yml
[{package.json,.travis.yml}]
indent_style = space
indent_size = 2

4
.github/CODEOWNERS vendored
View File

@@ -2,5 +2,5 @@
# Owners are automatically requested for review for PRs that changes code
# that they own.
* @ankitnayan
/frontend/ @palash-signoz
/deploy/ @prashant-shahi
/frontend/ @palash-signoz @pranshuchittora
/deploy/ @prashant-shahi

View File

@@ -26,6 +26,7 @@ assignees: ''
* **Signoz version**:
* **Browser version**:
* **Your OS and version**:
* **Your CPU Architecture**(ARM/Intel):
## Additional context

View File

@@ -2,11 +2,12 @@ name: build-pipeline
on:
pull_request:
branches:
- develop
- main
- v*
paths:
- 'pkg/**'
- 'frontend/**'
- "pkg/**"
- "frontend/**"
jobs:
get_filters:
@@ -17,17 +18,17 @@ jobs:
query-service: ${{ steps.filter.outputs.query-service }}
flattener: ${{ steps.filter.outputs.flattener }}
steps:
# For pull requests it's not necessary to checkout the code
- uses: dorny/paths-filter@v2
id: filter
with:
filters: |
frontend:
- 'frontend/**'
query-service:
- 'pkg/query-service/**'
flattener:
- 'pkg/processors/flattener/**'
# For pull requests it's not necessary to checkout the code
- uses: dorny/paths-filter@v2
id: filter
with:
filters: |
frontend:
- 'frontend/**'
query-service:
- 'pkg/query-service/**'
flattener:
- 'pkg/processors/flattener/**'
build-frontend:
runs-on: ubuntu-latest
@@ -39,12 +40,11 @@ jobs:
uses: actions/checkout@v2
- name: Install dependencies
run: cd frontend && yarn install
- name: Run Prettier
run: cd frontend && npm run prettify
continue-on-error: true
- name: Run ESLint
run: cd frontend && npm run lint
continue-on-error: true
- name: TSC
run: yarn tsc
working-directory: ./frontend
- name: Build frontend docker image
shell: bash
run: |

View File

@@ -52,14 +52,11 @@ jobs:
helm install my-release signoz/signoz -n platform \
--wait \
--timeout 10m0s \
--set cloud=null \
--set frontend.service.type=LoadBalancer \
--set query-service.image.tag=$DOCKER_TAG \
--set queryService.image.tag=$DOCKER_TAG \
--set frontend.image.tag=$DOCKER_TAG
# get pods, services and the container images
kubectl describe deploy/my-release-frontend -n platform | grep Image
kubectl describe statefulset/my-release-query-service -n platform | grep Image
kubectl get pods -n platform
kubectl get svc -n platform

25
.github/workflows/repo-stats.yml vendored Normal file
View File

@@ -0,0 +1,25 @@
on:
schedule:
# Run this once per day, towards the end of the day for keeping the most
# recent data point most meaningful (hours are interpreted in UTC).
- cron: "0 8 * * *"
workflow_dispatch: # Allow for running this manually.
jobs:
j1:
name: repostats
runs-on: ubuntu-latest
steps:
- name: run-ghrs
uses: jgehrcke/github-repo-stats@v1.1.0
with:
# Define the stats repository (the repo to fetch
# stats for and to generate the report for).
# Remove the parameter when the stats repository
# and the data repository are the same.
repository: signoz/signoz
# Set a GitHub API token that can read the stats
# repository, and that can push to the data
# repository (which this workflow file lives in),
# to store data and the report files.
ghtoken: ${{ github.token }}

7
.gitignore vendored
View File

@@ -42,4 +42,11 @@ frontend/cypress.env.json
frontend/*.env
pkg/query-service/signoz.db
pkg/query-service/tframe/test-deploy/data/
# local data
/deploy/docker/clickhouse-setup/data/
/deploy/docker-swarm/clickhouse-setup/data/

View File

@@ -11,7 +11,7 @@ tasks:
- name: Run Docker Images
init: |
cd ./deploy
sudo docker-compose --env-file ./docker/clickhouse-setup/env/x86_64.env -f docker/clickhouse-setup/docker-compose.yaml up -d
sudo docker-compose -f docker/clickhouse-setup/docker-compose.yaml up -d
# command:
- name: Run Frontend
@@ -22,7 +22,7 @@ tasks:
yarn dev
ports:
- port: 3000
- port: 3301
onOpen: open-browser
- port: 8080
onOpen: ignore

View File

@@ -21,6 +21,12 @@ Need to update [https://github.com/SigNoz/signoz/tree/main/frontend](https://git
- comment out frontend service section at `deploy/docker/clickhouse-setup/docker-compose.yaml#L59`
- run `cd deploy` to move to deploy directory
- Install signoz locally without the frontend
- Add below configuration to query-service section at `docker/clickhouse-setup/docker-compose.yaml#L36`
```docker
ports:
- "8080:8080"
```
- If you are using x86_64 processors (All Intel/AMD processors) run `sudo docker-compose -f docker/clickhouse-setup/docker-compose.yaml up -d`
- If you are on arm64 processors (Apple M1 Macbooks) run `sudo docker-compose -f docker/clickhouse-setup/docker-compose.arm.yaml up -d`
- `cd ../frontend` and change baseURL to `http://localhost:8080` in file `src/constants/env.ts`
@@ -47,13 +53,32 @@ Need to update [https://github.com/SigNoz/signoz/tree/main/pkg/query-service](ht
### To run ClickHouse setup (recommended for local development)
- git clone https://github.com/SigNoz/signoz.git
- run `cd signoz` to move to signoz directory
- run `sudo make dev-setup` to configure local setup to run query-service
- comment out frontend service section at `docker/clickhouse-setup/docker-compose.yaml#L59`
- comment out query-service section at `docker/clickhouse-setup/docker-compose.yaml#L38`
- comment out frontend service section at `docker/clickhouse-setup/docker-compose.yaml#L45`
- comment out query-service section at `docker/clickhouse-setup/docker-compose.yaml#L28`
- add below configuration to clickhouse section at `docker/clickhouse-setup/docker-compose.yaml#L6`
```docker
expose:
- 9000
ports:
- 9001:9000
```
- run `cd pkg/query-service/` to move to query-service directory
- Open ./constants/constants.go
- Replace ```const RELATIONAL_DATASOURCE_PATH = "/var/lib/signoz/signoz.db"``` \
with ```const RELATIONAL_DATASOURCE_PATH = "./signoz.db".```
- Install signoz locally without the frontend and query-service
- If you are using x86_64 processors (All Intel/AMD processors) run `sudo make run-x86`
- If you are on arm64 processors (Apple M1 Macbooks) run `sudo make run-arm`
#### Run locally
```console
ClickHouseUrl=tcp://localhost:9001 STORAGE=clickhouse go run main.go
```
> Notes for Maintainers/Contributors who will change Line Numbers of Frontend & Query-Section. Please Update Line Numbers in `./scripts/commentLinesForSetup.sh`
**_Query Service should now be available at `http://localhost:8080`_**
@@ -61,13 +86,13 @@ Need to update [https://github.com/SigNoz/signoz/tree/main/pkg/query-service](ht
> If you want to see how, frontend plays with query service, you can run frontend also in you local env with the baseURL changed to `http://localhost:8080` in file `src/constants/env.ts` as the query-service is now running at port `8080`
---
Instead of configuring a local setup, you can also use [Gitpod](https://www.gitpod.io/), a VSCode-based Web IDE.
<!-- Instead of configuring a local setup, you can also use [Gitpod](https://www.gitpod.io/), a VSCode-based Web IDE.
Click the button below. A workspace with all required environments will be created.
[![Open in Gitpod](https://gitpod.io/button/open-in-gitpod.svg)](https://gitpod.io/#https://github.com/SigNoz/signoz)
> To use it on your forked repo, edit the 'Open in Gitpod' button url to `https://gitpod.io/#https://github.com/<your-github-username>/signoz`
> To use it on your forked repo, edit the 'Open in Gitpod' button url to `https://gitpod.io/#https://github.com/<your-github-username>/signoz` -->
# Contribute to SigNoz Helm Chart

View File

@@ -12,6 +12,8 @@ BUILD_BRANCH ?= $(shell git rev-parse --abbrev-ref HEAD)
FRONTEND_DIRECTORY ?= frontend
FLATTENER_DIRECTORY ?= pkg/processors/flattener
QUERY_SERVICE_DIRECTORY ?= pkg/query-service
STANDALONE_DIRECTORY ?= deploy/docker/clickhouse-setup
SWARM_DIRECTORY ?= deploy/docker-swarm/clickhouse-setup
REPONAME ?= signoz
DOCKER_TAG ?= latest
@@ -38,7 +40,8 @@ build-frontend-amd64:
@echo "--> Building frontend docker image for amd64"
@echo "------------------"
@cd $(FRONTEND_DIRECTORY) && \
docker build -f Dockerfile --no-cache -t $(REPONAME)/$(FRONTEND_DOCKER_IMAGE):$(DOCKER_TAG) --build-arg TARGETPLATFORM="linux/amd64" .
docker build -f Dockerfile --no-cache -t $(REPONAME)/$(FRONTEND_DOCKER_IMAGE):$(DOCKER_TAG) \
--build-arg TARGETPLATFORM="linux/amd64" .
# Step to build and push docker image of frontend(used in push pipeline)
build-push-frontend:
@@ -46,7 +49,8 @@ build-push-frontend:
@echo "--> Building and pushing frontend docker image"
@echo "------------------"
@cd $(FRONTEND_DIRECTORY) && \
docker buildx build --file Dockerfile --progress plane --no-cache --push --platform linux/amd64 --tag $(REPONAME)/$(FRONTEND_DOCKER_IMAGE):$(DOCKER_TAG) .
docker buildx build --file Dockerfile --progress plane --no-cache --push --platform linux/amd64 \
--tag $(REPONAME)/$(FRONTEND_DOCKER_IMAGE):$(DOCKER_TAG) .
# Steps to build and push docker image of query service
.PHONY: build-query-service-amd64 build-push-query-service
@@ -56,7 +60,8 @@ build-query-service-amd64:
@echo "--> Building query-service docker image for amd64"
@echo "------------------"
@cd $(QUERY_SERVICE_DIRECTORY) && \
docker build -f Dockerfile --no-cache -t $(REPONAME)/$(QUERY_SERVICE_DOCKER_IMAGE):$(DOCKER_TAG) . --build-arg TARGETPLATFORM="linux/amd64" --build-arg LD_FLAGS=$(LD_FLAGS)
docker build -f Dockerfile --no-cache -t $(REPONAME)/$(QUERY_SERVICE_DOCKER_IMAGE):$(DOCKER_TAG) \
--build-arg TARGETPLATFORM="linux/amd64" --build-arg LD_FLAGS=$(LD_FLAGS) .
# Step to build and push docker image of query in amd64 and arm64 (used in push pipeline)
build-push-query-service:
@@ -64,7 +69,9 @@ build-push-query-service:
@echo "--> Building and pushing query-service docker image"
@echo "------------------"
@cd $(QUERY_SERVICE_DIRECTORY) && \
docker buildx build --file Dockerfile --progress plane --no-cache --push --platform linux/arm64,linux/amd64 --build-arg LD_FLAGS=$(LD_FLAGS) --tag $(REPONAME)/$(QUERY_SERVICE_DOCKER_IMAGE):$(DOCKER_TAG) .
docker buildx build --file Dockerfile --progress plane --no-cache \
--push --platform linux/arm64,linux/amd64 --build-arg LD_FLAGS=$(LD_FLAGS) \
--tag $(REPONAME)/$(QUERY_SERVICE_DOCKER_IMAGE):$(DOCKER_TAG) .
# Steps to build and push docker image of flattener
.PHONY: build-flattener-amd64 build-push-flattener
@@ -74,7 +81,8 @@ build-flattener-amd64:
@echo "--> Building flattener docker image for amd64"
@echo "------------------"
@cd $(FLATTENER_DIRECTORY) && \
docker build -f Dockerfile --no-cache -t $(REPONAME)/$(FLATTERNER_DOCKER_IMAGE):$(DOCKER_TAG) . --build-arg TARGETPLATFORM="linux/amd64"
docker build -f Dockerfile --no-cache -t $(REPONAME)/$(FLATTERNER_DOCKER_IMAGE):$(DOCKER_TAG) \
--build-arg TARGETPLATFORM="linux/amd64" .
# Step to build and push docker image of flattener in amd64 (used in push pipeline)
build-push-flattener:
@@ -82,7 +90,9 @@ build-push-flattener:
@echo "--> Building and pushing flattener docker image"
@echo "------------------"
@cd $(FLATTENER_DIRECTORY) && \
docker buildx build --file Dockerfile --progress plane --no-cache --push --platform linux/arm64,linux/amd64 --tag $(REPONAME)/$(FLATTERNER_DOCKER_IMAGE):$(DOCKER_TAG) .
docker buildx build --file Dockerfile --progress plane \
--no-cache --push --platform linux/arm64,linux/amd64 \
--tag $(REPONAME)/$(FLATTERNER_DOCKER_IMAGE):$(DOCKER_TAG) .
dev-setup:
mkdir -p /var/lib/signoz
@@ -93,7 +103,21 @@ dev-setup:
@echo "------------------"
run-x86:
@sudo docker-compose -f ./deploy/docker/clickhouse-setup/docker-compose.yaml up -d
@docker-compose -f $(STANDALONE_DIRECTORY)/docker-compose.yaml up -d
run-arm:
@sudo docker-compose -f ./deploy/docker/clickhouse-setup/docker-compose.arm.yaml up -d
@docker-compose -f $(STANDALONE_DIRECTORY)/docker-compose.arm.yaml up -d
down-x86:
@docker-compose -f $(STANDALONE_DIRECTORY)/docker-compose.yaml down -v
down-arm:
@docker-compose -f $(STANDALONE_DIRECTORY)/docker-compose.arm.yaml down -v
clear-standalone-data:
@docker run --rm -v "$(PWD)/$(STANDALONE_DIRECTORY)/data:/pwd" busybox \
sh -c "cd /pwd && rm -rf alertmanager/* clickhouse/* signoz/*"
clear-swarm-data:
@docker run --rm -v "$(PWD)/$(SWARM_DIRECTORY)/data:/pwd" busybox \
sh -c "cd /pwd && rm -rf alertmanager/* clickhouse/* signoz/*"

View File

@@ -6,7 +6,7 @@
<p align="center">
<img alt="License" src="https://img.shields.io/badge/license-MIT-brightgreen"> </a>
<img alt="Downloads" src="https://img.shields.io/docker/pulls/signoz/frontend?label=Downloads"> </a>
<img alt="Downloads" src="https://img.shields.io/docker/pulls/signoz/query-service?label=Downloads"> </a>
<img alt="GitHub issues" src="https://img.shields.io/github/issues/signoz/signoz"> </a>
<a href="https://twitter.com/intent/tweet?text=Monitor%20your%20applications%20and%20troubleshoot%20problems%20with%20SigNoz,%20an%20open-source%20alternative%20to%20DataDog,%20NewRelic.&url=https://signoz.io/&via=SigNozHQ&hashtags=opensource,signoz,observability">
<img alt="tweet" src="https://img.shields.io/twitter/url/http/shields.io.svg?style=social"> </a>
@@ -34,8 +34,10 @@ SigNoz helps developers monitor applications and troubleshoot problems in their
![screenzy-1644432902955](https://user-images.githubusercontent.com/504541/153270713-1b2156e6-ec03-42de-975b-3c02b8ec1836.png)
<br />
![screenzy-1644432986784](https://user-images.githubusercontent.com/504541/153270725-0efb73b3-06ed-4207-bf13-9b7e2e17c4b8.png)
<br />
![screenzy-1647005040573](https://user-images.githubusercontent.com/504541/157875938-a3d57904-ea6d-4278-b929-bd1408d7f94c.png)
<br /><br />

View File

@@ -0,0 +1,35 @@
global:
resolve_timeout: 1m
slack_api_url: 'https://hooks.slack.com/services/xxx'
route:
receiver: 'slack-notifications'
receivers:
- name: 'slack-notifications'
slack_configs:
- channel: '#alerts'
send_resolved: true
icon_url: https://avatars3.githubusercontent.com/u/3380462
title: |-
[{{ .Status | toUpper }}{{ if eq .Status "firing" }}:{{ .Alerts.Firing | len }}{{ end }}] {{ .CommonLabels.alertname }} for {{ .CommonLabels.job }}
{{- if gt (len .CommonLabels) (len .GroupLabels) -}}
{{" "}}(
{{- with .CommonLabels.Remove .GroupLabels.Names }}
{{- range $index, $label := .SortedPairs -}}
{{ if $index }}, {{ end }}
{{- $label.Name }}="{{ $label.Value -}}"
{{- end }}
{{- end -}}
)
{{- end }}
text: >-
{{ range .Alerts -}}
*Alert:* {{ .Annotations.title }}{{ if .Labels.severity }} - `{{ .Labels.severity }}`{{ end }}
*Description:* {{ .Annotations.description }}
*Details:*
{{ range .Labels.SortedPairs }} • *{{ .Name }}:* `{{ .Value }}`
{{ end }}
{{ end }}

View File

@@ -0,0 +1,11 @@
groups:
- name: ExampleCPULoadGroup
rules:
- alert: HighCpuLoad
expr: system_cpu_load_average_1m > 0.1
for: 0m
labels:
severity: warning
annotations:
summary: High CPU load
description: "CPU load is > 0.1\n VALUE = {{ $value }}\n LABELS = {{ $labels }}"

View File

@@ -1,11 +1,8 @@
<?xml version="1.0"?>
<yandex>
<logger>
<level>trace</level>
<log>/var/log/clickhouse-server/clickhouse-server.log</log>
<errorlog>/var/log/clickhouse-server/clickhouse-server.err.log</errorlog>
<size>1000M</size>
<count>10</count>
<level>information</level>
<console>1</console>
</logger>
<http_port>8123</http_port>
@@ -45,6 +42,34 @@
</client>
</openSSL>
<!-- Example config for tiered storage -->
<!-- <storage_configuration>
<disks>
<default>
<keep_free_space_bytes>10485760</keep_free_space_bytes>
</default>
<s3>
<type>s3</type>
<endpoint>https://BUCKET-NAME.s3.amazonaws.com/data/</endpoint>
<access_key_id>ACCESS-KEY-ID</access_key_id>
<secret_access_key>SECRET-ACCESS-KEY</secret_access_key>
</s3>
</disks>
<policies>
<tiered>
<volumes>
<default>
<disk>default</disk>
</default>
<s3>
<disk>s3</disk>
</s3>
</volumes>
</tiered>
</policies>
</storage_configuration> -->
<!-- Default root page on http[s] server. For example load UI from https://tabix.io/ when opening http://localhost:8123 -->
<!--
<http_server_default_response><![CDATA[<html ng-app="SMI2"><head><base href="http://ui.tabix.io/"></head><body><div ui-view="" class="content-ui"></div><script src="http://loader.tabix.io/master.js"></script></body></html>]]></http_server_default_response>

View File

@@ -1,30 +1,43 @@
version: "3"
version: "3.9"
services:
clickhouse:
image: yandex/clickhouse-server
expose:
- 8123
- 9000
ports:
- 9001:9000
- 8123:8123
volumes:
- ./clickhouse-config.xml:/etc/clickhouse-server/config.xml
- ./docker-entrypoint-initdb.d/init-db.sql:/docker-entrypoint-initdb.d/init-db.sql
- ./data/clickhouse/:/var/lib/clickhouse/
image: yandex/clickhouse-server:21.12.3.32
# ports:
# - "9000:9000"
# - "8123:8123"
volumes:
- ./clickhouse-config.xml:/etc/clickhouse-server/config.xml
- ./data/clickhouse/:/var/lib/clickhouse/
deploy:
restart_policy:
condition: on-failure
logging:
options:
max-size: 50m
max-file: "3"
healthcheck:
# "clickhouse", "client", "-u ${CLICKHOUSE_USER}", "--password ${CLICKHOUSE_PASSWORD}", "-q 'SELECT 1'"
test: ["CMD", "wget", "--spider", "-q", "localhost:8123/ping"]
interval: 30s
timeout: 5s
retries: 3
healthcheck:
# "clickhouse", "client", "-u ${CLICKHOUSE_USER}", "--password ${CLICKHOUSE_PASSWORD}", "-q 'SELECT 1'"
test: ["CMD", "wget", "--spider", "-q", "localhost:8123/ping"]
interval: 30s
timeout: 5s
retries: 3
alertmanager:
image: signoz/alertmanager:0.6.1
volumes:
- ./data/alertmanager:/data
command:
- --queryService.url=http://query-service:8080
- --storage.path=/data
depends_on:
- query-service
deploy:
restart_policy:
condition: on-failure
query-service:
image: signoz/query-service:0.4.1
container_name: query-service
restart: always
image: signoz/query-service:0.7.5
command: ["-config=/root/config/prometheus.yml"]
ports:
- "8080:8080"
@@ -35,72 +48,84 @@ services:
environment:
- ClickHouseUrl=tcp://clickhouse:9000
- STORAGE=clickhouse
- POSTHOG_API_KEY=H-htDCae7CR3RV57gUzmol6IAKtm5IMCvbcm_fwnL-w
- GODEBUG=netdns=go
depends_on:
- clickhouse
- TELEMETRY_ENABLED=true
- DEPLOYMENT_TYPE=docker-swarm
healthcheck:
test: ["CMD", "wget", "--spider", "-q", "localhost:8080/api/v1/version"]
interval: 30s
timeout: 5s
retries: 3
deploy:
restart_policy:
condition: on-failure
depends_on:
- clickhouse
frontend:
image: signoz/frontend:0.4.1
container_name: frontend
image: signoz/frontend:0.7.5
deploy:
restart_policy:
condition: on-failure
depends_on:
- alertmanager
- query-service
links:
- "query-service"
ports:
- "3301:3301"
volumes:
- ../common/nginx-config.conf:/etc/nginx/conf.d/default.conf
otel-collector:
image: signoz/otelcontribcol:0.4.0
command: ["--config=/etc/otel-collector-config.yaml", "--mem-ballast-size-mib=2000"]
image: signoz/otelcontribcol:0.43.0
command: ["--config=/etc/otel-collector-config.yaml"]
volumes:
- ./otel-collector-config.yaml:/etc/otel-collector-config.yaml
ports:
- "1777:1777" # pprof extension
- "8887:8888" # Prometheus metrics exposed by the agent
- "14268:14268" # Jaeger receiver
- "55678" # OpenCensus receiver
- "55680:55680" # OTLP HTTP/2.0 legacy port
- "55681:55681" # OTLP HTTP/1.0 receiver
- "4317:4317" # OTLP GRPC receiver
- "55679:55679" # zpages extension
- "13133" # health_check
- "4317:4317" # OTLP gRPC receiver
- "4318:4318" # OTLP HTTP receiver
# - "8889:8889" # Prometheus metrics exposed by the agent
# - "13133" # health_check
# - "14268:14268" # Jaeger receiver
# - "55678:55678" # OpenCensus receiver
# - "55679:55679" # zpages extension
# - "55680:55680" # OTLP gRPC legacy receiver
# - "55681:55681" # OTLP HTTP legacy receiver
deploy:
mode: replicated
replicas: 3
restart_policy:
condition: on-failure
resources:
limits:
memory: 2000m
depends_on:
- clickhouse
- clickhouse
otel-collector-hostmetrics:
image: signoz/otelcontribcol:0.4.0
command: ["--config=/etc/otel-collector-config-hostmetrics.yaml", "--mem-ballast-size-mib=683"]
otel-collector-metrics:
image: signoz/otelcontribcol:0.43.0
command: ["--config=/etc/otel-collector-metrics-config.yaml"]
volumes:
- ./otel-collector-config-hostmetrics.yaml:/etc/otel-collector-config-hostmetrics.yaml
- ./otel-collector-metrics-config.yaml:/etc/otel-collector-metrics-config.yaml
deploy:
restart_policy:
condition: on-failure
depends_on:
- clickhouse
- clickhouse
hotrod:
image: jaegertracing/example-hotrod:latest
container_name: hotrod
ports:
- "9000:8080"
image: jaegertracing/example-hotrod:1.30
command: ["all"]
environment:
- JAEGER_ENDPOINT=http://otel-collector:14268/api/traces
- JAEGER_ENDPOINT=http://otel-collector:14268/api/traces
logging:
options:
max-size: 50m
max-file: "3"
load-hotrod:
image: "grubykarol/locust:1.2.3-python3.9-alpine3.12"
container_name: load-hotrod
hostname: load-hotrod
ports:
- "8089:8089"
environment:
ATTACKED_HOST: http://hotrod:8080
LOCUST_MODE: standalone
@@ -110,4 +135,4 @@ services:
QUIET_MODE: "${QUIET_MODE:-false}"
LOCUST_OPTS: "--headless -u 10 -r 1"
volumes:
- ../common/locust-scripts:/locust
- ../common/locust-scripts:/locust

View File

@@ -1,4 +1,8 @@
receivers:
otlp/spanmetrics:
protocols:
grpc:
endpoint: "localhost:12345"
otlp:
protocols:
grpc:
@@ -7,18 +11,34 @@ receivers:
protocols:
grpc:
thrift_http:
hostmetrics:
collection_interval: 30s
scrapers:
cpu:
load:
memory:
disk:
filesystem:
network:
processors:
batch:
send_batch_size: 1000
timeout: 10s
memory_limiter:
# Same as --mem-ballast-size-mib CLI argument
ballast_size_mib: 683
# 80% of maximum memory up to 2G
limit_mib: 1500
# 25% of limit up to 2G
spike_limit_mib: 512
check_interval: 5s
signozspanmetrics/prometheus:
metrics_exporter: prometheus
latency_histogram_buckets: [100us, 1ms, 2ms, 6ms, 10ms, 50ms, 100ms, 250ms, 500ms, 1000ms, 1400ms, 2000ms, 5s, 10s, 20s, 40s, 60s ]
dimensions_cache_size: 10000
# memory_limiter:
# # 80% of maximum memory up to 2G
# limit_mib: 1500
# # 25% of limit up to 2G
# spike_limit_mib: 512
# check_interval: 5s
#
# # 50% of the maximum memory
# limit_percentage: 50
# # 20% of max memory usage spike expected
# spike_limit_percentage: 20
# queued_retry:
# num_workers: 4
# queue_size: 100
@@ -33,15 +53,19 @@ exporters:
endpoint: tcp://clickhouse:9000/?database=signoz_metrics
resource_to_telemetry_conversion:
enabled: true
prometheus:
endpoint: "0.0.0.0:8889"
service:
extensions: [health_check, zpages]
pipelines:
traces:
receivers: [jaeger, otlp]
processors: [batch]
processors: [signozspanmetrics/prometheus, batch]
exporters: [clickhouse]
metrics:
receivers: [otlp]
receivers: [otlp, hostmetrics]
processors: [batch]
exporters: [clickhousemetricswrite]
exporters: [clickhousemetricswrite]
metrics/spanmetrics:
receivers: [otlp/spanmetrics]
exporters: [prometheus]

View File

@@ -0,0 +1,47 @@
receivers:
otlp:
protocols:
grpc:
http:
# Data sources: metrics
prometheus:
config:
scrape_configs:
- job_name: "otel-collector"
scrape_interval: 30s
static_configs:
- targets: ["otel-collector:8889"]
processors:
batch:
send_batch_size: 1000
timeout: 10s
# memory_limiter:
# # 80% of maximum memory up to 2G
# limit_mib: 1500
# # 25% of limit up to 2G
# spike_limit_mib: 512
# check_interval: 5s
#
# # 50% of the maximum memory
# limit_percentage: 50
# # 20% of max memory usage spike expected
# spike_limit_percentage: 20
# queued_retry:
# num_workers: 4
# queue_size: 100
# retry_on_failure: true
extensions:
health_check: {}
zpages: {}
exporters:
clickhousemetricswrite:
endpoint: tcp://clickhouse:9000/?database=signoz_metrics
service:
extensions: [health_check, zpages]
pipelines:
metrics:
receivers: [otlp, prometheus]
processors: [batch]
exporters: [clickhousemetricswrite]

View File

@@ -9,12 +9,13 @@ alerting:
alertmanagers:
- static_configs:
- targets:
# - alertmanager:9093
- alertmanager:9093
# Load rules once and periodically evaluate them according to the global 'evaluation_interval'.
rule_files:
# - "first_rules.yml"
# - "second_rules.yml"
- 'alerts.yml'
# A scrape configuration containing exactly one endpoint to scrape:
# Here it's Prometheus itself.

View File

@@ -1,11 +1,8 @@
<?xml version="1.0"?>
<yandex>
<logger>
<level>trace</level>
<log>/var/log/clickhouse-server/clickhouse-server.log</log>
<errorlog>/var/log/clickhouse-server/clickhouse-server.err.log</errorlog>
<size>1000M</size>
<count>10</count>
<level>information</level>
<console>1</console>
</logger>
<http_port>8123</http_port>
@@ -45,6 +42,34 @@
</client>
</openSSL>
<!-- Example config for tiered storage -->
<!-- <storage_configuration>
<disks>
<default>
<keep_free_space_bytes>10485760</keep_free_space_bytes>
</default>
<s3>
<type>s3</type>
<endpoint>https://BUCKET-NAME.s3.amazonaws.com/data/</endpoint>
<access_key_id>ACCESS-KEY-ID</access_key_id>
<secret_access_key>SECRET-ACCESS-KEY</secret_access_key>
</s3>
</disks>
<policies>
<tiered>
<volumes>
<default>
<disk>default</disk>
</default>
<s3>
<disk>s3</disk>
</s3>
</volumes>
</tiered>
</policies>
</storage_configuration> -->
<!-- Default root page on http[s] server. For example load UI from https://tabix.io/ when opening http://localhost:8123 -->
<!--
<http_server_default_response><![CDATA[<html ng-app="SMI2"><head><base href="http://ui.tabix.io/"></head><body><div ui-view="" class="content-ui"></div><script src="http://loader.tabix.io/master.js"></script></body></html>]]></http_server_default_response>

View File

@@ -3,9 +3,17 @@ version: "2.4"
services:
clickhouse:
image: altinity/clickhouse-server:21.12.3.32.altinitydev.arm
# ports:
# - "9000:9000"
# - "8123:8123"
volumes:
- ./clickhouse-config.xml:/etc/clickhouse-server/config.xml
- ./data/clickhouse/:/var/lib/clickhouse/
restart: on-failure
logging:
options:
max-size: 50m
max-file: "3"
healthcheck:
# "clickhouse", "client", "-u ${CLICKHOUSE_USER}", "--password ${CLICKHOUSE_PASSWORD}", "-q 'SELECT 1'"
test: ["CMD", "wget", "--spider", "-q", "localhost:8123/ping"]
@@ -14,16 +22,19 @@ services:
retries: 3
alertmanager:
image: signoz/alertmanager:0.5.0
image: signoz/alertmanager:0.6.1
volumes:
- ./alertmanager.yml:/prometheus/alertmanager.yml
- ./data/alertmanager:/data
depends_on:
query-service:
condition: service_healthy
restart: on-failure
command:
- '--config.file=/prometheus/alertmanager.yml'
- '--storage.path=/data'
- --queryService.url=http://query-service:8080
- --storage.path=/data
query-service:
image: signoz/query-service:0.6.1
image: signoz/query-service:0.7.5
container_name: query-service
command: ["-config=/root/config/prometheus.yml"]
volumes:
@@ -35,14 +46,24 @@ services:
- STORAGE=clickhouse
- GODEBUG=netdns=go
- TELEMETRY_ENABLED=true
- DEPLOYMENT_TYPE=docker-standalone-arm
restart: on-failure
healthcheck:
test: ["CMD", "wget", "--spider", "-q", "localhost:8080/api/v1/version"]
interval: 30s
timeout: 5s
retries: 3
depends_on:
clickhouse:
condition: service_healthy
frontend:
image: signoz/frontend:0.6.1
image: signoz/frontend:0.7.5
container_name: frontend
restart: on-failure
depends_on:
- alertmanager
- query-service
ports:
- "3301:3301"
@@ -50,23 +71,32 @@ services:
- ../common/nginx-config.conf:/etc/nginx/conf.d/default.conf
otel-collector:
image: signoz/otelcontribcol:0.5.0
command: ["--config=/etc/otel-collector-config.yaml", "--mem-ballast-size-mib=683"]
image: signoz/otelcontribcol:0.43.0
command: ["--config=/etc/otel-collector-config.yaml"]
volumes:
- ./otel-collector-config.yaml:/etc/otel-collector-config.yaml
ports:
- "4317:4317" # OTLP GRPC receiver
- "4317:4317" # OTLP gRPC receiver
- "4318:4318" # OTLP HTTP receiver
# - "8889:8889" # Prometheus metrics exposed by the agent
# - "13133" # health_check
# - "14268:14268" # Jaeger receiver
# - "55678:55678" # OpenCensus receiver
# - "55679:55679" # zpages extension
# - "55680:55680" # OTLP gRPC legacy receiver
# - "55681:55681" # OTLP HTTP legacy receiver
mem_limit: 2000m
restart: always
restart: on-failure
depends_on:
clickhouse:
condition: service_healthy
otel-collector-metrics:
image: signoz/otelcontribcol:0.5.0
command: ["--config=/etc/otel-collector-metrics-config.yaml", "--mem-ballast-size-mib=683"]
image: signoz/otelcontribcol:0.43.0
command: ["--config=/etc/otel-collector-metrics-config.yaml"]
volumes:
- ./otel-collector-metrics-config.yaml:/etc/otel-collector-metrics-config.yaml
restart: on-failure
depends_on:
clickhouse:
condition: service_healthy
@@ -80,7 +110,7 @@ services:
max-file: "3"
command: ["all"]
environment:
- JAEGER_ENDPOINT=http://otel-collector:14268/api/traces
- JAEGER_ENDPOINT=http://otel-collector:14268/api/traces
load-hotrod:
image: "grubykarol/locust:1.2.3-python3.9-alpine3.12"

View File

@@ -3,9 +3,17 @@ version: "2.4"
services:
clickhouse:
image: yandex/clickhouse-server:21.12.3.32
# ports:
# - "9000:9000"
# - "8123:8123"
volumes:
- ./clickhouse-config.xml:/etc/clickhouse-server/config.xml
- ./data/clickhouse/:/var/lib/clickhouse/
restart: on-failure
logging:
options:
max-size: 50m
max-file: "3"
healthcheck:
# "clickhouse", "client", "-u ${CLICKHOUSE_USER}", "--password ${CLICKHOUSE_PASSWORD}", "-q 'SELECT 1'"
test: ["CMD", "wget", "--spider", "-q", "localhost:8123/ping"]
@@ -14,19 +22,21 @@ services:
retries: 3
alertmanager:
image: signoz/alertmanager:0.5.0
image: signoz/alertmanager:0.6.1
volumes:
- ./alertmanager.yml:/prometheus/alertmanager.yml
- ./data/alertmanager:/data
depends_on:
query-service:
condition: service_healthy
restart: on-failure
command:
- '--config.file=/prometheus/alertmanager.yml'
- '--storage.path=/data'
- --queryService.url=http://query-service:8080
- --storage.path=/data
# Notes for Maintainers/Contributors who will change Line Numbers of Frontend & Query-Section. Please Update Line Numbers in `./scripts/commentLinesForSetup.sh` & `./CONTRIBUTING.md`
query-service:
image: signoz/query-service:0.6.1
image: signoz/query-service:0.7.5
container_name: query-service
command: ["-config=/root/config/prometheus.yml"]
volumes:
@@ -38,14 +48,23 @@ services:
- STORAGE=clickhouse
- GODEBUG=netdns=go
- TELEMETRY_ENABLED=true
- DEPLOYMENT_TYPE=docker-standalone-amd
restart: on-failure
healthcheck:
test: ["CMD", "wget", "--spider", "-q", "localhost:8080/api/v1/version"]
interval: 30s
timeout: 5s
retries: 3
depends_on:
clickhouse:
condition: service_healthy
frontend:
image: signoz/frontend:0.6.1
image: signoz/frontend:0.7.5
container_name: frontend
restart: on-failure
depends_on:
- alertmanager
- query-service
ports:
- "3301:3301"
@@ -53,23 +72,32 @@ services:
- ../common/nginx-config.conf:/etc/nginx/conf.d/default.conf
otel-collector:
image: signoz/otelcontribcol:0.5.0
command: ["--config=/etc/otel-collector-config.yaml", "--mem-ballast-size-mib=683"]
image: signoz/otelcontribcol:0.43.0
command: ["--config=/etc/otel-collector-config.yaml"]
volumes:
- ./otel-collector-config.yaml:/etc/otel-collector-config.yaml
ports:
- "4317:4317" # OTLP GRPC receiver
- "4317:4317" # OTLP gRPC receiver
- "4318:4318" # OTLP HTTP receiver
# - "8889:8889" # Prometheus metrics exposed by the agent
# - "13133" # health_check
# - "14268:14268" # Jaeger receiver
# - "55678:55678" # OpenCensus receiver
# - "55679:55679" # zpages extension
# - "55680:55680" # OTLP gRPC legacy receiver
# - "55681:55681" # OTLP HTTP legacy receiver
mem_limit: 2000m
restart: always
restart: on-failure
depends_on:
clickhouse:
condition: service_healthy
otel-collector-metrics:
image: signoz/otelcontribcol:0.5.0
command: ["--config=/etc/otel-collector-metrics-config.yaml", "--mem-ballast-size-mib=683"]
image: signoz/otelcontribcol:0.43.0
command: ["--config=/etc/otel-collector-metrics-config.yaml"]
volumes:
- ./otel-collector-metrics-config.yaml:/etc/otel-collector-metrics-config.yaml
restart: on-failure
depends_on:
clickhouse:
condition: service_healthy

View File

@@ -27,14 +27,18 @@ processors:
signozspanmetrics/prometheus:
metrics_exporter: prometheus
latency_histogram_buckets: [100us, 1ms, 2ms, 6ms, 10ms, 50ms, 100ms, 250ms, 500ms, 1000ms, 1400ms, 2000ms, 5s, 10s, 20s, 40s, 60s ]
memory_limiter:
# Same as --mem-ballast-size-mib CLI argument
ballast_size_mib: 683
# 80% of maximum memory up to 2G
limit_mib: 1500
# 25% of limit up to 2G
spike_limit_mib: 512
check_interval: 5s
dimensions_cache_size: 10000
# memory_limiter:
# # 80% of maximum memory up to 2G
# limit_mib: 1500
# # 25% of limit up to 2G
# spike_limit_mib: 512
# check_interval: 5s
#
# # 50% of the maximum memory
# limit_percentage: 50
# # 20% of max memory usage spike expected
# spike_limit_percentage: 20
# queued_retry:
# num_workers: 4
# queue_size: 100

View File

@@ -16,14 +16,17 @@ processors:
batch:
send_batch_size: 1000
timeout: 10s
memory_limiter:
# Same as --mem-ballast-size-mib CLI argument
ballast_size_mib: 683
# 80% of maximum memory up to 2G
limit_mib: 1500
# 25% of limit up to 2G
spike_limit_mib: 512
check_interval: 5s
# memory_limiter:
# # 80% of maximum memory up to 2G
# limit_mib: 1500
# # 25% of limit up to 2G
# spike_limit_mib: 512
# check_interval: 5s
#
# # 50% of the maximum memory
# limit_percentage: 50
# # 20% of max memory usage spike expected
# spike_limit_percentage: 20
# queued_retry:
# num_workers: 4
# queue_size: 100

View File

@@ -102,7 +102,7 @@ check_os() {
# The script should error out in case they aren't available
check_ports_occupied() {
local port_check_output
local ports_pattern="80|3301|8080"
local ports_pattern="3301|4317"
if is_mac; then
port_check_output="$(netstat -anp tcp | awk '$6 == "LISTEN" && $4 ~ /^.*\.('"$ports_pattern"')$/')"
@@ -119,7 +119,7 @@ check_ports_occupied() {
send_event "port_not_available"
echo "+++++++++++ ERROR ++++++++++++++++++++++"
echo "SigNoz requires ports 80 & 443 to be open. Please shut down any other service(s) that may be running on these ports."
echo "SigNoz requires ports 3301 & 4317 to be open. Please shut down any other service(s) that may be running on these ports."
echo "You can run SigNoz on another port following this guide https://signoz.io/docs/deployment/docker#troubleshooting"
echo "++++++++++++++++++++++++++++++++++++++++"
echo ""
@@ -133,58 +133,44 @@ install_docker() {
if [[ $package_manager == apt-get ]]; then
apt_cmd="sudo apt-get --yes --quiet"
apt_cmd="$sudo_cmd apt-get --yes --quiet"
$apt_cmd update
$apt_cmd install software-properties-common gnupg-agent
curl -fsSL "https://download.docker.com/linux/$os/gpg" | sudo apt-key add -
sudo add-apt-repository \
curl -fsSL "https://download.docker.com/linux/$os/gpg" | $sudo_cmd apt-key add -
$sudo_cmd add-apt-repository \
"deb [arch=amd64] https://download.docker.com/linux/$os $(lsb_release -cs) stable"
$apt_cmd update
echo "Installing docker"
$apt_cmd install docker-ce docker-ce-cli containerd.io
elif [[ $package_manager == zypper ]]; then
zypper_cmd="sudo zypper --quiet --no-gpg-checks --non-interactive"
zypper_cmd="$sudo_cmd zypper --quiet --no-gpg-checks --non-interactive"
echo "Installing docker"
if [[ $os == sles ]]; then
os_sp="$(cat /etc/*-release | awk -F= '$1 == "VERSION_ID" { gsub(/"/, ""); print $2; exit }')"
os_arch="$(uname -i)"
sudo SUSEConnect -p sle-module-containers/$os_sp/$os_arch -r ''
SUSEConnect -p sle-module-containers/$os_sp/$os_arch -r ''
fi
$zypper_cmd install docker docker-runc containerd
sudo systemctl enable docker.service
$sudo_cmd systemctl enable docker.service
elif [[ $package_manager == yum && $os == 'amazon linux' ]]; then
echo
echo "Amazon Linux detected ... "
echo
# sudo yum install docker
# sudo service docker start
sudo amazon-linux-extras install docker
# yum install docker
# service docker start
$sudo_cmd yum install -y amazon-linux-extras
$sudo_cmd amazon-linux-extras enable docker
$sudo_cmd yum install -y docker
else
yum_cmd="sudo yum --assumeyes --quiet"
yum_cmd="$sudo_cmd yum --assumeyes --quiet"
$yum_cmd install yum-utils
sudo yum-config-manager --add-repo https://download.docker.com/linux/$os/docker-ce.repo
$sudo_cmd yum-config-manager --add-repo https://download.docker.com/linux/$os/docker-ce.repo
echo "Installing docker"
$yum_cmd install docker-ce docker-ce-cli containerd.io
fi
}
install_docker_machine() {
echo "\nInstalling docker machine ..."
if [[ $os == "Mac" ]];then
curl -sL https://github.com/docker/machine/releases/download/v0.16.2/docker-machine-`uname -s`-`uname -m` >/usr/local/bin/docker-machine
chmod +x /usr/local/bin/docker-machine
else
curl -sL https://github.com/docker/machine/releases/download/v0.16.2/docker-machine-`uname -s`-`uname -m` >/tmp/docker-machine
chmod +x /tmp/docker-machine
sudo cp /tmp/docker-machine /usr/local/bin/docker-machine
fi
}
install_docker_compose() {
@@ -192,9 +178,9 @@ install_docker_compose() {
if [[ ! -f /usr/bin/docker-compose ]];then
echo "++++++++++++++++++++++++"
echo "Installing docker-compose"
sudo curl -L "https://github.com/docker/compose/releases/download/1.26.0/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose
sudo ln -s /usr/local/bin/docker-compose /usr/bin/docker-compose
$sudo_cmd curl -L "https://github.com/docker/compose/releases/download/1.26.0/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
$sudo_cmd chmod +x /usr/local/bin/docker-compose
$sudo_cmd ln -s /usr/local/bin/docker-compose /usr/bin/docker-compose
echo "docker-compose installed!"
echo ""
fi
@@ -210,16 +196,23 @@ install_docker_compose() {
}
start_docker() {
echo "Starting Docker ..."
if [ $os = "Mac" ]; then
echo -e "🐳 Starting Docker ...\n"
if [[ $os == "Mac" ]]; then
open --background -a Docker && while ! docker system info > /dev/null 2>&1; do sleep 1; done
else
if ! sudo systemctl is-active docker.service > /dev/null; then
if ! $sudo_cmd systemctl is-active docker.service > /dev/null; then
echo "Starting docker service"
sudo systemctl start docker.service
$sudo_cmd systemctl start docker.service
fi
if [[ -z $sudo_cmd ]]; then
docker ps > /dev/null && true
if [[ $? -ne 0 ]]; then
request_sudo
fi
fi
fi
}
wait_for_containers_start() {
local timeout=$1
@@ -229,16 +222,6 @@ wait_for_containers_start() {
if [[ status_code -eq 200 ]]; then
break
else
if [ $setup_type == 'druid' ]; then
SUPERVISORS="$(curl -so - http://localhost:8888/druid/indexer/v1/supervisor)"
LEN_SUPERVISORS="${#SUPERVISORS}"
if [[ LEN_SUPERVISORS -ne 19 && $timeout -eq 50 ]];then
echo -e "\n🟠 Supervisors taking time to start ⏳ ... let's wait for some more time ⏱️\n\n"
sudo docker-compose -f ./docker/druid-kafka-setup/docker-compose-tiny.yaml up -d
fi
fi
echo -ne "Waiting for all containers to start. This check will timeout in $timeout seconds ...\r\c"
fi
((timeout--))
@@ -249,31 +232,30 @@ wait_for_containers_start() {
}
bye() { # Prints a friendly good bye message and exits the script.
if [ "$?" -ne 0 ]; then
if [[ "$?" -ne 0 ]]; then
set +o errexit
echo "🔴 The containers didn't seem to start correctly. Please run the following command to check containers that may have errored out:"
echo ""
if [ $setup_type == 'clickhouse' ]; then
if is_arm64; then
echo -e "sudo docker-compose -f ./docker/clickhouse-setup/docker-compose.arm.yaml ps -a"
else
echo -e "sudo docker-compose -f ./docker/clickhouse-setup/docker-compose.yaml ps -a"
fi
else
echo -e "sudo docker-compose -f ./docker/druid-kafka-setup/docker-compose-tiny.yaml ps -a"
if is_arm64; then
echo -e "$sudo_cmd docker-compose -f ./docker/clickhouse-setup/docker-compose.arm.yaml ps -a"
else
echo -e "$sudo_cmd docker-compose -f ./docker/clickhouse-setup/docker-compose.yaml ps -a"
fi
# echo "Please read our troubleshooting guide https://signoz.io/docs/deployment/docker#troubleshooting"
echo "or reach us for support in #help channel in our Slack Community https://signoz.io/slack"
echo "++++++++++++++++++++++++++++++++++++++++"
echo -e "\n📨 Please share your email to receive support with the installation"
read -rp 'Email: ' email
while [[ $email == "" ]]
do
if [[ $email == "" ]]; then
echo -e "\n📨 Please share your email to receive support with the installation"
read -rp 'Email: ' email
done
while [[ $email == "" ]]
do
read -rp 'Email: ' email
done
fi
send_event "installation_support"
@@ -284,26 +266,67 @@ bye() { # Prints a friendly good bye message and exits the script.
fi
}
request_sudo() {
if hash sudo 2>/dev/null; then
echo -e "\n\n🙇 We will need sudo access to complete the installation."
if (( $EUID != 0 )); then
sudo_cmd="sudo"
echo -e "Please enter your sudo password, if prompt."
$sudo_cmd -l | grep -e "NOPASSWD: ALL" > /dev/null
if [[ $? -ne 0 ]] && ! $sudo_cmd -v; then
echo "Need sudo privileges to proceed with the installation."
exit 1;
fi
echo -e "Got it! Thanks!! 🙏\n"
echo -e "Okay! We will bring up the SigNoz cluster from here 🚀\n"
fi
fi
}
echo ""
echo -e "👋 Thank you for trying out SigNoz! "
echo ""
sudo_cmd=""
# Check sudo permissions
if (( $EUID != 0 )); then
echo "🟡 Running installer with non-sudo permissions."
echo " In case of any failure or prompt, please consider running the script with sudo privileges."
echo ""
else
sudo_cmd="sudo"
fi
# Checking OS and assigning package manager
desired_os=0
os=""
email=""
echo -e "Detecting your OS ..."
echo -e "🌏 Detecting your OS ...\n"
check_os
# Obtain unique installation id
sysinfo="$(uname -a)"
if [ $? -ne 0 ]; then
if [[ $? -ne 0 ]]; then
uuid="$(uuidgen)"
uuid="${uuid:-$(cat /proc/sys/kernel/random/uuid)}"
SIGNOZ_INSTALLATION_ID="${uuid:-$(cat /proc/sys/kernel/random/uuid)}"
sysinfo="${uuid:-$(cat /proc/sys/kernel/random/uuid)}"
fi
digest_cmd=""
if hash shasum 2>/dev/null; then
digest_cmd="shasum -a 256"
elif hash sha256sum 2>/dev/null; then
digest_cmd="sha256sum"
elif hash openssl 2>/dev/null; then
digest_cmd="openssl dgst -sha256"
fi
if [[ -z $digest_cmd ]]; then
SIGNOZ_INSTALLATION_ID="$sysinfo"
else
SIGNOZ_INSTALLATION_ID=$(echo "$sysinfo" | shasum | cut -d ' ' -f1)
SIGNOZ_INSTALLATION_ID=$(echo "$sysinfo" | $digest_cmd | grep -E -o '[a-zA-Z0-9]{64}')
fi
# echo ""
@@ -364,13 +387,7 @@ send_event() {
'installation_error_checks')
event="Installation Error - Checks"
error="Containers not started"
if [ $setup_type == 'clickhouse' ]; then
others='"data": "some_checks",'
else
supervisors="$(curl -so - http://localhost:8888/druid/indexer/v1/supervisor)"
datasources="$(curl -so - http://localhost:8888/druid/coordinator/v1/datasources)"
others='"supervisors": "'"$supervisors"'", "datasources": "'"$datasources"'",'
fi
others='"data": "some_checks",'
;;
'installation_support')
event="Installation Support"
@@ -389,7 +406,7 @@ send_event() {
;;
esac
if [ "$error" != "" ]; then
if [[ "$error" != "" ]]; then
error='"error": "'"$error"'", '
fi
@@ -412,15 +429,28 @@ fi
# Check is Docker daemon is installed and available. If not, the install & start Docker for Linux machines. We cannot automatically install Docker Desktop on Mac OS
if ! is_command_present docker; then
if [[ $package_manager == "apt-get" || $package_manager == "zypper" || $package_manager == "yum" ]]; then
request_sudo
install_docker
else
# enable docker without sudo from next reboot
sudo usermod -aG docker "${USER}"
elif is_mac; then
echo ""
echo "+++++++++++ IMPORTANT READ ++++++++++++++++++++++"
echo "Docker Desktop must be installed manually on Mac OS to proceed. Docker can only be installed automatically on Ubuntu / openSUSE / SLES / Redhat / Cent OS"
echo "https://docs.docker.com/docker-for-mac/install/"
echo "++++++++++++++++++++++++++++++++++++++++++++++++"
send_event "docker_not_installed"
exit 1
else
echo ""
echo "+++++++++++ IMPORTANT READ ++++++++++++++++++++++"
echo "Docker must be installed manually on your machine to proceed. Docker can only be installed automatically on Ubuntu / openSUSE / SLES / Redhat / Cent OS"
echo "https://docs.docker.com/get-docker/"
echo "++++++++++++++++++++++++++++++++++++++++++++++++"
send_event "docker_not_installed"
exit 1
fi
@@ -428,42 +458,32 @@ fi
# Install docker-compose
if ! is_command_present docker-compose; then
request_sudo
install_docker_compose
fi
start_docker
# sudo docker-compose -f ./docker/clickhouse-setup/docker-compose.yaml up -d --remove-orphans || true
# $sudo_cmd docker-compose -f ./docker/clickhouse-setup/docker-compose.yaml up -d --remove-orphans || true
echo ""
echo -e "\n🟡 Pulling the latest container images for SigNoz. To run as sudo it may ask for system password\n"
if [ $setup_type == 'clickhouse' ]; then
if is_arm64; then
sudo docker-compose -f ./docker/clickhouse-setup/docker-compose.arm.yaml pull
else
sudo docker-compose -f ./docker/clickhouse-setup/docker-compose.yaml pull
fi
echo -e "\n🟡 Pulling the latest container images for SigNoz.\n"
if is_arm64; then
$sudo_cmd docker-compose -f ./docker/clickhouse-setup/docker-compose.arm.yaml pull
else
sudo docker-compose -f ./docker/druid-kafka-setup/docker-compose-tiny.yaml pull
$sudo_cmd docker-compose -f ./docker/clickhouse-setup/docker-compose.yaml pull
fi
echo ""
echo "🟡 Starting the SigNoz containers. It may take a few minutes ..."
echo
# The docker-compose command does some nasty stuff for the `--detach` functionality. So we add a `|| true` so that the
# script doesn't exit because this command looks like it failed to do it's thing.
if [ $setup_type == 'clickhouse' ]; then
if is_arm64; then
sudo docker-compose -f ./docker/clickhouse-setup/docker-compose.arm.yaml up --detach --remove-orphans || true
else
sudo docker-compose -f ./docker/clickhouse-setup/docker-compose.yaml up --detach --remove-orphans || true
fi
if is_arm64; then
$sudo_cmd docker-compose -f ./docker/clickhouse-setup/docker-compose.arm.yaml up --detach --remove-orphans || true
else
sudo docker-compose -f ./docker/druid-kafka-setup/docker-compose-tiny.yaml up --detach --remove-orphans || true
$sudo_cmd docker-compose -f ./docker/clickhouse-setup/docker-compose.yaml up --detach --remove-orphans || true
fi
wait_for_containers_start 60
@@ -473,11 +493,9 @@ if [[ $status_code -ne 200 ]]; then
echo "+++++++++++ ERROR ++++++++++++++++++++++"
echo "🔴 The containers didn't seem to start correctly. Please run the following command to check containers that may have errored out:"
echo ""
if [ $setup_type == 'clickhouse' ]; then
echo -e "sudo docker-compose -f ./docker/clickhouse-setup/docker-compose.yaml ps -a"
else
echo -e "sudo docker-compose -f ./docker/druid-kafka-setup/docker-compose-tiny.yaml ps -a"
fi
echo -e "$sudo_cmd docker-compose -f ./docker/clickhouse-setup/docker-compose.yaml ps -a"
echo "Please read our troubleshooting guide https://signoz.io/docs/deployment/docker/#troubleshooting-of-common-issues"
echo "or reach us on SigNoz for support https://signoz.io/slack"
echo "++++++++++++++++++++++++++++++++++++++++"
@@ -495,14 +513,10 @@ else
echo -e "🟢 Your frontend is running on http://localhost:3301"
echo ""
if [ $setup_type == 'clickhouse' ]; then
if is_arm64; then
echo " To bring down SigNoz and clean volumes : sudo docker-compose -f ./docker/clickhouse-setup/docker-compose.arm.yaml down -v"
else
echo " To bring down SigNoz and clean volumes : sudo docker-compose -f ./docker/clickhouse-setup/docker-compose.yaml down -v"
fi
if is_arm64; then
echo " To bring down SigNoz and clean volumes : $sudo_cmd docker-compose -f ./docker/clickhouse-setup/docker-compose.arm.yaml down -v"
else
echo " To bring down SigNoz and clean volumes : sudo docker-compose -f ./docker/druid-kafka-setup/docker-compose-tiny.yaml down -v"
echo " To bring down SigNoz and clean volumes : $sudo_cmd docker-compose -f ./docker/clickhouse-setup/docker-compose.yaml down -v"
fi
echo ""

View File

@@ -1,2 +1,2 @@
node_modules
build
build

View File

@@ -3,16 +3,23 @@ module.exports = {
browser: true,
es2021: true,
node: true,
'jest/globals': true,
},
extends: [
'airbnb',
'airbnb-typescript',
'eslint:recommended',
'plugin:react/recommended',
'plugin:@typescript-eslint/recommended',
'plugin:@typescript-eslint/eslint-recommended',
'plugin:prettier/recommended',
'plugin:sonarjs/recommended',
'plugin:import/errors',
'plugin:import/warnings',
],
parser: '@typescript-eslint/parser',
parserOptions: {
project: './tsconfig.json',
ecmaFeatures: {
jsx: true,
},
@@ -25,10 +32,17 @@ module.exports = {
'simple-import-sort',
'react-hooks',
'prettier',
'jest',
],
settings: {
react: {
version: 'latest',
version: 'detect',
},
'import/resolver': {
node: {
paths: ['src'],
extensions: ['.js', '.jsx', '.ts', '.tsx'],
},
},
},
rules: {
@@ -40,9 +54,13 @@ module.exports = {
],
'react/prop-types': 'off',
'@typescript-eslint/explicit-function-return-type': 'error',
'@typescript-eslint/no-var-requires': 0,
'react/no-array-index-key': 2,
'linebreak-style': ['error', process.platform === 'win32' ? 'windows' : 'unix'],
'@typescript-eslint/no-var-requires': 'error',
'react/no-array-index-key': 'error',
'linebreak-style': [
'error',
process.platform === 'win32' ? 'windows' : 'unix',
],
'@typescript-eslint/default-param-last': 'off',
// simple sort error
'simple-import-sort/imports': 'error',
@@ -50,7 +68,46 @@ module.exports = {
// hooks
'react-hooks/rules-of-hooks': 'error',
'react-hooks/exhaustive-deps': 'warn',
'react-hooks/exhaustive-deps': 'error',
// airbnb
'no-underscore-dangle': 'off',
'no-console': 'off',
'import/prefer-default-export': 'off',
'import/extensions': [
'error',
'ignorePackages',
{
js: 'never',
jsx: 'never',
ts: 'never',
tsx: 'never',
},
],
'import/no-extraneous-dependencies': ['error', { devDependencies: true }],
'jsx-a11y/label-has-associated-control': [
'error',
{
required: {
some: ['nesting', 'id'],
},
},
],
'jsx-a11y/label-has-for': [
'error',
{
required: {
some: ['nesting', 'id'],
},
},
],
// eslint rules need to remove
'no-shadow': 'off',
'@typescript-eslint/no-shadow': 'off',
'global-require': 'off',
'@typescript-eslint/no-var-requires': 'off',
'import/no-cycle': 'off',
'prettier/prettier': [
'error',

4
frontend/.husky/pre-commit Executable file
View File

@@ -0,0 +1,4 @@
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"
cd frontend && yarn lint-staged

View File

@@ -1,5 +1,5 @@
# stage1 as builder
FROM node:12.18.0 as builder
FROM node:12.22.0 as builder
# Add Maintainer Info
LABEL maintainer="signoz"

6
frontend/babel.config.js Normal file
View File

@@ -0,0 +1,6 @@
module.exports = {
presets: [
['@babel/preset-env', { targets: { node: 'current' } }],
'@babel/preset-typescript',
],
};

View File

@@ -0,0 +1,11 @@
const resizeObserverLoopErrRe = /ResizeObserver loop limit exceeded/;
const unCaughtExpection = (): void => {
cy.on('uncaught:exception', (err) => {
// returning false here prevents Cypress from
// failing the test
return !resizeObserverLoopErrRe.test(err.message);
});
};
export default unCaughtExpection;

View File

@@ -0,0 +1,35 @@
{
"items": {
"1644926280000000000": { "timestamp": 1644926280000000000, "value": 787 },
"1644926340000000000": { "timestamp": 1644926340000000000, "value": 2798 },
"1644926400000000000": { "timestamp": 1644926400000000000, "value": 2828 },
"1644926460000000000": { "timestamp": 1644926460000000000, "value": 2926 },
"1644926520000000000": { "timestamp": 1644926520000000000, "value": 2932 },
"1644926580000000000": { "timestamp": 1644926580000000000, "value": 2842 },
"1644926640000000000": { "timestamp": 1644926640000000000, "value": 2966 },
"1644926700000000000": { "timestamp": 1644926700000000000, "value": 2782 },
"1644926760000000000": { "timestamp": 1644926760000000000, "value": 2843 },
"1644926820000000000": { "timestamp": 1644926820000000000, "value": 2864 },
"1644926880000000000": { "timestamp": 1644926880000000000, "value": 2777 },
"1644926940000000000": { "timestamp": 1644926940000000000, "value": 2820 },
"1644927000000000000": { "timestamp": 1644927000000000000, "value": 2579 },
"1644927060000000000": { "timestamp": 1644927060000000000, "value": 2681 },
"1644927120000000000": { "timestamp": 1644927120000000000, "value": 2828 },
"1644927180000000000": { "timestamp": 1644927180000000000, "value": 2975 },
"1644927240000000000": { "timestamp": 1644927240000000000, "value": 2934 },
"1644927300000000000": { "timestamp": 1644927300000000000, "value": 2793 },
"1644927360000000000": { "timestamp": 1644927360000000000, "value": 2913 },
"1644927420000000000": { "timestamp": 1644927420000000000, "value": 2621 },
"1644927480000000000": { "timestamp": 1644927480000000000, "value": 2631 },
"1644927540000000000": { "timestamp": 1644927540000000000, "value": 2924 },
"1644927600000000000": { "timestamp": 1644927600000000000, "value": 2576 },
"1644927660000000000": { "timestamp": 1644927660000000000, "value": 2878 },
"1644927720000000000": { "timestamp": 1644927720000000000, "value": 2737 },
"1644927780000000000": { "timestamp": 1644927780000000000, "value": 2621 },
"1644927840000000000": { "timestamp": 1644927840000000000, "value": 2823 },
"1644927900000000000": { "timestamp": 1644927900000000000, "value": 3081 },
"1644927960000000000": { "timestamp": 1644927960000000000, "value": 2883 },
"1644928020000000000": { "timestamp": 1644928020000000000, "value": 2823 },
"1644928080000000000": { "timestamp": 1644928080000000000, "value": 455 }
}
}

View File

@@ -0,0 +1,19 @@
{
"serviceName": {
"customer": 1642,
"driver": 1642,
"frontend": 39408,
"mysql": 1642,
"redis": 22167,
"route": 16420
},
"status": { "error": 4105, "ok": 78816 },
"duration": { "maxDuration": 1253979000, "minDuration": 415000 },
"operation": {},
"httpCode": {},
"httpUrl": {},
"httpMethod": {},
"httpRoute": {},
"httpHost": {},
"component": {}
}

View File

@@ -0,0 +1,105 @@
{
"spans": [
{
"timestamp": "2022-02-15T12:16:09.542074Z",
"spanID": "303b39065c6f5df5",
"traceID": "00000000000000007fc49fab3cb75958",
"serviceName": "customer",
"operation": "HTTP GET /customer",
"durationNano": 313418000,
"httpCode": "200",
"httpMethod": "GET"
},
{
"timestamp": "2022-02-15T12:16:08.84038Z",
"spanID": "557e8303bc802992",
"traceID": "000000000000000079310bd1d435a92b",
"serviceName": "customer",
"operation": "HTTP GET /customer",
"durationNano": 318203000,
"httpCode": "200",
"httpMethod": "GET"
},
{
"timestamp": "2022-02-15T12:16:08.867689Z",
"spanID": "347113dd916dd20e",
"traceID": "00000000000000004c22c0409cee0f66",
"serviceName": "customer",
"operation": "HTTP GET /customer",
"durationNano": 512810000,
"httpCode": "200",
"httpMethod": "GET"
},
{
"timestamp": "2022-02-15T12:16:07.060882Z",
"spanID": "0a8d07f72aa1339b",
"traceID": "0000000000000000488e11a35959de96",
"serviceName": "customer",
"operation": "HTTP GET /customer",
"durationNano": 588705000,
"httpCode": "200",
"httpMethod": "GET"
},
{
"timestamp": "2022-02-15T12:16:07.134107Z",
"spanID": "0acd4ec344675998",
"traceID": "00000000000000000292efc7945d9bfa",
"serviceName": "customer",
"operation": "HTTP GET /customer",
"durationNano": 801632000,
"httpCode": "200",
"httpMethod": "GET"
},
{
"timestamp": "2022-02-15T12:16:06.474095Z",
"spanID": "3ae72e433301822a",
"traceID": "00000000000000001ac3004ff1b7eefe",
"serviceName": "customer",
"operation": "HTTP GET /customer",
"durationNano": 306650000,
"httpCode": "200",
"httpMethod": "GET"
},
{
"timestamp": "2022-02-15T12:16:06.996246Z",
"spanID": "1d765427af673039",
"traceID": "00000000000000002e78f59fabbcdecf",
"serviceName": "customer",
"operation": "HTTP GET /customer",
"durationNano": 311469000,
"httpCode": "200",
"httpMethod": "GET"
},
{
"timestamp": "2022-02-15T12:16:05.324296Z",
"spanID": "0987c90d83298a1d",
"traceID": "0000000000000000077bcb960609a350",
"serviceName": "customer",
"operation": "HTTP GET /customer",
"durationNano": 290680000,
"httpCode": "200",
"httpMethod": "GET"
},
{
"timestamp": "2022-02-15T12:16:02.458221Z",
"spanID": "5b0d0d403dd9acf4",
"traceID": "00000000000000007ae5b0aa69242556",
"serviceName": "customer",
"operation": "HTTP GET /customer",
"durationNano": 262763000,
"httpCode": "200",
"httpMethod": "GET"
},
{
"timestamp": "2022-02-15T12:16:00.584939Z",
"spanID": "3beafb277a76b9b4",
"traceID": "00000000000000000ab44953c2fd949e",
"serviceName": "customer",
"operation": "HTTP GET /customer",
"durationNano": 302851000,
"httpCode": "200",
"httpMethod": "GET"
}
],
"totalSpans": 82921
}

View File

@@ -4,6 +4,8 @@ import ROUTES from 'constants/routes';
import defaultRules from '../../fixtures/defaultRules.json';
const defaultRuleRoutes = `**/rules/**`;
describe('Alerts', () => {
beforeEach(() => {
window.localStorage.setItem('isLoggedIn', 'yes');
@@ -21,7 +23,7 @@ describe('Alerts', () => {
it('Edit Rules Page Failure', async () => {
cy
.intercept('**/rules/**', {
.intercept(defaultRuleRoutes, {
statusCode: 500,
})
.as('Get Rules Error');
@@ -49,7 +51,7 @@ describe('Alerts', () => {
const text = 'this is the sample value';
cy
.intercept('**/rules/**', {
.intercept(defaultRuleRoutes, {
statusCode: 200,
body: {
data: {
@@ -103,7 +105,7 @@ describe('Alerts', () => {
it('Rules are Deleted', async () => {
cy
.intercept('**/rules/**', {
.intercept(defaultRuleRoutes, {
body: {
data: 'Deleted',
message: 'Success',

View File

@@ -0,0 +1,160 @@
/* eslint-disable sonarjs/no-duplicate-string */
import ROUTES from 'constants/routes';
import { AppState } from 'store/reducers';
import { TraceFilterEnum } from 'types/reducer/trace';
import GraphInitialResponse from '../../fixtures/trace/initialAggregates.json';
import FilterInitialResponse from '../../fixtures/trace/initialSpanFilter.json';
import TableInitialResponse from '../../fixtures/trace/initialSpans.json';
const allFilters = '@Filters.all';
const allGraphs = '@Graph.all';
const allTable = '@Table.all';
describe('Trace', () => {
beforeEach(() => {
window.localStorage.setItem('isLoggedIn', 'yes');
cy
.intercept('POST', '**/aggregates', {
fixture: 'trace/initialAggregates',
})
.as('Graph');
cy
.intercept('POST', '**/getFilteredSpans', {
fixture: 'trace/initialSpans',
})
.as('Table');
cy
.intercept('POST', '**/api/v1/getSpanFilters', {
fixture: 'trace/initialSpanFilter',
})
.as('Filters');
cy.visit(Cypress.env('baseUrl') + `${ROUTES.TRACE}`);
});
it('First Initial Load should go with 3 AJAX request', () => {
cy.wait(['@Filters', '@Graph', '@Table']).then((e) => {
const [filter, graph, table] = e;
const { body: filterBody } = filter.request;
const { body: graphBody } = graph.request;
const { body: tableBody } = table.request;
expect(filterBody.exclude.length).to.equal(0);
expect(filterBody.getFilters.length).to.equal(3);
filterBody.getFilters.forEach((filter: TraceFilterEnum) => {
expect(filter).to.be.oneOf(['duration', 'status', 'serviceName']);
});
expect(graphBody.function).to.be.equal('count');
expect(graphBody.exclude.length).to.be.equal(0);
expect(typeof graphBody.exclude).to.be.equal('object');
expect(tableBody.tags.length).to.be.equal(0);
expect(typeof tableBody.tags).equal('object');
expect(tableBody.exclude.length).equals(0);
});
});
it('Render Time Request Response In All 3 Request', () => {
cy.wait(['@Filters', '@Graph', '@Table']).then((e) => {
const [filter, graph, table] = e;
expect(filter.response?.body).to.be.not.undefined;
expect(filter.response?.body).to.be.not.NaN;
expect(JSON.stringify(filter.response?.body)).to.be.equals(
JSON.stringify(FilterInitialResponse),
);
expect(JSON.stringify(graph.response?.body)).to.be.equals(
JSON.stringify(GraphInitialResponse),
);
expect(JSON.stringify(table.response?.body)).to.be.equals(
JSON.stringify(TableInitialResponse),
);
});
cy.get(allFilters).should('have.length', 1);
cy.get(allGraphs).should('have.length', 1);
cy.get(allTable).should('have.length', 1);
});
it('Clear All', () => {
cy.wait(['@Filters', '@Graph', '@Table']);
expect(cy.findAllByText('Clear All')).not.to.be.undefined;
cy
.window()
.its('store')
.invoke('getState')
.then((e: AppState) => {
const { traces } = e;
expect(traces.isFilterExclude.get('status')).to.be.undefined;
expect(traces.selectedFilter.size).to.be.equals(0);
});
cy.findAllByText('Clear All').then((e) => {
const [firstStatusClear] = e;
firstStatusClear.click();
cy.wait(['@Filters', '@Graph', '@Table']);
// insuring the api get call
cy.get(allFilters).should('have.length', 2);
cy.get(allGraphs).should('have.length', 2);
cy.get(allTable).should('have.length', 2);
cy
.window()
.its('store')
.invoke('getState')
.then((e: AppState) => {
const { traces } = e;
expect(traces.isFilterExclude.get('status')).to.be.equals(false);
expect(traces.userSelectedFilter.get('status')).to.be.undefined;
expect(traces.selectedFilter.size).to.be.equals(0);
});
});
});
it('Un Selecting one option from status', () => {
cy.wait(['@Filters', '@Graph', '@Table']);
cy.get('input[type="checkbox"]').then((e) => {
const [errorCheckbox] = e;
errorCheckbox.click();
cy.wait(['@Filters', '@Graph', '@Table']).then((e) => {
const [filter, graph, table] = e;
const filterBody = filter.request.body;
const graphBody = graph.request.body;
const tableBody = table.request.body;
expect(filterBody.exclude).not.to.be.undefined;
expect(filterBody.exclude.length).not.to.be.equal(0);
expect(filterBody.exclude[0] === 'status').to.be.true;
expect(graphBody.exclude).not.to.be.undefined;
expect(graphBody.exclude.length).not.to.be.equal(0);
expect(graphBody.exclude[0] === 'status').to.be.true;
expect(tableBody.exclude).not.to.be.undefined;
expect(tableBody.exclude.length).not.to.be.equal(0);
expect(tableBody.exclude[0] === 'status').to.be.true;
});
cy.get(allFilters).should('have.length', 2);
cy.get(allGraphs).should('have.length', 2);
cy.get(allTable).should('have.length', 2);
});
});
});

View File

@@ -9,12 +9,19 @@ const config: Config.InitialOptions = {
moduleNameMapper: {
'\\.(css|less)$': '<rootDir>/__mocks__/cssMock.ts',
},
notify: true,
notifyMode: 'always',
testMatch: ['<rootDir>/src/**/?(*.)(test).(ts|js)?(x)'],
transform: {
'\\.(js|jsx|ts|tsx)?$': 'babel-jest',
globals: {
extensionsToTreatAsEsm: ['.ts'],
'ts-jest': {
useESM: true,
},
},
testMatch: ['<rootDir>/src/**/?(*.)(test).(ts|js)?(x)'],
preset: 'ts-jest/presets/js-with-ts-esm',
transform: {
'^.+\\.(ts|tsx)?$': 'ts-jest',
'^.+\\.(js|jsx)$': 'babel-jest',
},
transformIgnorePatterns: ['node_modules/(?!(lodash-es)/)'],
setupFilesAfterEnv: ['<rootDir>jest.setup.ts'],
testPathIgnorePatterns: ['/node_modules/', '/public/'],
moduleDirectories: ['node_modules', 'src'],

View File

@@ -7,14 +7,15 @@
"dev": "cross-env NODE_ENV=development webpack serve --progress",
"build": "webpack --config=webpack.config.prod.js --progress",
"prettify": "prettier --write .",
"lint": "eslint . --debug",
"lint:fix": "eslint . --fix --debug",
"lint": "eslint ./src",
"lint:fix": "eslint ./src --fix",
"cypress:open": "cypress open",
"cypress:run": "cypress run",
"jest": "jest",
"jest:coverage": "jest --coverage",
"jest:watch": "jest --watch",
"bundle:size": "bundlesize"
"postinstall": "yarn husky:configure",
"husky:configure": "cd .. && husky install frontend/.husky"
},
"engines": {
"node": ">=12.13.0"
@@ -22,11 +23,15 @@
"author": "",
"license": "ISC",
"dependencies": {
"@ant-design/colors": "^6.0.0",
"@ant-design/icons": "^4.6.2",
"@grafana/data": "^8.4.3",
"@monaco-editor/react": "^4.3.1",
"@testing-library/jest-dom": "^5.11.4",
"@testing-library/react": "^11.1.0",
"@testing-library/user-event": "^12.1.10",
"antd": "^4.16.13",
"@welldone-software/why-did-you-render": "^6.2.1",
"antd": "4.19.2",
"axios": "^0.21.0",
"babel-eslint": "^10.1.0",
"babel-jest": "^26.6.0",
@@ -36,9 +41,11 @@
"babel-preset-react-app": "^10.0.0",
"chart.js": "^3.4.0",
"chartjs-adapter-date-fns": "^2.0.0",
"color": "^4.2.1",
"cross-env": "^7.0.3",
"css-loader": "4.3.0",
"css-minimizer-webpack-plugin": "^3.2.0",
"cypress": "^8.3.0",
"d3": "^6.2.0",
"d3-flame-graph": "^3.1.1",
"d3-tip": "^0.9.1",
@@ -47,21 +54,28 @@
"file-loader": "6.1.1",
"history": "4.10.1",
"html-webpack-plugin": "5.1.0",
"jest": "26.6.0",
"i18next": "^21.6.12",
"i18next-browser-languagedetector": "^6.1.3",
"i18next-http-backend": "^1.3.2",
"jest": "^27.5.1",
"less": "^4.1.2",
"less-loader": "^10.2.0",
"lodash-es": "^4.17.21",
"mini-css-extract-plugin": "2.4.5",
"monaco-editor": "^0.30.0",
"react": "17.0.0",
"react-dom": "17.0.0",
"react-force-graph": "^1.41.0",
"react-graph-vis": "^1.0.5",
"react-grid-layout": "^1.2.5",
"react-i18next": "^11.16.1",
"react-query": "^3.34.19",
"react-redux": "^7.2.2",
"react-router-dom": "^5.2.0",
"react-use": "^17.3.2",
"react-vis": "^1.11.7",
"redux": "^4.0.5",
"redux-thunk": "^2.3.0",
"stream": "^0.0.2",
"style-loader": "1.3.0",
"styled-components": "^5.2.1",
"terser-webpack-plugin": "^5.2.5",
@@ -92,13 +106,17 @@
"@babel/preset-env": "^7.12.17",
"@babel/preset-react": "^7.12.13",
"@babel/preset-typescript": "^7.12.17",
"@jest/globals": "^27.5.1",
"@testing-library/cypress": "^8.0.0",
"@testing-library/react-hooks": "^7.0.2",
"@types/color": "^3.0.3",
"@types/compression-webpack-plugin": "^9.0.0",
"@types/copy-webpack-plugin": "^8.0.1",
"@types/d3": "^6.2.0",
"@types/d3-tip": "^3.5.5",
"@types/jest": "^26.0.15",
"@types/lodash-es": "^4.17.4",
"@types/mini-css-extract-plugin": "^2.5.1",
"@types/node": "^16.10.3",
"@types/react": "^17.0.0",
"@types/react-dom": "^16.9.9",
@@ -113,32 +131,41 @@
"@types/webpack-dev-server": "^4.3.0",
"@typescript-eslint/eslint-plugin": "^4.28.2",
"@typescript-eslint/parser": "^4.28.2",
"@welldone-software/why-did-you-render": "^6.2.1",
"autoprefixer": "^9.0.0",
"babel-plugin-styled-components": "^1.12.0",
"bundlesize": "^0.18.1",
"compression-webpack-plugin": "^9.0.0",
"copy-webpack-plugin": "^8.1.0",
"critters-webpack-plugin": "^3.0.1",
"cypress": "^8.3.0",
"eslint": "^7.30.0",
"eslint-config-airbnb": "^19.0.4",
"eslint-config-airbnb-typescript": "^16.1.4",
"eslint-config-prettier": "^8.3.0",
"eslint-config-standard": "^16.0.3",
"eslint-plugin-import": "^2.23.4",
"eslint-plugin-import": "^2.25.4",
"eslint-plugin-jest": "^26.1.2",
"eslint-plugin-jsx-a11y": "^6.5.1",
"eslint-plugin-node": "^11.1.0",
"eslint-plugin-prettier": "^4.0.0",
"eslint-plugin-promise": "^5.1.0",
"eslint-plugin-react": "^7.24.0",
"eslint-plugin-react-hooks": "^4.3.0",
"eslint-plugin-simple-import-sort": "^7.0.0",
"husky": "4.3.8",
"eslint-plugin-sonarjs": "^0.12.0",
"husky": "^7.0.4",
"less-plugin-npm-import": "^2.1.0",
"lint-staged": "10.5.3",
"lodash-es": "^4.17.21",
"lint-staged": "^12.3.7",
"portfinder-sync": "^0.0.2",
"prettier": "2.2.1",
"react-hot-loader": "^4.13.0",
"ts-jest": "^27.1.4",
"ts-node": "^10.2.1",
"typescript-plugin-css-modules": "^3.4.0",
"webpack-bundle-analyzer": "^4.5.0",
"webpack-cli": "^4.5.0"
},
"lint-staged": {
"*.(js|jsx|ts|tsx)": [
"eslint --fix"
]
}
}

View File

@@ -0,0 +1,27 @@
{
"monitor_signup": "Monitor your applications. Find what is causing issues.",
"version": "Version",
"latest_version": "Latest version",
"current_version": "Current version",
"release_notes": "Release Notes",
"read_how_to_upgrade": "Read instructions on how to upgrade",
"latest_version_signoz": "You are running the latest version of SigNoz.",
"stale_version": "You are on an older version and may be loosing on the latest features we have shipped. We recommend to upgrade to the latest version",
"oops_something_went_wrong_version": "Oops.. facing issues with fetching updated version information",
"n_a": "N/A",
"routes": {
"general": "General",
"alert_channels": "Alert Channels"
},
"settings": {
"total_retention_period": "Total Retention Period",
"move_to_s3": "Move to S3\n(should be lower than total retention period)",
"retention_success_message": "Congrats. The retention periods for {{name}} has been updated successfully.",
"retention_error_message": "There was an issue in changing the retention period for {{name}}. Please try again or reach out to support@signoz.io",
"retention_failed_message": "There was an issue in changing the retention period. Please try again or reach out to support@signoz.io",
"retention_comparison_error": "Total retention period for {{name}} cant be lower or equal to the period after which data is moved to s3.",
"retention_null_value_error": "Retention Period for {{name}} is not set yet. Please set by choosing below",
"retention_confirmation": "Are you sure you want to change the retention period?",
"retention_confirmation_description": "This will change the amount of storage needed for saving metrics & traces."
}
}

View File

@@ -11,8 +11,7 @@ import AppReducer from 'types/reducer/app';
import routes from './routes';
const App = (): JSX.Element => {
function App(): JSX.Element {
const { isLoggedIn } = useSelector<AppState, AppReducer>((state) => state.app);
return (
@@ -20,8 +19,8 @@ const App = (): JSX.Element => {
<AppLayout>
<Suspense fallback={<Spinner size="large" tip="Loading..." />}>
<Switch>
{routes.map(({ path, component, exact }, index) => (
<Route key={index} exact={exact} path={path} component={component} />
{routes.map(({ path, component, exact }) => (
<Route key={`${path}`} exact={exact} path={path} component={component} />
))}
<Route
path="/"
@@ -40,7 +39,6 @@ const App = (): JSX.Element => {
</AppLayout>
</Router>
);
};
}
export default App;

View File

@@ -18,15 +18,12 @@ export const ServiceMapPage = Loadable(
),
);
export const TraceDetailPages = Loadable(
() => import(/* webpackChunkName: "TraceDetailPage" */ 'pages/Trace'),
export const TraceFilter = Loadable(
() => import(/* webpackChunkName: "Trace Filter Page" */ 'pages/Trace'),
);
export const TraceGraphPage = Loadable(
() =>
import(
/* webpackChunkName: "TraceGraphPage" */ 'modules/Traces/TraceGraphDef'
),
export const TraceDetail = Loadable(
() => import(/* webpackChunkName: "TraceDetail Page" */ 'pages/TraceDetail'),
);
export const UsageExplorerPage = Loadable(
@@ -88,3 +85,7 @@ export const EditAlertChannelsAlerts = Loadable(
export const AllAlertChannels = Loadable(
() => import(/* webpackChunkName: "All Channels" */ 'pages/AllAlertChannels'),
);
export const StatusPage = Loadable(
() => import(/* webpackChunkName: "All Status" */ 'pages/Status'),
);

View File

@@ -17,8 +17,9 @@ import {
ServicesTablePage,
SettingsPage,
SignupPage,
TraceDetailPages,
TraceGraphPage,
StatusPage,
TraceDetail,
TraceFilter,
UsageExplorerPage,
} from './pageComponents';
@@ -44,9 +45,9 @@ const routes: AppRoutes[] = [
exact: true,
},
{
path: ROUTES.TRACE_GRAPH,
path: ROUTES.TRACE_DETAIL,
exact: true,
component: TraceGraphPage,
component: TraceDetail,
},
{
path: ROUTES.SETTINGS,
@@ -96,7 +97,7 @@ const routes: AppRoutes[] = [
{
path: ROUTES.TRACE,
exact: true,
component: TraceDetailPages,
component: TraceFilter,
},
{
path: ROUTES.CHANNELS_NEW,
@@ -113,6 +114,11 @@ const routes: AppRoutes[] = [
exact: true,
component: AllAlertChannels,
},
{
path: ROUTES.VERSION,
exact: true,
component: StatusPage,
},
];
interface AppRoutes {

View File

@@ -0,0 +1,26 @@
import i18n from 'i18next';
import LanguageDetector from 'i18next-browser-languagedetector';
import Backend from 'i18next-http-backend';
import { initReactI18next } from 'react-i18next';
i18n
// load translation using http -> see /public/locales
.use(Backend)
// detect user language
.use(LanguageDetector)
// pass the i18n instance to react-i18next.
.use(initReactI18next)
// init i18next
.init({
debug: true,
fallbackLng: 'en',
interpolation: {
escapeValue: false, // not needed for react as it escapes by default
},
react: {
useSuspense: false,
},
});
export default i18n;

View File

@@ -2,14 +2,15 @@ import { AxiosError } from 'axios';
import { ErrorResponse } from 'types/api';
import { ErrorStatusCode } from 'types/common';
export const ErrorResponseHandler = (error: AxiosError): ErrorResponse => {
if (error.response) {
export function ErrorResponseHandler(error: AxiosError): ErrorResponse {
const { response, request } = error;
if (response) {
// client received an error response (5xx, 4xx)
// making the error status code as standard Error Status Code
const statusCode = error.response.status as ErrorStatusCode;
const statusCode = response.status as ErrorStatusCode;
if (statusCode >= 400 && statusCode < 500) {
const { data } = error.response;
const { data } = response;
if (statusCode === 404) {
return {
@@ -35,7 +36,7 @@ export const ErrorResponseHandler = (error: AxiosError): ErrorResponse => {
message: null,
};
}
if (error.request) {
if (request) {
// client never received a response, or request never left
console.error('client never received a response, or request never left');
@@ -51,7 +52,7 @@ export const ErrorResponseHandler = (error: AxiosError): ErrorResponse => {
return {
statusCode: 500,
payload: null,
error: error.toString(),
error: String(error),
message: null,
};
};
}

View File

@@ -1,9 +1,9 @@
import { AxiosAlertManagerInstance } from 'api';
import { ErrorResponseHandler } from 'api/ErrorResponseHandler';
import { AxiosError } from 'axios';
import convertObjectIntoParams from 'lib/query/convertObjectIntoParams';
import { ErrorResponse, SuccessResponse } from 'types/api';
import { PayloadProps, Props } from 'types/api/alerts/getGroups';
import convertObjectIntoParams from 'lib/query/convertObjectIntoParams';
const getGroups = async (
props: Props,

View File

@@ -0,0 +1,29 @@
import { AxiosAlertManagerInstance } from 'api';
import { ErrorResponseHandler } from 'api/ErrorResponseHandler';
import { AxiosError } from 'axios';
import convertObjectIntoParams from 'lib/query/convertObjectIntoParams';
import { ErrorResponse, SuccessResponse } from 'types/api';
import { PayloadProps, Props } from 'types/api/alerts/getTriggered';
const getTriggered = async (
props: Props,
): Promise<SuccessResponse<PayloadProps> | ErrorResponse> => {
try {
const queryParams = convertObjectIntoParams(props);
const response = await AxiosAlertManagerInstance.get(
`/alerts?${queryParams}`,
);
return {
statusCode: 200,
error: null,
message: response.data.status,
payload: response.data,
};
} catch (error) {
return ErrorResponseHandler(error as AxiosError);
}
};
export default getTriggered;

View File

@@ -1,7 +1,6 @@
const get = (key: string): string | null => {
try {
const value = localStorage.getItem(key);
return value;
return localStorage.getItem(key);
} catch (e) {
return '';
}

View File

@@ -0,0 +1,51 @@
import axios from 'api';
import { ErrorResponseHandler } from 'api/ErrorResponseHandler';
import { AxiosError } from 'axios';
import { ErrorResponse, SuccessResponse } from 'types/api';
import { PayloadProps, Props } from 'types/api/channels/createWebhook';
const create = async (
props: Props,
): Promise<SuccessResponse<PayloadProps> | ErrorResponse> => {
try {
let httpConfig = {};
if (props.username !== '' && props.password !== '') {
httpConfig = {
basic_auth: {
username: props.username,
password: props.password,
},
};
} else if (props.username === '' && props.password !== '') {
httpConfig = {
authorization: {
type: 'bearer',
credentials: props.password,
},
};
}
const response = await axios.post('/channels', {
name: props.name,
webhook_configs: [
{
send_resolved: true,
url: props.api_url,
http_config: httpConfig,
},
],
});
return {
statusCode: 200,
error: null,
message: 'Success',
payload: response.data.data,
};
} catch (error) {
return ErrorResponseHandler(error as AxiosError);
}
};
export default create;

View File

@@ -0,0 +1,50 @@
import axios from 'api';
import { ErrorResponseHandler } from 'api/ErrorResponseHandler';
import { AxiosError } from 'axios';
import { ErrorResponse, SuccessResponse } from 'types/api';
import { PayloadProps, Props } from 'types/api/channels/editWebhook';
const editWebhook = async (
props: Props,
): Promise<SuccessResponse<PayloadProps> | ErrorResponse> => {
try {
let httpConfig = {};
if (props.username !== '' && props.password !== '') {
httpConfig = {
basic_auth: {
username: props.username,
password: props.password,
},
};
} else if (props.username === '' && props.password !== '') {
httpConfig = {
authorization: {
type: 'bearer',
credentials: props.password,
},
};
}
const response = await axios.put(`/channels/${props.id}`, {
name: props.name,
webhook_configs: [
{
send_resolved: true,
url: props.api_url,
http_config: httpConfig,
},
],
});
return {
statusCode: 200,
error: null,
message: 'Success',
payload: response.data.data,
};
} catch (error) {
return ErrorResponseHandler(error as AxiosError);
}
};
export default editWebhook;

View File

@@ -0,0 +1,24 @@
import axios from 'api';
import { ErrorResponseHandler } from 'api/ErrorResponseHandler';
import { AxiosError } from 'axios';
import { ErrorResponse, SuccessResponse } from 'types/api';
import { PayloadProps } from 'types/api/disks/getDisks';
const getDisks = async (): Promise<
SuccessResponse<PayloadProps> | ErrorResponse
> => {
try {
const response = await axios.get(`/disks`);
return {
statusCode: 200,
error: null,
message: 'Success',
payload: response.data,
};
} catch (error) {
return ErrorResponseHandler(error as AxiosError);
}
};
export default getDisks;

View File

@@ -9,7 +9,11 @@ const setRetention = async (
): Promise<SuccessResponse<PayloadProps> | ErrorResponse> => {
try {
const response = await axios.post<PayloadProps>(
`/settings/ttl?duration=${props.duration}&type=${props.type}`,
`/settings/ttl?duration=${props.totalDuration}&type=${props.type}${
props.coldStorage
? `&coldStorage=${props.coldStorage};toColdDuration=${props.toColdDuration}`
: ''
}`,
);
return {

View File

@@ -1,9 +1,9 @@
import axios from 'api';
import { ErrorResponseHandler } from 'api/ErrorResponseHandler';
import { AxiosError } from 'axios';
import omitBy from 'lodash-es/omitBy';
import { ErrorResponse, SuccessResponse } from 'types/api';
import { PayloadProps, Props } from 'types/api/trace/getFilters';
import omitBy from 'lodash-es/omitBy';
const getFilters = async (
props: Props,
@@ -29,9 +29,9 @@ const getFilters = async (
end: props.end,
getFilters: props.getFilters,
...nonDuration,
maxDuration: String((duration['duration'] || [])[0] || ''),
minDuration: String((duration['duration'] || [])[1] || ''),
exclude: exclude,
maxDuration: String((duration.duration || [])[0] || ''),
minDuration: String((duration.duration || [])[1] || ''),
exclude,
});
return {

View File

@@ -39,8 +39,8 @@ const getSpans = async (
step: props.step,
tags: updatedSelectedTags,
...nonDuration,
maxDuration: String((duration['duration'] || [])[0] || ''),
minDuration: String((duration['duration'] || [])[1] || ''),
maxDuration: String((duration.duration || [])[0] || ''),
minDuration: String((duration.duration || [])[1] || ''),
exclude,
},
);

View File

@@ -15,6 +15,7 @@ const getSpanAggregate = async (
end: String(props.end),
limit: props.limit,
offset: props.offset,
order: props.order,
};
const exclude: TraceFilterEnum[] = [];
@@ -41,8 +42,8 @@ const getSpanAggregate = async (
...preProps,
tags: updatedSelectedTags,
...nonDuration,
maxDuration: String((duration['duration'] || [])[0] || ''),
minDuration: String((duration['duration'] || [])[1] || ''),
maxDuration: String((duration.duration || [])[0] || ''),
minDuration: String((duration.duration || [])[1] || ''),
exclude,
});

View File

@@ -20,8 +20,8 @@ const getTagFilters = async (
start: String(props.start),
end: String(props.end),
...nonDuration,
maxDuration: String((duration['duration'] || [])[0] || ''),
minDuration: String((duration['duration'] || [])[1] || ''),
maxDuration: String((duration.duration || [])[0] || ''),
minDuration: String((duration.duration || [])[1] || ''),
});
return {

View File

@@ -0,0 +1,28 @@
import axios from 'api';
import { ErrorResponseHandler } from 'api/ErrorResponseHandler';
import { AxiosError } from 'axios';
import { ErrorResponse, SuccessResponse } from 'types/api';
import { PayloadProps, Props } from 'types/api/trace/getTagValue';
const getTagValue = async (
props: Props,
): Promise<SuccessResponse<PayloadProps> | ErrorResponse> => {
try {
const response = await axios.post<PayloadProps>(`/getTagValues`, {
start: props.start.toString(),
end: props.end.toString(),
tagKey: props.tagKey,
});
return {
statusCode: 200,
error: null,
message: 'Success',
payload: response.data,
};
} catch (error) {
return ErrorResponseHandler(error as AxiosError);
}
};
export default getTagValue;

View File

@@ -0,0 +1,27 @@
import axios from 'api';
import { ErrorResponseHandler } from 'api/ErrorResponseHandler';
import { AxiosError } from 'axios';
import { ErrorResponse, SuccessResponse } from 'types/api';
import { PayloadProps, Props } from 'types/api/trace/getTraceItem';
const getTraceItem = async (
props: Props,
): Promise<SuccessResponse<PayloadProps> | ErrorResponse> => {
try {
const response = await axios.request<PayloadProps>({
url: `/traces/${props.id}`,
method: 'get',
});
return {
statusCode: 200,
error: null,
message: 'Success',
payload: response.data,
};
} catch (error) {
return ErrorResponseHandler(error as AxiosError);
}
};
export default getTraceItem;

View File

@@ -0,0 +1,25 @@
import { ErrorResponseHandler } from 'api/ErrorResponseHandler';
import axios, { AxiosError } from 'axios';
import { ErrorResponse, SuccessResponse } from 'types/api';
import { PayloadProps } from 'types/api/user/getLatestVersion';
const getLatestVersion = async (): Promise<
SuccessResponse<PayloadProps> | ErrorResponse
> => {
try {
const response = await axios.get(
`https://api.github.com/repos/signoz/signoz/releases/latest`,
);
return {
statusCode: 200,
error: null,
message: response.data.status,
payload: response.data,
};
} catch (error) {
return ErrorResponseHandler(error as AxiosError);
}
};
export default getLatestVersion;

View File

@@ -1,7 +1,7 @@
import React from 'react';
const TimeSeries = (props: TimeSeriesProps): JSX.Element => (
<React.Fragment>
function TimeSeries(): JSX.Element {
return (
<svg
width="81"
height="46"
@@ -31,12 +31,7 @@ const TimeSeries = (props: TimeSeriesProps): JSX.Element => (
/>
</defs>
</svg>
</React.Fragment>
);
export interface TimeSeriesProps{
fillColor: React.CSSProperties['color'];
);
}
export default TimeSeries;

View File

@@ -1,8 +1,9 @@
import React from 'react';
const Value = (props: ValueProps): JSX.Element => {
return(
<React.Fragment>
function Value(props: ValueProps): JSX.Element {
const { fillColor } = props;
return (
<svg
width="78"
height="32"
@@ -12,13 +13,13 @@ const Value = (props: ValueProps): JSX.Element => {
>
<path
d="M15.0215 17.875C14.2285 18.8184 13.2783 19.5771 12.1709 20.1514C11.0771 20.7256 9.87402 21.0127 8.56152 21.0127C6.83887 21.0127 5.33496 20.5889 4.0498 19.7412C2.77832 18.8936 1.79395 17.7041 1.09668 16.1729C0.399414 14.6279 0.0507812 12.9258 0.0507812 11.0664C0.0507812 9.07031 0.426758 7.27246 1.17871 5.67285C1.94434 4.07324 3.02441 2.84961 4.41895 2.00195C5.81348 1.1543 7.44043 0.730469 9.2998 0.730469C12.2529 0.730469 14.5771 1.83789 16.2725 4.05273C17.9814 6.25391 18.8359 9.26172 18.8359 13.0762V14.1836C18.8359 19.9941 17.6875 24.2393 15.3906 26.9189C13.0938 29.585 9.62793 30.9521 4.99316 31.0205H4.25488V27.8213H5.05469C8.18555 27.7666 10.5918 26.9531 12.2734 25.3809C13.9551 23.7949 14.8711 21.293 15.0215 17.875ZM9.17676 17.875C10.4482 17.875 11.6172 17.4854 12.6836 16.7061C13.7637 15.9268 14.5498 14.9629 15.042 13.8145V12.2969C15.042 9.80859 14.502 7.78516 13.4219 6.22656C12.3418 4.66797 10.9746 3.88867 9.32031 3.88867C7.65234 3.88867 6.3125 4.53125 5.30078 5.81641C4.28906 7.08789 3.7832 8.76953 3.7832 10.8613C3.7832 12.8984 4.26855 14.5801 5.23926 15.9062C6.22363 17.2188 7.53613 17.875 9.17676 17.875ZM24.5371 29.0107C24.5371 28.3545 24.7285 27.8076 25.1113 27.3701C25.5078 26.9326 26.0957 26.7139 26.875 26.7139C27.6543 26.7139 28.2422 26.9326 28.6387 27.3701C29.0488 27.8076 29.2539 28.3545 29.2539 29.0107C29.2539 29.6396 29.0488 30.166 28.6387 30.5898C28.2422 31.0137 27.6543 31.2256 26.875 31.2256C26.0957 31.2256 25.5078 31.0137 25.1113 30.5898C24.7285 30.166 24.5371 29.6396 24.5371 29.0107ZM51.1562 20.9717H55.2988V24.0684H51.1562V31H47.3418V24.0684H33.7451V21.833L47.1162 1.14062H51.1562V20.9717ZM38.0518 20.9717H47.3418V6.3291L46.8906 7.14941L38.0518 20.9717ZM73.6123 1.12012V4.33984H72.915C69.9619 4.39453 67.6104 5.26953 65.8604 6.96484C64.1104 8.66016 63.0986 11.0459 62.8252 14.1221C64.3975 12.3174 66.5439 11.415 69.2646 11.415C71.8623 11.415 73.9336 12.3311 75.4785 14.1631C77.0371 15.9951 77.8164 18.3604 77.8164 21.2588C77.8164 24.335 76.9756 26.7959 75.2939 28.6416C73.626 30.4873 71.3838 31.4102 68.5674 31.4102C65.71 31.4102 63.3926 30.3164 61.6152 28.1289C59.8379 25.9277 58.9492 23.0977 58.9492 19.6387V18.1826C58.9492 12.6865 60.1182 8.48926 62.4561 5.59082C64.8076 2.67871 68.3008 1.18848 72.9355 1.12012H73.6123ZM68.6289 14.5732C67.3301 14.5732 66.1338 14.9629 65.04 15.7422C63.9463 16.5215 63.1875 17.499 62.7637 18.6748V20.0693C62.7637 22.5303 63.3174 24.5127 64.4248 26.0166C65.5322 27.5205 66.9131 28.2725 68.5674 28.2725C70.2764 28.2725 71.6162 27.6436 72.5869 26.3857C73.5713 25.1279 74.0635 23.4805 74.0635 21.4434C74.0635 19.3926 73.5645 17.7383 72.5664 16.4805C71.582 15.209 70.2695 14.5732 68.6289 14.5732Z"
fill={props.fillColor}
fill={fillColor}
/>
</svg>
</React.Fragment>
)};
);
}
interface ValueProps{
interface ValueProps {
fillColor: React.CSSProperties['color'];
}

View File

@@ -1,6 +1,6 @@
import React from 'react';
const NotFound = (): JSX.Element => {
function NotFound(): JSX.Element {
return (
<svg
width="360"
@@ -261,6 +261,6 @@ const NotFound = (): JSX.Element => {
</defs>
</svg>
);
};
}
export default NotFound;

View File

@@ -1,6 +1,8 @@
import { Dayjs } from 'dayjs';
import dayjsGenerateConfig from 'rc-picker/lib/generate/dayjs';
import generatePicker from 'antd/es/date-picker/generatePicker';
import { Dayjs } from 'dayjs';
// included in antd
// eslint-disable-next-line import/no-extraneous-dependencies
import dayjsGenerateConfig from 'rc-picker/lib/generate/dayjs';
const DatePicker = generatePicker<Dayjs>(dayjsGenerateConfig);

View File

@@ -1,42 +1,23 @@
import * as monaco from 'monaco-editor';
import React, { useEffect, useRef } from 'react';
import MEditor from '@monaco-editor/react';
import React from 'react';
import { Container } from './styles';
const Editor = ({ value }: EditorProps): JSX.Element => {
const divEl = useRef<HTMLDivElement>(null);
const editorRef = useRef<monaco.editor.IStandaloneCodeEditor>();
useEffect(() => {
let editor = editorRef.current;
if (divEl.current) {
editor = monaco.editor.create(divEl.current, {
value: value.current || '',
useShadowDOM: true,
theme: 'vs-dark',
automaticLayout: true,
fontSize: 16,
minimap: {
enabled: false,
},
language: 'yaml',
});
}
editor?.getModel()?.onDidChangeContent(() => {
value.current = editor?.getValue() || '';
});
return (): void => {
if (editor) {
editor.dispose();
}
};
}, [value]);
return <Container ref={divEl} />;
};
function Editor({ value }: EditorProps): JSX.Element {
return (
<MEditor
theme="vs-dark"
defaultLanguage="yaml"
value={value.current}
options={{ fontSize: 16, automaticLayout: true }}
height="40vh"
onChange={(newValue): void => {
if (value.current && newValue) {
// eslint-disable-next-line no-param-reassign
value.current = newValue;
}
}}
/>
);
}
interface EditorProps {
value: React.MutableRefObject<string>;

View File

@@ -1,8 +0,0 @@
import styled from 'styled-components';
export const Container = styled.div`
&&& {
min-height: 40vh;
width: 100%;
}
`;

View File

@@ -0,0 +1,17 @@
import { grey } from '@ant-design/colors';
import { Chart } from 'chart.js';
export const emptyGraph = {
id: 'emptyChart',
afterDraw(chart: Chart): void {
const { height, width, ctx } = chart;
chart.clear();
ctx.save();
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
ctx.font = '1.5rem sans-serif';
ctx.fillStyle = `${grey.primary}`;
ctx.fillText('No data to display', width / 2, height / 2);
ctx.restore();
},
};

View File

@@ -1,7 +1,12 @@
import { Plugin, ChartType, Chart, ChartOptions } from 'chart.js';
import { Chart, ChartType, Plugin } from 'chart.js';
import { colors } from 'lib/getRandomColor';
import { get } from 'lodash-es';
const getOrCreateLegendList = (chart: Chart, id: string, isLonger: boolean) => {
const getOrCreateLegendList = (
chart: Chart,
id: string,
isLonger: boolean,
): HTMLUListElement => {
const legendContainer = document.getElementById(id);
let listContainer = legendContainer?.querySelector('ul');
@@ -27,7 +32,7 @@ const getOrCreateLegendList = (chart: Chart, id: string, isLonger: boolean) => {
export const legend = (id: string, isLonger: boolean): Plugin<ChartType> => {
return {
id: 'htmlLegend',
afterUpdate(chart, args, options: ChartOptions) {
afterUpdate(chart): void {
const ul = getOrCreateLegendList(chart, id || 'legend', isLonger);
// Remove old legend items
@@ -36,9 +41,20 @@ export const legend = (id: string, isLonger: boolean): Plugin<ChartType> => {
}
// Reuse the built-in legendItems generator
const items = chart?.options?.plugins?.legend?.labels?.generateLabels(chart);
const items = get(chart, [
'options',
'plugins',
'legend',
'labels',
'generateLabels',
])
? get(chart, ['options', 'plugins', 'legend', 'labels', 'generateLabels'])(
chart,
)
: null;
items?.forEach((item, index) => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
items?.forEach((item: Record<any, any>, index: number) => {
const li = document.createElement('li');
li.style.alignItems = 'center';
li.style.cursor = 'pointer';
@@ -46,7 +62,7 @@ export const legend = (id: string, isLonger: boolean): Plugin<ChartType> => {
li.style.marginLeft = '10px';
li.style.marginTop = '5px';
li.onclick = () => {
li.onclick = (): void => {
const { type } = chart.config;
if (type === 'pie' || type === 'doughnut') {
// Pie and doughnut charts only have a single dataset and visibility is per item
@@ -62,9 +78,9 @@ export const legend = (id: string, isLonger: boolean): Plugin<ChartType> => {
// Color box
const boxSpan = document.createElement('span');
boxSpan.style.background = item.strokeStyle || colors[0];
boxSpan.style.borderColor = item?.strokeStyle;
boxSpan.style.borderWidth = item.lineWidth + 'px';
boxSpan.style.background = `${item.strokeStyle}` || `${colors[0]}`;
boxSpan.style.borderColor = `${item?.strokeStyle}`;
boxSpan.style.borderWidth = `${item.lineWidth}px`;
boxSpan.style.display = 'inline-block';
boxSpan.style.minHeight = '20px';
boxSpan.style.marginRight = '10px';

View File

@@ -0,0 +1,75 @@
import { expect } from '@jest/globals';
import dayjs from 'dayjs';
import { convertTimeRange, TIME_UNITS } from '../xAxisConfig';
describe('xAxisConfig for Chart', () => {
describe('convertTimeRange', () => {
it('should return relevant time units for given range', () => {
{
const start = dayjs();
const end = start.add(10, 'millisecond');
expect(convertTimeRange(start.valueOf(), end.valueOf()).unitName).toEqual(
TIME_UNITS.millisecond,
);
}
{
const start = dayjs();
const end = start.add(10, 'second');
expect(convertTimeRange(start.valueOf(), end.valueOf()).unitName).toEqual(
TIME_UNITS.second,
);
}
{
const start = dayjs();
const end = start.add(10, 'minute');
expect(convertTimeRange(start.valueOf(), end.valueOf()).unitName).toEqual(
TIME_UNITS.minute,
);
}
{
const start = dayjs();
const end = start.add(10, 'hour');
expect(convertTimeRange(start.valueOf(), end.valueOf()).unitName).toEqual(
TIME_UNITS.hour,
);
}
{
const start = dayjs();
const end = start.add(10, 'day');
expect(convertTimeRange(start.valueOf(), end.valueOf()).unitName).toEqual(
TIME_UNITS.day,
);
}
{
const start = dayjs();
const end = start.add(10, 'week');
expect(convertTimeRange(start.valueOf(), end.valueOf()).unitName).toEqual(
TIME_UNITS.week,
);
}
{
const start = dayjs();
const end = start.add(10, 'month');
expect(convertTimeRange(start.valueOf(), end.valueOf()).unitName).toEqual(
TIME_UNITS.month,
);
}
{
const start = dayjs();
const end = start.add(10, 'year');
expect(convertTimeRange(start.valueOf(), end.valueOf()).unitName).toEqual(
TIME_UNITS.year,
);
}
});
});
});

View File

@@ -0,0 +1,19 @@
/* eslint-disable no-restricted-syntax */
import { ChartData } from 'chart.js';
export const hasData = (data: ChartData): boolean => {
const { datasets = [] } = data;
let hasData = false;
try {
for (const dataset of datasets) {
if (dataset.data.length > 0 && dataset.data.some((item) => item !== 0)) {
hasData = true;
break;
}
}
} catch (error) {
console.error(error);
}
return hasData;
};

View File

@@ -27,6 +27,13 @@ import { useSelector } from 'react-redux';
import { AppState } from 'store/reducers';
import AppReducer from 'types/reducer/app';
import { hasData } from './hasData';
import { legend } from './Plugin';
import { emptyGraph } from './Plugin/EmptyGraph';
import { LegendsContainer } from './styles';
import { useXAxisTimeUnit } from './xAxisConfig';
import { getYAxisFormattedValue } from './yAxisConfig';
Chart.register(
LineElement,
PointElement,
@@ -44,24 +51,24 @@ Chart.register(
BarController,
BarElement,
);
import { legend } from './Plugin';
import { LegendsContainer } from './styles';
const Graph = ({
function Graph({
animate = true,
data,
type,
title,
isStacked,
onClickHandler,
name,
}: GraphProps): JSX.Element => {
yAxisUnit = 'short',
forceReRender,
}: GraphProps): JSX.Element {
const { isDarkMode } = useSelector<AppState, AppReducer>((state) => state.app);
const chartRef = useRef<HTMLCanvasElement>(null);
const currentTheme = isDarkMode ? 'dark' : 'light';
const xAxisTimeUnit = useXAxisTimeUnit(data); // Computes the relevant time unit for x axis by analyzing the time stamp data
// const [tooltipVisible, setTooltipVisible] = useState<boolean>(false);
const lineChartRef = useRef<Chart>();
const getGridColor = useCallback(() => {
if (currentTheme === undefined) {
return 'rgba(231,233,237,0.1)';
@@ -74,6 +81,7 @@ const Graph = ({
return 'rgba(231,233,237,0.8)';
}, [currentTheme]);
// eslint-disable-next-line sonarjs/cognitive-complexity
const buildChart = useCallback(() => {
if (lineChartRef.current !== undefined) {
lineChartRef.current.destroy();
@@ -81,6 +89,9 @@ const Graph = ({
if (chartRef.current !== null) {
const options: ChartOptions = {
animation: {
duration: animate ? 200 : 0,
},
responsive: true,
maintainAspectRatio: false,
interaction: {
@@ -89,12 +100,27 @@ const Graph = ({
},
plugins: {
title: {
display: title === undefined ? false : true,
display: title !== undefined,
text: title,
},
legend: {
display: false,
},
tooltip: {
callbacks: {
label(context) {
let label = context.dataset.label || '';
if (label) {
label += ': ';
}
if (context.parsed.y !== null) {
label += getYAxisFormattedValue(context.parsed.y, yAxisUnit);
}
return label;
},
},
},
},
layout: {
padding: 0,
@@ -104,12 +130,24 @@ const Graph = ({
grid: {
display: true,
color: getGridColor(),
drawTicks: true,
},
adapters: {
date: chartjsAdapter,
},
time: {
unit: 'minute',
unit: xAxisTimeUnit?.unitName || 'minute',
stepSize: xAxisTimeUnit?.stepSize || 1,
displayFormats: {
millisecond: 'HH:mm:ss',
second: 'HH:mm:ss',
minute: 'HH:mm',
hour: 'MM/dd HH:mm',
day: 'MM/dd',
week: 'MM/dd',
month: 'yy-MM',
year: 'yy',
},
},
type: 'time',
},
@@ -119,6 +157,15 @@ const Graph = ({
display: true,
color: getGridColor(),
},
ticks: {
// Include a dollar sign in the ticks
callback(value) {
return getYAxisFormattedValue(
parseInt(value.toString(), 10),
yAxisUnit,
);
},
},
},
stacked: {
display: isStacked === undefined ? false : 'auto',
@@ -136,19 +183,37 @@ const Graph = ({
}
},
};
const chartHasData = hasData(data);
const chartPlugins = [];
if (chartHasData) {
chartPlugins.push(legend(name, data.datasets.length > 3));
} else {
chartPlugins.push(emptyGraph);
}
lineChartRef.current = new Chart(chartRef.current, {
type: type,
data: data,
type,
data,
options,
plugins: [legend(name, data.datasets.length > 3)],
plugins: chartPlugins,
});
}
}, [chartRef, data, type, title, isStacked, getGridColor, onClickHandler]);
}, [
animate,
title,
getGridColor,
xAxisTimeUnit?.unitName,
xAxisTimeUnit?.stepSize,
isStacked,
type,
data,
name,
yAxisUnit,
onClickHandler,
]);
useEffect(() => {
buildChart();
}, [buildChart]);
}, [buildChart, forceReRender]);
return (
<div style={{ height: '85%' }}>
@@ -156,23 +221,33 @@ const Graph = ({
<LegendsContainer id={name} />
</div>
);
};
}
interface GraphProps {
animate?: boolean;
type: ChartType;
data: Chart['data'];
title?: string;
isStacked?: boolean;
label?: string[];
onClickHandler?: graphOnClickHandler;
onClickHandler?: GraphOnClickHandler;
name: string;
yAxisUnit?: string;
forceReRender?: boolean | null | number;
}
export type graphOnClickHandler = (
export type GraphOnClickHandler = (
event: ChartEvent,
elements: ActiveElement[],
chart: Chart,
data: ChartData,
) => void;
Graph.defaultProps = {
animate: undefined,
title: undefined,
isStacked: undefined,
onClickHandler: undefined,
yAxisUnit: undefined,
forceReRender: undefined,
};
export default Graph;

View File

@@ -0,0 +1,154 @@
import { Chart, TimeUnit } from 'chart.js';
import { useMemo } from 'react';
import { useSelector } from 'react-redux';
import { AppState } from 'store/reducers';
import { GlobalReducer } from 'types/reducer/globalTime';
interface ITimeUnit {
[key: string]: TimeUnit;
}
interface IAxisTimeUintConfig {
unitName: TimeUnit;
multiplier: number;
}
interface IAxisTimeConfig {
unitName: TimeUnit;
stepSize: number;
}
export interface ITimeRange {
minTime: number | null;
maxTime: number | null;
}
export const TIME_UNITS: ITimeUnit = {
millisecond: 'millisecond',
second: 'second',
minute: 'minute',
hour: 'hour',
day: 'day',
week: 'week',
month: 'month',
year: 'year',
};
const TIME_UNITS_CONFIG: IAxisTimeUintConfig[] = [
{
unitName: TIME_UNITS.millisecond,
multiplier: 1,
},
{
unitName: TIME_UNITS.second,
multiplier: 1 / 1e3,
},
{
unitName: TIME_UNITS.minute,
multiplier: 1 / (1e3 * 60),
},
{
unitName: TIME_UNITS.hour,
multiplier: 1 / (1e3 * 60 * 60),
},
{
unitName: TIME_UNITS.day,
multiplier: 1 / (1e3 * 60 * 60 * 24),
},
{
unitName: TIME_UNITS.week,
multiplier: 1 / (1e3 * 60 * 60 * 24 * 7),
},
{
unitName: TIME_UNITS.month,
multiplier: 1 / (1e3 * 60 * 60 * 24 * 30),
},
{
unitName: TIME_UNITS.year,
multiplier: 1 / (1e3 * 60 * 60 * 24 * 365),
},
];
/**
* Finds the relevant time unit based on the input time stamps (in ms)
*/
export const convertTimeRange = (
start: number,
end: number,
): IAxisTimeConfig => {
const MIN_INTERVALS = 6;
const range = end - start;
let relevantTimeUnit = TIME_UNITS_CONFIG[1];
let stepSize = 1;
try {
for (let idx = TIME_UNITS_CONFIG.length - 1; idx >= 0; idx -= 1) {
const timeUnit = TIME_UNITS_CONFIG[idx];
const units = range * timeUnit.multiplier;
const steps = units / MIN_INTERVALS;
if (steps >= 1) {
relevantTimeUnit = timeUnit;
stepSize = steps;
break;
}
}
} catch (error) {
console.error(error);
}
return {
unitName: relevantTimeUnit.unitName,
stepSize: Math.floor(stepSize) || 1,
};
};
/**
* Accepts Chart.js data's data-structure and returns the relevant time unit for the axis based on the range of the data.
*/
export const useXAxisTimeUnit = (data: Chart['data']): IAxisTimeConfig => {
// Local time is the time range inferred from the input chart data.
let localTime: ITimeRange | null;
try {
let minTime = Number.POSITIVE_INFINITY;
let maxTime = Number.NEGATIVE_INFINITY;
data?.labels?.forEach((timeStamp: unknown): void => {
const getTimeStamp = (time: string | number): Date | number | string => {
if (typeof timeStamp === 'string') {
return Date.parse(timeStamp);
}
return time;
};
const time = getTimeStamp(timeStamp as string | number);
minTime = Math.min(parseInt(time.toString(), 10), minTime);
maxTime = Math.max(parseInt(time.toString(), 10), maxTime);
});
localTime = {
minTime: minTime === Number.POSITIVE_INFINITY ? null : minTime,
maxTime: maxTime === Number.NEGATIVE_INFINITY ? null : maxTime,
};
} catch (error) {
localTime = null;
console.error(error);
}
// Global time is the time selected from the global time selector menu.
const globalTime = useSelector<AppState, GlobalReducer>(
(state) => state.globalTime,
);
// Use local time if valid else use the global time range
const { maxTime, minTime } = useMemo(() => {
if (localTime && localTime.maxTime && localTime.minTime) {
return {
minTime: localTime.minTime,
maxTime: localTime.maxTime,
};
}
return {
minTime: globalTime.minTime / 1e6,
maxTime: globalTime.maxTime / 1e6,
};
}, [globalTime, localTime]);
return convertTimeRange(minTime, maxTime);
};

View File

@@ -0,0 +1,15 @@
import { formattedValueToString, getValueFormat } from '@grafana/data';
export const getYAxisFormattedValue = (
value: number,
format: string,
): string => {
try {
return formattedValueToString(
getValueFormat(format)(value, undefined, undefined, undefined),
);
} catch (error) {
console.error(error);
}
return `${value}`;
};

View File

@@ -1,7 +1,7 @@
import { Form, Input, InputProps } from 'antd';
import { Form, Input, InputProps, InputRef } from 'antd';
import React from 'react';
const InputComponent = ({
function InputComponent({
value,
type = 'text',
onChangeHandler,
@@ -14,29 +14,32 @@ const InputComponent = ({
labelOnTop,
addonBefore,
...props
}: InputComponentProps): JSX.Element => (
<Form.Item labelCol={{ span: labelOnTop ? 24 : 4 }} label={label}>
<Input
placeholder={placeholder}
type={type}
onChange={onChangeHandler}
value={value}
ref={ref}
size={size}
addonBefore={addonBefore}
onBlur={onBlurHandler}
onPressEnter={onPressEnterHandler}
{...props}
/>
</Form.Item>
);
}: InputComponentProps): JSX.Element {
return (
<Form.Item labelCol={{ span: labelOnTop ? 24 : 4 }} label={label}>
<Input
placeholder={placeholder}
type={type}
onChange={onChangeHandler}
value={value}
ref={ref as React.Ref<InputRef>}
size={size}
addonBefore={addonBefore}
onBlur={onBlurHandler}
onPressEnter={onPressEnterHandler}
// eslint-disable-next-line react/jsx-props-no-spreading
{...props}
/>
</Form.Item>
);
}
interface InputComponentProps extends InputProps {
value: InputProps['value'];
type?: InputProps['type'];
onChangeHandler?: React.ChangeEventHandler<HTMLInputElement>;
placeholder?: InputProps['placeholder'];
ref?: React.LegacyRef<Input>;
ref?: React.LegacyRef<InputRef>;
size?: InputProps['size'];
onBlurHandler?: React.FocusEventHandler<HTMLInputElement>;
onPressEnterHandler?: React.KeyboardEventHandler<HTMLInputElement>;
@@ -45,4 +48,17 @@ interface InputComponentProps extends InputProps {
addonBefore?: React.ReactNode;
}
InputComponent.defaultProps = {
type: undefined,
onChangeHandler: undefined,
placeholder: undefined,
ref: undefined,
size: undefined,
onBlurHandler: undefined,
onPressEnterHandler: undefined,
label: undefined,
labelOnTop: undefined,
addonBefore: undefined,
};
export default InputComponent;

View File

@@ -3,9 +3,7 @@ import { ComponentType, lazy } from 'react';
function Loadable(importPath: {
(): LoadableProps;
}): React.LazyExoticComponent<LazyComponent> {
const LazyComponent = lazy(() => importPath());
return LazyComponent;
return lazy(() => importPath());
}
type LazyComponent = ComponentType<Record<string, unknown>>;

View File

@@ -1,26 +1,24 @@
import { Modal, ModalProps as Props } from 'antd';
import React, { ReactElement } from 'react';
const CustomModal = ({
function CustomModal({
title,
children,
isModalVisible,
footer,
closable = true,
}: ModalProps): JSX.Element => {
}: ModalProps): JSX.Element {
return (
<>
<Modal
title={title}
visible={isModalVisible}
footer={footer}
closable={closable}
>
{children}
</Modal>
</>
<Modal
title={title}
visible={isModalVisible}
footer={footer}
closable={closable}
>
{children}
</Modal>
);
};
}
interface ModalProps {
isModalVisible: boolean;
@@ -30,4 +28,9 @@ interface ModalProps {
children: ReactElement;
}
CustomModal.defaultProps = {
closable: undefined,
footer: undefined,
};
export default CustomModal;

View File

@@ -1,3 +1,8 @@
/**
* @jest-environment jsdom
*/
import { expect } from '@jest/globals';
import { render } from '@testing-library/react';
import React from 'react';
import { MemoryRouter } from 'react-router-dom';

View File

@@ -3,7 +3,7 @@
exports[`Not Found page test should render Not Found page without errors 1`] = `
<DocumentFragment>
<div
class="sc-gtsrHT VomVY"
class="sc-gsDKAQ cLXpIa"
>
<svg
fill="none"
@@ -272,21 +272,21 @@ exports[`Not Found page test should render Not Found page without errors 1`] = `
</defs>
</svg>
<div
class="sc-hKFxyN dunFuJ"
class="sc-hKwDye foaleg"
>
<p
class="sc-dlnjwi cydxLA"
class="sc-dkPtRN fcyVIq"
>
Ah, seems like we reached a dead end!
</p>
<p
class="sc-dlnjwi cydxLA"
class="sc-dkPtRN fcyVIq"
>
Page Not Found
</p>
</div>
<a
class="sc-bdnxRM bYqcho"
class="sc-bdvvtL dbTZkj"
href="/application"
tabindex="0"
>

View File

@@ -4,7 +4,7 @@ import React from 'react';
import { Button, Container, Text, TextContainer } from './styles';
const NotFound = (): JSX.Element => {
function NotFound(): JSX.Element {
return (
<Container>
<NotFoundImage />
@@ -19,6 +19,6 @@ const NotFound = (): JSX.Element => {
</Button>
</Container>
);
};
}
export default NotFound;

View File

@@ -2,7 +2,6 @@ import { Link } from 'react-router-dom';
import styled from 'styled-components';
export const Button = styled(Link)`
height: 100%;
border: 2px solid #2f80ed;
box-sizing: border-box;
border-radius: 10px;

View File

@@ -0,0 +1,58 @@
import { Tabs, TabsProps } from 'antd';
import history from 'lib/history';
import React from 'react';
const { TabPane } = Tabs;
function RouteTab({
routes,
activeKey,
onChangeHandler,
...rest
}: RouteTabProps & TabsProps): JSX.Element {
const onChange = (activeRoute: string): void => {
if (onChangeHandler) {
onChangeHandler();
}
const selectedRoute = routes.find((e) => e.name === activeRoute);
if (selectedRoute) {
history.push(selectedRoute.route);
}
};
return (
<Tabs
onChange={onChange}
destroyInactiveTabPane
activeKey={activeKey}
// eslint-disable-next-line react/jsx-props-no-spreading
{...rest}
>
{routes.map(
({ Component, name }): JSX.Element => (
<TabPane tab={name} key={name}>
<Component />
</TabPane>
),
)}
</Tabs>
);
}
interface RouteTabProps {
routes: {
name: string;
route: string;
Component: () => JSX.Element;
}[];
activeKey: TabsProps['activeKey'];
onChangeHandler?: VoidFunction;
}
RouteTab.defaultProps = {
onChangeHandler: undefined,
};
export default RouteTab;

View File

@@ -4,16 +4,23 @@ import React from 'react';
import { SpinerStyle } from './styles';
const Spinner = ({ size, tip, height }: SpinnerProps): JSX.Element => (
<SpinerStyle height={height}>
<Spin spinning size={size} tip={tip} indicator={<LoadingOutlined spin />} />
</SpinerStyle>
);
function Spinner({ size, tip, height }: SpinnerProps): JSX.Element {
return (
<SpinerStyle height={height}>
<Spin spinning size={size} tip={tip} indicator={<LoadingOutlined spin />} />
</SpinerStyle>
);
}
interface SpinnerProps {
size?: SpinProps['size'];
tip?: SpinProps['tip'];
height?: React.CSSProperties['height'];
}
Spinner.defaultProps = {
size: undefined,
tip: undefined,
height: undefined,
};
export default Spinner;

View File

@@ -0,0 +1,72 @@
import * as AntD from 'antd';
import { TextProps } from 'antd/lib/typography/Text';
import { TitleProps } from 'antd/lib/typography/Title';
import React from 'react';
import styled, { FlattenSimpleInterpolation } from 'styled-components';
import { IStyledClass } from './types';
const styledClass = (props: IStyledClass): FlattenSimpleInterpolation | null =>
props.styledclass || null;
type TStyledCol = AntD.ColProps & IStyledClass;
const StyledCol = styled(AntD.Col)<TStyledCol>`
${styledClass}
`;
type TStyledRow = AntD.RowProps & IStyledClass;
const StyledRow = styled(AntD.Row)<TStyledRow>`
${styledClass}
`;
type TStyledDivider = AntD.DividerProps & IStyledClass;
const StyledDivider = styled(AntD.Divider)<TStyledDivider>`
${styledClass}
`;
type TStyledSpace = AntD.SpaceProps & IStyledClass;
const StyledSpace = styled(AntD.Space)<TStyledSpace>`
${styledClass}
`;
type TStyledTabs = AntD.TabsProps & IStyledClass;
const StyledTabs = styled(AntD.Divider)<TStyledTabs>`
${styledClass}
`;
type TStyledButton = AntD.ButtonProps & IStyledClass;
const StyledButton = styled(AntD.Button)<TStyledButton>`
${styledClass}
`;
const { Text } = AntD.Typography;
type TStyledTypographyText = TextProps & IStyledClass;
const StyledTypographyText = styled(Text)<TStyledTypographyText>`
${styledClass}
`;
const { Title } = AntD.Typography;
type TStyledTypographyTitle = TitleProps & IStyledClass;
const StyledTypographyTitle = styled(Title)<TStyledTypographyTitle>`
${styledClass}
`;
type TStyledDiv = React.HTMLAttributes<HTMLDivElement> & IStyledClass;
const StyledDiv = styled.div<TStyledDiv>`
${styledClass}
`;
const StyledTypography = {
Text: StyledTypographyText,
Title: StyledTypographyTitle,
};
export {
StyledButton,
StyledCol,
StyledDiv,
StyledDivider,
StyledRow,
StyledSpace,
StyledTabs,
StyledTypography,
};

View File

@@ -0,0 +1,42 @@
import { css, FlattenSimpleInterpolation } from 'styled-components';
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const cssProperty = (key: any, value: any): FlattenSimpleInterpolation =>
key &&
value &&
css`
${key}: ${value};
`;
interface IFlexProps {
flexDirection?: string; // Need to replace this with exact css props. Not able to find any :(
flex?: number | string;
}
export const Flex = ({
flexDirection,
flex,
}: IFlexProps): FlattenSimpleInterpolation => css`
${cssProperty('flex-direction', flexDirection)}
${cssProperty('flex', flex)}
`;
interface IDisplayProps {
display?: string;
}
export const Display = ({
display,
}: IDisplayProps): FlattenSimpleInterpolation => css`
${cssProperty('display', display)}
`;
interface ISpacingProps {
margin?: string;
padding?: string;
}
export const Spacing = ({
margin,
padding,
}: ISpacingProps): FlattenSimpleInterpolation => css`
${cssProperty('margin', margin)}
${cssProperty('padding', padding)}
`;

View File

@@ -0,0 +1,5 @@
import { FlattenSimpleInterpolation } from 'styled-components';
export interface IStyledClass {
styledclass?: FlattenSimpleInterpolation[];
}

View File

@@ -1,23 +1,26 @@
/* eslint-disable react/no-unstable-nested-components */
import { QuestionCircleFilled } from '@ant-design/icons';
import { Tooltip } from 'antd';
import React from 'react';
const TextToolTip = ({ text, url }: TextToolTipProps) => (
<Tooltip
overlay={() => {
return (
<div>
{`${text} `}
<a href={url} target={'_blank'}>
here
</a>
</div>
);
}}
>
<QuestionCircleFilled style={{ fontSize: '1.3125rem' }} />
</Tooltip>
);
function TextToolTip({ text, url }: TextToolTipProps): JSX.Element {
return (
<Tooltip
overlay={(): JSX.Element => {
return (
<div>
{`${text} `}
<a href={url} rel="noopener noreferrer" target="_blank">
here
</a>
</div>
);
}}
>
<QuestionCircleFilled style={{ fontSize: '1.3125rem' }} />
</Tooltip>
);
}
interface TextToolTipProps {
url: string;

View File

@@ -1,5 +1,5 @@
import { Button, Dropdown, Menu, Typography } from 'antd';
import timeItems, {
import TimeItems, {
timePreferance,
timePreferenceType,
} from 'container/NewWidget/RightContainer/timeItems';
@@ -7,13 +7,13 @@ import React, { useCallback } from 'react';
import { TextContainer } from './styles';
const TimePreference = ({
function TimePreference({
setSelectedTime,
selectedTime,
}: TimePreferenceDropDownProps): JSX.Element => {
}: TimePreferenceDropDownProps): JSX.Element {
const timeMenuItemOnChangeHandler = useCallback(
(event: TimeMenuItemOnChangeHandlerEvent) => {
const selectedTime = timeItems.find((e) => e.enum === event.key);
const selectedTime = TimeItems.find((e) => e.enum === event.key);
if (selectedTime !== undefined) {
setSelectedTime(selectedTime);
}
@@ -26,7 +26,7 @@ const TimePreference = ({
<Dropdown
overlay={
<Menu>
{timeItems.map((item) => (
{TimeItems.map((item) => (
<Menu.Item onClick={timeMenuItemOnChangeHandler} key={item.enum}>
<Typography>{item.name}</Typography>
</Menu.Item>
@@ -38,7 +38,7 @@ const TimePreference = ({
</Dropdown>
</TextContainer>
);
};
}
interface TimeMenuItemOnChangeHandlerEvent {
key: timePreferenceType | string;

View File

@@ -2,9 +2,9 @@ import React from 'react';
import { Value } from './styles';
const ValueGraph = ({ value }: ValueGraphProps): JSX.Element => (
<Value>{value}</Value>
);
function ValueGraph({ value }: ValueGraphProps): JSX.Element {
return <Value>{value}</Value>;
}
interface ValueGraphProps {
value: string;

View File

@@ -5,3 +5,5 @@ export const WITHOUT_SESSION_PATH = ['/redirect'];
export const AUTH0_REDIRECT_PATH = '/redirect';
export const DEFAULT_AUTH0_APP_REDIRECTION_PATH = ROUTES.APPLICATION;
export const IS_SIDEBAR_COLLAPSED = 'isSideBarCollapsed';

View File

@@ -1,3 +1,3 @@
export enum LOCAL_STORAGE {
export enum LOCALSTORAGE {
METRICS_TIME_IN_DURATION = 'metricsTimeDurations',
}

View File

@@ -1,3 +1,4 @@
// eslint-disable-next-line @typescript-eslint/naming-convention
export enum METRICS_PAGE_QUERY_PARAM {
interval = 'interval',
startTime = 'startTime',

View File

@@ -3,7 +3,7 @@ const ROUTES = {
SERVICE_METRICS: '/application/:servicename',
SERVICE_MAP: '/service-map',
TRACE: '/trace',
TRACE_GRAPH: '/trace/:id',
TRACE_DETAIL: '/trace/:id',
SETTINGS: '/settings',
INSTRUMENTATION: '/add-instrumentation',
USAGE_EXPLORER: '/usage-explorer',
@@ -17,6 +17,7 @@ const ROUTES = {
ALL_CHANNELS: '/settings/channels',
CHANNELS_NEW: '/setting/channels/new',
CHANNELS_EDIT: '/setting/channels/edit/:id',
VERSION: '/status',
};
export default ROUTES;

View File

@@ -4,12 +4,12 @@ import { ColumnsType } from 'antd/lib/table';
import ROUTES from 'constants/routes';
import history from 'lib/history';
import React, { useCallback, useState } from 'react';
import { generatePath } from 'react-router';
import { generatePath } from 'react-router-dom';
import { Channels, PayloadProps } from 'types/api/channels/getAll';
import Delete from './Delete';
const AlertChannels = ({ allChannels }: AlertChannelsProps): JSX.Element => {
function AlertChannels({ allChannels }: AlertChannelsProps): JSX.Element {
const [notifications, Element] = notification.useNotification();
const [channels, setChannels] = useState<Channels[]>(allChannels);
@@ -55,7 +55,7 @@ const AlertChannels = ({ allChannels }: AlertChannelsProps): JSX.Element => {
<Table rowKey="id" dataSource={channels} columns={columns} />
</>
);
};
}
interface AlertChannelsProps {
allChannels: PayloadProps;

View File

@@ -4,11 +4,7 @@ import deleteAlert from 'api/channels/delete';
import React, { useState } from 'react';
import { Channels } from 'types/api/channels/getAll';
const Delete = ({
notifications,
setChannels,
id,
}: DeleteProps): JSX.Element => {
function Delete({ notifications, setChannels, id }: DeleteProps): JSX.Element {
const [loading, setLoading] = useState(false);
const onClickHandler = async (): Promise<void> => {
@@ -34,7 +30,8 @@ const Delete = ({
} catch (error) {
notifications.error({
message: 'Error',
description: error.toString() || 'Something went wrong',
description:
error instanceof Error ? error.toString() : 'Something went wrong',
});
setLoading(false);
}
@@ -50,7 +47,7 @@ const Delete = ({
Delete
</Button>
);
};
}
interface DeleteProps {
notifications: NotificationInstance;

View File

@@ -7,12 +7,13 @@ import ROUTES from 'constants/routes';
import useFetch from 'hooks/useFetch';
import history from 'lib/history';
import React, { useCallback } from 'react';
const { Paragraph } = Typography;
import AlertChannlesComponent from './AlertChannels';
import { ButtonContainer, Button } from './styles';
import { Button, ButtonContainer } from './styles';
const AlertChannels = (): JSX.Element => {
const { Paragraph } = Typography;
function AlertChannels(): JSX.Element {
const onToggleHandler = useCallback(() => {
history.push(ROUTES.CHANNELS_NEW);
}, []);
@@ -24,7 +25,7 @@ const AlertChannels = (): JSX.Element => {
}
if (loading || payload === undefined) {
return <Spinner tip="Loading Channels.." height={'90vh'} />;
return <Spinner tip="Loading Channels.." height="90vh" />;
}
return (
@@ -36,7 +37,7 @@ const AlertChannels = (): JSX.Element => {
<div>
<TextToolTip
text={`More details on how to setting notification channels`}
text="More details on how to setting notification channels"
url="https://signoz.io/docs/userguide/alerts-management/#setting-notification-channel"
/>
@@ -49,6 +50,6 @@ const AlertChannels = (): JSX.Element => {
<AlertChannlesComponent allChannels={payload} />
</>
);
};
}
export default AlertChannels;

View File

@@ -1,5 +1,5 @@
import styled from 'styled-components';
import { Button as ButtonComponent } from 'antd';
import styled from 'styled-components';
export const ButtonContainer = styled.div`
&&& {

View File

@@ -1,127 +0,0 @@
import { CloseCircleOutlined, CommentOutlined } from '@ant-design/icons';
import { Button, Divider, Form, Input, notification, Typography } from 'antd';
import { Callbacks } from 'rc-field-form/lib/interface';
import React, { useCallback, useState } from 'react';
import {
Button as IconButton,
ButtonContainer,
Card,
CenterText,
Container,
TitleContainer,
FormItem,
} from './styles';
const { Title } = Typography;
const { TextArea } = Input;
import sendFeedbackApi from 'api/userFeedback/sendFeedback';
const Feedback = (): JSX.Element => {
const [isOpen, setisOpen] = useState<boolean>(false);
const [form] = Form.useForm();
const [isLoading, setIsLoading] = useState<boolean>(false);
const [notifications, Element] = notification.useNotification();
const isToggleHandler = useCallback(() => {
setisOpen((state) => !state);
}, []);
const onFinishHandler: Callbacks<Feedback>['onFinish'] = async (
value: Feedback,
): Promise<void> => {
try {
setIsLoading(true);
const { feedback, email = '' } = value;
const response = await sendFeedbackApi({
email,
message: feedback,
});
if (response === 200) {
notifications.success({
message: 'Thanks for your feedback!',
description:
'We have noted down your feedback and will work on improving SIgNoz based on that!',
});
isToggleHandler();
} else {
notifications.error({
message: 'Error!',
description: 'Something went wrong',
});
}
setIsLoading(false);
} catch (error) {
notifications.error({
message: 'Something went wrong',
});
setIsLoading(false);
}
};
return (
<Container>
{!isOpen && (
<IconButton onClick={isToggleHandler} type="primary" size="large">
<CommentOutlined />
</IconButton>
)}
{Element}
{isOpen && (
<Form onFinish={onFinishHandler} form={form}>
<Card>
<TitleContainer>
<Title
aria-label="How can we improve SigNoz?"
style={{ margin: 0 }}
level={5}
>
How can we improve SigNoz?
</Title>
<CloseCircleOutlined onClick={isToggleHandler} />
</TitleContainer>
<Divider />
<FormItem name="feedback" required>
<TextArea
required
rows={3}
placeholder="Share what can we improve ( e.g. Not able to find how to see metrics... )"
/>
</FormItem>
<FormItem name="email">
<Input type="email" placeholder="Email (optional)" />
</FormItem>
<CenterText>This will just be visible to our maintainers</CenterText>
<ButtonContainer>
<Button
disabled={isLoading}
loading={isLoading}
htmlType="submit"
type="primary"
>
Share
</Button>
</ButtonContainer>
</Card>
</Form>
)}
</Container>
);
};
interface Feedback {
email?: string;
feedback: string;
}
export default Feedback;

View File

@@ -1,64 +0,0 @@
import {
Button as ButtonComponent,
Card as CardComponent,
Typography,
Form,
} from 'antd';
import styled from 'styled-components';
export const Container = styled.div`
position: fixed;
bottom: 5%;
right: 4%;
z-index: 999999;
`;
export const CenterText = styled(Typography)`
&&& {
font-size: 0.75rem;
text-align: center;
margin-bottom: 0.5rem;
}
`;
export const TitleContainer = styled.div`
&&& {
display: flex;
justify-content: space-between;
align-items: center;
}
`;
export const Card = styled(CardComponent)`
&&& {
min-width: 400px;
}
`;
export const ButtonContainer = styled.div`
display: flex;
justify-content: flex-end;
align-items: center;
`;
export const Button = styled(ButtonComponent)`
height: 4rem !important;
width: 4rem !important;
display: flex;
justify-content: center;
align-items: center;
border-radius: 25px !important;
background-color: #65b7f3;
svg {
width: 2rem;
height: 2rem;
}
`;
export const FormItem = styled(Form.Item)`
margin-top: 0.75rem;
margin-bottom: 0.75rem;
`;

View File

@@ -1,34 +1,123 @@
import { notification } from 'antd';
import getLatestVersion from 'api/user/getLatestVersion';
import getVersion from 'api/user/getVersion';
import ROUTES from 'constants/routes';
import TopNav from 'container/Header';
import SideNav from 'container/SideNav';
import useFetch from 'hooks/useFetch';
import history from 'lib/history';
import React, { ReactNode, useEffect, useState } from 'react';
import { useSelector } from 'react-redux';
import React, { ReactNode, useEffect, useRef, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { useDispatch, useSelector } from 'react-redux';
import { useLocation } from 'react-router-dom';
import { Dispatch } from 'redux';
import { AppState } from 'store/reducers';
import AppActions from 'types/actions';
import {
UPDATE_CURRENT_ERROR,
UPDATE_CURRENT_VERSION,
UPDATE_LATEST_VERSION,
UPDATE_LATEST_VERSION_ERROR,
} from 'types/actions/app';
import AppReducer from 'types/reducer/app';
import Feedback from './FeedBack';
import { Content, Footer, Layout } from './styles';
import { Content, Layout } from './styles';
const AppLayout: React.FC<AppLayoutProps> = ({ children }) => {
function AppLayout(props: AppLayoutProps): JSX.Element {
const { isLoggedIn } = useSelector<AppState, AppReducer>((state) => state.app);
const { pathname } = useLocation();
const { t } = useTranslation();
const [isSignUpPage, setIsSignUpPage] = useState(
ROUTES.SIGN_UP === location.pathname,
const [isSignUpPage, setIsSignUpPage] = useState(ROUTES.SIGN_UP === pathname);
const { payload: versionPayload, loading, error: getVersionError } = useFetch(
getVersion,
);
const {
payload: latestVersionPayload,
loading: latestLoading,
error: latestError,
} = useFetch(getLatestVersion);
const { children } = props;
const dispatch = useDispatch<Dispatch<AppActions>>();
useEffect(() => {
if (!isLoggedIn) {
setIsSignUpPage(true);
history.push(ROUTES.SIGN_UP);
} else {
if (isSignUpPage) {
setIsSignUpPage(false);
}
} else if (isSignUpPage) {
setIsSignUpPage(false);
}
}, [isLoggedIn, isSignUpPage]);
const currentYear = new Date().getFullYear();
const latestCurrentCounter = useRef(0);
const latestVersionCounter = useRef(0);
useEffect(() => {
if (isLoggedIn && pathname === ROUTES.SIGN_UP) {
history.push(ROUTES.APPLICATION);
}
if (!latestLoading && latestError && latestCurrentCounter.current === 0) {
latestCurrentCounter.current = 1;
dispatch({
type: UPDATE_LATEST_VERSION_ERROR,
payload: {
isError: true,
},
});
notification.error({
message: t('oops_something_went_wrong_version'),
});
}
if (!loading && getVersionError && latestVersionCounter.current === 0) {
latestVersionCounter.current = 1;
dispatch({
type: UPDATE_CURRENT_ERROR,
payload: {
isError: true,
},
});
notification.error({
message: t('oops_something_went_wrong_version'),
});
}
if (!latestLoading && versionPayload) {
dispatch({
type: UPDATE_CURRENT_VERSION,
payload: {
currentVersion: versionPayload.version,
},
});
}
if (!loading && latestVersionPayload) {
dispatch({
type: UPDATE_LATEST_VERSION,
payload: {
latestVersion: latestVersionPayload.name,
},
});
}
}, [
dispatch,
loading,
latestLoading,
versionPayload,
latestVersionPayload,
isLoggedIn,
pathname,
getVersionError,
latestError,
t,
]);
return (
<Layout>
@@ -38,13 +127,10 @@ const AppLayout: React.FC<AppLayoutProps> = ({ children }) => {
{!isSignUpPage && <TopNav />}
{children}
</Content>
<Footer>{`SigNoz Inc. © ${currentYear}`}</Footer>
</Layout>
<Feedback />
</Layout>
);
};
}
interface AppLayoutProps {
children: ReactNode;

Some files were not shown because too many files have changed in this diff Show More