Compare commits

...

263 Commits

Author SHA1 Message Date
Shaheer Kochai
a22ef64bb0
fix: fix the flaky test (#9255)
* fix: fix the flaky test

* chore: remove unnecessary changes
2025-10-06 22:02:12 +05:30
Amlan Kumar Nandy
c770a1a4e1
chore: remove routing policies feature flag (#9249) 2025-10-04 21:39:18 +05:30
Nageshbansal
101b3668b5
chore(statsreporter): fix azure IMDS endpoint in statsreporter (#9243) 2025-10-03 17:00:06 +00:00
Srikanth Chekuri
1b1aa4915b
chore: link to docs, QB flavour for expr and update options (#9246) 2025-10-03 21:50:56 +05:30
aniketio-ctrl
f9a70a3a69
chore: notification routing | added notificaiton routing via expression based routes (#9195)
* chore: added custom distpatcher

* feat(notification-grouping): added notification grouping

* feat(notification-grouping): addded integration test dependency

* feat(notification-grouping): linting and test cases

* feat(notification-grouping): linting and test cases

* feat(notification-grouping): linting and test cases

* feat(notification-grouping): addded integration test dependency

* feat(notification-grouping): debug log lines

* feat(notification-grouping): debug log lines

* feat(notification-grouping): debug log lines

* feat(notification-grouping): addded integration test dependency

* feat(notification-grouping): addded integration test dependency

* feat(notification-grouping): addded integration test dependency

* feat(notification-grouping): added structure changes

* feat(notification-grouping): added structure changes

* feat(notification-routing): added notification routing

* chore(notification-grouping): added notificaiton grouping

* Update pkg/alertmanager/nfmanager/rulebasednotification/provider.go

Co-authored-by: ellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com>

* chore(notification-grouping): added renotification interval

* fix(notification-grouping): added fix for renotification

* chore(notificaiton-grouping): added no data renotify

* chore(notificaiton-grouping): added no data renotify

* chore(notificaiton-grouping): added no data renotify

* chore(notification-grouping): added no data renotify interval

* chore(notification-grouping): removed errors package from dispatcher

* chore(notification-grouping): removed errors package from dispatcher

* chore(notification-grouping): removed unwanted tests

* chore(notification-grouping): removed unwanted pkg name

* chore(notification-grouping): added delete notification setting

* chore(notification-grouping): added delete notification setting

* Update pkg/alertmanager/nfmanager/nfmanagertest/provider.go

Co-authored-by: ellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com>

* chore(notification-grouping): removed nfmanager config| notification settings in postable rule

* chore(notification-grouping): removed nfmanager config| notification settings in postable rule

* chore(notification-grouping): added test for dispatcher

* chore(notification-grouping): added test for dispatcher

* chore(notification-grouping): go linting errors

* chore(notification-grouping): added test cases for aggGroupPerRoute

* chore(notification-grouping): added test cases for aggGroupPerRoute

* chore(notification-grouping): corrected get notification config logic

* Update pkg/alertmanager/nfmanager/rulebasednotification/provider_test.go

Co-authored-by: ellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com>

* chore(notification-routing): added notification routing policies

* feat(notification-routing): added test cases for dispatcher

* chore(notification-routing): added notification routing policies

* chore(notification-routing): added notification routing policies

* Apply suggestions from code review

Co-authored-by: ellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com>

* chore(notification-routing): added notification routing policies

* chore(notification-routing): added notification routing policies

* Update pkg/alertmanager/alertmanagerserver/distpatcher_test.go

Co-authored-by: ellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com>

* chore(notification-routing): sorted imports

* chore(notification-routing): minor edit |pr resolve comments

* chore(notification-grouping): corrected dispatcher test cases

* chore(notification-routing): added notification routing policies

* chore(notification-routing): corrected race condition in test

* chore: resolved pr comments

* chore: passing threshold value to tempalte

* chore: completed delete rule functionality

* chore: added grouping disabled functionality

* chore: added grouping disabled functionality

* chore(notification-routing): resolved pr comments

* chore(notification-routing): resolved pr comments

* chore(notification-routing): resolved pr comments

* chore(notification-routing): sorted imports

* chore(notification-routing): fix linting errors

* chore(notification-routing): removed enabled flags

* fix: test rule multiple threhsold (#9224)

* chore: corrected linting errors

* chore: corrected linting errors

* chore: corrected linting errors

* chore: corrected linting errors

* chore: corrected migration errors

* chore: corrected migration errors

* chore: corrected migration errors

* chore: corrected migration errors

* Update pkg/sqlmigration/049_add_route_policy.go

Co-authored-by: ellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com>

* chore: added org_is as foreign key

* chore: resolved pr comments

* chore: removed route store unused

---------

Co-authored-by: Srikanth Chekuri <srikanth.chekuri92@gmail.com>
Co-authored-by: ellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com>
2025-10-03 19:47:15 +05:30
Nityananda Gohain
d3be2632b6
fix: exists/not exists for resource attributes (#9129)
* fix: exists/not exists for resource attributes

* fix: update tests

* fix: remove unwanted changes

---------

Co-authored-by: Srikanth Chekuri <srikanth.chekuri92@gmail.com>
2025-10-03 05:42:42 +00:00
Srikanth Chekuri
78e4f4f386
fix: handle resource/attribute context collision with expression using paranthesis (#9240) 2025-10-03 10:16:06 +05:30
Amlan Kumar Nandy
cbb24d9a34
chore: edit alerts api integration (#9210) 2025-09-30 17:37:47 +00:00
Nageshbansal
9ffe0d8143
chore(statsreporter): add nomad, vultr, aca platform detection (#9220) 2025-09-30 16:31:43 +05:30
Amlan Kumar Nandy
1a1ef5aff8
chore: create alerts ux improvements and api integration (#9165) 2025-09-29 17:03:29 +00:00
Abhi kumar
8b21ba5db9
ISSUE:2806 - View traces/logs functionality across the product with new QB (#9207)
* fix: issue-2806 view traces/logs functionality across the product with new qb

* test: added test for getfilter

* test: updated tests
2025-09-29 19:12:50 +05:30
Vikrant Gupta
1b818dd05d
feat(authz): build role module (#9136)
* feat(authz): build role module

* feat(authz): build role module

* feat(authz): refactor the role module to move transactions out

* feat(authz): add handler implementation except patch objects

* feat(authz): added the missing handler

* feat(authz): added changes for selectors

* feat(authz): added changes for selectors

* feat(authz): added changes for selectors

* feat(authz): make the role create handler just to create metadata

* feat(authz): address review comments

* feat(authz): address review comments

* feat(authz): address review comments

* feat(authz): address review comments
2025-09-29 17:45:52 +05:30
Aditya Singh
3c3641493e
fix: fix page offset in exceptions tab (#9184) 2025-09-28 12:45:56 +00:00
Amlan Kumar Nandy
411414fa45
chore: add routing polices page (#9198) 2025-09-27 21:02:14 +05:30
aniketio-ctrl
735b90722d
chore(notification grouping): added custom grouping in signoz dispatcher (#8812) 2025-09-26 13:24:58 +00:00
Yunus M
8b485de584
chore: create a HOC to wrap components with ErrorBoundary (#9096)
* chore: create a HOC to wrap components with ErrorBoundary

* feat: move svg to public, use render from test-utils
2025-09-26 18:07:59 +05:30
Abhi kumar
d595dcc222
fix: added fix for passing activeLogId in query range in log context view (#9180)
* fix: added fix for passing activitylogId in query range in log context view

* chore: added tests
2025-09-26 13:17:38 +05:30
Ekansh Gupta
7ddaa84387
feat: add materialise ttl = 0 in set ttl v2 (#9189) 2025-09-26 05:44:13 +00:00
Niladri Adhikary
6d5f0adab9
fix: prevent panels with all queries disabled (#9093)
Signed-off-by: “niladrix719” <niladrix719@gmail.com>
2025-09-26 01:08:35 +00:00
primus-bot[bot]
2c19f0171f
chore(release): bump to v0.96.1 (#9194)
Co-authored-by: primus-bot[bot] <171087277+primus-bot[bot]@users.noreply.github.com>
2025-09-25 20:47:24 +05:30
Abhi kumar
9a5bcb6b64
revert: removed changes done for cursor position jump fix (#9193) 2025-09-25 13:57:05 +00:00
Aditya Singh
96cdf21a92
Fix: Opening logs link broken (Pref framework) (#9182)
* fix: logs popover content logic extracted out

* fix: logs popover content in live view

* fix: destory popover on close

* feat: add logs format tests

* feat: minor refactor

* feat: test case refactor

* feat: remove menu refs in logs live view
2025-09-25 13:44:05 +00:00
Yunus M
1aa5f5d0e1
fix: extra content passed by consuming component (#9191) 2025-09-25 13:30:40 +00:00
Vishal Sharma
6ac812b5af
chore: change update workspace URL to upgrade guide (#9178)
* chore: change update workspace URL to upgrade guide

* chore: change upgrade workspace url
2025-09-25 16:38:38 +05:30
Vikrant Gupta
0b4831ca04
chore(authz): bump up openfga version (#9175)
* chore(authz): bump up openfga version

* chore(authz): bump up openfga version

* chore(authz): bump up openfga version

---------

Co-authored-by: Srikanth Chekuri <srikanth.chekuri92@gmail.com>
2025-09-25 13:07:48 +05:30
primus-bot[bot]
340aa9ec21
chore(release): bump to v0.96.0 (#9179)
Co-authored-by: primus-bot[bot] <171087277+primus-bot[bot]@users.noreply.github.com>
Co-authored-by: Vikrant Gupta <vikrant@signoz.io>
Co-authored-by: Priyanshu Shrivastava <priyanshu@signoz.io>
2025-09-25 12:51:25 +05:30
Yunus M
5a47a4349b
feat: hide feedback for non licensed users (#9176) 2025-09-25 12:40:21 +05:30
Ekansh Gupta
80f0c6dd92
feat: added cold storage in set ttl v2 method (#9151)
* feat: added cold storage in set ttl v2 method

* feat: standardised cold storage ttl to days

* feat: added coldstorage ttl in response structure of get api
2025-09-25 06:57:20 +00:00
Yunus M
c0acc69f87
fix: revert queryKey update to re-enable cancel run (#9105) 2025-09-25 12:05:02 +05:30
SagarRajput-7
9114b44c0e
fix: correctly set and unset the stackbarchart value across panel types (#9158) 2025-09-24 22:37:31 +05:30
Vikrant Gupta
c68096152d
chore(clickhouse): bump ch-go (#9169)
* fix(integration): fix tests

* fix(integration): fix tests

* chore(clickhouse): bump ch-go

---------

Co-authored-by: Nityananda Gohain <nityanandagohain@gmail.com>
2025-09-24 15:10:29 +05:30
Vikrant Gupta
4d8d0223e7
fix(integration): fix tests (#9168)
* fix(integration): fix tests

* fix(integration): fix tests
2025-09-24 14:54:43 +05:30
Yunus M
2f4b8f6f80
feat: standardise header to include share and feedback sections (#9037)
* feat: standardise header to include share and feedback sections

* feat: add unit test cases

* feat: handle click outside to close open modals

* fix: handle click outside to close modals

* chore: update event name and placeholder

* fix: test cases

* feat: show success / failure message on feedback submit, fix test cases

* feat: add test cases to check if toast messages are shown on feedback submit

* feat: address review comments

* feat: update test cases

---------

Co-authored-by: makeavish <makeavish786@gmail.com>
2025-09-24 11:52:37 +05:30
Amlan Kumar Nandy
a54c3a3d7f
chore: add notification settings section to create alert (#9162) 2025-09-24 08:52:05 +05:30
Amlan Kumar Nandy
2c59c1196d
chore: add evaluation settings section (#9134) 2025-09-23 15:36:40 +00:00
manika-signoz
73ff89a80a
feat: revamp onboarding (#9068)
* feat: revamp onboarding, send list to mixpanel, join logic to convert to single string

* chore: props changes

* fix: allow user to proceed even if api fails

* chore: remove console.log

* chore: remove commented code

* chore: minor colour tweaks

* chore: resolve comments
2025-09-23 20:47:39 +05:30
Abhi kumar
b2dc2790d8
fix: invalid function name cumsum (#9161) 2025-09-23 14:37:44 +00:00
SagarRajput-7
dc8e4365f5
fix: fixed scroll reset issue when interacting with legends (#9065)
* fix: fixed scroll reset issue when interacting with legends

* fix: added test cases to ensure codes execution and req function are attached

* fix: added test cases

---------

Co-authored-by: Srikanth Chekuri <srikanth.chekuri92@gmail.com>
2025-09-23 12:13:13 +00:00
Ekansh Gupta
eb38dd548a
3rd party sem conv fix (#8980)
* feat: adding support for 1.26 semconv

* feat: adding support for 1.26 semconv

* feat: adding support for 1.26 semconv

* feat: adding support for 1.26 semconv

* feat: added native support for 1.26

* feat: added native support for 1.26

* feat: adding support for 1.26 semconv

* feat: adding support for 1.26 semconv

* feat: adding support for 1.26 semconv

* feat: resolved conflicts

* feat: resolved conflicts

* feat: resolved conflicts

* feat: resolved conflicts

* feat: resolved conflicts

* feat: fixed merge conflicts

* feat: fixed merge conflicts

* feat: added intermediate methods to fix response structure

* feat: fixed the errors on errors.newf
2025-09-23 10:55:59 +00:00
Abhi kumar
0ac5d97495
feat: Move 3rd party apis to QB V5 (#9042)
* feat: moved apis out and added proper types

* feat: intergrated new api in 3rd party monitoring

* feat: intergrated new API structure

* chore: fix for null pointer exception

* test: added test for formatDataForTable function

* chore: added placeholder prop in querysearch

* chore: added placeholder prop in querysearch

* feat: added hook for listoverview api
2025-09-23 16:15:05 +05:30
Abhi kumar
710f7740d3
fix: added fix for cursor jump in QB (#9140)
* fix: added fix for cursor jump in QB

* chore: minor cleanup

* feat: updating the query when the editor is getting out for focus or running the query

* test: added test for QuerySearch

* chore: updated variable name for QB interaction

* chore: updated PR review changes

* chore: removed non required comments
2025-09-23 13:06:52 +05:30
Amlan Kumar Nandy
a16ab114f5
chore: add evaluation cadence component for alerts v2 (#9131) 2025-09-22 20:12:59 +05:30
SagarRajput-7
84ae5b4ca9
fix: added dashboard route param, to allow trigger when new panel creation action happens (#9141) 2025-09-22 11:53:14 +05:30
Nityananda Gohain
a564fa9d28
fix: dont accept materialized key from payload (#9139)
* fix: dont accept materialized key from payload

* fix: use correct omit operator
2025-09-22 05:11:57 +00:00
aniketio-ctrl
7f4390f370
fix: Edit and patch rule functionality (#9125)
* fix: fixed edit and patch rule functionality

* fix: fixed edit and patch rule functionality

* fix: fixed edit and patch rule functionality

* fix: added patch rule test and rule mock store

* fix: removed schema version field

* fix: removed schema version field

* fix: added test cases for patch, create, edit

* fix: removed schema version field
2025-09-21 17:48:31 +05:30
Aditya Singh
c41ae00433
fix intermittent failing test (#9138)
* feat: context links processors

* feat: context variables hook added

* feat: add support for field variables

* feat: minor refactor

* feat: minor refactor

* feat: minor refactor

* feat: handle on save

* feat: minor refactor

* feat: snapshot update

* feat: revert qbv5

* feat: aggregation header val

* feat: fix header color

* feat: minor refactor

* feat: minor refactor

* feat: fix breaking changes from qb v5

* feat: change api for breakout opitons

* feat: minor refactor

* feat: minor refactor

* fix: added fix for extractquerypararms when value is string in multivalue operator

* feat: minor refactor

* feat: add back in breakout

* feat: minor refactor

* feat: add substitute var api call to decode vars

* feat: minor fix

* feat: optimize query value comparison in QueryBuilderV2

* feat: minor fix

* feat: minor fix

* feat: test fix

* feat: added dynamic variables creation flow (#7541)

* feat: added dynamic variables creation flow

* feat: added keys and value apis and hooks

* feat: added api and select component changes

* feat: added keys fetching and preview values

* feat: added dynamic variable to variable items

* feat: handled value persistence and tab switches

* feat: added default value and formed a schema for dyn-variables

* feat: added client and server side searches

* feat: corrected the initial load getfieldKey api

* feat: removed fetch on mount restriction

* feat: added dynamic variable to the dashboard details (#7755)

* feat: added dynamic variable to the dashboard details

* feat: added new component to existing variables

* feat: added enhancement to multiselect and select for dyn-variables

* feat: added refetch method between all dynamic-variables

* feat: correct error handling

* feat: correct error handling

* feat: enforced non-empty selectedvalues and default value

* feat: added client and server side searches

* feat: retry on error

* feat: correct error handling

* feat: handle defautl value in existing variables

* feat: lowercase the source for payload

* feat: fixed the incorrect assignment of active indices

* feat: improved handling of all option

* feat: improved the ALL option visuals

* feat: handled default value enforcement in existing variables

* feat: added unix time to values call

* feat: added incomplete data message and info to search

* feat: changed dashboard panel call handling with existing variables

* feat: adjusted the response type and data with the new API schema for values

* feat: code refactor

* feat: made dyn-variable option as the default

* feat: added test cases for dyn variable creation and completion

* feat: updated test cases

* feat: added variable in url and made dashboard sync around that and sharable (#7944)

* feat: added dynamic variable to the dashboard details

* feat: added new component to existing variables

* feat: added enhancement to multiselect and select for dyn-variables

* feat: added refetch method between all dynamic-variables

* feat: correct error handling

* feat: correct error handling

* feat: enforced non-empty selectedvalues and default value

* feat: added client and server side searches

* feat: retry on error

* feat: correct error handling

* feat: handle defautl value in existing variables

* feat: lowercase the source for payload

* feat: fixed the incorrect assignment of active indices

* feat: improved handling of all option

* feat: improved the ALL option visuals

* feat: handled default value enforcement in existing variables

* feat: added unix time to values call

* feat: added incomplete data message and info to search

* feat: changed dashboard panel call handling with existing variables

* feat: adjusted the response type and data with the new API schema for values

* feat: code refactor

* feat: made dyn-variable option as the default

* feat: added test cases for dyn variable creation and completion

* feat: updated test cases

* feat: added variable in url and made dashboard sync around that and sharable

* feat: added test cases

* feat: added safety check

* feat: enabled url setting on first load itself

* feat: code refactor

* feat: cleared options query param when on dashboard list page

* feat: resolved conflicts

* feat: added dynamic variable suggestion in where clause

* feat: added test cases for hooks and api call functions

* feat: added test case for querybuildersearchv2 suggestion changes

* feat: code refactor

* feat: updated test case

* feat: corrected the regex matcher for resolved titles

* feat: added ability to add/remove variable filter to one or more existing panels

* feat: added widgetselector on variable creation

* feat: show labels in widget selector

* feat: added apply to all and variable removal logical

* feat: refectch only related and affected panels in case of dynamic variables

* feat: added button loader for apply-all

* feat: light-mode styles

* feat: minor refactor

* feat: added test cases

* feat: refactor

* feat: remove consoles

* feat: pass panel types to substitutevars

* feat: cross filtering init

* fix: added fix for query builder filters

* feat: cross filtering add set/unset/create functionality

* feat: test update

* fix: added migration to filter expression for crud operations of variable

* feat: format legend name according to existing format

* feat: breakout test init

* feat: breakout test match query

* feat: context links tests

* feat: minor refactor

* feat: show edit only if user has access

* feat: added dynamic variables creation flow (#7541)

* feat: added dynamic variables creation flow

* feat: added keys and value apis and hooks

* feat: added api and select component changes

* feat: added keys fetching and preview values

* feat: added dynamic variable to variable items

* feat: handled value persistence and tab switches

* feat: added default value and formed a schema for dyn-variables

* feat: added client and server side searches

* feat: corrected the initial load getfieldKey api

* feat: removed fetch on mount restriction

* feat: added dynamic variable to the dashboard details (#7755)

* feat: added dynamic variable to the dashboard details

* feat: added new component to existing variables

* feat: added enhancement to multiselect and select for dyn-variables

* feat: added refetch method between all dynamic-variables

* feat: correct error handling

* feat: correct error handling

* feat: enforced non-empty selectedvalues and default value

* feat: added client and server side searches

* feat: retry on error

* feat: correct error handling

* feat: handle defautl value in existing variables

* feat: lowercase the source for payload

* feat: fixed the incorrect assignment of active indices

* feat: improved handling of all option

* feat: improved the ALL option visuals

* feat: handled default value enforcement in existing variables

* feat: added unix time to values call

* feat: added incomplete data message and info to search

* feat: changed dashboard panel call handling with existing variables

* feat: adjusted the response type and data with the new API schema for values

* feat: code refactor

* feat: made dyn-variable option as the default

* feat: added test cases for dyn variable creation and completion

* feat: updated test cases

* feat: added dynamic variable suggestion in where clause

* feat: added test cases for hooks and api call functions

* feat: added test case for querybuildersearchv2 suggestion changes

* feat: code refactor

* feat: updated test case

* feat: corrected the regex matcher for resolved titles

* feat: added ability to add/remove variable filter to one or more existing panels

* feat: added widgetselector on variable creation

* feat: show labels in widget selector

* feat: added apply to all and variable removal logical

* feat: refectch only related and affected panels in case of dynamic variables

* feat: added button loader for apply-all

* feat: light-mode styles

* fix: added migration to filter expression for crud operations of variable

* feat: reverted dynamic variable url config changes (#8877)

* Revert "feat: changed query param name"

This reverts commit 62bee5f003bf74b0da1c5951f1b5d0f2c250905d.

* Revert "feat: added user-friendly format to dashboard variable url"

This reverts commit 6de8b1c2e8c6a838941014ea4929e9f5c908d975.

* feat: reverted url var changes

* feat: reverted url changed from usedashboardvarupdate hook

* feat: send empty array for widgetId

* feat: added type in the variables in query_range payload for dynamic

* feat: minor fixes

* fix: added fix for multivalue operator without brackets

* feat: minor fix

* feat: fix failing test

* feat: change revert

* test: added tests for querycontextUtils + querybuilderv2 utils

* fix: added fix for replacing filter with the new value

* fix: added fix for replacing filters + datetimepicker composite query

* test: fixed querybuilderv2 utils test

* feat: handle number dataType in filters

* feat: correct the variable addition to panel format for new qb expression

* feat: remove other queries in breakout

* feat: add metric to traces mapping

* feat: pass proper time range

* feat: update time range logic

* feat: value panel drilldown init

* feat: value panel drilldown init

* feat: enable context links in value panel

* feat: minor fix

* feat: update snapshot

* feat: hide breakout in value panel

* feat: add panel type to view mode

* feat: add support to change panel in breakouts

* feat: panel change for breakout logic added

* chore: fix style

* chore: show variables suggestion while creating context links

* chore: add timestamp to graphs

* chore: add timestamp to table panel

* chore: fix failing tests

* chore: fix infinite re-rendering due to queryRange

* chore: send appropriate time range when signal is metrics

* chore: show variables suggestion while creating context links

* chore: minor refactor

* chore: show trace details link if filter has trace_id

* chore: fix infinite render of table component

* chore: added tests for v2

* fix: context links set from dropdown

* chore: minor refactor

* chore: minor refactor

* chore: fix test

* chore: fix timerange for apm metrics

* fix: get correct timestamp for clicked data

* chore: comment out change to histogram on breakout by number

* chore: change panel type on panel type change in url

* chore: remove consoles

* feat: added dynamic variables creation flow (#7541)

* feat: added dynamic variables creation flow

* feat: added keys and value apis and hooks

* feat: added api and select component changes

* feat: added keys fetching and preview values

* feat: added dynamic variable to variable items

* feat: handled value persistence and tab switches

* feat: added default value and formed a schema for dyn-variables

* feat: added client and server side searches

* feat: corrected the initial load getfieldKey api

* feat: removed fetch on mount restriction

* feat: added dynamic variable to the dashboard details (#7755)

* feat: added dynamic variable to the dashboard details

* feat: added new component to existing variables

* feat: added enhancement to multiselect and select for dyn-variables

* feat: added refetch method between all dynamic-variables

* feat: correct error handling

* feat: correct error handling

* feat: enforced non-empty selectedvalues and default value

* feat: added client and server side searches

* feat: retry on error

* feat: correct error handling

* feat: handle defautl value in existing variables

* feat: lowercase the source for payload

* feat: fixed the incorrect assignment of active indices

* feat: improved handling of all option

* feat: improved the ALL option visuals

* feat: handled default value enforcement in existing variables

* feat: added unix time to values call

* feat: added incomplete data message and info to search

* feat: changed dashboard panel call handling with existing variables

* feat: adjusted the response type and data with the new API schema for values

* feat: code refactor

* feat: made dyn-variable option as the default

* feat: added test cases for dyn variable creation and completion

* feat: updated test cases

* feat: fix lint and test cases

* feat: fix typo

* feat: fixed test case

* feat: added dynamic variable suggestion in where clause

* feat: added test cases for hooks and api call functions

* feat: added test case for querybuildersearchv2 suggestion changes

* feat: code refactor

* feat: corrected the regex matcher for resolved titles

* feat: fixed test cases

* feat: added ability to add/remove variable filter to one or more existing panels

* feat: added widgetselector on variable creation

* feat: show labels in widget selector

* feat: added apply to all and variable removal logical

* feat: refectch only related and affected panels in case of dynamic variables

* feat: added button loader for apply-all

* feat: light-mode styles

* fix: added migration to filter expression for crud operations of variable

* feat: added type in the variables in query_range payload for dynamic

* feat: correct the variable addition to panel format for new qb expression

* feat: added test cases for dynamic variable and add/remove panel feat

* feat: implemented where clause suggestion in new qb v5

* feat: added retries for dyn variable and fixed on-enter selection issue

* feat: added relatedValues and existing query in param related changes

* feat: sanitized data storage and removed duplicates

* fix: fixed typechecks

* feat: updated panel wait and refetch logic and ALL option selection

* feat: fixed variable tabel reordering issue

* feat: added empty name validation in variable creation

* feat: change value to searchtext in values API

* feat: added option for regex in the component, disabled for now

* feat: added beta and not rec. tag in variable tabs

* feat: added check to prevent api and updates calls with same payload

* feat: optimized localstorage for all selection in dynamic variable and updated __all__ case

* feat: resolved variable tables infinite loop update error

* feat: aded variable name auto-update based on attribute name entered for dynamic variables

* feat: modified only/all click behaviour and set all selection always true for dynamic variable

* feat: fix dropdown closing doesn't reset us back to our all available values when we have a search

* feat: handled all state distinction and carry forward in existing variables

* feat: trucate + n more tooltip content to 10

* feat: fixed infinite loop because of dependency of frequently changing object ref in var table

* feat: fixed inconsist search implementations

* feat: reverted only - all updated area implementation

* feat: added more space for search in multiselect component

* feat: checked for variable id instead of variable key for refetch

* feat: improved performance around multiselect component and added confirm modal for apply to all

* feat: rewrite functionality around add and remove panels

* feat: changed color for apply to all modal

* feat: added changes under flag to handle variable specific removal for removeKeysFromExpression func

* feat: added validation in variable edit panel

* chore: fix dynamic variable update in context menu to latest logic

* chore: minor fix

* chore: type fix

* fix: remove unwanted code

* fix: remove unwanted code

* fix: resolved pr comments

* fix: minor fix

* fix: fix tests

* fix: style fix

* fix: hide drilldown options in view mode for non-builder panels

* chore: add global uplot mock

* chore: query builder context update to all provider

* chore: add cursor rules init

* chore: useSafeNavigate mock added

* chore: more cleanups

* chore: remove react-router-v5 mock from setup

* chore: update cursorrules

* chore: add tests readme init

* chore: minor refactor

* fix: refetch quick filters on revisit to page

* fix: return expected response from queryFn and use as state

* fix: change getByRole to getByText for performant test

* chore: add sonner mock

* chore: mock revert

---------

Co-authored-by: Aditya Singh <adityasingh@Adityas-MacBook-Pro.local>
Co-authored-by: Abhi Kumar <ahrefabhi@gmail.com>
Co-authored-by: SagarRajput-7 <162284829+SagarRajput-7@users.noreply.github.com>
Co-authored-by: SagarRajput-7 <sagar@signoz.io>
2025-09-20 11:18:04 +05:30
Amlan Kumar Nandy
9aacf7f2f5
chore: add context and time utils for usage in alerts (#9114) 2025-09-19 06:18:53 +00:00
SagarRajput-7
792d0f3db6
fix: removed staleTime and cacheTime from query client level (#9124)
* fix: removed staleTime for dashboard API, to fetch fresh data while switching between dashboards

* fix: removed query client level staleTime and cacheTime

* fix: adding dashbaordID to the query key

* fix: removed unnecessary query key
2025-09-19 10:55:19 +05:30
Aditya Singh
47e8a89dbe
Fix: No quick filter found screen on navigating back from a diff screen (#9121)
* feat: minor refactor

* feat: change contextlinks data structure

* feat: context menu changes init

* feat: context menu hook refactor

* feat: context links processors

* feat: context variables hook added

* feat: add support for field variables

* feat: minor refactor

* feat: minor refactor

* feat: minor refactor

* feat: handle on save

* feat: minor refactor

* feat: snapshot update

* feat: revert qbv5

* feat: aggregation header val

* feat: fix header color

* feat: minor refactor

* feat: minor refactor

* feat: fix breaking changes from qb v5

* feat: change api for breakout opitons

* feat: minor refactor

* feat: minor refactor

* fix: added fix for extractquerypararms when value is string in multivalue operator

* feat: minor refactor

* feat: add back in breakout

* feat: minor refactor

* feat: add substitute var api call to decode vars

* feat: minor fix

* feat: optimize query value comparison in QueryBuilderV2

* feat: minor fix

* feat: minor fix

* feat: test fix

* feat: added dynamic variables creation flow (#7541)

* feat: added dynamic variables creation flow

* feat: added keys and value apis and hooks

* feat: added api and select component changes

* feat: added keys fetching and preview values

* feat: added dynamic variable to variable items

* feat: handled value persistence and tab switches

* feat: added default value and formed a schema for dyn-variables

* feat: added client and server side searches

* feat: corrected the initial load getfieldKey api

* feat: removed fetch on mount restriction

* feat: added dynamic variable to the dashboard details (#7755)

* feat: added dynamic variable to the dashboard details

* feat: added new component to existing variables

* feat: added enhancement to multiselect and select for dyn-variables

* feat: added refetch method between all dynamic-variables

* feat: correct error handling

* feat: correct error handling

* feat: enforced non-empty selectedvalues and default value

* feat: added client and server side searches

* feat: retry on error

* feat: correct error handling

* feat: handle defautl value in existing variables

* feat: lowercase the source for payload

* feat: fixed the incorrect assignment of active indices

* feat: improved handling of all option

* feat: improved the ALL option visuals

* feat: handled default value enforcement in existing variables

* feat: added unix time to values call

* feat: added incomplete data message and info to search

* feat: changed dashboard panel call handling with existing variables

* feat: adjusted the response type and data with the new API schema for values

* feat: code refactor

* feat: made dyn-variable option as the default

* feat: added test cases for dyn variable creation and completion

* feat: updated test cases

* feat: added variable in url and made dashboard sync around that and sharable (#7944)

* feat: added dynamic variable to the dashboard details

* feat: added new component to existing variables

* feat: added enhancement to multiselect and select for dyn-variables

* feat: added refetch method between all dynamic-variables

* feat: correct error handling

* feat: correct error handling

* feat: enforced non-empty selectedvalues and default value

* feat: added client and server side searches

* feat: retry on error

* feat: correct error handling

* feat: handle defautl value in existing variables

* feat: lowercase the source for payload

* feat: fixed the incorrect assignment of active indices

* feat: improved handling of all option

* feat: improved the ALL option visuals

* feat: handled default value enforcement in existing variables

* feat: added unix time to values call

* feat: added incomplete data message and info to search

* feat: changed dashboard panel call handling with existing variables

* feat: adjusted the response type and data with the new API schema for values

* feat: code refactor

* feat: made dyn-variable option as the default

* feat: added test cases for dyn variable creation and completion

* feat: updated test cases

* feat: added variable in url and made dashboard sync around that and sharable

* feat: added test cases

* feat: added safety check

* feat: enabled url setting on first load itself

* feat: code refactor

* feat: cleared options query param when on dashboard list page

* feat: resolved conflicts

* feat: added dynamic variable suggestion in where clause

* feat: added test cases for hooks and api call functions

* feat: added test case for querybuildersearchv2 suggestion changes

* feat: code refactor

* feat: updated test case

* feat: corrected the regex matcher for resolved titles

* feat: added ability to add/remove variable filter to one or more existing panels

* feat: added widgetselector on variable creation

* feat: show labels in widget selector

* feat: added apply to all and variable removal logical

* feat: refectch only related and affected panels in case of dynamic variables

* feat: added button loader for apply-all

* feat: light-mode styles

* feat: minor refactor

* feat: added test cases

* feat: refactor

* feat: remove consoles

* feat: pass panel types to substitutevars

* feat: cross filtering init

* fix: added fix for query builder filters

* feat: cross filtering add set/unset/create functionality

* feat: test update

* fix: added migration to filter expression for crud operations of variable

* feat: format legend name according to existing format

* feat: breakout test init

* feat: breakout test match query

* feat: context links tests

* feat: minor refactor

* feat: show edit only if user has access

* feat: added dynamic variables creation flow (#7541)

* feat: added dynamic variables creation flow

* feat: added keys and value apis and hooks

* feat: added api and select component changes

* feat: added keys fetching and preview values

* feat: added dynamic variable to variable items

* feat: handled value persistence and tab switches

* feat: added default value and formed a schema for dyn-variables

* feat: added client and server side searches

* feat: corrected the initial load getfieldKey api

* feat: removed fetch on mount restriction

* feat: added dynamic variable to the dashboard details (#7755)

* feat: added dynamic variable to the dashboard details

* feat: added new component to existing variables

* feat: added enhancement to multiselect and select for dyn-variables

* feat: added refetch method between all dynamic-variables

* feat: correct error handling

* feat: correct error handling

* feat: enforced non-empty selectedvalues and default value

* feat: added client and server side searches

* feat: retry on error

* feat: correct error handling

* feat: handle defautl value in existing variables

* feat: lowercase the source for payload

* feat: fixed the incorrect assignment of active indices

* feat: improved handling of all option

* feat: improved the ALL option visuals

* feat: handled default value enforcement in existing variables

* feat: added unix time to values call

* feat: added incomplete data message and info to search

* feat: changed dashboard panel call handling with existing variables

* feat: adjusted the response type and data with the new API schema for values

* feat: code refactor

* feat: made dyn-variable option as the default

* feat: added test cases for dyn variable creation and completion

* feat: updated test cases

* feat: added dynamic variable suggestion in where clause

* feat: added test cases for hooks and api call functions

* feat: added test case for querybuildersearchv2 suggestion changes

* feat: code refactor

* feat: updated test case

* feat: corrected the regex matcher for resolved titles

* feat: added ability to add/remove variable filter to one or more existing panels

* feat: added widgetselector on variable creation

* feat: show labels in widget selector

* feat: added apply to all and variable removal logical

* feat: refectch only related and affected panels in case of dynamic variables

* feat: added button loader for apply-all

* feat: light-mode styles

* fix: added migration to filter expression for crud operations of variable

* feat: reverted dynamic variable url config changes (#8877)

* Revert "feat: changed query param name"

This reverts commit 62bee5f003bf74b0da1c5951f1b5d0f2c250905d.

* Revert "feat: added user-friendly format to dashboard variable url"

This reverts commit 6de8b1c2e8c6a838941014ea4929e9f5c908d975.

* feat: reverted url var changes

* feat: reverted url changed from usedashboardvarupdate hook

* feat: send empty array for widgetId

* feat: added type in the variables in query_range payload for dynamic

* feat: minor fixes

* fix: added fix for multivalue operator without brackets

* feat: minor fix

* feat: fix failing test

* feat: change revert

* test: added tests for querycontextUtils + querybuilderv2 utils

* fix: added fix for replacing filter with the new value

* fix: added fix for replacing filters + datetimepicker composite query

* test: fixed querybuilderv2 utils test

* feat: handle number dataType in filters

* feat: correct the variable addition to panel format for new qb expression

* feat: remove other queries in breakout

* feat: add metric to traces mapping

* feat: pass proper time range

* feat: update time range logic

* feat: value panel drilldown init

* feat: value panel drilldown init

* feat: enable context links in value panel

* feat: minor fix

* feat: update snapshot

* feat: hide breakout in value panel

* feat: add panel type to view mode

* feat: add support to change panel in breakouts

* feat: panel change for breakout logic added

* chore: fix style

* chore: show variables suggestion while creating context links

* chore: add timestamp to graphs

* chore: add timestamp to table panel

* chore: fix failing tests

* chore: fix infinite re-rendering due to queryRange

* chore: send appropriate time range when signal is metrics

* chore: show variables suggestion while creating context links

* chore: minor refactor

* chore: show trace details link if filter has trace_id

* chore: fix infinite render of table component

* chore: added tests for v2

* fix: context links set from dropdown

* chore: minor refactor

* chore: minor refactor

* chore: fix test

* chore: fix timerange for apm metrics

* fix: get correct timestamp for clicked data

* chore: comment out change to histogram on breakout by number

* chore: change panel type on panel type change in url

* chore: remove consoles

* feat: added dynamic variables creation flow (#7541)

* feat: added dynamic variables creation flow

* feat: added keys and value apis and hooks

* feat: added api and select component changes

* feat: added keys fetching and preview values

* feat: added dynamic variable to variable items

* feat: handled value persistence and tab switches

* feat: added default value and formed a schema for dyn-variables

* feat: added client and server side searches

* feat: corrected the initial load getfieldKey api

* feat: removed fetch on mount restriction

* feat: added dynamic variable to the dashboard details (#7755)

* feat: added dynamic variable to the dashboard details

* feat: added new component to existing variables

* feat: added enhancement to multiselect and select for dyn-variables

* feat: added refetch method between all dynamic-variables

* feat: correct error handling

* feat: correct error handling

* feat: enforced non-empty selectedvalues and default value

* feat: added client and server side searches

* feat: retry on error

* feat: correct error handling

* feat: handle defautl value in existing variables

* feat: lowercase the source for payload

* feat: fixed the incorrect assignment of active indices

* feat: improved handling of all option

* feat: improved the ALL option visuals

* feat: handled default value enforcement in existing variables

* feat: added unix time to values call

* feat: added incomplete data message and info to search

* feat: changed dashboard panel call handling with existing variables

* feat: adjusted the response type and data with the new API schema for values

* feat: code refactor

* feat: made dyn-variable option as the default

* feat: added test cases for dyn variable creation and completion

* feat: updated test cases

* feat: fix lint and test cases

* feat: fix typo

* feat: fixed test case

* feat: added dynamic variable suggestion in where clause

* feat: added test cases for hooks and api call functions

* feat: added test case for querybuildersearchv2 suggestion changes

* feat: code refactor

* feat: corrected the regex matcher for resolved titles

* feat: fixed test cases

* feat: added ability to add/remove variable filter to one or more existing panels

* feat: added widgetselector on variable creation

* feat: show labels in widget selector

* feat: added apply to all and variable removal logical

* feat: refectch only related and affected panels in case of dynamic variables

* feat: added button loader for apply-all

* feat: light-mode styles

* fix: added migration to filter expression for crud operations of variable

* feat: added type in the variables in query_range payload for dynamic

* feat: correct the variable addition to panel format for new qb expression

* feat: added test cases for dynamic variable and add/remove panel feat

* feat: implemented where clause suggestion in new qb v5

* feat: added retries for dyn variable and fixed on-enter selection issue

* feat: added relatedValues and existing query in param related changes

* feat: sanitized data storage and removed duplicates

* fix: fixed typechecks

* feat: updated panel wait and refetch logic and ALL option selection

* feat: fixed variable tabel reordering issue

* feat: added empty name validation in variable creation

* feat: change value to searchtext in values API

* feat: added option for regex in the component, disabled for now

* feat: added beta and not rec. tag in variable tabs

* feat: added check to prevent api and updates calls with same payload

* feat: optimized localstorage for all selection in dynamic variable and updated __all__ case

* feat: resolved variable tables infinite loop update error

* feat: aded variable name auto-update based on attribute name entered for dynamic variables

* feat: modified only/all click behaviour and set all selection always true for dynamic variable

* feat: fix dropdown closing doesn't reset us back to our all available values when we have a search

* feat: handled all state distinction and carry forward in existing variables

* feat: trucate + n more tooltip content to 10

* feat: fixed infinite loop because of dependency of frequently changing object ref in var table

* feat: fixed inconsist search implementations

* feat: reverted only - all updated area implementation

* feat: added more space for search in multiselect component

* feat: checked for variable id instead of variable key for refetch

* feat: improved performance around multiselect component and added confirm modal for apply to all

* feat: rewrite functionality around add and remove panels

* feat: changed color for apply to all modal

* feat: added changes under flag to handle variable specific removal for removeKeysFromExpression func

* feat: added validation in variable edit panel

* chore: fix dynamic variable update in context menu to latest logic

* chore: minor fix

* chore: type fix

* fix: remove unwanted code

* fix: remove unwanted code

* fix: resolved pr comments

* fix: minor fix

* fix: fix tests

* fix: style fix

* fix: hide drilldown options in view mode for non-builder panels

* chore: add global uplot mock

* chore: query builder context update to all provider

* chore: add cursor rules init

* chore: useSafeNavigate mock added

* chore: more cleanups

* chore: remove react-router-v5 mock from setup

* chore: update cursorrules

* chore: add tests readme init

* chore: minor refactor

* fix: refetch quick filters on revisit to page

* fix: return expected response from queryFn and use as state

---------

Co-authored-by: Aditya Singh <adityasingh@Adityas-MacBook-Pro.local>
Co-authored-by: Abhi Kumar <ahrefabhi@gmail.com>
Co-authored-by: SagarRajput-7 <162284829+SagarRajput-7@users.noreply.github.com>
Co-authored-by: SagarRajput-7 <sagar@signoz.io>
2025-09-18 12:51:54 +05:30
Aditya Singh
bced4774bb
feat: frontend unit test suite setup (#9027)
* feat: update context link modal form init

* feat: add double way sync on urls and param

* feat: minor refactor

* feat: minor refactor

* feat: change contextlinks data structure

* feat: context menu changes init

* feat: context menu hook refactor

* feat: context links processors

* feat: context variables hook added

* feat: add support for field variables

* feat: minor refactor

* feat: minor refactor

* feat: minor refactor

* feat: handle on save

* feat: minor refactor

* feat: snapshot update

* feat: revert qbv5

* feat: aggregation header val

* feat: fix header color

* feat: minor refactor

* feat: minor refactor

* feat: fix breaking changes from qb v5

* feat: change api for breakout opitons

* feat: minor refactor

* feat: minor refactor

* fix: added fix for extractquerypararms when value is string in multivalue operator

* feat: minor refactor

* feat: add back in breakout

* feat: minor refactor

* feat: add substitute var api call to decode vars

* feat: minor fix

* feat: optimize query value comparison in QueryBuilderV2

* feat: minor fix

* feat: minor fix

* feat: test fix

* feat: added dynamic variables creation flow (#7541)

* feat: added dynamic variables creation flow

* feat: added keys and value apis and hooks

* feat: added api and select component changes

* feat: added keys fetching and preview values

* feat: added dynamic variable to variable items

* feat: handled value persistence and tab switches

* feat: added default value and formed a schema for dyn-variables

* feat: added client and server side searches

* feat: corrected the initial load getfieldKey api

* feat: removed fetch on mount restriction

* feat: added dynamic variable to the dashboard details (#7755)

* feat: added dynamic variable to the dashboard details

* feat: added new component to existing variables

* feat: added enhancement to multiselect and select for dyn-variables

* feat: added refetch method between all dynamic-variables

* feat: correct error handling

* feat: correct error handling

* feat: enforced non-empty selectedvalues and default value

* feat: added client and server side searches

* feat: retry on error

* feat: correct error handling

* feat: handle defautl value in existing variables

* feat: lowercase the source for payload

* feat: fixed the incorrect assignment of active indices

* feat: improved handling of all option

* feat: improved the ALL option visuals

* feat: handled default value enforcement in existing variables

* feat: added unix time to values call

* feat: added incomplete data message and info to search

* feat: changed dashboard panel call handling with existing variables

* feat: adjusted the response type and data with the new API schema for values

* feat: code refactor

* feat: made dyn-variable option as the default

* feat: added test cases for dyn variable creation and completion

* feat: updated test cases

* feat: added variable in url and made dashboard sync around that and sharable (#7944)

* feat: added dynamic variable to the dashboard details

* feat: added new component to existing variables

* feat: added enhancement to multiselect and select for dyn-variables

* feat: added refetch method between all dynamic-variables

* feat: correct error handling

* feat: correct error handling

* feat: enforced non-empty selectedvalues and default value

* feat: added client and server side searches

* feat: retry on error

* feat: correct error handling

* feat: handle defautl value in existing variables

* feat: lowercase the source for payload

* feat: fixed the incorrect assignment of active indices

* feat: improved handling of all option

* feat: improved the ALL option visuals

* feat: handled default value enforcement in existing variables

* feat: added unix time to values call

* feat: added incomplete data message and info to search

* feat: changed dashboard panel call handling with existing variables

* feat: adjusted the response type and data with the new API schema for values

* feat: code refactor

* feat: made dyn-variable option as the default

* feat: added test cases for dyn variable creation and completion

* feat: updated test cases

* feat: added variable in url and made dashboard sync around that and sharable

* feat: added test cases

* feat: added safety check

* feat: enabled url setting on first load itself

* feat: code refactor

* feat: cleared options query param when on dashboard list page

* feat: resolved conflicts

* feat: added dynamic variable suggestion in where clause

* feat: added test cases for hooks and api call functions

* feat: added test case for querybuildersearchv2 suggestion changes

* feat: code refactor

* feat: updated test case

* feat: corrected the regex matcher for resolved titles

* feat: added ability to add/remove variable filter to one or more existing panels

* feat: added widgetselector on variable creation

* feat: show labels in widget selector

* feat: added apply to all and variable removal logical

* feat: refectch only related and affected panels in case of dynamic variables

* feat: added button loader for apply-all

* feat: light-mode styles

* feat: minor refactor

* feat: added test cases

* feat: refactor

* feat: remove consoles

* feat: pass panel types to substitutevars

* feat: cross filtering init

* fix: added fix for query builder filters

* feat: cross filtering add set/unset/create functionality

* feat: test update

* fix: added migration to filter expression for crud operations of variable

* feat: format legend name according to existing format

* feat: breakout test init

* feat: breakout test match query

* feat: context links tests

* feat: minor refactor

* feat: show edit only if user has access

* feat: added dynamic variables creation flow (#7541)

* feat: added dynamic variables creation flow

* feat: added keys and value apis and hooks

* feat: added api and select component changes

* feat: added keys fetching and preview values

* feat: added dynamic variable to variable items

* feat: handled value persistence and tab switches

* feat: added default value and formed a schema for dyn-variables

* feat: added client and server side searches

* feat: corrected the initial load getfieldKey api

* feat: removed fetch on mount restriction

* feat: added dynamic variable to the dashboard details (#7755)

* feat: added dynamic variable to the dashboard details

* feat: added new component to existing variables

* feat: added enhancement to multiselect and select for dyn-variables

* feat: added refetch method between all dynamic-variables

* feat: correct error handling

* feat: correct error handling

* feat: enforced non-empty selectedvalues and default value

* feat: added client and server side searches

* feat: retry on error

* feat: correct error handling

* feat: handle defautl value in existing variables

* feat: lowercase the source for payload

* feat: fixed the incorrect assignment of active indices

* feat: improved handling of all option

* feat: improved the ALL option visuals

* feat: handled default value enforcement in existing variables

* feat: added unix time to values call

* feat: added incomplete data message and info to search

* feat: changed dashboard panel call handling with existing variables

* feat: adjusted the response type and data with the new API schema for values

* feat: code refactor

* feat: made dyn-variable option as the default

* feat: added test cases for dyn variable creation and completion

* feat: updated test cases

* feat: added dynamic variable suggestion in where clause

* feat: added test cases for hooks and api call functions

* feat: added test case for querybuildersearchv2 suggestion changes

* feat: code refactor

* feat: updated test case

* feat: corrected the regex matcher for resolved titles

* feat: added ability to add/remove variable filter to one or more existing panels

* feat: added widgetselector on variable creation

* feat: show labels in widget selector

* feat: added apply to all and variable removal logical

* feat: refectch only related and affected panels in case of dynamic variables

* feat: added button loader for apply-all

* feat: light-mode styles

* fix: added migration to filter expression for crud operations of variable

* feat: reverted dynamic variable url config changes (#8877)

* Revert "feat: changed query param name"

This reverts commit 62bee5f003bf74b0da1c5951f1b5d0f2c250905d.

* Revert "feat: added user-friendly format to dashboard variable url"

This reverts commit 6de8b1c2e8c6a838941014ea4929e9f5c908d975.

* feat: reverted url var changes

* feat: reverted url changed from usedashboardvarupdate hook

* feat: send empty array for widgetId

* feat: added type in the variables in query_range payload for dynamic

* feat: minor fixes

* fix: added fix for multivalue operator without brackets

* feat: minor fix

* feat: fix failing test

* feat: change revert

* test: added tests for querycontextUtils + querybuilderv2 utils

* fix: added fix for replacing filter with the new value

* fix: added fix for replacing filters + datetimepicker composite query

* test: fixed querybuilderv2 utils test

* feat: handle number dataType in filters

* feat: correct the variable addition to panel format for new qb expression

* feat: remove other queries in breakout

* feat: add metric to traces mapping

* feat: pass proper time range

* feat: update time range logic

* feat: value panel drilldown init

* feat: value panel drilldown init

* feat: enable context links in value panel

* feat: minor fix

* feat: update snapshot

* feat: hide breakout in value panel

* feat: add panel type to view mode

* feat: add support to change panel in breakouts

* feat: panel change for breakout logic added

* chore: fix style

* chore: show variables suggestion while creating context links

* chore: add timestamp to graphs

* chore: add timestamp to table panel

* chore: fix failing tests

* chore: fix infinite re-rendering due to queryRange

* chore: send appropriate time range when signal is metrics

* chore: show variables suggestion while creating context links

* chore: minor refactor

* chore: show trace details link if filter has trace_id

* chore: fix infinite render of table component

* chore: added tests for v2

* fix: context links set from dropdown

* chore: minor refactor

* chore: minor refactor

* chore: fix test

* chore: fix timerange for apm metrics

* fix: get correct timestamp for clicked data

* chore: comment out change to histogram on breakout by number

* chore: change panel type on panel type change in url

* chore: remove consoles

* feat: added dynamic variables creation flow (#7541)

* feat: added dynamic variables creation flow

* feat: added keys and value apis and hooks

* feat: added api and select component changes

* feat: added keys fetching and preview values

* feat: added dynamic variable to variable items

* feat: handled value persistence and tab switches

* feat: added default value and formed a schema for dyn-variables

* feat: added client and server side searches

* feat: corrected the initial load getfieldKey api

* feat: removed fetch on mount restriction

* feat: added dynamic variable to the dashboard details (#7755)

* feat: added dynamic variable to the dashboard details

* feat: added new component to existing variables

* feat: added enhancement to multiselect and select for dyn-variables

* feat: added refetch method between all dynamic-variables

* feat: correct error handling

* feat: correct error handling

* feat: enforced non-empty selectedvalues and default value

* feat: added client and server side searches

* feat: retry on error

* feat: correct error handling

* feat: handle defautl value in existing variables

* feat: lowercase the source for payload

* feat: fixed the incorrect assignment of active indices

* feat: improved handling of all option

* feat: improved the ALL option visuals

* feat: handled default value enforcement in existing variables

* feat: added unix time to values call

* feat: added incomplete data message and info to search

* feat: changed dashboard panel call handling with existing variables

* feat: adjusted the response type and data with the new API schema for values

* feat: code refactor

* feat: made dyn-variable option as the default

* feat: added test cases for dyn variable creation and completion

* feat: updated test cases

* feat: fix lint and test cases

* feat: fix typo

* feat: fixed test case

* feat: added dynamic variable suggestion in where clause

* feat: added test cases for hooks and api call functions

* feat: added test case for querybuildersearchv2 suggestion changes

* feat: code refactor

* feat: corrected the regex matcher for resolved titles

* feat: fixed test cases

* feat: added ability to add/remove variable filter to one or more existing panels

* feat: added widgetselector on variable creation

* feat: show labels in widget selector

* feat: added apply to all and variable removal logical

* feat: refectch only related and affected panels in case of dynamic variables

* feat: added button loader for apply-all

* feat: light-mode styles

* fix: added migration to filter expression for crud operations of variable

* feat: added type in the variables in query_range payload for dynamic

* feat: correct the variable addition to panel format for new qb expression

* feat: added test cases for dynamic variable and add/remove panel feat

* feat: implemented where clause suggestion in new qb v5

* feat: added retries for dyn variable and fixed on-enter selection issue

* feat: added relatedValues and existing query in param related changes

* feat: sanitized data storage and removed duplicates

* fix: fixed typechecks

* feat: updated panel wait and refetch logic and ALL option selection

* feat: fixed variable tabel reordering issue

* feat: added empty name validation in variable creation

* feat: change value to searchtext in values API

* feat: added option for regex in the component, disabled for now

* feat: added beta and not rec. tag in variable tabs

* feat: added check to prevent api and updates calls with same payload

* feat: optimized localstorage for all selection in dynamic variable and updated __all__ case

* feat: resolved variable tables infinite loop update error

* feat: aded variable name auto-update based on attribute name entered for dynamic variables

* feat: modified only/all click behaviour and set all selection always true for dynamic variable

* feat: fix dropdown closing doesn't reset us back to our all available values when we have a search

* feat: handled all state distinction and carry forward in existing variables

* feat: trucate + n more tooltip content to 10

* feat: fixed infinite loop because of dependency of frequently changing object ref in var table

* feat: fixed inconsist search implementations

* feat: reverted only - all updated area implementation

* feat: added more space for search in multiselect component

* feat: checked for variable id instead of variable key for refetch

* feat: improved performance around multiselect component and added confirm modal for apply to all

* feat: rewrite functionality around add and remove panels

* feat: changed color for apply to all modal

* feat: added changes under flag to handle variable specific removal for removeKeysFromExpression func

* feat: added validation in variable edit panel

* chore: fix dynamic variable update in context menu to latest logic

* chore: minor fix

* chore: type fix

* fix: remove unwanted code

* fix: remove unwanted code

* fix: resolved pr comments

* fix: minor fix

* fix: fix tests

* fix: style fix

* fix: hide drilldown options in view mode for non-builder panels

* chore: add global uplot mock

* chore: query builder context update to all provider

* chore: add cursor rules init

* chore: useSafeNavigate mock added

* chore: more cleanups

* chore: remove react-router-v5 mock from setup

* chore: update cursorrules

* chore: add tests readme init

* chore: minor refactor

---------

Co-authored-by: Aditya Singh <adityasingh@Adityas-MacBook-Pro.local>
Co-authored-by: Abhi Kumar <ahrefabhi@gmail.com>
Co-authored-by: SagarRajput-7 <162284829+SagarRajput-7@users.noreply.github.com>
Co-authored-by: SagarRajput-7 <sagar@signoz.io>
2025-09-18 12:19:57 +05:30
Vikrant Gupta
0c25de9560
feat(authz): build authz service (#9064)
* feat(authz): define the domain layer

* feat(authz): added openfga schema and split the enterprise code

* feat(authz): revert http handler

* feat(authz): address comments

* feat(authz): address comments

* feat(authz): typo comments

* feat(authz): address review comments

* feat(authz): address review comments

* feat(authz): update the oss model

* feat(authz): update the sequential check
2025-09-17 21:35:11 +05:30
Shaheer Kochai
24307b48ff
Fix: trace details bugfixes (#9116)
* fix: make the trace details sidebar scrollable

* fix: fix the long value overflowing trace details attributes

* fix: fix the layout issues in trace details v2

* Revert "fix: make the trace details sidebar scrollable"

This reverts commit 469022ed6aa89f9cc5864fdd30bdd6096bb11870.

* fix: make the trace details sidebar scrollable

* fix: make the attribute value take 100% width

---------

Co-authored-by: Nityananda Gohain <nityanandagohain@gmail.com>
2025-09-17 19:28:34 +05:30
Piyush Singariya
0626a89412
Revert "fix: upgrading clickhouse-go (#8969)" (#9113)
This reverts commit 5cd775f2b286a941bd3d0b9c8349c9d9cf9aadf1.
2025-09-17 16:31:02 +05:30
Piyush Singariya
5cd775f2b2
fix: upgrading clickhouse-go (#8969)
* test: upgrading clickhouse-go

* fix: go mod tidy

* fix: upgrade semconv

---------

Co-authored-by: Nityananda Gohain <nityanandagohain@gmail.com>
Co-authored-by: Vikrant Gupta <vikrant@signoz.io>
2025-09-17 14:11:18 +05:30
primus-bot[bot]
c9568be5d8
chore(release): bump to v0.95.0 (#9112)
Co-authored-by: primus-bot[bot] <171087277+primus-bot[bot]@users.noreply.github.com>
2025-09-17 12:55:46 +05:30
Srikanth Chekuri
1c257f3e14
chore: populate default zero queries for metrics (#9103) 2025-09-17 07:05:38 +00:00
Amlan Kumar Nandy
ff8ac96d37
chore: fix edit alerts page crashing (#9025) 2025-09-17 06:14:25 +00:00
Tushar Vats
e8035b7dd2
Added Download Button to leverage exportRawData API (#9050)
This pull request introduces a new, customizable logs export feature in the Logs Explorer view, replacing the previous hardcoded download functionality. Users can now select export format, row limit, and which columns to include via a dedicated options menu. The implementation includes a new API integration for downloading export data, UI components for export options, and associated styling.
2025-09-17 03:37:44 +00:00
Srikanth Chekuri
cc77b829af
chore: recognize dashboard view page for log_comment (#9084) 2025-09-16 19:43:54 +00:00
Nityananda Gohain
49306cbe3d
fix: add trace perf improvement only when there is any filter (#9099) 2025-09-16 17:08:58 +00:00
Srikanth Chekuri
233a8e4cc3
chore: use wss usage for workloads listing (#9104) 2025-09-16 16:42:15 +00:00
Srikanth Chekuri
629378bbec
chore: do not fail on non-existent signoz_ dbs (#9092) 2025-09-16 16:15:11 +00:00
Shaheer Kochai
d96073f478
feat: highlight the searched spans and dim other spans in trace details v2 (#9032) 2025-09-16 14:29:48 +00:00
Tushar Vats
ba8a49929a
Converted format options menu to popover (#9094)
This pull request refactors the LogsFormatOptionsMenu component to use the Ant Design Popover for displaying format options, replacing the previous custom dropdown implementation. It also updates the related styles and removes now-unnecessary state and logic from parent components. The changes improve code maintainability, UI consistency, and simplify event handling.
2025-09-16 13:12:15 +00:00
Shaheer Kochai
a90904951e
feat: make the trace details v2 sidebar resizable (#9034)
* feat: make the trace details v2 sidebar resizable

* chore: fix the failing test

* chore: improve the UI while resizing the sidebar
2025-09-16 17:20:32 +04:30
Shaheer Kochai
6c57735a81
feat: add support for span logs (#8857) 2025-09-16 11:22:15 +00:00
Shaheer Kochai
4851527840
fix: fix the incorrect matching spans count (#9033) 2025-09-16 08:56:47 +00:00
Niladri Adhikary
c5051128fa
feat: warn when LIKE/ILIKE is used without any %/_ (#9098)
* feat: warn when LIKE/ILIKE is used without any %/_

Signed-off-by: “niladrix719” <niladrix719@gmail.com>
2025-09-16 06:23:26 +00:00
Yunus M
2acdd101d8
feat: clean up tooltip elements and add dependencies (#8815) 2025-09-16 11:08:51 +05:30
Amlan Kumar Nandy
39c2738ef9
feat: add alert condition component (#9008) 2025-09-15 21:22:07 +05:30
manika-signoz
d075ceecba
chore: copy changes and minor fixes, onboarding hint (#9095) 2025-09-15 18:54:37 +05:30
aniketio-ctrl
ac81eab7bb
chore: added cumulative window support (#8828)
* feat(multi-threshold): added multi threshold

* Update pkg/types/ruletypes/api_params.go

Co-authored-by: ellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com>

* feat(multiple-threshold): added multiple thresholds

* Update pkg/types/ruletypes/alerting.go

Co-authored-by: ellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com>

* feat(multiple-threshold): added multiple thresholds

* feat(cumulative-window): added cumulative window

* feat(multi-threshold): added recovery min points

* Update pkg/query-service/rules/threshold_rule.go

Co-authored-by: ellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com>

* feat(multi-threshold): fixed log lines

* feat(multi-threshold): added severity as threshold name

* feat(cumulative-window): added cumulative window for alerts v2

* feat(multi-threshold): removed break to send multi threshold alerts

* feat(multi-threshold): removed break to send multi threshold alerts

* feat(cumulative-window): segregated json marshalling with evaluation logic

* feat(multi-threshold): corrected the test cases

* feat(cumulative-window): segregated json marshalling and evaluation logic

* feat(cumulative-window): segregated json marshalling and evaluation logic

* feat(multi-threshold): added segregation on json marshalling and actual threhsold logic

* feat(multi-threshold): added segregation on json marshalling and actual threhsold logic

* feat(cumulative-window): segregated json marshalling and evaluation logic

* feat(multi-threshold): added segregation on json marshalling and actual threhsold logic

* feat(cumulative-window): segregated json marshalling and evaluation logic

* feat(multi-threhsold): added error wrapper

* feat(multi-threhsold): added error wrapper

* feat(cumulative-window): segregated json marshalling and evaluation logic

* feat(multi-threhsold): added error wrapper

* Update pkg/types/ruletypes/threshold.go

Co-authored-by: ellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com>

* feat(cumulative-window): segregated json marshalling and evaluation logic

* feat(multi-threshold): added validation and error propagation

* feat(multi-notification): removed pre defined labels from links of log and traces

* feat(multi-notification): removed pre defined labels from links of log and traces

* feat(multi-threshold): added json parser for gettable rule

* feat(multi-threshold): added json parser for gettable rule

* feat(multi-threshold): added json parser for gettable rule

* feat(multi-threshold): added umnarshaller for postable rule

* feat(multi-threshold): added umnarshaller for postable rule

* feat(cumulative-window): added validation check

* Update pkg/types/ruletypes/evaluation.go

Co-authored-by: ellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com>

* feat(multi-threhsold): removed yaml support for alerts

* Update pkg/types/ruletypes/evaluation.go

Co-authored-by: Srikanth Chekuri <srikanth.chekuri92@gmail.com>

* Update pkg/types/ruletypes/evaluation.go

Co-authored-by: Srikanth Chekuri <srikanth.chekuri92@gmail.com>

* chore(cumulative-window): renamed funcitons

* chore(cumulative-window): removed naked errors

* chore(cumulative-window): added reset boundary condition tests

* chore(cumulative-window): added reset boundary condition tests

* chore(cumulative-window): sorted imports

* chore(cumulative-window): sorted imports

* chore(cumulative-window): sorted imports

* chore(cumulative-window): removed error from next window for

* chore(cumulative-window): removed error from next window for

* chore(cumulative-window): added case for timezone

* chore(cumulative-window): added validation for eval window

* chore(cumulative-window): updated api structure for cumulative window

* chore(cumulative-window): updated schedule enum

---------

Co-authored-by: ellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com>
Co-authored-by: Srikanth Chekuri <srikanth.chekuri92@gmail.com>
2025-09-15 15:00:12 +05:30
Srikanth Chekuri
c982b1e76d
chore: allow number segment, #, @, {} in key (#9082) 2025-09-14 22:14:42 +05:30
Srikanth Chekuri
252786deb6
chore: make qb v5 default (#9085) 2025-09-14 20:41:13 +05:30
Nityananda Gohain
38ca467d13
fix: trace perf - scan only required traces (#9072) 2025-09-14 13:12:48 +00:00
Nityananda Gohain
a686941880
fix: exception on resource filters with numeric values (#9028) 2025-09-14 13:00:16 +00:00
Nityananda Gohain
ae58915020
chore: support for json column in resources (#8376) 2025-09-14 18:18:39 +05:30
Vibhu Pandey
e9222ab3e0
docs(integration): add docs for writing integration tests (#9070) 2025-09-12 12:16:04 +00:00
aniketio-ctrl
d801fcee76
chore: add multiple thresholds support (#8816) 2025-09-12 13:11:54 +05:30
Vibhu Pandey
61acd946cc
fix: enable dot metrics by default (#9061) 2025-09-11 17:59:55 +00:00
Abhi kumar
c477ec65da
feat: added support for hasToken function in QB (#9058)
* feat: updated grammer to add hasToken function

* feat: added function constant
2025-09-11 12:55:13 +05:30
SagarRajput-7
9d999feabb
feat: change Bar color opacity and make stacking as default (#9026) 2025-09-10 14:56:40 +00:00
Amlan Kumar Nandy
0658c561b9
chore: add query section to create alerts (#8991) 2025-09-10 14:43:54 +00:00
Abhi kumar
b1ea7eab70
chore: automatically show query addon when the value is present even after refresh (#9024)
* chore: automatically show query addon when the value is present even after refresh

* chore: minor cleanup

* test: added tests for queryAddon

* test: removed inputwithlabel mock
2025-09-10 19:53:06 +05:30
Vibhu Pandey
31e042adf7
feat(alertmanager): deprecate legacy alertmanager (#9046)
- Deprecate legacy alertmanager. Are the new alert improvements compatible with legacy? I don't think they are. More importantly, I don't think they should be. It will be a pain to manage it at both places.

- Improve msteamsv2 experience. I have taken alertmanager's upstream and merged it with our custom implementation. Note the use of `titleLink` field to propagate the url of the alert.

- Delete the private http server needed for alertmanager. It's cleanup as part of 1.
2025-09-10 08:28:13 +00:00
SagarRajput-7
f23000831c
feat: update yarn lock file (#9055) 2025-09-10 05:52:57 +00:00
SagarRajput-7
f82e9b55f8
fix: logs explorer chart severity text bugfixes (#8731)
* fix: fixed severity color getting incorrectly assigned due to the response changed in v5 API

* fix: implement consistent severity variant colors across logs chart and indicator component

* chore: fix the failing tests

* chore: fix the failing check

---------

Co-authored-by: ahmadshaheer <ashaheerki@gmail.com>
Co-authored-by: Nityananda Gohain <nityanandagohain@gmail.com>
2025-09-10 05:21:06 +00:00
Shaheer Kochai
f91115948a
feat: add support for span hover card in trace details v2 (#8930)
* feat: add support for span hover card in trace details v2

* chore: remove the unnecessary tooltip

---------

Co-authored-by: Nityananda Gohain <nityanandagohain@gmail.com>
2025-09-10 09:01:57 +04:30
SagarRajput-7
011b769d4d
chore: added resolution brace-expansion to 2.0.2 to fix the vulnerability (#9049) 2025-09-09 14:53:36 +00:00
Abhi kumar
0129326a0b
Fix: changelog modal spacing issue (#9048)
* fix: added fix for changelog modal styling issue

* chore: minor code cleanup

* chore: pr review changes

* chore: minor preetier fix
2025-09-09 18:44:33 +05:30
Tushar Vats
6c7275d355
Feat: API for exporting raw data (#8936)
This introduces a new Raw Data Export module to the codebase, enabling users to export raw log data via a dedicated API endpoint. The changes include the implementation of the module and handler, integration with existing infrastructure, configuration updates, and adjustments to tests and module wiring.
2025-09-09 17:04:40 +05:30
Vibhu Pandey
c83eaf3d50
chore: enable forbidigo and noerrors in depguard (#9047)
* chore: enable forbidgo

* chore: enable forbidgo
2025-09-09 15:44:27 +05:30
primus-bot[bot]
57013e1c4f
chore(release): bump to v0.94.1 (#9045)
Co-authored-by: primus-bot[bot] <171087277+primus-bot[bot]@users.noreply.github.com>
Co-authored-by: Vikrant Gupta <vikrant@signoz.io>
2025-09-09 08:11:33 +00:00
Amlan Kumar Nandy
717efaf167
feat: base setup for new create alerts page (#8957) 2025-09-09 07:56:29 +00:00
Vikrant Gupta
6709b09646
fix(user): populate correct error message on client (#9043)
* fix(user): populate correct error message on client

* fix(user): populate correct error message on client
2025-09-09 13:05:07 +05:30
primus-bot[bot]
144e866afc
chore(release): bump to v0.94.0 (#9040)
Co-authored-by: primus-bot[bot] <171087277+primus-bot[bot]@users.noreply.github.com>
2025-09-08 22:26:06 +05:30
Nageshbansal
3f2763251a
chore(clickhouse-upgrade): updates docker and docker swarm compose for clickhouse-25.5.6 (#9031) 2025-09-08 19:54:58 +05:30
Srikanth Chekuri
e67a576c07
chore: update CODEOWNERS (#9030) 2025-09-08 10:37:51 +00:00
aniketio-ctrl
c737a7e070
chore: enable alertmanager metrics collection with instrumentation::metrics (#9020)
* feat(alerts-v2): exposed alertmanager metrics for signozalertmanager

* feat(alerts-v2): exposed alertmanager metrics for signozalertmanager

* feat(alerts-v2): exposed alertmanager metrics for signozalertmanager

* feat(notification-routing): added custom meter provider

* feat(notification-routing): added custom meter provider

* feat(notification-routing): added custom meter provider

* feat(notification-routing): added custom meter provider

* feat(notification-routing): added org id label
2025-09-08 14:41:18 +05:30
Aditya Singh
74be8f5611
Interactive dashboards fix: hide drilldown features for non-query builder panels (#9023)
* feat: drilldown prop drilldowned

* feat: refactor code

* feat: update click plugin in uplot

* feat: lint fix

* feat: add search to breakout and other refactor

* feat: context menu - increase width and add overlay

* feat: add context links

* feat: context links init

* feat: context links init

* feat: context links init

* feat: update context link modal form init

* feat: add double way sync on urls and param

* feat: minor refactor

* feat: minor refactor

* feat: change contextlinks data structure

* feat: context menu changes init

* feat: context menu hook refactor

* feat: context links processors

* feat: context variables hook added

* feat: add support for field variables

* feat: minor refactor

* feat: minor refactor

* feat: minor refactor

* feat: handle on save

* feat: minor refactor

* feat: snapshot update

* feat: revert qbv5

* feat: aggregation header val

* feat: fix header color

* feat: minor refactor

* feat: minor refactor

* feat: fix breaking changes from qb v5

* feat: change api for breakout opitons

* feat: minor refactor

* feat: minor refactor

* fix: added fix for extractquerypararms when value is string in multivalue operator

* feat: minor refactor

* feat: add back in breakout

* feat: minor refactor

* feat: add substitute var api call to decode vars

* feat: minor fix

* feat: optimize query value comparison in QueryBuilderV2

* feat: minor fix

* feat: minor fix

* feat: test fix

* feat: added dynamic variables creation flow (#7541)

* feat: added dynamic variables creation flow

* feat: added keys and value apis and hooks

* feat: added api and select component changes

* feat: added keys fetching and preview values

* feat: added dynamic variable to variable items

* feat: handled value persistence and tab switches

* feat: added default value and formed a schema for dyn-variables

* feat: added client and server side searches

* feat: corrected the initial load getfieldKey api

* feat: removed fetch on mount restriction

* feat: added dynamic variable to the dashboard details (#7755)

* feat: added dynamic variable to the dashboard details

* feat: added new component to existing variables

* feat: added enhancement to multiselect and select for dyn-variables

* feat: added refetch method between all dynamic-variables

* feat: correct error handling

* feat: correct error handling

* feat: enforced non-empty selectedvalues and default value

* feat: added client and server side searches

* feat: retry on error

* feat: correct error handling

* feat: handle defautl value in existing variables

* feat: lowercase the source for payload

* feat: fixed the incorrect assignment of active indices

* feat: improved handling of all option

* feat: improved the ALL option visuals

* feat: handled default value enforcement in existing variables

* feat: added unix time to values call

* feat: added incomplete data message and info to search

* feat: changed dashboard panel call handling with existing variables

* feat: adjusted the response type and data with the new API schema for values

* feat: code refactor

* feat: made dyn-variable option as the default

* feat: added test cases for dyn variable creation and completion

* feat: updated test cases

* feat: added variable in url and made dashboard sync around that and sharable (#7944)

* feat: added dynamic variable to the dashboard details

* feat: added new component to existing variables

* feat: added enhancement to multiselect and select for dyn-variables

* feat: added refetch method between all dynamic-variables

* feat: correct error handling

* feat: correct error handling

* feat: enforced non-empty selectedvalues and default value

* feat: added client and server side searches

* feat: retry on error

* feat: correct error handling

* feat: handle defautl value in existing variables

* feat: lowercase the source for payload

* feat: fixed the incorrect assignment of active indices

* feat: improved handling of all option

* feat: improved the ALL option visuals

* feat: handled default value enforcement in existing variables

* feat: added unix time to values call

* feat: added incomplete data message and info to search

* feat: changed dashboard panel call handling with existing variables

* feat: adjusted the response type and data with the new API schema for values

* feat: code refactor

* feat: made dyn-variable option as the default

* feat: added test cases for dyn variable creation and completion

* feat: updated test cases

* feat: added variable in url and made dashboard sync around that and sharable

* feat: added test cases

* feat: added safety check

* feat: enabled url setting on first load itself

* feat: code refactor

* feat: cleared options query param when on dashboard list page

* feat: resolved conflicts

* feat: added dynamic variable suggestion in where clause

* feat: added test cases for hooks and api call functions

* feat: added test case for querybuildersearchv2 suggestion changes

* feat: code refactor

* feat: updated test case

* feat: corrected the regex matcher for resolved titles

* feat: added ability to add/remove variable filter to one or more existing panels

* feat: added widgetselector on variable creation

* feat: show labels in widget selector

* feat: added apply to all and variable removal logical

* feat: refectch only related and affected panels in case of dynamic variables

* feat: added button loader for apply-all

* feat: light-mode styles

* feat: minor refactor

* feat: added test cases

* feat: refactor

* feat: remove consoles

* feat: pass panel types to substitutevars

* feat: cross filtering init

* fix: added fix for query builder filters

* feat: cross filtering add set/unset/create functionality

* feat: test update

* fix: added migration to filter expression for crud operations of variable

* feat: format legend name according to existing format

* feat: breakout test init

* feat: breakout test match query

* feat: context links tests

* feat: minor refactor

* feat: show edit only if user has access

* feat: added dynamic variables creation flow (#7541)

* feat: added dynamic variables creation flow

* feat: added keys and value apis and hooks

* feat: added api and select component changes

* feat: added keys fetching and preview values

* feat: added dynamic variable to variable items

* feat: handled value persistence and tab switches

* feat: added default value and formed a schema for dyn-variables

* feat: added client and server side searches

* feat: corrected the initial load getfieldKey api

* feat: removed fetch on mount restriction

* feat: added dynamic variable to the dashboard details (#7755)

* feat: added dynamic variable to the dashboard details

* feat: added new component to existing variables

* feat: added enhancement to multiselect and select for dyn-variables

* feat: added refetch method between all dynamic-variables

* feat: correct error handling

* feat: correct error handling

* feat: enforced non-empty selectedvalues and default value

* feat: added client and server side searches

* feat: retry on error

* feat: correct error handling

* feat: handle defautl value in existing variables

* feat: lowercase the source for payload

* feat: fixed the incorrect assignment of active indices

* feat: improved handling of all option

* feat: improved the ALL option visuals

* feat: handled default value enforcement in existing variables

* feat: added unix time to values call

* feat: added incomplete data message and info to search

* feat: changed dashboard panel call handling with existing variables

* feat: adjusted the response type and data with the new API schema for values

* feat: code refactor

* feat: made dyn-variable option as the default

* feat: added test cases for dyn variable creation and completion

* feat: updated test cases

* feat: added dynamic variable suggestion in where clause

* feat: added test cases for hooks and api call functions

* feat: added test case for querybuildersearchv2 suggestion changes

* feat: code refactor

* feat: updated test case

* feat: corrected the regex matcher for resolved titles

* feat: added ability to add/remove variable filter to one or more existing panels

* feat: added widgetselector on variable creation

* feat: show labels in widget selector

* feat: added apply to all and variable removal logical

* feat: refectch only related and affected panels in case of dynamic variables

* feat: added button loader for apply-all

* feat: light-mode styles

* fix: added migration to filter expression for crud operations of variable

* feat: reverted dynamic variable url config changes (#8877)

* Revert "feat: changed query param name"

This reverts commit 62bee5f003bf74b0da1c5951f1b5d0f2c250905d.

* Revert "feat: added user-friendly format to dashboard variable url"

This reverts commit 6de8b1c2e8c6a838941014ea4929e9f5c908d975.

* feat: reverted url var changes

* feat: reverted url changed from usedashboardvarupdate hook

* feat: send empty array for widgetId

* feat: added type in the variables in query_range payload for dynamic

* feat: minor fixes

* fix: added fix for multivalue operator without brackets

* feat: minor fix

* feat: fix failing test

* feat: change revert

* test: added tests for querycontextUtils + querybuilderv2 utils

* fix: added fix for replacing filter with the new value

* fix: added fix for replacing filters + datetimepicker composite query

* test: fixed querybuilderv2 utils test

* feat: handle number dataType in filters

* feat: correct the variable addition to panel format for new qb expression

* feat: remove other queries in breakout

* feat: add metric to traces mapping

* feat: pass proper time range

* feat: update time range logic

* feat: value panel drilldown init

* feat: value panel drilldown init

* feat: enable context links in value panel

* feat: minor fix

* feat: update snapshot

* feat: hide breakout in value panel

* feat: add panel type to view mode

* feat: add support to change panel in breakouts

* feat: panel change for breakout logic added

* chore: fix style

* chore: show variables suggestion while creating context links

* chore: add timestamp to graphs

* chore: add timestamp to table panel

* chore: fix failing tests

* chore: fix infinite re-rendering due to queryRange

* chore: send appropriate time range when signal is metrics

* chore: show variables suggestion while creating context links

* chore: minor refactor

* chore: show trace details link if filter has trace_id

* chore: fix infinite render of table component

* chore: added tests for v2

* fix: context links set from dropdown

* chore: minor refactor

* chore: minor refactor

* chore: fix test

* chore: fix timerange for apm metrics

* fix: get correct timestamp for clicked data

* chore: comment out change to histogram on breakout by number

* chore: change panel type on panel type change in url

* chore: remove consoles

* feat: added dynamic variables creation flow (#7541)

* feat: added dynamic variables creation flow

* feat: added keys and value apis and hooks

* feat: added api and select component changes

* feat: added keys fetching and preview values

* feat: added dynamic variable to variable items

* feat: handled value persistence and tab switches

* feat: added default value and formed a schema for dyn-variables

* feat: added client and server side searches

* feat: corrected the initial load getfieldKey api

* feat: removed fetch on mount restriction

* feat: added dynamic variable to the dashboard details (#7755)

* feat: added dynamic variable to the dashboard details

* feat: added new component to existing variables

* feat: added enhancement to multiselect and select for dyn-variables

* feat: added refetch method between all dynamic-variables

* feat: correct error handling

* feat: correct error handling

* feat: enforced non-empty selectedvalues and default value

* feat: added client and server side searches

* feat: retry on error

* feat: correct error handling

* feat: handle defautl value in existing variables

* feat: lowercase the source for payload

* feat: fixed the incorrect assignment of active indices

* feat: improved handling of all option

* feat: improved the ALL option visuals

* feat: handled default value enforcement in existing variables

* feat: added unix time to values call

* feat: added incomplete data message and info to search

* feat: changed dashboard panel call handling with existing variables

* feat: adjusted the response type and data with the new API schema for values

* feat: code refactor

* feat: made dyn-variable option as the default

* feat: added test cases for dyn variable creation and completion

* feat: updated test cases

* feat: fix lint and test cases

* feat: fix typo

* feat: fixed test case

* feat: added dynamic variable suggestion in where clause

* feat: added test cases for hooks and api call functions

* feat: added test case for querybuildersearchv2 suggestion changes

* feat: code refactor

* feat: corrected the regex matcher for resolved titles

* feat: fixed test cases

* feat: added ability to add/remove variable filter to one or more existing panels

* feat: added widgetselector on variable creation

* feat: show labels in widget selector

* feat: added apply to all and variable removal logical

* feat: refectch only related and affected panels in case of dynamic variables

* feat: added button loader for apply-all

* feat: light-mode styles

* fix: added migration to filter expression for crud operations of variable

* feat: added type in the variables in query_range payload for dynamic

* feat: correct the variable addition to panel format for new qb expression

* feat: added test cases for dynamic variable and add/remove panel feat

* feat: implemented where clause suggestion in new qb v5

* feat: added retries for dyn variable and fixed on-enter selection issue

* feat: added relatedValues and existing query in param related changes

* feat: sanitized data storage and removed duplicates

* fix: fixed typechecks

* feat: updated panel wait and refetch logic and ALL option selection

* feat: fixed variable tabel reordering issue

* feat: added empty name validation in variable creation

* feat: change value to searchtext in values API

* feat: added option for regex in the component, disabled for now

* feat: added beta and not rec. tag in variable tabs

* feat: added check to prevent api and updates calls with same payload

* feat: optimized localstorage for all selection in dynamic variable and updated __all__ case

* feat: resolved variable tables infinite loop update error

* feat: aded variable name auto-update based on attribute name entered for dynamic variables

* feat: modified only/all click behaviour and set all selection always true for dynamic variable

* feat: fix dropdown closing doesn't reset us back to our all available values when we have a search

* feat: handled all state distinction and carry forward in existing variables

* feat: trucate + n more tooltip content to 10

* feat: fixed infinite loop because of dependency of frequently changing object ref in var table

* feat: fixed inconsist search implementations

* feat: reverted only - all updated area implementation

* feat: added more space for search in multiselect component

* feat: checked for variable id instead of variable key for refetch

* feat: improved performance around multiselect component and added confirm modal for apply to all

* feat: rewrite functionality around add and remove panels

* feat: changed color for apply to all modal

* feat: added changes under flag to handle variable specific removal for removeKeysFromExpression func

* feat: added validation in variable edit panel

* chore: fix dynamic variable update in context menu to latest logic

* chore: minor fix

* chore: type fix

* fix: remove unwanted code

* fix: remove unwanted code

* fix: resolved pr comments

* fix: minor fix

* fix: fix tests

* fix: style fix

* fix: hide drilldown options in view mode for non-builder panels

---------

Co-authored-by: Aditya Singh <adityasingh@Adityas-MacBook-Pro.local>
Co-authored-by: Abhi Kumar <ahrefabhi@gmail.com>
Co-authored-by: SagarRajput-7 <162284829+SagarRajput-7@users.noreply.github.com>
Co-authored-by: SagarRajput-7 <sagar@signoz.io>
2025-09-07 09:29:33 +00:00
Srikanth Chekuri
1d3a8ecd66
fix(variable_replace_visitor): do not skip boolean value (#9021) 2025-09-07 08:40:11 +00:00
SagarRajput-7
0f5825a2b3
chore: product link and retires retry condition (#9018)
* feat: product link and retires retry condition

* feat: retry logic for 4xx and 5xx

* chore: tooltip editorial changes (#9019)

* chore: tooltip editorial changes

* feat: fixed lint error and styling

---------

Co-authored-by: SagarRajput-7 <sagar@signoz.io>

* feat: added test cases

* feat: fixed lint error

* feat: added product link in single select for dyn variables

---------

Co-authored-by: Srikanth Chekuri <srikanth.chekuri92@gmail.com>
2025-09-07 13:36:12 +05:30
Aditya Singh
eee96503ff
feat/interactive dashbaord v2 (#9011)
* feat: add drilldown options in uplot

* feat: add time range to timeseries, bar charts

* feat: remove unwanted code

* feat: minor refactor

* feat: drilldown prop drilldowned

* feat: refactor code

* feat: update click plugin in uplot

* feat: lint fix

* feat: add search to breakout and other refactor

* feat: context menu - increase width and add overlay

* feat: add context links

* feat: context links init

* feat: context links init

* feat: context links init

* feat: update context link modal form init

* feat: add double way sync on urls and param

* feat: minor refactor

* feat: minor refactor

* feat: change contextlinks data structure

* feat: context menu changes init

* feat: context menu hook refactor

* feat: context links processors

* feat: context variables hook added

* feat: add support for field variables

* feat: minor refactor

* feat: minor refactor

* feat: minor refactor

* feat: handle on save

* feat: minor refactor

* feat: snapshot update

* feat: revert qbv5

* feat: aggregation header val

* feat: fix header color

* feat: minor refactor

* feat: minor refactor

* feat: fix breaking changes from qb v5

* feat: change api for breakout opitons

* feat: minor refactor

* feat: minor refactor

* fix: added fix for extractquerypararms when value is string in multivalue operator

* feat: minor refactor

* feat: add back in breakout

* feat: minor refactor

* feat: add substitute var api call to decode vars

* feat: minor fix

* feat: optimize query value comparison in QueryBuilderV2

* feat: minor fix

* feat: minor fix

* feat: test fix

* feat: added dynamic variables creation flow (#7541)

* feat: added dynamic variables creation flow

* feat: added keys and value apis and hooks

* feat: added api and select component changes

* feat: added keys fetching and preview values

* feat: added dynamic variable to variable items

* feat: handled value persistence and tab switches

* feat: added default value and formed a schema for dyn-variables

* feat: added client and server side searches

* feat: corrected the initial load getfieldKey api

* feat: removed fetch on mount restriction

* feat: added dynamic variable to the dashboard details (#7755)

* feat: added dynamic variable to the dashboard details

* feat: added new component to existing variables

* feat: added enhancement to multiselect and select for dyn-variables

* feat: added refetch method between all dynamic-variables

* feat: correct error handling

* feat: correct error handling

* feat: enforced non-empty selectedvalues and default value

* feat: added client and server side searches

* feat: retry on error

* feat: correct error handling

* feat: handle defautl value in existing variables

* feat: lowercase the source for payload

* feat: fixed the incorrect assignment of active indices

* feat: improved handling of all option

* feat: improved the ALL option visuals

* feat: handled default value enforcement in existing variables

* feat: added unix time to values call

* feat: added incomplete data message and info to search

* feat: changed dashboard panel call handling with existing variables

* feat: adjusted the response type and data with the new API schema for values

* feat: code refactor

* feat: made dyn-variable option as the default

* feat: added test cases for dyn variable creation and completion

* feat: updated test cases

* feat: added variable in url and made dashboard sync around that and sharable (#7944)

* feat: added dynamic variable to the dashboard details

* feat: added new component to existing variables

* feat: added enhancement to multiselect and select for dyn-variables

* feat: added refetch method between all dynamic-variables

* feat: correct error handling

* feat: correct error handling

* feat: enforced non-empty selectedvalues and default value

* feat: added client and server side searches

* feat: retry on error

* feat: correct error handling

* feat: handle defautl value in existing variables

* feat: lowercase the source for payload

* feat: fixed the incorrect assignment of active indices

* feat: improved handling of all option

* feat: improved the ALL option visuals

* feat: handled default value enforcement in existing variables

* feat: added unix time to values call

* feat: added incomplete data message and info to search

* feat: changed dashboard panel call handling with existing variables

* feat: adjusted the response type and data with the new API schema for values

* feat: code refactor

* feat: made dyn-variable option as the default

* feat: added test cases for dyn variable creation and completion

* feat: updated test cases

* feat: added variable in url and made dashboard sync around that and sharable

* feat: added test cases

* feat: added safety check

* feat: enabled url setting on first load itself

* feat: code refactor

* feat: cleared options query param when on dashboard list page

* feat: resolved conflicts

* feat: added dynamic variable suggestion in where clause

* feat: added test cases for hooks and api call functions

* feat: added test case for querybuildersearchv2 suggestion changes

* feat: code refactor

* feat: updated test case

* feat: corrected the regex matcher for resolved titles

* feat: added ability to add/remove variable filter to one or more existing panels

* feat: added widgetselector on variable creation

* feat: show labels in widget selector

* feat: added apply to all and variable removal logical

* feat: refectch only related and affected panels in case of dynamic variables

* feat: added button loader for apply-all

* feat: light-mode styles

* feat: minor refactor

* feat: added test cases

* feat: refactor

* feat: remove consoles

* feat: pass panel types to substitutevars

* feat: cross filtering init

* fix: added fix for query builder filters

* feat: cross filtering add set/unset/create functionality

* feat: test update

* fix: added migration to filter expression for crud operations of variable

* feat: format legend name according to existing format

* feat: breakout test init

* feat: breakout test match query

* feat: context links tests

* feat: minor refactor

* feat: show edit only if user has access

* feat: added dynamic variables creation flow (#7541)

* feat: added dynamic variables creation flow

* feat: added keys and value apis and hooks

* feat: added api and select component changes

* feat: added keys fetching and preview values

* feat: added dynamic variable to variable items

* feat: handled value persistence and tab switches

* feat: added default value and formed a schema for dyn-variables

* feat: added client and server side searches

* feat: corrected the initial load getfieldKey api

* feat: removed fetch on mount restriction

* feat: added dynamic variable to the dashboard details (#7755)

* feat: added dynamic variable to the dashboard details

* feat: added new component to existing variables

* feat: added enhancement to multiselect and select for dyn-variables

* feat: added refetch method between all dynamic-variables

* feat: correct error handling

* feat: correct error handling

* feat: enforced non-empty selectedvalues and default value

* feat: added client and server side searches

* feat: retry on error

* feat: correct error handling

* feat: handle defautl value in existing variables

* feat: lowercase the source for payload

* feat: fixed the incorrect assignment of active indices

* feat: improved handling of all option

* feat: improved the ALL option visuals

* feat: handled default value enforcement in existing variables

* feat: added unix time to values call

* feat: added incomplete data message and info to search

* feat: changed dashboard panel call handling with existing variables

* feat: adjusted the response type and data with the new API schema for values

* feat: code refactor

* feat: made dyn-variable option as the default

* feat: added test cases for dyn variable creation and completion

* feat: updated test cases

* feat: added dynamic variable suggestion in where clause

* feat: added test cases for hooks and api call functions

* feat: added test case for querybuildersearchv2 suggestion changes

* feat: code refactor

* feat: updated test case

* feat: corrected the regex matcher for resolved titles

* feat: added ability to add/remove variable filter to one or more existing panels

* feat: added widgetselector on variable creation

* feat: show labels in widget selector

* feat: added apply to all and variable removal logical

* feat: refectch only related and affected panels in case of dynamic variables

* feat: added button loader for apply-all

* feat: light-mode styles

* fix: added migration to filter expression for crud operations of variable

* feat: reverted dynamic variable url config changes (#8877)

* Revert "feat: changed query param name"

This reverts commit 62bee5f003bf74b0da1c5951f1b5d0f2c250905d.

* Revert "feat: added user-friendly format to dashboard variable url"

This reverts commit 6de8b1c2e8c6a838941014ea4929e9f5c908d975.

* feat: reverted url var changes

* feat: reverted url changed from usedashboardvarupdate hook

* feat: send empty array for widgetId

* feat: added type in the variables in query_range payload for dynamic

* feat: minor fixes

* fix: added fix for multivalue operator without brackets

* feat: minor fix

* feat: fix failing test

* feat: change revert

* test: added tests for querycontextUtils + querybuilderv2 utils

* fix: added fix for replacing filter with the new value

* fix: added fix for replacing filters + datetimepicker composite query

* test: fixed querybuilderv2 utils test

* feat: handle number dataType in filters

* feat: correct the variable addition to panel format for new qb expression

* feat: remove other queries in breakout

* feat: add metric to traces mapping

* feat: pass proper time range

* feat: update time range logic

* feat: value panel drilldown init

* feat: value panel drilldown init

* feat: enable context links in value panel

* feat: minor fix

* feat: update snapshot

* feat: hide breakout in value panel

* feat: add panel type to view mode

* feat: add support to change panel in breakouts

* feat: panel change for breakout logic added

* chore: fix style

* chore: show variables suggestion while creating context links

* chore: add timestamp to graphs

* chore: add timestamp to table panel

* chore: fix failing tests

* chore: fix infinite re-rendering due to queryRange

* chore: send appropriate time range when signal is metrics

* chore: show variables suggestion while creating context links

* chore: minor refactor

* chore: show trace details link if filter has trace_id

* chore: fix infinite render of table component

* chore: added tests for v2

* fix: context links set from dropdown

* chore: minor refactor

* chore: minor refactor

* chore: fix test

* chore: fix timerange for apm metrics

* fix: get correct timestamp for clicked data

* chore: comment out change to histogram on breakout by number

* chore: change panel type on panel type change in url

* chore: remove consoles

* feat: added dynamic variables creation flow (#7541)

* feat: added dynamic variables creation flow

* feat: added keys and value apis and hooks

* feat: added api and select component changes

* feat: added keys fetching and preview values

* feat: added dynamic variable to variable items

* feat: handled value persistence and tab switches

* feat: added default value and formed a schema for dyn-variables

* feat: added client and server side searches

* feat: corrected the initial load getfieldKey api

* feat: removed fetch on mount restriction

* feat: added dynamic variable to the dashboard details (#7755)

* feat: added dynamic variable to the dashboard details

* feat: added new component to existing variables

* feat: added enhancement to multiselect and select for dyn-variables

* feat: added refetch method between all dynamic-variables

* feat: correct error handling

* feat: correct error handling

* feat: enforced non-empty selectedvalues and default value

* feat: added client and server side searches

* feat: retry on error

* feat: correct error handling

* feat: handle defautl value in existing variables

* feat: lowercase the source for payload

* feat: fixed the incorrect assignment of active indices

* feat: improved handling of all option

* feat: improved the ALL option visuals

* feat: handled default value enforcement in existing variables

* feat: added unix time to values call

* feat: added incomplete data message and info to search

* feat: changed dashboard panel call handling with existing variables

* feat: adjusted the response type and data with the new API schema for values

* feat: code refactor

* feat: made dyn-variable option as the default

* feat: added test cases for dyn variable creation and completion

* feat: updated test cases

* feat: fix lint and test cases

* feat: fix typo

* feat: fixed test case

* feat: added dynamic variable suggestion in where clause

* feat: added test cases for hooks and api call functions

* feat: added test case for querybuildersearchv2 suggestion changes

* feat: code refactor

* feat: corrected the regex matcher for resolved titles

* feat: fixed test cases

* feat: added ability to add/remove variable filter to one or more existing panels

* feat: added widgetselector on variable creation

* feat: show labels in widget selector

* feat: added apply to all and variable removal logical

* feat: refectch only related and affected panels in case of dynamic variables

* feat: added button loader for apply-all

* feat: light-mode styles

* fix: added migration to filter expression for crud operations of variable

* feat: added type in the variables in query_range payload for dynamic

* feat: correct the variable addition to panel format for new qb expression

* feat: added test cases for dynamic variable and add/remove panel feat

* feat: implemented where clause suggestion in new qb v5

* feat: added retries for dyn variable and fixed on-enter selection issue

* feat: added relatedValues and existing query in param related changes

* feat: sanitized data storage and removed duplicates

* fix: fixed typechecks

* feat: updated panel wait and refetch logic and ALL option selection

* feat: fixed variable tabel reordering issue

* feat: added empty name validation in variable creation

* feat: change value to searchtext in values API

* feat: added option for regex in the component, disabled for now

* feat: added beta and not rec. tag in variable tabs

* feat: added check to prevent api and updates calls with same payload

* feat: optimized localstorage for all selection in dynamic variable and updated __all__ case

* feat: resolved variable tables infinite loop update error

* feat: aded variable name auto-update based on attribute name entered for dynamic variables

* feat: modified only/all click behaviour and set all selection always true for dynamic variable

* feat: fix dropdown closing doesn't reset us back to our all available values when we have a search

* feat: handled all state distinction and carry forward in existing variables

* feat: trucate + n more tooltip content to 10

* feat: fixed infinite loop because of dependency of frequently changing object ref in var table

* feat: fixed inconsist search implementations

* feat: reverted only - all updated area implementation

* feat: added more space for search in multiselect component

* feat: checked for variable id instead of variable key for refetch

* feat: improved performance around multiselect component and added confirm modal for apply to all

* feat: rewrite functionality around add and remove panels

* feat: changed color for apply to all modal

* feat: added changes under flag to handle variable specific removal for removeKeysFromExpression func

* feat: added validation in variable edit panel

* chore: fix dynamic variable update in context menu to latest logic

* chore: minor fix

* chore: type fix

* fix: remove unwanted code

* fix: remove unwanted code

* fix: resolved pr comments

* fix: minor fix

* fix: fix tests

* fix: style fix

---------

Co-authored-by: Aditya Singh <adityasingh@Adityas-MacBook-Pro.local>
Co-authored-by: Abhi Kumar <ahrefabhi@gmail.com>
Co-authored-by: SagarRajput-7 <162284829+SagarRajput-7@users.noreply.github.com>
Co-authored-by: SagarRajput-7 <sagar@signoz.io>
2025-09-07 11:50:35 +05:30
SagarRajput-7
7f925bd50e
feat: added dynamic variable and other variable enhancements (#8873)
* feat: added dynamic variables creation flow (#7541)

* feat: added dynamic variables creation flow

* feat: added keys and value apis and hooks

* feat: added api and select component changes

* feat: added keys fetching and preview values

* feat: added dynamic variable to variable items

* feat: handled value persistence and tab switches

* feat: added default value and formed a schema for dyn-variables

* feat: added client and server side searches

* feat: corrected the initial load getfieldKey api

* feat: removed fetch on mount restriction

* feat: added dynamic variable to the dashboard details (#7755)

* feat: added dynamic variable to the dashboard details

* feat: added new component to existing variables

* feat: added enhancement to multiselect and select for dyn-variables

* feat: added refetch method between all dynamic-variables

* feat: correct error handling

* feat: correct error handling

* feat: enforced non-empty selectedvalues and default value

* feat: added client and server side searches

* feat: retry on error

* feat: correct error handling

* feat: handle defautl value in existing variables

* feat: lowercase the source for payload

* feat: fixed the incorrect assignment of active indices

* feat: improved handling of all option

* feat: improved the ALL option visuals

* feat: handled default value enforcement in existing variables

* feat: added unix time to values call

* feat: added incomplete data message and info to search

* feat: changed dashboard panel call handling with existing variables

* feat: adjusted the response type and data with the new API schema for values

* feat: code refactor

* feat: made dyn-variable option as the default

* feat: added test cases for dyn variable creation and completion

* feat: updated test cases

* feat: fix lint and test cases

* feat: fix typo

* feat: resolved comments and refactoring

* feat: added dynamic variable suggestion in where clause (#8875)

* feat: added dynamic variable suggestion in where clause

* feat: added test cases for hooks and api call functions

* feat: added test case for querybuildersearchv2 suggestion changes

* feat: code refactor

* feat: corrected the regex matcher for resolved titles

* feat: fixed test cases

* feat: added ability to add/remove variable filter to one or more existing panels (#8876)

* feat: added ability to add/remove variable filter to one or more existing panels

* feat: added widgetselector on variable creation

* feat: show labels in widget selector

* feat: added apply to all and variable removal logical

* feat: refectch only related and affected panels in case of dynamic variables

* feat: added button loader for apply-all

* feat: light-mode styles

* fix: added migration to filter expression for crud operations of variable

* feat: added type in the variables in query_range payload for dynamic

* feat: correct the variable addition to panel format for new qb expression

* feat: added test cases for dynamic variable and add/remove panel feat

* feat: implemented where clause suggestion in new qb v5

* feat: added retries for dyn variable and fixed on-enter selection issue

* feat: added relatedValues and existing query in param related changes

* feat: sanitized data storage and removed duplicates

* fix: fixed typechecks

* feat: updated panel wait and refetch logic and ALL option selection

* feat: fixed variable tabel reordering issue

* feat: added empty name validation in variable creation

* feat: change value to searchtext in values API

* feat: added option for regex in the component, disabled for now

* feat: added beta and not rec. tag in variable tabs

* feat: added check to prevent api and updates calls with same payload

* feat: optimized localstorage for all selection in dynamic variable and updated __all__ case

* feat: resolved variable tables infinite loop update error

* feat: aded variable name auto-update based on attribute name entered for dynamic variables

* feat: modified only/all click behaviour and set all selection always true for dynamic variable

* feat: fix dropdown closing doesn't reset us back to our all available values when we have a search

* feat: handled all state distinction and carry forward in existing variables

* feat: trucate + n more tooltip content to 10

* feat: fixed infinite loop because of dependency of frequently changing object ref in var table

* feat: fixed inconsist search implementations

* feat: reverted only - all updated area implementation

* feat: added more space for search in multiselect component

* feat: checked for variable id instead of variable key for refetch

* feat: improved performance around multiselect component and added confirm modal for apply to all

* feat: rewrite functionality around add and remove panels

* feat: changed color for apply to all modal

* feat: added changes under flag to handle variable specific removal for removeKeysFromExpression func

* feat: added validation in variable edit panel

* feat: fixed failing test cases due to recent logic change

* feat: added doc links in the dynamic variable feat

* feat: resolved comments and refactoring

* feat: resolved comments and refactoring

* feat: fixed test cases

* feat: fixed test cases
2025-09-06 14:48:45 +05:30
SagarRajput-7
1aa7e8b5d9
feat: added new component to existing variables (#7744)
* feat: added new component to existing variables

* feat: added multiselect component and solved dropdown closing on every selection

* feat: fixed incorrect all label

* feat: allow custom value

* feat: better styles

* feat: added maxtagcount placeholder

* feat: added onclear function

* feat: updated regex and handlings

* feat: updated regex and handlings

* feat: added enableall prop control

* feat: fix the rebase conflict

* feat: fixed comments

* feat: fix test case

* feat: added test cases for customMultiselect, customSelect and variableItem integration

* feat: added test cases for behaviour around values added and selections showed

* feat: refactored test cases

---------

Co-authored-by: Srikanth Chekuri <srikanth.chekuri92@gmail.com>
2025-09-06 12:26:15 +05:30
Abhi kumar
bf704333b3
Feature/trace operators (#8869)
* feat: added traceoperator component and styles

* chore: minor style improvments

* feat: added conditions for traceoperator

* chore: minor UI fixes

* chore: type changes

* chore: added initialvalue for trace operators

* chore: Added changes to prepare request payload

* chore: fixed minor styles + minor ux fix

* feat: added span selector

* chore: added ui changes in the editor

* chore: removed traceoperations and reused queryoperations

* chore: minor changes in queryaddon and aggregation for support

* chore: added traceoperators in alerts

* chore: minor pr review change

* chore: linter fix

* fix: fixed minor ts issues

* fix: added limit support in traceoperator

* chore: minor fix in traceoperator styles

* chore: linting fix + icon changes

* chore: updated type

* chore: lint fixes

* feat: added changes for showing querynames in alerts

* feat: added trace operator grammer + antlr files

* feat: added traceoperator context util

* chore: added traceoperator validation function

* feat: added traceoperator editor

* feat: added queryname boost + operator constants

* fix: pr reviews

* chore: minor ui fix

* fix: updated grammer files

* test: added test for traceoperatorcontext

* chore: removed check for multiple queries in traceexplorer

* test: minor test fix

* test: fixed breaking mapQueryDataFromApi test

* chore: fixed logic to show trace operator

* chore: updated docs link

* chore: minor ui issue fix

* chore: changed trace operator query name

* chore: removed using spans from in trace opeartors

* fix: added fix for order by in trace opeartor

* feat: added changes related to saved in views in trace opeartor

* chore: added changes to keep indirect descendent operator at bottom

* chore: removed returnspansfrom field from traceoperator

* chore: updated file names + regenerated grammer

* chore: added beta tag in trace opeartor

* chore: pr review fixes

* Fix/tsc trace operator + tests (#8942)

* fix: added tsc fixes for trace operator

* chore: moved traceoperator utils

* test: added test for traceopertor util

* chore: tsc fix

* fix: fixed tsc issue

* Feat/trace operator dashboards (#8992)

* chore: added callout message for multiple queries without trace operators

* feat: added changes for supporting trace operators in dashboards

* chore: minor changes for list panel
2025-09-05 16:00:24 +00:00
Vibhu Pandey
f63f175a77
fix(binding): better error messages (#9010) 2025-09-05 15:47:19 +00:00
Ekansh Gupta
b6f5c053a0
feat: trace operators BE (#8293)
* feat: [draft] added implementation of trace operators

* feat: [draft] added implementation of trace operators

* feat: [draft] added implementation of trace operators

* feat: [draft] added implementation of trace operators

* feat: added implementation of trace operators

* feat: added implementation of trace operators

* feat: added implementation of trace operators

* feat: added implementation of trace operators

* feat: added implementation of trace operators

* feat: added implementation of trace operators

* feat: added implementation of trace operators

* feat: added implementation of trace operators

* feat: added implementation of trace operators

* feat: added implementation of trace operators

* feat: refactor trace operator

* feat: added postprocess

* feat: added postprocess

* feat: added postprocess

* feat: refactored the consume function

* feat: refactored the consume function

* feat: refactored the consume function

* feat: refactored the consume function

* feat: refactored the consume function

* feat: resolved conflicts

* feat: resolved conflicts

* feat: resolved conflicts

* feat: resolved conflicts

* feat: resolved conflicts

* feat: resolved conflicts

* feat: resolved conflicts

* feat: resolved conflicts

* feat: resolved conflicts

* feat: resolved conflicts

* feat: resolved conflicts

* feat: resolved conflicts

* feat: resolved conflicts

* feat: resolved conflicts

* feat: resolved conflicts

* feat: resolved conflicts

* feat: resolved conflicts

* feat: resolved conflicts

* feat: resolved conflicts

* feat: resolved conflicts

* feat: resolved conflicts

* feat: resolved conflicts

* feat: resolved conflicts

* feat: resolved conflicts

* feat: resolved conflicts

* feat: resolved conflicts

* feat: resolved conflicts

* feat: resolved conflicts

* feat: resolved conflicts

* feat: resolved conflicts

* feat: resolved conflicts

* feat: resolved conflicts

* feat: resolved conflicts

* feat: resolved conflicts

* feat: resolved conflicts

* feat: resolved conflicts

* feat: replaced info to debug logs

* feat: replaced info to debug logs

* feat: replaced info to debug logs

* feat: updated time series query

* feat: fixed merge conflicts

* feat: fixed merge conflicts

* feat: fixed merge conflicts

* feat: fixed merge conflicts

* feat: added deep copy in ranged queries

* feat: refactored fingerprinting

* feat: refactored fingerprinting

* feat: refactored fingerprinting

* feat: refactored fingerprinting

* feat: refactored fingerprinting

* feat: refactored fingerprinting

* feat: refactored fingerprinting

* feat: added comment for build all spans cte

* feat: added postprocess for timeseries and added limits to memory

* feat: fixed span count in trace view

* feat: fixed span count in trace view

* feat: fixed linting issues

* feat: fixed linting issues

* feat: fixed linting issues

* feat: fixed linting issues

---------

Co-authored-by: Nityananda Gohain <nityanandagohain@gmail.com>
2025-09-05 21:07:10 +05:30
Abhi kumar
abeadc7672
fix: backward compatibility for explorer in case of aggregateAttribute is not present (#9000) 2025-09-04 13:21:16 +00:00
SagarRajput-7
faadc60c74
fix: fixed table panels not sorting, due to mismatch in lookup (id vs name) for aggregations (#9002)
* fix: fixed table panels not sorting, due to mismatch in id for aggregations

* fix: added test cases for the sort and util for qbv5 aggregation
2025-09-04 18:44:38 +05:30
Vibhu Pandey
360e8309c8
feat(password): implement strong controls for password (#8983)
## 📄 Summary

implement strong controls for password. Now the password requirement is : 

password must be at least 12 characters long, should contain at least one uppercase letter [A-Z], one lowercase letter [a-z], one number [0-9], and one symbol
2025-09-04 17:22:28 +05:30
SagarRajput-7
27580b62ba
fix: fixed full view height for table panel (#9004) 2025-09-04 10:40:30 +00:00
SagarRajput-7
bcd21cee74
fix: y axis unit not interactive in the panel edit mode (#9003) 2025-09-04 16:00:03 +05:30
Vikrant Gupta
2dbe0777f4
feat(authz): add openfga authz middleware (#8990)
* feat(authz): add openfga authz middleware

* feat(authz): update the auth context

* feat(authz): update the auth context

* feat(authz): update check request

* feat(authz): update check request

* feat(authz): add lifecycle tests

* feat(authz): add lifecycle tests

* feat(authz): add start-stop tests
2025-09-04 08:37:11 +00:00
SagarRajput-7
7602d863dd
fix: fixed table panel no scroll issue due to style override from calender component (#8996) 2025-09-04 09:55:46 +05:30
Abhi kumar
68d9c6c3cc
fix: added fix for incorrect query in dashboard on panel change to list panel (#8994)
* fix: added fix for incorrect query in dashboard on panel change to list issue

* test: added test for handleQueryChange

* chore: pr reviews
2025-09-03 14:00:22 +00:00
manika-signoz
10c6e1fac7
feat: add delete button to invite user flow (#8993) 2025-09-03 19:07:35 +05:30
Shaheer Kochai
3999a64c64
feat: add pinning functionality for span attributes (#8769)
* refactor: adjust the attribute pinning changes based on trace actionables latest changes

* feat: persist pinned attributes on the BE, fallback to local storage

* chore: overall improvement

* chore: fix the failing tests

* fix: make the changes w.r.t. pinned attributes preferences in in preference.go
2025-09-03 16:36:10 +04:30
Vikrant Gupta
729bfb31f1
feat(authz): implement the current usecases in openfga (#8982)
* feat(authz): implement the current usecases in openfga

* feat(authz): implement the current usecases in openfga

* feat(authz): extract out the schema and DI the same

* feat(authz): extract out the schema and DI the same
2025-09-02 11:00:47 +00:00
Nityananda Gohain
052fb8b703
fix: support canDefaultZero for logs and traces (#8973)
* fix: support canDefaultZero for logs and traces

* fix: remove increase

* fix: move changes to req.go

* fix: add tood

* fix: address comments
2025-09-02 09:54:55 +00:00
nikhilmantri0902
5d9247f591
Allow deletion of multiple panels for dashboard updates made with API key (#8903) 2025-09-02 09:30:22 +00:00
Yunus M
c0a9948146
feat: handle active log flow (#8946)
* feat: handle active log flow

* feat: show live logs in logs explorer view

* feat: enable live logs in logs explorer

* feat: show live time option only in logs list view

* chore: pass showLiveLogs as false in test cases

* fix: handle live logs data format to open in log details

* fix: use current query state for frequency chart in live logs view

* fix: encode filter expression, show live option only in list view
2025-09-02 11:05:52 +05:30
Vikrant Gupta
f3569a9a02
chore(meter): remove the meter data validity message for non cloud users (#8972) 2025-09-01 16:18:47 +00:00
Vikrant Gupta
0df1ed3b57
fix(dashboard): remove context from dashboard types (#8971) 2025-09-01 16:08:25 +00:00
Nityananda Gohain
d0132f11ae
fix: update clickhouse-sql-parser (#8970) 2025-09-01 13:25:27 +00:00
Vikrant Gupta
f61e859901
feat(authz): embed openfga server (#8966)
* feat(access-control): embed openfga in signoz

* feat(authz): rename access control to authz

* feat(authz): fix codeowners and go mod tidy

* feat(authz): fix lint

* feat(authz): update go version and move convertor to instrumentation

* feat(authz): some more lint issues

* feat(authz): some more lint issues

* feat(authz): some more lint issues

* feat(authz): fix more lint issues

* feat(authz): make logger converter interface
2025-09-01 17:10:13 +05:30
Ekansh Gupta
4daec45d98
feat: added custom retention for logs api (#8513)
* feat: added custom retention for logs api

* feat: added custom retention for logs api

* feat: added implementation of trace operators

* feat: added validation checks for resource keys

* feat: added validation checks for resource keys

* feat: added validation checks for resource keys

* feat: added validation checks for resource keys

* feat: added validation checks for resource keys

* feat: added validation checks for resource keys

* feat: added validation checks for resource keys

* feat: added validation checks for resource keys

* feat: added default checks for custom retention

* feat: added default checks for custom retention

* feat: added default checks for custom retention

* feat: added change for ttl

* feat: v2 api supports both v1 and v2

* feat: v2 api supports both v1 and v2

* feat: v2 api supports both v1 and v2

* feat: v2 api supports both v1 and v2

* feat: added default_ttl in v1

* feat: added set logs ttl v1 from v2

* feat: resolved conflicts

* feat: resolved conflicts

* feat: resolved conflicts

* feat: resolved conflicts

* feat: resolved conflicts

* feat: resolved conflicts

* feat: resolved conflicts

* feat: resolved conflicts

* feat: resolved conflicts

* feat: resolved conflicts

* feat: resolved conflicts
2025-09-01 07:30:57 +00:00
Ekansh Gupta
382d9d4a87
Revert "3rd party API sem conv fix (Supports >1.26) (#8822)" (#8954)
This reverts commit 396e0cdc2d7cf58814295f34e7efaf9f845931bc.
2025-09-01 07:20:56 +00:00
Nityananda Gohain
87ce197631
fix: don't skip resource filter in main table for OR queries (#8958)
* fix: don't skip resource filter in main table for OR queries

* fix: dont skip resource table

* fix: make check case insensitive

* fix: iterate over token stream
2025-08-30 23:16:56 +05:30
aniketio-ctrl
3cc5a24a4b
fix: return 404 status code if rule not found (#8940)
* fix(rule-alert-state): added 404 status code for invalid rules
2025-08-30 12:32:03 +05:30
Yunus M
9b8a892079
chore: use infinity table for logs column view (#8953) 2025-08-29 16:12:27 +05:30
Ekansh Gupta
396e0cdc2d
3rd party API sem conv fix (Supports >1.26) (#8822)
* feat: adding support for 1.26 semconv

* feat: adding support for 1.26 semconv

* feat: adding support for 1.26 semconv

* feat: adding support for 1.26 semconv

* feat: added native support for 1.26

* feat: added native support for 1.26

* feat: adding support for 1.26 semconv

* feat: adding support for 1.26 semconv

* feat: adding support for 1.26 semconv

* feat: resolved conflicts

* feat: resolved conflicts

* feat: resolved conflicts

* feat: resolved conflicts

* feat: resolved conflicts
2025-08-29 09:50:16 +00:00
Abhi kumar
c838d7e2d4
chore: added api chagnes for logs retenetion v2 api (#8649)
* chore: added api chagnes for logs retenetion v2 api

* chore: added pr review fixes

* chore: minor fix

* feat: added api changes for setting retention period

* chore: pr review fixes

* chore: removed return statement

* fix: pr reviews

* fix: pr review
2025-08-29 15:10:15 +05:30
Nityananda Gohain
1a193fb1a9
fix: update email template for update role (#8610)
* fix: update email template for update role

* fix: remove space
2025-08-29 06:51:03 +00:00
Yunus M
88dff3f552
feat: minor ui updates (#8947) 2025-08-29 11:36:32 +05:30
Nityananda Gohain
5bb6d78c42
fix: remove isRoot and Entrypoint from selectfields (#8893)
* fix: remove isRoot and Entrypoint from selectfields

* fix: add comment

* fix: add comment

* fix: move logic to validation

* fix: remove requestType trace

* fix: update comment

* fix: update error message
2025-08-29 05:46:16 +00:00
Yunus M
369f77977d
feat: use update props from data table component for better UX (#8950) 2025-08-29 10:06:43 +05:30
Vikrant Gupta
836605def5
feat(ingestion): add ingestion id to details (#8949) 2025-08-29 00:47:42 +05:30
Yunus M
cc80923265
feat: show timestamp in selected timezone format (#8948) 2025-08-29 00:18:05 +05:30
Yunus M
92e5986af2
feat: replace infinity list view component with data table component (#8904)
* feat: replace infinity list view component with data table component

* feat: remove duplicate hook calls

* chore: add @signozhq/table to transformIgnorePatterns

* feat: update test cases for frequency chart in logs explorer

* feat: address review comments , add sonner for notifications

* feat: address review comments
2025-08-28 19:03:29 +05:30
Abhi kumar
912a34da8d
fix: added fix for context query not getting updated (#8941) 2025-08-28 15:14:18 +05:30
primus-bot[bot]
8b99ba0f9f
chore(release): bump SigNoz to v0.93.0, OTel Collector to v0.129.2 (#8939)
Co-authored-by: primus-bot[bot] <171087277+primus-bot[bot]@users.noreply.github.com>
2025-08-28 12:26:46 +05:30
Nityananda Gohain
841abf8c0b
fix: update live tail api (#8807)
* fix: update live tail api

* fix: minor fixes

* fix: more minor fixes

* fix: remove zap

* fix: correct spelling

* fix: tests

* fix: lint issues

* fix: remove debug

* fix: address comments

* fix: update name

---------

Co-authored-by: Srikanth Chekuri <srikanth.chekuri92@gmail.com>
2025-08-28 11:44:43 +05:30
Vishal Sharma
df54e6350d
fix: trace explorer and home page keyboard shortcut (#8934) 2025-08-27 18:19:54 +00:00
Srikanth Chekuri
f6bc30050b
fix: exclusion operators use AND combinator on ambiguity (#8928) 2025-08-26 14:22:23 +00:00
Srikanth Chekuri
1e76046c7c
chore: add value search for related values request (#8925) 2025-08-26 19:37:25 +05:30
SagarRajput-7
910751713d
fix: removed transformstringwithprefix and removeprefix utilities (#8922)
* fix: removed transformstringwithprefix and removeprefix utilities

* fix: fixed testcase
2025-08-26 16:13:08 +05:30
Vikrant Gupta
85c671c8d5
fix(meter): meter regex for comment middleware (#8921) 2025-08-26 08:12:31 +00:00
Yunus M
4d2094b4ce
feat: enable global actions (#8906)
* feat: enable global actions

* feat: separate actions for collapse and open sidebar

* fix: remove spaces from shortcuts

* chore: remove console log

* chore: yarn install to update yarn.lock
2025-08-26 13:28:28 +05:30
Shaheer Kochai
32410baa72
feat: display HTTP status badge in trace details v2 spans (#8699)
* feat: display http status badge in trace details v2 spans

* chore: change the fallback background for status code badge

* fix: align the status badge to the end of span details column

* chore: fix the failing tests
2025-08-26 06:38:23 +00:00
Yunus M
2a5fb9fd6f
feat: date picker v2 (#8886)
* feat: date picker v2

* feat: custom date time range history

* feat: light mode updates and interaction fixes

* fix: improve usability

* chore: add calendar, input and popover to transformIgnorePatterns

* chore: add date-fns to transformIgnorePatterns

* chore: add @signozhq/button to transformIgnorePatterns

* feat: update css variables
2025-08-26 06:13:23 +00:00
Nityananda Gohain
514bceca34
feat: support for hasToken (#8891)
* feat: support for hasToken

* fix: address comments

* fix: address comments
2025-08-26 05:58:31 +00:00
Shaheer Kochai
ac7d8bcde2
chore: add tests for trace details actionables (#8840) 2025-08-26 05:48:25 +00:00
Shaheer Kochai
88312e971d
fix: fix the trace explorer back navigation issue (#8760) 2025-08-26 04:47:28 +00:00
Shaheer Kochai
17533b2f1c
fix: fix the issue of group by queries not switching to timeseries view in logs and traces explorer (#8870)
* fix: fix the issue of group by queries not switching to timeseries view in logs explorer

* fix: fix the issue of group by queries not switching to timeseries view in traces explorer

* chore: overall improvements
2025-08-25 13:05:50 +00:00
SagarRajput-7
c4044fa2c5
feat: fixed panel correlation and alert multiaggregation issues (#8733)
* feat: fixed panel coorelation not spreading the filter expression in explorer pages

* feat: fixed multiagregation not getting sent in create alert

* fix: fixed failing test cases

* Update frontend/src/api/v5/queryRange/prepareQueryRangePayloadV5.ts

Co-authored-by: ellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com>

* fix: fix lint error

* fix: stepInterval not updating in panel qb

* fix: added test cases for mapQueryDataFromApi and prepareQueryRangePayloadV5

* fix: added convertV5Response test cases - timeseries, pie and table

* fix: refactored handleRunQuery

* fix: code refactor

* fix: refactored the mapQueryDataFromApi function according to new sub_var api

* fix: updated test cases

* fix: removed isJSON and isColumn from everywhere

* fix: fixed code and test cases

* fix: fixed bar chart custom - step interval for qb v5 (#8806)

* fix: added querytype boolean check for v5 changes

* fix: fixed typechecks

* fix: fixed typechecks

---------

Co-authored-by: ellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com>
2025-08-25 11:15:17 +00:00
Abhi kumar
deddf47e84
fix: added fix for query builder filters (#8830)
* fix: added fix for query builder filters

* fix: added fix for multivalue operator without brackets

* test: added tests for querycontextUtils + querybuilderv2 utils

* fix: added fix for replacing filter with the new value

* fix: added fix for replacing filters + datetimepicker composite query

* test: fixed querybuilderv2 utils test

* chore: added changes for jest to use es6

* test: fixed tests for querycontextutils + querybuilderv2 utils

* test: fixed failing tests
2025-08-25 16:35:16 +05:30
Vishal Sharma
08323e4dfd
chore: update dashboard template links to SigNoz website dashboard template landing page (#8897) 2025-08-25 13:29:55 +05:30
Vibhu Pandey
ee19f1749b
fix(web): fix panic on nil file info (#8907)
fix panic on nil file info
2025-08-25 09:01:32 +05:30
Vikrant Gupta
b21db878e8
chore(meter): added product analytics for meter module (#8898)
* chore(meter): added product analytics for meter package

* chore(meter): added product analytics for meter package
2025-08-24 14:21:45 +05:30
Srikanth Chekuri
a7ddd2ddf0
chore: do not send field context as tag for deprecated fields (#8902) 2025-08-24 11:14:12 +05:30
Srikanth Chekuri
4d72f47758
chore: parse into number alias for mat column from statement (#8900) 2025-08-24 09:44:58 +05:30
Vikrant Gupta
b5b513f1e0
chore(meter): add warnings and make meter live in sidenav (#8882)
* chore(meter): add warnings and make meter live in sidenav

* chore(meter): add warnings and make meter live in sidenav

* chore(meter): add warnings and make meter live in sidenav

* chore(meter): add warnings and make meter live in sidenav

* chore(meter): add warnings and make meter live in sidenav

* chore(meter): add warnings and make meter live in sidenav
2025-08-23 15:00:07 +05:30
Nityananda Gohain
4878f725ea
fix: use lower and convert re2 to string in fulltext (#8887)
* fix: use lower and convert re2 to string in fulltext

* fix: minor error change

* fix: address comments

---------

Co-authored-by: Srikanth Chekuri <srikanth.chekuri92@gmail.com>
2025-08-22 20:20:42 +05:30
Srikanth Chekuri
eca13075e9
fix: related links for rule history page (#8883) 2025-08-22 16:19:27 +05:30
Amlan Kumar Nandy
e5ab664483
fix: resolve sentry issues in alert list (#8878)
* fix: resolve sentry issues in alert list

* chore: update the key

---------

Co-authored-by: srikanthccv <srikanth.chekuri92@gmail.com>
2025-08-21 19:21:15 +05:30
Vibhu Pandey
a3f32b3d85
fix(comment): add a dedicated comment parsing middleware (#8855)
## 📄 Summary

- add a dedicated comment parsing middleware. This removes duplication and double parsing of referrer.
2025-08-20 20:20:28 +05:30
Amlan Kumar Nandy
9c2f127282
chore: backend changes for y-axis management (#8730) 2025-08-20 04:04:50 +00:00
Srikanth Chekuri
e30de5f13e
chore: do not store query name in cache (#8838) 2025-08-19 13:01:55 +05:30
SagarRajput-7
019083983a
fix: added sanity logic for explorer old urls (#8804)
* fix: added sanity logic for explorer old urls

* fix: added test for useSanitizeOrderBy

* fix: added sentry events for orderby validation

* fix: cleanup unused logic and renamed boolean state
2025-08-19 12:46:02 +05:30
Shaheer Kochai
fdcad997f5
feat: trace detail page actionables (#8761)
* feat: add table view with actionables to span details drawer attributes

* feat: span actions functionality

* refactor: overall improvements

* feat: revert to key-value pair UI with hover actions

* feat: add support for copying trace attribute value on click

* refactor: prevent prop drilling and access return values from useTraceActions in AttributeActions

* refactor: integrate filter conversion logic into useTraceActions for improved query handling
2025-08-19 06:50:28 +00:00
Yunus M
03359a40a2
fix: set source on add new query (#8836)
Co-authored-by: Vikrant Gupta <vikrant@signoz.io>
2025-08-19 05:51:33 +00:00
Abhi kumar
4f45801729
fix: added fix for supporting older queries (#8834)
* fix: added fix for supporting older queries

* fix: added fix for exist operator

* chore: minor fix for quick filters

* chore: added tests for convertfilterstoexpression

* chore: added fix for regex to regexp conversion

* test: added test for regex to regexp

* fix: added fix for functions conversion and tests

* fix: added fix for negated non_value_operators
2025-08-19 10:55:45 +05:30
Amlan Kumar Nandy
674556d672
chore: add new y-axis unit selector (#8765) 2025-08-19 04:55:46 +00:00
Amlan Kumar Nandy
af987e53ce
chore: add unit tests for k8s entity details (#8774) 2025-08-19 04:28:39 +00:00
Vikrant Gupta
59d5accd33
fix(meter): meter where clause keys fix (#8833) 2025-08-18 22:57:02 +05:30
manika-signoz
5a7ad670d8
feat: change copy /signup route (#8783)
* feat: change copy /signup route

* feat: remove firstName from payload
2025-08-18 16:48:09 +00:00
Abhi kumar
9d04b397ac
fix: added fix for code block in light mode (#8831) 2025-08-18 22:00:58 +05:30
Vikrant Gupta
a4f3be5e46
feat(meter): add pre-defined panels for meter breakdown and improvements (#8827)
* feat(meter): add pre-defined panels for meter breakdown

* feat(meter): update the routes for future scope

* feat(meter): added graphs for total calculation

* feat(meter): added graphs for total calculation
2025-08-18 19:44:44 +05:30
Srikanth Chekuri
8f833fa62c
fix: incorrect query prepared for group by body.{key} (#8823) 2025-08-18 15:11:53 +05:30
dependabot[bot]
7029233596
chore(deps): bump @babel/runtime from 7.21.0 to 7.28.2 in /frontend (#8726)
Bumps [@babel/runtime](https://github.com/babel/babel/tree/HEAD/packages/babel-runtime) from 7.21.0 to 7.28.2.
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/commits/v7.28.2/packages/babel-runtime)

---
updated-dependencies:
- dependency-name: "@babel/runtime"
  dependency-version: 7.28.2
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-08-18 07:09:52 +00:00
Vibhu Pandey
d26efd2833
feat: address bitnami migration (#8808) 2025-08-14 20:54:28 +05:30
Abhi kumar
0e3ac2a179
fix: added loading indicators in traces pages when running query (#8782) 2025-08-14 13:53:39 +05:30
Amlan Kumar Nandy
249f8be845
fix: resolve infinite loading issue in metric view in messaging queues (#8779) 2025-08-14 04:16:39 +00:00
primus-bot[bot]
9c952942ad
chore(release): bump to v0.92.1 (#8780)
Co-authored-by: primus-bot[bot] <171087277+primus-bot[bot]@users.noreply.github.com>
2025-08-13 15:10:08 +05:30
Nityananda Gohain
dac46d82ff
fix: check ch version (#8778)
Check the clickhouse version, before the setting secondary_indices_enable_bulk_filtering is used.
2025-08-13 14:57:25 +05:30
primus-bot[bot]
802ce6de01
chore(release): bump to v0.92.0 (#8776)
#### Summary
 - Release SigNoz v0.92.0
 - Bump SigNoz OTel Collector to v0.129.0
2025-08-13 12:17:43 +05:30
dependabot[bot]
6853f0c99d
chore(deps): bump urllib3 from 2.4.0 to 2.5.0 in /tests/integration (#8296) 2025-08-13 04:58:39 +00:00
Srikanth Chekuri
3f8a2870e4
fix: key CONTAINS value doesn't work for numeric values (#8768) 2025-08-13 09:59:28 +05:30
Srikanth Chekuri
5fa70ea802
chore: use *_keys tables instead of tag_attributes_v2 for suggestions (#8753) 2025-08-12 18:10:35 +05:30
Yunus M
3a952fa330
fix: pass metric name to get value suggestions api (#8671)
* fix: pass metric name to get value suggestions api

* feat: add source to get value suggestions
2025-08-11 08:10:31 +00:00
Yunus M
6d97db1d9d
fix: use localstorage value to avoid waiting for pref api to set the toggle state, add shortcut (#8751) 2025-08-11 10:26:27 +05:30
Shaheer Kochai
5412e7f70b
feat: show count in span details drawer tabs (#8702)
* feat: show event count in Events tab of SpanDetailsDrawer

* feat: add count badges to all SpanDetailsDrawer tabs
2025-08-10 05:39:20 +00:00
aniketio-ctrl
8e5cb9046d
fix(alert): added querier v5 in test notify (#8749) 2025-08-08 18:01:23 +05:30
Srikanth Chekuri
760eabb2dc
chore: do not return err for meter source temporality (#8750) 2025-08-08 17:39:06 +05:30
Srikanth Chekuri
35ddaaa2fc
chore: add env to override logs keys table name (#8748) 2025-08-08 11:34:09 +00:00
nikhilmantri0902
a51ee66c02
Improvement: Added Otel-collector setup for local dev environment (#8701)
* feat(devenv): add otel-collector support for local development

- Add .devenv/docker/otel-collector/ with compose.yaml and config
- Add devenv-otel-collector and devenv-up targets to Makefile
- Update development.md with otel-collector setup instructions
- Add README.md with usage documentation for otel-collector setup

This enables developers to run the complete SigNoz stack locally,
including the OpenTelemetry Collector for receiving telemetry data
on ports 4317 (gRPC) and 4318 (HTTP).

* docs: improve collector setup wordings

* chore: fixed comment and service name

* chore: docker service name updated otel-collector -> signoz-otel-collector
2025-08-08 16:54:05 +05:30
Yunus M
75d189162b
feat: migrate old saved columns keys to name (#8747) 2025-08-08 14:41:34 +05:30
Yunus M
932918e3a4
feat: meter explorer (#8741)
* feat: meter explorer

* feat: meter explorer

* fix: remove meter as data source

* fix: change meter-explorer to meter - quick filter

* chore: delete test file

* fix: failing test cases
2025-08-08 12:03:26 +05:30
Vibhu Pandey
aa3bc16dcb
test(integration): bump requests to 2.32.4 (#8743) 2025-08-08 00:25:38 +05:30
Yunus M
b5098e00a3
fix: logs explorer - should have atleast 1 column, discard empty key columns (#8740) 2025-08-07 20:17:34 +05:30
Abhi kumar
20dc561bfe
fix: added fix for query becoming empty on time change (#8739) 2025-08-07 19:42:07 +05:30
Nityananda Gohain
99bbb87738
chore: add option to ignore data skipping indices (#8738)
* chore: add option to ignore data skipping indices

* fix: update example
2025-08-07 13:21:17 +00:00
Vikrant Gupta
f1ce93171c
feat(telemetrymeter): add support for telemetry meter (#8667)
* feat(telemetry/meter): added base setup for telemetry meter signal

* feat(telemetry/meter): added metadata setup for meter

* feat(telemetry/meter): fix stmnt builder tests

* feat(telemetry/meter): test query range API fixes

* feat(telemetry/meter): improve error messages

* feat(telemetrymeter): step interval improvements

* feat(telemetrymeter): metadata changes and aggregate attribute changes

* feat(telemetrymeter): metadata changes and aggregate attribute changes

* feat(telemetrymeter): deprecate the signal and use aggregation instead

* feat(telemetrymeter): deprecate the signal and use aggregation instead

* feat(telemetrymeter): deprecate the signal and use aggregation instead

* feat(telemetrymeter): cleanup the types

* feat(telemetrymeter): introduce source for query

* feat(telemetrymeter): better naming for source in metadata

* feat(telemetrymeter): added quick filters for meter explorer

* feat(telemetrymeter): incorporate the new changes to stmnt builder

* feat(telemetrymeter): add the statement builder for the ranged cache queries

* feat(telemetrymeter): use meter aggregate keys

* feat(telemetrymeter): use meter aggregate keys

* feat(telemetrymeter): remove meter from complete bools

* feat(telemetrymeter): remove meter from complete bools

* feat(telemetrymeter): update the quick filters to use meter
2025-08-07 16:50:37 +05:30
Srikanth Chekuri
92794389d6
fix: limit keys for empty search key (#8728) 2025-08-07 00:34:44 +05:30
Srikanth Chekuri
bd02848623
chore: add sql migration for dashboards, alerts, and saved views (#8642)
## 📄 Summary

To reliably migrate the alerts and dashboards, we need access to the telemetrystore to fetch some metadata and while doing migration, I need to log some stuff to fix stuff later.

Key changes:
- Modified the migration to include telemetrystore and a logging provider (open to using a standard logger instead)
- To avoid the previous issues with imported dashboards failing during migration, I've ensured that imported JSON files are automatically transformed when migration is active
- Implemented detailed logic to handle dashboard migration cleanly and prevent unnecessary errors
- Separated the core migration logic from SQL migration code, as users from the dot metrics migration requested shareable code snippets for local migrations. This modular approach allows others to easily reuse the migration functionality.

Known: I didn't register the migration yet in this PR, and will not merge this yet, so please review with that in mid.
2025-08-06 23:05:39 +05:30
Abhi kumar
b5016b061b
fix: added fix for key suggestions (#8727) 2025-08-06 11:48:43 +00:00
Abhi kumar
c308e8668c
fix: added fix for query addon lightmode ui (#8725) 2025-08-06 16:21:35 +05:30
SagarRajput-7
41ee4176ad
fix: fixed metric aggregation and value retention inconsistency in edit mode (#8718) 2025-08-06 13:55:16 +05:30
Abhi kumar
994663110d
fix: added fix for query suggestions position (#8719)
* fix: added fix for query suggestions position

* chore: added box-shadows in the dropdowns
2025-08-06 12:48:07 +05:30
Abhi kumar
3a2eab2019
fixes: includes fixes required in the new QB (#8675)
* fix: removed unused code for querycontext (#8674)

* Update frontend/src/utils/queryValidationUtils.ts

Co-authored-by: ellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com>

* feat: added tooltips in metric aggregations

* feat: enabled legend enhancement for explorer pages and alert page

* feat: updated the error state in explorer pages with new APIError

* fix: cloned panel query shows previous query (#8681)

* fix: cloned panel query shows previous query

* chore: removed comments

* chore: added null check

* fix: added fix for auto run query in dashboard panel + trace view issue

---------

Co-authored-by: Abhi Kumar <abhikumar@Mac.lan>

* feat: added new SubstituteVars api and enable v5 for creating new alerts (#8683)

* feat: added new SubstituteVars api and enable v5 for creating new alerts

* feat: add warning notification for query response

* feat: fixed failing test case

* fix: metric histogram UI config state in edit mode

* fix: fixed table columns getting duplicate data (#8685)

* fix: added fix for conversion of QB function to filter expression. (#8684)

* fix: added fix for QB filters for functions

* chore: minor fix

---------

Co-authored-by: SagarRajput-7 <162284829+SagarRajput-7@users.noreply.github.com>

* feat: query builder fixes and enhancement (#8692)

* feat: legend format fixes around single and multiple aggregation

* feat: fixed table unit and metric units

* feat: add fallbacks to columnWidth and columnUnits for old-dashboards

* feat: fixed metric edit issue and having filter suggestion duplications

* feat: fix and cleanup functions across product for v5

* chore: add tooltips with links to documentation (#8676)

* fix: added fix for query validation and empty query error (#8694)

* fix: added fix for selected columns being empty in logs explorer (#8709)

* feat: added columnUnit changes for old dashboard migrations (#8706)

* fix: fixed keyfetching logic (#8712)

* chore: lint fix

* fix: fixed logs explorer test

* feat: fix type checks

---------

Co-authored-by: ellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com>
Co-authored-by: SagarRajput-7 <sagar@signoz.io>
Co-authored-by: Abhi Kumar <abhikumar@Mac.lan>
Co-authored-by: SagarRajput-7 <162284829+SagarRajput-7@users.noreply.github.com>
Co-authored-by: Srikanth Chekuri <srikanth.chekuri92@gmail.com>
2025-08-06 00:16:20 +05:30
SagarRajput-7
01202b5800
feat: created new error content plugin for QB v5 (#8700)
* feat: created new error content plugin for QB v5

* feat: added warning popover content for QB v5 feature

* feat: icon change for warning

* feat: added warning to QB v5 components

* feat: fixed type error

* feat: fix test cases

---------

Co-authored-by: Srikanth Chekuri <srikanth.chekuri92@gmail.com>
2025-08-05 23:45:39 +05:30
Amlan Kumar Nandy
2901e052ae
chore: improve metrics explorer empty state (#8711) 2025-08-05 20:45:21 +07:00
Amlan Kumar Nandy
372372694e
chore: update home page task tracker for metrics explorer (#8631) 2025-08-05 11:09:31 +05:30
Shaheer Kochai
8e5b1be106
fix: improve the UX of trying to create a funnel with existing name (#8693) 2025-08-05 09:29:52 +04:30
Amlan Kumar Nandy
301d9ca4dd
fix: disabling alert from overview page doesn't work (#8640) 2025-08-05 02:40:19 +00:00
Srikanth Chekuri
f350b0e2f0
chore: add endpoint to replace varibales (#8689) 2025-08-04 21:02:54 +05:30
nikhilmantri0902
090538f11f
docs: add step to cd into frontend directory before yarn commands (#8696) 2025-08-04 08:41:19 +00:00
Shaheer Kochai
db13f85a3c
fix: fix the issue of stale pipeline processor state while switching between different processors (#8661) 2025-08-04 05:58:51 +00:00
Vibhu Pandey
3d874c22b0
chore(resp): add omitempty to timestamp (#8688)
For the requestType: Trace, we don't care about the timestamp in the rawRow. 

- Handling Zero timestamp values in the rawData response
- simplify RawRow `map[string]*any` to `map[string]any` and eliminate unnecessary pointer indirection.
2025-08-03 17:18:51 +05:30
Vibhu Pandey
e68ce11183
test(integration): add traces integration tests (#8666)
- add integration tests for traces listing page
2025-07-31 15:42:34 +05:30
Yunus M
587b0ef6c4
Sign In / Sign Up UI updates (#8562)
* feat: update login page UI

* feat: update login and signup page UI

* chore: font optimization

* feat: update test cases for login

* feat: address review comments

* feat: remove playwright report file

* fix: fix the failing login test

---------

Co-authored-by: ahmadshaheer <ashaheerki@gmail.com>
2025-07-31 13:33:42 +05:30
Yunus M
bb6c366031
feat: new query builder (#8466) 2025-07-31 12:16:55 +05:30
Srikanth Chekuri
5c1f070d8f
chore: use new querier for v5 versioned alerts (#8650) 2025-07-30 19:25:27 +05:30
Vishal Sharma
1ce150d4b0
chore: add unsupported saml list (#8665) 2025-07-30 17:08:27 +05:30
Abhi kumar
f6d96c2118
fix: minor fix for changelog popup to show only when preference is available (#8663) 2025-07-30 15:15:13 +05:30
Yunus M
ff3235bd02
fix: replace column resize with grab icon as the functionality is of reorder (#8662) 2025-07-30 12:19:36 +05:30
Nityananda Gohain
8e9a1b34cb
fix: use correct column names (#8659) 2025-07-30 10:32:58 +05:30
SagarRajput-7
3d80a03f8a
fix: uPlot logarithmic scale range error (#8637)
* fix: uPlot logarithmic scale range error

* fix: removed sanitzation of data
2025-07-30 10:41:12 +07:00
Harshit Raj Sinha
1c650c3c23
fix: adding missing flags to run go-run-community (#8653)
The change adds missing flags required during execution of `make go-run-community`. Currently, running the command cause the error "unknown flag: --config", mentioned in the issue #8623
2025-07-29 23:37:32 +05:30
Ankit Nayan
6b1d62ba8f
feat: enable creating more than 3 steps in trace funnels + enable latency pointer (#8628)
* feat: enable creating more than 3 steps in trace funnels

- Remove 3-step limitation from FunnelContext.tsx addNewStep function
- Remove UI restriction in StepsContent.tsx to always show "Add Funnel Step" button
- Allow unlimited funnel steps while maintaining proper step_order indexing
- Step indexing continues to work correctly for API calls (1-based indexing)

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>

* feat: enable latency pointer configuration with smart defaults (#8629)

- Enable latency pointer dropdown UI in funnel step configuration
- Set step 1 default to 'Start of span' and all other steps to 'End of span'
- Add permission-based controls for latency pointer selection

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-authored-by: Ankit Nayan <ankitnayan@Ankits-MacBook-Pro.local>
Co-authored-by: Claude <noreply@anthropic.com>

---------

Co-authored-by: Ankit Nayan <ankitnayan@Ankits-MacBook-Pro.local>
Co-authored-by: Claude <noreply@anthropic.com>
2025-07-29 22:20:40 +05:30
Ankit Nayan
3c53ba308f
fix: prevent creation of funnels with duplicate names (#8633)
* fix: prevent creation of funnels with duplicate names

- Fixed Update method to validate duplicate names before updating
- Added proper duplicate name validation that excludes the current funnel being updated
- Fixed incorrect error wrapping in Update method that was marking all errors as "already exists"
- Fixed typo in error message ("funnelr" -> "funnel")
- Added comprehensive tests for duplicate name validation in both Create and Update operations
- Used internal errors package for consistent error handling

The funnel API now properly prevents creating or updating funnels with duplicate names
within the same organization, resolving issues where duplicate funnels could be created
but would fail during retrieval.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>

* fix: returning error instance

* fix: implement database transactions for funnel creation and updates

- Wrap check-and-create operations in Bun transactions to prevent race conditions
- Apply transaction pattern to both Create() and Update() methods
- Ensures atomic operations when checking for duplicate funnel names
- Prevents concurrent requests from creating duplicate funnels
- Follows existing transaction patterns from user store implementation

Addresses PR feedback for race condition prevention

---------

Co-authored-by: Ankit Nayan <ankitnayan@Ankits-MacBook-Pro.local>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Shaheer Kochai <ashaheerki@gmail.com>
2025-07-29 22:04:06 +05:30
Ankit Nayan
f2abddd2ed
feat: refactor tracefunnel to support dynamic multi-step funnels (#8627)
* feat: refactor tracefunnel to support dynamic multi-step funnels

Replace hardcoded 2-step and 3-step funnel functions with dynamic
implementations that support unlimited steps. Add comprehensive tests
for multi-step funnel functionality while maintaining backward
compatibility.

Key changes:
- Add dynamic query builders for n-step funnels
- Update all query functions to use new builders
- Remove old hardcoded functions
- Add tests for 1-6 step funnels
- Maintain temporal ordering logic

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>

* feat: add duration calculation for latency_pointer='end' in funnel qu… (#8632)

* feat: add duration calculation for latency_pointer='end' in funnel queries

- Updated BuildFunnelOverviewQuery and BuildFunnelStepOverviewQuery to calculate end time
  when latency_pointer is 'end'
- Modified BuildFunnelTopSlowTracesQuery and BuildFunnelTopSlowErrorTracesQuery to support
  latency pointer parameters
- Added comprehensive tests for latency pointer functionality in
  clickhouse_queries_latency_test.go
- When latency_pointer is 'end', the query now adds span duration to timestamp for
  accurate latency calculations

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>

* do matching after lowercase conversion

Co-authored-by: ellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com>

---------

Co-authored-by: Ankit Nayan <ankitnayan@Ankits-MacBook-Pro.local>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: ellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com>

* fix: apply remaining changes from PR #8615 for ClickHouse 25.5 compatibility

- Updated BuildTracesFilter to BuildTracesFilterQuery with false parameter in query.go
- Updated test files to expect resource_string_service$$name instead of serviceName
- Fixed function reference in query_test.go

These changes complete the ClickHouse 25.5 compatibility updates while maintaining
the dynamic multi-step funnel functionality.

* fix: replace durationNano with duration_nano for ClickHouse compatibility

- Updated all SQL queries in clickhouse_queries.go to use duration_nano column name
- Updated test expectations in clickhouse_queries_latency_test.go
- Ensures consistency with ClickHouse snake_case column naming convention

* refactor: code formatting and add TODO comment

- Remove trailing whitespace in query.go
- Add TODO comment for GetErroredTraces function regarding product improvement
- Add newline at end of file for proper formatting

---------

Co-authored-by: Ankit Nayan <ankitnayan@Ankits-MacBook-Pro.local>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: ellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com>
2025-07-29 16:18:15 +00:00
Shaheer Kochai
f53a13e7fa
chore: write test for recalculating timestamps on clicking stage and run in logs explorer (#8581) 2025-07-29 15:51:54 +00:00
Shaheer Kochai
b69ac637c3
fix: fix the pipeline processor re-ordering issue (#8646) 2025-07-29 15:38:19 +00:00
Vibhu Pandey
a3c039006f
chore(goreleaser): fix main path (#8654)
#### Chores

- Fix main path in goreleaser
2025-07-29 13:31:08 +00:00
Shaheer Kochai
2141b1b90a
feat: enhance logs explorer chart to display full selected time window (#8446)
* feat: enhance logs explorer chart to display full selected time window

* fix: don't show tooltip in logs chart on empty hover areas + lint fix

---------

Co-authored-by: Nityananda Gohain <nityanandagohain@gmail.com>
2025-07-29 12:30:34 +00:00
aniketio-ctrl
771ba45d01
Chore/added_ilike : added ilike and notIlike filter operator (#8595)
* chore(added-ilike): added ilike operator in qbv5

* chore(added-ilike): added test cases
2025-07-29 11:58:25 +00:00
Nageshbansal
7df5c33ce9
chore: adds advocate.md for community advocate program (#8648) 2025-07-29 11:42:00 +00:00
Vibhu Pandey
537c95e05a
test(integration): add or filter with resource attributes (#8651) 2025-07-29 16:33:11 +05:30
Srikanth Chekuri
7d9e0523c9
chore: add anomaly to v5 response (#8643) 2025-07-29 10:00:28 +00:00
aniketio-ctrl
360285ef33
fix(added-backticks): added backticks for hyphen (#8644)
* fix(added-backticks): added backticks for hyphen also

* Update pkg/query-service/utils/format.go

Co-authored-by: ellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com>

---------

Co-authored-by: ellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com>
2025-07-29 09:49:28 +00:00
Vibhu Pandey
c17241272f
test(integration): add integration tests for logs (#8619) 2025-07-29 14:44:16 +05:30
Yunus M
fa936a7e0d
fix: open log details on clicking on empty column cell too (#8618) 2025-07-29 14:06:13 +05:30
SagarRajput-7
498d398ea3
chore: resolved conflicting npm-form-data version requirement (#8645) 2025-07-29 11:25:01 +05:30
Srikanth Chekuri
8b2ed674a4
chore: add alert link visitor for expression link (#8641) 2025-07-28 17:44:58 +00:00
Srikanth Chekuri
9a06603ff3
chore: add event for query range v5 (#8639)
I am also using the referrer to derive the information, as it requires some development effort to have the frontend send this information.
2025-07-28 17:35:44 +00:00
Abhi kumar
4888491a79
fix: added fix for changelog modal auto popup for new users (#8634)
* fix: added fix for changelog modal auto popup for new users

* fix: removed custom logic for diff calculation

* chore: minor PR reviews
2025-07-28 21:59:37 +05:30
Srikanth Chekuri
7c9f05c2cc
chore: order time series result set (#8638)
## 📄 Summary

- Fix the order by for the time series result
- Add the statement builder for trace query (was supposed to be replaced with new development but that never happened, so we continue the old table)
- Removed `pkg/types/telemetrytypes/virtualfield.go`, not used currently anywhere but causing circular import. Will re-introduce later.
2025-07-28 21:42:56 +05:30
Amlan Kumar Nandy
160802fe11
fix: prefill alert conditions only if no condition are already set (#8636) 2025-07-28 14:30:57 +00:00
Nityananda Gohain
86057cad9f
fix: changes in code to support ch 25.5 (#8615)
* fix: changes in code to support ch 25.5

* fix: address comments

* fix: make changes in funnels
2025-07-28 19:49:52 +05:30
Abhi kumar
210393e281
Fix: Minor UI fixes in changelog + sidebar (#8625)
* fix: removed feature count from changelog modal

* fix: sidenav width fix

* chore: added arrows in external link

* fix: refetch condition fix

* fix: added changes for not showing changelogmodal to restricted users

* chore: minor changes
2025-07-27 18:30:02 +05:30
Yunus M
e96ed433fe
chore: update e2e github action and playwright config (#8624)
* chore: update e2e github action and playwright config

* chore: update e2e github action and playwright config
2025-07-27 16:59:17 +05:30
Yunus M
52636284fc
feat: update env variable names (#8621) 2025-07-26 11:46:44 +00:00
Yunus M
2639f975ee
Update run-e2e.yaml (#8620) 2025-07-26 11:07:31 +00:00
Yunus M
f9db796489
feat: settings e2e sanity test cases (#8613)
* feat: generate e2e test plan and tests using playwright mcp

* feat: settings e2e sanity test cases

* feat: playwright prettier

* feat: update the gitignore file temporarily exclude test plans

* chore: remove e2e test-plan directories from git tracking and update .gitignore

* chore: remove playwright github action from frontend repo

* chore: update base url in playwright config

* chore: add github action to run playwright tests

* chore: wrap env variables in quotes and enable uploading test results always

* chore: update github action

* chore: update github action

* Update run-e2e.yaml

* Update run-e2e.yaml

* feat: update github action
2025-07-26 16:08:47 +05:30
Vibhu Pandey
65018abc4a
fix(community): fix injection of alertmanager (#8612) 2025-07-25 13:58:56 +05:30
SagarRajput-7
43706f877a
chore: upgraded typescript-plugin-css-modules package to latest and remove stylus resolution (#8611) 2025-07-25 12:41:21 +05:30
Yunus M
d7fdbcd90d
feat: open entities in new tab on ctrl / cmd + click (#8607)
* feat: open entities in new tab on ctrl / cmd + click

* feat: open entities in new tab on ctrl / cmd + click
2025-07-25 11:08:12 +05:30
Amlan Kumar Nandy
db0f362482
chore: fix sentry issues in alerts and infra monitoring (#8566) 2025-07-24 14:30:47 +00:00
Yunus M
db440a6eb4
feat: alert module ui improvements (#8572)
* feat: alert module ui improvements

* feat: update something went wrong page

* feat: remove safe navigate hook usage in ErrorBoundaryFallback
2025-07-24 13:40:48 +00:00
Yunus M
76b58b7317
feat: show success message with note to notify user on role change (#8491) 2025-07-24 19:01:17 +05:30
primus-bot[bot]
bba3e95914
chore(release): bump to v0.91.0 (#8596)
Co-authored-by: primus-bot[bot] <171087277+primus-bot[bot]@users.noreply.github.com>
2025-07-24 12:20:10 +05:30
1500 changed files with 129122 additions and 19259 deletions

View File

@ -1,6 +1,6 @@
services:
clickhouse:
image: clickhouse/clickhouse-server:24.1.2-alpine
image: clickhouse/clickhouse-server:25.5.6
container_name: clickhouse
volumes:
- ${PWD}/fs/etc/clickhouse-server/config.d/config.xml:/etc/clickhouse-server/config.d/config.xml
@ -23,8 +23,10 @@ services:
retries: 3
depends_on:
- zookeeper
environment:
- CLICKHOUSE_SKIP_USER_SETUP=1
zookeeper:
image: bitnami/zookeeper:3.7.1
image: signoz/zookeeper:3.7.1
container_name: zookeeper
volumes:
- ${PWD}/fs/tmp/zookeeper:/bitnami/zookeeper
@ -40,7 +42,7 @@ services:
timeout: 5s
retries: 3
schema-migrator-sync:
image: signoz/signoz-schema-migrator:v0.128.2
image: signoz/signoz-schema-migrator:v0.129.6
container_name: schema-migrator-sync
command:
- sync
@ -53,7 +55,7 @@ services:
condition: service_healthy
restart: on-failure
schema-migrator-async:
image: signoz/signoz-schema-migrator:v0.128.2
image: signoz/signoz-schema-migrator:v0.129.6
container_name: schema-migrator-async
command:
- async

View File

@ -0,0 +1,29 @@
services:
signoz-otel-collector:
image: signoz/signoz-otel-collector:v0.129.6
container_name: signoz-otel-collector-dev
command:
- --config=/etc/otel-collector-config.yaml
- --feature-gates=-pkg.translator.prometheus.NormalizeName
volumes:
- ./otel-collector-config.yaml:/etc/otel-collector-config.yaml
environment:
- OTEL_RESOURCE_ATTRIBUTES=host.name=signoz-host,os.type=linux
- LOW_CARDINAL_EXCEPTION_GROUPING=false
ports:
- "4317:4317" # OTLP gRPC receiver
- "4318:4318" # OTLP HTTP receiver
- "13133:13133" # health check extension
healthcheck:
test:
- CMD
- wget
- --spider
- -q
- localhost:13133
interval: 30s
timeout: 5s
retries: 3
restart: unless-stopped
extra_hosts:
- "host.docker.internal:host-gateway"

View File

@ -0,0 +1,96 @@
receivers:
otlp:
protocols:
grpc:
endpoint: 0.0.0.0:4317
http:
endpoint: 0.0.0.0:4318
prometheus:
config:
global:
scrape_interval: 60s
scrape_configs:
- job_name: otel-collector
static_configs:
- targets:
- localhost:8888
labels:
job_name: otel-collector
processors:
batch:
send_batch_size: 10000
send_batch_max_size: 11000
timeout: 10s
resourcedetection:
# Using OTEL_RESOURCE_ATTRIBUTES envvar, env detector adds custom labels.
detectors: [env, system]
timeout: 2s
signozspanmetrics/delta:
metrics_exporter: signozclickhousemetrics
metrics_flush_interval: 60s
latency_histogram_buckets: [100us, 1ms, 2ms, 6ms, 10ms, 50ms, 100ms, 250ms, 500ms, 1000ms, 1400ms, 2000ms, 5s, 10s, 20s, 40s, 60s ]
dimensions_cache_size: 100000
aggregation_temporality: AGGREGATION_TEMPORALITY_DELTA
enable_exp_histogram: true
dimensions:
- name: service.namespace
default: default
- name: deployment.environment
default: default
# This is added to ensure the uniqueness of the timeseries
# Otherwise, identical timeseries produced by multiple replicas of
# collectors result in incorrect APM metrics
- name: signoz.collector.id
- name: service.version
- name: browser.platform
- name: browser.mobile
- name: k8s.cluster.name
- name: k8s.node.name
- name: k8s.namespace.name
- name: host.name
- name: host.type
- name: container.name
extensions:
health_check:
endpoint: 0.0.0.0:13133
pprof:
endpoint: 0.0.0.0:1777
exporters:
clickhousetraces:
datasource: tcp://host.docker.internal:9000/signoz_traces
low_cardinal_exception_grouping: ${env:LOW_CARDINAL_EXCEPTION_GROUPING}
use_new_schema: true
signozclickhousemetrics:
dsn: tcp://host.docker.internal:9000/signoz_metrics
clickhouselogsexporter:
dsn: tcp://host.docker.internal:9000/signoz_logs
timeout: 10s
use_new_schema: true
service:
telemetry:
logs:
encoding: json
extensions:
- health_check
- pprof
pipelines:
traces:
receivers: [otlp]
processors: [signozspanmetrics/delta, batch]
exporters: [clickhousetraces]
metrics:
receivers: [otlp]
processors: [batch]
exporters: [signozclickhousemetrics]
metrics/prometheus:
receivers: [prometheus]
processors: [batch]
exporters: [signozclickhousemetrics]
logs:
receivers: [otlp]
processors: [batch]
exporters: [clickhouselogsexporter]

43
.github/CODEOWNERS vendored
View File

@ -5,6 +5,45 @@
/frontend/ @SigNoz/frontend @YounixM
/frontend/src/container/MetricsApplication @srikanthccv
/frontend/src/container/NewWidget/RightContainer/types.ts @srikanthccv
# Dashboard, Alert, Metrics, Service Map, Services
/frontend/src/container/ListOfDashboard/ @srikanthccv
/frontend/src/container/NewDashboard/ @srikanthccv
/frontend/src/pages/DashboardsListPage/ @srikanthccv
/frontend/src/pages/DashboardWidget/ @srikanthccv
/frontend/src/pages/NewDashboard/ @srikanthccv
/frontend/src/providers/Dashboard/ @srikanthccv
# Alerts
/frontend/src/container/AlertHistory/ @srikanthccv
/frontend/src/container/AllAlertChannels/ @srikanthccv
/frontend/src/container/AnomalyAlertEvaluationView/ @srikanthccv
/frontend/src/container/CreateAlertChannels/ @srikanthccv
/frontend/src/container/CreateAlertRule/ @srikanthccv
/frontend/src/container/EditAlertChannels/ @srikanthccv
/frontend/src/container/FormAlertChannels/ @srikanthccv
/frontend/src/container/FormAlertRules/ @srikanthccv
/frontend/src/container/ListAlertRules/ @srikanthccv
/frontend/src/container/TriggeredAlerts/ @srikanthccv
/frontend/src/pages/AlertChannelCreate/ @srikanthccv
/frontend/src/pages/AlertDetails/ @srikanthccv
/frontend/src/pages/AlertHistory/ @srikanthccv
/frontend/src/pages/AlertList/ @srikanthccv
/frontend/src/pages/CreateAlert/ @srikanthccv
/frontend/src/providers/Alert.tsx @srikanthccv
# Metrics
/frontend/src/container/MetricsExplorer/ @srikanthccv
/frontend/src/pages/MetricsApplication/ @srikanthccv
/frontend/src/pages/MetricsExplorer/ @srikanthccv
# Services and Service Map
/frontend/src/container/ServiceApplication/ @srikanthccv
/frontend/src/container/ServiceTable/ @srikanthccv
/frontend/src/pages/Services/ @srikanthccv
/frontend/src/pages/ServiceTopLevelOperations/ @srikanthccv
/frontend/src/container/Home/Services/ @srikanthccv
/deploy/ @SigNoz/devops
.github @SigNoz/devops
@ -42,3 +81,7 @@
/pkg/telemetrymetadata/ @srikanthccv
/pkg/telemetrymetrics/ @srikanthccv
/pkg/telemetrytraces/ @srikanthccv
# AuthN / AuthZ Owners
/pkg/authz/ @vikrantgupta25 @grandwizard28

View File

@ -62,7 +62,7 @@ jobs:
secrets: inherit
with:
PRIMUS_REF: main
GO_VERSION: 1.23
GO_VERSION: 1.24
GO_NAME: signoz-community
GO_INPUT_ARTIFACT_CACHE_KEY: community-jsbuild-${{ github.sha }}
GO_INPUT_ARTIFACT_PATH: frontend/build

View File

@ -93,7 +93,7 @@ jobs:
secrets: inherit
with:
PRIMUS_REF: main
GO_VERSION: 1.23
GO_VERSION: 1.24
GO_INPUT_ARTIFACT_CACHE_KEY: enterprise-jsbuild-${{ github.sha }}
GO_INPUT_ARTIFACT_PATH: frontend/build
GO_BUILD_CONTEXT: ./cmd/enterprise

View File

@ -92,7 +92,7 @@ jobs:
secrets: inherit
with:
PRIMUS_REF: main
GO_VERSION: 1.23
GO_VERSION: 1.24
GO_INPUT_ARTIFACT_CACHE_KEY: staging-jsbuild-${{ github.sha }}
GO_INPUT_ARTIFACT_PATH: frontend/build
GO_BUILD_CONTEXT: ./cmd/enterprise

View File

@ -18,7 +18,7 @@ jobs:
with:
PRIMUS_REF: main
GO_TEST_CONTEXT: ./...
GO_VERSION: 1.23
GO_VERSION: 1.24
fmt:
if: |
(github.event_name == 'pull_request' && ! github.event.pull_request.head.repo.fork && github.event.pull_request.user.login != 'dependabot[bot]' && ! contains(github.event.pull_request.labels.*.name, 'safe-to-test')) ||
@ -27,7 +27,7 @@ jobs:
secrets: inherit
with:
PRIMUS_REF: main
GO_VERSION: 1.23
GO_VERSION: 1.24
lint:
if: |
(github.event_name == 'pull_request' && ! github.event.pull_request.head.repo.fork && github.event.pull_request.user.login != 'dependabot[bot]' && ! contains(github.event.pull_request.labels.*.name, 'safe-to-test')) ||
@ -36,7 +36,7 @@ jobs:
secrets: inherit
with:
PRIMUS_REF: main
GO_VERSION: 1.23
GO_VERSION: 1.24
deps:
if: |
(github.event_name == 'pull_request' && ! github.event.pull_request.head.repo.fork && github.event.pull_request.user.login != 'dependabot[bot]' && ! contains(github.event.pull_request.labels.*.name, 'safe-to-test')) ||
@ -45,7 +45,7 @@ jobs:
secrets: inherit
with:
PRIMUS_REF: main
GO_VERSION: 1.23
GO_VERSION: 1.24
build:
if: |
(github.event_name == 'pull_request' && ! github.event.pull_request.head.repo.fork && github.event.pull_request.user.login != 'dependabot[bot]' && ! contains(github.event.pull_request.labels.*.name, 'safe-to-test')) ||
@ -57,7 +57,7 @@ jobs:
- name: go-install
uses: actions/setup-go@v5
with:
go-version: "1.23"
go-version: "1.24"
- name: qemu-install
uses: docker/setup-qemu-action@v3
- name: aarch64-install

View File

@ -58,7 +58,7 @@ jobs:
- name: setup-go
uses: actions/setup-go@v5
with:
go-version: "1.23"
go-version: "1.24"
- name: cross-compilation-tools
if: matrix.os == 'ubuntu-latest'
run: |
@ -122,7 +122,7 @@ jobs:
- name: setup-go
uses: actions/setup-go@v5
with:
go-version: "1.23"
go-version: "1.24"
# copy the caches from build
- name: get-sha

View File

@ -72,7 +72,7 @@ jobs:
- name: setup-go
uses: actions/setup-go@v5
with:
go-version: "1.23"
go-version: "1.24"
- name: cross-compilation-tools
if: matrix.os == 'ubuntu-latest'
run: |
@ -135,7 +135,7 @@ jobs:
- name: setup-go
uses: actions/setup-go@v5
with:
go-version: "1.23"
go-version: "1.24"
# copy the caches from build
- name: get-sha

View File

@ -15,14 +15,15 @@ jobs:
matrix:
src:
- bootstrap
- auth
- querier
sqlstore-provider:
- postgres
- sqlite
clickhouse-version:
- 24.1.2-alpine
- 25.5.6
schema-migrator-version:
- v0.128.1
- v0.129.6
postgres-version:
- 15
if: |

62
.github/workflows/run-e2e.yaml vendored Normal file
View File

@ -0,0 +1,62 @@
name: e2eci
on:
workflow_dispatch:
inputs:
userRole:
description: "Role of the user (ADMIN, EDITOR, VIEWER)"
required: true
type: choice
options:
- ADMIN
- EDITOR
- VIEWER
jobs:
test:
name: Run Playwright Tests
runs-on: ubuntu-latest
timeout-minutes: 60
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: lts/*
- name: Mask secrets and input
run: |
echo "::add-mask::${{ secrets.BASE_URL }}"
echo "::add-mask::${{ secrets.LOGIN_USERNAME }}"
echo "::add-mask::${{ secrets.LOGIN_PASSWORD }}"
echo "::add-mask::${{ github.event.inputs.userRole }}"
- name: Install dependencies
working-directory: frontend
run: |
npm install -g yarn
yarn
- name: Install Playwright Browsers
working-directory: frontend
run: yarn playwright install --with-deps
- name: Run Playwright Tests
working-directory: frontend
run: |
BASE_URL="${{ secrets.BASE_URL }}" \
LOGIN_USERNAME="${{ secrets.LOGIN_USERNAME }}" \
LOGIN_PASSWORD="${{ secrets.LOGIN_PASSWORD }}" \
USER_ROLE="${{ github.event.inputs.userRole }}" \
yarn playwright test
- name: Upload Playwright Report
uses: actions/upload-artifact@v4
if: always()
with:
name: playwright-report
path: frontend/playwright-report/
retention-days: 30

6
.gitignore vendored
View File

@ -86,6 +86,8 @@ queries.active
.devenv/**/tmp/**
.qodo
.dev
### Python ###
# Byte-compiled / optimized / DLL files
__pycache__/
@ -228,4 +230,6 @@ poetry.toml
# LSP config files
pyrightconfig.json
# End of https://www.toptal.com/developers/gitignore/api/python
# cursor files
frontend/.cursor/

View File

@ -8,6 +8,7 @@ linters:
- depguard
- iface
- unparam
- forbidigo
linters-settings:
sloglint:
@ -24,6 +25,10 @@ linters-settings:
deny:
- pkg: "go.uber.org/zap"
desc: "Do not use zap logger. Use slog instead."
noerrors:
deny:
- pkg: "errors"
desc: "Do not use errors package. Use github.com/SigNoz/signoz/pkg/errors instead."
iface:
enable:
- identical

62
ADVOCATE.md Normal file
View File

@ -0,0 +1,62 @@
# SigNoz Community Advocate Program
Our community is filled with passionate developers who love SigNoz and have been helping spread the word about observability across the world. The SigNoz Community Advocate Program is our way of recognizing these incredible community members and creating deeper collaboration opportunities.
## What is the SigNoz Community Advocate Program?
The SigNoz Community Advocate Program celebrates and supports community members who are already passionate about observability and helping fellow developers. If you're someone who loves discussing SigNoz, helping others with their implementations, or sharing knowledge about observability practices, this program is designed with you in mind.
Our advocates are the heart of the SigNoz community, helping other developers succeed with observability and providing valuable insights that help us build better products.
## What Do Advocates Do?
1. **Community Support**
- Help fellow developers in our Slack community and GitHub Discussions
- Answer questions and share solutions
- Guide newcomers through SigNoz self-host implementations
2. **Knowledge Sharing**
- Spread awareness about observability best practices on developer forums
- Create content like blog posts, social media posts, and videos
- Host local meetups and events in their regions
3. **Product Collaboration**
- Provide insights on features, changes, and improvements the community needs
- Beta test new features and provide early feedback
- Help us understand real-world use cases and pain points
## What's In It For You?
**Recognition & Swag**
- Official recognition as a SigNoz advocate
- Welcome hamper upon joining
- Exclusive swag box within your first 3 months
- Feature on our website (with your permission)
**Early Access**
- First look at new features and updates
- Direct line to the SigNoz team for feedback and suggestions
- Opportunity to influence product roadmap
**Community Impact**
- Help shape the observability landscape
- Build your reputation in the developer community
- Connect with like-minded developers globally
## How Does It Work?
Currently, the SigNoz Community Advocate Program is **invite-only**. We're starting with a small group of passionate community members who have already been making a difference.
We'll be working closely with our first advocates to shape the program details, benefits, and structure based on what works best for everyone involved.
If you're interested in learning more about the program or want to get more involved in the SigNoz community, join our [Slack community](https://signoz-community.slack.com/) and let us know!
---
*The SigNoz Community Advocate Program recognizes and celebrates the amazing community members who are already passionate about helping fellow developers succeed with observability.*

View File

@ -78,3 +78,5 @@ Need assistance? Join our Slack community:
- Set up your [development environment](docs/contributing/development.md)
- Deploy and observe [SigNoz in action with OpenTelemetry Demo Application](docs/otel-demo-docs.md)
- Explore the [SigNoz Community Advocate Program](ADVOCATE.md), which recognises contributors who support the community, share their expertise, and help shape SigNoz's future.
- Write [integration tests](docs/contributing/go/integration.md)

View File

@ -61,6 +61,17 @@ devenv-postgres: ## Run postgres in devenv
@cd .devenv/docker/postgres; \
docker compose -f compose.yaml up -d
.PHONY: devenv-signoz-otel-collector
devenv-signoz-otel-collector: ## Run signoz-otel-collector in devenv (requires clickhouse to be running)
@cd .devenv/docker/signoz-otel-collector; \
docker compose -f compose.yaml up -d
.PHONY: devenv-up
devenv-up: devenv-clickhouse devenv-signoz-otel-collector ## Start both clickhouse and signoz-otel-collector for local development
@echo "Development environment is ready!"
@echo " - ClickHouse: http://localhost:8123"
@echo " - Signoz OTel Collector: grpc://localhost:4317, http://localhost:4318"
##############################################################
# go commands
##############################################################
@ -92,7 +103,7 @@ go-run-community: ## Runs the community go backend server
SIGNOZ_TELEMETRYSTORE_PROVIDER=clickhouse \
SIGNOZ_TELEMETRYSTORE_CLICKHOUSE_DSN=tcp://127.0.0.1:9000 \
go run -race \
$(GO_BUILD_CONTEXT_COMMUNITY)/*.go \
$(GO_BUILD_CONTEXT_COMMUNITY)/*.go server \
--config ./conf/prometheus.yml \
--cluster cluster

View File

@ -11,7 +11,7 @@ before:
builds:
- id: signoz
binary: bin/signoz
main: cmd/community
main: ./cmd/community
env:
- CGO_ENABLED=1
- >-

View File

@ -32,7 +32,7 @@ func registerServer(parentCmd *cobra.Command, logger *slog.Logger) {
Short: "Run the SigNoz server",
FParseErrWhitelist: cobra.FParseErrWhitelist{UnknownFlags: true},
RunE: func(currCmd *cobra.Command, args []string) error {
config, err := cmd.NewSigNozConfig(currCmd.Context(), flags)
config, err := cmd.NewSigNozConfig(currCmd.Context(), logger, flags)
if err != nil {
return err
}

View File

@ -2,7 +2,6 @@ package cmd
import (
"context"
"fmt"
"log/slog"
"os"
@ -12,9 +11,10 @@ import (
"github.com/SigNoz/signoz/pkg/signoz"
)
func NewSigNozConfig(ctx context.Context, flags signoz.DeprecatedFlags) (signoz.Config, error) {
func NewSigNozConfig(ctx context.Context, logger *slog.Logger, flags signoz.DeprecatedFlags) (signoz.Config, error) {
config, err := signoz.NewConfig(
ctx,
logger,
config.ResolverConfig{
Uris: []string{"env:"},
ProviderFactories: []config.ProviderFactory{
@ -31,14 +31,10 @@ func NewSigNozConfig(ctx context.Context, flags signoz.DeprecatedFlags) (signoz.
return config, nil
}
func NewJWTSecret(_ context.Context, _ *slog.Logger) string {
func NewJWTSecret(ctx context.Context, logger *slog.Logger) string {
jwtSecret := os.Getenv("SIGNOZ_JWT_SECRET")
if len(jwtSecret) == 0 {
fmt.Println("🚨 CRITICAL SECURITY ISSUE: No JWT secret key specified!")
fmt.Println("SIGNOZ_JWT_SECRET environment variable is not set. This has dire consequences for the security of the application.")
fmt.Println("Without a JWT secret, user sessions are vulnerable to tampering and unauthorized access.")
fmt.Println("Please set the SIGNOZ_JWT_SECRET environment variable immediately.")
fmt.Println("For more information, please refer to https://github.com/SigNoz/signoz/issues/8400.")
logger.ErrorContext(ctx, "🚨 CRITICAL SECURITY ISSUE: No JWT secret key specified!", "error", "SIGNOZ_JWT_SECRET environment variable is not set. This has dire consequences for the security of the application. Without a JWT secret, user sessions are vulnerable to tampering and unauthorized access. Please set the SIGNOZ_JWT_SECRET environment variable immediately. For more information, please refer to https://github.com/SigNoz/signoz/issues/8400.")
}
return jwtSecret

View File

@ -11,7 +11,7 @@ before:
builds:
- id: signoz
binary: bin/signoz
main: cmd/enterprise
main: ./cmd/enterprise
env:
- CGO_ENABLED=1
- >-

View File

@ -1,4 +1,12 @@
FROM golang:1.23-bullseye
FROM node:18-bullseye AS build
WORKDIR /opt/
COPY ./frontend/ ./
ENV NODE_OPTIONS=--max-old-space-size=8192
RUN CI=1 yarn install
RUN CI=1 yarn build
FROM golang:1.24-bullseye
ARG OS="linux"
ARG TARGETARCH
@ -32,6 +40,8 @@ COPY Makefile Makefile
RUN TARGET_DIR=/root ARCHS=${TARGETARCH} ZEUS_URL=${ZEUSURL} LICENSE_URL=${ZEUSURL}/api/v1 make go-build-enterprise-race
RUN mv /root/linux-${TARGETARCH}/signoz /root/signoz
COPY --from=build /opt/build ./web/
RUN chmod 755 /root /root/signoz
ENTRYPOINT ["/root/signoz", "server"]

View File

@ -35,7 +35,7 @@ func registerServer(parentCmd *cobra.Command, logger *slog.Logger) {
Short: "Run the SigNoz server",
FParseErrWhitelist: cobra.FParseErrWhitelist{UnknownFlags: true},
RunE: func(currCmd *cobra.Command, args []string) error {
config, err := cmd.NewSigNozConfig(currCmd.Context(), flags)
config, err := cmd.NewSigNozConfig(currCmd.Context(), logger, flags)
if err != nil {
return err
}

View File

@ -121,6 +121,8 @@ telemetrystore:
timeout_before_checking_execution_speed: 0
max_bytes_to_read: 0
max_result_rows: 0
ignore_data_skipping_indices: ""
secondary_indices_enable_bulk_filtering: false
##################### Prometheus #####################
prometheus:
@ -135,10 +137,7 @@ prometheus:
##################### Alertmanager #####################
alertmanager:
# Specifies the alertmanager provider to use.
provider: legacy
legacy:
# The API URL (with prefix) of the legacy Alertmanager instance.
api_url: http://localhost:9093/api
provider: signoz
signoz:
# The poll interval for periodically syncing the alertmanager with the config in the store.
poll_interval: 1m

View File

@ -11,7 +11,7 @@ x-common: &common
max-file: "3"
x-clickhouse-defaults: &clickhouse-defaults
!!merge <<: *common
image: clickhouse/clickhouse-server:24.1.2-alpine
image: clickhouse/clickhouse-server:25.5.6
tty: true
deploy:
labels:
@ -37,9 +37,11 @@ x-clickhouse-defaults: &clickhouse-defaults
nofile:
soft: 262144
hard: 262144
environment:
- CLICKHOUSE_SKIP_USER_SETUP=1
x-zookeeper-defaults: &zookeeper-defaults
!!merge <<: *common
image: bitnami/zookeeper:3.7.1
image: signoz/zookeeper:3.7.1
user: root
deploy:
labels:
@ -63,7 +65,7 @@ x-db-depend: &db-depend
services:
init-clickhouse:
!!merge <<: *common
image: clickhouse/clickhouse-server:24.1.2-alpine
image: clickhouse/clickhouse-server:25.5.6
command:
- bash
- -c
@ -174,7 +176,7 @@ services:
# - ../common/clickhouse/storage.xml:/etc/clickhouse-server/config.d/storage.xml
signoz:
!!merge <<: *db-depend
image: signoz/signoz:v0.90.1
image: signoz/signoz:v0.96.1
command:
- --config=/root/config/prometheus.yml
ports:
@ -207,7 +209,7 @@ services:
retries: 3
otel-collector:
!!merge <<: *db-depend
image: signoz/signoz-otel-collector:v0.128.2
image: signoz/signoz-otel-collector:v0.129.6
command:
- --config=/etc/otel-collector-config.yaml
- --manager-config=/etc/manager-config.yaml
@ -231,7 +233,7 @@ services:
- signoz
schema-migrator:
!!merge <<: *common
image: signoz/signoz-schema-migrator:v0.128.2
image: signoz/signoz-schema-migrator:v0.129.6
deploy:
restart_policy:
condition: on-failure

View File

@ -11,7 +11,7 @@ x-common: &common
max-file: "3"
x-clickhouse-defaults: &clickhouse-defaults
!!merge <<: *common
image: clickhouse/clickhouse-server:24.1.2-alpine
image: clickhouse/clickhouse-server:25.5.6
tty: true
deploy:
labels:
@ -36,9 +36,11 @@ x-clickhouse-defaults: &clickhouse-defaults
nofile:
soft: 262144
hard: 262144
environment:
- CLICKHOUSE_SKIP_USER_SETUP=1
x-zookeeper-defaults: &zookeeper-defaults
!!merge <<: *common
image: bitnami/zookeeper:3.7.1
image: signoz/zookeeper:3.7.1
user: root
deploy:
labels:
@ -60,7 +62,7 @@ x-db-depend: &db-depend
services:
init-clickhouse:
!!merge <<: *common
image: clickhouse/clickhouse-server:24.1.2-alpine
image: clickhouse/clickhouse-server:25.5.6
command:
- bash
- -c
@ -115,7 +117,7 @@ services:
# - ../common/clickhouse/storage.xml:/etc/clickhouse-server/config.d/storage.xml
signoz:
!!merge <<: *db-depend
image: signoz/signoz:v0.90.1
image: signoz/signoz:v0.96.1
command:
- --config=/root/config/prometheus.yml
ports:
@ -148,7 +150,7 @@ services:
retries: 3
otel-collector:
!!merge <<: *db-depend
image: signoz/signoz-otel-collector:v0.128.2
image: signoz/signoz-otel-collector:v0.129.6
command:
- --config=/etc/otel-collector-config.yaml
- --manager-config=/etc/manager-config.yaml
@ -174,7 +176,7 @@ services:
- signoz
schema-migrator:
!!merge <<: *common
image: signoz/signoz-schema-migrator:v0.128.2
image: signoz/signoz-schema-migrator:v0.129.6
deploy:
restart_policy:
condition: on-failure

View File

@ -10,7 +10,7 @@ x-common: &common
x-clickhouse-defaults: &clickhouse-defaults
!!merge <<: *common
# addding non LTS version due to this fix https://github.com/ClickHouse/ClickHouse/commit/32caf8716352f45c1b617274c7508c86b7d1afab
image: clickhouse/clickhouse-server:24.1.2-alpine
image: clickhouse/clickhouse-server:25.5.6
tty: true
labels:
signoz.io/scrape: "true"
@ -40,9 +40,11 @@ x-clickhouse-defaults: &clickhouse-defaults
nofile:
soft: 262144
hard: 262144
environment:
- CLICKHOUSE_SKIP_USER_SETUP=1
x-zookeeper-defaults: &zookeeper-defaults
!!merge <<: *common
image: bitnami/zookeeper:3.7.1
image: signoz/zookeeper:3.7.1
user: root
labels:
signoz.io/scrape: "true"
@ -65,7 +67,7 @@ x-db-depend: &db-depend
services:
init-clickhouse:
!!merge <<: *common
image: clickhouse/clickhouse-server:24.1.2-alpine
image: clickhouse/clickhouse-server:25.5.6
container_name: signoz-init-clickhouse
command:
- bash
@ -177,7 +179,7 @@ services:
# - ../common/clickhouse/storage.xml:/etc/clickhouse-server/config.d/storage.xml
signoz:
!!merge <<: *db-depend
image: signoz/signoz:${VERSION:-v0.90.1}
image: signoz/signoz:${VERSION:-v0.96.1}
container_name: signoz
command:
- --config=/root/config/prometheus.yml
@ -211,7 +213,7 @@ services:
# TODO: support otel-collector multiple replicas. Nginx/Traefik for loadbalancing?
otel-collector:
!!merge <<: *db-depend
image: signoz/signoz-otel-collector:${OTELCOL_TAG:-v0.128.2}
image: signoz/signoz-otel-collector:${OTELCOL_TAG:-v0.129.6}
container_name: signoz-otel-collector
command:
- --config=/etc/otel-collector-config.yaml
@ -237,7 +239,7 @@ services:
condition: service_healthy
schema-migrator-sync:
!!merge <<: *common
image: signoz/signoz-schema-migrator:${OTELCOL_TAG:-v0.128.2}
image: signoz/signoz-schema-migrator:${OTELCOL_TAG:-v0.129.6}
container_name: schema-migrator-sync
command:
- sync
@ -248,7 +250,7 @@ services:
condition: service_healthy
schema-migrator-async:
!!merge <<: *db-depend
image: signoz/signoz-schema-migrator:${OTELCOL_TAG:-v0.128.2}
image: signoz/signoz-schema-migrator:${OTELCOL_TAG:-v0.129.6}
container_name: schema-migrator-async
command:
- async

View File

@ -9,8 +9,7 @@ x-common: &common
max-file: "3"
x-clickhouse-defaults: &clickhouse-defaults
!!merge <<: *common
# addding non LTS version due to this fix https://github.com/ClickHouse/ClickHouse/commit/32caf8716352f45c1b617274c7508c86b7d1afab
image: clickhouse/clickhouse-server:24.1.2-alpine
image: clickhouse/clickhouse-server:25.5.6
tty: true
labels:
signoz.io/scrape: "true"
@ -36,9 +35,11 @@ x-clickhouse-defaults: &clickhouse-defaults
nofile:
soft: 262144
hard: 262144
environment:
- CLICKHOUSE_SKIP_USER_SETUP=1
x-zookeeper-defaults: &zookeeper-defaults
!!merge <<: *common
image: bitnami/zookeeper:3.7.1
image: signoz/zookeeper:3.7.1
user: root
labels:
signoz.io/scrape: "true"
@ -61,7 +62,7 @@ x-db-depend: &db-depend
services:
init-clickhouse:
!!merge <<: *common
image: clickhouse/clickhouse-server:24.1.2-alpine
image: clickhouse/clickhouse-server:25.5.6
container_name: signoz-init-clickhouse
command:
- bash
@ -110,7 +111,7 @@ services:
# - ../common/clickhouse/storage.xml:/etc/clickhouse-server/config.d/storage.xml
signoz:
!!merge <<: *db-depend
image: signoz/signoz:${VERSION:-v0.90.1}
image: signoz/signoz:${VERSION:-v0.96.1}
container_name: signoz
command:
- --config=/root/config/prometheus.yml
@ -143,7 +144,7 @@ services:
retries: 3
otel-collector:
!!merge <<: *db-depend
image: signoz/signoz-otel-collector:${OTELCOL_TAG:-v0.128.2}
image: signoz/signoz-otel-collector:${OTELCOL_TAG:-v0.129.6}
container_name: signoz-otel-collector
command:
- --config=/etc/otel-collector-config.yaml
@ -165,7 +166,7 @@ services:
condition: service_healthy
schema-migrator-sync:
!!merge <<: *common
image: signoz/signoz-schema-migrator:${OTELCOL_TAG:-v0.128.2}
image: signoz/signoz-schema-migrator:${OTELCOL_TAG:-v0.129.6}
container_name: schema-migrator-sync
command:
- sync
@ -177,7 +178,7 @@ services:
restart: on-failure
schema-migrator-async:
!!merge <<: *db-depend
image: signoz/signoz-schema-migrator:${OTELCOL_TAG:-v0.128.2}
image: signoz/signoz-schema-migrator:${OTELCOL_TAG:-v0.129.6}
container_name: schema-migrator-async
command:
- async

View File

@ -44,20 +44,35 @@ Before diving in, make sure you have these tools installed:
SigNoz has three main components: Clickhouse, Backend, and Frontend. Let's set them up one by one.
### 1. Setting up Clickhouse
### 1. Setting up ClickHouse
First, we need to get Clickhouse running:
First, we need to get ClickHouse running:
```bash
make devenv-clickhouse
```
This command:
- Starts Clickhouse in a single-shard, single-replica cluster
- Starts ClickHouse in a single-shard, single-replica cluster
- Sets up Zookeeper
- Runs the latest schema migrations
### 2. Starting the Backend
### 2. Setting up SigNoz OpenTelemetry Collector
Next, start the OpenTelemetry Collector to receive telemetry data:
```bash
make devenv-signoz-otel-collector
```
This command:
- Starts the SigNoz OpenTelemetry Collector
- Listens on port 4317 (gRPC) and 4318 (HTTP) for incoming telemetry data
- Forwards data to ClickHouse for storage
> 💡 **Quick Setup**: Use `make devenv-up` to start both ClickHouse and OTel Collector together
### 3. Starting the Backend
1. Run the backend server:
```bash
@ -73,19 +88,24 @@ This command:
> 💡 **Tip**: The API server runs at `http://localhost:8080/` by default
### 3. Setting up the Frontend
### 4. Setting up the Frontend
1. Install dependencies:
1. Navigate to the frontend directory:
```bash
cd frontend
```
2. Install dependencies:
```bash
yarn install
```
2. Create a `.env` file in the `frontend` directory:
3. Create a `.env` file in this directory:
```env
FRONTEND_API_ENDPOINT=http://localhost:8080
```
3. Start the development server:
4. Start the development server:
```bash
yarn dev
```
@ -93,3 +113,25 @@ This command:
> 💡 **Tip**: `yarn dev` will automatically rebuild when you make changes to the code
Now you're all set to start developing! Happy coding! 🎉
## Verifying Your Setup
To verify everything is working correctly:
1. **Check ClickHouse**: `curl http://localhost:8123/ping` (should return "Ok.")
2. **Check OTel Collector**: `curl http://localhost:13133` (should return health status)
3. **Check Backend**: `curl http://localhost:8080/api/v1/health` (should return `{"status":"ok"}`)
4. **Check Frontend**: Open `http://localhost:3301` in your browser
## How to send test data?
You can now send telemetry data to your local SigNoz instance:
- **OTLP gRPC**: `localhost:4317`
- **OTLP HTTP**: `localhost:4318`
For example, using `curl` to send a test trace:
```bash
curl -X POST http://localhost:4318/v1/traces \
-H "Content-Type: application/json" \
-d '{"resourceSpans":[{"resource":{"attributes":[{"key":"service.name","value":{"stringValue":"test-service"}}]},"scopeSpans":[{"spans":[{"traceId":"12345678901234567890123456789012","spanId":"1234567890123456","name":"test-span","startTimeUnixNano":"1609459200000000000","endTimeUnixNano":"1609459201000000000"}]}]}]}'
```

View File

@ -0,0 +1,213 @@
# Integration Tests
SigNoz uses integration tests to verify that different components work together correctly in a real environment. These tests run against actual services (ClickHouse, PostgreSQL, etc.) to ensure end-to-end functionality.
## How to set up the integration test environment?
### Prerequisites
Before running integration tests, ensure you have the following installed:
- Python 3.13+
- Poetry (for dependency management)
- Docker (for containerized services)
### Initial Setup
1. Navigate to the integration tests directory:
```bash
cd tests/integration
```
2. Install dependencies using Poetry:
```bash
poetry install --no-root
```
### Starting the Test Environment
To spin up all the containers necessary for writing integration tests and keep them running:
```bash
poetry run pytest --basetemp=./tmp/ -vv --reuse src/bootstrap/setup.py::test_setup
```
This command will:
- Start all required services (ClickHouse, PostgreSQL, Zookeeper, etc.)
- Keep containers running due to the `--reuse` flag
- Verify that the setup is working correctly
### Stopping the Test Environment
When you're done writing integration tests, clean up the environment:
```bash
poetry run pytest --basetemp=./tmp/ -vv --teardown -s src/bootstrap/setup.py::test_teardown
```
This will destroy the running integration test setup and clean up resources.
## Understanding the Integration Test Framework
Python and pytest form the foundation of the integration testing framework. Testcontainers are used to spin up disposable integration environments. Wiremock is used to spin up **test doubles** of other services.
- **Why Python/pytest?** It's expressive, low-boilerplate, and has powerful fixture capabilities that make integration testing straightforward. Extensive libraries for HTTP requests, JSON handling, and data analysis (numpy) make it easier to test APIs and verify data
- **Why testcontainers?** They let us spin up isolated dependencies that match our production environment without complex setup.
- **Why wiremock?** Well maintained, documented and extensible.
```
.
├── conftest.py
├── fixtures
│ ├── __init__.py
│ ├── auth.py
│ ├── clickhouse.py
│ ├── fs.py
│ ├── http.py
│ ├── migrator.py
│ ├── network.py
│ ├── postgres.py
│ ├── signoz.py
│ ├── sql.py
│ ├── sqlite.py
│ ├── types.py
│ └── zookeeper.py
├── poetry.lock
├── pyproject.toml
└── src
└── bootstrap
├── __init__.py
├── a_database.py
├── b_register.py
└── c_license.py
```
Each test suite follows some important principles:
1. **Organization**: Test suites live under `src/` in self-contained packages. Fixtures (a pytest concept) live inside `fixtures/`.
2. **Execution Order**: Files are prefixed with `a_`, `b_`, `c_` to ensure sequential execution.
3. **Time Constraints**: Each suite should complete in under 10 minutes (setup takes ~4 mins).
### Test Suite Design
Test suites should target functional domains or subsystems within SigNoz. When designing a test suite, consider these principles:
- **Functional Cohesion**: Group tests around a specific capability or service boundary
- **Data Flow**: Follow the path of data through related components
- **Change Patterns**: Components frequently modified together should be tested together
The exact boundaries for modules are intentionally flexible, allowing teams to define logical groupings based on their specific context and knowledge of the system.
Eg: The **bootstrap** integration test suite validates core system functionality:
- Database initialization
- Version check
Other test suites can be **pipelines, auth, querier.**
## How to write an integration test?
Now start writing an integration test. Create a new file `src/bootstrap/e_version.py` and paste the following:
```python
import requests
from fixtures import types
from fixtures.logger import setup_logger
logger = setup_logger(__name__)
def test_version(signoz: types.SigNoz) -> None:
response = requests.get(signoz.self.host_config.get("/api/v1/version"), timeout=2)
logger.info(response)
```
We have written a simple test which calls the `version` endpoint of the container in step 1. In **order to just run this function, run the following command:**
```bash
poetry run pytest --basetemp=./tmp/ -vv --reuse src/bootstrap/e_version.py::test_version
```
> Note: The `--reuse` flag is used to reuse the environment if it is already running. Always use this flag when writing and running integration tests. If you don't use this flag, the environment will be destroyed and recreated every time you run the test.
Here's another example of how to write a more comprehensive integration test:
```python
from http import HTTPStatus
import requests
from fixtures import types
from fixtures.logger import setup_logger
logger = setup_logger(__name__)
def test_user_registration(signoz: types.SigNoz) -> None:
"""Test user registration functionality."""
response = requests.post(
signoz.self.host_configs["8080"].get("/api/v1/register"),
json={
"name": "testuser",
"orgId": "",
"orgName": "test.org",
"email": "test@example.com",
"password": "password123Z$",
},
timeout=2,
)
assert response.status_code == HTTPStatus.OK
assert response.json()["setupCompleted"] is True
```
## How to run integration tests?
### Running All Tests
```bash
poetry run pytest --basetemp=./tmp/ -vv --reuse src/
```
### Running Specific Test Categories
```bash
poetry run pytest --basetemp=./tmp/ -vv --reuse src/<suite>
# Run querier tests
poetry run pytest --basetemp=./tmp/ -vv --reuse src/querier/
# Run auth tests
poetry run pytest --basetemp=./tmp/ -vv --reuse src/auth/
```
### Running Individual Tests
```bash
poetry run pytest --basetemp=./tmp/ -vv --reuse src/<suite>/<file>.py::test_name
# Run test_register in file a_register.py in auth suite
poetry run pytest --basetemp=./tmp/ -vv --reuse src/auth/a_register.py::test_register
```
## How to configure different options for integration tests?
Tests can be configured using pytest options:
- `--sqlstore-provider` - Choose database provider (default: postgres)
- `--postgres-version` - PostgreSQL version (default: 15)
- `--clickhouse-version` - ClickHouse version (default: 25.5.6)
- `--zookeeper-version` - Zookeeper version (default: 3.7.1)
Example:
```bash
poetry run pytest --basetemp=./tmp/ -vv --reuse --sqlstore-provider=postgres --postgres-version=14 src/auth/
```
## What should I remember?
- **Always use the `--reuse` flag** when setting up the environment to keep containers running
- **Use the `--teardown` flag** when cleaning up to avoid resource leaks
- **Follow the naming convention** with alphabetical prefixes for test execution order
- **Use proper timeouts** in HTTP requests to avoid hanging tests
- **Clean up test data** between tests to avoid interference
- **Use descriptive test names** that clearly indicate what is being tested
- **Leverage fixtures** for common setup and authentication
- **Test both success and failure scenarios** to ensure robust functionality

34
ee/anomaly/daily.go Normal file
View File

@ -0,0 +1,34 @@
package anomaly
import (
"context"
"github.com/SigNoz/signoz/pkg/valuer"
)
type DailyProvider struct {
BaseSeasonalProvider
}
var _ BaseProvider = (*DailyProvider)(nil)
func (dp *DailyProvider) GetBaseSeasonalProvider() *BaseSeasonalProvider {
return &dp.BaseSeasonalProvider
}
func NewDailyProvider(opts ...GenericProviderOption[*DailyProvider]) *DailyProvider {
dp := &DailyProvider{
BaseSeasonalProvider: BaseSeasonalProvider{},
}
for _, opt := range opts {
opt(dp)
}
return dp
}
func (p *DailyProvider) GetAnomalies(ctx context.Context, orgID valuer.UUID, req *AnomaliesRequest) (*AnomaliesResponse, error) {
req.Seasonality = SeasonalityDaily
return p.getAnomalies(ctx, orgID, req)
}

35
ee/anomaly/hourly.go Normal file
View File

@ -0,0 +1,35 @@
package anomaly
import (
"context"
"github.com/SigNoz/signoz/pkg/valuer"
)
type HourlyProvider struct {
BaseSeasonalProvider
}
var _ BaseProvider = (*HourlyProvider)(nil)
func (hp *HourlyProvider) GetBaseSeasonalProvider() *BaseSeasonalProvider {
return &hp.BaseSeasonalProvider
}
// NewHourlyProvider now uses the generic option type
func NewHourlyProvider(opts ...GenericProviderOption[*HourlyProvider]) *HourlyProvider {
hp := &HourlyProvider{
BaseSeasonalProvider: BaseSeasonalProvider{},
}
for _, opt := range opts {
opt(hp)
}
return hp
}
func (p *HourlyProvider) GetAnomalies(ctx context.Context, orgID valuer.UUID, req *AnomaliesRequest) (*AnomaliesResponse, error) {
req.Seasonality = SeasonalityHourly
return p.getAnomalies(ctx, orgID, req)
}

223
ee/anomaly/params.go Normal file
View File

@ -0,0 +1,223 @@
package anomaly
import (
"time"
qbtypes "github.com/SigNoz/signoz/pkg/types/querybuildertypes/querybuildertypesv5"
"github.com/SigNoz/signoz/pkg/valuer"
)
type Seasonality struct{ valuer.String }
var (
SeasonalityHourly = Seasonality{valuer.NewString("hourly")}
SeasonalityDaily = Seasonality{valuer.NewString("daily")}
SeasonalityWeekly = Seasonality{valuer.NewString("weekly")}
)
var (
oneWeekOffset = uint64(24 * 7 * time.Hour.Milliseconds())
oneDayOffset = uint64(24 * time.Hour.Milliseconds())
oneHourOffset = uint64(time.Hour.Milliseconds())
fiveMinOffset = uint64(5 * time.Minute.Milliseconds())
)
func (s Seasonality) IsValid() bool {
switch s {
case SeasonalityHourly, SeasonalityDaily, SeasonalityWeekly:
return true
default:
return false
}
}
type AnomaliesRequest struct {
Params qbtypes.QueryRangeRequest
Seasonality Seasonality
}
type AnomaliesResponse struct {
Results []*qbtypes.TimeSeriesData
}
// anomalyParams is the params for anomaly detection
// prediction = avg(past_period_query) + avg(current_season_query) - mean(past_season_query, past2_season_query, past3_season_query)
//
// ^ ^
// | |
// (rounded value for past peiod) + (seasonal growth)
//
// score = abs(value - prediction) / stddev (current_season_query)
type anomalyQueryParams struct {
// CurrentPeriodQuery is the query range params for period user is looking at or eval window
// Example: (now-5m, now), (now-30m, now), (now-1h, now)
// The results obtained from this query are used to compare with predicted values
// and to detect anomalies
CurrentPeriodQuery qbtypes.QueryRangeRequest
// PastPeriodQuery is the query range params for past period of seasonality
// Example: For weekly seasonality, (now-1w-5m, now-1w)
// : For daily seasonality, (now-1d-5m, now-1d)
// : For hourly seasonality, (now-1h-5m, now-1h)
PastPeriodQuery qbtypes.QueryRangeRequest
// CurrentSeasonQuery is the query range params for current period (seasonal)
// Example: For weekly seasonality, this is the query range params for the (now-1w-5m, now)
// : For daily seasonality, this is the query range params for the (now-1d-5m, now)
// : For hourly seasonality, this is the query range params for the (now-1h-5m, now)
CurrentSeasonQuery qbtypes.QueryRangeRequest
// PastSeasonQuery is the query range params for past seasonal period to the current season
// Example: For weekly seasonality, this is the query range params for the (now-2w-5m, now-1w)
// : For daily seasonality, this is the query range params for the (now-2d-5m, now-1d)
// : For hourly seasonality, this is the query range params for the (now-2h-5m, now-1h)
PastSeasonQuery qbtypes.QueryRangeRequest
// Past2SeasonQuery is the query range params for past 2 seasonal period to the current season
// Example: For weekly seasonality, this is the query range params for the (now-3w-5m, now-2w)
// : For daily seasonality, this is the query range params for the (now-3d-5m, now-2d)
// : For hourly seasonality, this is the query range params for the (now-3h-5m, now-2h)
Past2SeasonQuery qbtypes.QueryRangeRequest
// Past3SeasonQuery is the query range params for past 3 seasonal period to the current season
// Example: For weekly seasonality, this is the query range params for the (now-4w-5m, now-3w)
// : For daily seasonality, this is the query range params for the (now-4d-5m, now-3d)
// : For hourly seasonality, this is the query range params for the (now-4h-5m, now-3h)
Past3SeasonQuery qbtypes.QueryRangeRequest
}
func prepareAnomalyQueryParams(req qbtypes.QueryRangeRequest, seasonality Seasonality) *anomalyQueryParams {
start := req.Start
end := req.End
currentPeriodQuery := qbtypes.QueryRangeRequest{
Start: start,
End: end,
RequestType: qbtypes.RequestTypeTimeSeries,
CompositeQuery: req.CompositeQuery,
NoCache: false,
}
var pastPeriodStart, pastPeriodEnd uint64
switch seasonality {
// for one week period, we fetch the data from the past week with 5 min offset
case SeasonalityWeekly:
pastPeriodStart = start - oneWeekOffset - fiveMinOffset
pastPeriodEnd = end - oneWeekOffset
// for one day period, we fetch the data from the past day with 5 min offset
case SeasonalityDaily:
pastPeriodStart = start - oneDayOffset - fiveMinOffset
pastPeriodEnd = end - oneDayOffset
// for one hour period, we fetch the data from the past hour with 5 min offset
case SeasonalityHourly:
pastPeriodStart = start - oneHourOffset - fiveMinOffset
pastPeriodEnd = end - oneHourOffset
}
pastPeriodQuery := qbtypes.QueryRangeRequest{
Start: pastPeriodStart,
End: pastPeriodEnd,
RequestType: qbtypes.RequestTypeTimeSeries,
CompositeQuery: req.CompositeQuery,
NoCache: false,
}
// seasonality growth trend
var currentGrowthPeriodStart, currentGrowthPeriodEnd uint64
switch seasonality {
case SeasonalityWeekly:
currentGrowthPeriodStart = start - oneWeekOffset
currentGrowthPeriodEnd = start
case SeasonalityDaily:
currentGrowthPeriodStart = start - oneDayOffset
currentGrowthPeriodEnd = start
case SeasonalityHourly:
currentGrowthPeriodStart = start - oneHourOffset
currentGrowthPeriodEnd = start
}
currentGrowthQuery := qbtypes.QueryRangeRequest{
Start: currentGrowthPeriodStart,
End: currentGrowthPeriodEnd,
RequestType: qbtypes.RequestTypeTimeSeries,
CompositeQuery: req.CompositeQuery,
NoCache: false,
}
var pastGrowthPeriodStart, pastGrowthPeriodEnd uint64
switch seasonality {
case SeasonalityWeekly:
pastGrowthPeriodStart = start - 2*oneWeekOffset
pastGrowthPeriodEnd = start - 1*oneWeekOffset
case SeasonalityDaily:
pastGrowthPeriodStart = start - 2*oneDayOffset
pastGrowthPeriodEnd = start - 1*oneDayOffset
case SeasonalityHourly:
pastGrowthPeriodStart = start - 2*oneHourOffset
pastGrowthPeriodEnd = start - 1*oneHourOffset
}
pastGrowthQuery := qbtypes.QueryRangeRequest{
Start: pastGrowthPeriodStart,
End: pastGrowthPeriodEnd,
RequestType: qbtypes.RequestTypeTimeSeries,
CompositeQuery: req.CompositeQuery,
NoCache: false,
}
var past2GrowthPeriodStart, past2GrowthPeriodEnd uint64
switch seasonality {
case SeasonalityWeekly:
past2GrowthPeriodStart = start - 3*oneWeekOffset
past2GrowthPeriodEnd = start - 2*oneWeekOffset
case SeasonalityDaily:
past2GrowthPeriodStart = start - 3*oneDayOffset
past2GrowthPeriodEnd = start - 2*oneDayOffset
case SeasonalityHourly:
past2GrowthPeriodStart = start - 3*oneHourOffset
past2GrowthPeriodEnd = start - 2*oneHourOffset
}
past2GrowthQuery := qbtypes.QueryRangeRequest{
Start: past2GrowthPeriodStart,
End: past2GrowthPeriodEnd,
RequestType: qbtypes.RequestTypeTimeSeries,
CompositeQuery: req.CompositeQuery,
NoCache: false,
}
var past3GrowthPeriodStart, past3GrowthPeriodEnd uint64
switch seasonality {
case SeasonalityWeekly:
past3GrowthPeriodStart = start - 4*oneWeekOffset
past3GrowthPeriodEnd = start - 3*oneWeekOffset
case SeasonalityDaily:
past3GrowthPeriodStart = start - 4*oneDayOffset
past3GrowthPeriodEnd = start - 3*oneDayOffset
case SeasonalityHourly:
past3GrowthPeriodStart = start - 4*oneHourOffset
past3GrowthPeriodEnd = start - 3*oneHourOffset
}
past3GrowthQuery := qbtypes.QueryRangeRequest{
Start: past3GrowthPeriodStart,
End: past3GrowthPeriodEnd,
RequestType: qbtypes.RequestTypeTimeSeries,
CompositeQuery: req.CompositeQuery,
NoCache: false,
}
return &anomalyQueryParams{
CurrentPeriodQuery: currentPeriodQuery,
PastPeriodQuery: pastPeriodQuery,
CurrentSeasonQuery: currentGrowthQuery,
PastSeasonQuery: pastGrowthQuery,
Past2SeasonQuery: past2GrowthQuery,
Past3SeasonQuery: past3GrowthQuery,
}
}
type anomalyQueryResults struct {
CurrentPeriodResults []*qbtypes.TimeSeriesData
PastPeriodResults []*qbtypes.TimeSeriesData
CurrentSeasonResults []*qbtypes.TimeSeriesData
PastSeasonResults []*qbtypes.TimeSeriesData
Past2SeasonResults []*qbtypes.TimeSeriesData
Past3SeasonResults []*qbtypes.TimeSeriesData
}

11
ee/anomaly/provider.go Normal file
View File

@ -0,0 +1,11 @@
package anomaly
import (
"context"
"github.com/SigNoz/signoz/pkg/valuer"
)
type Provider interface {
GetAnomalies(ctx context.Context, orgID valuer.UUID, req *AnomaliesRequest) (*AnomaliesResponse, error)
}

463
ee/anomaly/seasonal.go Normal file
View File

@ -0,0 +1,463 @@
package anomaly
import (
"context"
"log/slog"
"math"
"github.com/SigNoz/signoz/pkg/querier"
"github.com/SigNoz/signoz/pkg/valuer"
qbtypes "github.com/SigNoz/signoz/pkg/types/querybuildertypes/querybuildertypesv5"
)
var (
// TODO(srikanthccv): make this configurable?
movingAvgWindowSize = 7
)
// BaseProvider is an interface that includes common methods for all provider types
type BaseProvider interface {
GetBaseSeasonalProvider() *BaseSeasonalProvider
}
// GenericProviderOption is a generic type for provider options
type GenericProviderOption[T BaseProvider] func(T)
func WithQuerier[T BaseProvider](querier querier.Querier) GenericProviderOption[T] {
return func(p T) {
p.GetBaseSeasonalProvider().querier = querier
}
}
func WithLogger[T BaseProvider](logger *slog.Logger) GenericProviderOption[T] {
return func(p T) {
p.GetBaseSeasonalProvider().logger = logger
}
}
type BaseSeasonalProvider struct {
querier querier.Querier
logger *slog.Logger
}
func (p *BaseSeasonalProvider) getQueryParams(req *AnomaliesRequest) *anomalyQueryParams {
if !req.Seasonality.IsValid() {
req.Seasonality = SeasonalityDaily
}
return prepareAnomalyQueryParams(req.Params, req.Seasonality)
}
func (p *BaseSeasonalProvider) toTSResults(ctx context.Context, resp *qbtypes.QueryRangeResponse) []*qbtypes.TimeSeriesData {
tsData := []*qbtypes.TimeSeriesData{}
if resp == nil {
p.logger.InfoContext(ctx, "nil response from query range")
return tsData
}
for _, item := range resp.Data.Results {
if resultData, ok := item.(*qbtypes.TimeSeriesData); ok {
tsData = append(tsData, resultData)
}
}
return tsData
}
func (p *BaseSeasonalProvider) getResults(ctx context.Context, orgID valuer.UUID, params *anomalyQueryParams) (*anomalyQueryResults, error) {
// TODO(srikanthccv): parallelize this?
p.logger.InfoContext(ctx, "fetching results for current period", "anomaly_current_period_query", params.CurrentPeriodQuery)
currentPeriodResults, err := p.querier.QueryRange(ctx, orgID, &params.CurrentPeriodQuery)
if err != nil {
return nil, err
}
p.logger.InfoContext(ctx, "fetching results for past period", "anomaly_past_period_query", params.PastPeriodQuery)
pastPeriodResults, err := p.querier.QueryRange(ctx, orgID, &params.PastPeriodQuery)
if err != nil {
return nil, err
}
p.logger.InfoContext(ctx, "fetching results for current season", "anomaly_current_season_query", params.CurrentSeasonQuery)
currentSeasonResults, err := p.querier.QueryRange(ctx, orgID, &params.CurrentSeasonQuery)
if err != nil {
return nil, err
}
p.logger.InfoContext(ctx, "fetching results for past season", "anomaly_past_season_query", params.PastSeasonQuery)
pastSeasonResults, err := p.querier.QueryRange(ctx, orgID, &params.PastSeasonQuery)
if err != nil {
return nil, err
}
p.logger.InfoContext(ctx, "fetching results for past 2 season", "anomaly_past_2season_query", params.Past2SeasonQuery)
past2SeasonResults, err := p.querier.QueryRange(ctx, orgID, &params.Past2SeasonQuery)
if err != nil {
return nil, err
}
p.logger.InfoContext(ctx, "fetching results for past 3 season", "anomaly_past_3season_query", params.Past3SeasonQuery)
past3SeasonResults, err := p.querier.QueryRange(ctx, orgID, &params.Past3SeasonQuery)
if err != nil {
return nil, err
}
return &anomalyQueryResults{
CurrentPeriodResults: p.toTSResults(ctx, currentPeriodResults),
PastPeriodResults: p.toTSResults(ctx, pastPeriodResults),
CurrentSeasonResults: p.toTSResults(ctx, currentSeasonResults),
PastSeasonResults: p.toTSResults(ctx, pastSeasonResults),
Past2SeasonResults: p.toTSResults(ctx, past2SeasonResults),
Past3SeasonResults: p.toTSResults(ctx, past3SeasonResults),
}, nil
}
// getMatchingSeries gets the matching series from the query result
// for the given series
func (p *BaseSeasonalProvider) getMatchingSeries(_ context.Context, queryResult *qbtypes.TimeSeriesData, series *qbtypes.TimeSeries) *qbtypes.TimeSeries {
if queryResult == nil || len(queryResult.Aggregations) == 0 || len(queryResult.Aggregations[0].Series) == 0 {
return nil
}
for _, curr := range queryResult.Aggregations[0].Series {
currLabelsKey := qbtypes.GetUniqueSeriesKey(curr.Labels)
seriesLabelsKey := qbtypes.GetUniqueSeriesKey(series.Labels)
if currLabelsKey == seriesLabelsKey {
return curr
}
}
return nil
}
func (p *BaseSeasonalProvider) getAvg(series *qbtypes.TimeSeries) float64 {
if series == nil || len(series.Values) == 0 {
return 0
}
var sum float64
for _, smpl := range series.Values {
sum += smpl.Value
}
return sum / float64(len(series.Values))
}
func (p *BaseSeasonalProvider) getStdDev(series *qbtypes.TimeSeries) float64 {
if series == nil || len(series.Values) == 0 {
return 0
}
avg := p.getAvg(series)
var sum float64
for _, smpl := range series.Values {
sum += math.Pow(smpl.Value-avg, 2)
}
return math.Sqrt(sum / float64(len(series.Values)))
}
// getMovingAvg gets the moving average for the given series
// for the given window size and start index
func (p *BaseSeasonalProvider) getMovingAvg(series *qbtypes.TimeSeries, movingAvgWindowSize, startIdx int) float64 {
if series == nil || len(series.Values) == 0 {
return 0
}
if startIdx >= len(series.Values)-movingAvgWindowSize {
startIdx = int(math.Max(0, float64(len(series.Values)-movingAvgWindowSize)))
}
var sum float64
points := series.Values[startIdx:]
windowSize := int(math.Min(float64(movingAvgWindowSize), float64(len(points))))
for i := 0; i < windowSize; i++ {
sum += points[i].Value
}
avg := sum / float64(windowSize)
return avg
}
func (p *BaseSeasonalProvider) getMean(floats ...float64) float64 {
if len(floats) == 0 {
return 0
}
var sum float64
for _, f := range floats {
sum += f
}
return sum / float64(len(floats))
}
func (p *BaseSeasonalProvider) getPredictedSeries(
ctx context.Context,
series, prevSeries, currentSeasonSeries, pastSeasonSeries, past2SeasonSeries, past3SeasonSeries *qbtypes.TimeSeries,
) *qbtypes.TimeSeries {
predictedSeries := &qbtypes.TimeSeries{
Labels: series.Labels,
Values: make([]*qbtypes.TimeSeriesValue, 0),
}
// for each point in the series, get the predicted value
// the predicted value is the moving average (with window size = 7) of the previous period series
// plus the average of the current season series
// minus the mean of the past season series, past2 season series and past3 season series
for idx, curr := range series.Values {
movingAvg := p.getMovingAvg(prevSeries, movingAvgWindowSize, idx)
avg := p.getAvg(currentSeasonSeries)
mean := p.getMean(p.getAvg(pastSeasonSeries), p.getAvg(past2SeasonSeries), p.getAvg(past3SeasonSeries))
predictedValue := movingAvg + avg - mean
if predictedValue < 0 {
// this should not happen (except when the data has extreme outliers)
// we will use the moving avg of the previous period series in this case
p.logger.WarnContext(ctx, "predicted value is less than 0 for series", "anomaly_predicted_value", predictedValue, "anomaly_labels", series.Labels)
predictedValue = p.getMovingAvg(prevSeries, movingAvgWindowSize, idx)
}
p.logger.DebugContext(ctx, "predicted value for series",
"anomaly_moving_avg", movingAvg,
"anomaly_avg", avg,
"anomaly_mean", mean,
"anomaly_labels", series.Labels,
"anomaly_predicted_value", predictedValue,
"anomaly_curr", curr.Value,
)
predictedSeries.Values = append(predictedSeries.Values, &qbtypes.TimeSeriesValue{
Timestamp: curr.Timestamp,
Value: predictedValue,
})
}
return predictedSeries
}
// getBounds gets the upper and lower bounds for the given series
// for the given z score threshold
// moving avg of the previous period series + z score threshold * std dev of the series
// moving avg of the previous period series - z score threshold * std dev of the series
func (p *BaseSeasonalProvider) getBounds(
series, predictedSeries *qbtypes.TimeSeries,
zScoreThreshold float64,
) (*qbtypes.TimeSeries, *qbtypes.TimeSeries) {
upperBoundSeries := &qbtypes.TimeSeries{
Labels: series.Labels,
Values: make([]*qbtypes.TimeSeriesValue, 0),
}
lowerBoundSeries := &qbtypes.TimeSeries{
Labels: series.Labels,
Values: make([]*qbtypes.TimeSeriesValue, 0),
}
for idx, curr := range series.Values {
upperBound := p.getMovingAvg(predictedSeries, movingAvgWindowSize, idx) + zScoreThreshold*p.getStdDev(series)
lowerBound := p.getMovingAvg(predictedSeries, movingAvgWindowSize, idx) - zScoreThreshold*p.getStdDev(series)
upperBoundSeries.Values = append(upperBoundSeries.Values, &qbtypes.TimeSeriesValue{
Timestamp: curr.Timestamp,
Value: upperBound,
})
lowerBoundSeries.Values = append(lowerBoundSeries.Values, &qbtypes.TimeSeriesValue{
Timestamp: curr.Timestamp,
Value: math.Max(lowerBound, 0),
})
}
return upperBoundSeries, lowerBoundSeries
}
// getExpectedValue gets the expected value for the given series
// for the given index
// prevSeriesAvg + currentSeasonSeriesAvg - mean of past season series, past2 season series and past3 season series
func (p *BaseSeasonalProvider) getExpectedValue(
_, prevSeries, currentSeasonSeries, pastSeasonSeries, past2SeasonSeries, past3SeasonSeries *qbtypes.TimeSeries, idx int,
) float64 {
prevSeriesAvg := p.getMovingAvg(prevSeries, movingAvgWindowSize, idx)
currentSeasonSeriesAvg := p.getAvg(currentSeasonSeries)
pastSeasonSeriesAvg := p.getAvg(pastSeasonSeries)
past2SeasonSeriesAvg := p.getAvg(past2SeasonSeries)
past3SeasonSeriesAvg := p.getAvg(past3SeasonSeries)
return prevSeriesAvg + currentSeasonSeriesAvg - p.getMean(pastSeasonSeriesAvg, past2SeasonSeriesAvg, past3SeasonSeriesAvg)
}
// getScore gets the anomaly score for the given series
// for the given index
// (value - expectedValue) / std dev of the series
func (p *BaseSeasonalProvider) getScore(
series, prevSeries, weekSeries, weekPrevSeries, past2SeasonSeries, past3SeasonSeries *qbtypes.TimeSeries, value float64, idx int,
) float64 {
expectedValue := p.getExpectedValue(series, prevSeries, weekSeries, weekPrevSeries, past2SeasonSeries, past3SeasonSeries, idx)
if expectedValue < 0 {
expectedValue = p.getMovingAvg(prevSeries, movingAvgWindowSize, idx)
}
return (value - expectedValue) / p.getStdDev(weekSeries)
}
// getAnomalyScores gets the anomaly scores for the given series
// for the given index
// (value - expectedValue) / std dev of the series
func (p *BaseSeasonalProvider) getAnomalyScores(
series, prevSeries, currentSeasonSeries, pastSeasonSeries, past2SeasonSeries, past3SeasonSeries *qbtypes.TimeSeries,
) *qbtypes.TimeSeries {
anomalyScoreSeries := &qbtypes.TimeSeries{
Labels: series.Labels,
Values: make([]*qbtypes.TimeSeriesValue, 0),
}
for idx, curr := range series.Values {
anomalyScore := p.getScore(series, prevSeries, currentSeasonSeries, pastSeasonSeries, past2SeasonSeries, past3SeasonSeries, curr.Value, idx)
anomalyScoreSeries.Values = append(anomalyScoreSeries.Values, &qbtypes.TimeSeriesValue{
Timestamp: curr.Timestamp,
Value: anomalyScore,
})
}
return anomalyScoreSeries
}
func (p *BaseSeasonalProvider) getAnomalies(ctx context.Context, orgID valuer.UUID, req *AnomaliesRequest) (*AnomaliesResponse, error) {
anomalyParams := p.getQueryParams(req)
anomalyQueryResults, err := p.getResults(ctx, orgID, anomalyParams)
if err != nil {
return nil, err
}
currentPeriodResults := make(map[string]*qbtypes.TimeSeriesData)
for _, result := range anomalyQueryResults.CurrentPeriodResults {
currentPeriodResults[result.QueryName] = result
}
pastPeriodResults := make(map[string]*qbtypes.TimeSeriesData)
for _, result := range anomalyQueryResults.PastPeriodResults {
pastPeriodResults[result.QueryName] = result
}
currentSeasonResults := make(map[string]*qbtypes.TimeSeriesData)
for _, result := range anomalyQueryResults.CurrentSeasonResults {
currentSeasonResults[result.QueryName] = result
}
pastSeasonResults := make(map[string]*qbtypes.TimeSeriesData)
for _, result := range anomalyQueryResults.PastSeasonResults {
pastSeasonResults[result.QueryName] = result
}
past2SeasonResults := make(map[string]*qbtypes.TimeSeriesData)
for _, result := range anomalyQueryResults.Past2SeasonResults {
past2SeasonResults[result.QueryName] = result
}
past3SeasonResults := make(map[string]*qbtypes.TimeSeriesData)
for _, result := range anomalyQueryResults.Past3SeasonResults {
past3SeasonResults[result.QueryName] = result
}
for _, result := range currentPeriodResults {
funcs := req.Params.FuncsForQuery(result.QueryName)
var zScoreThreshold float64
for _, f := range funcs {
if f.Name == qbtypes.FunctionNameAnomaly {
for _, arg := range f.Args {
if arg.Name != "z_score_threshold" {
continue
}
value, ok := arg.Value.(float64)
if ok {
zScoreThreshold = value
} else {
p.logger.InfoContext(ctx, "z_score_threshold not provided, defaulting")
zScoreThreshold = 3
}
break
}
}
}
pastPeriodResult, ok := pastPeriodResults[result.QueryName]
if !ok {
continue
}
currentSeasonResult, ok := currentSeasonResults[result.QueryName]
if !ok {
continue
}
pastSeasonResult, ok := pastSeasonResults[result.QueryName]
if !ok {
continue
}
past2SeasonResult, ok := past2SeasonResults[result.QueryName]
if !ok {
continue
}
past3SeasonResult, ok := past3SeasonResults[result.QueryName]
if !ok {
continue
}
// no data;
if len(result.Aggregations) == 0 {
continue
}
aggOfInterest := result.Aggregations[0]
for _, series := range aggOfInterest.Series {
stdDev := p.getStdDev(series)
p.logger.InfoContext(ctx, "calculated standard deviation for series", "anomaly_std_dev", stdDev, "anomaly_labels", series.Labels)
pastPeriodSeries := p.getMatchingSeries(ctx, pastPeriodResult, series)
currentSeasonSeries := p.getMatchingSeries(ctx, currentSeasonResult, series)
pastSeasonSeries := p.getMatchingSeries(ctx, pastSeasonResult, series)
past2SeasonSeries := p.getMatchingSeries(ctx, past2SeasonResult, series)
past3SeasonSeries := p.getMatchingSeries(ctx, past3SeasonResult, series)
prevSeriesAvg := p.getAvg(pastPeriodSeries)
currentSeasonSeriesAvg := p.getAvg(currentSeasonSeries)
pastSeasonSeriesAvg := p.getAvg(pastSeasonSeries)
past2SeasonSeriesAvg := p.getAvg(past2SeasonSeries)
past3SeasonSeriesAvg := p.getAvg(past3SeasonSeries)
p.logger.InfoContext(ctx, "calculated mean for series",
"anomaly_prev_series_avg", prevSeriesAvg,
"anomaly_current_season_series_avg", currentSeasonSeriesAvg,
"anomaly_past_season_series_avg", pastSeasonSeriesAvg,
"anomaly_past_2season_series_avg", past2SeasonSeriesAvg,
"anomaly_past_3season_series_avg", past3SeasonSeriesAvg,
"anomaly_labels", series.Labels,
)
predictedSeries := p.getPredictedSeries(
ctx,
series,
pastPeriodSeries,
currentSeasonSeries,
pastSeasonSeries,
past2SeasonSeries,
past3SeasonSeries,
)
aggOfInterest.PredictedSeries = append(aggOfInterest.PredictedSeries, predictedSeries)
upperBoundSeries, lowerBoundSeries := p.getBounds(
series,
predictedSeries,
zScoreThreshold,
)
aggOfInterest.UpperBoundSeries = append(aggOfInterest.UpperBoundSeries, upperBoundSeries)
aggOfInterest.LowerBoundSeries = append(aggOfInterest.LowerBoundSeries, lowerBoundSeries)
anomalyScoreSeries := p.getAnomalyScores(
series,
pastPeriodSeries,
currentSeasonSeries,
pastSeasonSeries,
past2SeasonSeries,
past3SeasonSeries,
)
aggOfInterest.AnomalyScores = append(aggOfInterest.AnomalyScores, anomalyScoreSeries)
}
}
results := make([]*qbtypes.TimeSeriesData, 0, len(currentPeriodResults))
for _, result := range currentPeriodResults {
results = append(results, result)
}
return &AnomaliesResponse{
Results: results,
}, nil
}

34
ee/anomaly/weekly.go Normal file
View File

@ -0,0 +1,34 @@
package anomaly
import (
"context"
"github.com/SigNoz/signoz/pkg/valuer"
)
type WeeklyProvider struct {
BaseSeasonalProvider
}
var _ BaseProvider = (*WeeklyProvider)(nil)
func (wp *WeeklyProvider) GetBaseSeasonalProvider() *BaseSeasonalProvider {
return &wp.BaseSeasonalProvider
}
func NewWeeklyProvider(opts ...GenericProviderOption[*WeeklyProvider]) *WeeklyProvider {
wp := &WeeklyProvider{
BaseSeasonalProvider: BaseSeasonalProvider{},
}
for _, opt := range opts {
opt(wp)
}
return wp
}
func (p *WeeklyProvider) GetAnomalies(ctx context.Context, orgID valuer.UUID, req *AnomaliesRequest) (*AnomaliesResponse, error) {
req.Seasonality = SeasonalityWeekly
return p.getAnomalies(ctx, orgID, req)
}

View File

@ -0,0 +1,40 @@
module base
type organisation
relations
define read: [user, role#assignee]
define update: [user, role#assignee]
type user
relations
define read: [user, role#assignee]
define update: [user, role#assignee]
define delete: [user, role#assignee]
type anonymous
type role
relations
define assignee: [user]
define read: [user, role#assignee]
define update: [user, role#assignee]
define delete: [user, role#assignee]
type resources
relations
define create: [user, role#assignee]
define list: [user, role#assignee]
type resource
relations
define read: [user, anonymous, role#assignee]
define update: [user, role#assignee]
define delete: [user, role#assignee]
define block: [user, role#assignee]
type telemetry
relations
define read: [user, anonymous, role#assignee]

View File

@ -0,0 +1,29 @@
package openfgaschema
import (
"context"
_ "embed"
"github.com/SigNoz/signoz/pkg/authz"
openfgapkgtransformer "github.com/openfga/language/pkg/go/transformer"
)
var (
//go:embed base.fga
baseDSL string
)
type schema struct{}
func NewSchema() authz.Schema {
return &schema{}
}
func (schema *schema) Get(ctx context.Context) []openfgapkgtransformer.ModuleFile {
return []openfgapkgtransformer.ModuleFile{
{
Name: "base.fga",
Contents: baseDSL,
},
}
}

132
ee/http/middleware/authz.go Normal file
View File

@ -0,0 +1,132 @@
package middleware
import (
"log/slog"
"net/http"
"github.com/SigNoz/signoz/pkg/authz"
"github.com/SigNoz/signoz/pkg/http/render"
"github.com/SigNoz/signoz/pkg/types/authtypes"
"github.com/gorilla/mux"
)
const (
authzDeniedMessage string = "::AUTHZ-DENIED::"
)
type AuthZ struct {
logger *slog.Logger
authzService authz.AuthZ
}
func NewAuthZ(logger *slog.Logger) *AuthZ {
if logger == nil {
panic("cannot build authz middleware, logger is empty")
}
return &AuthZ{logger: logger}
}
func (middleware *AuthZ) ViewAccess(next http.HandlerFunc) http.HandlerFunc {
return http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
claims, err := authtypes.ClaimsFromContext(req.Context())
if err != nil {
render.Error(rw, err)
return
}
if err := claims.IsViewer(); err != nil {
middleware.logger.WarnContext(req.Context(), authzDeniedMessage, "claims", claims)
render.Error(rw, err)
return
}
next(rw, req)
})
}
func (middleware *AuthZ) EditAccess(next http.HandlerFunc) http.HandlerFunc {
return http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
claims, err := authtypes.ClaimsFromContext(req.Context())
if err != nil {
render.Error(rw, err)
return
}
if err := claims.IsEditor(); err != nil {
middleware.logger.WarnContext(req.Context(), authzDeniedMessage, "claims", claims)
render.Error(rw, err)
return
}
next(rw, req)
})
}
func (middleware *AuthZ) AdminAccess(next http.HandlerFunc) http.HandlerFunc {
return http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
claims, err := authtypes.ClaimsFromContext(req.Context())
if err != nil {
render.Error(rw, err)
return
}
if err := claims.IsAdmin(); err != nil {
middleware.logger.WarnContext(req.Context(), authzDeniedMessage, "claims", claims)
render.Error(rw, err)
return
}
next(rw, req)
})
}
func (middleware *AuthZ) SelfAccess(next http.HandlerFunc) http.HandlerFunc {
return http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
claims, err := authtypes.ClaimsFromContext(req.Context())
if err != nil {
render.Error(rw, err)
return
}
id := mux.Vars(req)["id"]
if err := claims.IsSelfAccess(id); err != nil {
middleware.logger.WarnContext(req.Context(), authzDeniedMessage, "claims", claims)
render.Error(rw, err)
return
}
next(rw, req)
})
}
func (middleware *AuthZ) OpenAccess(next http.HandlerFunc) http.HandlerFunc {
return http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
next(rw, req)
})
}
// Check middleware accepts the relation, typeable, parentTypeable (for direct access + group relations) and a callback function to derive selector and parentSelectors on per request basis.
func (middleware *AuthZ) Check(next http.HandlerFunc, relation authtypes.Relation, translation authtypes.Relation, typeable authtypes.Typeable, cb authtypes.SelectorCallbackFn) http.HandlerFunc {
return http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
claims, err := authtypes.ClaimsFromContext(req.Context())
if err != nil {
render.Error(rw, err)
return
}
selector, err := cb(req.Context(), claims)
if err != nil {
render.Error(rw, err)
return
}
err = middleware.authzService.CheckWithTupleCreation(req.Context(), claims, relation, typeable, selector)
if err != nil {
render.Error(rw, err)
return
}
next(rw, req)
})
}

View File

@ -59,7 +59,7 @@ func NewAPIHandler(opts APIHandlerOptions, signoz *signoz.SigNoz) (*APIHandler,
LicensingAPI: httplicensing.NewLicensingAPI(signoz.Licensing),
FieldsAPI: fields.NewAPI(signoz.Instrumentation.ToProviderSettings(), signoz.TelemetryStore),
Signoz: signoz,
QuerierAPI: querierAPI.NewAPI(signoz.Instrumentation.ToProviderSettings(), signoz.Querier),
QuerierAPI: querierAPI.NewAPI(signoz.Instrumentation.ToProviderSettings(), signoz.Querier, signoz.Analytics),
})
if err != nil {
@ -110,6 +110,11 @@ func (ah *APIHandler) RegisterRoutes(router *mux.Router, am *middleware.AuthZ) {
// v4
router.HandleFunc("/api/v4/query_range", am.ViewAccess(ah.queryRangeV4)).Methods(http.MethodPost)
// v5
router.HandleFunc("/api/v5/query_range", am.ViewAccess(ah.queryRangeV5)).Methods(http.MethodPost)
router.HandleFunc("/api/v5/substitute_vars", am.ViewAccess(ah.QuerierAPI.ReplaceVariables)).Methods(http.MethodPost)
// Gateway
router.PathPrefix(gateway.RoutePrefix).HandlerFunc(am.EditAccess(ah.ServeGatewayHTTP))

View File

@ -13,11 +13,11 @@ import (
"github.com/SigNoz/signoz/ee/query-service/constants"
"github.com/SigNoz/signoz/pkg/errors"
"github.com/SigNoz/signoz/pkg/http/render"
"github.com/SigNoz/signoz/pkg/modules/user"
basemodel "github.com/SigNoz/signoz/pkg/query-service/model"
"github.com/SigNoz/signoz/pkg/types"
"github.com/SigNoz/signoz/pkg/types/authtypes"
"github.com/SigNoz/signoz/pkg/valuer"
"github.com/google/uuid"
"github.com/gorilla/mux"
"go.uber.org/zap"
)
@ -192,14 +192,14 @@ func (ah *APIHandler) getOrCreateCloudIntegrationUser(
))
}
password, err := types.NewFactorPassword(uuid.NewString())
password := types.MustGenerateFactorPassword(newUser.ID.StringValue())
integrationUser, err := ah.Signoz.Modules.User.CreateUserWithPassword(ctx, newUser, password)
err = ah.Signoz.Modules.User.CreateUser(ctx, newUser, user.WithFactorPassword(password))
if err != nil {
return nil, basemodel.InternalError(fmt.Errorf("couldn't create cloud integration user: %w", err))
}
return integrationUser, nil
return newUser, nil
}
func getIngestionUrlAndSigNozAPIUrl(ctx context.Context, licenseKey string) (

View File

@ -2,11 +2,16 @@ package api
import (
"bytes"
"context"
"encoding/json"
"fmt"
"io"
"net/http"
"runtime/debug"
anomalyV2 "github.com/SigNoz/signoz/ee/anomaly"
"github.com/SigNoz/signoz/ee/query-service/anomaly"
"github.com/SigNoz/signoz/pkg/errors"
"github.com/SigNoz/signoz/pkg/http/render"
baseapp "github.com/SigNoz/signoz/pkg/query-service/app"
"github.com/SigNoz/signoz/pkg/query-service/app/queryBuilder"
@ -15,6 +20,8 @@ import (
"github.com/SigNoz/signoz/pkg/types/authtypes"
"github.com/SigNoz/signoz/pkg/valuer"
"go.uber.org/zap"
qbtypes "github.com/SigNoz/signoz/pkg/types/querybuildertypes/querybuildertypesv5"
)
func (aH *APIHandler) queryRangeV4(w http.ResponseWriter, r *http.Request) {
@ -136,3 +143,139 @@ func (aH *APIHandler) queryRangeV4(w http.ResponseWriter, r *http.Request) {
aH.QueryRangeV4(w, r)
}
}
func extractSeasonality(anomalyQuery *qbtypes.QueryBuilderQuery[qbtypes.MetricAggregation]) anomalyV2.Seasonality {
for _, fn := range anomalyQuery.Functions {
if fn.Name == qbtypes.FunctionNameAnomaly {
for _, arg := range fn.Args {
if arg.Name == "seasonality" {
if seasonalityStr, ok := arg.Value.(string); ok {
switch seasonalityStr {
case "weekly":
return anomalyV2.SeasonalityWeekly
case "hourly":
return anomalyV2.SeasonalityHourly
}
}
}
}
}
}
return anomalyV2.SeasonalityDaily // default
}
func createAnomalyProvider(aH *APIHandler, seasonality anomalyV2.Seasonality) anomalyV2.Provider {
switch seasonality {
case anomalyV2.SeasonalityWeekly:
return anomalyV2.NewWeeklyProvider(
anomalyV2.WithQuerier[*anomalyV2.WeeklyProvider](aH.Signoz.Querier),
anomalyV2.WithLogger[*anomalyV2.WeeklyProvider](aH.Signoz.Instrumentation.Logger()),
)
case anomalyV2.SeasonalityHourly:
return anomalyV2.NewHourlyProvider(
anomalyV2.WithQuerier[*anomalyV2.HourlyProvider](aH.Signoz.Querier),
anomalyV2.WithLogger[*anomalyV2.HourlyProvider](aH.Signoz.Instrumentation.Logger()),
)
default:
return anomalyV2.NewDailyProvider(
anomalyV2.WithQuerier[*anomalyV2.DailyProvider](aH.Signoz.Querier),
anomalyV2.WithLogger[*anomalyV2.DailyProvider](aH.Signoz.Instrumentation.Logger()),
)
}
}
func (aH *APIHandler) handleAnomalyQuery(ctx context.Context, orgID valuer.UUID, anomalyQuery *qbtypes.QueryBuilderQuery[qbtypes.MetricAggregation], queryRangeRequest qbtypes.QueryRangeRequest) (*anomalyV2.AnomaliesResponse, error) {
seasonality := extractSeasonality(anomalyQuery)
provider := createAnomalyProvider(aH, seasonality)
return provider.GetAnomalies(ctx, orgID, &anomalyV2.AnomaliesRequest{Params: queryRangeRequest})
}
func (aH *APIHandler) queryRangeV5(rw http.ResponseWriter, req *http.Request) {
bodyBytes, err := io.ReadAll(req.Body)
if err != nil {
render.Error(rw, errors.NewInvalidInputf(errors.CodeInvalidInput, "failed to read request body: %v", err))
return
}
req.Body = io.NopCloser(bytes.NewBuffer(bodyBytes))
ctx := req.Context()
claims, err := authtypes.ClaimsFromContext(ctx)
if err != nil {
render.Error(rw, err)
return
}
var queryRangeRequest qbtypes.QueryRangeRequest
if err := json.NewDecoder(req.Body).Decode(&queryRangeRequest); err != nil {
render.Error(rw, errors.NewInvalidInputf(errors.CodeInvalidInput, "failed to decode request body: %v", err))
return
}
defer func() {
if r := recover(); r != nil {
stackTrace := string(debug.Stack())
queryJSON, _ := json.Marshal(queryRangeRequest)
aH.Signoz.Instrumentation.Logger().ErrorContext(ctx, "panic in QueryRange",
"error", r,
"user", claims.UserID,
"payload", string(queryJSON),
"stacktrace", stackTrace,
)
render.Error(rw, errors.NewInternalf(
errors.CodeInternal,
"Something went wrong on our end. It's not you, it's us. Our team is notified about it. Reach out to support if issue persists.",
))
}
}()
if err := queryRangeRequest.Validate(); err != nil {
render.Error(rw, err)
return
}
orgID, err := valuer.NewUUID(claims.OrgID)
if err != nil {
render.Error(rw, err)
return
}
if anomalyQuery, ok := queryRangeRequest.IsAnomalyRequest(); ok {
anomalies, err := aH.handleAnomalyQuery(ctx, orgID, anomalyQuery, queryRangeRequest)
if err != nil {
render.Error(rw, errors.NewInternalf(errors.CodeInternal, "failed to get anomalies: %v", err))
return
}
results := []any{}
for _, item := range anomalies.Results {
results = append(results, item)
}
finalResp := &qbtypes.QueryRangeResponse{
Type: queryRangeRequest.RequestType,
Data: struct {
Results []any `json:"results"`
}{
Results: results,
},
Meta: struct {
RowsScanned uint64 `json:"rowsScanned"`
BytesScanned uint64 `json:"bytesScanned"`
DurationMS uint64 `json:"durationMs"`
}{},
}
render.Success(rw, http.StatusOK, finalResp)
return
} else {
// regular query range request, let the querier handle it
req.Body = io.NopCloser(bytes.NewBuffer(bodyBytes))
aH.QuerierAPI.QueryRange(rw, req)
}
}

View File

@ -3,10 +3,13 @@ package app
import (
"context"
"fmt"
"log/slog"
"net"
"net/http"
_ "net/http/pprof" // http profiler
"github.com/SigNoz/signoz/pkg/ruler/rulestore/sqlrulestore"
"github.com/gorilla/handlers"
"github.com/SigNoz/signoz/ee/query-service/app/api"
@ -18,6 +21,7 @@ import (
"github.com/SigNoz/signoz/pkg/http/middleware"
"github.com/SigNoz/signoz/pkg/modules/organization"
"github.com/SigNoz/signoz/pkg/prometheus"
"github.com/SigNoz/signoz/pkg/querier"
"github.com/SigNoz/signoz/pkg/signoz"
"github.com/SigNoz/signoz/pkg/sqlstore"
"github.com/SigNoz/signoz/pkg/telemetrystore"
@ -42,19 +46,6 @@ import (
"go.uber.org/zap"
)
type ServerOptions struct {
Config signoz.Config
SigNoz *signoz.SigNoz
HTTPHostPort string
PrivateHostPort string
PreferSpanMetrics bool
FluxInterval string
FluxIntervalForTraceDetail string
Cluster string
GatewayUrl string
Jwt *authtypes.JWT
}
// Server runs HTTP, Mux and a grpc server
type Server struct {
config signoz.Config
@ -67,11 +58,6 @@ type Server struct {
httpServer *http.Server
httpHostPort string
// private http
privateConn net.Listener
privateHTTP *http.Server
privateHostPort string
opampServer *opamp.Server
// Usage manager
@ -104,6 +90,8 @@ func NewServer(config signoz.Config, signoz *signoz.SigNoz, jwt *authtypes.JWT)
signoz.TelemetryStore,
signoz.Prometheus,
signoz.Modules.OrgGetter,
signoz.Querier,
signoz.Instrumentation.Logger(),
)
if err != nil {
@ -179,7 +167,6 @@ func NewServer(config signoz.Config, signoz *signoz.SigNoz, jwt *authtypes.JWT)
jwt: jwt,
ruleManager: rm,
httpHostPort: baseconst.HTTPHostPort,
privateHostPort: baseconst.PrivateHostPort,
unavailableChannel: make(chan healthcheck.Status),
usageManager: usageManager,
}
@ -192,13 +179,6 @@ func NewServer(config signoz.Config, signoz *signoz.SigNoz, jwt *authtypes.JWT)
s.httpServer = httpServer
privateServer, err := s.createPrivateServer(apiHandler)
if err != nil {
return nil, err
}
s.privateHTTP = privateServer
s.opampServer = opamp.InitializeServer(
&opAmpModel.AllAgents, agentConfMgr, signoz.Instrumentation,
)
@ -211,36 +191,6 @@ func (s Server) HealthCheckStatus() chan healthcheck.Status {
return s.unavailableChannel
}
func (s *Server) createPrivateServer(apiHandler *api.APIHandler) (*http.Server, error) {
r := baseapp.NewRouter()
r.Use(middleware.NewAuth(s.jwt, []string{"Authorization", "Sec-WebSocket-Protocol"}, s.signoz.Sharder, s.signoz.Instrumentation.Logger()).Wrap)
r.Use(middleware.NewAPIKey(s.signoz.SQLStore, []string{"SIGNOZ-API-KEY"}, s.signoz.Instrumentation.Logger(), s.signoz.Sharder).Wrap)
r.Use(middleware.NewTimeout(s.signoz.Instrumentation.Logger(),
s.config.APIServer.Timeout.ExcludedRoutes,
s.config.APIServer.Timeout.Default,
s.config.APIServer.Timeout.Max,
).Wrap)
r.Use(middleware.NewLogging(s.signoz.Instrumentation.Logger(), s.config.APIServer.Logging.ExcludedRoutes).Wrap)
apiHandler.RegisterPrivateRoutes(r)
c := cors.New(cors.Options{
//todo(amol): find out a way to add exact domain or
// ip here for alert manager
AllowedOrigins: []string{"*"},
AllowedMethods: []string{"GET", "DELETE", "POST", "PUT", "PATCH"},
AllowedHeaders: []string{"Accept", "Authorization", "Content-Type", "SIGNOZ-API-KEY", "X-SIGNOZ-QUERY-ID", "Sec-WebSocket-Protocol"},
})
handler := c.Handler(r)
handler = handlers.CompressHandler(handler)
return &http.Server{
Handler: handler,
}, nil
}
func (s *Server) createPublicServer(apiHandler *api.APIHandler, web web.Web) (*http.Server, error) {
r := baseapp.NewRouter()
am := middleware.NewAuthZ(s.signoz.Instrumentation.Logger())
@ -253,6 +203,7 @@ func (s *Server) createPublicServer(apiHandler *api.APIHandler, web web.Web) (*h
s.config.APIServer.Timeout.Max,
).Wrap)
r.Use(middleware.NewLogging(s.signoz.Instrumentation.Logger(), s.config.APIServer.Logging.ExcludedRoutes).Wrap)
r.Use(middleware.NewComment().Wrap)
apiHandler.RegisterRoutes(r, am)
apiHandler.RegisterLogsRoutes(r, am)
@ -305,19 +256,6 @@ func (s *Server) initListeners() error {
zap.L().Info(fmt.Sprintf("Query server started listening on %s...", s.httpHostPort))
// listen on private port to support internal services
privateHostPort := s.privateHostPort
if privateHostPort == "" {
return fmt.Errorf("baseconst.PrivateHostPort is required")
}
s.privateConn, err = net.Listen("tcp", privateHostPort)
if err != nil {
return err
}
zap.L().Info(fmt.Sprintf("Query server started listening on private port %s...", s.privateHostPort))
return nil
}
@ -356,26 +294,6 @@ func (s *Server) Start(ctx context.Context) error {
}
}()
var privatePort int
if port, err := utils.GetPort(s.privateConn.Addr()); err == nil {
privatePort = port
}
go func() {
zap.L().Info("Starting Private HTTP server", zap.Int("port", privatePort), zap.String("addr", s.privateHostPort))
switch err := s.privateHTTP.Serve(s.privateConn); err {
case nil, http.ErrServerClosed, cmux.ErrListenerClosed:
// normal exit, nothing to do
zap.L().Info("private http server closed")
default:
zap.L().Error("Could not start private HTTP server", zap.Error(err))
}
s.unavailableChannel <- healthcheck.Unavailable
}()
go func() {
zap.L().Info("Starting OpAmp Websocket server", zap.String("addr", baseconst.OpAmpWsEndpoint))
err := s.opampServer.Start(baseconst.OpAmpWsEndpoint)
@ -395,12 +313,6 @@ func (s *Server) Stop(ctx context.Context) error {
}
}
if s.privateHTTP != nil {
if err := s.privateHTTP.Shutdown(ctx); err != nil {
return err
}
}
s.opampServer.Stop()
if s.ruleManager != nil {
@ -413,15 +325,9 @@ func (s *Server) Stop(ctx context.Context) error {
return nil
}
func makeRulesManager(
ch baseint.Reader,
cache cache.Cache,
alertmanager alertmanager.Alertmanager,
sqlstore sqlstore.SQLStore,
telemetryStore telemetrystore.TelemetryStore,
prometheus prometheus.Prometheus,
orgGetter organization.Getter,
) (*baserules.Manager, error) {
func makeRulesManager(ch baseint.Reader, cache cache.Cache, alertmanager alertmanager.Alertmanager, sqlstore sqlstore.SQLStore, telemetryStore telemetrystore.TelemetryStore, prometheus prometheus.Prometheus, orgGetter organization.Getter, querier querier.Querier, logger *slog.Logger) (*baserules.Manager, error) {
ruleStore := sqlrulestore.NewRuleStore(sqlstore)
maintenanceStore := sqlrulestore.NewMaintenanceStore(sqlstore)
// create manager opts
managerOpts := &baserules.ManagerOptions{
TelemetryStore: telemetryStore,
@ -429,13 +335,17 @@ func makeRulesManager(
Context: context.Background(),
Logger: zap.L(),
Reader: ch,
Querier: querier,
SLogger: logger,
Cache: cache,
EvalDelay: baseconst.GetEvalDelay(),
PrepareTaskFunc: rules.PrepareTaskFunc,
PrepareTestRuleFunc: rules.TestNotification,
Alertmanager: alertmanager,
SQLStore: sqlstore,
OrgGetter: orgGetter,
RuleStore: ruleStore,
MaintenanceStore: maintenanceStore,
SqlStore: sqlstore,
}
// create Manager

View File

@ -40,7 +40,7 @@ var IsDotMetricsEnabled = false
var IsPreferSpanMetrics = false
func init() {
if GetOrDefaultEnv(DotMetricsEnabled, "false") == "true" {
if GetOrDefaultEnv(DotMetricsEnabled, "true") == "true" {
IsDotMetricsEnabled = true
}

View File

@ -1,7 +1,7 @@
package model
import (
"fmt"
"errors"
basemodel "github.com/SigNoz/signoz/pkg/query-service/model"
)
@ -57,7 +57,7 @@ func Unauthorized(err error) *ApiError {
func BadRequestStr(s string) *ApiError {
return &ApiError{
Typ: basemodel.ErrorBadData,
Err: fmt.Errorf(s),
Err: errors.New(s),
}
}
@ -73,7 +73,7 @@ func InternalError(err error) *ApiError {
func InternalErrorStr(s string) *ApiError {
return &ApiError{
Typ: basemodel.ErrorInternal,
Err: fmt.Errorf(s),
Err: errors.New(s),
}
}

View File

@ -4,17 +4,17 @@ import (
"context"
"encoding/json"
"fmt"
"log/slog"
"math"
"strings"
"sync"
"time"
"go.uber.org/zap"
"github.com/SigNoz/signoz/ee/query-service/anomaly"
"github.com/SigNoz/signoz/pkg/cache"
"github.com/SigNoz/signoz/pkg/query-service/common"
"github.com/SigNoz/signoz/pkg/query-service/model"
"github.com/SigNoz/signoz/pkg/transition"
ruletypes "github.com/SigNoz/signoz/pkg/types/ruletypes"
"github.com/SigNoz/signoz/pkg/valuer"
@ -30,7 +30,11 @@ import (
baserules "github.com/SigNoz/signoz/pkg/query-service/rules"
yaml "gopkg.in/yaml.v2"
querierV5 "github.com/SigNoz/signoz/pkg/querier"
anomalyV2 "github.com/SigNoz/signoz/ee/anomaly"
qbtypes "github.com/SigNoz/signoz/pkg/types/querybuildertypes/querybuildertypesv5"
)
const (
@ -47,7 +51,14 @@ type AnomalyRule struct {
// querierV2 is used for alerts created after the introduction of new metrics query builder
querierV2 interfaces.Querier
provider anomaly.Provider
// querierV5 is used for alerts migrated after the introduction of new query builder
querierV5 querierV5.Querier
provider anomaly.Provider
providerV2 anomalyV2.Provider
version string
logger *slog.Logger
seasonality anomaly.Seasonality
}
@ -57,11 +68,15 @@ func NewAnomalyRule(
orgID valuer.UUID,
p *ruletypes.PostableRule,
reader interfaces.Reader,
querierV5 querierV5.Querier,
logger *slog.Logger,
cache cache.Cache,
opts ...baserules.RuleOption,
) (*AnomalyRule, error) {
zap.L().Info("creating new AnomalyRule", zap.String("id", id), zap.Any("opts", opts))
logger.Info("creating new AnomalyRule", "rule_id", id)
opts = append(opts, baserules.WithLogger(logger))
if p.RuleCondition.CompareOp == ruletypes.ValueIsBelow {
target := -1 * *p.RuleCondition.Target
@ -88,7 +103,7 @@ func NewAnomalyRule(
t.seasonality = anomaly.SeasonalityDaily
}
zap.L().Info("using seasonality", zap.String("seasonality", t.seasonality.String()))
logger.Info("using seasonality", "seasonality", t.seasonality.String())
querierOptsV2 := querierV2.QuerierOptions{
Reader: reader,
@ -117,6 +132,27 @@ func NewAnomalyRule(
anomaly.WithReader[*anomaly.WeeklyProvider](reader),
)
}
if t.seasonality == anomaly.SeasonalityHourly {
t.providerV2 = anomalyV2.NewHourlyProvider(
anomalyV2.WithQuerier[*anomalyV2.HourlyProvider](querierV5),
anomalyV2.WithLogger[*anomalyV2.HourlyProvider](logger),
)
} else if t.seasonality == anomaly.SeasonalityDaily {
t.providerV2 = anomalyV2.NewDailyProvider(
anomalyV2.WithQuerier[*anomalyV2.DailyProvider](querierV5),
anomalyV2.WithLogger[*anomalyV2.DailyProvider](logger),
)
} else if t.seasonality == anomaly.SeasonalityWeekly {
t.providerV2 = anomalyV2.NewWeeklyProvider(
anomalyV2.WithQuerier[*anomalyV2.WeeklyProvider](querierV5),
anomalyV2.WithLogger[*anomalyV2.WeeklyProvider](logger),
)
}
t.querierV5 = querierV5
t.version = p.Version
t.logger = logger
return &t, nil
}
@ -124,20 +160,15 @@ func (r *AnomalyRule) Type() ruletypes.RuleType {
return RuleTypeAnomaly
}
func (r *AnomalyRule) prepareQueryRange(ts time.Time) (*v3.QueryRangeParamsV3, error) {
func (r *AnomalyRule) prepareQueryRange(ctx context.Context, ts time.Time) (*v3.QueryRangeParamsV3, error) {
zap.L().Info("prepareQueryRange", zap.Int64("ts", ts.UnixMilli()), zap.Int64("evalWindow", r.EvalWindow().Milliseconds()), zap.Int64("evalDelay", r.EvalDelay().Milliseconds()))
r.logger.InfoContext(
ctx, "prepare query range request v4", "ts", ts.UnixMilli(), "eval_window", r.EvalWindow().Milliseconds(), "eval_delay", r.EvalDelay().Milliseconds(),
)
start := ts.Add(-time.Duration(r.EvalWindow())).UnixMilli()
end := ts.UnixMilli()
if r.EvalDelay() > 0 {
start = start - int64(r.EvalDelay().Milliseconds())
end = end - int64(r.EvalDelay().Milliseconds())
}
// round to minute otherwise we could potentially miss data
start = start - (start % (60 * 1000))
end = end - (end % (60 * 1000))
st, en := r.Timestamps(ts)
start := st.UnixMilli()
end := en.UnixMilli()
compositeQuery := r.Condition().CompositeQuery
@ -156,13 +187,34 @@ func (r *AnomalyRule) prepareQueryRange(ts time.Time) (*v3.QueryRangeParamsV3, e
}, nil
}
func (r *AnomalyRule) prepareQueryRangeV5(ctx context.Context, ts time.Time) (*qbtypes.QueryRangeRequest, error) {
r.logger.InfoContext(ctx, "prepare query range request v5", "ts", ts.UnixMilli(), "eval_window", r.EvalWindow().Milliseconds(), "eval_delay", r.EvalDelay().Milliseconds())
startTs, endTs := r.Timestamps(ts)
start, end := startTs.UnixMilli(), endTs.UnixMilli()
req := &qbtypes.QueryRangeRequest{
Start: uint64(start),
End: uint64(end),
RequestType: qbtypes.RequestTypeTimeSeries,
CompositeQuery: qbtypes.CompositeQuery{
Queries: make([]qbtypes.QueryEnvelope, 0),
},
NoCache: true,
}
req.CompositeQuery.Queries = make([]qbtypes.QueryEnvelope, len(r.Condition().CompositeQuery.Queries))
copy(req.CompositeQuery.Queries, r.Condition().CompositeQuery.Queries)
return req, nil
}
func (r *AnomalyRule) GetSelectedQuery() string {
return r.Condition().GetSelectedQueryName()
}
func (r *AnomalyRule) buildAndRunQuery(ctx context.Context, orgID valuer.UUID, ts time.Time) (ruletypes.Vector, error) {
params, err := r.prepareQueryRange(ts)
params, err := r.prepareQueryRange(ctx, ts)
if err != nil {
return nil, err
}
@ -190,13 +242,70 @@ func (r *AnomalyRule) buildAndRunQuery(ctx context.Context, orgID valuer.UUID, t
var resultVector ruletypes.Vector
scoresJSON, _ := json.Marshal(queryResult.AnomalyScores)
zap.L().Info("anomaly scores", zap.String("scores", string(scoresJSON)))
r.logger.InfoContext(ctx, "anomaly scores", "scores", string(scoresJSON))
for _, series := range queryResult.AnomalyScores {
smpl, shouldAlert := r.ShouldAlert(*series)
if shouldAlert {
resultVector = append(resultVector, smpl)
if r.Condition() != nil && r.Condition().RequireMinPoints {
if len(series.Points) < r.Condition().RequiredNumPoints {
r.logger.InfoContext(ctx, "not enough data points to evaluate series, skipping", "ruleid", r.ID(), "numPoints", len(series.Points), "requiredPoints", r.Condition().RequiredNumPoints)
continue
}
}
results, err := r.Threshold.ShouldAlert(*series, r.Unit())
if err != nil {
return nil, err
}
resultVector = append(resultVector, results...)
}
return resultVector, nil
}
func (r *AnomalyRule) buildAndRunQueryV5(ctx context.Context, orgID valuer.UUID, ts time.Time) (ruletypes.Vector, error) {
params, err := r.prepareQueryRangeV5(ctx, ts)
if err != nil {
return nil, err
}
anomalies, err := r.providerV2.GetAnomalies(ctx, orgID, &anomalyV2.AnomaliesRequest{
Params: *params,
Seasonality: anomalyV2.Seasonality{String: valuer.NewString(r.seasonality.String())},
})
if err != nil {
return nil, err
}
var qbResult *qbtypes.TimeSeriesData
for _, result := range anomalies.Results {
if result.QueryName == r.GetSelectedQuery() {
qbResult = result
break
}
}
if qbResult == nil {
r.logger.WarnContext(ctx, "nil qb result", "ts", ts.UnixMilli())
}
queryResult := transition.ConvertV5TimeSeriesDataToV4Result(qbResult)
var resultVector ruletypes.Vector
scoresJSON, _ := json.Marshal(queryResult.AnomalyScores)
r.logger.InfoContext(ctx, "anomaly scores", "scores", string(scoresJSON))
for _, series := range queryResult.AnomalyScores {
if r.Condition().RequireMinPoints {
if len(series.Points) < r.Condition().RequiredNumPoints {
r.logger.InfoContext(ctx, "not enough data points to evaluate series, skipping", "ruleid", r.ID(), "numPoints", len(series.Points), "requiredPoints", r.Condition().RequiredNumPoints)
continue
}
}
results, err := r.Threshold.ShouldAlert(*series, r.Unit())
if err != nil {
return nil, err
}
resultVector = append(resultVector, results...)
}
return resultVector, nil
}
@ -206,8 +315,17 @@ func (r *AnomalyRule) Eval(ctx context.Context, ts time.Time) (interface{}, erro
prevState := r.State()
valueFormatter := formatter.FromUnit(r.Unit())
res, err := r.buildAndRunQuery(ctx, r.OrgID(), ts)
var res ruletypes.Vector
var err error
if r.version == "v5" {
r.logger.InfoContext(ctx, "running v5 query")
res, err = r.buildAndRunQueryV5(ctx, r.OrgID(), ts)
} else {
r.logger.InfoContext(ctx, "running v4 query")
res, err = r.buildAndRunQuery(ctx, r.OrgID(), ts)
}
if err != nil {
return nil, err
}
@ -218,15 +336,20 @@ func (r *AnomalyRule) Eval(ctx context.Context, ts time.Time) (interface{}, erro
resultFPs := map[uint64]struct{}{}
var alerts = make(map[uint64]*ruletypes.Alert, len(res))
ruleReceivers := r.Threshold.GetRuleReceivers()
ruleReceiverMap := make(map[string][]string)
for _, value := range ruleReceivers {
ruleReceiverMap[value.Name] = value.Channels
}
for _, smpl := range res {
l := make(map[string]string, len(smpl.Metric))
for _, lbl := range smpl.Metric {
l[lbl.Name] = lbl.Value
}
value := valueFormatter.Format(smpl.V, r.Unit())
threshold := valueFormatter.Format(r.TargetVal(), r.Unit())
zap.L().Debug("Alert template data for rule", zap.String("name", r.Name()), zap.String("formatter", valueFormatter.Name()), zap.String("value", value), zap.String("threshold", threshold))
threshold := valueFormatter.Format(smpl.Target, smpl.TargetUnit)
r.logger.DebugContext(ctx, "Alert template data for rule", "rule_name", r.Name(), "formatter", valueFormatter.Name(), "value", value, "threshold", threshold)
tmplData := ruletypes.AlertTemplateData(l, value, threshold)
// Inject some convenience variables that are easier to remember for users
@ -247,7 +370,7 @@ func (r *AnomalyRule) Eval(ctx context.Context, ts time.Time) (interface{}, erro
result, err := tmpl.Expand()
if err != nil {
result = fmt.Sprintf("<error expanding template: %s>", err)
zap.L().Error("Expanding alert template failed", zap.Error(err), zap.Any("data", tmplData))
r.logger.ErrorContext(ctx, "Expanding alert template failed", "error", err, "data", tmplData, "rule_name", r.Name())
}
return result
}
@ -269,6 +392,7 @@ func (r *AnomalyRule) Eval(ctx context.Context, ts time.Time) (interface{}, erro
}
if smpl.IsMissing {
lb.Set(labels.AlertNameLabel, "[No data] "+r.Name())
lb.Set(labels.NoDataLabel, "true")
}
lbs := lb.Labels()
@ -276,7 +400,7 @@ func (r *AnomalyRule) Eval(ctx context.Context, ts time.Time) (interface{}, erro
resultFPs[h] = struct{}{}
if _, ok := alerts[h]; ok {
zap.L().Error("the alert query returns duplicate records", zap.String("ruleid", r.ID()), zap.Any("alert", alerts[h]))
r.logger.ErrorContext(ctx, "the alert query returns duplicate records", "rule_id", r.ID(), "alert", alerts[h])
err = fmt.Errorf("duplicate alert found, vector contains metrics with the same labelset after applying alert labels")
return nil, err
}
@ -289,13 +413,12 @@ func (r *AnomalyRule) Eval(ctx context.Context, ts time.Time) (interface{}, erro
State: model.StatePending,
Value: smpl.V,
GeneratorURL: r.GeneratorURL(),
Receivers: r.PreferredChannels(),
Receivers: ruleReceiverMap[lbs.Map()[ruletypes.LabelThresholdName]],
Missing: smpl.IsMissing,
}
}
zap.L().Info("number of alerts found", zap.String("name", r.Name()), zap.Int("count", len(alerts)))
r.logger.InfoContext(ctx, "number of alerts found", "rule_name", r.Name(), "alerts_count", len(alerts))
// alerts[h] is ready, add or update active list now
for h, a := range alerts {
// Check whether we already have alerting state for the identifying label set.
@ -304,7 +427,9 @@ func (r *AnomalyRule) Eval(ctx context.Context, ts time.Time) (interface{}, erro
alert.Value = a.Value
alert.Annotations = a.Annotations
alert.Receivers = r.PreferredChannels()
if v, ok := alert.Labels.Map()[ruletypes.LabelThresholdName]; ok {
alert.Receivers = ruleReceiverMap[v]
}
continue
}
@ -317,7 +442,7 @@ func (r *AnomalyRule) Eval(ctx context.Context, ts time.Time) (interface{}, erro
for fp, a := range r.Active {
labelsJSON, err := json.Marshal(a.QueryResultLables)
if err != nil {
zap.L().Error("error marshaling labels", zap.Error(err), zap.Any("labels", a.Labels))
r.logger.ErrorContext(ctx, "error marshaling labels", "error", err, "labels", a.Labels)
}
if _, ok := resultFPs[fp]; !ok {
// If the alert was previously firing, keep it around for a given
@ -387,7 +512,7 @@ func (r *AnomalyRule) String() string {
PreferredChannels: r.PreferredChannels(),
}
byt, err := yaml.Marshal(ar)
byt, err := json.Marshal(ar)
if err != nil {
return fmt.Sprintf("error marshaling alerting rule: %s", err.Error())
}

View File

@ -3,8 +3,10 @@ package rules
import (
"context"
"fmt"
"time"
"github.com/SigNoz/signoz/pkg/errors"
basemodel "github.com/SigNoz/signoz/pkg/query-service/model"
baserules "github.com/SigNoz/signoz/pkg/query-service/rules"
"github.com/SigNoz/signoz/pkg/query-service/utils/labels"
@ -20,6 +22,10 @@ func PrepareTaskFunc(opts baserules.PrepareTaskOptions) (baserules.Task, error)
var task baserules.Task
ruleId := baserules.RuleIdFromTaskName(opts.TaskName)
evaluation, err := opts.Rule.Evaluation.GetEvaluation()
if err != nil {
return nil, errors.NewInvalidInputf(errors.CodeInvalidInput, "evaluation is invalid: %v", err)
}
if opts.Rule.RuleType == ruletypes.RuleTypeThreshold {
// create a threshold rule
tr, err := baserules.NewThresholdRule(
@ -27,6 +33,8 @@ func PrepareTaskFunc(opts baserules.PrepareTaskOptions) (baserules.Task, error)
opts.OrgID,
opts.Rule,
opts.Reader,
opts.Querier,
opts.SLogger,
baserules.WithEvalDelay(opts.ManagerOpts.EvalDelay),
baserules.WithSQLStore(opts.SQLStore),
)
@ -38,7 +46,7 @@ func PrepareTaskFunc(opts baserules.PrepareTaskOptions) (baserules.Task, error)
rules = append(rules, tr)
// create ch rule task for evalution
task = newTask(baserules.TaskTypeCh, opts.TaskName, time.Duration(opts.Rule.Frequency), rules, opts.ManagerOpts, opts.NotifyFunc, opts.MaintenanceStore, opts.OrgID)
task = newTask(baserules.TaskTypeCh, opts.TaskName, time.Duration(evaluation.GetFrequency()), rules, opts.ManagerOpts, opts.NotifyFunc, opts.MaintenanceStore, opts.OrgID)
} else if opts.Rule.RuleType == ruletypes.RuleTypeProm {
@ -47,7 +55,7 @@ func PrepareTaskFunc(opts baserules.PrepareTaskOptions) (baserules.Task, error)
ruleId,
opts.OrgID,
opts.Rule,
opts.Logger,
opts.SLogger,
opts.Reader,
opts.ManagerOpts.Prometheus,
baserules.WithSQLStore(opts.SQLStore),
@ -60,7 +68,7 @@ func PrepareTaskFunc(opts baserules.PrepareTaskOptions) (baserules.Task, error)
rules = append(rules, pr)
// create promql rule task for evalution
task = newTask(baserules.TaskTypeProm, opts.TaskName, time.Duration(opts.Rule.Frequency), rules, opts.ManagerOpts, opts.NotifyFunc, opts.MaintenanceStore, opts.OrgID)
task = newTask(baserules.TaskTypeProm, opts.TaskName, time.Duration(evaluation.GetFrequency()), rules, opts.ManagerOpts, opts.NotifyFunc, opts.MaintenanceStore, opts.OrgID)
} else if opts.Rule.RuleType == ruletypes.RuleTypeAnomaly {
// create anomaly rule
@ -69,6 +77,8 @@ func PrepareTaskFunc(opts baserules.PrepareTaskOptions) (baserules.Task, error)
opts.OrgID,
opts.Rule,
opts.Reader,
opts.Querier,
opts.SLogger,
opts.Cache,
baserules.WithEvalDelay(opts.ManagerOpts.EvalDelay),
baserules.WithSQLStore(opts.SQLStore),
@ -80,7 +90,7 @@ func PrepareTaskFunc(opts baserules.PrepareTaskOptions) (baserules.Task, error)
rules = append(rules, ar)
// create anomaly rule task for evalution
task = newTask(baserules.TaskTypeCh, opts.TaskName, time.Duration(opts.Rule.Frequency), rules, opts.ManagerOpts, opts.NotifyFunc, opts.MaintenanceStore, opts.OrgID)
task = newTask(baserules.TaskTypeCh, opts.TaskName, time.Duration(evaluation.GetFrequency()), rules, opts.ManagerOpts, opts.NotifyFunc, opts.MaintenanceStore, opts.OrgID)
} else {
return nil, fmt.Errorf("unsupported rule type %s. Supported types: %s, %s", opts.Rule.RuleType, ruletypes.RuleTypeProm, ruletypes.RuleTypeThreshold)
@ -116,7 +126,6 @@ func TestNotification(opts baserules.PrepareTestRuleOptions) (int, *basemodel.Ap
if parsedRule.RuleType == ruletypes.RuleTypeThreshold {
// add special labels for test alerts
parsedRule.Annotations[labels.AlertSummaryLabel] = fmt.Sprintf("The rule threshold is set to %.4f, and the observed metric value is {{$value}}.", *parsedRule.RuleCondition.Target)
parsedRule.Labels[labels.RuleSourceLabel] = ""
parsedRule.Labels[labels.AlertRuleIdLabel] = ""
@ -126,6 +135,8 @@ func TestNotification(opts baserules.PrepareTestRuleOptions) (int, *basemodel.Ap
opts.OrgID,
parsedRule,
opts.Reader,
opts.Querier,
opts.SLogger,
baserules.WithSendAlways(),
baserules.WithSendUnmatched(),
baserules.WithSQLStore(opts.SQLStore),
@ -143,7 +154,7 @@ func TestNotification(opts baserules.PrepareTestRuleOptions) (int, *basemodel.Ap
alertname,
opts.OrgID,
parsedRule,
opts.Logger,
opts.SLogger,
opts.Reader,
opts.ManagerOpts.Prometheus,
baserules.WithSendAlways(),
@ -162,6 +173,8 @@ func TestNotification(opts baserules.PrepareTestRuleOptions) (int, *basemodel.Ap
opts.OrgID,
parsedRule,
opts.Reader,
opts.Querier,
opts.SLogger,
opts.Cache,
baserules.WithSendAlways(),
baserules.WithSendUnmatched(),

484
frontend/.cursorrules Normal file
View File

@ -0,0 +1,484 @@
# Persona
You are an expert developer with deep knowledge of Jest, React Testing Library, MSW, and TypeScript, tasked with creating unit tests for this repository.
# Auto-detect TypeScript Usage
Check for TypeScript in the project through tsconfig.json or package.json dependencies.
Adjust syntax based on this detection.
# TypeScript Type Safety for Jest Tests
**CRITICAL**: All Jest tests MUST be fully type-safe with proper TypeScript types.
**Type Safety Requirements:**
- Use proper TypeScript interfaces for all mock data
- Type all Jest mock functions with `jest.MockedFunction<T>`
- Use generic types for React components and hooks
- Define proper return types for mock functions
- Use `as const` for literal types when needed
- Avoid `any` type use proper typing instead
# Unit Testing Focus
Focus on critical functionality (business logic, utility functions, component behavior)
Mock dependencies (API calls, external modules) before imports
Test multiple data scenarios (valid inputs, invalid inputs, edge cases)
Write maintainable tests with descriptive names grouped in describe blocks
# Global vs Local Mocks
**Use Global Mocks for:**
- High-frequency dependencies (20+ test files)
- Core infrastructure (react-router-dom, react-query, antd)
- Standard implementations across the app
- Browser APIs (ResizeObserver, matchMedia, localStorage)
- Utility libraries (date-fns, lodash)
**Use Local Mocks for:**
- Business logic dependencies (5-15 test files)
- Test-specific behavior (different data per test)
- API endpoints with specific responses
- Domain-specific components
- Error scenarios and edge cases
**Global Mock Files Available (from jest.config.ts):**
- `uplot` → `__mocks__/uplotMock.ts`
# Repo-specific Testing Conventions
## Imports
Always import from our harness:
```ts
import { render, screen, userEvent, waitFor } from 'tests/test-utils';
```
For API mocks:
```ts
import { server, rest } from 'mocks-server/server';
```
Do not import directly from `@testing-library/react`.
## Router
Use the router built into render:
```ts
render(<Page />, undefined, { initialRoute: '/traces-explorer' });
```
Only mock `useLocation` / `useParams` if the test depends on them.
## Hook Mocks
Pattern:
```ts
import useFoo from 'hooks/useFoo';
jest.mock('hooks/useFoo');
const mockUseFoo = jest.mocked(useFoo);
mockUseFoo.mockReturnValue(/* minimal shape */ as any);
```
Prefer helpers (`rqSuccess`, `rqLoading`, `rqError`) for React Query results.
## MSW
Global MSW server runs automatically.
Override per-test:
```ts
server.use(
rest.get('*/api/v1/foo', (_req, res, ctx) => res(ctx.status(200), ctx.json({ ok: true })))
);
```
Keep large responses in `mocks-server/__mockdata_`.
## Interactions
- Prefer `userEvent` for real user interactions (click, type, select, tab).
- Use `fireEvent` only for low-level/programmatic events not covered by `userEvent` (e.g., scroll, resize, setting `element.scrollTop` for virtualization). Wrap in `act(...)` if needed.
- Always await interactions:
```ts
const user = userEvent.setup({ pointerEventsCheck: 0 });
await user.click(screen.getByRole('button', { name: /save/i }));
```
```ts
// Example: virtualized list scroll (no userEvent helper)
const scroller = container.querySelector('[data-test-id="virtuoso-scroller"]') as HTMLElement;
scroller.scrollTop = targetScrollTop;
act(() => { fireEvent.scroll(scroller); });
```
## Timers
❌ No global fake timers.
✅ Per-test only, for debounce/throttle:
```ts
jest.useFakeTimers();
const user = userEvent.setup({ advanceTimers: (ms) => jest.advanceTimersByTime(ms) });
await user.type(screen.getByRole('textbox'), 'query');
jest.advanceTimersByTime(400);
jest.useRealTimers();
```
## Queries
Prefer accessible queries (`getByRole`, `findByRole`, `getByLabelText`).
Fallback: visible text.
Last resort: `data-testid`.
# Example Test (using only configured global mocks)
```ts
import { render, screen, userEvent, waitFor } from 'tests/test-utils';
import { server, rest } from 'mocks-server/server';
import MyComponent from '../MyComponent';
describe('MyComponent', () => {
it('renders and interacts', async () => {
const user = userEvent.setup({ pointerEventsCheck: 0 });
server.use(
rest.get('*/api/v1/example', (_req, res, ctx) => res(ctx.status(200), ctx.json({ value: 42 })))
);
render(<MyComponent />, undefined, { initialRoute: '/foo' });
expect(await screen.findByText(/value: 42/i)).toBeInTheDocument();
await user.click(screen.getByRole('button', { name: /refresh/i }));
await waitFor(() => expect(screen.getByText(/loading/i)).toBeInTheDocument());
});
});
```
# Anti-patterns
❌ Importing RTL directly
❌ Using global fake timers
❌ Wrapping render in `act(...)`
❌ Mocking infra dependencies locally (router, react-query)
✅ Use our harness (`tests/test-utils`)
✅ Use MSW for API overrides
✅ Use userEvent + await
✅ Pin time only in tests that assert relative dates
# Best Practices
- **Critical Functionality**: Prioritize testing business logic and utilities
- **Dependency Mocking**: Global mocks for infra, local mocks for business logic
- **Data Scenarios**: Always test valid, invalid, and edge cases
- **Descriptive Names**: Make test intent clear
- **Organization**: Group related tests in describe
- **Consistency**: Match repo conventions
- **Edge Cases**: Test null, undefined, unexpected values
- **Limit Scope**: 35 focused tests per file
- **Use Helpers**: `rqSuccess`, `makeUser`, etc.
- **No Any**: Enforce type safety
# Example Test
```ts
import { render, screen, userEvent, waitFor } from 'tests/test-utils';
import { server, rest } from 'mocks-server/server';
import MyComponent from '../MyComponent';
describe('MyComponent', () => {
it('renders and interacts', async () => {
const user = userEvent.setup({ pointerEventsCheck: 0 });
server.use(
rest.get('*/api/v1/example', (_req, res, ctx) => res(ctx.status(200), ctx.json({ value: 42 })))
);
render(<MyComponent />, undefined, { initialRoute: '/foo' });
expect(await screen.findByText(/value: 42/i)).toBeInTheDocument();
await user.click(screen.getByRole('button', { name: /refresh/i }));
await waitFor(() => expect(screen.getByText(/loading/i)).toBeInTheDocument());
});
});
```
# Anti-patterns
❌ Importing RTL directly
❌ Using global fake timers
❌ Wrapping render in `act(...)`
❌ Mocking infra dependencies locally (router, react-query)
✅ Use our harness (`tests/test-utils`)
✅ Use MSW for API overrides
✅ Use userEvent + await
✅ Pin time only in tests that assert relative dates
# TypeScript Type Safety Examples
## Proper Mock Typing
```ts
// ✅ GOOD - Properly typed mocks
interface User {
id: number;
name: string;
email: string;
}
interface ApiResponse<T> {
data: T;
status: number;
message: string;
}
// Type the mock functions
const mockFetchUser = jest.fn() as jest.MockedFunction<(id: number) => Promise<ApiResponse<User>>>;
const mockUpdateUser = jest.fn() as jest.MockedFunction<(user: User) => Promise<ApiResponse<User>>>;
// Mock implementation with proper typing
mockFetchUser.mockResolvedValue({
data: { id: 1, name: 'John Doe', email: 'john@example.com' },
status: 200,
message: 'Success'
});
// ❌ BAD - Using any type
const mockFetchUser = jest.fn() as any; // Don't do this
```
## React Component Testing with Types
```ts
// ✅ GOOD - Properly typed component testing
interface ComponentProps {
title: string;
data: User[];
onUserSelect: (user: User) => void;
isLoading?: boolean;
}
const TestComponent: React.FC<ComponentProps> = ({ title, data, onUserSelect, isLoading = false }) => {
// Component implementation
};
describe('TestComponent', () => {
it('should render with proper props', () => {
// Arrange - Type the props properly
const mockProps: ComponentProps = {
title: 'Test Title',
data: [{ id: 1, name: 'John', email: 'john@example.com' }],
onUserSelect: jest.fn() as jest.MockedFunction<(user: User) => void>,
isLoading: false
};
// Act
render(<TestComponent {...mockProps} />);
// Assert
expect(screen.getByText('Test Title')).toBeInTheDocument();
});
});
```
## Hook Testing with Types
```ts
// ✅ GOOD - Properly typed hook testing
interface UseUserDataReturn {
user: User | null;
loading: boolean;
error: string | null;
refetch: () => void;
}
const useUserData = (id: number): UseUserDataReturn => {
// Hook implementation
};
describe('useUserData', () => {
it('should return user data with proper typing', () => {
// Arrange
const mockUser: User = { id: 1, name: 'John', email: 'john@example.com' };
mockFetchUser.mockResolvedValue({
data: mockUser,
status: 200,
message: 'Success'
});
// Act
const { result } = renderHook(() => useUserData(1));
// Assert
expect(result.current.user).toEqual(mockUser);
expect(result.current.loading).toBe(false);
expect(result.current.error).toBeNull();
});
});
```
## Global Mock Type Safety
```ts
// ✅ GOOD - Type-safe global mocks
// In __mocks__/routerMock.ts
export const mockUseLocation = (overrides: Partial<Location> = {}): Location => ({
pathname: '/traces',
search: '',
hash: '',
state: null,
key: 'test-key',
...overrides,
});
// In test files
const location = useLocation(); // Properly typed from global mock
expect(location.pathname).toBe('/traces');
```
# TypeScript Configuration for Jest
## Required Jest Configuration
```json
// jest.config.ts
{
"preset": "ts-jest/presets/js-with-ts-esm",
"globals": {
"ts-jest": {
"useESM": true,
"isolatedModules": true,
"tsconfig": "<rootDir>/tsconfig.jest.json"
}
},
"extensionsToTreatAsEsm": [".ts", ".tsx"],
"moduleFileExtensions": ["ts", "tsx", "js", "json"]
}
```
## TypeScript Jest Configuration
```json
// tsconfig.jest.json
{
"extends": "./tsconfig.json",
"compilerOptions": {
"types": ["jest", "@testing-library/jest-dom"],
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"moduleResolution": "node"
},
"include": [
"src/**/*",
"**/*.test.ts",
"**/*.test.tsx",
"__mocks__/**/*"
]
}
```
## Common Type Safety Patterns
### Mock Function Typing
```ts
// ✅ GOOD - Proper mock function typing
const mockApiCall = jest.fn() as jest.MockedFunction<typeof apiCall>;
const mockEventHandler = jest.fn() as jest.MockedFunction<(event: Event) => void>;
// ❌ BAD - Using any
const mockApiCall = jest.fn() as any;
```
### Generic Mock Typing
```ts
// ✅ GOOD - Generic mock typing
interface MockApiResponse<T> {
data: T;
status: number;
}
const mockFetchData = jest.fn() as jest.MockedFunction<
<T>(endpoint: string) => Promise<MockApiResponse<T>>
>;
// Usage
mockFetchData<User>('/users').mockResolvedValue({
data: { id: 1, name: 'John' },
status: 200
});
```
### React Testing Library with Types
```ts
// ✅ GOOD - Typed testing utilities
import { render, screen, RenderResult } from '@testing-library/react';
import { ComponentProps } from 'react';
type TestComponentProps = ComponentProps<typeof TestComponent>;
const renderTestComponent = (props: Partial<TestComponentProps> = {}): RenderResult => {
const defaultProps: TestComponentProps = {
title: 'Test',
data: [],
onSelect: jest.fn(),
...props
};
return render(<TestComponent {...defaultProps} />);
};
```
### Error Handling with Types
```ts
// ✅ GOOD - Typed error handling
interface ApiError {
message: string;
code: number;
details?: Record<string, unknown>;
}
const mockApiError: ApiError = {
message: 'API Error',
code: 500,
details: { endpoint: '/users' }
};
mockFetchUser.mockRejectedValue(new Error(JSON.stringify(mockApiError)));
```
## Type Safety Checklist
- [ ] All mock functions use `jest.MockedFunction<T>`
- [ ] All mock data has proper interfaces
- [ ] No `any` types in test files
- [ ] Generic types are used where appropriate
- [ ] Error types are properly defined
- [ ] Component props are typed
- [ ] Hook return types are defined
- [ ] API response types are defined
- [ ] Global mocks are type-safe
- [ ] Test utilities are properly typed
# Mock Decision Tree
```
Is it used in 20+ test files?
├─ YES → Use Global Mock
│ ├─ react-router-dom
│ ├─ react-query
│ ├─ antd components
│ └─ browser APIs
└─ NO → Is it business logic?
├─ YES → Use Local Mock
│ ├─ API endpoints
│ ├─ Custom hooks
│ └─ Domain components
└─ NO → Is it test-specific?
├─ YES → Use Local Mock
│ ├─ Error scenarios
│ ├─ Loading states
│ └─ Specific data
└─ NO → Consider Global Mock
└─ If it becomes frequently used
```
# Common Anti-Patterns to Avoid
❌ **Don't mock global dependencies locally:**
```js
// BAD - This is already globally mocked
jest.mock('react-router-dom', () => ({ ... }));
```
❌ **Don't create global mocks for test-specific data:**
```js
// BAD - This should be local
jest.mock('../api/tracesService', () => ({
getTraces: jest.fn(() => specificTestData)
}));
```
✅ **Do use global mocks for infrastructure:**
```js
// GOOD - Use global mock
import { useLocation } from 'react-router-dom';
```
✅ **Do create local mocks for business logic:**
```js
// GOOD - Local mock for specific test needs
jest.mock('../api/tracesService', () => ({
getTraces: jest.fn(() => mockTracesData)
}));
```

View File

@ -1,4 +1,5 @@
node_modules
build
*.typegen.ts
i18-generate-hash.js
i18-generate-hash.js
src/parser/TraceOperatorParser/**

View File

@ -1,4 +1,5 @@
module.exports = {
ignorePatterns: ['src/parser/*.ts'],
env: {
browser: true,
es2021: true,

27
frontend/.gitignore vendored
View File

@ -2,3 +2,30 @@
# Sentry Config File
.env.sentry-build-plugin
.qodo
# Playwright
node_modules/
/test-results/
/playwright-report/
/blob-report/
/playwright/.cache/
/playwright/test-results/
/playwright/blob-report/
/playwright/playwright-report/
e2e/test-plan/alerts/
e2e/test-plan/dashboards/
e2e/test-plan/exceptions/
e2e/test-plan/external-apis/
e2e/test-plan/help-support/
e2e/test-plan/infrastructure/
e2e/test-plan/logs/
e2e/test-plan/messaging-queues/
e2e/test-plan/metrics/
e2e/test-plan/navigation/
e2e/test-plan/onboarding/
e2e/test-plan/saved-views/
e2e/test-plan/service-map/
e2e/test-plan/services/
e2e/test-plan/traces/
e2e/test-plan/user-preferences/

View File

@ -8,3 +8,8 @@ public/
# Ignore all JSON files:
**/*.json
# Ignore all files in parser folder:
src/parser/**
src/TraceOperator/parser/**

View File

@ -0,0 +1,51 @@
/* eslint-disable @typescript-eslint/no-unused-vars */
// Mock for uplot library used in tests
export interface MockUPlotInstance {
setData: jest.Mock;
setSize: jest.Mock;
destroy: jest.Mock;
redraw: jest.Mock;
setSeries: jest.Mock;
}
export interface MockUPlotPaths {
spline: jest.Mock;
bars: jest.Mock;
}
// Create mock instance methods
const createMockUPlotInstance = (): MockUPlotInstance => ({
setData: jest.fn(),
setSize: jest.fn(),
destroy: jest.fn(),
redraw: jest.fn(),
setSeries: jest.fn(),
});
// Create mock paths
const mockPaths: MockUPlotPaths = {
spline: jest.fn(),
bars: jest.fn(),
};
// Mock static methods
const mockTzDate = jest.fn(
(date: Date, _timezone: string) => new Date(date.getTime()),
);
// Mock uPlot constructor - this needs to be a proper constructor function
function MockUPlot(
_options: unknown,
_data: unknown,
_target: HTMLElement,
): MockUPlotInstance {
return createMockUPlotInstance();
}
// Add static methods to the constructor
MockUPlot.tzDate = mockTzDate;
MockUPlot.paths = mockPaths;
// Export the constructor as default
export default MockUPlot;

View File

@ -0,0 +1,29 @@
// Mock for useSafeNavigate hook to avoid React Router version conflicts in tests
interface SafeNavigateOptions {
replace?: boolean;
state?: unknown;
}
interface SafeNavigateTo {
pathname?: string;
search?: string;
hash?: string;
}
type SafeNavigateToType = string | SafeNavigateTo;
interface UseSafeNavigateReturn {
safeNavigate: jest.MockedFunction<
(to: SafeNavigateToType, options?: SafeNavigateOptions) => void
>;
}
export const useSafeNavigate = (): UseSafeNavigateReturn => ({
safeNavigate: jest.fn(
(to: SafeNavigateToType, options?: SafeNavigateOptions) => {
console.log(`Mock safeNavigate called with:`, to, options);
},
) as jest.MockedFunction<
(to: SafeNavigateToType, options?: SafeNavigateOptions) => void
>,
});

View File

@ -0,0 +1,29 @@
# SigNoz E2E Test Plan
This directory contains the structured test plan for the SigNoz application. Each subfolder corresponds to a main module or feature area, and contains scenario files for all user journeys, edge cases, and cross-module flows. These documents serve as the basis for generating Playwright MCP-driven E2E tests.
## Structure
- Each main module (e.g., logs, traces, dashboards, alerts, settings, etc.) has its own folder or markdown file.
- Each file contains detailed scenario templates, including preconditions, step-by-step actions, and expected outcomes.
- Use these documents to write, review, and update test cases as the application evolves.
## Folders & Files
- `logs/` — Logs module scenarios
- `traces/` — Traces module scenarios
- `metrics/` — Metrics module scenarios
- `dashboards/` — Dashboards module scenarios
- `alerts/` — Alerts module scenarios
- `services/` — Services module scenarios
- `settings/` — Settings and all sub-settings scenarios
- `onboarding/` — Onboarding and signup flows
- `navigation/` — Navigation, sidebar, and cross-module flows
- `exceptions/` — Exception and error handling scenarios
- `external-apis/` — External API monitoring scenarios
- `messaging-queues/` — Messaging queue scenarios
- `infrastructure/` — Infrastructure monitoring scenarios
- `help-support/` — Help & support scenarios
- `user-preferences/` — User preferences and personalization scenarios
- `service-map/` — Service map scenarios
- `saved-views/` — Saved views scenarios

View File

@ -0,0 +1,16 @@
# Settings Module Test Plan
This folder contains E2E test scenarios for the Settings module and all sub-settings.
## Scenario Categories
- General settings (org/workspace, branding, version info)
- Billing settings
- Members & SSO
- Custom domain
- Integrations
- Notification channels
- API keys
- Ingestion
- Account settings (profile, password, preferences)
- Keyboard shortcuts

View File

@ -0,0 +1,43 @@
# Account Settings E2E Scenarios (Updated)
## 1. Update Name
- **Precondition:** User is logged in
- **Steps:**
1. Click 'Update name' button
2. Edit name field in the modal/dialog
3. Save changes
- **Expected:** Name is updated in the UI
## 2. Update Email
- **Note:** The email field is not editable in the current UI.
## 3. Reset Password
- **Precondition:** User is logged in
- **Steps:**
1. Click 'Reset password' button
2. Complete reset flow (modal/dialog or external flow)
- **Expected:** Password is reset
## 4. Toggle 'Adapt to my timezone'
- **Precondition:** User is logged in
- **Steps:**
1. Toggle 'Adapt to my timezone' switch
- **Expected:** Timezone adapts accordingly (UI feedback/confirmation should be checked)
## 5. Toggle Theme (Dark/Light)
- **Precondition:** User is logged in
- **Steps:**
1. Toggle theme radio buttons ('Dark', 'Light Beta')
- **Expected:** Theme changes
## 6. Toggle Sidebar Always Open
- **Precondition:** User is logged in
- **Steps:**
1. Toggle 'Keep the primary sidebar always open' switch
- **Expected:** Sidebar remains open/closed as per toggle

View File

@ -0,0 +1,26 @@
# API Keys E2E Scenarios (Updated)
## 1. Create a New API Key
- **Precondition:** User is admin
- **Steps:**
1. Click 'New Key' button
2. Enter details in the modal/dialog
3. Click 'Save'
- **Expected:** API key is created and listed in the table
## 2. Revoke an API Key
- **Precondition:** API key exists
- **Steps:**
1. In the table, locate the API key row
2. Click the revoke/delete button (icon button in the Action column)
3. Confirm if prompted
- **Expected:** API key is revoked/removed from the table
## 3. View API Key Usage
- **Precondition:** API key exists
- **Steps:**
1. View the 'Last used' and 'Expired' columns in the table
- **Expected:** Usage data is displayed for each API key

View File

@ -0,0 +1,17 @@
# Billing Settings E2E Scenarios (Updated)
## 1. View Billing Information
- **Precondition:** User is admin
- **Steps:**
1. Navigate to Billing Settings
2. Wait for the billing chart/data to finish loading
- **Expected:**
- Billing heading and subheading are displayed
- Usage/cost table is visible with columns: Unit, Data Ingested, Price per Unit, Cost (Billing period to date)
- "Download CSV" and "Manage Billing" buttons are present and enabled after loading
- Test clicking "Download CSV" and "Manage Billing" for expected behavior (e.g., file download, navigation, or modal)
> Note: If these features are expected to trigger specific flows, document the observed behavior for each button.

View File

@ -0,0 +1,18 @@
# Custom Domain E2E Scenarios (Updated)
## 1. Add or Update Custom Domain
- **Precondition:** User is admin
- **Steps:**
1. Click 'Customize teams URL' button
2. In the 'Customize your teams URL' dialog, enter the preferred subdomain
3. Click 'Apply Changes'
- **Expected:** Domain is set/updated for the team (UI feedback/confirmation should be checked)
## 2. Verify Domain Ownership
- **Note:** No explicit 'Verify' button or flow is present in the current UI. If verification is required, it may be handled automatically or via support.
## 3. Remove a Custom Domain
- **Note:** No explicit 'Remove' button or flow is present in the current UI. The only available action is to update the subdomain.

View File

@ -0,0 +1,31 @@
# General Settings E2E Scenarios
## 1. View General Settings
- **Precondition:** User is logged in
- **Steps:**
1. Navigate to General Settings
- **Expected:** General settings are displayed
## 2. Update Organization/Workspace Name
- **Precondition:** User is admin
- **Steps:**
1. Edit organization/workspace name
2. Save changes
- **Expected:** Name is updated and visible
## 3. Update Logo or Branding
- **Precondition:** User is admin
- **Steps:**
1. Upload new logo/branding
2. Save changes
- **Expected:** Branding is updated
## 4. View Version/Build Info
- **Precondition:** User is logged in
- **Steps:**
1. View version/build info section
- **Expected:** Version/build info is displayed

View File

@ -0,0 +1,20 @@
# Ingestion E2E Scenarios (Updated)
## 1. View Ingestion Sources
- **Precondition:** User is admin
- **Steps:**
1. Navigate to the Integrations page
- **Expected:** List of available data sources/integrations is displayed
## 2. Configure Ingestion Sources
- **Precondition:** User is admin
- **Steps:**
1. Click 'Configure' for a data source/integration
2. Complete the configuration flow (modal or page, as available)
- **Expected:** Source is configured (UI feedback/confirmation should be checked)
## 3. Disable/Enable Ingestion
- **Note:** No visible enable/disable toggle for ingestion sources in the current UI. Ingestion is managed via the Integrations configuration flows.

View File

@ -0,0 +1,51 @@
# Integrations E2E Scenarios (Updated)
## 1. View List of Available Integrations
- **Precondition:** User is logged in
- **Steps:**
1. Navigate to Integrations
- **Expected:** List of integrations is displayed, each with a name, description, and 'Configure' button
## 2. Search Integrations by Name/Type
- **Precondition:** Integrations exist
- **Steps:**
1. Enter search/filter criteria in the 'Search for an integration...' box
- **Expected:** Only matching integrations are shown
## 3. Connect a New Integration
- **Precondition:** User is admin
- **Steps:**
1. Click 'Configure' for an integration
2. Complete the configuration flow (modal or page, as available)
- **Expected:** Integration is connected/configured (UI feedback/confirmation should be checked)
## 4. Disconnect an Integration
- **Note:** No visible 'Disconnect' button in the main list. This may be available in the configuration flow for a connected integration.
## 5. Configure Integration Settings
- **Note:** Configuration is handled in the flow after clicking 'Configure' for an integration.
## 6. Test Integration Connection
- **Note:** No visible 'Test Connection' button in the main list. This may be available in the configuration flow.
## 7. View Integration Status/Logs
- **Note:** No visible status/logs section in the main list. This may be available in the configuration flow.
## 8. Filter Integrations by Category
- **Note:** No explicit category filter in the current UI, only a search box.
## 9. View Integration Documentation/Help
- **Note:** No visible 'Help/Docs' button in the main list. This may be available in the configuration flow.
## 10. Update Integration Configuration
- **Note:** Configuration is handled in the flow after clicking 'Configure' for an integration.

View File

@ -0,0 +1,19 @@
# Keyboard Shortcuts E2E Scenarios (Updated)
## 1. View Keyboard Shortcuts
- **Precondition:** User is logged in
- **Steps:**
1. Navigate to Keyboard Shortcuts
- **Expected:** Shortcuts are displayed in categorized tables (Global, Logs Explorer, Query Builder, Dashboard)
## 2. Customize Keyboard Shortcuts (if supported)
- **Note:** Customization is not available in the current UI. Shortcuts are view-only.
## 3. Use Keyboard Shortcuts for Navigation/Actions
- **Precondition:** User is logged in
- **Steps:**
1. Use shortcut for navigation/action (e.g., shift+s for Services, cmd+enter for running query)
- **Expected:** Navigation/action is performed as per shortcut

View File

@ -0,0 +1,49 @@
# Members & SSO E2E Scenarios (Updated)
## 1. Invite a New Member
- **Precondition:** User is admin
- **Steps:**
1. Click 'Invite Members' button
2. In the 'Invite team members' dialog, enter email address, name (optional), and select role
3. (Optional) Click 'Add another team member' to invite more
4. Click 'Invite team members' to send invite(s)
- **Expected:** Pending invite appears in the 'Pending Invites' table
## 2. Remove a Member
- **Precondition:** User is admin, member exists
- **Steps:**
1. In the 'Members' table, locate the member row
2. Click 'Delete' in the Action column
3. Confirm removal if prompted
- **Expected:** Member is removed from the table
## 3. Update Member Roles
- **Precondition:** User is admin, member exists
- **Steps:**
1. In the 'Members' table, locate the member row
2. Click 'Edit' in the Action column
3. Change role in the edit dialog/modal
4. Save changes
- **Expected:** Member role is updated in the table
## 4. Configure SSO
- **Precondition:** User is admin
- **Steps:**
1. In the 'Authenticated Domains' section, locate the domain row
2. Click 'Configure SSO' or 'Edit Google Auth' as available
3. Complete SSO provider configuration in the modal/dialog
4. Save settings
- **Expected:** SSO is configured for the domain
## 5. Login via SSO
- **Precondition:** SSO is configured
- **Steps:**
1. Log out from the app
2. On the login page, click 'Login with SSO'
3. Complete SSO login flow
- **Expected:** User is logged in via SSO

View File

@ -0,0 +1,39 @@
# Notification Channels E2E Scenarios (Updated)
## 1. Add a New Notification Channel
- **Precondition:** User is admin
- **Steps:**
1. Click 'New Alert Channel' button
2. In the 'New Notification Channel' form, fill in required fields (Name, Type, Webhook URL, etc.)
3. (Optional) Toggle 'Send resolved alerts'
4. (Optional) Click 'Test' to send a test notification
5. Click 'Save' to add the channel
- **Expected:** Channel is added and listed in the table
## 2. Test Notification Channel
- **Precondition:** Channel is being created or edited
- **Steps:**
1. In the 'New Notification Channel' or 'Edit Notification Channel' form, click 'Test'
- **Expected:** Test notification is sent (UI feedback/confirmation should be checked)
## 3. Remove a Notification Channel
- **Precondition:** Channel is added
- **Steps:**
1. In the table, locate the channel row
2. Click 'Delete' in the Action column
3. Confirm removal if prompted
- **Expected:** Channel is removed from the table
## 4. Update Notification Channel Settings
- **Precondition:** Channel is added
- **Steps:**
1. In the table, locate the channel row
2. Click 'Edit' in the Action column
3. In the 'Edit Notification Channel' form, update fields as needed
4. (Optional) Click 'Test' to send a test notification
5. Click 'Save' to update the channel
- **Expected:** Settings are updated

View File

@ -0,0 +1,199 @@
# SigNoz Test Plan Validation Report
This report documents the validation of the E2E test plan against the current live application using Playwright MCP. Each module is reviewed for coverage, gaps, and required updates.
---
## Home Module
- **Coverage:**
- Widgets for logs, traces, metrics, dashboards, alerts, services, saved views, onboarding checklist
- Quick access buttons: Explore Logs, Create dashboard, Create an alert
- **Gaps/Updates:**
- Add scenarios for checklist interactions (e.g., “Ill do this later”, progress tracking)
- Add scenarios for Saved Views and cross-module links
- Add scenario for onboarding checklist completion
---
## Logs Module
- **Coverage:**
- Explorer, Pipelines, Views tabs
- Filtering by service, environment, severity, host, k8s, etc.
- Search, save view, create alert, add to dashboard, export, view mode switching
- **Gaps/Updates:**
- Add scenario for quick filter customization
- Add scenario for “Old Explorer” button
- Add scenario for frequency chart toggle
- Add scenario for “Stage & Run Query” workflow
---
## Traces Module
- **Coverage:**
- Tabs: Explorer, Funnels, Views
- Filtering by name, error status, duration, environment, function, service, RPC, status code, HTTP, trace ID, etc.
- Search, save view, create alert, add to dashboard, export, view mode switching (List, Traces, Time Series, Table)
- Pagination, quick filter customization, group by, aggregation
- **Gaps/Updates:**
- Add scenario for quick filter customization
- Add scenario for “Stage & Run Query” workflow
- Add scenario for all view modes (List, Traces, Time Series, Table)
- Add scenario for group by/aggregation
- Add scenario for trace detail navigation (clicking on trace row)
- Add scenario for Funnels tab (create/edit/delete funnel)
- Add scenario for Views tab (manage saved views)
---
## Metrics Module
- **Coverage:**
- Tabs: Summary, Explorer, Views
- Filtering by metric, type, unit, etc.
- Search, save view, add to dashboard, export, view mode switching (chart, table, proportion view)
- Pagination, group by, aggregation, custom queries
- **Gaps/Updates:**
- Add scenario for Proportion View in Summary
- Add scenario for all view modes (chart, table, proportion)
- Add scenario for group by/aggregation
- Add scenario for custom queries in Explorer
- Add scenario for Views tab (manage saved views)
---
## Dashboards Module
- **Coverage:**
- List, search, and filter dashboards
- Create new dashboard (button and template link)
- Edit, delete, and view dashboard details
- Add/edit/delete widgets (implied by dashboard detail)
- Pagination through dashboards
- **Gaps/Updates:**
- Add scenario for browsing dashboard templates (external link)
- Add scenario for requesting new template
- Add scenario for dashboard owner and creation info
- Add scenario for dashboard tags and filtering by tags
- Add scenario for dashboard sharing (if available)
- Add scenario for dashboard image/preview
---
## Messaging Queues Module
- **Coverage:**
- Overview tab: queue metrics, filters (Service Name, Span Name, Msg System, Destination, Kind)
- Search across all columns
- Pagination of queue data
- Sync and Share buttons
- Tabs for Kafka and Celery
- **Gaps/Updates:**
- Add scenario for Kafka tab (detailed metrics, actions)
- Add scenario for Celery tab (detailed metrics, actions)
- Add scenario for filter combinations and edge cases
- Add scenario for sharing queue data
- Add scenario for time range selection
---
## External APIs Module
- **Coverage:**
- Accessed via side navigation under MORE
- Explorer tab: domain, endpoints, last used, rate, error %, avg. latency
- Filters: Deployment Environment, Service Name, Rpc Method, Show IP addresses
- Table pagination
- Share and Stage & Run Query buttons
- **Gaps/Updates:**
- Add scenario for customizing quick filters
- Add scenario for running and staging queries
- Add scenario for sharing API data
- Add scenario for edge cases in filters and table data
---
## Alerts Module
- **Coverage:**
- Alert Rules tab: list, search, create (New Alert), edit, delete, enable/disable, severity, labels, actions
- Triggered Alerts tab (visible in tablist)
- Configuration tab (visible in tablist)
- Table pagination
- **Gaps/Updates:**
- Add scenario for triggered alerts (view, acknowledge, resolve)
- Add scenario for alert configuration (settings, integrations)
- Add scenario for edge cases in alert creation and management
- Add scenario for searching and filtering alerts
---
## Integrations Module
- **Coverage:**
- Integrations tab: list, search, configure (e.g., AWS), request new integration
- One-click setup for AWS monitoring
- Request more integrations (form)
- **Gaps/Updates:**
- Add scenario for configuring integrations (step-by-step)
- Add scenario for searching and filtering integrations
- Add scenario for requesting new integrations
- Add scenario for edge cases (e.g., failed configuration)
---
## Exceptions Module
- **Coverage:**
- All Exceptions: list, search, filter (Deployment Environment, Service Name, Host Name, K8s Cluster/Deployment/Namespace, Net Peer Name)
- Table: Exception Type, Error Message, Count, Last Seen, First Seen, Application
- Pagination
- Exception detail links
- Share and Stage & Run Query buttons
- **Gaps/Updates:**
- Add scenario for exception detail view
- Add scenario for advanced filtering and edge cases
- Add scenario for sharing and running queries
- Add scenario for error grouping and navigation
---
## Service Map Module
- **Coverage:**
- Service Map visualization (main graph)
- Filters: environment, resource attributes
- Time range selection
- Sync and Share buttons
- **Gaps/Updates:**
- Add scenario for interacting with the map (zoom, pan, select service)
- Add scenario for filtering and edge cases
- Add scenario for sharing the map
- Add scenario for time range and environment combinations
---
## Billing Module
- **Coverage:**
- Billing overview: cost monitoring, invoices, CSV download (disabled), manage billing (disabled)
- Teams Cloud section
- Billing table: Unit, Data Ingested, Price per Unit, Cost (Billing period to date)
- **Gaps/Updates:**
- Add scenario for invoice download and management (when enabled)
- Add scenario for cost monitoring and edge cases
- Add scenario for billing table data validation
- Add scenario for permissions and access control
---
## Usage Explorer Module
- **Status:**
- Not accessible in the current environment. Removing from test plan flows.
---
## [Next modules will be filled as validation proceeds]

View File

@ -0,0 +1,42 @@
import { expect, test } from '@playwright/test';
import { ensureLoggedIn } from '../../../utils/login.util';
test('Account Settings - View and Assert Static Controls', async ({ page }) => {
await ensureLoggedIn(page);
// 1. Open the sidebar settings menu using data-testid
await page.getByTestId('settings-nav-item').click();
// 2. Click Account Settings in the dropdown (by role/name or data-testid if available)
await page.getByRole('menuitem', { name: 'Account Settings' }).click();
// Assert the main tabpanel/heading (confirmed by DOM)
await expect(page.getByTestId('settings-page-title')).toBeVisible();
// Assert General section and controls (confirmed by DOM)
await expect(
page.getByLabel('My Settings').getByText('General'),
).toBeVisible();
await expect(page.getByText('Manage your account settings.')).toBeVisible();
await expect(page.getByRole('button', { name: 'Update name' })).toBeVisible();
await expect(
page.getByRole('button', { name: 'Reset password' }),
).toBeVisible();
// Assert User Preferences section and controls (confirmed by DOM)
await expect(page.getByText('User Preferences')).toBeVisible();
await expect(
page.getByText('Tailor the SigNoz console to work according to your needs.'),
).toBeVisible();
await expect(page.getByText('Select your theme')).toBeVisible();
const themeSelector = page.getByTestId('theme-selector');
await expect(themeSelector.getByText('Dark')).toBeVisible();
await expect(themeSelector.getByText('Light')).toBeVisible();
await expect(themeSelector.getByText('System')).toBeVisible();
await expect(page.getByTestId('timezone-adaptation-switch')).toBeVisible();
await expect(page.getByTestId('side-nav-pinned-switch')).toBeVisible();
});

View File

@ -0,0 +1,42 @@
import { expect, test } from '@playwright/test';
import { ensureLoggedIn } from '../../../utils/login.util';
test('API Keys Settings - View and Interact', async ({ page }) => {
await ensureLoggedIn(page);
// 1. Open the sidebar settings menu using data-testid
await page.getByTestId('settings-nav-item').click();
// 2. Click Account Settings in the dropdown (by role/name or data-testid if available)
await page.getByRole('menuitem', { name: 'Account Settings' }).click();
// Assert the main tabpanel/heading (confirmed by DOM)
await expect(page.getByTestId('settings-page-title')).toBeVisible();
// Focus on the settings page sidenav
await page.getByTestId('settings-page-sidenav').focus();
// Click API Keys tab in the settings sidebar (by data-testid)
await page.getByTestId('api-keys').click();
// Assert heading and subheading
await expect(page.getByRole('heading', { name: 'API Keys' })).toBeVisible();
await expect(
page.getByText('Create and manage API keys for the SigNoz API'),
).toBeVisible();
// Assert presence of New Key button
const newKeyBtn = page.getByRole('button', { name: 'New Key' });
await expect(newKeyBtn).toBeVisible();
// Assert table columns
await expect(page.getByText('Last used').first()).toBeVisible();
await expect(page.getByText('Expired').first()).toBeVisible();
// Assert at least one API key row with action buttons
// Select the first action cell's first button (icon button)
const firstActionCell = page.locator('table tr').nth(1).locator('td').last();
const deleteBtn = firstActionCell.locator('button').first();
await expect(deleteBtn).toBeVisible();
});

View File

@ -0,0 +1,71 @@
import { expect, test } from '@playwright/test';
import { ensureLoggedIn } from '../../../utils/login.util';
// E2E: Billing Settings - View Billing Information and Button Actions
test('View Billing Information and Button Actions', async ({
page,
context,
}) => {
// Ensure user is logged in
await ensureLoggedIn(page);
// 1. Open the sidebar settings menu using data-testid
await page.getByTestId('settings-nav-item').click();
// 2. Click Account Settings in the dropdown (by role/name or data-testid if available)
await page.getByRole('menuitem', { name: 'Account Settings' }).click();
// Assert the main tabpanel/heading (confirmed by DOM)
await expect(page.getByTestId('settings-page-title')).toBeVisible();
// Focus on the settings page sidenav
await page.getByTestId('settings-page-sidenav').focus();
// Click Billing tab in the settings sidebar (by data-testid)
await page.getByTestId('billing').click();
// Wait for billing chart/data to finish loading
await page.getByText('loading').first().waitFor({ state: 'hidden' });
// Assert visibility of subheading (unique)
await expect(
page.getByText(
'Manage your billing information, invoices, and monitor costs.',
),
).toBeVisible();
// Assert visibility of Teams Cloud heading
await expect(page.getByRole('heading', { name: 'Teams Cloud' })).toBeVisible();
// Assert presence of summary and detailed tables
await expect(page.getByText('TOTAL SPENT')).toBeVisible();
await expect(page.getByText('Data Ingested')).toBeVisible();
await expect(page.getByText('Price per Unit')).toBeVisible();
await expect(page.getByText('Cost (Billing period to date)')).toBeVisible();
// Assert presence of alert and note
await expect(
page.getByText('Your current billing period is from', { exact: false }),
).toBeVisible();
await expect(
page.getByText('Billing metrics are updated once every 24 hours.'),
).toBeVisible();
// Test Download CSV button
const [download] = await Promise.all([
page.waitForEvent('download'),
page.getByRole('button', { name: 'cloud-download Download CSV' }).click(),
]);
// Optionally, check download file name
expect(download.suggestedFilename()).toContain('billing_usage');
// Test Manage Billing button (opens Stripe in new tab)
const [newPage] = await Promise.all([
context.waitForEvent('page'),
page.getByTestId('header-billing-button').click(),
]);
await newPage.waitForLoadState();
expect(newPage.url()).toContain('stripe.com');
await newPage.close();
});

View File

@ -0,0 +1,52 @@
import { expect, test } from '@playwright/test';
import { ensureLoggedIn } from '../../../utils/login.util';
test('Custom Domain Settings - View and Interact', async ({ page }) => {
await ensureLoggedIn(page);
// 1. Open the sidebar settings menu using data-testid
await page.getByTestId('settings-nav-item').click();
// 2. Click Account Settings in the dropdown (by role/name or data-testid if available)
await page.getByRole('menuitem', { name: 'Account Settings' }).click();
// Assert the main tabpanel/heading (confirmed by DOM)
await expect(page.getByTestId('settings-page-title')).toBeVisible();
// Focus on the settings page sidenav
await page.getByTestId('settings-page-sidenav').focus();
// Click Custom Domain tab in the settings sidebar (by data-testid)
await page.getByTestId('custom-domain').click();
// Wait for custom domain chart/data to finish loading
await page.getByText('loading').first().waitFor({ state: 'hidden' });
// Assert heading and subheading
await expect(
page.getByRole('heading', { name: 'Custom Domain Settings' }),
).toBeVisible();
await expect(
page.getByText('Personalize your workspace domain effortlessly.'),
).toBeVisible();
// Assert presence of Customize teams URL button
const customizeBtn = page.getByRole('button', {
name: 'Customize teams URL',
});
await expect(customizeBtn).toBeVisible();
await customizeBtn.click();
// Assert modal/dialog fields and buttons
await expect(
page.getByRole('dialog', { name: 'Customize your teams URL' }),
).toBeVisible();
await expect(page.getByLabel('Teams URL subdomain')).toBeVisible();
await expect(
page.getByRole('button', { name: 'Apply Changes' }),
).toBeVisible();
await expect(page.getByRole('button', { name: 'Close' })).toBeVisible();
// Close the modal
await page.getByRole('button', { name: 'Close' }).click();
});

View File

@ -0,0 +1,32 @@
import { expect, test } from '@playwright/test';
import { ensureLoggedIn } from '../../../utils/login.util';
test('View General Settings', async ({ page }) => {
await ensureLoggedIn(page);
// 1. Open the sidebar settings menu using data-testid
await page.getByTestId('settings-nav-item').click();
// 2. Click Account Settings in the dropdown (by role/name or data-testid if available)
await page.getByRole('menuitem', { name: 'Account Settings' }).click();
// Assert the main tabpanel/heading (confirmed by DOM)
await expect(page.getByTestId('settings-page-title')).toBeVisible();
// Focus on the settings page sidenav
await page.getByTestId('settings-page-sidenav').focus();
// Click General tab in the settings sidebar (by data-testid)
await page.getByTestId('general').click();
// Wait for General tab to be visible
await page.getByRole('tabpanel', { name: 'General' }).waitFor();
// Assert visibility of definitive/static elements
await expect(page.getByRole('heading', { name: 'Metrics' })).toBeVisible();
await expect(page.getByRole('heading', { name: 'Traces' })).toBeVisible();
await expect(page.getByRole('heading', { name: 'Logs' })).toBeVisible();
await expect(page.getByText('Please')).toBeVisible();
await expect(page.getByRole('link', { name: 'email us' })).toBeVisible();
});

View File

@ -0,0 +1,48 @@
import { expect, test } from '@playwright/test';
import { ensureLoggedIn } from '../../../utils/login.util';
test('Ingestion Settings - View and Interact', async ({ page }) => {
await ensureLoggedIn(page);
// 1. Open the sidebar settings menu using data-testid
await page.getByTestId('settings-nav-item').click();
// 2. Click Account Settings in the dropdown (by role/name or data-testid if available)
await page.getByRole('menuitem', { name: 'Account Settings' }).click();
// Assert the main tabpanel/heading (confirmed by DOM)
await expect(page.getByTestId('settings-page-title')).toBeVisible();
// Focus on the settings page sidenav
await page.getByTestId('settings-page-sidenav').focus();
// Click Ingestion tab in the settings sidebar (by data-testid)
await page.getByTestId('ingestion').click();
// Assert heading and subheading (Integrations page)
await expect(
page.getByRole('heading', { name: 'Integrations' }),
).toBeVisible();
await expect(
page.getByText('Manage Integrations for this workspace'),
).toBeVisible();
// Assert presence of search box
await expect(
page.getByPlaceholder('Search for an integration...'),
).toBeVisible();
// Assert at least one data source with Configure button
const configureBtn = page.getByRole('button', { name: 'Configure' }).first();
await expect(configureBtn).toBeVisible();
// Assert Request more integrations section
await expect(
page.getByText(
"Can't find what youre looking for? Request more integrations",
),
).toBeVisible();
await expect(page.getByPlaceholder('Enter integration name...')).toBeVisible();
await expect(page.getByRole('button', { name: 'Submit' })).toBeVisible();
});

View File

@ -0,0 +1,48 @@
import { expect, test } from '@playwright/test';
import { ensureLoggedIn } from '../../../utils/login.util';
test('Integrations Settings - View and Interact', async ({ page }) => {
await ensureLoggedIn(page);
// 1. Open the sidebar settings menu using data-testid
await page.getByTestId('settings-nav-item').click();
// 2. Click Account Settings in the dropdown (by role/name or data-testid if available)
await page.getByRole('menuitem', { name: 'Account Settings' }).click();
// Assert the main tabpanel/heading (confirmed by DOM)
await expect(page.getByTestId('settings-page-title')).toBeVisible();
// Focus on the settings page sidenav
await page.getByTestId('settings-page-sidenav').focus();
// Click Integrations tab in the settings sidebar (by data-testid)
await page.getByTestId('integrations').click();
// Assert heading and subheading
await expect(
page.getByRole('heading', { name: 'Integrations' }),
).toBeVisible();
await expect(
page.getByText('Manage Integrations for this workspace'),
).toBeVisible();
// Assert presence of search box
await expect(
page.getByPlaceholder('Search for an integration...'),
).toBeVisible();
// Assert at least one integration with Configure button
const configureBtn = page.getByRole('button', { name: 'Configure' }).first();
await expect(configureBtn).toBeVisible();
// Assert Request more integrations section
await expect(
page.getByText(
"Can't find what youre looking for? Request more integrations",
),
).toBeVisible();
await expect(page.getByPlaceholder('Enter integration name...')).toBeVisible();
await expect(page.getByRole('button', { name: 'Submit' })).toBeVisible();
});

View File

@ -0,0 +1,56 @@
import { expect, test } from '@playwright/test';
import { ensureLoggedIn } from '../../../utils/login.util';
test('Members & SSO Settings - View and Interact', async ({ page }) => {
await ensureLoggedIn(page);
// 1. Open the sidebar settings menu using data-testid
await page.getByTestId('settings-nav-item').click();
// 2. Click Account Settings in the dropdown (by role/name or data-testid if available)
await page.getByRole('menuitem', { name: 'Account Settings' }).click();
// Assert the main tabpanel/heading (confirmed by DOM)
await expect(page.getByTestId('settings-page-title')).toBeVisible();
// Focus on the settings page sidenav
await page.getByTestId('settings-page-sidenav').focus();
// Click Members & SSO tab in the settings sidebar (by data-testid)
await page.getByTestId('members-sso').click();
// Assert headings and tables
await expect(
page.getByRole('heading', { name: /Members \(\d+\)/ }),
).toBeVisible();
await expect(
page.getByRole('heading', { name: /Pending Invites \(\d+\)/ }),
).toBeVisible();
await expect(
page.getByRole('heading', { name: 'Authenticated Domains' }),
).toBeVisible();
// Assert Invite Members button is visible and clickable
const inviteBtn = page.getByRole('button', { name: /Invite Members/ });
await expect(inviteBtn).toBeVisible();
await inviteBtn.click();
// Assert Invite Members modal/dialog appears (modal title is unique)
await expect(page.getByText('Invite team members').first()).toBeVisible();
// Close the modal (use unique 'Close' button)
await page.getByRole('button', { name: 'Close' }).click();
// Assert Edit and Delete buttons are present for at least one member
const editBtn = page.getByRole('button', { name: /Edit/ }).first();
const deleteBtn = page.getByRole('button', { name: /Delete/ }).first();
await expect(editBtn).toBeVisible();
await expect(deleteBtn).toBeVisible();
// Assert Add Domains button is visible
await expect(page.getByRole('button', { name: /Add Domains/ })).toBeVisible();
// Assert Configure SSO or Edit Google Auth button is visible for at least one domain
const ssoBtn = page
.getByRole('button', { name: /Configure SSO|Edit Google Auth/ })
.first();
await expect(ssoBtn).toBeVisible();
});

View File

@ -0,0 +1,57 @@
import { expect, test } from '@playwright/test';
import { ensureLoggedIn } from '../../../utils/login.util';
test('Notification Channels Settings - View and Interact', async ({ page }) => {
await ensureLoggedIn(page);
// 1. Open the sidebar settings menu using data-testid
await page.getByTestId('settings-nav-item').click();
// 2. Click Account Settings in the dropdown (by role/name or data-testid if available)
await page.getByRole('menuitem', { name: 'Account Settings' }).click();
// Assert the main tabpanel/heading (confirmed by DOM)
await expect(page.getByTestId('settings-page-title')).toBeVisible();
// Focus on the settings page sidenav
await page.getByTestId('settings-page-sidenav').focus();
// Click Notification Channels tab in the settings sidebar (by data-testid)
await page.getByTestId('notification-channels').click();
// Wait for loading to finish
await page.getByText('loading').first().waitFor({ state: 'hidden' });
// Assert presence of New Alert Channel button
const newChannelBtn = page.getByRole('button', { name: /New Alert Channel/ });
await expect(newChannelBtn).toBeVisible();
// Assert table columns
await expect(page.getByText('Name')).toBeVisible();
await expect(page.getByText('Type')).toBeVisible();
await expect(page.getByText('Action')).toBeVisible();
// Click New Alert Channel and assert modal fields/buttons
await newChannelBtn.click();
await expect(
page.getByRole('heading', { name: 'New Notification Channel' }),
).toBeVisible();
await expect(page.getByLabel('Name')).toBeVisible();
await expect(page.getByLabel('Type')).toBeVisible();
await expect(page.getByLabel('Webhook URL')).toBeVisible();
await expect(
page.getByRole('switch', { name: 'Send resolved alerts' }),
).toBeVisible();
await expect(page.getByRole('button', { name: 'Save' })).toBeVisible();
await expect(page.getByRole('button', { name: 'Test' })).toBeVisible();
await expect(page.getByRole('button', { name: 'Back' })).toBeVisible();
// Close modal
await page.getByRole('button', { name: 'Back' }).click();
// Assert Edit and Delete buttons for at least one channel
const editBtn = page.getByRole('button', { name: 'Edit' }).first();
const deleteBtn = page.getByRole('button', { name: 'Delete' }).first();
await expect(editBtn).toBeVisible();
await expect(deleteBtn).toBeVisible();
});

View File

@ -0,0 +1,35 @@
import { Page } from '@playwright/test';
// Read credentials from environment variables
const username = process.env.LOGIN_USERNAME;
const password = process.env.LOGIN_PASSWORD;
const baseURL = process.env.BASE_URL;
/**
* Ensures the user is logged in. If not, performs the login steps.
* Follows the MCP process step-by-step.
*/
export async function ensureLoggedIn(page: Page): Promise<void> {
// if already in home page, return
if (await page.url().includes('/home')) {
return;
}
if (!username || !password) {
throw new Error(
'E2E_EMAIL and E2E_PASSWORD environment variables must be set.',
);
}
await page.goto(`${baseURL}/login`);
await page.getByTestId('email').click();
await page.getByTestId('email').fill(username);
await page.getByTestId('initiate_login').click();
await page.getByTestId('password').click();
await page.getByTestId('password').fill(password);
await page.getByRole('button', { name: 'Login' }).click();
await page
.getByText('Hello there, Welcome to your')
.waitFor({ state: 'visible' });
}

View File

@ -1,6 +1,9 @@
import type { Config } from '@jest/types';
const USE_SAFE_NAVIGATE_MOCK_PATH = '<rootDir>/__mocks__/useSafeNavigate.ts';
const config: Config.InitialOptions = {
silent: true,
clearMocks: true,
coverageDirectory: 'coverage',
coverageReporters: ['text', 'cobertura', 'html', 'json-summary'],
@ -10,12 +13,17 @@ const config: Config.InitialOptions = {
moduleNameMapper: {
'\\.(css|less|scss)$': '<rootDir>/__mocks__/cssMock.ts',
'\\.md$': '<rootDir>/__mocks__/cssMock.ts',
'^uplot$': '<rootDir>/__mocks__/uplotMock.ts',
'^hooks/useSafeNavigate$': USE_SAFE_NAVIGATE_MOCK_PATH,
'^src/hooks/useSafeNavigate$': USE_SAFE_NAVIGATE_MOCK_PATH,
'^.*/useSafeNavigate$': USE_SAFE_NAVIGATE_MOCK_PATH,
},
globals: {
extensionsToTreatAsEsm: ['.ts'],
'ts-jest': {
useESM: true,
isolatedModules: true,
tsconfig: '<rootDir>/tsconfig.jest.json',
},
},
testMatch: ['<rootDir>/src/**/*?(*.)(test).(ts|js)?(x)'],
@ -25,7 +33,7 @@ const config: Config.InitialOptions = {
'^.+\\.(js|jsx)$': 'babel-jest',
},
transformIgnorePatterns: [
'node_modules/(?!(lodash-es|react-dnd|core-dnd|@react-dnd|dnd-core|react-dnd-html5-backend|axios|@signozhq/design-tokens|d3-interpolate|d3-color|api)/)',
'node_modules/(?!(lodash-es|react-dnd|core-dnd|@react-dnd|dnd-core|react-dnd-html5-backend|axios|@signozhq/design-tokens|@signozhq/table|@signozhq/calendar|@signozhq/input|@signozhq/popover|@signozhq/button|@signozhq/sonner|@signozhq/*|date-fns|d3-interpolate|d3-color|api|@codemirror|@lezer|@marijn)/)',
],
setupFilesAfterEnv: ['<rootDir>jest.setup.ts'],
testPathIgnorePatterns: ['/node_modules/', '/public/'],

View File

@ -28,6 +28,8 @@
"dependencies": {
"@ant-design/colors": "6.0.0",
"@ant-design/icons": "4.8.0",
"@codemirror/autocomplete": "6.18.6",
"@codemirror/lang-javascript": "6.2.3",
"@dnd-kit/core": "6.1.0",
"@dnd-kit/modifiers": "7.0.0",
"@dnd-kit/sortable": "8.0.0",
@ -36,13 +38,27 @@
"@mdx-js/loader": "2.3.0",
"@mdx-js/react": "2.3.0",
"@monaco-editor/react": "^4.3.1",
"@playwright/test": "1.54.1",
"@radix-ui/react-tabs": "1.0.4",
"@radix-ui/react-tooltip": "1.0.7",
"@sentry/react": "8.41.0",
"@sentry/webpack-plugin": "2.22.6",
"@signozhq/badge": "0.0.2",
"@signozhq/button": "0.0.2",
"@signozhq/calendar": "0.0.0",
"@signozhq/callout": "0.0.2",
"@signozhq/design-tokens": "1.1.4",
"@signozhq/input": "0.0.2",
"@signozhq/popover": "0.0.0",
"@signozhq/resizable": "0.0.0",
"@signozhq/sonner": "0.1.0",
"@signozhq/table": "0.3.7",
"@signozhq/tooltip": "0.0.2",
"@tanstack/react-table": "8.20.6",
"@tanstack/react-virtual": "3.11.2",
"@uiw/codemirror-theme-copilot": "4.23.11",
"@uiw/codemirror-theme-github": "4.24.1",
"@uiw/react-codemirror": "4.23.10",
"@uiw/react-md-editor": "3.23.5",
"@visx/group": "3.3.0",
"@visx/hierarchy": "3.12.0",
@ -52,6 +68,7 @@
"ansi-to-html": "0.7.2",
"antd": "5.11.0",
"antd-table-saveas-excel": "2.2.1",
"antlr4": "4.13.2",
"axios": "1.8.2",
"babel-eslint": "^10.1.0",
"babel-jest": "^29.6.4",
@ -85,6 +102,7 @@
"i18next-http-backend": "^1.3.2",
"jest": "^27.5.1",
"js-base64": "^3.7.2",
"kbar": "0.1.0-beta.48",
"less": "^4.1.2",
"less-loader": "^10.2.0",
"lodash-es": "^4.17.21",
@ -121,6 +139,7 @@
"redux": "^4.0.5",
"redux-thunk": "^2.3.0",
"rehype-raw": "7.0.0",
"rrule": "2.8.1",
"stream": "^0.0.2",
"style-loader": "1.3.0",
"styled-components": "^5.3.11",
@ -235,7 +254,7 @@
"sharp": "^0.33.4",
"ts-jest": "^27.1.5",
"ts-node": "^10.2.1",
"typescript-plugin-css-modules": "5.0.1",
"typescript-plugin-css-modules": "5.2.0",
"webpack-bundle-analyzer": "^4.5.0",
"webpack-cli": "^5.1.4"
},
@ -259,6 +278,7 @@
"serialize-javascript": "6.0.2",
"prismjs": "1.30.0",
"got": "11.8.5",
"stylus": "0.0.1-security"
"form-data": "4.0.4",
"brace-expansion": "^2.0.2"
}
}

View File

@ -0,0 +1,95 @@
import { defineConfig, devices } from '@playwright/test';
import dotenv from 'dotenv';
import path from 'path';
// Read from ".env" file.
dotenv.config({ path: path.resolve(__dirname, '.env') });
/**
* Read environment variables from file.
* https://github.com/motdotla/dotenv
*/
// import dotenv from 'dotenv';
// import path from 'path';
// dotenv.config({ path: path.resolve(__dirname, '.env') });
/**
* See https://playwright.dev/docs/test-configuration.
*/
export default defineConfig({
testDir: './e2e/tests',
/* Run tests in files in parallel */
fullyParallel: true,
/* Fail the build on CI if you accidentally left test.only in the source code. */
forbidOnly: !!process.env.CI,
/* Retry on CI only */
retries: process.env.CI ? 2 : 0,
/* Run tests in parallel even in CI - optimized for GitHub Actions free tier */
workers: process.env.CI ? 2 : undefined,
/* Reporter to use. See https://playwright.dev/docs/test-reporters */
reporter: 'html',
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
use: {
/* Base URL to use in actions like `await page.goto('/')`. */
baseURL:
process.env.SIGNOZ_E2E_BASE_URL || 'https://app.us.staging.signoz.cloud',
/* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
trace: 'on-first-retry',
colorScheme: 'dark',
locale: 'en-US',
viewport: { width: 1280, height: 720 },
},
/* Configure projects for major browsers */
projects: [
{
name: 'chromium',
use: {
launchOptions: { args: ['--start-maximized'] },
viewport: null,
colorScheme: 'dark',
locale: 'en-US',
baseURL: 'https://app.us.staging.signoz.cloud',
trace: 'on-first-retry',
},
},
{
name: 'firefox',
use: { ...devices['Desktop Firefox'] },
},
{
name: 'webkit',
use: { ...devices['Desktop Safari'] },
},
/* Test against mobile viewports. */
// {
// name: 'Mobile Chrome',
// use: { ...devices['Pixel 5'] },
// },
// {
// name: 'Mobile Safari',
// use: { ...devices['iPhone 12'] },
// },
/* Test against branded browsers. */
// {
// name: 'Microsoft Edge',
// use: { ...devices['Desktop Edge'], channel: 'msedge' },
// },
// {
// name: 'Google Chrome',
// use: { ...devices['Desktop Chrome'], channel: 'chrome' },
// },
],
/* Run your local dev server before starting the tests */
// webServer: {
// command: 'npm run start',
// url: 'http://localhost:3000',
// reuseExistingServer: !process.env.CI,
// },
});

View File

@ -0,0 +1,16 @@
RULE: All test code for this repo must be generated by following the step-by-step Playwright MCP process as described below.
- You are a playwright test generator.
- You are given a scenario and you need to generate a playwright test for it.
- Use login util if not logged in.
- DO NOT generate test code based on the scenario alone.
- DO run steps one by one using the tools provided by the Playwright MCP.
- Only after all steps are completed, emit a Playwright TypeScript test that uses @playwright/test based on message history
- Gather correct selectors before writing the test
- DO NOT valiate for dynamic content in the tests, only validate for the correctness with meta data
- Always inspect the DOM at each navigation or interaction step to determine the correct selector for the next action. Do not assume selectors, confirm via inspection before proceeding.
- Assert visibility of definitive/static elements in the UI (such as labels, headings, or section titles) rather than dynamic values or content that may change between runs.
- Save generated test file in the tests directory
- Execute the test file and iterate until the test passes

View File

@ -0,0 +1,81 @@
<svg
width="32"
height="32"
viewBox="0 0 32 32"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M19.11 16.8483L14.0369 17.7304C14.0369 17.7304 12.3481 22.0324 12.2437 22.3235C12.1392 22.6146 12.1437 23.0746 12.6037 23.0746C13.1881 23.0746 16.1546 23.0591 16.1546 23.0591C16.1546 23.0591 15.4346 26.5322 15.3924 26.8433C15.3502 27.1544 15.6835 27.4277 15.9768 27.1144C16.2701 26.8011 20.3121 21.6058 20.4877 21.3525C20.801 20.8992 20.4988 20.4814 20.1433 20.4614C19.7877 20.4414 17.4056 20.4925 17.4056 20.4925L19.11 16.8483Z"
fill="#FECA18"
/>
<path
d="M17.7589 17.4527C17.7589 17.4527 16.6279 19.9548 16.5856 20.097C16.4612 20.5192 17.0078 20.6903 17.1634 20.3481C17.3189 20.0037 18.6655 17.2194 18.6655 17.2194L17.7589 17.4527Z"
fill="#FDB900"
/>
<path
d="M12.8859 22.2592C13.1836 22.2503 15.7968 22.2436 16.0146 22.2281C16.4213 22.1969 16.4835 22.7591 16.0146 22.7591C15.528 22.7591 12.9637 22.768 12.8081 22.7747C12.4481 22.7925 12.3992 22.2747 12.8859 22.2592Z"
fill="#FDB900"
/>
<path
d="M14.9813 17.1127C14.9813 17.1127 13.6481 20.4592 13.5725 20.7103C13.2592 21.7591 14.3858 21.728 14.6836 21.1325C14.8302 20.837 16.2635 17.8016 16.3257 17.2527C16.3879 16.7061 14.9813 17.1127 14.9813 17.1127Z"
fill="#FFE36A"
/>
<path
d="M15.3347 21.0148C15.1436 20.8837 14.9125 20.9992 14.7725 21.2192C14.6325 21.4392 14.428 21.797 14.7414 21.9858C15.0236 22.1547 15.2724 21.8147 15.3835 21.657C15.4924 21.4992 15.6324 21.217 15.3347 21.0148Z"
fill="#FFE36A"
/>
<path
d="M17.6301 21.7326C17.1212 21.6237 16.9568 22.0459 16.8479 22.5459C16.739 23.0459 16.3302 24.6636 16.2546 25.0635C16.1457 25.6257 16.6612 25.7057 16.8812 25.188C17.0457 24.8013 17.759 23.057 17.8501 22.7792C17.9901 22.3592 18.1456 21.8437 17.6301 21.7326Z"
fill="#FFE36A"
/>
<path
d="M25.7585 12.0573C25.7585 12.0573 26.3363 4.28441 19.69 3.2978C13.7147 2.41118 12.5415 8.08421 12.5415 8.08421C12.5415 8.08421 10.2838 7.55757 8.66166 9.00639C7.05064 10.4463 7.17508 12.1507 7.17508 12.1507C7.17508 12.1507 3.20195 11.524 2.79531 14.935C2.41533 18.1215 7.11286 17.3282 7.11286 17.3282L29.4183 15.686C29.4183 15.686 29.9472 14.0106 28.2606 12.7462C27.2585 11.9929 25.7585 12.0573 25.7585 12.0573Z"
fill="#E4EAEE"
/>
<path
d="M13.7347 13.8196C13.9213 13.7574 14.9857 14.6662 18.0522 14.6951C22.2653 14.7373 25.4563 12.2552 25.4563 12.2552C25.4563 12.2552 25.5629 13.0108 25.2274 13.5485C24.8096 14.2151 24.163 14.3418 24.163 14.3418C24.163 14.3418 25.3318 15.1551 26.9362 15.0307C28.3828 14.9173 29.4294 14.4262 29.4294 14.4262C29.4294 14.4262 29.5694 15.1395 29.4916 15.8351C29.3361 17.2217 28.5228 17.7861 27.6251 17.8883C26.9651 17.9638 21.3276 17.9905 19.0122 18.0127C16.9256 18.0327 6.29285 18.2994 5.20624 18.1794C4.07963 18.0549 3.22412 17.3772 2.91303 16.4061C2.67526 15.6706 2.78859 15.1973 2.78859 15.1973C2.78859 15.1973 4.85959 15.7462 6.02175 15.6151C7.48167 15.4484 8.46162 14.5307 8.46162 14.5307C8.46162 14.5307 9.33713 15.0307 11.277 14.864C12.9458 14.7173 13.7347 13.8196 13.7347 13.8196Z"
fill="url(#paint0_radial_811_5475)"
/>
<path
d="M24.8653 18.2661C24.6386 18.1394 23.832 18.8927 23.3787 19.346C23.1009 19.6238 22.2165 20.3504 22.0965 21.0504C21.7988 22.7703 23.7698 23.1614 24.552 22.3637C25.143 21.7615 25.0364 20.586 25.0364 20.1904C25.0386 19.6416 25.1475 18.4216 24.8653 18.2661Z"
fill="#52C0EE"
/>
<path
d="M8.67058 19.1904C8.45504 19.0659 7.68174 19.7948 7.24621 20.237C6.97956 20.5058 6.13294 21.2103 6.01294 21.8947C5.71962 23.5723 7.5973 23.9657 8.34837 23.1924C8.91501 22.608 8.82168 21.4591 8.82391 21.0725C8.82613 20.537 8.93723 19.3459 8.67058 19.1904Z"
fill="#52C0EE"
/>
<path
d="M12.2548 24.1634C12.0126 24.0723 11.1971 24.8145 10.7438 25.2678C10.466 25.5456 9.64386 26.2566 9.52386 26.9566C9.2261 28.6765 11.1349 29.0832 11.9171 28.2854C12.5081 27.6832 12.4104 26.5077 12.4015 26.1122C12.3793 25.0812 12.4215 24.2256 12.2548 24.1634Z"
fill="#52C0EE"
/>
<path
d="M23.5054 20.4926C23.1943 20.3304 22.8165 20.3993 22.5765 20.8992C22.3365 21.3992 22.5343 21.797 22.7854 21.9103C23.0743 22.0436 23.432 21.9214 23.672 21.5147C23.912 21.1081 23.7654 20.6281 23.5054 20.4926Z"
fill="#B2E6FE"
/>
<path
d="M10.6682 26.4279C10.3482 26.3168 9.99715 26.4345 9.83716 26.9478C9.67717 27.4611 9.92382 27.8122 10.1794 27.8878C10.4749 27.9744 10.7993 27.8078 10.9727 27.3834C11.1438 26.9589 10.9349 26.5212 10.6682 26.4279Z"
fill="#B2E6FE"
/>
<path
d="M7.12613 21.3258C6.78837 21.2325 6.43283 21.3769 6.30395 21.9169C6.17507 22.4569 6.45061 22.8035 6.71948 22.8613C7.03058 22.9302 7.35278 22.7369 7.50389 22.288C7.65277 21.8436 7.41056 21.4036 7.12613 21.3258Z"
fill="#B2E6FE"
/>
<defs>
<radialGradient
id="paint0_radial_811_5475"
cx="0"
cy="0"
r="1"
gradientTransform="matrix(0.18837 -6.53799 9.79456 0.282554 16.401 18.5051)"
gradientUnits="userSpaceOnUse"
>
<stop offset="0.1934" stopColor="#FFE366" />
<stop offset="0.3305" stopColor="#EDDD82" />
<stop offset="0.5709" stopColor="#D0D4AD" />
<stop offset="0.7589" stopColor="#BFCFC7" />
<stop offset="0.8699" stopColor="#B8CDD1" />
</radialGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 5.4 KiB

View File

@ -46,5 +46,8 @@
"ALERT_HISTORY": "SigNoz | Alert Rule History",
"ALERT_OVERVIEW": "SigNoz | Alert Rule Overview",
"INFRASTRUCTURE_MONITORING_HOSTS": "SigNoz | Infra Monitoring",
"INFRASTRUCTURE_MONITORING_KUBERNETES": "SigNoz | Infra Monitoring"
"INFRASTRUCTURE_MONITORING_KUBERNETES": "SigNoz | Infra Monitoring",
"METER_EXPLORER": "SigNoz | Meter Explorer",
"METER_EXPLORER_VIEWS": "SigNoz | Meter Explorer Views",
"METER": "SigNoz | Meter"
}

View File

@ -69,5 +69,8 @@
"METRICS_EXPLORER": "SigNoz | Metrics Explorer",
"METRICS_EXPLORER_EXPLORER": "SigNoz | Metrics Explorer",
"METRICS_EXPLORER_VIEWS": "SigNoz | Metrics Explorer",
"API_MONITORING": "SigNoz | External APIs"
"API_MONITORING": "SigNoz | External APIs",
"METER_EXPLORER": "SigNoz | Meter Explorer",
"METER_EXPLORER_VIEWS": "SigNoz | Meter Explorer Views",
"METER": "SigNoz | Meter"
}

View File

@ -4,6 +4,7 @@ import getLocalStorageApi from 'api/browser/localstorage/get';
import setLocalStorageApi from 'api/browser/localstorage/set';
import logEvent from 'api/common/logEvent';
import AppLoading from 'components/AppLoading/AppLoading';
import KBarCommandPalette from 'components/KBarCommandPalette/KBarCommandPalette';
import NotFound from 'components/NotFound';
import Spinner from 'components/Spinner';
import UserpilotRouteTracker from 'components/UserpilotRouteTracker/UserpilotRouteTracker';
@ -25,6 +26,7 @@ import { useAppContext } from 'providers/App/App';
import { IUser } from 'providers/App/types';
import { DashboardProvider } from 'providers/Dashboard/Dashboard';
import { ErrorModalProvider } from 'providers/ErrorModalProvider';
import { KBarCommandPaletteProvider } from 'providers/KBarCommandPaletteProvider';
import { QueryBuilderProvider } from 'providers/QueryBuilder';
import { Suspense, useCallback, useEffect, useState } from 'react';
import { Route, Router, Switch } from 'react-router-dom';
@ -368,39 +370,42 @@ function App(): JSX.Element {
<ConfigProvider theme={themeConfig}>
<Router history={history}>
<CompatRouter>
<UserpilotRouteTracker />
<NotificationProvider>
<ErrorModalProvider>
<PrivateRoute>
<ResourceProvider>
<QueryBuilderProvider>
<DashboardProvider>
<KeyboardHotkeysProvider>
<AlertRuleProvider>
<AppLayout>
<Suspense fallback={<Spinner size="large" tip="Loading..." />}>
<Switch>
{routes.map(({ path, component, exact }) => (
<Route
key={`${path}`}
exact={exact}
path={path}
component={component}
/>
))}
<Route exact path="/" component={Home} />
<Route path="*" component={NotFound} />
</Switch>
</Suspense>
</AppLayout>
</AlertRuleProvider>
</KeyboardHotkeysProvider>
</DashboardProvider>
</QueryBuilderProvider>
</ResourceProvider>
</PrivateRoute>
</ErrorModalProvider>
</NotificationProvider>
<KBarCommandPaletteProvider>
<UserpilotRouteTracker />
<KBarCommandPalette />
<NotificationProvider>
<ErrorModalProvider>
<PrivateRoute>
<ResourceProvider>
<QueryBuilderProvider>
<DashboardProvider>
<KeyboardHotkeysProvider>
<AlertRuleProvider>
<AppLayout>
<Suspense fallback={<Spinner size="large" tip="Loading..." />}>
<Switch>
{routes.map(({ path, component, exact }) => (
<Route
key={`${path}`}
exact={exact}
path={path}
component={component}
/>
))}
<Route exact path="/" component={Home} />
<Route path="*" component={NotFound} />
</Switch>
</Suspense>
</AppLayout>
</AlertRuleProvider>
</KeyboardHotkeysProvider>
</DashboardProvider>
</QueryBuilderProvider>
</ResourceProvider>
</PrivateRoute>
</ErrorModalProvider>
</NotificationProvider>
</KBarCommandPaletteProvider>
</CompatRouter>
</Router>
</ConfigProvider>

View File

@ -1,5 +1,6 @@
import ROUTES from 'constants/routes';
import MessagingQueues from 'pages/MessagingQueues';
import MeterExplorer from 'pages/MeterExplorer';
import { RouteProps } from 'react-router-dom';
import {
@ -434,6 +435,28 @@ const routes: AppRoutes[] = [
key: 'METRICS_EXPLORER_VIEWS',
isPrivate: true,
},
{
path: ROUTES.METER,
exact: true,
component: MeterExplorer,
key: 'METER',
isPrivate: true,
},
{
path: ROUTES.METER_EXPLORER,
exact: true,
component: MeterExplorer,
key: 'METER_EXPLORER',
isPrivate: true,
},
{
path: ROUTES.METER_EXPLORER_VIEWS,
exact: true,
component: MeterExplorer,
key: 'METER_EXPLORER_VIEWS',
isPrivate: true,
},
{
path: ROUTES.API_MONITORING,
exact: true,

View File

@ -0,0 +1,28 @@
import axios from 'api';
import { ErrorResponse, SuccessResponse } from 'types/api';
import {
AlertRuleV2,
PostableAlertRuleV2,
} from 'types/api/alerts/alertTypesV2';
export interface CreateAlertRuleResponse {
data: AlertRuleV2;
status: string;
}
const createAlertRule = async (
props: PostableAlertRuleV2,
): Promise<SuccessResponse<CreateAlertRuleResponse> | ErrorResponse> => {
const response = await axios.post(`/rules`, {
...props,
});
return {
statusCode: 200,
error: null,
message: response.data.status,
payload: response.data.data,
};
};
export default createAlertRule;

View File

@ -0,0 +1,28 @@
import axios from 'api';
import { ErrorResponse, SuccessResponse } from 'types/api';
import { PostableAlertRuleV2 } from 'types/api/alerts/alertTypesV2';
export interface TestAlertRuleResponse {
data: {
alertCount: number;
message: string;
};
status: string;
}
const testAlertRule = async (
props: PostableAlertRuleV2,
): Promise<SuccessResponse<TestAlertRuleResponse> | ErrorResponse> => {
const response = await axios.post(`/testRule`, {
...props,
});
return {
statusCode: 200,
error: null,
message: response.data.status,
payload: response.data.data,
};
};
export default testAlertRule;

View File

@ -0,0 +1,26 @@
import axios from 'api';
import { ErrorResponse, SuccessResponse } from 'types/api';
import { PostableAlertRuleV2 } from 'types/api/alerts/alertTypesV2';
export interface UpdateAlertRuleResponse {
data: string;
status: string;
}
const updateAlertRule = async (
id: string,
postableAlertRule: PostableAlertRuleV2,
): Promise<SuccessResponse<UpdateAlertRuleResponse> | ErrorResponse> => {
const response = await axios.put(`/rules/${id}`, {
...postableAlertRule,
});
return {
statusCode: 200,
error: null,
message: response.data.status,
payload: response.data.data,
};
};
export default updateAlertRule;

View File

@ -3,6 +3,7 @@ const apiV1 = '/api/v1/';
export const apiV2 = '/api/v2/';
export const apiV3 = '/api/v3/';
export const apiV4 = '/api/v4/';
export const apiV5 = '/api/v5/';
export const gatewayApiV1 = '/api/gateway/v1/';
export const gatewayApiV2 = '/api/gateway/v2/';
export const apiAlertManager = '/api/alertmanager/';

View File

@ -0,0 +1,34 @@
import { ApiV5Instance } from 'api';
import { ErrorResponseHandlerV2 } from 'api/ErrorResponseHandlerV2';
import { QueryRangePayloadV5 } from 'api/v5/v5';
import { AxiosError } from 'axios';
import { ErrorV2Resp, SuccessResponseV2 } from 'types/api';
import { ICompositeMetricQuery } from 'types/api/alerts/compositeQuery';
interface ISubstituteVars {
compositeQuery: ICompositeMetricQuery;
}
export const getSubstituteVars = async (
props?: Partial<QueryRangePayloadV5>,
signal?: AbortSignal,
headers?: Record<string, string>,
): Promise<SuccessResponseV2<ISubstituteVars>> => {
try {
const response = await ApiV5Instance.post<{ data: ISubstituteVars }>(
'/substitute_vars',
props,
{
signal,
headers,
},
);
return {
httpStatusCode: response.status,
data: response.data.data,
};
} catch (error) {
ErrorResponseHandlerV2(error as AxiosError<ErrorV2Resp>);
}
};

View File

@ -0,0 +1,115 @@
/* eslint-disable sonarjs/no-duplicate-string */
import { ApiBaseInstance } from 'api';
import { getFieldKeys } from '../getFieldKeys';
// Mock the API instance
jest.mock('api', () => ({
ApiBaseInstance: {
get: jest.fn(),
},
}));
describe('getFieldKeys API', () => {
beforeEach(() => {
jest.clearAllMocks();
});
const mockSuccessResponse = {
status: 200,
data: {
status: 'success',
data: {
keys: {
'service.name': [],
'http.status_code': [],
},
complete: true,
},
},
};
it('should call API with correct parameters when no args provided', async () => {
// Mock successful API response
(ApiBaseInstance.get as jest.Mock).mockResolvedValueOnce(mockSuccessResponse);
// Call function with no parameters
await getFieldKeys();
// Verify API was called correctly with empty params object
expect(ApiBaseInstance.get).toHaveBeenCalledWith('/fields/keys', {
params: {},
});
});
it('should call API with signal parameter when provided', async () => {
// Mock successful API response
(ApiBaseInstance.get as jest.Mock).mockResolvedValueOnce(mockSuccessResponse);
// Call function with signal parameter
await getFieldKeys('traces');
// Verify API was called with signal parameter
expect(ApiBaseInstance.get).toHaveBeenCalledWith('/fields/keys', {
params: { signal: 'traces' },
});
});
it('should call API with name parameter when provided', async () => {
// Mock successful API response
(ApiBaseInstance.get as jest.Mock).mockResolvedValueOnce({
status: 200,
data: {
status: 'success',
data: {
keys: { service: [] },
complete: false,
},
},
});
// Call function with name parameter
await getFieldKeys(undefined, 'service');
// Verify API was called with name parameter
expect(ApiBaseInstance.get).toHaveBeenCalledWith('/fields/keys', {
params: { name: 'service' },
});
});
it('should call API with both signal and name when provided', async () => {
// Mock successful API response
(ApiBaseInstance.get as jest.Mock).mockResolvedValueOnce({
status: 200,
data: {
status: 'success',
data: {
keys: { service: [] },
complete: false,
},
},
});
// Call function with both parameters
await getFieldKeys('logs', 'service');
// Verify API was called with both parameters
expect(ApiBaseInstance.get).toHaveBeenCalledWith('/fields/keys', {
params: { signal: 'logs', name: 'service' },
});
});
it('should return properly formatted response', async () => {
// Mock API to return our response
(ApiBaseInstance.get as jest.Mock).mockResolvedValueOnce(mockSuccessResponse);
// Call the function
const result = await getFieldKeys('traces');
// Verify the returned structure matches SuccessResponseV2 format
expect(result).toEqual({
httpStatusCode: 200,
data: mockSuccessResponse.data.data,
});
});
});

View File

@ -0,0 +1,214 @@
/* eslint-disable sonarjs/no-duplicate-string */
import { ApiBaseInstance } from 'api';
import { getFieldValues } from '../getFieldValues';
// Mock the API instance
jest.mock('api', () => ({
ApiBaseInstance: {
get: jest.fn(),
},
}));
describe('getFieldValues API', () => {
beforeEach(() => {
jest.clearAllMocks();
});
it('should call the API with correct parameters (no options)', async () => {
// Mock API response
(ApiBaseInstance.get as jest.Mock).mockResolvedValueOnce({
status: 200,
data: {
status: 'success',
data: {
values: {
stringValues: ['frontend', 'backend'],
},
complete: true,
},
},
});
// Call function without parameters
await getFieldValues();
// Verify API was called correctly with empty params
expect(ApiBaseInstance.get).toHaveBeenCalledWith('/fields/values', {
params: {},
});
});
it('should call the API with signal parameter', async () => {
// Mock API response
(ApiBaseInstance.get as jest.Mock).mockResolvedValueOnce({
status: 200,
data: {
status: 'success',
data: {
values: {
stringValues: ['frontend', 'backend'],
},
complete: true,
},
},
});
// Call function with signal parameter
await getFieldValues('traces');
// Verify API was called with signal parameter
expect(ApiBaseInstance.get).toHaveBeenCalledWith('/fields/values', {
params: { signal: 'traces' },
});
});
it('should call the API with name parameter', async () => {
// Mock API response
(ApiBaseInstance.get as jest.Mock).mockResolvedValueOnce({
status: 200,
data: {
status: 'success',
data: {
values: {
stringValues: ['frontend', 'backend'],
},
complete: true,
},
},
});
// Call function with name parameter
await getFieldValues(undefined, 'service.name');
// Verify API was called with name parameter
expect(ApiBaseInstance.get).toHaveBeenCalledWith('/fields/values', {
params: { name: 'service.name' },
});
});
it('should call the API with value parameter', async () => {
// Mock API response
(ApiBaseInstance.get as jest.Mock).mockResolvedValueOnce({
status: 200,
data: {
status: 'success',
data: {
values: {
stringValues: ['frontend'],
},
complete: false,
},
},
});
// Call function with value parameter
await getFieldValues(undefined, 'service.name', 'front');
// Verify API was called with value parameter
expect(ApiBaseInstance.get).toHaveBeenCalledWith('/fields/values', {
params: { name: 'service.name', searchText: 'front' },
});
});
it('should call the API with time range parameters', async () => {
// Mock API response
(ApiBaseInstance.get as jest.Mock).mockResolvedValueOnce({
status: 200,
data: {
status: 'success',
data: {
values: {
stringValues: ['frontend', 'backend'],
},
complete: true,
},
},
});
// Call function with time range parameters
const startUnixMilli = 1625097600000000; // Note: nanoseconds
const endUnixMilli = 1625184000000000;
await getFieldValues(
'logs',
'service.name',
undefined,
startUnixMilli,
endUnixMilli,
);
// Verify API was called with time range parameters (converted to milliseconds)
expect(ApiBaseInstance.get).toHaveBeenCalledWith('/fields/values', {
params: {
signal: 'logs',
name: 'service.name',
startUnixMilli: '1625097600', // Should be converted to seconds (divided by 1000000)
endUnixMilli: '1625184000', // Should be converted to seconds (divided by 1000000)
},
});
});
it('should normalize the response values', async () => {
// Mock API response with multiple value types
const mockResponse = {
status: 200,
data: {
status: 'success',
data: {
values: {
stringValues: ['frontend', 'backend'],
numberValues: [200, 404],
boolValues: [true, false],
},
complete: true,
},
},
};
(ApiBaseInstance.get as jest.Mock).mockResolvedValueOnce(mockResponse);
// Call the function
const result = await getFieldValues('traces', 'mixed.values');
// Verify the response has normalized values array
expect(result.data?.normalizedValues).toContain('frontend');
expect(result.data?.normalizedValues).toContain('backend');
expect(result.data?.normalizedValues).toContain('200');
expect(result.data?.normalizedValues).toContain('404');
expect(result.data?.normalizedValues).toContain('true');
expect(result.data?.normalizedValues).toContain('false');
expect(result.data?.normalizedValues?.length).toBe(6);
});
it('should return a properly formatted success response', async () => {
// Create mock response
const mockApiResponse = {
status: 200,
data: {
status: 'success',
data: {
values: {
stringValues: ['frontend', 'backend'],
},
complete: true,
},
},
};
// Mock API to return our response
(ApiBaseInstance.get as jest.Mock).mockResolvedValueOnce(mockApiResponse);
// Call the function
const result = await getFieldValues('traces', 'service.name');
// Verify the returned structure matches SuccessResponseV2 format
expect(result).toEqual({
httpStatusCode: 200,
data: expect.objectContaining({
values: expect.any(Object),
normalizedValues: expect.any(Array),
complete: true,
}),
});
});
});

View File

@ -0,0 +1,38 @@
import { ApiBaseInstance } from 'api';
import { ErrorResponseHandlerV2 } from 'api/ErrorResponseHandlerV2';
import { AxiosError } from 'axios';
import { ErrorV2Resp, SuccessResponseV2 } from 'types/api';
import { FieldKeyResponse } from 'types/api/dynamicVariables/getFieldKeys';
/**
* Get field keys for a given signal type
* @param signal Type of signal (traces, logs, metrics)
* @param name Optional search text
*/
export const getFieldKeys = async (
signal?: 'traces' | 'logs' | 'metrics',
name?: string,
): Promise<SuccessResponseV2<FieldKeyResponse>> => {
const params: Record<string, string> = {};
if (signal) {
params.signal = encodeURIComponent(signal);
}
if (name) {
params.name = encodeURIComponent(name);
}
try {
const response = await ApiBaseInstance.get('/fields/keys', { params });
return {
httpStatusCode: response.status,
data: response.data.data,
};
} catch (error) {
ErrorResponseHandlerV2(error as AxiosError<ErrorV2Resp>);
}
};
export default getFieldKeys;

View File

@ -0,0 +1,87 @@
/* eslint-disable sonarjs/cognitive-complexity */
import { ApiBaseInstance } from 'api';
import { ErrorResponseHandlerV2 } from 'api/ErrorResponseHandlerV2';
import { AxiosError } from 'axios';
import { ErrorV2Resp, SuccessResponseV2 } from 'types/api';
import { FieldValueResponse } from 'types/api/dynamicVariables/getFieldValues';
/**
* Get field values for a given signal type and field name
* @param signal Type of signal (traces, logs, metrics)
* @param name Name of the attribute for which values are being fetched
* @param value Optional search text
* @param existingQuery Optional existing query - across all present dynamic variables
*/
export const getFieldValues = async (
signal?: 'traces' | 'logs' | 'metrics',
name?: string,
searchText?: string,
startUnixMilli?: number,
endUnixMilli?: number,
existingQuery?: string,
): Promise<SuccessResponseV2<FieldValueResponse>> => {
const params: Record<string, string> = {};
if (signal) {
params.signal = encodeURIComponent(signal);
}
if (name) {
params.name = encodeURIComponent(name);
}
if (searchText) {
params.searchText = encodeURIComponent(searchText);
}
if (startUnixMilli) {
params.startUnixMilli = Math.floor(startUnixMilli / 1000000).toString();
}
if (endUnixMilli) {
params.endUnixMilli = Math.floor(endUnixMilli / 1000000).toString();
}
if (existingQuery) {
params.existingQuery = existingQuery;
}
try {
const response = await ApiBaseInstance.get('/fields/values', { params });
// Normalize values from different types (stringValues, boolValues, etc.)
if (response.data?.data?.values) {
const allValues: string[] = [];
Object.entries(response.data?.data?.values).forEach(
([key, valueArray]: [string, any]) => {
// Skip RelatedValues as they should be kept separate
if (key === 'relatedValues') {
return;
}
if (Array.isArray(valueArray)) {
allValues.push(...valueArray.map(String));
}
},
);
// Add a normalized values array to the response
response.data.data.normalizedValues = allValues;
// Add relatedValues to the response as per FieldValueResponse
if (response.data?.data?.values?.relatedValues) {
response.data.data.relatedValues =
response.data?.data?.values?.relatedValues;
}
}
return {
httpStatusCode: response.status,
data: response.data.data,
};
} catch (error) {
ErrorResponseHandlerV2(error as AxiosError<ErrorV2Resp>);
}
};
export default getFieldValues;

View File

@ -19,6 +19,7 @@ import apiV1, {
apiV2,
apiV3,
apiV4,
apiV5,
gatewayApiV1,
gatewayApiV2,
} from './apiV1';
@ -171,6 +172,18 @@ ApiV4Instance.interceptors.response.use(
ApiV4Instance.interceptors.request.use(interceptorsRequestResponse);
//
// axios V5
export const ApiV5Instance = axios.create({
baseURL: `${ENVIRONMENT.baseURL}${apiV5}`,
});
ApiV5Instance.interceptors.response.use(
interceptorsResponse,
interceptorRejected,
);
ApiV5Instance.interceptors.request.use(interceptorsRequestResponse);
//
// axios Base
export const ApiBaseInstance = axios.create({
baseURL: `${ENVIRONMENT.baseURL}${apiV1}`,

View File

@ -2,7 +2,7 @@ import { ApiV3Instance, ApiV4Instance } from 'api';
import { ErrorResponseHandler } from 'api/ErrorResponseHandler';
import { AxiosError } from 'axios';
import { ENTITY_VERSION_V4 } from 'constants/app';
import { ErrorResponse, SuccessResponse } from 'types/api';
import { ErrorResponse, SuccessResponse, Warning } from 'types/api';
import {
MetricRangePayloadV3,
QueryRangePayload,
@ -13,7 +13,9 @@ export const getMetricsQueryRange = async (
version: string,
signal: AbortSignal,
headers?: Record<string, string>,
): Promise<SuccessResponse<MetricRangePayloadV3> | ErrorResponse> => {
): Promise<
(SuccessResponse<MetricRangePayloadV3> & { warning?: Warning }) | ErrorResponse
> => {
try {
if (version && version === ENTITY_VERSION_V4) {
const response = await ApiV4Instance.post('/query_range', props, {

View File

@ -17,6 +17,7 @@ export const getAggregateAttribute = async ({
aggregateOperator,
searchText,
dataSource,
source,
}: IGetAggregateAttributePayload): Promise<
SuccessResponse<IQueryAutocompleteResponse> | ErrorResponse
> => {
@ -27,7 +28,7 @@ export const getAggregateAttribute = async ({
`/autocomplete/aggregate_attributes?${createQueryParams({
aggregateOperator,
searchText,
dataSource,
dataSource: source === 'meter' ? 'meter' : dataSource,
})}`,
);

View File

@ -0,0 +1,30 @@
import axios from 'api';
import { AxiosResponse } from 'axios';
import {
QueryKeyRequestProps,
QueryKeySuggestionsResponseProps,
} from 'types/api/querySuggestions/types';
export const getKeySuggestions = (
props: QueryKeyRequestProps,
): Promise<AxiosResponse<QueryKeySuggestionsResponseProps>> => {
const {
signal = '',
searchText = '',
metricName = '',
fieldContext = '',
fieldDataType = '',
signalSource = '',
} = props;
const encodedSignal = encodeURIComponent(signal);
const encodedSearchText = encodeURIComponent(searchText);
const encodedMetricName = encodeURIComponent(metricName);
const encodedFieldContext = encodeURIComponent(fieldContext);
const encodedFieldDataType = encodeURIComponent(fieldDataType);
const encodedSource = encodeURIComponent(signalSource);
return axios.get(
`/fields/keys?signal=${encodedSignal}&searchText=${encodedSearchText}&metricName=${encodedMetricName}&fieldContext=${encodedFieldContext}&fieldDataType=${encodedFieldDataType}&source=${encodedSource}`,
);
};

View File

@ -0,0 +1,22 @@
import axios from 'api';
import { AxiosResponse } from 'axios';
import {
QueryKeyValueRequestProps,
QueryKeyValueSuggestionsResponseProps,
} from 'types/api/querySuggestions/types';
export const getValueSuggestions = (
props: QueryKeyValueRequestProps,
): Promise<AxiosResponse<QueryKeyValueSuggestionsResponseProps>> => {
const { signal, key, searchText, signalSource, metricName } = props;
const encodedSignal = encodeURIComponent(signal);
const encodedKey = encodeURIComponent(key);
const encodedMetricName = encodeURIComponent(metricName || '');
const encodedSearchText = encodeURIComponent(searchText);
const encodedSource = encodeURIComponent(signalSource || '');
return axios.get(
`/fields/values?signal=${encodedSignal}&name=${encodedKey}&searchText=${encodedSearchText}&metricName=${encodedMetricName}&source=${encodedSource}`,
);
};

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