Compare commits

...

59 Commits

Author SHA1 Message Date
Prashant Shahi
a48340a2ea Merge branch 'main' into release/v0.49.x 2024-07-04 22:27:41 +05:30
Prashant Shahi
e542d2ee09 chore(signoz): 📌 pin versions: SigNoz 0.49.1, SigNoz OtelCollector 0.102.2
Signed-off-by: Prashant Shahi <prashant@signoz.io>
2024-07-04 22:24:57 +05:30
Prashant Shahi
08431131a9 Merge branch 'develop' into release/v0.49.x 2024-07-04 22:21:07 +05:30
Nityananda Gohain
1b0ec8ac43 fix: typecase support added for float to int (#5408) 2024-07-04 12:08:42 +05:30
Yunus M
2e0ddc7c7f chore: remove dynamic config invocation (#5416) 2024-07-04 01:07:55 +05:30
Prashant Shahi
858a0cb0de Merge pull request #5418 from SigNoz/release/v0.49.x
Release/v0.49.x
2024-07-03 18:54:14 +05:30
Prashant Shahi
216ad36234 chore(signoz): 📌 pin versions: SigNoz 0.49.0, SigNoz OtelCollector 0.102.1
Signed-off-by: Prashant Shahi <prashant@signoz.io>
2024-07-03 16:53:11 +05:30
Prashant Shahi
6628abd435 Merge branch 'main' into release/v0.49.x 2024-07-03 16:51:16 +05:30
dependabot[bot]
7c81270ed9 chore(deps): bump ws from 7.5.9 to 7.5.10 in /frontend (#5265)
Bumps [ws](https://github.com/websockets/ws) from 7.5.9 to 7.5.10.
- [Release notes](https://github.com/websockets/ws/releases)
- [Commits](https://github.com/websockets/ws/compare/7.5.9...7.5.10)

---
updated-dependencies:
- dependency-name: ws
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-07-03 15:39:28 +05:30
dependabot[bot]
81c3e6fa65 chore(deps): bump braces from 3.0.2 to 3.0.3 in /frontend (#5196)
Bumps [braces](https://github.com/micromatch/braces) from 3.0.2 to 3.0.3.
- [Changelog](https://github.com/micromatch/braces/blob/master/CHANGELOG.md)
- [Commits](https://github.com/micromatch/braces/compare/3.0.2...3.0.3)

---
updated-dependencies:
- dependency-name: braces
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-07-03 12:33:22 +05:30
Yunus M
d215ce09b0 fix: remove pagination from members listing in org settings page (#5400) 2024-07-03 10:30:41 +05:30
Raj Kamal Singh
161a69fbe9 chore: remove workaround for supporting pipeline filters using attribs with . replaced with _ (#5405) 2024-07-02 17:14:08 +05:30
Srikanth Chekuri
3ee51770fd chore: remove rules dependency in CH reader (#5396) 2024-07-02 12:03:01 +05:30
Nityananda Gohain
932b7ddc69 fix: orderby validation and correction in logs old QB (#5399) 2024-07-02 11:53:30 +05:30
Vishal Sharma
6e466df89d chore: update posthog-js (#5382) 2024-07-01 21:11:31 +05:30
Srikanth Chekuri
326dec21fd fix: use the correct formatter for the description (#5388) 2024-07-01 18:34:02 +05:30
Srikanth Chekuri
b0b69c83db fix: use fill gaps only for time series panel types (#5387) 2024-07-01 14:06:28 +05:30
Vikrant Gupta
02106277a6 fix: restructure code to handle loading state for panel type change (#5378)
* fix: restructure code to handle loading state for panel type change

* fix: add inline comments
2024-06-28 13:53:35 +05:30
Vikrant Gupta
b34509215e fix: pie chart panels not rendering (#5376)
* fix: pie chart panels not rendering

* fix: restructure code
2024-06-28 12:10:57 +05:30
Raj Kamal Singh
fd603b8fdf Fix: pipeline alias collisions shouldnt lead to duplicate log processors (#5372)
* chore: add test validating pipeline alias collisions dont lead to bad config recommendations

* chore: emit error log on detecting duplicate processors in generated config

* chore: ensure collector config processor names for pipelines are unique

* chore: minor cleanups
2024-06-28 09:31:21 +05:30
Vikrant Gupta
c5d23336a7 chore: move the table calculation to backend (#5351) 2024-06-27 22:04:14 +05:30
SagarRajput-7
53c6288025 feat: added track event in Alerts - (multiple places) (#5354)
* feat: added track event in Alerts - (multiple places)

* feat: comment resolve and code refactor

* feat: add Alert Channel: Channel list page visited event

* feat: removed testSuccess variable and used responseStatus directly

* feat: added save status in alert channel: save action

* feat: added channel detail in save and test notification event

* feat: code refactor

* feat: added status message for save and test

* feat: added status message for save channel events

* feat: code refactor
2024-06-27 21:40:11 +05:30
Nityananda Gohain
4f2c314f39 feat: add spanKind and status in span response (#5120)
* feat: add spanKind and errorMessage in span response

* fix: add statusCodeString
2024-06-27 12:34:23 +05:30
Shaheer Kochai
1ad61615c6 Merge pull request #5362 from SigNoz/fix-duplicate-severityText-in-raw-logs
fix: remove duplicate severityText in raw logs
2024-06-27 10:31:49 +04:30
ahmadshaheer1
7ddfadfb18 fix: remove duplicate severityText in raw logs 2024-06-27 09:18:39 +04:30
KJ
a7e02af8b0 Hot rod load command fix (#5352)
* fix: added user_count and spawn_rate options to hotRod load data command

* fix: removed locust_count and hatch_rate options

* fix: updated user_count and spawn_rate values to the default values used in other places

---------

Co-authored-by: Prashant Shahi <prashant@signoz.io>
2024-06-27 00:07:34 +05:30
Vikrant Gupta
da3f6fd7fd fix: labelsArray being returned null despite of labels being present (#5357) 2024-06-26 22:09:14 +05:30
Shaheer Kochai
a453471b51 Merge pull request #5316 from SigNoz/remove-pagination-for-single-page-lists-
feat: remove pagination for single-page lists
2024-06-26 19:54:11 +04:30
ahmadshaheer1
13df87ed69 chore: discard passing 'hideOnSinglePage' to <ResizeTable, since already overridden 2024-06-26 18:44:27 +05:30
ahmadshaheer1
f23ceea54e chore: remove the unnecessary hideOnSinglePage prop 2024-06-26 18:44:27 +05:30
ahmadshaheer1
46b4c8a004 chore: extract pagination config 2024-06-26 18:44:27 +05:30
ahmadshaheer1
580198ca7a feat: remove pagination for single-page lists 2024-06-26 18:44:27 +05:30
Vikrant Gupta
2fb5b16840 fix: search not working in services table (#5353) 2024-06-26 16:30:11 +05:30
Srikanth Chekuri
de571aa69a chore: flaky TestTransformToTableForClickHouseQueries (#5355) 2024-06-26 16:19:24 +05:30
Srikanth Chekuri
daa5a05677 chore: update table response format (#5349) 2024-06-26 14:34:27 +05:30
CheetoDa
4f69996b9d fix: aks collector instruction fix (#5350) 2024-06-26 11:43:55 +05:30
SagarRajput-7
6c402d9e46 fix: added correct query for external metric service graph (#5318) 2024-06-25 21:31:52 +05:30
Prashant Shahi
c6e9eeeee6 Merge pull request #5348 from SigNoz/release/v0.48.1
Release/v0.48.1
2024-06-25 19:54:14 +05:30
Prashant Shahi
97b66741a7 chore(signoz): 📌 pin versions: SigNoz 0.48.1
Signed-off-by: Prashant Shahi <prashant@signoz.io>
2024-06-25 17:59:37 +05:30
Prashant Shahi
6b234da969 Merge branch 'main' into release/v0.48.1 2024-06-25 17:58:39 +05:30
Vishal Sharma
51032f6caa chore: move posthog to segment (#5330) 2024-06-25 15:50:09 +05:30
Vikrant Gupta
41f91db622 fix: apdex tooltip not visible in service details page (#5346) 2024-06-25 14:01:49 +05:30
Srikanth Chekuri
52e0303997 fix: table order by with builder queries (#5308) 2024-06-25 13:42:40 +05:30
Vikrant Gupta
5df25e83d1 fix: make the license key check case insensitive (#5331)
* fix: make the license key check case insensitive

* fix: added safety checks
2024-06-25 10:56:52 +05:30
Srikanth Chekuri
873280abea chore: read double pointer numbers from result (#5300) 2024-06-25 10:32:44 +05:30
Srikanth Chekuri
8ccdc71eaf chore: remove deprecated option (#5239) 2024-06-25 10:10:33 +05:30
Prashant Shahi
d5f156a6e9 ci(push): include POSTHOG_KEY environment in frontend (#5327)
Signed-off-by: Prashant Shahi <prashant@signoz.io>
2024-06-24 19:24:42 +05:30
Vikrant Gupta
cc7559ddee fix: stacked series no data case (#5328) 2024-06-24 18:17:34 +05:30
Yunus M
415057c260 feat: go to traces should use start time and end time from trace details (#5326)
* feat: go to traces should use start time and endtime from trace details

* chore: remove console log

---------

Co-authored-by: Vishal Sharma <makeavish786@gmail.com>
2024-06-24 16:57:05 +05:30
Vishal Sharma
89b67b8880 chore: posthog js init (#5324)
* chore: posthog js init

* feat: posthog events

---------

Co-authored-by: YounixM <myounis.ar@live.com>
2024-06-24 16:48:25 +05:30
Vishal Sharma
878cb7c0a6 fix: trace detail api start and end time (#5325) 2024-06-24 16:07:42 +05:30
Srikanth Chekuri
0375fc47a7 chore: add start/end millis for trace details response (#5321) 2024-06-24 14:45:26 +05:30
Srikanth Chekuri
a7a160df76 fix: incorrect telemetry query for samples (#5314) 2024-06-24 09:23:18 +05:30
Yunus M
8cd60b5c60 fix: handle overflow for attribute tooltips in trace details page (#5313) 2024-06-22 15:41:42 +05:30
CheetoDa
8ff392bc96 feat: azure monitoring docs (#5159)
* feat: azure monitoring docs

* chore: mapped paths

* chore: fixed instructions

* fix: added central collector steps

* fix: handle default azure steps, card alignment and reload issues

* fix: removed return true

---------

Co-authored-by: YounixM <myounis.ar@live.com>
2024-06-21 15:05:37 +05:30
SagarRajput-7
b59d9c7b90 fix: handled value as string from queryParams for trace filters (#5274)
* fix: handled value as string from queryParams for trace filters

* fix: added isArray check
2024-06-21 12:55:27 +05:30
Rajat Dabade
afcee9cd02 refactor: add to query should not open log detail drawer (#4732)
Co-authored-by: Rajat-Dabade <rajat@signoz.io>
2024-06-21 11:46:04 +05:30
Prashant Shahi
9dbef080c6 Merge pull request #5288 from SigNoz/release/v0.48.x
Release/v0.48.x
2024-06-20 20:49:47 +05:30
Vikrant Gupta
82a079e687 fix: move date time picker to click rather than hover (#5296) 2024-06-20 19:19:42 +05:30
162 changed files with 5034 additions and 621 deletions

View File

@@ -158,6 +158,7 @@ jobs:
echo 'SENTRY_DSN="${{ secrets.SENTRY_DSN }}"' >> frontend/.env
echo 'TUNNEL_URL="${{ secrets.TUNNEL_URL }}"' >> frontend/.env
echo 'TUNNEL_DOMAIN="${{ secrets.TUNNEL_DOMAIN }}"' >> frontend/.env
echo 'POSTHOG_KEY="${{ secrets.POSTHOG_KEY }}"' >> frontend/.env
- name: Install dependencies
working-directory: frontend
run: yarn install

View File

@@ -347,7 +347,7 @@ curl -sL https://github.com/SigNoz/signoz/raw/develop/sample-apps/hotrod/hotrod-
```bash
kubectl -n sample-application run strzal --image=djbingham/curl \
--restart='OnFailure' -i --tty --rm --command -- curl -X POST -F \
'locust_count=6' -F 'hatch_rate=2' http://locust-master:8089/swarm
'user_count=6' -F 'spawn_rate=2' http://locust-master:8089/swarm
```
**5.1.3 To stop the load generation:**

View File

@@ -188,3 +188,4 @@ test:
go test ./pkg/query-service/tests/integration/...
go test ./pkg/query-service/rules/...
go test ./pkg/query-service/collectorsimulator/...
go test ./pkg/query-service/postprocess/...

View File

@@ -146,7 +146,7 @@ services:
condition: on-failure
query-service:
image: signoz/query-service:0.48.0
image: signoz/query-service:0.49.1
command:
[
"-config=/root/config/prometheus.yml",
@@ -199,7 +199,7 @@ services:
- ../common/nginx-config.conf:/etc/nginx/conf.d/default.conf
otel-collector:
image: signoz/signoz-otel-collector:0.102.0
image: signoz/signoz-otel-collector:0.102.2
command:
[
"--config=/etc/otel-collector-config.yaml",
@@ -237,7 +237,7 @@ services:
- query-service
otel-collector-migrator:
image: signoz/signoz-schema-migrator:0.102.0
image: signoz/signoz-schema-migrator:0.102.2
deploy:
restart_policy:
condition: on-failure

View File

@@ -66,7 +66,7 @@ services:
- --storage.path=/data
otel-collector-migrator:
image: signoz/signoz-schema-migrator:${OTELCOL_TAG:-0.102.0}
image: signoz/signoz-schema-migrator:${OTELCOL_TAG:-0.102.2}
container_name: otel-migrator
command:
- "--dsn=tcp://clickhouse:9000"
@@ -81,7 +81,7 @@ services:
# Notes for Maintainers/Contributors who will change Line Numbers of Frontend & Query-Section. Please Update Line Numbers in `./scripts/commentLinesForSetup.sh` & `./CONTRIBUTING.md`
otel-collector:
container_name: signoz-otel-collector
image: signoz/signoz-otel-collector:0.102.0
image: signoz/signoz-otel-collector:0.102.2
command:
[
"--config=/etc/otel-collector-config.yaml",

View File

@@ -164,7 +164,7 @@ services:
# Notes for Maintainers/Contributors who will change Line Numbers of Frontend & Query-Section. Please Update Line Numbers in `./scripts/commentLinesForSetup.sh` & `./CONTRIBUTING.md`
query-service:
image: signoz/query-service:${DOCKER_TAG:-0.48.0}
image: signoz/query-service:${DOCKER_TAG:-0.49.1}
container_name: signoz-query-service
command:
[
@@ -204,7 +204,7 @@ services:
<<: *db-depend
frontend:
image: signoz/frontend:${DOCKER_TAG:-0.48.0}
image: signoz/frontend:${DOCKER_TAG:-0.49.1}
container_name: signoz-frontend
restart: on-failure
depends_on:
@@ -216,7 +216,7 @@ services:
- ../common/nginx-config.conf:/etc/nginx/conf.d/default.conf
otel-collector-migrator:
image: signoz/signoz-schema-migrator:${OTELCOL_TAG:-0.102.0}
image: signoz/signoz-schema-migrator:${OTELCOL_TAG:-0.102.2}
container_name: otel-migrator
command:
- "--dsn=tcp://clickhouse:9000"
@@ -230,7 +230,7 @@ services:
otel-collector:
image: signoz/signoz-otel-collector:${OTELCOL_TAG:-0.102.0}
image: signoz/signoz-otel-collector:${OTELCOL_TAG:-0.102.2}
container_name: signoz-otel-collector
command:
[

View File

@@ -164,7 +164,7 @@ services:
# Notes for Maintainers/Contributors who will change Line Numbers of Frontend & Query-Section. Please Update Line Numbers in `./scripts/commentLinesForSetup.sh` & `./CONTRIBUTING.md`
query-service:
image: signoz/query-service:${DOCKER_TAG:-0.48.0}
image: signoz/query-service:${DOCKER_TAG:-0.49.1}
container_name: signoz-query-service
command:
[
@@ -203,7 +203,7 @@ services:
<<: *db-depend
frontend:
image: signoz/frontend:${DOCKER_TAG:-0.48.0}
image: signoz/frontend:${DOCKER_TAG:-0.49.1}
container_name: signoz-frontend
restart: on-failure
depends_on:
@@ -215,7 +215,7 @@ services:
- ../common/nginx-config.conf:/etc/nginx/conf.d/default.conf
otel-collector-migrator:
image: signoz/signoz-schema-migrator:${OTELCOL_TAG:-0.102.0}
image: signoz/signoz-schema-migrator:${OTELCOL_TAG:-0.102.2}
container_name: otel-migrator
command:
- "--dsn=tcp://clickhouse:9000"
@@ -229,7 +229,7 @@ services:
otel-collector:
image: signoz/signoz-otel-collector:${OTELCOL_TAG:-0.102.0}
image: signoz/signoz-otel-collector:${OTELCOL_TAG:-0.102.2}
container_name: signoz-otel-collector
command:
[

View File

@@ -389,7 +389,7 @@ trap bye EXIT
URL="https://api.segment.io/v1/track"
HEADER_1="Content-Type: application/json"
HEADER_2="Authorization: Basic NEdtb2E0aXhKQVVIeDJCcEp4c2p3QTFiRWZud0VlUno6"
HEADER_2="Authorization: Basic OWtScko3b1BDR1BFSkxGNlFqTVBMdDVibGpGaFJRQnI="
send_event() {
error=""

View File

@@ -24,7 +24,6 @@ import (
type APIHandlerOptions struct {
DataConnector interfaces.DataConnector
SkipConfig *basemodel.SkipConfig
PreferDelta bool
PreferSpanMetrics bool
MaxIdleConns int
MaxOpenConns int
@@ -53,7 +52,6 @@ func NewAPIHandler(opts APIHandlerOptions) (*APIHandler, error) {
baseHandler, err := baseapp.NewAPIHandler(baseapp.APIHandlerOpts{
Reader: opts.DataConnector,
SkipConfig: opts.SkipConfig,
PerferDelta: opts.PreferDelta,
PreferSpanMetrics: opts.PreferSpanMetrics,
MaxIdleConns: opts.MaxIdleConns,
MaxOpenConns: opts.MaxOpenConns,

View File

@@ -64,7 +64,6 @@ type ServerOptions struct {
// alert specific params
DisableRules bool
RuleRepoURL string
PreferDelta bool
PreferSpanMetrics bool
MaxIdleConns int
MaxOpenConns int
@@ -256,7 +255,6 @@ func NewServer(serverOptions *ServerOptions) (*Server, error) {
apiOpts := api.APIHandlerOptions{
DataConnector: reader,
SkipConfig: skipConfig,
PreferDelta: serverOptions.PreferDelta,
PreferSpanMetrics: serverOptions.PreferSpanMetrics,
MaxIdleConns: serverOptions.MaxIdleConns,
MaxOpenConns: serverOptions.MaxOpenConns,

View File

@@ -89,7 +89,6 @@ func main() {
var cacheConfigPath, fluxInterval string
var enableQueryServiceLogOTLPExport bool
var preferDelta bool
var preferSpanMetrics bool
var maxIdleConns int
@@ -100,14 +99,13 @@ func main() {
flag.StringVar(&promConfigPath, "config", "./config/prometheus.yml", "(prometheus config to read metrics)")
flag.StringVar(&skipTopLvlOpsPath, "skip-top-level-ops", "", "(config file to skip top level operations)")
flag.BoolVar(&disableRules, "rules.disable", false, "(disable rule evaluation)")
flag.BoolVar(&preferDelta, "prefer-delta", false, "(prefer delta over cumulative metrics)")
flag.BoolVar(&preferSpanMetrics, "prefer-span-metrics", false, "(prefer span metrics for service level metrics)")
flag.IntVar(&maxIdleConns, "max-idle-conns", 50, "(number of connections to maintain in the pool.)")
flag.IntVar(&maxOpenConns, "max-open-conns", 100, "(max connections for use at any time.)")
flag.DurationVar(&dialTimeout, "dial-timeout", 5*time.Second, "(the maximum time to establish a connection.)")
flag.StringVar(&ruleRepoURL, "rules.repo-url", baseconst.AlertHelpPage, "(host address used to build rule link in alert messages)")
flag.StringVar(&cacheConfigPath, "experimental.cache-config", "", "(cache config to use)")
flag.StringVar(&fluxInterval, "flux-interval", "5m", "(cache config to use)")
flag.StringVar(&fluxInterval, "flux-interval", "5m", "(the interval to exclude data from being cached to avoid incorrect cache for data in motion)")
flag.BoolVar(&enableQueryServiceLogOTLPExport, "enable.query.service.log.otlp.export", false, "(enable query service log otlp export)")
flag.StringVar(&cluster, "cluster", "cluster", "(cluster name - defaults to 'cluster')")
flag.StringVar(&gatewayUrl, "gateway-url", "", "(url to the gateway)")
@@ -125,7 +123,6 @@ func main() {
HTTPHostPort: baseconst.HTTPHostPort,
PromConfigPath: promConfigPath,
SkipTopLvlOpsPath: skipTopLvlOpsPath,
PreferDelta: preferDelta,
PreferSpanMetrics: preferSpanMetrics,
PrivateHostPort: baseconst.PrivateHostPort,
DisableRules: disableRules,

View File

@@ -88,6 +88,7 @@
"lucide-react": "0.379.0",
"mini-css-extract-plugin": "2.4.5",
"papaparse": "5.4.1",
"posthog-js": "1.142.1",
"rc-tween-one": "3.0.6",
"react": "18.2.0",
"react-addons-update": "15.6.3",

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 18 18"><defs><linearGradient id="a" x1="2.94" y1="3.74" x2="8.67" y2="3.74" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#b77af4"/><stop offset="1" stop-color="#773adc"/></linearGradient><linearGradient id="b" x1="9.13" y1="3.79" x2="14.85" y2="3.79" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#b77af4"/><stop offset="1" stop-color="#773adc"/></linearGradient><linearGradient id="c" x1=".01" y1="9.12" x2="5.73" y2="9.12" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#b77af4"/><stop offset="1" stop-color="#773adc"/></linearGradient><linearGradient id="d" x1="6.18" y1="9.08" x2="11.9" y2="9.08" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#b77af4"/><stop offset="1" stop-color="#773adc"/></linearGradient><linearGradient id="e" x1="12.35" y1="9.13" x2="18.08" y2="9.13" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#b77af4"/><stop offset="1" stop-color="#773adc"/></linearGradient><linearGradient id="f" x1="2.87" y1="14.56" x2="8.6" y2="14.56" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#b77af4"/><stop offset="1" stop-color="#773adc"/></linearGradient><linearGradient id="g" x1="9.05" y1="14.6" x2="14.78" y2="14.6" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#b77af4"/><stop offset="1" stop-color="#773adc"/></linearGradient></defs><path fill="url(#a)" d="M5.8 1.22l-2.86.53v3.9l2.86.61 2.87-1.15V2.2L5.8 1.22z"/><path d="M5.91 6.2l2.62-1.06A.2.2 0 008.65 5V2.36a.21.21 0 00-.13-.18l-2.65-.9h-.12l-2.6.48a.2.2 0 00-.15.18v3.53a.19.19 0 00.15.19l2.63.55a.32.32 0 00.13-.01z" fill="none"/><path d="M2.94 1.75v3.9l2.89.61v-5zm1.22 3.6l-.81-.16v-3l.81-.13zm1.26.23l-.93-.15V2l.93-.16z" fill="#341a6e"/><path fill="url(#b)" d="M11.99 1.27l-2.86.53v3.9l2.86.61 2.86-1.16v-2.9l-2.86-.98z"/><path d="M9.13 1.8v3.9l2.87.61v-5zm1.21 3.6l-.81-.16v-3l.81-.13zm1.26.23l-.93-.15V2.05l.93-.17z" fill="#341a6e"/><path fill="url(#c)" d="M2.87 6.6l-2.86.53v3.9l2.86.61 2.87-1.15V7.58L2.87 6.6z"/><path d="M0 7.13V11l2.89.61v-5zm1.21 3.61l-.81-.17v-3l.81-.14zm1.27.26l-.93-.15V7.38l.93-.16z" fill="#341a6e"/><path fill="url(#d)" d="M9.04 6.56l-2.86.53v3.9l2.86.62 2.86-1.16V7.54l-2.86-.98z"/><path d="M6.18 7.09V11l2.88.61v-5zm1.21 3.61l-.81-.17v-3l.81-.14zm1.26.22l-.93-.15V7.34l.93-.16z" fill="#341a6e"/><path fill="url(#e)" d="M15.21 6.61l-2.86.53v3.9l2.86.61 2.87-1.15V7.59l-2.87-.98z"/><path d="M12.35 7.14V11l2.89.61v-5zm1.22 3.61l-.81-.17v-3l.81-.14zm1.26.22l-.93-.15V7.39l.93-.16z" fill="#341a6e"/><path fill="url(#f)" d="M5.73 12.04l-2.86.52v3.9l2.86.62 2.87-1.16v-2.9l-2.87-.98z"/><path d="M5.84 17l2.61-1a.18.18 0 00.12-.18v-2.6a.2.2 0 00-.13-.22l-2.64-.9a.17.17 0 00-.12 0l-2.6.47a.19.19 0 00-.16.19v3.54a.19.19 0 00.15.19L5.7 17a.23.23 0 00.14 0z" fill="none"/><path d="M2.87 12.56v3.9l2.89.62V12zm1.22 3.61L3.28 16v-3l.81-.14zm1.26.23l-.93-.15v-3.44l.93-.16z" fill="#341a6e"/><path fill="url(#g)" d="M11.91 12.08l-2.86.53v3.9l2.86.61 2.87-1.15v-2.91l-2.87-.98z"/><path d="M9.05 12.61v3.9l2.89.61v-5zm1.22 3.61l-.81-.17v-3l.81-.14zm1.26.22l-.93-.15v-3.43l.93-.16z" fill="#341a6e"/></svg>

After

Width:  |  Height:  |  Size: 3.1 KiB

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 18 18"><defs><linearGradient id="b" x1="4.4" y1="11.48" x2="4.37" y2="7.53" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#ccc"/><stop offset="1" stop-color="#fcfcfc"/></linearGradient><linearGradient id="c" x1="10.13" y1="15.45" x2="10.13" y2="11.9" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#ccc"/><stop offset="1" stop-color="#fcfcfc"/></linearGradient><linearGradient id="d" x1="14.18" y1="11.15" x2="14.18" y2="7.38" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#ccc"/><stop offset="1" stop-color="#fcfcfc"/></linearGradient><radialGradient id="a" cx="13428.81" cy="3518.86" r="56.67" gradientTransform="matrix(.15 0 0 .15 -2005.33 -518.83)" gradientUnits="userSpaceOnUse"><stop offset=".18" stop-color="#5ea0ef"/><stop offset="1" stop-color="#0078d4"/></radialGradient></defs><path d="M14.21 15.72A8.5 8.5 0 013.79 2.28l.09-.06a8.5 8.5 0 0110.33 13.5" fill="url(#a)"/><path d="M6.69 7.23a13 13 0 018.91-3.58 8.47 8.47 0 00-1.49-1.44 14.34 14.34 0 00-4.69 1.1 12.54 12.54 0 00-4.08 2.82 2.76 2.76 0 011.35 1.1zM2.48 10.65a17.86 17.86 0 00-.83 2.62 7.82 7.82 0 00.62.92c.18.23.35.44.55.65a17.94 17.94 0 011.08-3.47 2.76 2.76 0 01-1.42-.72z" fill="#fff" opacity=".6"/><path d="M3.46 6.11a12 12 0 01-.69-2.94 8.15 8.15 0 00-1.1 1.45A12.69 12.69 0 002.24 7a2.69 2.69 0 011.22-.89z" fill="#f2f2f2" opacity=".55"/><circle cx="4.38" cy="8.68" r="2.73" fill="url(#b)"/><path d="M8.36 13.67a1.77 1.77 0 01.54-1.27 11.88 11.88 0 01-2.53-1.86 2.74 2.74 0 01-1.49.83 13.1 13.1 0 001.45 1.28 12.12 12.12 0 002.05 1.25 1.79 1.79 0 01-.02-.23zM14.66 13.88a12 12 0 01-2.76-.32.41.41 0 010 .11 1.75 1.75 0 01-.51 1.24 13.69 13.69 0 003.42.24A8.21 8.21 0 0016 13.81a11.5 11.5 0 01-1.34.07z" fill="#f2f2f2" opacity=".55"/><circle cx="10.13" cy="13.67" r="1.78" fill="url(#c)"/><path d="M12.32 8.93a1.83 1.83 0 01.61-1 25.5 25.5 0 01-4.46-4.14 16.91 16.91 0 01-2-2.92 7.64 7.64 0 00-1.09.42 18.14 18.14 0 002.15 3.18 26.44 26.44 0 004.79 4.46z" fill="#f2f2f2" opacity=".7"/><circle cx="14.18" cy="9.27" r="1.89" fill="url(#d)"/><path d="M17.35 10.54l-.35-.17-.3-.16h-.06l-.26-.21h-.07L16 9.8a1.76 1.76 0 01-.64.92c.12.08.25.15.38.22l.08.05.35.19.86.45a8.63 8.63 0 00.29-1.11z" fill="#f2f2f2" opacity=".55"/><circle cx="4.38" cy="8.68" r="2.73" fill="url(#b)"/><circle cx="10.13" cy="13.67" r="1.78" fill="url(#c)"/></svg>

After

Width:  |  Height:  |  Size: 2.3 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 6.7 KiB

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 18 18"><defs><linearGradient id="b27f1ad0-7d11-4247-9da3-91bce6211f32" x1="8.798" y1="8.703" x2="14.683" y2="8.703" gradientUnits="userSpaceOnUse"><stop offset="0.001" stop-color="#773adc" /><stop offset="1" stop-color="#552f99" /></linearGradient><linearGradient id="b2f92112-4ca9-4b17-a019-c9f26c1a4a8f" x1="5.764" y1="3.777" x2="5.764" y2="13.78" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#a67af4" /><stop offset="0.999" stop-color="#773adc" /></linearGradient></defs><g id="b8a0486a-5501-4d92-b540-a766c4b3b548"><g><g><g><path d="M16.932,11.578a8.448,8.448,0,0,1-7.95,5.59,8.15,8.15,0,0,1-2.33-.33,2.133,2.133,0,0,0,.18-.83c.01,0,.03.01.04.01a7.422,7.422,0,0,0,2.11.3,7.646,7.646,0,0,0,6.85-4.28l.01-.01Z" fill="#32bedd" /><path d="M3.582,14.068a2.025,2.025,0,0,0-.64.56,8.6,8.6,0,0,1-1.67-2.44l1.04.23v.26a.6.6,0,0,0,.47.59l.14.03a6.136,6.136,0,0,0,.62.73Z" fill="#32bedd" /><path d="M12.352.958a2.28,2.28,0,0,0-.27.81c-.02-.01-.05-.02-.07-.03a7.479,7.479,0,0,0-3.03-.63,7.643,7.643,0,0,0-5.9,2.8l-.29.06a.6.6,0,0,0-.48.58v.46l-1.02.19A8.454,8.454,0,0,1,8.982.268,8.6,8.6,0,0,1,12.352.958Z" fill="#32bedd" /><path d="M16.872,5.7l-1.09-.38a6.6,6.6,0,0,0-.72-1.16c-.02-.03-.04-.05-.05-.07a2.083,2.083,0,0,0,.72-.45A7.81,7.81,0,0,1,16.872,5.7Z" fill="#32bedd" /><path d="M10.072,11.908l2.54.56L8.672,14.1c-.02,0-.03.01-.05.01a.154.154,0,0,1-.15-.15V3.448a.154.154,0,0,1,.15-.15.09.09,0,0,1,.05.01l4.46,1.56-3.05.57a.565.565,0,0,0-.44.54v5.4A.537.537,0,0,0,10.072,11.908Z" fill="#fff" /><g><g id="e918f286-5032-4942-ad29-ea17e6f1cc90"><path d="M1.1,5.668l1.21-.23v6.55l-1.23-.27-.99-.22a.111.111,0,0,1-.09-.12v-5.4a.12.12,0,0,1,.09-.12Z" fill="#a67af4" /></g><g><g id="a47a99dd-4d47-4c70-8c42-c5ac274ce496"><g><path d="M10.072,11.908l2.54.56L8.672,14.1c-.02,0-.03.01-.05.01a.154.154,0,0,1-.15-.15V3.448a.154.154,0,0,1,.15-.15.09.09,0,0,1,.05.01l4.46,1.56-3.05.57a.565.565,0,0,0-.44.54v5.4A.537.537,0,0,0,10.072,11.908Z" fill="url(#b27f1ad0-7d11-4247-9da3-91bce6211f32)" /><path d="M8.586,3.3,2.878,4.378a.177.177,0,0,0-.14.175V12.68a.177.177,0,0,0,.137.174L8.581,14.1a.176.176,0,0,0,.21-.174V3.478A.175.175,0,0,0,8.619,3.3Z" fill="url(#b2f92112-4ca9-4b17-a019-c9f26c1a4a8f)" /></g></g><polygon points="5.948 4.921 5.948 12.483 7.934 12.814 7.934 4.564 5.948 4.921" fill="#b796f9" opacity="0.5" /><polygon points="3.509 5.329 3.509 11.954 5.238 12.317 5.238 5.031 3.509 5.329" fill="#b796f9" opacity="0.5" /></g></g></g><path d="M16,2.048a1.755,1.755,0,1,1-1.76-1.76A1.756,1.756,0,0,1,16,2.048Z" fill="#32bedd" /><circle cx="4.65" cy="15.973" r="1.759" fill="#32bedd" /></g><path d="M18,6.689v3.844a.222.222,0,0,1-.133.2l-.766.316-3.07,1.268-.011,0a.126.126,0,0,1-.038,0,.1.1,0,0,1-.1-.1V5.234a.1.1,0,0,1,.054-.088l0,0,.019,0a.031.031,0,0,1,.019,0,.055.055,0,0,1,.034.008l.011,0,.012,0L17.05,6.2l.8.282A.213.213,0,0,1,18,6.689Z" fill="#773adc" /><path d="M13.959,5.14l-3.8.715a.118.118,0,0,0-.093.117v5.409a.118.118,0,0,0,.091.116l3.8.831a.115.115,0,0,0,.137-.09.109.109,0,0,0,0-.026V5.256a.117.117,0,0,0-.115-.118A.082.082,0,0,0,13.959,5.14Z" fill="#a67af4" /></g></g></svg>

After

Width:  |  Height:  |  Size: 3.1 KiB

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 18 18"><defs><linearGradient id="a" x1="-175.993" y1="-343.723" x2="-175.993" y2="-359.232" gradientTransform="matrix(1.156 0 0 1.029 212.573 370.548)" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#fea11b"/><stop offset=".284" stop-color="#fea51a"/><stop offset=".547" stop-color="#feb018"/><stop offset=".8" stop-color="#ffc314"/><stop offset="1" stop-color="#ffd70f"/></linearGradient></defs><path d="M5.54 13.105l-.586.588a.267.267 0 01-.377 0L.223 9.353a.533.533 0 010-.755l.588-.59 4.732 4.718a.267.267 0 010 .378z" fill="#50e6ff"/><path d="M4.863 4.305l.59.588a.267.267 0 010 .378L.806 9.932l-.59-.589a.533.533 0 01-.001-.754l4.273-4.285a.267.267 0 01.376 0z" fill="#1490df"/><path d="M17.19 8.012l.588.59a.533.533 0 01-.001.754l-4.354 4.34a.267.267 0 01-.377 0l-.586-.587a.267.267 0 010-.377l4.732-4.718z" fill="#50e6ff"/><path d="M17.782 9.34l-.59.589-4.648-4.662a.267.267 0 010-.377l.59-.588a.267.267 0 01.378 0l4.273 4.286a.533.533 0 010 .753z" fill="#1490df"/><path d="M8.459 9.9H4.87a.193.193 0 01-.2-.181.166.166 0 01.018-.075L8.991 1.13a.206.206 0 01.186-.106h4.245a.193.193 0 01.2.181.165.165 0 01-.035.1L8.534 7.966h4.928a.193.193 0 01.2.181.176.176 0 01-.052.122l-8.189 8.519c-.077.046-.624.5-.356-.189z" fill="url(#a)"/></svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 18 18"><defs><radialGradient id="b" cx="9.36" cy="10.57" r="7.07" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#f2f2f2"/><stop offset=".58" stop-color="#eee"/><stop offset="1" stop-color="#e6e6e6"/></radialGradient><linearGradient id="a" x1="2.59" y1="10.16" x2="15.41" y2="10.16" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#005ba1"/><stop offset=".07" stop-color="#0060a9"/><stop offset=".36" stop-color="#0071c8"/><stop offset=".52" stop-color="#0078d4"/><stop offset=".64" stop-color="#0074cd"/><stop offset=".82" stop-color="#006abb"/><stop offset="1" stop-color="#005ba1"/></linearGradient></defs><path d="M9 5.14c-3.54 0-6.41-1-6.41-2.32v12.36c0 1.27 2.82 2.3 6.32 2.32H9c3.54 0 6.41-1 6.41-2.32V2.82c0 1.29-2.87 2.32-6.41 2.32z" fill="url(#a)"/><path d="M15.41 2.82c0 1.29-2.87 2.32-6.41 2.32s-6.41-1-6.41-2.32S5.46.5 9 .5s6.41 1 6.41 2.32" fill="#e8e8e8"/><path d="M13.92 2.63c0 .82-2.21 1.48-4.92 1.48s-4.92-.66-4.92-1.48S6.29 1.16 9 1.16s4.92.66 4.92 1.47" fill="#50e6ff"/><path d="M9 3a11.55 11.55 0 00-3.89.57A11.42 11.42 0 009 4.11a11.15 11.15 0 003.89-.58A11.84 11.84 0 009 3z" fill="#198ab3"/><path d="M12.9 11.4V8H12v4.13h2.46v-.73zM5.76 9.73a1.83 1.83 0 01-.51-.31.44.44 0 01-.12-.32.34.34 0 01.15-.3.68.68 0 01.42-.12 1.62 1.62 0 011 .29v-.86a2.58 2.58 0 00-1-.16 1.64 1.64 0 00-1.09.34 1.08 1.08 0 00-.42.89c0 .51.32.91 1 1.21a2.88 2.88 0 01.62.36.42.42 0 01.15.32.38.38 0 01-.16.31.81.81 0 01-.45.11 1.66 1.66 0 01-1.09-.42V12a2.17 2.17 0 001.07.24 1.88 1.88 0 001.18-.33 1.08 1.08 0 00.33-.91 1.05 1.05 0 00-.25-.7 2.42 2.42 0 00-.83-.57zM11 11.32a2.34 2.34 0 00.33-1.26A2.32 2.32 0 0011 9a1.81 1.81 0 00-.7-.75 2 2 0 00-1-.26 2.11 2.11 0 00-1.08.27 1.86 1.86 0 00-.73.74 2.46 2.46 0 00-.26 1.14 2.26 2.26 0 00.24 1 1.76 1.76 0 00.69.74 2.06 2.06 0 001 .3l.86 1h1.21L10 12.08a1.79 1.79 0 001-.76zm-1-.25a.94.94 0 01-.76.35.92.92 0 01-.76-.36 1.52 1.52 0 01-.29-1 1.53 1.53 0 01.29-1 1 1 0 01.78-.37.87.87 0 01.75.37 1.62 1.62 0 01.27 1 1.46 1.46 0 01-.28 1.01z" fill="url(#b)"/></svg>

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 18 18"><defs><linearGradient id="a" x1="8.88" y1="12.21" x2="8.88" y2=".21" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#0078d4"/><stop offset=".82" stop-color="#5ea0ef"/></linearGradient><linearGradient id="b" x1="8.88" y1="16.84" x2="8.88" y2="12.21" gradientUnits="userSpaceOnUse"><stop offset=".15" stop-color="#ccc"/><stop offset="1" stop-color="#707070"/></linearGradient></defs><rect x="-.12" y=".21" width="18" height="12" rx=".6" fill="url(#a)"/><path fill="#50e6ff" d="M11.88 4.46v3.49l-3 1.76v-3.5l3-1.75z"/><path fill="#c3f1ff" d="M11.88 4.46l-3 1.76-3-1.76 3-1.75 3 1.75z"/><path fill="#9cebff" d="M8.88 6.22v3.49l-3-1.76V4.46l3 1.76z"/><path fill="#c3f1ff" d="M5.88 7.95l3-1.74v3.5l-3-1.76z"/><path fill="#9cebff" d="M11.88 7.95l-3-1.74v3.5l3-1.76z"/><path d="M12.49 15.84c-1.78-.28-1.85-1.56-1.85-3.63H7.11c0 2.07-.06 3.35-1.84 3.63a1 1 0 00-.89 1h9a1 1 0 00-.89-1z" fill="url(#b)"/></svg>

After

Width:  |  Height:  |  Size: 973 B

View File

@@ -8,6 +8,7 @@
"GET_STARTED_LOGS_MANAGEMENT": "SigNoz | Get Started | Logs",
"GET_STARTED_INFRASTRUCTURE_MONITORING": "SigNoz | Get Started | Infrastructure",
"GET_STARTED_AWS_MONITORING": "SigNoz | Get Started | AWS",
"GET_STARTED_AZURE_MONITORING": "SigNoz | Get Started | AZURE",
"TRACE": "SigNoz | Trace",
"TRACE_DETAIL": "SigNoz | Trace Detail",
"TRACES_EXPLORER": "SigNoz | Traces Explorer",

View File

@@ -17,6 +17,7 @@ import { NotificationProvider } from 'hooks/useNotifications';
import { ResourceProvider } from 'hooks/useResourceAttribute';
import history from 'lib/history';
import { identity, pick, pickBy } from 'lodash-es';
import posthog from 'posthog-js';
import { DashboardProvider } from 'providers/Dashboard/Dashboard';
import { QueryBuilderProvider } from 'providers/QueryBuilder';
import { Suspense, useEffect, useState } from 'react';
@@ -38,7 +39,7 @@ import defaultRoutes, {
function App(): JSX.Element {
const themeConfig = useThemeConfig();
const { data } = useLicense();
const { data: licenseData } = useLicense();
const [routes, setRoutes] = useState<AppRoutes[]>(defaultRoutes);
const { role, isLoggedIn: isLoggedInState, user, org } = useSelector<
AppState,
@@ -92,10 +93,10 @@ function App(): JSX.Element {
});
const isOnBasicPlan =
data?.payload?.licenses?.some(
licenseData?.payload?.licenses?.some(
(license) =>
license.isCurrent && license.planKey === LICENSE_PLAN_KEY.BASIC_PLAN,
) || data?.payload?.licenses === null;
) || licenseData?.payload?.licenses === null;
const enableAnalytics = (user: User): void => {
const orgName =
@@ -112,9 +113,7 @@ function App(): JSX.Element {
};
const sanitizedIdentifyPayload = pickBy(identifyPayload, identity);
const domain = extractDomain(email);
const hostNameParts = hostname.split('.');
const groupTraits = {
@@ -127,10 +126,30 @@ function App(): JSX.Element {
};
window.analytics.identify(email, sanitizedIdentifyPayload);
window.analytics.group(domain, groupTraits);
window.clarity('identify', email, name);
posthog?.identify(email, {
email,
name,
orgName,
tenant_id: hostNameParts[0],
data_region: hostNameParts[1],
tenant_url: hostname,
company_domain: domain,
source: 'signoz-ui',
isPaidUser: !!licenseData?.payload?.trialConvertedToSubscription,
});
posthog?.group('company', domain, {
name: orgName,
tenant_id: hostNameParts[0],
data_region: hostNameParts[1],
tenant_url: hostname,
company_domain: domain,
source: 'signoz-ui',
isPaidUser: !!licenseData?.payload?.trialConvertedToSubscription,
});
};
useEffect(() => {
@@ -144,10 +163,6 @@ function App(): JSX.Element {
!isIdentifiedUser
) {
setLocalStorageApi(LOCALSTORAGE.IS_IDENTIFIED_USER, 'true');
if (isCloudUserVal) {
enableAnalytics(user);
}
}
if (
@@ -195,6 +210,11 @@ function App(): JSX.Element {
console.error('Failed to parse local storage theme analytics event');
}
}
if (isCloudUserVal && user && user.email) {
enableAnalytics(user);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [user]);

View File

@@ -287,7 +287,7 @@ function CustomTimePicker({
)
}
arrow={false}
trigger="hover"
trigger="click"
open={open}
onOpenChange={handleOpenChange}
style={{

View File

@@ -5,7 +5,13 @@ import { Button, Dropdown, MenuProps } from 'antd';
import { useIsDarkMode } from 'hooks/useDarkMode';
import { useState } from 'react';
function DropDown({ element }: { element: JSX.Element[] }): JSX.Element {
function DropDown({
element,
onDropDownItemClick,
}: {
element: JSX.Element[];
onDropDownItemClick?: MenuProps['onClick'];
}): JSX.Element {
const isDarkMode = useIsDarkMode();
const items: MenuProps['items'] = element.map(
@@ -23,6 +29,7 @@ function DropDown({ element }: { element: JSX.Element[] }): JSX.Element {
items,
onMouseEnter: (): void => setDdOpen(true),
onMouseLeave: (): void => setDdOpen(false),
onClick: (item): void => onDropDownItemClick?.(item),
}}
open={isDdOpen}
>
@@ -40,4 +47,8 @@ function DropDown({ element }: { element: JSX.Element[] }): JSX.Element {
);
}
DropDown.defaultProps = {
onDropDownItemClick: (): void => {},
};
export default DropDown;

View File

@@ -2,7 +2,7 @@ import './AddToQueryHOC.styles.scss';
import { Popover } from 'antd';
import { OPERATORS } from 'constants/queryBuilder';
import { memo, ReactNode, useCallback, useMemo } from 'react';
import { memo, MouseEvent, ReactNode, useMemo } from 'react';
function AddToQueryHOC({
fieldKey,
@@ -10,9 +10,10 @@ function AddToQueryHOC({
onAddToQuery,
children,
}: AddToQueryHOCProps): JSX.Element {
const handleQueryAdd = useCallback(() => {
const handleQueryAdd = (event: MouseEvent<HTMLDivElement>): void => {
event.stopPropagation();
onAddToQuery(fieldKey, fieldValue, OPERATORS.IN);
}, [fieldKey, fieldValue, onAddToQuery]);
};
const popOverContent = useMemo(() => <span>Add to query: {fieldKey}</span>, [
fieldKey,

View File

@@ -62,8 +62,6 @@ function RawLogView({
const isDarkMode = useIsDarkMode();
const isReadOnlyLog = !isLogsExplorerPage || isReadOnly;
const severityText = data.severity_text ? `${data.severity_text} |` : '';
const logType = getLogIndicatorType(data);
const updatedSelecedFields = useMemo(
@@ -88,17 +86,16 @@ function RawLogView({
attributesText += ' | ';
}
const text = useMemo(
() =>
const text = useMemo(() => {
const date =
typeof data.timestamp === 'string'
? `${dayjs(data.timestamp).format(
'YYYY-MM-DD HH:mm:ss.SSS',
)} | ${attributesText} ${severityText} ${data.body}`
: `${dayjs(data.timestamp / 1e6).format(
'YYYY-MM-DD HH:mm:ss.SSS',
)} | ${attributesText} ${severityText} ${data.body}`,
[data.timestamp, data.body, severityText, attributesText],
);
? dayjs(data.timestamp)
: dayjs(data.timestamp / 1e6);
return `${date.format('YYYY-MM-DD HH:mm:ss.SSS')} | ${attributesText} ${
data.body
}`;
}, [data.timestamp, data.body, attributesText]);
const handleClickExpand = useCallback(() => {
if (activeContextLog || isReadOnly) return;

View File

@@ -2,7 +2,9 @@
import './DynamicColumnTable.syles.scss';
import { Button, Dropdown, Flex, MenuProps, Switch } from 'antd';
import { ColumnGroupType, ColumnType } from 'antd/es/table';
import { ColumnsType } from 'antd/lib/table';
import logEvent from 'api/common/logEvent';
import FacingIssueBtn from 'components/facingIssueBtn/FacingIssueBtn';
import { SlidersHorizontal } from 'lucide-react';
import { memo, useEffect, useState } from 'react';
@@ -22,6 +24,7 @@ function DynamicColumnTable({
dynamicColumns,
onDragColumn,
facingIssueBtn,
shouldSendAlertsLogEvent,
...restProps
}: DynamicColumnTableProps): JSX.Element {
const [columnsData, setColumnsData] = useState<ColumnsType | undefined>(
@@ -47,11 +50,18 @@ function DynamicColumnTable({
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [columns, dynamicColumns]);
const onToggleHandler = (index: number) => (
checked: boolean,
event: React.MouseEvent<HTMLButtonElement>,
): void => {
const onToggleHandler = (
index: number,
column: ColumnGroupType<any> | ColumnType<any>,
) => (checked: boolean, event: React.MouseEvent<HTMLButtonElement>): void => {
event.stopPropagation();
if (shouldSendAlertsLogEvent) {
logEvent('Alert: Column toggled', {
column: column?.title,
action: checked ? 'Enable' : 'Disable',
});
}
setVisibleColumns({
tablesource,
dynamicColumns,
@@ -75,7 +85,7 @@ function DynamicColumnTable({
<div>{column.title?.toString()}</div>
<Switch
checked={columnsData?.findIndex((c) => c.key === column.key) !== -1}
onChange={onToggleHandler(index)}
onChange={onToggleHandler(index, column)}
/>
</div>
),

View File

@@ -3,6 +3,7 @@
import { Table } from 'antd';
import { ColumnsType } from 'antd/lib/table';
import { dragColumnParams } from 'hooks/useDragColumns/configs';
import { set } from 'lodash-es';
import {
SyntheticEvent,
useCallback,
@@ -20,6 +21,7 @@ import { ResizeTableProps } from './types';
function ResizeTable({
columns,
onDragColumn,
pagination,
...restProps
}: ResizeTableProps): JSX.Element {
const [columnsData, setColumns] = useState<ColumnsType>([]);
@@ -58,14 +60,21 @@ function ResizeTable({
[columnsData, onDragColumn, handleResize],
);
const tableParams = useMemo(
() => ({
const tableParams = useMemo(() => {
const props = {
...restProps,
components: { header: { cell: ResizableHeader } },
columns: mergedColumns,
}),
[mergedColumns, restProps],
);
};
set(
props,
'pagination',
pagination ? { ...pagination, hideOnSinglePage: true } : false,
);
return props;
}, [mergedColumns, pagination, restProps]);
useEffect(() => {
if (columns) {

View File

@@ -14,6 +14,7 @@ export interface DynamicColumnTableProps extends TableProps<any> {
dynamicColumns: TableProps<any>['columns'];
onDragColumn?: (fromIndex: number, toIndex: number) => void;
facingIssueBtn?: FacingIssueBtnProps;
shouldSendAlertsLogEvent?: boolean;
}
export type GetVisibleColumnsFunction = (

View File

@@ -9,7 +9,6 @@ import { Tooltip } from 'antd';
import { themeColors } from 'constants/theme';
import { useIsDarkMode } from 'hooks/useDarkMode';
import { useMemo } from 'react';
import { popupContainer } from 'utils/selectPopupContainer';
import { style } from './constant';
@@ -64,7 +63,7 @@ function TextToolTip({
);
return (
<Tooltip getTooltipContainer={popupContainer} overlay={overlay}>
<Tooltip overlay={overlay}>
{useFilledIcon ? (
<QuestionCircleFilled style={iconStyle} />
) : (

View File

@@ -13,6 +13,7 @@ const ROUTES = {
GET_STARTED_INFRASTRUCTURE_MONITORING:
'/get-started/infrastructure-monitoring',
GET_STARTED_AWS_MONITORING: '/get-started/aws-monitoring',
GET_STARTED_AZURE_MONITORING: '/get-started/azure-monitoring',
USAGE_EXPLORER: '/usage-explorer',
APPLICATION: '/services',
ALL_DASHBOARD: '/dashboard',

View File

@@ -1,13 +1,15 @@
import { PlusOutlined } from '@ant-design/icons';
import { Tooltip, Typography } from 'antd';
import getAll from 'api/channels/getAll';
import logEvent from 'api/common/logEvent';
import Spinner from 'components/Spinner';
import TextToolTip from 'components/TextToolTip';
import ROUTES from 'constants/routes';
import useComponentPermission from 'hooks/useComponentPermission';
import useFetch from 'hooks/useFetch';
import history from 'lib/history';
import { useCallback } from 'react';
import { isUndefined } from 'lodash-es';
import { useCallback, useEffect } from 'react';
import { useTranslation } from 'react-i18next';
import { useSelector } from 'react-redux';
import { AppState } from 'store/reducers';
@@ -31,6 +33,14 @@ function AlertChannels(): JSX.Element {
const { loading, payload, error, errorMessage } = useFetch(getAll);
useEffect(() => {
if (!isUndefined(payload)) {
logEvent('Alert Channel: Channel list page visited', {
number: payload?.length,
});
}
}, [payload]);
if (error) {
return <Typography>{errorMessage}</Typography>;
}

View File

@@ -6,7 +6,6 @@ import './AppLayout.styles.scss';
import * as Sentry from '@sentry/react';
import { Flex } from 'antd';
import getLocalStorageKey from 'api/browser/localstorage/get';
import getDynamicConfigs from 'api/dynamicConfigs/getDynamicConfigs';
import getUserLatestVersion from 'api/user/getLatestVersion';
import getUserVersion from 'api/user/getVersion';
import cx from 'classnames';
@@ -38,7 +37,6 @@ import { sideBarCollapse } from 'store/actions';
import { AppState } from 'store/reducers';
import AppActions from 'types/actions';
import {
UPDATE_CONFIGS,
UPDATE_CURRENT_ERROR,
UPDATE_CURRENT_VERSION,
UPDATE_LATEST_VERSION,
@@ -66,11 +64,7 @@ function AppLayout(props: AppLayoutProps): JSX.Element {
const { pathname } = useLocation();
const { t } = useTranslation(['titles']);
const [
getUserVersionResponse,
getUserLatestVersionResponse,
getDynamicConfigsResponse,
] = useQueries([
const [getUserVersionResponse, getUserLatestVersionResponse] = useQueries([
{
queryFn: getUserVersion,
queryKey: ['getUserVersion', user?.accessJwt],
@@ -81,10 +75,6 @@ function AppLayout(props: AppLayoutProps): JSX.Element {
queryKey: ['getUserLatestVersion', user?.accessJwt],
enabled: isLoggedIn,
},
{
queryFn: getDynamicConfigs,
queryKey: ['getDynamicConfigs', user?.accessJwt],
},
]);
useEffect(() => {
@@ -95,15 +85,7 @@ function AppLayout(props: AppLayoutProps): JSX.Element {
if (getUserVersionResponse.status === 'idle' && isLoggedIn) {
getUserVersionResponse.refetch();
}
if (getDynamicConfigsResponse.status === 'idle') {
getDynamicConfigsResponse.refetch();
}
}, [
getUserLatestVersionResponse,
getUserVersionResponse,
isLoggedIn,
getDynamicConfigsResponse,
]);
}, [getUserLatestVersionResponse, getUserVersionResponse, isLoggedIn]);
const { children } = props;
@@ -111,7 +93,6 @@ function AppLayout(props: AppLayoutProps): JSX.Element {
const latestCurrentCounter = useRef(0);
const latestVersionCounter = useRef(0);
const latestConfigCounter = useRef(0);
const { notifications } = useNotifications();
@@ -189,23 +170,6 @@ function AppLayout(props: AppLayoutProps): JSX.Element {
},
});
}
if (
getDynamicConfigsResponse.isFetched &&
getDynamicConfigsResponse.isSuccess &&
getDynamicConfigsResponse.data &&
getDynamicConfigsResponse.data.payload &&
latestConfigCounter.current === 0
) {
latestConfigCounter.current = 1;
dispatch({
type: UPDATE_CONFIGS,
payload: {
configs: getDynamicConfigsResponse.data.payload,
},
});
}
}, [
dispatch,
isLoggedIn,
@@ -220,9 +184,6 @@ function AppLayout(props: AppLayoutProps): JSX.Element {
getUserLatestVersionResponse.isFetched,
getUserVersionResponse.isFetched,
getUserLatestVersionResponse.isSuccess,
getDynamicConfigsResponse.data,
getDynamicConfigsResponse.isFetched,
getDynamicConfigsResponse.isSuccess,
notifications,
]);
@@ -236,7 +197,8 @@ function AppLayout(props: AppLayoutProps): JSX.Element {
pathname === ROUTES.GET_STARTED_APPLICATION_MONITORING ||
pathname === ROUTES.GET_STARTED_INFRASTRUCTURE_MONITORING ||
pathname === ROUTES.GET_STARTED_LOGS_MANAGEMENT ||
pathname === ROUTES.GET_STARTED_AWS_MONITORING;
pathname === ROUTES.GET_STARTED_AWS_MONITORING ||
pathname === ROUTES.GET_STARTED_AZURE_MONITORING;
const [showTrialExpiryBanner, setShowTrialExpiryBanner] = useState(false);

View File

@@ -11,11 +11,12 @@ import testOpsGenie from 'api/channels/testOpsgenie';
import testPagerApi from 'api/channels/testPager';
import testSlackApi from 'api/channels/testSlack';
import testWebhookApi from 'api/channels/testWebhook';
import logEvent from 'api/common/logEvent';
import ROUTES from 'constants/routes';
import FormAlertChannels from 'container/FormAlertChannels';
import { useNotifications } from 'hooks/useNotifications';
import history from 'lib/history';
import { useCallback, useState } from 'react';
import { useCallback, useEffect, useState } from 'react';
import { useTranslation } from 'react-i18next';
import {
@@ -43,6 +44,10 @@ function CreateAlertChannels({
const [formInstance] = Form.useForm();
useEffect(() => {
logEvent('Alert Channel: Create channel page visited', {});
}, []);
const [selectedConfig, setSelectedConfig] = useState<
Partial<
SlackChannel &
@@ -139,19 +144,25 @@ function CreateAlertChannels({
description: t('channel_creation_done'),
});
history.replace(ROUTES.ALL_CHANNELS);
} else {
notifications.error({
message: 'Error',
description: response.error || t('channel_creation_failed'),
});
return { status: 'success', statusMessage: t('channel_creation_done') };
}
notifications.error({
message: 'Error',
description: response.error || t('channel_creation_failed'),
});
return {
status: 'failed',
statusMessage: response.error || t('channel_creation_failed'),
};
} catch (error) {
notifications.error({
message: 'Error',
description: t('channel_creation_failed'),
});
return { status: 'failed', statusMessage: t('channel_creation_failed') };
} finally {
setSavingState(false);
}
setSavingState(false);
}, [prepareSlackRequest, t, notifications]);
const prepareWebhookRequest = useCallback(() => {
@@ -200,19 +211,25 @@ function CreateAlertChannels({
description: t('channel_creation_done'),
});
history.replace(ROUTES.ALL_CHANNELS);
} else {
notifications.error({
message: 'Error',
description: response.error || t('channel_creation_failed'),
});
return { status: 'success', statusMessage: t('channel_creation_done') };
}
notifications.error({
message: 'Error',
description: response.error || t('channel_creation_failed'),
});
return {
status: 'failed',
statusMessage: response.error || t('channel_creation_failed'),
};
} catch (error) {
notifications.error({
message: 'Error',
description: t('channel_creation_failed'),
});
return { status: 'failed', statusMessage: t('channel_creation_failed') };
} finally {
setSavingState(false);
}
setSavingState(false);
}, [prepareWebhookRequest, t, notifications]);
const preparePagerRequest = useCallback(() => {
@@ -245,8 +262,8 @@ function CreateAlertChannels({
setSavingState(true);
const request = preparePagerRequest();
if (request) {
try {
try {
if (request) {
const response = await createPagerApi(request);
if (response.statusCode === 200) {
@@ -255,20 +272,31 @@ function CreateAlertChannels({
description: t('channel_creation_done'),
});
history.replace(ROUTES.ALL_CHANNELS);
} else {
notifications.error({
message: 'Error',
description: response.error || t('channel_creation_failed'),
});
return { status: 'success', statusMessage: t('channel_creation_done') };
}
} catch (e) {
notifications.error({
message: 'Error',
description: t('channel_creation_failed'),
description: response.error || t('channel_creation_failed'),
});
return {
status: 'failed',
statusMessage: response.error || t('channel_creation_failed'),
};
}
notifications.error({
message: 'Error',
description: t('channel_creation_failed'),
});
return { status: 'failed', statusMessage: t('channel_creation_failed') };
} catch (error) {
notifications.error({
message: 'Error',
description: t('channel_creation_failed'),
});
return { status: 'failed', statusMessage: t('channel_creation_failed') };
} finally {
setSavingState(false);
}
setSavingState(false);
}, [t, notifications, preparePagerRequest]);
const prepareOpsgenieRequest = useCallback(
@@ -295,19 +323,25 @@ function CreateAlertChannels({
description: t('channel_creation_done'),
});
history.replace(ROUTES.ALL_CHANNELS);
} else {
notifications.error({
message: 'Error',
description: response.error || t('channel_creation_failed'),
});
return { status: 'success', statusMessage: t('channel_creation_done') };
}
notifications.error({
message: 'Error',
description: response.error || t('channel_creation_failed'),
});
return {
status: 'failed',
statusMessage: response.error || t('channel_creation_failed'),
};
} catch (error) {
notifications.error({
message: 'Error',
description: t('channel_creation_failed'),
});
return { status: 'failed', statusMessage: t('channel_creation_failed') };
} finally {
setSavingState(false);
}
setSavingState(false);
}, [prepareOpsgenieRequest, t, notifications]);
const prepareEmailRequest = useCallback(
@@ -332,19 +366,25 @@ function CreateAlertChannels({
description: t('channel_creation_done'),
});
history.replace(ROUTES.ALL_CHANNELS);
} else {
notifications.error({
message: 'Error',
description: response.error || t('channel_creation_failed'),
});
return { status: 'success', statusMessage: t('channel_creation_done') };
}
notifications.error({
message: 'Error',
description: response.error || t('channel_creation_failed'),
});
return {
status: 'failed',
statusMessage: response.error || t('channel_creation_failed'),
};
} catch (error) {
notifications.error({
message: 'Error',
description: t('channel_creation_failed'),
});
return { status: 'failed', statusMessage: t('channel_creation_failed') };
} finally {
setSavingState(false);
}
setSavingState(false);
}, [prepareEmailRequest, t, notifications]);
const prepareMsTeamsRequest = useCallback(
@@ -370,19 +410,25 @@ function CreateAlertChannels({
description: t('channel_creation_done'),
});
history.replace(ROUTES.ALL_CHANNELS);
} else {
notifications.error({
message: 'Error',
description: response.error || t('channel_creation_failed'),
});
return { status: 'success', statusMessage: t('channel_creation_done') };
}
notifications.error({
message: 'Error',
description: response.error || t('channel_creation_failed'),
});
return {
status: 'failed',
statusMessage: response.error || t('channel_creation_failed'),
};
} catch (error) {
notifications.error({
message: 'Error',
description: t('channel_creation_failed'),
});
return { status: 'failed', statusMessage: t('channel_creation_failed') };
} finally {
setSavingState(false);
}
setSavingState(false);
}, [prepareMsTeamsRequest, t, notifications]);
const onSaveHandler = useCallback(
@@ -400,7 +446,15 @@ function CreateAlertChannels({
const functionToCall = functionMapper[value as keyof typeof functionMapper];
if (functionToCall) {
functionToCall();
const result = await functionToCall();
logEvent('Alert Channel: Save channel', {
type: value,
sendResolvedAlert: selectedConfig.send_resolved,
name: selectedConfig.name,
new: 'true',
status: result?.status,
statusMessage: result?.statusMessage,
});
} else {
notifications.error({
message: 'Error',
@@ -409,6 +463,7 @@ function CreateAlertChannels({
}
}
},
// eslint-disable-next-line react-hooks/exhaustive-deps
[
onSlackHandler,
onWebhookHandler,
@@ -472,14 +527,25 @@ function CreateAlertChannels({
description: t('channel_test_failed'),
});
}
logEvent('Alert Channel: Test notification', {
type: channelType,
sendResolvedAlert: selectedConfig.send_resolved,
name: selectedConfig.name,
new: 'true',
status:
response && response.statusCode === 200 ? 'Test success' : 'Test failed',
});
} catch (error) {
notifications.error({
message: 'Error',
description: t('channel_test_unexpected'),
});
}
setTestingState(false);
},
// eslint-disable-next-line react-hooks/exhaustive-deps
[
prepareWebhookRequest,
t,

View File

@@ -1,4 +1,6 @@
import { Row, Typography } from 'antd';
import logEvent from 'api/common/logEvent';
import { ALERTS_DATA_SOURCE_MAP } from 'constants/alerts';
import { useMemo } from 'react';
import { useTranslation } from 'react-i18next';
import { AlertTypes } from 'types/api/alerts/alertTypes';
@@ -34,6 +36,13 @@ function SelectAlertType({ onSelect }: SelectAlertTypeProps): JSX.Element {
default:
break;
}
logEvent('Alert: Sample alert link clicked', {
dataSource: ALERTS_DATA_SOURCE_MAP[option],
link: url,
page: 'New alert data source selection page',
});
window.open(url, '_blank');
}
const renderOptions = useMemo(

View File

@@ -1,4 +1,5 @@
import { Form, Row } from 'antd';
import logEvent from 'api/common/logEvent';
import { ENTITY_VERSION_V4 } from 'constants/app';
import { QueryParams } from 'constants/query';
import FormAlertRules from 'container/FormAlertRules';
@@ -68,6 +69,8 @@ function CreateRules(): JSX.Element {
useEffect(() => {
if (alertType) {
onSelectType(alertType);
} else {
logEvent('Alert: New alert data source selection page visited', {});
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [alertType]);

View File

@@ -11,6 +11,7 @@ import testOpsgenie from 'api/channels/testOpsgenie';
import testPagerApi from 'api/channels/testPager';
import testSlackApi from 'api/channels/testSlack';
import testWebhookApi from 'api/channels/testWebhook';
import logEvent from 'api/common/logEvent';
import ROUTES from 'constants/routes';
import {
ChannelType,
@@ -89,7 +90,7 @@ function EditAlertChannels({
description: t('webhook_url_required'),
});
setSavingState(false);
return;
return { status: 'failed', statusMessage: t('webhook_url_required') };
}
const response = await editSlackApi(prepareSlackRequest());
@@ -101,13 +102,17 @@ function EditAlertChannels({
});
history.replace(ROUTES.ALL_CHANNELS);
} else {
notifications.error({
message: 'Error',
description: response.error || t('channel_edit_failed'),
});
return { status: 'success', statusMessage: t('channel_edit_done') };
}
notifications.error({
message: 'Error',
description: response.error || t('channel_edit_failed'),
});
setSavingState(false);
return {
status: 'failed',
statusMessage: response.error || t('channel_edit_failed'),
};
}, [prepareSlackRequest, t, notifications, selectedConfig]);
const prepareWebhookRequest = useCallback(() => {
@@ -136,13 +141,13 @@ function EditAlertChannels({
if (selectedConfig?.api_url === '') {
showError(t('webhook_url_required'));
setSavingState(false);
return;
return { status: 'failed', statusMessage: t('webhook_url_required') };
}
if (username && (!password || password === '')) {
showError(t('username_no_password'));
setSavingState(false);
return;
return { status: 'failed', statusMessage: t('username_no_password') };
}
const response = await editWebhookApi(prepareWebhookRequest());
@@ -154,10 +159,15 @@ function EditAlertChannels({
});
history.replace(ROUTES.ALL_CHANNELS);
} else {
showError(response.error || t('channel_edit_failed'));
return { status: 'success', statusMessage: t('channel_edit_done') };
}
showError(response.error || t('channel_edit_failed'));
setSavingState(false);
return {
status: 'failed',
statusMessage: response.error || t('channel_edit_failed'),
};
}, [prepareWebhookRequest, t, notifications, selectedConfig]);
const prepareEmailRequest = useCallback(
@@ -181,13 +191,18 @@ function EditAlertChannels({
description: t('channel_edit_done'),
});
history.replace(ROUTES.ALL_CHANNELS);
} else {
notifications.error({
message: 'Error',
description: response.error || t('channel_edit_failed'),
});
return { status: 'success', statusMessage: t('channel_edit_done') };
}
notifications.error({
message: 'Error',
description: response.error || t('channel_edit_failed'),
});
setSavingState(false);
return {
status: 'failed',
statusMessage: response.error || t('channel_edit_failed'),
};
}, [prepareEmailRequest, t, notifications]);
const preparePagerRequest = useCallback(
@@ -218,7 +233,7 @@ function EditAlertChannels({
description: validationError,
});
setSavingState(false);
return;
return { status: 'failed', statusMessage: validationError };
}
const response = await editPagerApi(preparePagerRequest());
@@ -229,13 +244,18 @@ function EditAlertChannels({
});
history.replace(ROUTES.ALL_CHANNELS);
} else {
notifications.error({
message: 'Error',
description: response.error || t('channel_edit_failed'),
});
return { status: 'success', statusMessage: t('channel_edit_done') };
}
notifications.error({
message: 'Error',
description: response.error || t('channel_edit_failed'),
});
setSavingState(false);
return {
status: 'failed',
statusMessage: response.error || t('channel_edit_failed'),
};
}, [preparePagerRequest, notifications, selectedConfig, t]);
const prepareOpsgenieRequest = useCallback(
@@ -259,7 +279,7 @@ function EditAlertChannels({
description: t('api_key_required'),
});
setSavingState(false);
return;
return { status: 'failed', statusMessage: t('api_key_required') };
}
const response = await editOpsgenie(prepareOpsgenieRequest());
@@ -271,13 +291,18 @@ function EditAlertChannels({
});
history.replace(ROUTES.ALL_CHANNELS);
} else {
notifications.error({
message: 'Error',
description: response.error || t('channel_edit_failed'),
});
return { status: 'success', statusMessage: t('channel_edit_done') };
}
notifications.error({
message: 'Error',
description: response.error || t('channel_edit_failed'),
});
setSavingState(false);
return {
status: 'failed',
statusMessage: response.error || t('channel_edit_failed'),
};
}, [prepareOpsgenieRequest, t, notifications, selectedConfig]);
const prepareMsTeamsRequest = useCallback(
@@ -301,7 +326,7 @@ function EditAlertChannels({
description: t('webhook_url_required'),
});
setSavingState(false);
return;
return { status: 'failed', statusMessage: t('webhook_url_required') };
}
const response = await editMsTeamsApi(prepareMsTeamsRequest());
@@ -313,31 +338,46 @@ function EditAlertChannels({
});
history.replace(ROUTES.ALL_CHANNELS);
} else {
notifications.error({
message: 'Error',
description: response.error || t('channel_edit_failed'),
});
return { status: 'success', statusMessage: t('channel_edit_done') };
}
notifications.error({
message: 'Error',
description: response.error || t('channel_edit_failed'),
});
setSavingState(false);
return {
status: 'failed',
statusMessage: response.error || t('channel_edit_failed'),
};
}, [prepareMsTeamsRequest, t, notifications, selectedConfig]);
const onSaveHandler = useCallback(
(value: ChannelType) => {
async (value: ChannelType) => {
let result;
if (value === ChannelType.Slack) {
onSlackEditHandler();
result = await onSlackEditHandler();
} else if (value === ChannelType.Webhook) {
onWebhookEditHandler();
result = await onWebhookEditHandler();
} else if (value === ChannelType.Pagerduty) {
onPagerEditHandler();
result = await onPagerEditHandler();
} else if (value === ChannelType.MsTeams) {
onMsTeamsEditHandler();
result = await onMsTeamsEditHandler();
} else if (value === ChannelType.Opsgenie) {
onOpsgenieEditHandler();
result = await onOpsgenieEditHandler();
} else if (value === ChannelType.Email) {
onEmailEditHandler();
result = await onEmailEditHandler();
}
logEvent('Alert Channel: Save channel', {
type: value,
sendResolvedAlert: selectedConfig.send_resolved,
name: selectedConfig.name,
new: 'false',
status: result?.status,
statusMessage: result?.statusMessage,
});
},
// eslint-disable-next-line react-hooks/exhaustive-deps
[
onSlackEditHandler,
onWebhookEditHandler,
@@ -399,6 +439,14 @@ function EditAlertChannels({
description: t('channel_test_failed'),
});
}
logEvent('Alert Channel: Test notification', {
type: channelType,
sendResolvedAlert: selectedConfig.send_resolved,
name: selectedConfig.name,
new: 'false',
status:
response && response.statusCode === 200 ? 'Test success' : 'Test failed',
});
} catch (error) {
notifications.error({
message: 'Error',
@@ -407,6 +455,7 @@ function EditAlertChannels({
}
setTestingState(false);
},
// eslint-disable-next-line react-hooks/exhaustive-deps
[
t,
prepareWebhookRequest,

View File

@@ -3,6 +3,8 @@ import './FormAlertRules.styles.scss';
import { PlusOutlined } from '@ant-design/icons';
import { Button, Form, Select, Switch, Tooltip } from 'antd';
import getChannels from 'api/channels/getAll';
import logEvent from 'api/common/logEvent';
import { ALERTS_DATA_SOURCE_MAP } from 'constants/alerts';
import ROUTES from 'constants/routes';
import useComponentPermission from 'hooks/useComponentPermission';
import useFetch from 'hooks/useFetch';
@@ -10,6 +12,7 @@ import { useCallback, useEffect, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { useSelector } from 'react-redux';
import { AppState } from 'store/reducers';
import { AlertTypes } from 'types/api/alerts/alertTypes';
import { AlertDef, Labels } from 'types/api/alerts/def';
import AppReducer from 'types/reducer/app';
import { requireErrorMessage } from 'utils/form/requireErrorMessage';
@@ -73,9 +76,24 @@ function BasicInfo({
const noChannels = channels.payload?.length === 0;
const handleCreateNewChannels = useCallback(() => {
logEvent('Alert: Create notification channel button clicked', {
dataSource: ALERTS_DATA_SOURCE_MAP[alertDef?.alertType as AlertTypes],
ruleId: isNewRule ? 0 : alertDef?.id,
});
window.open(ROUTES.CHANNELS_NEW, '_blank');
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
useEffect(() => {
if (!channels.loading && isNewRule) {
logEvent('Alert: New alert creation page visited', {
dataSource: ALERTS_DATA_SOURCE_MAP[alertDef?.alertType as AlertTypes],
numberOfChannels: channels.payload?.length,
});
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [channels.payload, channels.loading]);
return (
<>
<StepHeading> {t('alert_form_step3')} </StepHeading>

View File

@@ -2,6 +2,7 @@ import './QuerySection.styles.scss';
import { Color } from '@signozhq/design-tokens';
import { Button, Tabs, Tooltip } from 'antd';
import logEvent from 'api/common/logEvent';
import PromQLIcon from 'assets/Dashboard/PromQl';
import { ALERTS_DATA_SOURCE_MAP } from 'constants/alerts';
import { ENTITY_VERSION_V4 } from 'constants/app';
@@ -31,6 +32,7 @@ function QuerySection({
runQuery,
alertDef,
panelType,
ruleId,
}: QuerySectionProps): JSX.Element {
// init namespace for translations
const { t } = useTranslation('alerts');
@@ -158,7 +160,15 @@ function QuerySection({
<span style={{ display: 'flex', gap: '1rem', alignItems: 'center' }}>
<Button
type="primary"
onClick={runQuery}
onClick={(): void => {
runQuery();
logEvent('Alert: Stage and run query', {
dataSource: ALERTS_DATA_SOURCE_MAP[alertType],
isNewRule: !ruleId || ruleId === 0,
ruleId,
queryType: queryCategory,
});
}}
className="stage-run-query"
icon={<Play size={14} />}
>
@@ -228,6 +238,7 @@ interface QuerySectionProps {
runQuery: VoidFunction;
alertDef: AlertDef;
panelType: PANEL_TYPES;
ruleId: number;
}
export default QuerySection;

View File

@@ -12,8 +12,10 @@ import {
} from 'antd';
import saveAlertApi from 'api/alerts/save';
import testAlertApi from 'api/alerts/testAlert';
import logEvent from 'api/common/logEvent';
import FacingIssueBtn from 'components/facingIssueBtn/FacingIssueBtn';
import { alertHelpMessage } from 'components/facingIssueBtn/util';
import { ALERTS_DATA_SOURCE_MAP } from 'constants/alerts';
import { FeatureKeys } from 'constants/features';
import { QueryParams } from 'constants/query';
import { PANEL_TYPES } from 'constants/queryBuilder';
@@ -338,8 +340,13 @@ function FormAlertRules({
return;
}
const postableAlert = memoizedPreparePostData();
setLoading(true);
let logData = {
status: 'error',
statusMessage: t('unexpected_error'),
};
try {
const apiReq =
ruleId && ruleId > 0
@@ -349,10 +356,15 @@ function FormAlertRules({
const response = await saveAlertApi(apiReq);
if (response.statusCode === 200) {
logData = {
status: 'success',
statusMessage:
!ruleId || ruleId === 0 ? t('rule_created') : t('rule_edited'),
};
notifications.success({
message: 'Success',
description:
!ruleId || ruleId === 0 ? t('rule_created') : t('rule_edited'),
description: logData.statusMessage,
});
// invalidate rule in cache
@@ -367,18 +379,42 @@ function FormAlertRules({
history.replace(`${ROUTES.LIST_ALL_ALERT}?${urlQuery.toString()}`);
}, 2000);
} else {
logData = {
status: 'error',
statusMessage: response.error || t('unexpected_error'),
};
notifications.error({
message: 'Error',
description: response.error || t('unexpected_error'),
description: logData.statusMessage,
});
}
} catch (e) {
logData = {
status: 'error',
statusMessage: t('unexpected_error'),
};
notifications.error({
message: 'Error',
description: t('unexpected_error'),
description: logData.statusMessage,
});
}
setLoading(false);
logEvent('Alert: Save alert', {
...logData,
dataSource: ALERTS_DATA_SOURCE_MAP[postableAlert?.alertType as AlertTypes],
channelNames: postableAlert?.preferredChannels,
broadcastToAll: postableAlert?.broadcastToAll,
isNewRule: !ruleId || ruleId === 0,
ruleId,
queryType: currentQuery.queryType,
alertId: postableAlert?.id,
alertName: postableAlert?.alert,
});
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [
isFormValid,
memoizedPreparePostData,
@@ -414,6 +450,7 @@ function FormAlertRules({
}
const postableAlert = memoizedPreparePostData();
let statusResponse = { status: 'failed', message: '' };
setLoading(true);
try {
const response = await testAlertApi({ data: postableAlert });
@@ -425,25 +462,43 @@ function FormAlertRules({
message: 'Error',
description: t('no_alerts_found'),
});
statusResponse = { status: 'failed', message: t('no_alerts_found') };
} else {
notifications.success({
message: 'Success',
description: t('rule_test_fired'),
});
statusResponse = { status: 'success', message: t('rule_test_fired') };
}
} else {
notifications.error({
message: 'Error',
description: response.error || t('unexpected_error'),
});
statusResponse = {
status: 'failed',
message: response.error || t('unexpected_error'),
};
}
} catch (e) {
notifications.error({
message: 'Error',
description: t('unexpected_error'),
});
statusResponse = { status: 'failed', message: t('unexpected_error') };
}
setLoading(false);
logEvent('Alert: Test notification', {
dataSource: ALERTS_DATA_SOURCE_MAP[alertDef?.alertType as AlertTypes],
channelNames: postableAlert?.preferredChannels,
broadcastToAll: postableAlert?.broadcastToAll,
isNewRule: !ruleId || ruleId === 0,
ruleId,
queryType: currentQuery.queryType,
status: statusResponse.status,
statusMessage: statusResponse.message,
});
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [t, isFormValid, memoizedPreparePostData, notifications]);
const renderBasicInfo = (): JSX.Element => (
@@ -513,6 +568,16 @@ function FormAlertRules({
const isRuleCreated = !ruleId || ruleId === 0;
useEffect(() => {
if (!isRuleCreated) {
logEvent('Alert: Edit page visited', {
ruleId,
dataSource: ALERTS_DATA_SOURCE_MAP[alertType as AlertTypes],
});
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
function handleRedirection(option: AlertTypes): void {
let url = '';
switch (option) {
@@ -535,6 +600,13 @@ function FormAlertRules({
default:
break;
}
logEvent('Alert: Check example alert clicked', {
dataSource: ALERTS_DATA_SOURCE_MAP[alertDef?.alertType as AlertTypes],
isNewRule: !ruleId || ruleId === 0,
ruleId,
queryType: currentQuery.queryType,
link: url,
});
window.open(url, '_blank');
}
@@ -572,6 +644,7 @@ function FormAlertRules({
alertDef={alertDef}
panelType={panelType || PANEL_TYPES.TIME_SERIES}
key={currentQuery.queryType}
ruleId={ruleId}
/>
<RuleOptions

View File

@@ -80,6 +80,8 @@ function FullView({
query: updatedQuery,
globalSelectedInterval: globalSelectedTime,
variables: getDashboardVariables(selectedDashboard?.data.variables),
fillGaps: widget.fillSpans,
formatForWeb: widget.panelTypes === PANEL_TYPES.TABLE,
};
}
updatedQuery.builder.queryData[0].pageSize = 10;

View File

@@ -109,6 +109,7 @@ function GridCardGraph({
globalSelectedInterval,
variables: getDashboardVariables(variables),
fillGaps: widget.fillSpans,
formatForWeb: widget.panelTypes === PANEL_TYPES.TABLE,
};
}
updatedQuery.builder.queryData[0].pageSize = 10;

View File

@@ -0,0 +1,215 @@
export const tableDataMultipleQueriesSuccessResponse = {
columns: [
{
name: 'service_name',
queryName: '',
isValueColumn: false,
},
{
name: 'A',
queryName: 'A',
isValueColumn: true,
},
{
name: 'B',
queryName: 'B',
isValueColumn: true,
},
],
rows: [
{
data: {
A: 4196.71,
B: 'n/a',
service_name: 'demo-app',
},
},
{
data: {
A: 500.83,
B: 'n/a',
service_name: 'customer',
},
},
{
data: {
A: 499.5,
B: 'n/a',
service_name: 'mysql',
},
},
{
data: {
A: 293.22,
B: 'n/a',
service_name: 'frontend',
},
},
{
data: {
A: 230.03,
B: 'n/a',
service_name: 'driver',
},
},
{
data: {
A: 67.09,
B: 'n/a',
service_name: 'route',
},
},
{
data: {
A: 30.96,
B: 'n/a',
service_name: 'redis',
},
},
{
data: {
A: 'n/a',
B: 112.27,
service_name: 'n/a',
},
},
],
};
export const widgetQueryWithLegend = {
clickhouse_sql: [
{
name: 'A',
legend: '',
disabled: false,
query: '',
},
],
promql: [
{
name: 'A',
query: '',
legend: '',
disabled: false,
},
],
builder: {
queryData: [
{
dataSource: 'metrics',
queryName: 'A',
aggregateOperator: 'count',
aggregateAttribute: {
dataType: 'float64',
id: 'signoz_latency--float64--ExponentialHistogram--true',
isColumn: true,
isJSON: false,
key: 'signoz_latency',
type: 'ExponentialHistogram',
},
timeAggregation: '',
spaceAggregation: 'p90',
functions: [],
filters: {
items: [],
op: 'AND',
},
expression: 'A',
disabled: false,
stepInterval: 60,
having: [],
limit: null,
orderBy: [],
groupBy: [
{
dataType: 'string',
isColumn: false,
isJSON: false,
key: 'service_name',
type: 'tag',
id: 'service_name--string--tag--false',
},
],
legend: 'p99',
reduceTo: 'avg',
},
{
dataSource: 'metrics',
queryName: 'B',
aggregateOperator: 'rate',
aggregateAttribute: {
dataType: 'float64',
id: 'system_disk_operations--float64--Sum--true',
isColumn: true,
isJSON: false,
key: 'system_disk_operations',
type: 'Sum',
},
timeAggregation: 'rate',
spaceAggregation: 'sum',
functions: [],
filters: {
items: [],
op: 'AND',
},
expression: 'B',
disabled: false,
stepInterval: 60,
having: [],
limit: null,
orderBy: [],
groupBy: [],
legend: '',
reduceTo: 'avg',
},
],
queryFormulas: [],
},
id: '48ad5a67-9a3c-49d4-a886-d7a34f8b875d',
queryType: 'builder',
};
export const expectedOutputWithLegends = {
dataSource: [
{
A: 4196.71,
B: 'n/a',
service_name: 'demo-app',
},
{
A: 500.83,
B: 'n/a',
service_name: 'customer',
},
{
A: 499.5,
B: 'n/a',
service_name: 'mysql',
},
{
A: 293.22,
B: 'n/a',
service_name: 'frontend',
},
{
A: 230.03,
B: 'n/a',
service_name: 'driver',
},
{
A: 67.09,
B: 'n/a',
service_name: 'route',
},
{
A: 30.96,
B: 'n/a',
service_name: 'redis',
},
{
A: 'n/a',
B: 112.27,
service_name: 'n/a',
},
],
};

View File

@@ -0,0 +1,42 @@
import { Query } from 'types/api/queryBuilder/queryBuilderData';
import { createColumnsAndDataSource, getQueryLegend } from '../utils';
import {
expectedOutputWithLegends,
tableDataMultipleQueriesSuccessResponse,
widgetQueryWithLegend,
} from './response';
describe('Table Panel utils', () => {
it('createColumnsAndDataSource function', () => {
const data = tableDataMultipleQueriesSuccessResponse;
const query = widgetQueryWithLegend as Query;
const { columns, dataSource } = createColumnsAndDataSource(data, query);
expect(dataSource).toStrictEqual(expectedOutputWithLegends.dataSource);
// this makes sure that the columns are rendered in the same order as response
expect(columns[0].title).toBe('service_name');
// the next specifically makes sure that the legends are properly applied in multiple queries
expect(columns[1].title).toBe('p99');
// this makes sure that the query without a legend takes the title from the query response
expect(columns[2].title).toBe('B');
// this is to ensure that the rows properly map to the column data indexes as the dataIndex should be equal to name of the columns
// returned in the response as the rows will be mapped with them
expect((columns[0] as any).dataIndex).toBe('service_name');
expect((columns[1] as any).dataIndex).toBe('A');
expect((columns[2] as any).dataIndex).toBe('B');
});
it('getQueryLegend function', () => {
const query = widgetQueryWithLegend as Query;
// query A has a legend of p99
expect(getQueryLegend(query, 'A')).toBe('p99');
// should return undefined when legend not present
expect(getQueryLegend(query, 'B')).toBe(undefined);
});
});

View File

@@ -3,10 +3,7 @@ import { Space, Tooltip } from 'antd';
import { getYAxisFormattedValue } from 'components/Graph/yAxisConfig';
import { Events } from 'constants/events';
import { QueryTable } from 'container/QueryTable';
import {
createTableColumnsFromQuery,
RowData,
} from 'lib/query/createTableColumnsFromQuery';
import { RowData } from 'lib/query/createTableColumnsFromQuery';
import { cloneDeep, get, isEmpty, set } from 'lodash-es';
import { memo, ReactNode, useCallback, useEffect, useMemo } from 'react';
import { useTranslation } from 'react-i18next';
@@ -14,7 +11,11 @@ import { eventEmitter } from 'utils/getEventEmitter';
import { WrapperStyled } from './styles';
import { GridTableComponentProps } from './types';
import { findMatchingThreshold } from './utils';
import {
createColumnsAndDataSource,
findMatchingThreshold,
TableData,
} from './utils';
function GridTableComponent({
data,
@@ -25,28 +26,26 @@ function GridTableComponent({
...props
}: GridTableComponentProps): JSX.Element {
const { t } = useTranslation(['valueGraph']);
// create columns and dataSource in the ui friendly structure
// use the query from the widget here to extract the legend information
const { columns, dataSource: originalDataSource } = useMemo(
() =>
createTableColumnsFromQuery({
query,
queryTableData: data,
}),
[data, query],
() => createColumnsAndDataSource((data as unknown) as TableData, query),
[query, data],
);
const createDataInCorrectFormat = useCallback(
(dataSource: RowData[]): RowData[] =>
dataSource.map((d) => {
const finalObject = {};
const keys = Object.keys(d);
keys.forEach((k) => {
const label = get(
columns.find((c) => get(c, 'dataIndex', '') === k) || {},
'title',
'',
// we use the order of the columns here to have similar download as the user view
columns.forEach((k) => {
set(
finalObject,
get(k, 'title', '') as string,
get(d, get(k, 'dataIndex', ''), 'n/a'),
);
if (label) {
set(finalObject, label as string, d[k]);
}
});
return finalObject as RowData;
}),
@@ -65,7 +64,11 @@ function GridTableComponent({
const newValue = { ...val };
Object.keys(val).forEach((k) => {
if (columnUnits[k]) {
newValue[k] = getYAxisFormattedValue(String(val[k]), columnUnits[k]);
// the check below takes care of not adding units for rows that have n/a values
newValue[k] =
val[k] !== 'n/a'
? getYAxisFormattedValue(String(val[k]), columnUnits[k])
: val[k];
newValue[`${k}_without_unit`] = val[k];
}
});

View File

@@ -1,4 +1,11 @@
import { ColumnsType, ColumnType } from 'antd/es/table';
import { ThresholdProps } from 'container/NewWidget/RightContainer/Threshold/types';
import { QUERY_TABLE_CONFIG } from 'container/QueryTable/config';
import { QueryTableProps } from 'container/QueryTable/QueryTable.intefaces';
import { RowData } from 'lib/query/createTableColumnsFromQuery';
import { isEmpty, isNaN } from 'lodash-es';
import { Query } from 'types/api/queryBuilder/queryBuilderData';
import { EQueryType } from 'types/common/dashboard';
// Helper function to evaluate the condition based on the operator
function evaluateCondition(
@@ -56,3 +63,85 @@ export function findMatchingThreshold(
hasMultipleMatches,
};
}
export interface TableData {
columns: { name: string; queryName: string; isValueColumn: boolean }[];
rows: { data: any }[];
}
export function getQueryLegend(
currentQuery: Query,
queryName: string,
): string | undefined {
let legend: string | undefined;
switch (currentQuery.queryType) {
case EQueryType.QUERY_BUILDER:
// check if the value is present in the queries
legend = currentQuery.builder.queryData.find(
(query) => query.queryName === queryName,
)?.legend;
if (!legend) {
// check if the value is present in the formula
legend = currentQuery.builder.queryFormulas.find(
(query) => query.queryName === queryName,
)?.legend;
}
break;
case EQueryType.CLICKHOUSE:
legend = currentQuery.clickhouse_sql.find(
(query) => query.name === queryName,
)?.legend;
break;
case EQueryType.PROM:
legend = currentQuery.promql.find((query) => query.name === queryName)
?.legend;
break;
default:
legend = undefined;
break;
}
return legend;
}
export function createColumnsAndDataSource(
data: TableData,
currentQuery: Query,
renderColumnCell?: QueryTableProps['renderColumnCell'],
): { columns: ColumnsType<RowData>; dataSource: RowData[] } {
const columns: ColumnsType<RowData> =
data.columns?.reduce<ColumnsType<RowData>>((acc, item) => {
// is the column is the value column then we need to check for the available legend
const legend = item.isValueColumn
? getQueryLegend(currentQuery, item.queryName)
: undefined;
const column: ColumnType<RowData> = {
dataIndex: item.name,
// if no legend present then rely on the column name value
title: !isEmpty(legend) ? legend : item.name,
width: QUERY_TABLE_CONFIG.width,
render: renderColumnCell && renderColumnCell[item.name],
sorter: (a: RowData, b: RowData): number => {
const valueA = Number(a[`${item.name}_without_unit`] ?? a[item.name]);
const valueB = Number(b[`${item.name}_without_unit`] ?? b[item.name]);
if (!isNaN(valueA) && !isNaN(valueB)) {
return valueA - valueB;
}
return ((a[item.name] as string) || '').localeCompare(
(b[item.name] as string) || '',
);
},
};
return [...acc, column];
}, []) || [];
// the rows returned have data encapsulation hence removing the same here
const dataSource = data.rows?.map((d) => d.data) || [];
return { columns, dataSource };
}

View File

@@ -27,6 +27,7 @@ import {
import { useSelector } from 'react-redux';
import { NavLink } from 'react-router-dom';
import { AppState } from 'store/reducers';
import { License } from 'types/api/licenses/def';
import AppReducer from 'types/reducer/app';
import { getFormattedDate, getRemainingDays } from 'utils/timeUtils';
@@ -109,9 +110,13 @@ function HeaderContainer(): JSX.Element {
const { data: licenseData, isFetching, status: licenseStatus } = useLicense();
const licensesStatus: string =
licenseData?.payload?.licenses?.find((e: License) => e.isCurrent)?.status ||
'';
const isLicenseActive =
licenseData?.payload?.licenses?.find((e) => e.isCurrent)?.status ===
LICENSE_PLAN_STATUS.VALID;
licensesStatus?.toLocaleLowerCase() ===
LICENSE_PLAN_STATUS.VALID.toLocaleLowerCase();
useEffect(() => {
if (

View File

@@ -7,17 +7,20 @@ interface AlertInfoCardProps {
header: string;
subheader: string;
link: string;
onClick: () => void;
}
function AlertInfoCard({
header,
subheader,
link,
onClick,
}: AlertInfoCardProps): JSX.Element {
return (
<div
className="alert-info-card"
onClick={(): void => {
onClick();
window.open(link, '_blank');
}}
>

View File

@@ -2,6 +2,7 @@ import './AlertsEmptyState.styles.scss';
import { PlusOutlined } from '@ant-design/icons';
import { Button, Divider, Typography } from 'antd';
import logEvent from 'api/common/logEvent';
import ROUTES from 'constants/routes';
import useComponentPermission from 'hooks/useComponentPermission';
import { useNotifications } from 'hooks/useNotifications';
@@ -10,12 +11,26 @@ import { useCallback, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { useSelector } from 'react-redux';
import { AppState } from 'store/reducers';
import { DataSource } from 'types/common/queryBuilder';
import AppReducer from 'types/reducer/app';
import AlertInfoCard from './AlertInfoCard';
import { ALERT_CARDS, ALERT_INFO_LINKS } from './alertLinks';
import InfoLinkText from './InfoLinkText';
const alertLogEvents = (
title: string,
link: string,
dataSource?: DataSource,
): void => {
const attributes = {
link,
page: 'Alert empty state page',
};
logEvent(title, dataSource ? { ...attributes, dataSource } : attributes);
};
export function AlertsEmptyState(): JSX.Element {
const { t } = useTranslation('common');
const { role, featureResponse } = useSelector<AppState, AppReducer>(
@@ -91,18 +106,33 @@ export function AlertsEmptyState(): JSX.Element {
link="https://youtu.be/xjxNIqiv4_M"
leftIconVisible
rightIconVisible
onClick={(): void =>
alertLogEvents(
'Alert: Video tutorial link clicked',
'https://youtu.be/xjxNIqiv4_M',
)
}
/>
</div>
{ALERT_INFO_LINKS.map((info) => (
<InfoLinkText
key={info.link}
infoText={info.infoText}
link={info.link}
leftIconVisible={info.leftIconVisible}
rightIconVisible={info.rightIconVisible}
/>
))}
{ALERT_INFO_LINKS.map((info) => {
const logEventTriggered = (): void =>
alertLogEvents(
'Alert: Tutorial doc link clicked',
info.link,
info.dataSource,
);
return (
<InfoLinkText
key={info.link}
infoText={info.infoText}
link={info.link}
leftIconVisible={info.leftIconVisible}
rightIconVisible={info.rightIconVisible}
onClick={logEventTriggered}
/>
);
})}
</div>
</section>
<div className="get-started-text">
@@ -113,14 +143,23 @@ export function AlertsEmptyState(): JSX.Element {
</Divider>
</div>
{ALERT_CARDS.map((card) => (
<AlertInfoCard
key={card.link}
header={card.header}
subheader={card.subheader}
link={card.link}
/>
))}
{ALERT_CARDS.map((card) => {
const logEventTriggered = (): void =>
alertLogEvents(
'Alert: Sample alert link clicked',
card.link,
card.dataSource,
);
return (
<AlertInfoCard
key={card.link}
header={card.header}
subheader={card.subheader}
link={card.link}
onClick={logEventTriggered}
/>
);
})}
</div>
</div>
);

View File

@@ -6,6 +6,7 @@ interface InfoLinkTextProps {
link: string;
leftIconVisible: boolean;
rightIconVisible: boolean;
onClick: () => void;
}
function InfoLinkText({
@@ -13,10 +14,12 @@ function InfoLinkText({
link,
leftIconVisible,
rightIconVisible,
onClick,
}: InfoLinkTextProps): JSX.Element {
return (
<Flex
onClick={(): void => {
onClick();
window.open(link, '_blank');
}}
className="info-link-container"

View File

@@ -1,3 +1,5 @@
import { DataSource } from 'types/common/queryBuilder';
export const ALERT_INFO_LINKS = [
{
infoText: 'How to create Metrics-based alerts',
@@ -5,6 +7,7 @@ export const ALERT_INFO_LINKS = [
'https://signoz.io/docs/alerts-management/metrics-based-alerts/?utm_source=product&utm_medium=alert-empty-page',
leftIconVisible: false,
rightIconVisible: true,
dataSource: DataSource.METRICS,
},
{
infoText: 'How to create Log-based alerts',
@@ -12,6 +15,7 @@ export const ALERT_INFO_LINKS = [
'https://signoz.io/docs/alerts-management/log-based-alerts/?utm_source=product&utm_medium=alert-empty-page',
leftIconVisible: false,
rightIconVisible: true,
dataSource: DataSource.LOGS,
},
{
infoText: 'How to create Trace-based alerts',
@@ -19,6 +23,7 @@ export const ALERT_INFO_LINKS = [
'https://signoz.io/docs/alerts-management/trace-based-alerts/?utm_source=product&utm_medium=alert-empty-page',
leftIconVisible: false,
rightIconVisible: true,
dataSource: DataSource.TRACES,
},
];
@@ -26,24 +31,28 @@ export const ALERT_CARDS = [
{
header: 'Alert on high memory usage',
subheader: "Monitor your host's memory usage",
dataSource: DataSource.METRICS,
link:
'https://signoz.io/docs/alerts-management/metrics-based-alerts/?utm_source=product&utm_medium=alert-empty-page#1-alert-when-memory-usage-for-host-goes-above-400-mb-or-any-fixed-memory',
},
{
header: 'Alert on slow external API calls',
subheader: 'Monitor your external API calls',
dataSource: DataSource.TRACES,
link:
'https://signoz.io/docs/alerts-management/trace-based-alerts/?utm_source=product&utm_medium=alert-empty-page#1-alert-when-external-api-latency-p90-is-over-1-second-for-last-5-mins',
},
{
header: 'Alert on high percentage of timeout errors in logs',
subheader: 'Monitor your logs for errors',
dataSource: DataSource.LOGS,
link:
'https://signoz.io/docs/alerts-management/log-based-alerts/?utm_source=product&utm_medium=alert-empty-page#1-alert-when-percentage-of-redis-timeout-error-logs-greater-than-7-in-last-5-mins',
},
{
header: 'Alert on high error percentage of an endpoint',
subheader: 'Monitor your API endpoint',
dataSource: DataSource.METRICS,
link:
'https://signoz.io/docs/alerts-management/metrics-based-alerts/?utm_source=product&utm_medium=alert-empty-page#3-alert-when-the-error-percentage-for-an-endpoint-exceeds-5',
},

View File

@@ -3,6 +3,7 @@ import { PlusOutlined } from '@ant-design/icons';
import { Input, Typography } from 'antd';
import type { ColumnsType } from 'antd/es/table/interface';
import saveAlertApi from 'api/alerts/save';
import logEvent from 'api/common/logEvent';
import DropDown from 'components/DropDown/DropDown';
import { listAlertMessage } from 'components/facingIssueBtn/util';
import {
@@ -41,7 +42,7 @@ import {
} from './styles';
import Status from './TableComponents/Status';
import ToggleAlertState from './ToggleAlertState';
import { filterAlerts } from './utils';
import { alertActionLogEvent, filterAlerts } from './utils';
const { Search } = Input;
@@ -107,12 +108,16 @@ function ListAlert({ allAlertRules, refetch }: ListAlertProps): JSX.Element {
}, [notificationsApi, t]);
const onClickNewAlertHandler = useCallback(() => {
logEvent('Alert: New alert button clicked', {
number: allAlertRules?.length,
});
featureResponse
.refetch()
.then(() => {
history.push(ROUTES.ALERTS_NEW);
})
.catch(handleError);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [featureResponse, handleError]);
const onEditHandler = (record: GettableAlert) => (): void => {
@@ -321,6 +326,7 @@ function ListAlert({ allAlertRules, refetch }: ListAlertProps): JSX.Element {
width: 10,
render: (id: GettableAlert['id'], record): JSX.Element => (
<DropDown
onDropDownItemClick={(item): void => alertActionLogEvent(item.key, record)}
element={[
<ToggleAlertState
key="1"
@@ -356,6 +362,9 @@ function ListAlert({ allAlertRules, refetch }: ListAlertProps): JSX.Element {
});
}
const paginationConfig = {
defaultCurrent: Number(paginationParam) || 1,
};
return (
<>
<SearchContainer>
@@ -385,11 +394,10 @@ function ListAlert({ allAlertRules, refetch }: ListAlertProps): JSX.Element {
columns={columns}
rowKey="id"
dataSource={data}
shouldSendAlertsLogEvent
dynamicColumns={dynamicColumns}
onChange={handleChange}
pagination={{
defaultCurrent: Number(paginationParam) || 1,
}}
pagination={paginationConfig}
facingIssueBtn={{
attributes: {
screen: 'Alert list page',

View File

@@ -1,9 +1,11 @@
import { Space } from 'antd';
import getAll from 'api/alerts/getAll';
import logEvent from 'api/common/logEvent';
import ReleaseNote from 'components/ReleaseNote';
import Spinner from 'components/Spinner';
import { useNotifications } from 'hooks/useNotifications';
import { useEffect } from 'react';
import { isUndefined } from 'lodash-es';
import { useEffect, useRef } from 'react';
import { useTranslation } from 'react-i18next';
import { useQuery } from 'react-query';
import { useLocation } from 'react-router-dom';
@@ -19,8 +21,19 @@ function ListAlertRules(): JSX.Element {
cacheTime: 0,
});
const logEventCalledRef = useRef(false);
const { notifications } = useNotifications();
useEffect(() => {
if (!logEventCalledRef.current && !isUndefined(data?.payload)) {
logEvent('Alert: List page visited', {
number: data?.payload?.length,
});
logEventCalledRef.current = true;
}
}, [data?.payload]);
useEffect(() => {
if (status === 'error' || (status === 'success' && data.statusCode >= 400)) {
notifications.error({

View File

@@ -1,3 +1,6 @@
import logEvent from 'api/common/logEvent';
import { ALERTS_DATA_SOURCE_MAP } from 'constants/alerts';
import { AlertTypes } from 'types/api/alerts/alertTypes';
import { GettableAlert } from 'types/api/alerts/get';
export const filterAlerts = (
@@ -23,3 +26,32 @@ export const filterAlerts = (
);
});
};
export const alertActionLogEvent = (
action: string,
record: GettableAlert,
): void => {
let actionValue = '';
switch (action) {
case '0':
actionValue = 'Enable/Disable';
break;
case '1':
actionValue = 'Edit';
break;
case '2':
actionValue = 'Clone';
break;
case '3':
actionValue = 'Delete';
break;
default:
break;
}
logEvent('Alert: Action', {
ruleId: record.id,
dataSource: ALERTS_DATA_SOURCE_MAP[record.alertType as AlertTypes],
name: record.alert,
action: actionValue,
});
};

View File

@@ -609,6 +609,16 @@ function DashboardsList(): JSX.Element {
</>
);
const paginationConfig = data.length > 20 && {
pageSize: 20,
showTotal: showPaginationItem,
showSizeChanger: false,
onChange: (page: any): void => handlePageSizeUpdate(page),
current: Number(sortOrder.pagination),
defaultCurrent: Number(sortOrder.pagination) || 1,
hideOnSinglePage: true,
};
return (
<div className="dashboards-list-container">
<div className="dashboards-list-view-content">
@@ -822,16 +832,7 @@ function DashboardsList(): JSX.Element {
showSorterTooltip
loading={isDashboardListLoading || isFilteringDashboards}
showHeader={false}
pagination={
data.length > 20 && {
pageSize: 20,
showTotal: showPaginationItem,
showSizeChanger: false,
onChange: (page): void => handlePageSizeUpdate(page),
current: Number(sortOrder.pagination),
defaultCurrent: Number(sortOrder.pagination) || 1,
}
}
pagination={paginationConfig}
/>
</>
)}

View File

@@ -15,6 +15,7 @@ import {
} from 'hooks/useResourceAttribute/utils';
import { useMemo, useState } from 'react';
import { useParams } from 'react-router-dom';
import { DataTypes } from 'types/api/queryBuilder/queryAutocompleteResponse';
import { EQueryType } from 'types/common/dashboard';
import { v4 as uuid } from 'uuid';
@@ -93,6 +94,26 @@ function External(): JSX.Element {
[servicename, tagFilterItems],
);
const errorApmToTraceQuery = useGetAPMToTracesQueries({
servicename,
isExternalCall: true,
filters: [
{
id: uuid().slice(0, 8),
key: {
key: 'hasError',
dataType: DataTypes.bool,
type: 'tag',
isColumn: true,
isJSON: false,
id: 'hasError--bool--tag--true',
},
op: 'in',
value: ['true'],
},
],
});
const externalCallRPSWidget = useMemo(
() =>
getWidgetQueryBuilder({
@@ -156,7 +177,7 @@ function External(): JSX.Element {
servicename,
selectedTraceTags,
timestamp: selectedTimeStamp,
apmToTraceQuery,
apmToTraceQuery: errorApmToTraceQuery,
})}
>
View Traces

View File

@@ -2,8 +2,6 @@ import { Card, Typography } from 'antd';
import Spinner from 'components/Spinner';
import { PANEL_TYPES } from 'constants/queryBuilder';
import { WidgetGraphContainerProps } from 'container/NewWidget/types';
// import useUrlQuery from 'hooks/useUrlQuery';
// import { useDashboard } from 'providers/Dashboard/Dashboard';
import { getSortedSeriesData } from 'utils/getSortedSeriesData';
import { NotFoundContainer } from './styles';
@@ -14,6 +12,7 @@ function WidgetGraphContainer({
queryResponse,
setRequestData,
selectedWidget,
isLoadingPanelData,
}: WidgetGraphContainerProps): JSX.Element {
if (queryResponse.data && selectedGraph === PANEL_TYPES.BAR) {
const sortedSeriesData = getSortedSeriesData(
@@ -38,6 +37,10 @@ function WidgetGraphContainer({
return <Spinner size="large" tip="Loading..." />;
}
if (isLoadingPanelData) {
return <Spinner size="large" tip="Loading..." />;
}
if (
selectedGraph !== PANEL_TYPES.LIST &&
queryResponse.data?.payload.data?.result?.length === 0
@@ -59,6 +62,14 @@ function WidgetGraphContainer({
);
}
if (queryResponse.isIdle) {
return (
<NotFoundContainer>
<Typography>No Data</Typography>
</NotFoundContainer>
);
}
return (
<WidgetGraph
selectedWidget={selectedWidget}

View File

@@ -17,6 +17,7 @@ function WidgetGraph({
queryResponse,
setRequestData,
selectedWidget,
isLoadingPanelData,
}: WidgetGraphContainerProps): JSX.Element {
const { currentQuery } = useQueryBuilder();
@@ -43,6 +44,7 @@ function WidgetGraph({
)}
<WidgetGraphComponent
isLoadingPanelData={isLoadingPanelData}
selectedGraph={selectedGraph}
queryResponse={queryResponse}
setRequestData={setRequestData}

View File

@@ -1,18 +1,15 @@
import './LeftContainer.styles.scss';
import { DEFAULT_ENTITY_VERSION } from 'constants/app';
import { initialQueriesMap, PANEL_TYPES } from 'constants/queryBuilder';
import { PANEL_TYPES } from 'constants/queryBuilder';
import { REACT_QUERY_KEY } from 'constants/reactQueryKeys';
import { useGetQueryRange } from 'hooks/queryBuilder/useGetQueryRange';
import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
import { getDashboardVariables } from 'lib/dashbaordVariables/getDashboardVariables';
import { GetQueryResultsProps } from 'lib/dashboard/getQueryResults';
import { useDashboard } from 'providers/Dashboard/Dashboard';
import { memo, useEffect, useState } from 'react';
import { memo } from 'react';
import { useSelector } from 'react-redux';
import { AppState } from 'store/reducers';
import { GlobalReducer } from 'types/reducer/globalTime';
import { getGraphType } from 'utils/getGraphType';
import { WidgetGraphProps } from '../types';
import ExplorerColumnsRenderer from './ExplorerColumnsRenderer';
@@ -27,62 +24,17 @@ function LeftContainer({
selectedTracesFields,
setSelectedTracesFields,
selectedWidget,
selectedTime,
requestData,
setRequestData,
isLoadingPanelData,
}: WidgetGraphProps): JSX.Element {
const { stagedQuery, redirectWithQueryBuilderData } = useQueryBuilder();
const { stagedQuery } = useQueryBuilder();
const { selectedDashboard } = useDashboard();
const { selectedTime: globalSelectedInterval } = useSelector<
AppState,
GlobalReducer
>((state) => state.globalTime);
const [requestData, setRequestData] = useState<GetQueryResultsProps>(() => {
if (selectedWidget && selectedGraph !== PANEL_TYPES.LIST) {
return {
selectedTime: selectedWidget?.timePreferance,
graphType: getGraphType(selectedGraph || selectedWidget.panelTypes),
query: stagedQuery || initialQueriesMap.metrics,
globalSelectedInterval,
variables: getDashboardVariables(selectedDashboard?.data.variables),
};
}
const updatedQuery = { ...(stagedQuery || initialQueriesMap.metrics) };
updatedQuery.builder.queryData[0].pageSize = 10;
redirectWithQueryBuilderData(updatedQuery);
return {
query: updatedQuery,
graphType: PANEL_TYPES.LIST,
selectedTime: selectedTime.enum || 'GLOBAL_TIME',
globalSelectedInterval,
tableParams: {
pagination: {
offset: 0,
limit: updatedQuery.builder.queryData[0].limit || 0,
},
},
};
});
useEffect(() => {
if (stagedQuery) {
setRequestData((prev) => ({
...prev,
selectedTime: selectedTime.enum || prev.selectedTime,
globalSelectedInterval,
graphType: getGraphType(selectedGraph || selectedWidget.panelTypes),
query: stagedQuery,
fillGaps: selectedWidget.fillSpans || false,
}));
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [
stagedQuery,
selectedTime,
selectedWidget.fillSpans,
globalSelectedInterval,
]);
const queryResponse = useGetQueryRange(
requestData,
selectedDashboard?.data?.version || DEFAULT_ENTITY_VERSION,
@@ -104,6 +56,7 @@ function LeftContainer({
queryResponse={queryResponse}
setRequestData={setRequestData}
selectedWidget={selectedWidget}
isLoadingPanelData={isLoadingPanelData}
/>
<QueryContainer className="query-section-left-container">
<QuerySection selectedGraph={selectedGraph} queryResponse={queryResponse} />

View File

@@ -7,7 +7,7 @@ import FacingIssueBtn from 'components/facingIssueBtn/FacingIssueBtn';
import { chartHelpMessage } from 'components/facingIssueBtn/util';
import { FeatureKeys } from 'constants/features';
import { QueryParams } from 'constants/query';
import { PANEL_TYPES } from 'constants/queryBuilder';
import { initialQueriesMap, PANEL_TYPES } from 'constants/queryBuilder';
import ROUTES from 'constants/routes';
import { DashboardShortcuts } from 'constants/shortcuts/DashboardShortcuts';
import { DEFAULT_BUCKET_COUNT } from 'container/PanelWrapper/constants';
@@ -18,6 +18,8 @@ import useAxiosError from 'hooks/useAxiosError';
import { useIsDarkMode } from 'hooks/useDarkMode';
import { MESSAGE, useIsFeatureDisabled } from 'hooks/useFeatureFlag';
import useUrlQuery from 'hooks/useUrlQuery';
import { getDashboardVariables } from 'lib/dashbaordVariables/getDashboardVariables';
import { GetQueryResultsProps } from 'lib/dashboard/getQueryResults';
import history from 'lib/history';
import { defaultTo, isUndefined } from 'lodash-es';
import { Check, X } from 'lucide-react';
@@ -38,6 +40,8 @@ import { IField } from 'types/api/logs/fields';
import { EQueryType } from 'types/common/dashboard';
import { DataSource } from 'types/common/queryBuilder';
import AppReducer from 'types/reducer/app';
import { GlobalReducer } from 'types/reducer/globalTime';
import { getGraphType, getGraphTypeForFormat } from 'utils/getGraphType';
import LeftContainer from './LeftContainer';
import QueryTypeTag from './LeftContainer/QueryTypeTag';
@@ -83,6 +87,10 @@ function NewWidget({ selectedGraph }: NewWidgetProps): JSX.Element {
const { featureResponse } = useSelector<AppState, AppReducer>(
(state) => state.app,
);
const { selectedTime: globalSelectedInterval } = useSelector<
AppState,
GlobalReducer
>((state) => state.globalTime);
const { widgets = [] } = selectedDashboard?.data || {};
@@ -278,6 +286,65 @@ function NewWidget({ selectedGraph }: NewWidgetProps): JSX.Element {
const handleError = useAxiosError();
// this loading state is to take care of mismatch in the responses for table and other panels
// hence while changing the query contains the older value and the processing logic fails
const [isLoadingPanelData, setIsLoadingPanelData] = useState<boolean>(false);
// request data should be handled by the parent and the child components should consume the same
// this has been moved here from the left container
const [requestData, setRequestData] = useState<GetQueryResultsProps>(() => {
if (selectedWidget && selectedGraph !== PANEL_TYPES.LIST) {
return {
selectedTime: selectedWidget?.timePreferance,
graphType: getGraphType(selectedGraph || selectedWidget.panelTypes),
query: stagedQuery || initialQueriesMap.metrics,
globalSelectedInterval,
formatForWeb:
getGraphTypeForFormat(selectedGraph || selectedWidget.panelTypes) ===
PANEL_TYPES.TABLE,
variables: getDashboardVariables(selectedDashboard?.data.variables),
};
}
const updatedQuery = { ...(stagedQuery || initialQueriesMap.metrics) };
updatedQuery.builder.queryData[0].pageSize = 10;
redirectWithQueryBuilderData(updatedQuery);
return {
query: updatedQuery,
graphType: PANEL_TYPES.LIST,
selectedTime: selectedTime.enum || 'GLOBAL_TIME',
globalSelectedInterval,
tableParams: {
pagination: {
offset: 0,
limit: updatedQuery.builder.queryData[0].limit || 0,
},
},
};
});
useEffect(() => {
if (stagedQuery) {
setIsLoadingPanelData(false);
setRequestData((prev) => ({
...prev,
selectedTime: selectedTime.enum || prev.selectedTime,
globalSelectedInterval,
graphType: getGraphType(selectedGraph || selectedWidget.panelTypes),
query: stagedQuery,
fillGaps: selectedWidget.fillSpans || false,
formatForWeb:
getGraphTypeForFormat(selectedGraph || selectedWidget.panelTypes) ===
PANEL_TYPES.TABLE,
}));
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [
stagedQuery,
selectedTime,
selectedWidget.fillSpans,
globalSelectedInterval,
]);
const onClickSaveHandler = useCallback(() => {
if (!selectedDashboard) {
return;
@@ -402,6 +469,7 @@ function NewWidget({ selectedGraph }: NewWidgetProps): JSX.Element {
}, [dashboardId]);
const setGraphHandler = (type: PANEL_TYPES): void => {
setIsLoadingPanelData(true);
const updatedQuery = handleQueryChange(type as any, supersetQuery);
setGraphType(type);
redirectWithQueryBuilderData(
@@ -527,6 +595,9 @@ function NewWidget({ selectedGraph }: NewWidgetProps): JSX.Element {
setSelectedTracesFields={setSelectedTracesFields}
selectedWidget={selectedWidget}
selectedTime={selectedTime}
requestData={requestData}
setRequestData={setRequestData}
isLoadingPanelData={isLoadingPanelData}
/>
)}
</LeftContainerWrapper>

View File

@@ -24,6 +24,9 @@ export interface WidgetGraphProps {
selectedWidget: Widgets;
selectedGraph: PANEL_TYPES;
selectedTime: timePreferance;
requestData: GetQueryResultsProps;
setRequestData: Dispatch<SetStateAction<GetQueryResultsProps>>;
isLoadingPanelData: boolean;
}
export type WidgetGraphContainerProps = {
@@ -34,4 +37,5 @@ export type WidgetGraphContainerProps = {
setRequestData: Dispatch<SetStateAction<GetQueryResultsProps>>;
selectedGraph: PANEL_TYPES;
selectedWidget: Widgets;
isLoadingPanelData: boolean;
};

View File

@@ -0,0 +1,108 @@
## Setup
### Installing with OpenTelemetry Helm Charts
Prior to installation, you must ensure your Kubernetes cluster is ready and that you have the necessary permissions to deploy applications. Follow these steps to use Helm for setting up the Collector:
&nbsp;
1. **Add the OpenTelemetry Helm repository:**
```bash
helm repo add open-telemetry https://open-telemetry.github.io/opentelemetry-helm-charts
```
&nbsp;
2. **Prepare the `otel-collector-values.yaml` Configuration**
&nbsp;
#### Azure Event Hub Receiver Configuration
Replace the placeholders `<Primary Connection String>` with the primary connection string for your Event Hub, it should look something like this:
```yaml
connection: Endpoint=sb://namespace.servicebus.windows.net/;SharedAccessKeyName=RootManageSharedAccessKey;SharedAccessKey=superSecret1234=;EntityPath=hubName
```
The Event Hub setup have a step to create a SAS policy for the event hub and copy the connection string.
&nbsp;
#### Azure Monitor Receiver Configuration
You will need to set up a [service principal](https://learn.microsoft.com/en-us/entra/identity-platform/howto-create-service-principal-portal) with Read permissions to receive data from Azure Monitor.
1. Follow the steps in the [Create a service principal Azure Doc](https://learn.microsoft.com/en-us/entra/identity-platform/howto-create-service-principal-portal#register-an-application-with-microsoft-entra-id-and-create-a-service-principal) documentation to create a service principal.
You can name it `signoz-central-collector-app` the redirect URI can be empty.
2. To add read permissions to Azure Monitor, Follow the [Assign Role](https://learn.microsoft.com/en-us/entra/identity-platform/howto-create-service-principal-portal#assign-a-role-to-the-application) documentation. The read acess can be given to the full subscription.
3. There are multiple ways to authenticate the service principal, we will use the client secret option, follow [Creating a client secret](https://learn.microsoft.com/en-us/entra/identity-platform/howto-create-service-principal-portal#option-3-create-a-new-client-secret) and don't forget to copy the client secret. The secret is used in the configuration file as `client_secret`.
4. To find `client_id` and `tenant_id`, go to the [Azure Portal](https://portal.azure.com/) and search for the `Application` you created. You would see the `Application (client) ID` and `Directory (tenant) ID` in the Overview section.
5. To find `subscription_id`, follow steps in [Find Your Subscription](https://learn.microsoft.com/en-us/azure/azure-portal/get-subscription-tenant-id#find-your-azure-subscription) and populate them in the configuration file.
6. Ensure you replace the placeholders `<region>` and `<ingestion-key>` with the appropriate values for your signoz cloud instance.
Below is an example targeting the SigNoz backend with Azure Monitor receivers configured:
```yaml
service:
pipelines:
metrics/am:
receivers: [azuremonitor]
exporters: [otlp]
traces:
receivers: [otlp]
processors: [batch]
exporters: [otlp]
metrics:
receivers: [otlp]
processors: [batch]
exporters: [otlp]
logs:
receivers: [otlp, azureeventhub]
processors: [batch]
exporters: [otlp]
receivers:
otlp:
protocols:
grpc:
endpoint: 0.0.0.0:4317
http:
endpoint: 0.0.0.0:4318
azureeventhub:
connection: Endpoint=sb://namespace.servicebus.windows.net/;SharedAccessKeyName=RootManageSharedAccessKey;SharedAccessKey=superSecret1234=;EntityPath=hubName
format: "azure"
azuremonitor:
subscription_id: "<Subscription ID>"
tenant_id: "<AD Tenant ID>"
client_id: "<Client ID>"
client_secret: "<Client Secret>"
resource_groups: ["<rg-1>"]
collection_interval: 60s
processors:
batch: {}
exporters:
otlp:
endpoint: "ingest.{{REGION}}.signoz.cloud:443"
tls:
insecure: false
headers:
"signoz-access-token": "{{SIGNOZ_INGESTION_KEY}}"
```
&nbsp;
3. **Deploy the OpenTelemetry Collector to your Kubernetes cluster:**
You'll need to prepare a custom configuration file, say `otel-collector-values.yaml`, that matches your environment's specific needs. Replace `<namespace>` with the Kubernetes namespace where you wish to install the Collector.
```bash
helm install -n <namespace> --create-namespace otel-collector open-telemetry/opentelemetry-collector -f otel-collector-values.yaml
```
For more detail, refer to the [official OpenTelemetry Helm Chart documentation](https://github.com/open-telemetry/opentelemetry-helm-charts/tree/main/charts/opentelemetry-collector), which offers comprehensive installation instructions and configuration options tailored to your environment's requirements.

View File

@@ -0,0 +1,8 @@
## Prerequisite
- An AKS cluster
- Central Collector Setup
&nbsp;
Once you have setup the Central Collector, it will automatically start collecting your Logs.

View File

@@ -0,0 +1,8 @@
## Prerequisite
- An AKS cluster
- Central Collector Setup
&nbsp;
Once you have setup the Central Collector, it will automatically start sending your Metrics to SigNoz.

View File

@@ -0,0 +1,40 @@
## Overview
Azure Event Hubs is a big data streaming platform ideal for centralizing logging and real-time log streaming for applications on Azure or on-premises.
Integrate SigNoz with Azure Event Hubs for a robust log management solution, leveraging SigNoz's log aggregation, querying, visualization, and alerting features.
## Prerequisites
- An active Azure subscription
## Setup
### 1. Create an Event Hubs Namespace
1. In the [Azure portal](https://portal.azure.com), create an Event Hubs namespace.
2. Fill in the required details:
- **Resource group**: Choose or create a new one.
- **Namespace name**: Enter a unique name, e.g., `<orgName>-obs-signoz`.
- **Pricing tier**: Based on your logging requirements.
- **Region**: Should match the region of the resources you want to monitor.
- **Throughput units**: Choose based on logging needs.
3. Click "Review + create" and then "Create".
### 2. Create an Event Hub
1. Navigate to the Event Hubs namespace you created in the Azure portal.
2. Click "+ Event Hub" to create a new event hub.
3. Enter a name, e.g., `logs`and click "Create"
### 3. Create a SAS Policy and Copy Connection String
1. Navigate to the Event Hub in the Azure portal.
2. Click "Shared access policies" in the left menu.
3. Click "Add" to create a new policy named `signozListen`.
4. Select the "Listen" permission and set the expiration time.
5. Click "Save".
6. Copy the *Connection stringprimary key*.

View File

@@ -0,0 +1,16 @@
## Application level Tracing
For application-level tracing, you can use the OpenTelemetry SDKs integrated with your application. These SDKs will automatically collect and forward traces to the Central Collector.
&nbsp;
To see how you can instrument your applications like FastAPI, NextJS, Node.js, Spring etc. you can check out the **Application Monitoring** section available at the start of this onboarding or you can checkout this [documentation](https://signoz.io/docs/instrumentation/).
## Configure the OpenTelemetry SDK
```bash
# Set env vars or config file
export OTEL_EXPORTER_OTLP_ENDPOINT="http://otel-collector.kubelet-otel.svc.cluster.local:4318/"
```
For application-level traces and metrics, configure your application to use the `kube-dns` name of the **Central Collector** you set up earlier.

View File

@@ -0,0 +1,129 @@
Set up the OpenTelemetry Collector on a Virtual Machine (VM). The setup is compatible with cloud VM instances, your own data center, or even a local VM on your development machine. Here's how to do it:
## Download and Install the OpenTelemetry Collector Binary
Please visit [Documentation For VM](https://signoz.io/docs/tutorial/opentelemetry-binary-usage-in-virtual-machine/) which provides further guidance on a VM installation.
&nbsp;
## Configure OpenTelemetry Collector
While following the documentation above for installing the OpenTelemetry Collector Binary, you must have created `config.yaml` file. Replace the content of the `config.yaml` with the below config file which includes the **Azure Monitor receiver**.
```yaml
receivers:
otlp:
protocols:
grpc:
endpoint: 0.0.0.0:4317
http:
endpoint: 0.0.0.0:4318
azureeventhub:
connection: <Primary Connection String>
format: "azure"
azuremonitor:
subscription_id: "<Subscription ID>"
tenant_id: "<AD Tenant ID>"
client_id: "<Client ID>"
client_secret: "<Client Secret>"
resource_groups: ["<rg-1>"]
collection_interval: 60s
processors:
batch: {}
exporters:
otlp:
endpoint: "ingest.{{REGION}}.signoz.cloud:443"
tls:
insecure: false
headers:
"signoz-access-token": "{{SIGNOZ_INGESTION_KEY}}"
service:
pipelines:
metrics/am:
receivers: [azuremonitor]
exporters: [otlp]
traces:
receivers: [otlp]
processors: [batch]
exporters: [otlp]
metrics:
receivers: [otlp]
processors: [batch]
exporters: [otlp]
logs:
receivers: [otlp, azureeventhub]
processors: [batch]
exporters: [otlp]
```
**NOTE:**
Replace the `<Primary Connection String>` in the config file with the primary connection string for your Event Hub that you created in the previous section. It would look something like this:
```bash
Endpoint=sb://namespace.servicebus.windows.net/;SharedAccessKeyName=RootManageSharedAccessKey;SharedAccessKey=superSecret1234=;EntityPath=hubName
```
&nbsp;
## Azure Monitor Receiver Configuration
You will need to set up a [service principal](https://learn.microsoft.com/en-us/entra/identity-platform/howto-create-service-principal-portal) with Read permissions to receive data from Azure Monitor.
1. Follow the steps in the [Create a service principal Azure Doc](https://learn.microsoft.com/en-us/entra/identity-platform/howto-create-service-principal-portal#register-an-application-with-microsoft-entra-id-and-create-a-service-principal) documentation to create a service principal.
You can name it `signoz-central-collector-app` the redirect URI can be empty.
2. To add read permissions to Azure Monitor, Follow the [Assign Role](https://learn.microsoft.com/en-us/entra/identity-platform/howto-create-service-principal-portal#assign-a-role-to-the-application) documentation. The read access can be given to the full subscription.
3. There are multiple ways to authenticate the service principal, we will use the client secret option, follow [Creating a client secret](https://learn.microsoft.com/en-us/entra/identity-platform/howto-create-service-principal-portal#option-3-create-a-new-client-secret) and don't forget to copy the client secret. The secret is used in the configuration file as `client_secret`.
4. To find `client_id` and `tenant_id`, go to the [Azure Portal](https://portal.azure.com/) and search for the `Application` you created. You would see the `Application (client) ID` and `Directory (tenant) ID` in the Overview section.
5. To find `subscription_id`, follow steps in [Find Your Subscription](https://learn.microsoft.com/en-us/azure/azure-portal/get-subscription-tenant-id#find-your-azure-subscription) and populate them in the configuration file.
**NOTE:**
By following the above steps, you will get the values for `<Subscription ID>`, `<AD Tenant ID>`, `<Client ID>` and `<Client Secret>` which you need to fill in the `config.yaml` file.
&nbsp;
## Run the Collector
With your configuration file ready, you can now start the Collector using the following command:
```bash
# Runs in background with the configuration we just created
./otelcol-contrib --config ./config.yaml &> otelcol-output.log & echo "$!" > otel-pid
```
&nbsp;
### Open Ports
You will need to open the following ports on your Azure VM:
- 4317 for gRPC
- 4318 for HTTP
You can do this by navigating to the Azure VM's Networking section and adding a new inbound rule for the ports.
&nbsp;
### Validating the Deployment
Once the Collector is running, ensure that telemetry data is being successfully sent and received. Use the logging exporter as defined in your configuration file, or check the logs for any startup errors.
&nbsp;
## Configure DNS label For Collector
To the IP address of the collector, you can add a DNS label to the Public IP address. This will make it easier to refer to the centralized collector from other services. You can do this by following these steps:
1. Go to the Public IP address of the collector. This would be the IP address of the VM or Load Balancer in case of Kubernetes or Load Balanced collector.
2. Click on the "Configuration" tab.
3. Enter the DNS label you want to use for the collector.
4. Click on "Save".
**NOTE:** Please take note of the DNS label you have entered. You will need this in the next steps.
&nbsp;
If you encounter any difficulties, please refer to this [troubleshooting section](https://signoz.io/docs/azure-monitoring/bootstrapping/collector-setup/#troubleshooting)

View File

@@ -0,0 +1,33 @@
Follow these steps if you want to setup logging for your Azure App Service.
&nbsp;
## Prerequisites
- EventHub Setup
- Central Collector Setup
## Setup
1. Navigate to your App Service in the Azure portal
2. Search for "Diagnostic settings" in the left navigation menu
3. Click on "Add Diagnostic Setting"
4. Select the desired log categories to export:
- HTTP logs
- App Service Console Logs
- App Service Application Logs
- Access Audit Logs
- IPSecurity Audit logs
- App Service Platform logs
5. Configure the destination details as **"Stream to an Event Hub"** and select the Event Hub namespace and Event Hub name created during the EventHub Setup in the earlier steps.
6. Save the diagnostic settings
This will start sending your Azure App Service Logs to SigNoz!

View File

@@ -0,0 +1,25 @@
Follow these steps if you want to monitor System metrics like CPU Percentage, Memory Percentage etc. of your Azure App Service.
&nbsp;
## Prerequisites
- EventHub Setup
- Central Collector Setup
## Dashboard Example
Once you have completed the prerequisites, you can start monitoring your Azure App Service's system metrics with SigNoz Cloud. Here's how you can do it:
1. Log in to your SigNoz account
2. Navigate to the Dashboards section, and [add a dashboard](https://signoz.io/docs/userguide/manage-dashboards/)
3. Add a Timeseries Panel
4. In **Metrics**, select `azure_memorypercentage_total` and **Avg By** select tag `location`
5. In Filter say `name = <app-svc-plan-name>`
6. Hit “Save Changes” and you now have Memory Usage of your App Service in a Dashboard for reporting and alerting
In this way, you can monitor system metrics of your Azure App Service in SigNoz Cloud.
&nbsp;
If you encounter any difficulties, please refer to this [troubleshooting section](https://signoz.io/docs/azure-monitoring/app-service/metrics/#troubleshooting)

View File

@@ -0,0 +1,54 @@
## Overview
Azure Event Hubs is a big data streaming platform ideal for centralizing logging and real-time log streaming for applications on Azure or on-premises.
Integrate SigNoz with Azure Event Hubs for a robust log management solution, leveraging SigNoz's log aggregation, querying, visualization, and alerting features.
## Prerequisites
- An active Azure subscription
## Setup
### 1. Create an Event Hubs Namespace
1. In the [Azure portal](https://portal.azure.com), create an Event Hubs namespace.
2. Fill in the required details:
- **Resource group**: Choose or create a new one.
- **Namespace name**: Enter a unique name, e.g., `<orgName>-obs-signoz`.
- **Pricing tier**: Based on your logging requirements.
- **Region**: Should match the region of the resources you want to monitor.
- **Throughput units**: Choose based on logging needs.
3. Click "Review + create" and then "Create".
### 2. Create an Event Hub
1. Navigate to the Event Hubs namespace you created in the Azure portal.
2. Click "+ Event Hub" to create a new event hub.
3. Enter a name, e.g., `logs`and click "Create"
### 3. Create a SAS Policy and Copy Connection String
1. Navigate to the Event Hub in the Azure portal.
2. Click "Shared access policies" in the left menu.
3. Click "Add" to create a new policy named `signozListen`.
4. Select the "Listen" permission and set the expiration time.
5. Click "Save".
6. Copy the *Connection stringprimary key*.
<!-- ### 4. Configure OpenTelemetry Integration
1. Add a new receiver to [Central Collector Setup](../collector-setup).
2. Configure the receiver with the Event Hubs namespace connection string and the event hub name.
### 5. Stream Logs to Event Hubs
1. Configure Azure services' diagnostic settings to forward logs to the Event Hub.
2. Ensure logs are in [Azure Common Log Format](https://learn.microsoft.com/en-us/azure/azure-monitor/essentials/resource-logs-schema).
3. Verify logs are streaming to Event Hubs and received by SigNoz.
For detailed instructions, refer to the Azure documentation: [Azure Event Hub](https://learn.microsoft.com/en-us/azure/event-hubs/event-hubs-create). -->
<!-- For more configuration options, see the [OpenTelemetry Documentation](https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/main/receiver/azureeventhubreceiver). -->

View File

@@ -0,0 +1,29 @@
## Application level Tracing
For application-level tracing, you can use the OpenTelemetry SDKs integrated with your application. These SDKs will automatically collect and forward traces to the Central Collector.
&nbsp;
To see how you can instrument your applications like FastAPI, NextJS, Node.js, Spring etc. you can check out the **Application Monitoring** section available at the start of this onboarding or you can checkout this [documentation](https://signoz.io/docs/instrumentation/).
&nbsp;
## Prerequisites
1. **Azure Subscription & App Service**: You need an active Azure subscription with a running Azure App Service instance.
2. **Central Collector Setup**: Make sure you have set up the Central Collector
&nbsp;
## Configure the OpenTelemetry SDK
```bash
# Set env vars or config file
export OTEL_EXPORTER_OTLP_ENDPOINT="http://<Your-Central-Collector-DNS>:4318/"
```
For application-level traces, configure your application to use the DNS name of the **Central Collector** you set up earlier. This Central Collector will automatically forward the collected data to SigNoz.
&nbsp;
If you encounter any difficulties, please refer to this [troubleshooting section](https://signoz.io/docs/azure-monitoring/app-service/tracing/#troubleshooting)

View File

@@ -0,0 +1,129 @@
Set up the OpenTelemetry Collector on a Virtual Machine (VM). The setup is compatible with cloud VM instances, your own data center, or even a local VM on your development machine. Here's how to do it:
## Download and Install the OpenTelemetry Collector Binary
Please visit [Documentation For VM](https://signoz.io/docs/tutorial/opentelemetry-binary-usage-in-virtual-machine/) which provides further guidance on a VM installation.
&nbsp;
## Configure OpenTelemetry Collector
While following the documentation above for installing the OpenTelemetry Collector Binary, you must have created `config.yaml` file. Replace the content of the `config.yaml` with the below config file which includes the **Azure Monitor receiver**.
```yaml
receivers:
otlp:
protocols:
grpc:
endpoint: 0.0.0.0:4317
http:
endpoint: 0.0.0.0:4318
azureeventhub:
connection: <Primary Connection String>
format: "azure"
azuremonitor:
subscription_id: "<Subscription ID>"
tenant_id: "<AD Tenant ID>"
client_id: "<Client ID>"
client_secret: "<Client Secret>"
resource_groups: ["<rg-1>"]
collection_interval: 60s
processors:
batch: {}
exporters:
otlp:
endpoint: "ingest.{{REGION}}.signoz.cloud:443"
tls:
insecure: false
headers:
"signoz-access-token": "{{SIGNOZ_INGESTION_KEY}}"
service:
pipelines:
metrics/am:
receivers: [azuremonitor]
exporters: [otlp]
traces:
receivers: [otlp]
processors: [batch]
exporters: [otlp]
metrics:
receivers: [otlp]
processors: [batch]
exporters: [otlp]
logs:
receivers: [otlp, azureeventhub]
processors: [batch]
exporters: [otlp]
```
**NOTE:**
Replace the `<Primary Connection String>` in the config file with the primary connection string for your Event Hub that you created in the previous section. It would look something like this:
```bash
Endpoint=sb://namespace.servicebus.windows.net/;SharedAccessKeyName=RootManageSharedAccessKey;SharedAccessKey=superSecret1234=;EntityPath=hubName
```
&nbsp;
## Azure Monitor Receiver Configuration
You will need to set up a [service principal](https://learn.microsoft.com/en-us/entra/identity-platform/howto-create-service-principal-portal) with Read permissions to receive data from Azure Monitor.
1. Follow the steps in the [Create a service principal Azure Doc](https://learn.microsoft.com/en-us/entra/identity-platform/howto-create-service-principal-portal#register-an-application-with-microsoft-entra-id-and-create-a-service-principal) documentation to create a service principal.
You can name it `signoz-central-collector-app` the redirect URI can be empty.
2. To add read permissions to Azure Monitor, Follow the [Assign Role](https://learn.microsoft.com/en-us/entra/identity-platform/howto-create-service-principal-portal#assign-a-role-to-the-application) documentation. The read access can be given to the full subscription.
3. There are multiple ways to authenticate the service principal, we will use the client secret option, follow [Creating a client secret](https://learn.microsoft.com/en-us/entra/identity-platform/howto-create-service-principal-portal#option-3-create-a-new-client-secret) and don't forget to copy the client secret. The secret is used in the configuration file as `client_secret`.
4. To find `client_id` and `tenant_id`, go to the [Azure Portal](https://portal.azure.com/) and search for the `Application` you created. You would see the `Application (client) ID` and `Directory (tenant) ID` in the Overview section.
5. To find `subscription_id`, follow steps in [Find Your Subscription](https://learn.microsoft.com/en-us/azure/azure-portal/get-subscription-tenant-id#find-your-azure-subscription) and populate them in the configuration file.
**NOTE:**
By following the above steps, you will get the values for `<Subscription ID>`, `<AD Tenant ID>`, `<Client ID>` and `<Client Secret>` which you need to fill in the `config.yaml` file.
&nbsp;
## Run the Collector
With your configuration file ready, you can now start the Collector using the following command:
```bash
# Runs in background with the configuration we just created
./otelcol-contrib --config ./config.yaml &> otelcol-output.log & echo "$!" > otel-pid
```
&nbsp;
### Open Ports
You will need to open the following ports on your Azure VM:
- 4317 for gRPC
- 4318 for HTTP
You can do this by navigating to the Azure VM's Networking section and adding a new inbound rule for the ports.
&nbsp;
### Validating the Deployment
Once the Collector is running, ensure that telemetry data is being successfully sent and received. Use the logging exporter as defined in your configuration file, or check the logs for any startup errors.
&nbsp;
## Configure DNS label For Collector
To the IP address of the collector, you can add a DNS label to the Public IP address. This will make it easier to refer to the centralized collector from other services. You can do this by following these steps:
1. Go to the Public IP address of the collector. This would be the IP address of the VM or Load Balancer in case of Kubernetes or Load Balanced collector.
2. Click on the "Configuration" tab.
3. Enter the DNS label you want to use for the collector.
4. Click on "Save".
**NOTE:** Please take note of the DNS label you have entered. You will need this in the next steps.
&nbsp;
If you encounter any difficulties, please refer to this [troubleshooting section](https://signoz.io/docs/azure-monitoring/bootstrapping/collector-setup/#troubleshooting)

View File

@@ -0,0 +1,23 @@
Follow these steps if you want to setup logging for your Azure App Service.
&nbsp;
## Prerequisites
- EventHub Setup
- Central Collector Setup
## Setup
1. Navigate to the relevant Storage Account in the Azure portal
2. Search for "Diagnostic settings" in the left navigation menu
3. Click on `blob` under the storage account
4. Click on "Add Diagnostic Setting"
5. Select the desired log categories to export:
- Storage Read
- Storage Write
- Storage Delete
5. Configure the destination details as "**Stream to an Event Hub**" and select the Event Hub namespace and Event Hub name created during the EventHub Setup
6. Save the diagnostic settings
That's it! You have successfully set up logging for your Azure Blob Storage.

View File

@@ -0,0 +1,28 @@
Follow these steps if you want to monitor system metrics like Total Requests, Total Ingress / Egress, and Total Errors etc., of your Azure Blob Storage.
&nbsp;
## Prerequisites
- Azure Subscription and Azure Blob storage instance running
- Central Collector Setup
&nbsp;
## Dashboard Example
Once you have completed the prerequisites, you can start monitoring your Azure Blob Storage's system metrics with SigNoz.
1. Log in to your SigNoz account.
2. Navigate to the Dashboards, and [add a dashboard](https://signoz.io/docs/userguide/manage-dashboards/)
3. Add a Timeseries Panel
4. In **Metrics**, select `azure_ingress_total` and **Avg B*y* select tag `location`
5. In Filter say `name = <storage-account-name>`
6. Hit “Save Changes”. You now have Total Ingress of your Azure Blob Storage in a Dashboard for reporting and alerting
That's it! You have successfully set up monitoring for your Azure Blob Storage's system metrics with SigNoz. You can now start creating other panels and dashboards to monitor other Azure Blob Storage's metrics.
&nbsp;
If you encounter any difficulties, please refer to this [troubleshooting section](https://signoz.io/docs/azure-monitoring/az-blob-storage/metrics/#troubleshooting)

View File

@@ -0,0 +1,54 @@
## Overview
Azure Event Hubs is a big data streaming platform ideal for centralizing logging and real-time log streaming for applications on Azure or on-premises.
Integrate SigNoz with Azure Event Hubs for a robust log management solution, leveraging SigNoz's log aggregation, querying, visualization, and alerting features.
## Prerequisites
- An active Azure subscription
## Setup
### 1. Create an Event Hubs Namespace
1. In the [Azure portal](https://portal.azure.com), create an Event Hubs namespace.
2. Fill in the required details:
- **Resource group**: Choose or create a new one.
- **Namespace name**: Enter a unique name, e.g., `<orgName>-obs-signoz`.
- **Pricing tier**: Based on your logging requirements.
- **Region**: Should match the region of the resources you want to monitor.
- **Throughput units**: Choose based on logging needs.
3. Click "Review + create" and then "Create".
### 2. Create an Event Hub
1. Navigate to the Event Hubs namespace you created in the Azure portal.
2. Click "+ Event Hub" to create a new event hub.
3. Enter a name, e.g., `logs`and click "Create"
### 3. Create a SAS Policy and Copy Connection String
1. Navigate to the Event Hub in the Azure portal.
2. Click "Shared access policies" in the left menu.
3. Click "Add" to create a new policy named `signozListen`.
4. Select the "Listen" permission and set the expiration time.
5. Click "Save".
6. Copy the *Connection stringprimary key*.
<!-- ### 4. Configure OpenTelemetry Integration
1. Add a new receiver to [Central Collector Setup](../collector-setup).
2. Configure the receiver with the Event Hubs namespace connection string and the event hub name.
### 5. Stream Logs to Event Hubs
1. Configure Azure services' diagnostic settings to forward logs to the Event Hub.
2. Ensure logs are in [Azure Common Log Format](https://learn.microsoft.com/en-us/azure/azure-monitor/essentials/resource-logs-schema).
3. Verify logs are streaming to Event Hubs and received by SigNoz.
For detailed instructions, refer to the Azure documentation: [Azure Event Hub](https://learn.microsoft.com/en-us/azure/event-hubs/event-hubs-create). -->
<!-- For more configuration options, see the [OpenTelemetry Documentation](https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/main/receiver/azureeventhubreceiver). -->

View File

@@ -0,0 +1,129 @@
Set up the OpenTelemetry Collector on a Virtual Machine (VM). The setup is compatible with cloud VM instances, your own data center, or even a local VM on your development machine. Here's how to do it:
## Download and Install the OpenTelemetry Collector Binary
Please visit [Documentation For VM](https://signoz.io/docs/tutorial/opentelemetry-binary-usage-in-virtual-machine/) which provides further guidance on a VM installation.
&nbsp;
## Configure OpenTelemetry Collector
While following the documentation above for installing the OpenTelemetry Collector Binary, you must have created `config.yaml` file. Replace the content of the `config.yaml` with the below config file which includes the **Azure Monitor receiver**.
```yaml
receivers:
otlp:
protocols:
grpc:
endpoint: 0.0.0.0:4317
http:
endpoint: 0.0.0.0:4318
azureeventhub:
connection: <Primary Connection String>
format: "azure"
azuremonitor:
subscription_id: "<Subscription ID>"
tenant_id: "<AD Tenant ID>"
client_id: "<Client ID>"
client_secret: "<Client Secret>"
resource_groups: ["<rg-1>"]
collection_interval: 60s
processors:
batch: {}
exporters:
otlp:
endpoint: "ingest.{{REGION}}.signoz.cloud:443"
tls:
insecure: false
headers:
"signoz-access-token": "{{SIGNOZ_INGESTION_KEY}}"
service:
pipelines:
metrics/am:
receivers: [azuremonitor]
exporters: [otlp]
traces:
receivers: [otlp]
processors: [batch]
exporters: [otlp]
metrics:
receivers: [otlp]
processors: [batch]
exporters: [otlp]
logs:
receivers: [otlp, azureeventhub]
processors: [batch]
exporters: [otlp]
```
**NOTE:**
Replace the `<Primary Connection String>` in the config file with the primary connection string for your Event Hub that you created in the previous section. It would look something like this:
```bash
Endpoint=sb://namespace.servicebus.windows.net/;SharedAccessKeyName=RootManageSharedAccessKey;SharedAccessKey=superSecret1234=;EntityPath=hubName
```
&nbsp;
## Azure Monitor Receiver Configuration
You will need to set up a [service principal](https://learn.microsoft.com/en-us/entra/identity-platform/howto-create-service-principal-portal) with Read permissions to receive data from Azure Monitor.
1. Follow the steps in the [Create a service principal Azure Doc](https://learn.microsoft.com/en-us/entra/identity-platform/howto-create-service-principal-portal#register-an-application-with-microsoft-entra-id-and-create-a-service-principal) documentation to create a service principal.
You can name it `signoz-central-collector-app` the redirect URI can be empty.
2. To add read permissions to Azure Monitor, Follow the [Assign Role](https://learn.microsoft.com/en-us/entra/identity-platform/howto-create-service-principal-portal#assign-a-role-to-the-application) documentation. The read access can be given to the full subscription.
3. There are multiple ways to authenticate the service principal, we will use the client secret option, follow [Creating a client secret](https://learn.microsoft.com/en-us/entra/identity-platform/howto-create-service-principal-portal#option-3-create-a-new-client-secret) and don't forget to copy the client secret. The secret is used in the configuration file as `client_secret`.
4. To find `client_id` and `tenant_id`, go to the [Azure Portal](https://portal.azure.com/) and search for the `Application` you created. You would see the `Application (client) ID` and `Directory (tenant) ID` in the Overview section.
5. To find `subscription_id`, follow steps in [Find Your Subscription](https://learn.microsoft.com/en-us/azure/azure-portal/get-subscription-tenant-id#find-your-azure-subscription) and populate them in the configuration file.
**NOTE:**
By following the above steps, you will get the values for `<Subscription ID>`, `<AD Tenant ID>`, `<Client ID>` and `<Client Secret>` which you need to fill in the `config.yaml` file.
&nbsp;
## Run the Collector
With your configuration file ready, you can now start the Collector using the following command:
```bash
# Runs in background with the configuration we just created
./otelcol-contrib --config ./config.yaml &> otelcol-output.log & echo "$!" > otel-pid
```
&nbsp;
### Open Ports
You will need to open the following ports on your Azure VM:
- 4317 for gRPC
- 4318 for HTTP
You can do this by navigating to the Azure VM's Networking section and adding a new inbound rule for the ports.
&nbsp;
### Validating the Deployment
Once the Collector is running, ensure that telemetry data is being successfully sent and received. Use the logging exporter as defined in your configuration file, or check the logs for any startup errors.
&nbsp;
## Configure DNS label For Collector
To the IP address of the collector, you can add a DNS label to the Public IP address. This will make it easier to refer to the centralized collector from other services. You can do this by following these steps:
1. Go to the Public IP address of the collector. This would be the IP address of the VM or Load Balancer in case of Kubernetes or Load Balanced collector.
2. Click on the "Configuration" tab.
3. Enter the DNS label you want to use for the collector.
4. Click on "Save".
**NOTE:** Please take note of the DNS label you have entered. You will need this in the next steps.
&nbsp;
If you encounter any difficulties, please refer to this [troubleshooting section](https://signoz.io/docs/azure-monitoring/bootstrapping/collector-setup/#troubleshooting)

View File

@@ -0,0 +1,28 @@
Follow these steps if you want to setup logging for your Azure Container App.
&nbsp;
## Prerequisites
- EventHub Setup
- Central Collector Setup
## Setup
1. Navigate to your Container Apps in the Azure portal
2. Click on "Container Apps Environment" to open the Container Apps Environment
3. Search for "Diagnostic settings" in the left navigation menu
4. Click on "Add Diagnostic Setting"
5. Select the desired log categories to export:
- Container App console logs
- Container App system logs
- Spring App console logs
6. Configure the destination details as **"Stream to an Event Hub"** and select the Event Hub namespace and Event Hub name created during the EventHub Setup.
7. Save the diagnostic settings
That's it! You have successfully set up logging for your Azure Container App.

View File

@@ -0,0 +1,27 @@
Follow these steps if you want to monitor System metrics like CPU Percentage, Memory Percentage etc. of your Azure Container App.
&nbsp;
## Prerequisites
- Azure subscription and an Azure Container App instance running
- Central Collector Setup
&nbsp;
# Dashboard Example
Once you have completed the prerequisites, you can start monitoring your Azure Container App's system metrics with SigNoz. Here's how you can do it:
1. Log in to your SigNoz account.
2. Navigate to the Dashboards, and [add an dashboard](https://signoz.io/docs/userguide/manage-dashboards/)
3. Add a Timeseries Panel
4. In **Metrics**, select `azure_replicas_count` and **Avg By** select tag `name`
5. In Filter say `type = Microsoft.App/containerApps`
6. Hit “Save Changes”. You now have Memory Usage of your Container App in a Dashboard for reporting and alerting
In this way, you can monitor system metrics of your Azure Container App in SigNoz!
&nbsp;
If you encounter any difficulties, please refer to this [troubleshooting section](https://signoz.io/docs/azure-monitoring/az-container-apps/metrics/#troubleshooting)

View File

@@ -0,0 +1,54 @@
## Overview
Azure Event Hubs is a big data streaming platform ideal for centralizing logging and real-time log streaming for applications on Azure or on-premises.
Integrate SigNoz with Azure Event Hubs for a robust log management solution, leveraging SigNoz's log aggregation, querying, visualization, and alerting features.
## Prerequisites
- An active Azure subscription
## Setup
### 1. Create an Event Hubs Namespace
1. In the [Azure portal](https://portal.azure.com), create an Event Hubs namespace.
2. Fill in the required details:
- **Resource group**: Choose or create a new one.
- **Namespace name**: Enter a unique name, e.g., `<orgName>-obs-signoz`.
- **Pricing tier**: Based on your logging requirements.
- **Region**: Should match the region of the resources you want to monitor.
- **Throughput units**: Choose based on logging needs.
3. Click "Review + create" and then "Create".
### 2. Create an Event Hub
1. Navigate to the Event Hubs namespace you created in the Azure portal.
2. Click "+ Event Hub" to create a new event hub.
3. Enter a name, e.g., `logs`and click "Create"
### 3. Create a SAS Policy and Copy Connection String
1. Navigate to the Event Hub in the Azure portal.
2. Click "Shared access policies" in the left menu.
3. Click "Add" to create a new policy named `signozListen`.
4. Select the "Listen" permission and set the expiration time.
5. Click "Save".
6. Copy the *Connection stringprimary key*.
<!-- ### 4. Configure OpenTelemetry Integration
1. Add a new receiver to [Central Collector Setup](../collector-setup).
2. Configure the receiver with the Event Hubs namespace connection string and the event hub name.
### 5. Stream Logs to Event Hubs
1. Configure Azure services' diagnostic settings to forward logs to the Event Hub.
2. Ensure logs are in [Azure Common Log Format](https://learn.microsoft.com/en-us/azure/azure-monitor/essentials/resource-logs-schema).
3. Verify logs are streaming to Event Hubs and received by SigNoz.
For detailed instructions, refer to the Azure documentation: [Azure Event Hub](https://learn.microsoft.com/en-us/azure/event-hubs/event-hubs-create). -->
<!-- For more configuration options, see the [OpenTelemetry Documentation](https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/main/receiver/azureeventhubreceiver). -->

View File

@@ -0,0 +1,29 @@
## Application level Tracing
For application-level tracing, you can use the OpenTelemetry SDKs integrated with your application. These SDKs will automatically collect and forward traces to the Central Collector.
&nbsp;
To see how you can instrument your applications like FastAPI, NextJS, Node.js, Spring etc. you can check out the **Application Monitoring** section available at the start of this onboarding or you can checkout this [documentation](https://signoz.io/docs/instrumentation/).
&nbsp;
## Prerequisites
1. **Azure Subscription & App Service**: You need an active Azure subscription with a running Azure App Service instance.
2. **Central Collector Setup**: Make sure you have set up the Central Collector
&nbsp;
## Configure the OpenTelemetry SDK
```bash
# Set env vars or config file
export OTEL_EXPORTER_OTLP_ENDPOINT="http://<Your-Central-Collector-DNS>:4318/"
```
For application-level traces, configure your application to use the DNS name of the **Central Collector** you set up earlier. This Central Collector will automatically forward the collected data to SigNoz.
&nbsp;
If you encounter any difficulties, please refer to this [troubleshooting section](https://signoz.io/docs/azure-monitoring/az-container-apps/tracing/#troubleshooting)

View File

@@ -0,0 +1,129 @@
Set up the OpenTelemetry Collector on a Virtual Machine (VM). The setup is compatible with cloud VM instances, your own data center, or even a local VM on your development machine. Here's how to do it:
## Download and Install the OpenTelemetry Collector Binary
Please visit [Documentation For VM](https://signoz.io/docs/tutorial/opentelemetry-binary-usage-in-virtual-machine/) which provides further guidance on a VM installation.
&nbsp;
## Configure OpenTelemetry Collector
While following the documentation above for installing the OpenTelemetry Collector Binary, you must have created `config.yaml` file. Replace the content of the `config.yaml` with the below config file which includes the **Azure Monitor receiver**.
```yaml
receivers:
otlp:
protocols:
grpc:
endpoint: 0.0.0.0:4317
http:
endpoint: 0.0.0.0:4318
azureeventhub:
connection: <Primary Connection String>
format: "azure"
azuremonitor:
subscription_id: "<Subscription ID>"
tenant_id: "<AD Tenant ID>"
client_id: "<Client ID>"
client_secret: "<Client Secret>"
resource_groups: ["<rg-1>"]
collection_interval: 60s
processors:
batch: {}
exporters:
otlp:
endpoint: "ingest.{{REGION}}.signoz.cloud:443"
tls:
insecure: false
headers:
"signoz-access-token": "{{SIGNOZ_INGESTION_KEY}}"
service:
pipelines:
metrics/am:
receivers: [azuremonitor]
exporters: [otlp]
traces:
receivers: [otlp]
processors: [batch]
exporters: [otlp]
metrics:
receivers: [otlp]
processors: [batch]
exporters: [otlp]
logs:
receivers: [otlp, azureeventhub]
processors: [batch]
exporters: [otlp]
```
**NOTE:**
Replace the `<Primary Connection String>` in the config file with the primary connection string for your Event Hub that you created in the previous section. It would look something like this:
```bash
Endpoint=sb://namespace.servicebus.windows.net/;SharedAccessKeyName=RootManageSharedAccessKey;SharedAccessKey=superSecret1234=;EntityPath=hubName
```
&nbsp;
## Azure Monitor Receiver Configuration
You will need to set up a [service principal](https://learn.microsoft.com/en-us/entra/identity-platform/howto-create-service-principal-portal) with Read permissions to receive data from Azure Monitor.
1. Follow the steps in the [Create a service principal Azure Doc](https://learn.microsoft.com/en-us/entra/identity-platform/howto-create-service-principal-portal#register-an-application-with-microsoft-entra-id-and-create-a-service-principal) documentation to create a service principal.
You can name it `signoz-central-collector-app` the redirect URI can be empty.
2. To add read permissions to Azure Monitor, Follow the [Assign Role](https://learn.microsoft.com/en-us/entra/identity-platform/howto-create-service-principal-portal#assign-a-role-to-the-application) documentation. The read access can be given to the full subscription.
3. There are multiple ways to authenticate the service principal, we will use the client secret option, follow [Creating a client secret](https://learn.microsoft.com/en-us/entra/identity-platform/howto-create-service-principal-portal#option-3-create-a-new-client-secret) and don't forget to copy the client secret. The secret is used in the configuration file as `client_secret`.
4. To find `client_id` and `tenant_id`, go to the [Azure Portal](https://portal.azure.com/) and search for the `Application` you created. You would see the `Application (client) ID` and `Directory (tenant) ID` in the Overview section.
5. To find `subscription_id`, follow steps in [Find Your Subscription](https://learn.microsoft.com/en-us/azure/azure-portal/get-subscription-tenant-id#find-your-azure-subscription) and populate them in the configuration file.
**NOTE:**
By following the above steps, you will get the values for `<Subscription ID>`, `<AD Tenant ID>`, `<Client ID>` and `<Client Secret>` which you need to fill in the `config.yaml` file.
&nbsp;
## Run the Collector
With your configuration file ready, you can now start the Collector using the following command:
```bash
# Runs in background with the configuration we just created
./otelcol-contrib --config ./config.yaml &> otelcol-output.log & echo "$!" > otel-pid
```
&nbsp;
### Open Ports
You will need to open the following ports on your Azure VM:
- 4317 for gRPC
- 4318 for HTTP
You can do this by navigating to the Azure VM's Networking section and adding a new inbound rule for the ports.
&nbsp;
### Validating the Deployment
Once the Collector is running, ensure that telemetry data is being successfully sent and received. Use the logging exporter as defined in your configuration file, or check the logs for any startup errors.
&nbsp;
## Configure DNS label For Collector
To the IP address of the collector, you can add a DNS label to the Public IP address. This will make it easier to refer to the centralized collector from other services. You can do this by following these steps:
1. Go to the Public IP address of the collector. This would be the IP address of the VM or Load Balancer in case of Kubernetes or Load Balanced collector.
2. Click on the "Configuration" tab.
3. Enter the DNS label you want to use for the collector.
4. Click on "Save".
**NOTE:** Please take note of the DNS label you have entered. You will need this in the next steps.
&nbsp;
If you encounter any difficulties, please refer to this [troubleshooting section](https://signoz.io/docs/azure-monitoring/bootstrapping/collector-setup/#troubleshooting)

View File

@@ -0,0 +1,21 @@
Follow these steps if you want to setup logging for your Azure Functions.
&nbsp;
## Prerequisites
- EventHub Setup
- Central Collector Setup
## Setup
1. Navigate to your Azure Function in the Azure portal
2. Search for "Diagnostic settings" in the left navigation menu
3. Click on "Add Diagnostic Setting"
4. Select the desired log categories to export:
- Function App logs
5. Configure the destination details as "**Stream to an Event Hub**" and select the Event Hub namespace and Event Hub name created during the EventHub Setup
6. Save the diagnostic settings
That's it! You have successfully set up logging for your Azure Function.

View File

@@ -0,0 +1,28 @@
Follow these steps if you want to monitor System metrics like CPU Percentage, Memory Percentage etc. of your Azure Functions.
&nbsp;
## Prerequisites
- Azure subscription and an Azure Container App instance running
- Central Collector Setup
&nbsp;
## Dashboard Example
Once you have completed the prerequisites, you can start monitoring your Azure Function's system metrics with SigNoz. Here's how you can do it:
1. Log in to your SigNoz account.
2. Navigate to the Dashboards, and add an dashboard
3. Add a Timeseries Panel
4. In *Metrics*, select `azure_requests_total` and *Avg By* select tag `location`
5. In Filter say `name = <function-name>`
6. Hit “Save Changes” You now have Total Requests of your Azure Function in a Dashboard for reporting and alerting
That's it! You have successfully set up monitoring for your Azure Function's system metrics with SigNoz.
&nbsp;
If you encounter any difficulties, please refer to this [troubleshooting section](https://signoz.io/docs/azure-monitoring/az-fns/metrics/#troubleshooting)

View File

@@ -0,0 +1,54 @@
## Overview
Azure Event Hubs is a big data streaming platform ideal for centralizing logging and real-time log streaming for applications on Azure or on-premises.
Integrate SigNoz with Azure Event Hubs for a robust log management solution, leveraging SigNoz's log aggregation, querying, visualization, and alerting features.
## Prerequisites
- An active Azure subscription
## Setup
### 1. Create an Event Hubs Namespace
1. In the [Azure portal](https://portal.azure.com), create an Event Hubs namespace.
2. Fill in the required details:
- **Resource group**: Choose or create a new one.
- **Namespace name**: Enter a unique name, e.g., `<orgName>-obs-signoz`.
- **Pricing tier**: Based on your logging requirements.
- **Region**: Should match the region of the resources you want to monitor.
- **Throughput units**: Choose based on logging needs.
3. Click "Review + create" and then "Create".
### 2. Create an Event Hub
1. Navigate to the Event Hubs namespace you created in the Azure portal.
2. Click "+ Event Hub" to create a new event hub.
3. Enter a name, e.g., `logs`and click "Create"
### 3. Create a SAS Policy and Copy Connection String
1. Navigate to the Event Hub in the Azure portal.
2. Click "Shared access policies" in the left menu.
3. Click "Add" to create a new policy named `signozListen`.
4. Select the "Listen" permission and set the expiration time.
5. Click "Save".
6. Copy the *Connection stringprimary key*.
<!-- ### 4. Configure OpenTelemetry Integration
1. Add a new receiver to [Central Collector Setup](../collector-setup).
2. Configure the receiver with the Event Hubs namespace connection string and the event hub name.
### 5. Stream Logs to Event Hubs
1. Configure Azure services' diagnostic settings to forward logs to the Event Hub.
2. Ensure logs are in [Azure Common Log Format](https://learn.microsoft.com/en-us/azure/azure-monitor/essentials/resource-logs-schema).
3. Verify logs are streaming to Event Hubs and received by SigNoz.
For detailed instructions, refer to the Azure documentation: [Azure Event Hub](https://learn.microsoft.com/en-us/azure/event-hubs/event-hubs-create). -->
<!-- For more configuration options, see the [OpenTelemetry Documentation](https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/main/receiver/azureeventhubreceiver). -->

View File

@@ -0,0 +1,29 @@
## Application level Tracing
For application-level tracing, you can use the OpenTelemetry SDKs integrated with your application. These SDKs will automatically collect and forward traces to the Central Collector.
&nbsp;
To see how you can instrument your applications like FastAPI, NextJS, Node.js, Spring etc. you can check out the **Application Monitoring** section available at the start of this onboarding or you can checkout this [documentation](https://signoz.io/docs/instrumentation/).
&nbsp;
## Prerequisites
1. **Azure Subscription & App Service**: You need an active Azure subscription with a running Azure Function App instance.
2. **Central Collector Setup**: Make sure you have set up the Central Collector
&nbsp;
## Configure the OpenTelemetry SDK
```bash
# Set env vars or config file
export OTEL_EXPORTER_OTLP_ENDPOINT="http://<Your-Central-Collector-DNS>:4318/"
```
For application-level traces, configure your application to use the DNS name of the **Central Collector** you set up earlier. This Central Collector will automatically forward the collected data to SigNoz.
&nbsp;
If you encounter any difficulties, please refer to this [troubleshooting section](https://signoz.io/docs/azure-monitoring/az-fns/tracing/#troubleshooting)

View File

@@ -0,0 +1,129 @@
Set up the OpenTelemetry Collector on a Virtual Machine (VM). The setup is compatible with cloud VM instances, your own data center, or even a local VM on your development machine. Here's how to do it:
## Download and Install the OpenTelemetry Collector Binary
Please visit [Documentation For VM](https://signoz.io/docs/tutorial/opentelemetry-binary-usage-in-virtual-machine/) which provides further guidance on a VM installation.
&nbsp;
## Configure OpenTelemetry Collector
While following the documentation above for installing the OpenTelemetry Collector Binary, you must have created `config.yaml` file. Replace the content of the `config.yaml` with the below config file which includes the **Azure Monitor receiver**.
```yaml
receivers:
otlp:
protocols:
grpc:
endpoint: 0.0.0.0:4317
http:
endpoint: 0.0.0.0:4318
azureeventhub:
connection: <Primary Connection String>
format: "azure"
azuremonitor:
subscription_id: "<Subscription ID>"
tenant_id: "<AD Tenant ID>"
client_id: "<Client ID>"
client_secret: "<Client Secret>"
resource_groups: ["<rg-1>"]
collection_interval: 60s
processors:
batch: {}
exporters:
otlp:
endpoint: "ingest.{{REGION}}.signoz.cloud:443"
tls:
insecure: false
headers:
"signoz-access-token": "{{SIGNOZ_INGESTION_KEY}}"
service:
pipelines:
metrics/am:
receivers: [azuremonitor]
exporters: [otlp]
traces:
receivers: [otlp]
processors: [batch]
exporters: [otlp]
metrics:
receivers: [otlp]
processors: [batch]
exporters: [otlp]
logs:
receivers: [otlp, azureeventhub]
processors: [batch]
exporters: [otlp]
```
**NOTE:**
Replace the `<Primary Connection String>` in the config file with the primary connection string for your Event Hub that you created in the previous section. It would look something like this:
```bash
Endpoint=sb://namespace.servicebus.windows.net/;SharedAccessKeyName=RootManageSharedAccessKey;SharedAccessKey=superSecret1234=;EntityPath=hubName
```
&nbsp;
## Azure Monitor Receiver Configuration
You will need to set up a [service principal](https://learn.microsoft.com/en-us/entra/identity-platform/howto-create-service-principal-portal) with Read permissions to receive data from Azure Monitor.
1. Follow the steps in the [Create a service principal Azure Doc](https://learn.microsoft.com/en-us/entra/identity-platform/howto-create-service-principal-portal#register-an-application-with-microsoft-entra-id-and-create-a-service-principal) documentation to create a service principal.
You can name it `signoz-central-collector-app` the redirect URI can be empty.
2. To add read permissions to Azure Monitor, Follow the [Assign Role](https://learn.microsoft.com/en-us/entra/identity-platform/howto-create-service-principal-portal#assign-a-role-to-the-application) documentation. The read access can be given to the full subscription.
3. There are multiple ways to authenticate the service principal, we will use the client secret option, follow [Creating a client secret](https://learn.microsoft.com/en-us/entra/identity-platform/howto-create-service-principal-portal#option-3-create-a-new-client-secret) and don't forget to copy the client secret. The secret is used in the configuration file as `client_secret`.
4. To find `client_id` and `tenant_id`, go to the [Azure Portal](https://portal.azure.com/) and search for the `Application` you created. You would see the `Application (client) ID` and `Directory (tenant) ID` in the Overview section.
5. To find `subscription_id`, follow steps in [Find Your Subscription](https://learn.microsoft.com/en-us/azure/azure-portal/get-subscription-tenant-id#find-your-azure-subscription) and populate them in the configuration file.
**NOTE:**
By following the above steps, you will get the values for `<Subscription ID>`, `<AD Tenant ID>`, `<Client ID>` and `<Client Secret>` which you need to fill in the `config.yaml` file.
&nbsp;
## Run the Collector
With your configuration file ready, you can now start the Collector using the following command:
```bash
# Runs in background with the configuration we just created
./otelcol-contrib --config ./config.yaml &> otelcol-output.log & echo "$!" > otel-pid
```
&nbsp;
### Open Ports
You will need to open the following ports on your Azure VM:
- 4317 for gRPC
- 4318 for HTTP
You can do this by navigating to the Azure VM's Networking section and adding a new inbound rule for the ports.
&nbsp;
### Validating the Deployment
Once the Collector is running, ensure that telemetry data is being successfully sent and received. Use the logging exporter as defined in your configuration file, or check the logs for any startup errors.
&nbsp;
## Configure DNS label For Collector
To the IP address of the collector, you can add a DNS label to the Public IP address. This will make it easier to refer to the centralized collector from other services. You can do this by following these steps:
1. Go to the Public IP address of the collector. This would be the IP address of the VM or Load Balancer in case of Kubernetes or Load Balanced collector.
2. Click on the "Configuration" tab.
3. Enter the DNS label you want to use for the collector.
4. Click on "Save".
**NOTE:** Please take note of the DNS label you have entered. You will need this in the next steps.
&nbsp;
If you encounter any difficulties, please refer to this [troubleshooting section](https://signoz.io/docs/azure-monitoring/bootstrapping/collector-setup/#troubleshooting)

View File

@@ -0,0 +1,31 @@
## Prerequisite
- Azure subscription and Database instance running
- Central Collector Setup
- [SQL monitoring profile](https://learn.microsoft.com/en-us/azure/azure-sql/database/sql-insights-enable?view=azuresql#create-sql-monitoring-profile) created to monitor the databases in Azure Monitor
&nbsp;
## Setup
Once you have completed the prerequisites, you can start monitoring your Database's system metrics with SigNoz. Here's how you can do it:
1. Log in to your SigNoz account.
2. Navigate to the Dashboards Section, and [add an dashboard](https://signoz.io/docs/userguide/manage-dashboards/)
3. Add a Timeseries Panel
4. In **Metrics**, select `azure_storage_maximum` and **Avg By** select tag `location`
5. In Filter say `name = <database-name>`
6. Hit “Save Changes”. You now have Memory Usage of your Database in a Dashboard for reporting and alerting
That's it! You have successfully set up monitoring for your Database's system metrics with SigNoz.
&nbsp;
**NOTE:**
Make sure you have created a sql monitoring profile in Azure Monitor if not, follow this guide to [Create SQL Monitoring Profile](https://learn.microsoft.com/en-us/azure/azure-sql/database/sql-insights-enable?view=azuresql#create-sql-monitoring-profile).
You can monitor multiple databases in a single profile.
&nbsp;
If you encounter any difficulties, please refer to this [troubleshooting section](https://signoz.io/docs/azure-monitoring/db-metrics/#troubleshooting)

View File

@@ -0,0 +1,54 @@
## Overview
Azure Event Hubs is a big data streaming platform ideal for centralizing logging and real-time log streaming for applications on Azure or on-premises.
Integrate SigNoz with Azure Event Hubs for a robust log management solution, leveraging SigNoz's log aggregation, querying, visualization, and alerting features.
## Prerequisites
- An active Azure subscription
## Setup
### 1. Create an Event Hubs Namespace
1. In the [Azure portal](https://portal.azure.com), create an Event Hubs namespace.
2. Fill in the required details:
- **Resource group**: Choose or create a new one.
- **Namespace name**: Enter a unique name, e.g., `<orgName>-obs-signoz`.
- **Pricing tier**: Based on your logging requirements.
- **Region**: Should match the region of the resources you want to monitor.
- **Throughput units**: Choose based on logging needs.
3. Click "Review + create" and then "Create".
### 2. Create an Event Hub
1. Navigate to the Event Hubs namespace you created in the Azure portal.
2. Click "+ Event Hub" to create a new event hub.
3. Enter a name, e.g., `logs`and click "Create"
### 3. Create a SAS Policy and Copy Connection String
1. Navigate to the Event Hub in the Azure portal.
2. Click "Shared access policies" in the left menu.
3. Click "Add" to create a new policy named `signozListen`.
4. Select the "Listen" permission and set the expiration time.
5. Click "Save".
6. Copy the *Connection stringprimary key*.
<!-- ### 4. Configure OpenTelemetry Integration
1. Add a new receiver to [Central Collector Setup](../collector-setup).
2. Configure the receiver with the Event Hubs namespace connection string and the event hub name.
### 5. Stream Logs to Event Hubs
1. Configure Azure services' diagnostic settings to forward logs to the Event Hub.
2. Ensure logs are in [Azure Common Log Format](https://learn.microsoft.com/en-us/azure/azure-monitor/essentials/resource-logs-schema).
3. Verify logs are streaming to Event Hubs and received by SigNoz.
For detailed instructions, refer to the Azure documentation: [Azure Event Hub](https://learn.microsoft.com/en-us/azure/event-hubs/event-hubs-create). -->
<!-- For more configuration options, see the [OpenTelemetry Documentation](https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/main/receiver/azureeventhubreceiver). -->

View File

@@ -0,0 +1,134 @@
## Prerequisites
- An Azure subscription with Azure VM and SSH access enabled
- Central Collector Setup
### Connect to the VM
The [SSH Keys Guide](https://learn.microsoft.com/en-us/azure/virtual-machines/ssh-keys-portal#connect-to-the-vm) has steps on how to connect to your VM via SSH.
&nbsp;
### Install OpenTelemetry Collector
Follow the [OpenTelemetry SigNoz documentation](https://signoz.io/docs/tutorial/opentelemetry-binary-usage-in-virtual-machine/) to install the OpenTelemetry Collector.
&nbsp;
### Configure Collector
We send the logs, traces and metrics to the central collector that we set up in the previous step instead of SigNoz directly, in order to adopt a scalable architecture pattern. We recommend to our users to use the same pattern in your Azure subscription.
Replace the content of the `config.yaml` file that you created while installing the collector.
```yaml
receivers:
filelog:
include: [ <file paths> ] # /var/log/myservice/*.json
operators:
- type: json_parser
timestamp:
parse_from: attributes.time
layout: '%Y-%m-%d %H:%M:%S'
otlp:
protocols:
grpc:
endpoint: 0.0.0.0:4317
http:
endpoint: 0.0.0.0:4318
hostmetrics:
collection_interval: 60s
scrapers:
cpu: {}
disk: {}
load: {}
filesystem: {}
memory: {}
network: {}
paging: {}
process:
mute_process_name_error: true
mute_process_exe_error: true
mute_process_io_error: true
processes: {}
prometheus:
config:
global:
scrape_interval: 60s
scrape_configs:
- job_name: otel-collector-binary
static_configs:
- targets:
# - localhost:8888
processors:
batch:
send_batch_size: 1000
timeout: 10s
# Ref: https://github.com/open-telemetry/opentelemetry-collector-contrib/blob/main/processor/resourcedetectionprocessor/README.md
resourcedetection:
detectors: [env, azure, system]
# Using OTEL_RESOURCE_ATTRIBUTES envvar, env detector adds custom labels.
timeout: 2s
system:
hostname_sources: [dns, os]
extensions:
health_check: {}
zpages: {}
exporters:
otlp:
endpoint: "<Central Collector DNS Name>:4318"
logging:
verbosity: normal
service:
telemetry:
metrics:
address: 0.0.0.0:8888
extensions: [health_check, zpages]
pipelines:
metrics:
receivers: [otlp]
processors: [batch]
exporters: [otlp]
metrics/internal:
receivers: [prometheus, hostmetrics]
processors: [resourcedetection, batch]
exporters: [otlp]
traces:
receivers: [otlp]
processors: [batch]
exporters: [otlp]
logs:
receivers: [otlp, filelog]
processors: [batch]
exporters: [otlp]
```
&nbsp;
#### OLTP Exporter Configuration
Make sure to replace `<Central Collector DNS Name>` with the DNS name of your central collector that you set up earlier.
&nbsp;
#### File Logs Receiver Configuration
The file logs receiver needs to be configured with the paths to the log files that you want to stream to SigNoz. You can specify multiple paths by separating them as a array.
You can also specify globed path patterns to match multiple log files. For example, `/var/log/myservice/*.json` will match all log files in the `/var/log/myservice` directory with a `.json` extension.
&nbsp;
### Start the OpenTelemetry Collector
Once we are done with the above configurations, we can now run the collector service with the following command:
```bash
./otelcol-contrib --config ./config.yaml &> otelcol-output.log & echo "$!" > otel-pid
```
&nbsp;
### Hostmetrics Dashboard
Once the collector is running, you can access the SigNoz dashboard to view the logs and metrics from your Azure VM.
Please refer to the [Hostmetrics Dashboard](https://signoz.io/docs/userguide/hostmetrics/) for information on how to import and use the dashboard.

View File

@@ -0,0 +1,129 @@
Set up the OpenTelemetry Collector on a Virtual Machine (VM). The setup is compatible with cloud VM instances, your own data center, or even a local VM on your development machine. Here's how to do it:
## Download and Install the OpenTelemetry Collector Binary
Please visit [Documentation For VM](https://signoz.io/docs/tutorial/opentelemetry-binary-usage-in-virtual-machine/) which provides further guidance on a VM installation.
&nbsp;
## Configure OpenTelemetry Collector
While following the documentation above for installing the OpenTelemetry Collector Binary, you must have created `config.yaml` file. Replace the content of the `config.yaml` with the below config file which includes the **Azure Monitor receiver**.
```yaml
receivers:
otlp:
protocols:
grpc:
endpoint: 0.0.0.0:4317
http:
endpoint: 0.0.0.0:4318
azureeventhub:
connection: <Primary Connection String>
format: "azure"
azuremonitor:
subscription_id: "<Subscription ID>"
tenant_id: "<AD Tenant ID>"
client_id: "<Client ID>"
client_secret: "<Client Secret>"
resource_groups: ["<rg-1>"]
collection_interval: 60s
processors:
batch: {}
exporters:
otlp:
endpoint: "ingest.{{REGION}}.signoz.cloud:443"
tls:
insecure: false
headers:
"signoz-access-token": "{{SIGNOZ_INGESTION_KEY}}"
service:
pipelines:
metrics/am:
receivers: [azuremonitor]
exporters: [otlp]
traces:
receivers: [otlp]
processors: [batch]
exporters: [otlp]
metrics:
receivers: [otlp]
processors: [batch]
exporters: [otlp]
logs:
receivers: [otlp, azureeventhub]
processors: [batch]
exporters: [otlp]
```
**NOTE:**
Replace the `<Primary Connection String>` in the config file with the primary connection string for your Event Hub that you created in the previous section. It would look something like this:
```bash
Endpoint=sb://namespace.servicebus.windows.net/;SharedAccessKeyName=RootManageSharedAccessKey;SharedAccessKey=superSecret1234=;EntityPath=hubName
```
&nbsp;
## Azure Monitor Receiver Configuration
You will need to set up a [service principal](https://learn.microsoft.com/en-us/entra/identity-platform/howto-create-service-principal-portal) with Read permissions to receive data from Azure Monitor.
1. Follow the steps in the [Create a service principal Azure Doc](https://learn.microsoft.com/en-us/entra/identity-platform/howto-create-service-principal-portal#register-an-application-with-microsoft-entra-id-and-create-a-service-principal) documentation to create a service principal.
You can name it `signoz-central-collector-app` the redirect URI can be empty.
2. To add read permissions to Azure Monitor, Follow the [Assign Role](https://learn.microsoft.com/en-us/entra/identity-platform/howto-create-service-principal-portal#assign-a-role-to-the-application) documentation. The read access can be given to the full subscription.
3. There are multiple ways to authenticate the service principal, we will use the client secret option, follow [Creating a client secret](https://learn.microsoft.com/en-us/entra/identity-platform/howto-create-service-principal-portal#option-3-create-a-new-client-secret) and don't forget to copy the client secret. The secret is used in the configuration file as `client_secret`.
4. To find `client_id` and `tenant_id`, go to the [Azure Portal](https://portal.azure.com/) and search for the `Application` you created. You would see the `Application (client) ID` and `Directory (tenant) ID` in the Overview section.
5. To find `subscription_id`, follow steps in [Find Your Subscription](https://learn.microsoft.com/en-us/azure/azure-portal/get-subscription-tenant-id#find-your-azure-subscription) and populate them in the configuration file.
**NOTE:**
By following the above steps, you will get the values for `<Subscription ID>`, `<AD Tenant ID>`, `<Client ID>` and `<Client Secret>` which you need to fill in the `config.yaml` file.
&nbsp;
## Run the Collector
With your configuration file ready, you can now start the Collector using the following command:
```bash
# Runs in background with the configuration we just created
./otelcol-contrib --config ./config.yaml &> otelcol-output.log & echo "$!" > otel-pid
```
&nbsp;
### Open Ports
You will need to open the following ports on your Azure VM:
- 4317 for gRPC
- 4318 for HTTP
You can do this by navigating to the Azure VM's Networking section and adding a new inbound rule for the ports.
&nbsp;
### Validating the Deployment
Once the Collector is running, ensure that telemetry data is being successfully sent and received. Use the logging exporter as defined in your configuration file, or check the logs for any startup errors.
&nbsp;
## Configure DNS label For Collector
To the IP address of the collector, you can add a DNS label to the Public IP address. This will make it easier to refer to the centralized collector from other services. You can do this by following these steps:
1. Go to the Public IP address of the collector. This would be the IP address of the VM or Load Balancer in case of Kubernetes or Load Balanced collector.
2. Click on the "Configuration" tab.
3. Enter the DNS label you want to use for the collector.
4. Click on "Save".
**NOTE:** Please take note of the DNS label you have entered. You will need this in the next steps.
&nbsp;
If you encounter any difficulties, please refer to this [troubleshooting section](https://signoz.io/docs/azure-monitoring/bootstrapping/collector-setup/#troubleshooting)

View File

@@ -0,0 +1,54 @@
## Overview
Azure Event Hubs is a big data streaming platform ideal for centralizing logging and real-time log streaming for applications on Azure or on-premises.
Integrate SigNoz with Azure Event Hubs for a robust log management solution, leveraging SigNoz's log aggregation, querying, visualization, and alerting features.
## Prerequisites
- An active Azure subscription
## Setup
### 1. Create an Event Hubs Namespace
1. In the [Azure portal](https://portal.azure.com), create an Event Hubs namespace.
2. Fill in the required details:
- **Resource group**: Choose or create a new one.
- **Namespace name**: Enter a unique name, e.g., `<orgName>-obs-signoz`.
- **Pricing tier**: Based on your logging requirements.
- **Region**: Should match the region of the resources you want to monitor.
- **Throughput units**: Choose based on logging needs.
3. Click "Review + create" and then "Create".
### 2. Create an Event Hub
1. Navigate to the Event Hubs namespace you created in the Azure portal.
2. Click "+ Event Hub" to create a new event hub.
3. Enter a name, e.g., `logs`and click "Create"
### 3. Create a SAS Policy and Copy Connection String
1. Navigate to the Event Hub in the Azure portal.
2. Click "Shared access policies" in the left menu.
3. Click "Add" to create a new policy named `signozListen`.
4. Select the "Listen" permission and set the expiration time.
5. Click "Save".
6. Copy the *Connection stringprimary key*.
<!-- ### 4. Configure OpenTelemetry Integration
1. Add a new receiver to [Central Collector Setup](../collector-setup).
2. Configure the receiver with the Event Hubs namespace connection string and the event hub name.
### 5. Stream Logs to Event Hubs
1. Configure Azure services' diagnostic settings to forward logs to the Event Hub.
2. Ensure logs are in [Azure Common Log Format](https://learn.microsoft.com/en-us/azure/azure-monitor/essentials/resource-logs-schema).
3. Verify logs are streaming to Event Hubs and received by SigNoz.
For detailed instructions, refer to the Azure documentation: [Azure Event Hub](https://learn.microsoft.com/en-us/azure/event-hubs/event-hubs-create). -->
<!-- For more configuration options, see the [OpenTelemetry Documentation](https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/main/receiver/azureeventhubreceiver). -->

View File

@@ -31,7 +31,7 @@
.onboardingHeader {
text-align: center;
margin-top: 48px;
margin-top: 24px;
}
.onboardingHeader h1 {
@@ -51,13 +51,14 @@
justify-content: center;
gap: 36px;
margin: 36px;
flex-wrap: wrap;
}
.moduleStyles {
padding: 0;
box-sizing: border-box;
cursor: pointer;
width: 400px;
width: 300px;
transition: 0.3s;
.ant-card-body {

View File

@@ -25,6 +25,7 @@ import { DataSourceType } from './Steps/DataSource/DataSource';
import {
defaultApplicationDataSource,
defaultAwsServices,
defaultAzureServices,
defaultInfraMetricsType,
defaultLogsType,
moduleRouteMap,
@@ -32,6 +33,7 @@ import {
import {
APM_STEPS,
AWS_MONITORING_STEPS,
AZURE_MONITORING_STEPS,
getSteps,
INFRASTRUCTURE_MONITORING_STEPS,
LOGS_MANAGEMENT_STEPS,
@@ -42,6 +44,7 @@ export enum ModulesMap {
LogsManagement = 'LogsManagement',
InfrastructureMonitoring = 'InfrastructureMonitoring',
AwsMonitoring = 'AwsMonitoring',
AzureMonitoring = 'AzureMonitoring',
}
export interface ModuleProps {
@@ -81,6 +84,12 @@ export const useCases = {
desc:
'Monitor your traces, logs and metrics for AWS services like EC2, ECS, EKS etc.',
},
AzureMonitoring: {
id: ModulesMap.AzureMonitoring,
title: 'Azure Monitoring',
desc:
'Monitor your traces, logs and metrics for Azure services like AKS, Container Apps, App Service etc.',
},
};
export default function Onboarding(): JSX.Element {
@@ -172,6 +181,7 @@ export default function Onboarding(): JSX.Element {
setSelectedModuleSteps(APM_STEPS);
};
// eslint-disable-next-line sonarjs/cognitive-complexity
useEffect(() => {
if (selectedModule?.id === ModulesMap.InfrastructureMonitoring) {
if (selectedDataSource) {
@@ -194,6 +204,13 @@ export default function Onboarding(): JSX.Element {
setSelectedModuleSteps(AWS_MONITORING_STEPS);
updateSelectedDataSource(defaultAwsServices);
}
} else if (selectedModule?.id === ModulesMap.AzureMonitoring) {
if (selectedDataSource) {
setModuleStepsBasedOnSelectedDataSource(selectedDataSource);
} else {
setSelectedModuleSteps(AZURE_MONITORING_STEPS);
updateSelectedDataSource(defaultAzureServices);
}
} else if (selectedModule?.id === ModulesMap.APM) {
handleAPMSteps();
@@ -240,18 +257,24 @@ export default function Onboarding(): JSX.Element {
};
useEffect(() => {
if (location.pathname === ROUTES.GET_STARTED_APPLICATION_MONITORING) {
const { pathname } = location;
if (pathname === ROUTES.GET_STARTED_APPLICATION_MONITORING) {
handleModuleSelect(useCases.APM);
updateSelectedDataSource(defaultApplicationDataSource);
handleNextStep();
} else if (
location.pathname === ROUTES.GET_STARTED_INFRASTRUCTURE_MONITORING
) {
} else if (pathname === ROUTES.GET_STARTED_INFRASTRUCTURE_MONITORING) {
handleModuleSelect(useCases.InfrastructureMonitoring);
handleNextStep();
} else if (location.pathname === ROUTES.GET_STARTED_LOGS_MANAGEMENT) {
} else if (pathname === ROUTES.GET_STARTED_LOGS_MANAGEMENT) {
handleModuleSelect(useCases.LogsManagement);
handleNextStep();
} else if (pathname === ROUTES.GET_STARTED_AWS_MONITORING) {
handleModuleSelect(useCases.AwsMonitoring);
handleNextStep();
} else if (pathname === ROUTES.GET_STARTED_AZURE_MONITORING) {
handleModuleSelect(useCases.AzureMonitoring);
handleNextStep();
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);

View File

@@ -2,6 +2,7 @@
import { MarkdownRenderer } from 'components/MarkdownRenderer/MarkdownRenderer';
import { ApmDocFilePaths } from 'container/OnboardingContainer/constants/apmDocFilePaths';
import { AwsMonitoringDocFilePaths } from 'container/OnboardingContainer/constants/awsMonitoringDocFilePaths';
import { AzureMonitoringDocFilePaths } from 'container/OnboardingContainer/constants/azureMonitoringDocFilePaths';
import { InfraMonitoringDocFilePaths } from 'container/OnboardingContainer/constants/infraMonitoringDocFilePaths';
import { LogsManagementDocFilePaths } from 'container/OnboardingContainer/constants/logsManagementDocFilePaths';
import {
@@ -69,6 +70,8 @@ export default function MarkdownStep(): JSX.Element {
docFilePaths = InfraMonitoringDocFilePaths;
} else if (selectedModule?.id === ModulesMap.AwsMonitoring) {
docFilePaths = AwsMonitoringDocFilePaths;
} else if (selectedModule?.id === ModulesMap.AzureMonitoring) {
docFilePaths = AzureMonitoringDocFilePaths;
}
// @ts-ignore
if (docFilePaths && docFilePaths[path]) {

View File

@@ -0,0 +1,82 @@
import AzureMonitoring_azureAks_setupCentralCollector from '../Modules/AzureMonitoring/AKS/aks-installCentralCollector.md';
import AzureMonitoring_azureAks_sendLogs from '../Modules/AzureMonitoring/AKS/aks-logs.md';
import AzureMonitoring_azureAks_sendMetrics from '../Modules/AzureMonitoring/AKS/aks-metrics.md';
import AzureMonitoring_azureAks_setupAzureEventsHub from '../Modules/AzureMonitoring/AKS/aks-setupEventsHub.md';
import AzureMonitoring_azureAks_sendTraces from '../Modules/AzureMonitoring/AKS/aks-tracing.md';
// Azure App Service
import AzureMonitoring_azureAppService_setupCentralCollector from '../Modules/AzureMonitoring/AppService/appService-installCentralCollector.md';
import AzureMonitoring_azureAppService_sendLogs from '../Modules/AzureMonitoring/AppService/appService-logs.md';
import AzureMonitoring_azureAppService_sendMetrics from '../Modules/AzureMonitoring/AppService/appService-metrics.md';
import AzureMonitoring_azureAppService_setupAzureEventsHub from '../Modules/AzureMonitoring/AppService/appService-setupEventsHub.md';
import AzureMonitoring_azureAppService_sendTraces from '../Modules/AzureMonitoring/AppService/appService-tracing.md';
// Azure Blob Storage
import AzureMonitoring_azureBlobStorage_setupCentralCollector from '../Modules/AzureMonitoring/BlobStorage/blobStorage-installCentralCollector.md';
import AzureMonitoring_azureBlobStorage_sendLogs from '../Modules/AzureMonitoring/BlobStorage/blobStorage-logs.md';
import AzureMonitoring_azureBlobStorage_sendMetrics from '../Modules/AzureMonitoring/BlobStorage/blobStorage-metrics.md';
import AzureMonitoring_azureBlobStorage_setupAzureEventsHub from '../Modules/AzureMonitoring/BlobStorage/blobStorage-setupEventsHub.md';
// Azure Container Apps
import AzureMonitoring_azureContainerApps_setupCentralCollector from '../Modules/AzureMonitoring/ContainerApps/containerApps-installCentralCollector.md';
import AzureMonitoring_azureContainerApps_sendLogs from '../Modules/AzureMonitoring/ContainerApps/containerApps-logs.md';
import AzureMonitoring_azureContainerApps_sendMetrics from '../Modules/AzureMonitoring/ContainerApps/containerApps-metrics.md';
import AzureMonitoring_azureContainerApps_setupAzureEventsHub from '../Modules/AzureMonitoring/ContainerApps/containerApps-setupEventsHub.md';
import AzureMonitoring_azureContainerApps_sendTraces from '../Modules/AzureMonitoring/ContainerApps/containerApps-tracing.md';
// Azure Functions
import AzureMonitoring_azureFunctions_setupCentralCollector from '../Modules/AzureMonitoring/Functions/functions-installCentralCollector.md';
import AzureMonitoring_azureFunctions_sendLogs from '../Modules/AzureMonitoring/Functions/functions-logs.md';
import AzureMonitoring_azureFunctions_sendMetrics from '../Modules/AzureMonitoring/Functions/functions-metrics.md';
import AzureMonitoring_azureFunctions_setupAzureEventsHub from '../Modules/AzureMonitoring/Functions/functions-setupEventsHub.md';
import AzureMonitoring_azureFunctions_sendTraces from '../Modules/AzureMonitoring/Functions/functions-tracing.md';
// Azure SQL Database Metrics
import AzureMonitoring_azureSQLDatabaseMetrics_setupCentralCollector from '../Modules/AzureMonitoring/SqlDatabaseMetrics/sqlDatabaseMetrics-installCentralCollector.md';
import AzureMonitoring_azureSQLDatabaseMetrics_sendMetrics from '../Modules/AzureMonitoring/SqlDatabaseMetrics/sqlDatabaseMetrics-metrics.md';
import AzureMonitoring_azureSQLDatabaseMetrics_setupAzureEventsHub from '../Modules/AzureMonitoring/SqlDatabaseMetrics/sqlDatabaseMetrics-setupEventsHub.md';
import AzureMonitoring_azureVm_sendHostmetricsLogs from '../Modules/AzureMonitoring/Vm/vm-hostmetrics-and-logs.md';
// Azure VM
import AzureMonitoring_azureVm_setupCentralCollector from '../Modules/AzureMonitoring/Vm/vm-installCentralCollector.md';
import AzureMonitoring_azureVm_setupAzureEventsHub from '../Modules/AzureMonitoring/Vm/vm-setupEventsHub.md';
export const AzureMonitoringDocFilePaths = {
// Azure AKS
AzureMonitoring_azureAks_setupCentralCollector,
AzureMonitoring_azureAks_setupAzureEventsHub,
AzureMonitoring_azureAks_sendTraces,
AzureMonitoring_azureAks_sendLogs,
AzureMonitoring_azureAks_sendMetrics,
// Azure App Service
AzureMonitoring_azureFunctions_setupCentralCollector,
AzureMonitoring_azureFunctions_setupAzureEventsHub,
AzureMonitoring_azureFunctions_sendTraces,
AzureMonitoring_azureFunctions_sendLogs,
AzureMonitoring_azureFunctions_sendMetrics,
// Azure Functions
AzureMonitoring_azureAppService_setupCentralCollector,
AzureMonitoring_azureAppService_setupAzureEventsHub,
AzureMonitoring_azureAppService_sendTraces,
AzureMonitoring_azureAppService_sendLogs,
AzureMonitoring_azureAppService_sendMetrics,
// Azure Container Apps
AzureMonitoring_azureContainerApps_setupCentralCollector,
AzureMonitoring_azureContainerApps_setupAzureEventsHub,
AzureMonitoring_azureContainerApps_sendTraces,
AzureMonitoring_azureContainerApps_sendLogs,
AzureMonitoring_azureContainerApps_sendMetrics,
// Azure VM
AzureMonitoring_azureVm_setupCentralCollector,
AzureMonitoring_azureVm_setupAzureEventsHub,
AzureMonitoring_azureVm_sendHostmetricsLogs,
// Azure SQL Database Metrics
AzureMonitoring_azureSQLDatabaseMetrics_setupCentralCollector,
AzureMonitoring_azureSQLDatabaseMetrics_setupAzureEventsHub,
AzureMonitoring_azureSQLDatabaseMetrics_sendMetrics,
// Azure Blob Storage
AzureMonitoring_azureBlobStorage_setupCentralCollector,
AzureMonitoring_azureBlobStorage_setupAzureEventsHub,
AzureMonitoring_azureBlobStorage_sendLogs,
AzureMonitoring_azureBlobStorage_sendMetrics,
};

View File

@@ -35,6 +35,12 @@ export const stepsMap = {
deployTaskDefinition: `deployTaskDefinition`,
ecsSendLogsData: `ecsSendLogsData`,
monitorDashboard: `monitorDashboard`,
setupCentralCollector: `setupCentralCollector`,
setupAzureEventsHub: `setupAzureEventsHub`,
sendTraces: `sendTraces`,
sendLogs: `sendLogs`,
sendMetrics: `sendMetrics`,
sendHostmetricsLogs: `sendHostmetricsLogs`,
};
export const DataSourceStep: SelectedModuleStepProps = {
@@ -201,3 +207,33 @@ export const MonitorDashboard: SelectedModuleStepProps = {
title: 'Monitor using Dashboard ',
component: <MarkdownStep />,
};
export const SetupCentralCollectorStep: SelectedModuleStepProps = {
id: stepsMap.setupCentralCollector,
title: 'Setup Central Collector ',
component: <MarkdownStep />,
};
export const SetupAzureEventsHub: SelectedModuleStepProps = {
id: stepsMap.setupAzureEventsHub,
title: 'Setup EventsHub',
component: <MarkdownStep />,
};
export const SendTraces: SelectedModuleStepProps = {
id: stepsMap.sendTraces,
title: 'Send Traces',
component: <MarkdownStep />,
};
export const SendLogs: SelectedModuleStepProps = {
id: stepsMap.sendLogs,
title: 'Send Logs',
component: <MarkdownStep />,
};
export const SendMetrics: SelectedModuleStepProps = {
id: stepsMap.sendMetrics,
title: 'Send Metrics',
component: <MarkdownStep />,
};
export const SendHostmetricsLogs: SelectedModuleStepProps = {
id: stepsMap.sendHostmetricsLogs,
title: 'HostMetrics and Logging',
component: <MarkdownStep />,
};

View File

@@ -8,6 +8,7 @@ export enum ModulesMap {
LogsManagement = 'LogsManagement',
InfrastructureMonitoring = 'InfrastructureMonitoring',
AwsMonitoring = 'AwsMonitoring',
AzureMonitoring = 'AzureMonitoring',
}
export const frameworksMap = {
@@ -82,6 +83,7 @@ export const frameworksMap = {
LogsManagement: {},
InfrastructureMonitoring: {},
AwsMonitoring: {},
AzureMonitoring: {},
};
export const defaultApplicationDataSource = {
@@ -270,6 +272,50 @@ const supportedAwsServices = [
},
];
export const defaultAzureServices = {
name: 'VM',
id: 'azureVm',
imgURL: `/Logos/azure-vm.svg`,
};
const supportedAzureServices = [
{
name: 'VM',
id: 'azureVm',
imgURL: `/Logos/azure-vm.svg`,
},
{
name: 'App Service',
id: 'azureAppService',
imgURL: `/Logos/azure-app-service.svg`,
},
{
name: 'AKS',
id: 'azureAks',
imgURL: `/Logos/azure-aks.svg`,
},
{
name: 'Azure Functions',
id: 'azureFunctions',
imgURL: `/Logos/azure-functions.svg`,
},
{
name: 'Azure Container Apps',
id: 'azureContainerApps',
imgURL: `/Logos/azure-container-apps.svg`,
},
{
name: 'SQL Database Metrics',
id: 'azureSQLDatabaseMetrics',
imgURL: `/Logos/azure-sql-database-metrics.svg`,
},
{
name: 'Azure Blob Storage',
id: 'azureBlobStorage',
imgURL: `/Logos/azure-blob-storage.svg`,
},
];
export const getDataSources = (module: ModuleProps): DataSourceType[] => {
if (module.id === ModulesMap.APM) {
return supportedLanguages;
@@ -283,7 +329,11 @@ export const getDataSources = (module: ModuleProps): DataSourceType[] => {
return supportedLogsTypes;
}
return supportedAwsServices;
if (module.id === ModulesMap.AwsMonitoring) {
return supportedAwsServices;
}
return supportedAzureServices;
};
export const getSupportedFrameworks = ({
@@ -347,4 +397,5 @@ export const moduleRouteMap = {
[ModulesMap.InfrastructureMonitoring]:
ROUTES.GET_STARTED_INFRASTRUCTURE_MONITORING,
[ModulesMap.AwsMonitoring]: ROUTES.GET_STARTED_AWS_MONITORING,
[ModulesMap.AzureMonitoring]: ROUTES.GET_STARTED_AZURE_MONITORING,
};

View File

@@ -22,7 +22,13 @@ import {
RestartOtelCollector,
RunApplicationStep,
SelectMethodStep,
SendHostmetricsLogs,
SendLogs,
SendLogsCloudwatch,
SendMetrics,
SendTraces,
SetupAzureEventsHub,
SetupCentralCollectorStep,
SetupDaemonService,
SetupLogDrains,
SetupOtelCollectorStep,
@@ -57,6 +63,10 @@ export const INFRASTRUCTURE_MONITORING_STEPS: SelectedModuleStepProps[] = [
export const AWS_MONITORING_STEPS: SelectedModuleStepProps[] = [DataSourceStep];
export const AZURE_MONITORING_STEPS: SelectedModuleStepProps[] = [
DataSourceStep,
];
export const getSteps = ({
selectedDataSource,
}: GetStepsProps): SelectedModuleStepProps[] => {
@@ -144,6 +154,70 @@ export const getSteps = ({
];
case 'awsEks':
return [DataSourceStep, SetupOtelCollectorStep, MonitorDashboard];
case 'azureVm':
return [
DataSourceStep,
SetupAzureEventsHub,
SetupCentralCollectorStep,
SendHostmetricsLogs,
];
// eslint-disable-next-line sonarjs/no-duplicated-branches
case 'azureAks':
return [
DataSourceStep,
SetupAzureEventsHub,
SetupCentralCollectorStep,
SendTraces,
SendLogs,
SendMetrics,
];
// eslint-disable-next-line sonarjs/no-duplicated-branches
case 'azureAppService':
return [
DataSourceStep,
SetupAzureEventsHub,
SetupCentralCollectorStep,
SendTraces,
SendLogs,
SendMetrics,
];
// eslint-disable-next-line sonarjs/no-duplicated-branches
case 'azureFunctions':
return [
DataSourceStep,
SetupAzureEventsHub,
SetupCentralCollectorStep,
SendTraces,
SendLogs,
SendMetrics,
];
// eslint-disable-next-line sonarjs/no-duplicated-branches
case 'azureContainerApps':
return [
DataSourceStep,
SetupAzureEventsHub,
SetupCentralCollectorStep,
SendTraces,
SendLogs,
SendMetrics,
];
// eslint-disable-next-line sonarjs/no-duplicated-branches
case 'azureBlobStorage':
return [
DataSourceStep,
SetupAzureEventsHub,
SetupCentralCollectorStep,
SendLogs,
SendMetrics,
];
// eslint-disable-next-line sonarjs/no-duplicated-branches
case 'azureSQLDatabaseMetrics':
return [
DataSourceStep,
SetupAzureEventsHub,
SetupCentralCollectorStep,
SendMetrics,
];
default:
return [DataSourceStep];

View File

@@ -0,0 +1,37 @@
import { act, render, screen, waitFor } from 'tests/test-utils';
import Members from '../Members';
describe('Organization Settings Page', () => {
afterEach(() => {
jest.clearAllMocks();
});
it('render list of members', async () => {
act(() => {
render(<Members />);
});
const title = await screen.findByText(/Members/i);
expect(title).toBeInTheDocument();
await waitFor(() => {
expect(screen.getByText('firstUser@test.io')).toBeInTheDocument(); // first item
expect(screen.getByText('lastUser@test.io')).toBeInTheDocument(); // last item
});
});
// this is required as our edit/delete logic is dependent on the index and it will break with pagination enabled
it('render list of members without pagination', async () => {
render(<Members />);
await waitFor(() => {
expect(screen.getByText('firstUser@test.io')).toBeInTheDocument(); // first item
expect(screen.getByText('lastUser@test.io')).toBeInTheDocument(); // last item
expect(
document.querySelector('.ant-table-pagination'),
).not.toBeInTheDocument();
});
});
});

View File

@@ -9,7 +9,7 @@ function TablePanelWrapper({
tableProcessedDataRef,
}: PanelWrapperProps): JSX.Element {
const panelData =
queryResponse.data?.payload?.data?.newResult?.data?.result || [];
(queryResponse.data?.payload?.data?.result?.[0] as any)?.table || [];
const { thresholds } = widget;
return (
<GridTableComponent

View File

@@ -1,3 +1,4 @@
export const historyPagination = {
defaultPageSize: 5,
hideOnSinglePage: true,
};

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