diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index afd70250c4..2781d2a0c6 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -2,5 +2,6 @@ # Owners are automatically requested for review for PRs that changes code # that they own. * @ankitnayan -/frontend/ @palash-signoz @pranshuchittora +/frontend/ @palashgdev @pranshuchittora /deploy/ @prashant-shahi +/pkg/query-service/ @srikanthccv @makeavish @nityanandagohain diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index f9096698cc..8f346bf882 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -17,6 +17,8 @@ jobs: run: cd frontend && yarn install - name: Run ESLint run: cd frontend && npm run lint + - name: Run Jest + run: cd frontend && npm run jest - name: TSC run: yarn tsc working-directory: ./frontend diff --git a/.github/workflows/codeball.yml b/.github/workflows/codeball.yml new file mode 100644 index 0000000000..ed69d5c10e --- /dev/null +++ b/.github/workflows/codeball.yml @@ -0,0 +1,17 @@ +name: Codeball +on: [pull_request] + +jobs: + codeball_job: + runs-on: ubuntu-latest + name: Codeball + steps: + # Run Codeball on all new Pull Requests 🚀 + # For customizations and more documentation, see https://github.com/sturdy-dev/codeball-action + - name: Codeball + uses: sturdy-dev/codeball-action@v2 + with: + approvePullRequests: "true" + labelPullRequestsWhenApproved: "true" + labelPullRequestsWhenReviewNeeded: "false" + failJobsWhenReviewNeeded: "false" diff --git a/.github/workflows/playwright.yaml b/.github/workflows/playwright.yaml index be8108e6ef..0a6addfaeb 100644 --- a/.github/workflows/playwright.yaml +++ b/.github/workflows/playwright.yaml @@ -1,22 +1,24 @@ name: Playwright Tests -on: - deployment_status: +on: [pull_request] + jobs: - test: + playwright: + defaults: + run: + working-directory: frontend timeout-minutes: 60 runs-on: ubuntu-latest - if: github.event.deployment_status.state == 'success' steps: - uses: actions/checkout@v2 - uses: actions/setup-node@v2 with: - node-version: "14.x" + node-version: "16.x" - name: Install dependencies - run: npm ci + run: CI=1 yarn install - name: Install Playwright run: npx playwright install --with-deps - name: Run Playwright tests - run: npm run test:e2e + run: yarn playwright env: # This might depend on your test-runner/language binding - PLAYWRIGHT_TEST_BASE_URL: ${{ github.event.deployment_status.target_url }} + PLAYWRIGHT_TEST_BASE_URL: ${{ secrets.PLAYWRIGHT_TEST_BASE_URL }} diff --git a/deploy/docker-swarm/clickhouse-setup/clickhouse-config.xml b/deploy/docker-swarm/clickhouse-setup/clickhouse-config.xml index 7a5f40d299..3bb26a3a36 100644 --- a/deploy/docker-swarm/clickhouse-setup/clickhouse-config.xml +++ b/deploy/docker-swarm/clickhouse-setup/clickhouse-config.xml @@ -1,137 +1,567 @@ - + + - information - 1 + + trace + /var/log/clickhouse-server/clickhouse-server.log + /var/log/clickhouse-server/clickhouse-server.err.log + + 1000M + 10 + + + + + + + + + + + + + + + 8123 + + 9000 - - + + 9004 - - - - - /etc/clickhouse-server/server.crt - /etc/clickhouse-server/server.key - - /etc/clickhouse-server/dhparam.pem - none - true - true - sslv2,sslv3 - true - + + 9005 - - true - true - sslv2,sslv3 - true - - - - RejectCertificateHandler - - - + + - - + + + + - - + + 9009 - -9009 + + + If not specified, then it is determined analogous to 'hostname -f' command. + This setting could be used to switch replication to another network interface + (the server may be connected to multiple networks via multiple addresses) + --> + + example.clickhouse.com + --> - -:: - - + + - - + + -4096 -3 - -100 + + + + + + + + + + + + + + + 4096 + + + 3 + + + + + false + + + /path/to/ssl_cert_file + /path/to/ssl_key_file + + + false + + + /path/to/ssl_ca_cert_file + + + none + + + 0 + + + -1 + -1 + + + false + + + + + + + /etc/clickhouse-server/server.crt + /etc/clickhouse-server/server.key + + + none + true + true + sslv2,sslv3 + true + + + + true + true + sslv2,sslv3 + true + + + + RejectCertificateHandler + + + + + + + + + 100 + + + 0 + + + + 10000 + + + + + + 0.9 + + + 4194304 + + + 0 + correct maximum value. --> - 8589934592 + + Note: uncompressed cache can be pointless for lz4, because memory bandwidth + is slower than multi-core decompression on some server configurations. + Enabling it can sometimes paradoxically make queries slower. + --> + 8589934592 - 5368709120 + --> + 5368709120 - - /var/lib/clickhouse/ + + 1000 - - /var/lib/clickhouse/tmp/ + + 134217728 - - users.xml + + 10000 - - default + + /var/lib/clickhouse/ - - default + + /var/lib/clickhouse/tmp/ + + + + ` + + + + + + /var/lib/clickhouse/user_files/ + + + + + + + + + + + + + users.xml + + + + /var/lib/clickhouse/access/ + + + + + + + default + + + + + + + + + + + + default - + Example: Zulu is an alias for UTC. + --> + - + --> + + + + true + + + false + + ' | sed -e 's|.*>\(.*\)<.*|\1|') + wget https://github.com/ClickHouse/clickhouse-jdbc-bridge/releases/download/v$PKG_VER/clickhouse-jdbc-bridge_$PKG_VER-1_all.deb + apt install --no-install-recommends -f ./clickhouse-jdbc-bridge_$PKG_VER-1_all.deb + clickhouse-jdbc-bridge & + + * [CentOS/RHEL] + export MVN_URL=https://repo1.maven.org/maven2/ru/yandex/clickhouse/clickhouse-jdbc-bridge + export PKG_VER=$(curl -sL $MVN_URL/maven-metadata.xml | grep '' | sed -e 's|.*>\(.*\)<.*|\1|') + wget https://github.com/ClickHouse/clickhouse-jdbc-bridge/releases/download/v$PKG_VER/clickhouse-jdbc-bridge-$PKG_VER-1.noarch.rpm + yum localinstall -y clickhouse-jdbc-bridge-$PKG_VER-1.noarch.rpm + clickhouse-jdbc-bridge & + + Please refer to https://github.com/ClickHouse/clickhouse-jdbc-bridge#usage for more information. + ]]> + - + https://clickhouse.com/docs/en/operations/table_engines/distributed/ + --> + + + + + + + + + + + localhost + 9000 + + + + + + + + false + + 127.0.0.1 + 9000 + + + 127.0.0.2 + 9000 + + + 127.0.0.3 + 9000 + + + + + + + + localhost + 9000 + + + + + localhost + 9000 + + + + + + + 127.0.0.1 + 9000 + + + + + 127.0.0.2 + 9000 + + + + + + true + + 127.0.0.1 + 9000 + + + + true + + 127.0.0.2 + 9000 + + + + + + + localhost + 9440 + 1 + + + + localhost 9000 - + + + localhost + 1 + + + + + + + + + + Values for substitutions are specified in /clickhouse/name_of_substitution elements in that file. + --> - + See https://clickhouse.com/docs/en/engines/table-engines/mergetree-family/replication/ + --> + + - + See https://clickhouse.com/docs/en/engines/table-engines/mergetree-family/replication/#creating-replicated-tables + --> + - - 3600 + + 3600 - - 3600 + + 3600 - - 60 + + 60 - + + --> + + + - + true + true + true + true + + --> + + + + system + query_log
+ + toYYYYMM(event_date) + + + - system - query_log
- - 7500 -
+ + 7500 +
+ + + system + trace_log
- + + system + query_thread_log
+ toYYYYMM(event_date) + 7500 +
+ + + + system + query_views_log
+ toYYYYMM(event_date) + 7500 +
+ + system part_log
- + toYYYYMM(event_date) 7500
---> + + + + + + system + metric_log
+ 7500 + 1000 +
+ + + + system + asynchronous_metric_log
+ + 7000 +
+ + + + + + engine MergeTree + partition by toYYYYMM(finish_date) + order by (finish_date, finish_time_us, trace_id) + + system + opentelemetry_span_log
+ 7500 +
- + + + system + crash_log
- - + + 1000 +
- - + + + + + + system + processors_profile_log
+ + toYYYYMM(event_date) + 7500 +
+ + + + + + - *_dictionary.xml + https://clickhouse.com/docs/en/sql-reference/dictionaries/external-dictionaries/external-dicts + --> + *_dictionary.xml + + + *_function.xml - + --> - + + + + + + + + + + + + + + + + + + + + + + + + + Works only if ZooKeeper is enabled. Comment it if such functionality isn't required. --> /clickhouse/task_queue/ddl + + + + + + + + + + + + + + + + + @@ -304,239 +1149,156 @@ 5 ---> + --> - + --> + + - - - + + - ^carbon\. + click_cost any 0 + 3600 + + + 86400 60 - - 7776000 - 3600 - - - 10368000 - 21600 - - - 34560000 - 43200 - - - 63072000 - 86400 - - - 94608000 - 604800 - - - - ^collectd\. - any - - 0 - 10 - - - 43200 - 60 - - - 864000 - 900 - - - 1728000 - 1800 - - - 3456000 - 3600 - - - 10368000 - 21600 - - - 34560000 - 43200 - - - 63072000 - 86400 - - - 94608000 - 604800 - - - - - ^high\. - any - - 0 - 10 - - - 172800 - 60 - - - 864000 - 900 - - - 1728000 - 1800 - - - 3456000 - 3600 - - - 10368000 - 21600 - - - 34560000 - 43200 - - - 63072000 - 86400 - - - 94608000 - 604800 - - - - - ^medium\. - any - - 0 - 60 - - - 864000 - 900 - - - 1728000 - 1800 - - - 3456000 - 3600 - - - 10368000 - 21600 - - - 34560000 - 43200 - - - 63072000 - 86400 - - - 94608000 - 604800 - - - - - ^low\. - any - - 0 - 600 - - - 15552000 - 1800 - - - 31536000 - 3600 - - - 63072000 - 21600 - - - 126144000 - 43200 - - - 252288000 - 86400 - - - 315360000 - 604800 - - - - any + max 0 60 - 864000 - 900 + 3600 + 300 - 1728000 - 1800 - - - 3456000 + 86400 3600 - - 10368000 - 21600 - - - 34560000 - 43200 - - - 63072000 - 86400 - - - 94608000 - 604800 - - + - /var/lib/clickhouse/format_schemas/ -
+ --> + /var/lib/clickhouse/format_schemas/ + + + + + hide encrypt/decrypt arguments + ((?:aes_)?(?:encrypt|decrypt)(?:_mysql)?)\s*\(\s*(?:'(?:\\'|.)+'|.*?)\s*\) + + \1(???) + + + + + + + + + + false + + false + + + https://6f33034cfe684dd7a3ab9875e57b1c8d@o388870.ingest.sentry.io/5226277 + + + + + + + + + + + 268435456 + true + + diff --git a/deploy/docker-swarm/clickhouse-setup/clickhouse-storage.xml b/deploy/docker-swarm/clickhouse-setup/clickhouse-storage.xml new file mode 100644 index 0000000000..aab0c15da7 --- /dev/null +++ b/deploy/docker-swarm/clickhouse-setup/clickhouse-storage.xml @@ -0,0 +1,28 @@ + + + + + + 10485760 + + + s3 + https://BUCKET-NAME.s3.amazonaws.com/data/ + ACCESS-KEY-ID + SECRET-ACCESS-KEY + + + + + + + default + + + s3 + + + + + + diff --git a/deploy/docker-swarm/clickhouse-setup/clickhouse-users.xml b/deploy/docker-swarm/clickhouse-setup/clickhouse-users.xml new file mode 100644 index 0000000000..f18562071d --- /dev/null +++ b/deploy/docker-swarm/clickhouse-setup/clickhouse-users.xml @@ -0,0 +1,123 @@ + + + + + + + + + + 10000000000 + + + random + + + + + 1 + + + + + + + + + + + + + ::/0 + + + + default + + + default + + + + + + + + + + + + + + 3600 + + + 0 + 0 + 0 + 0 + 0 + + + + diff --git a/deploy/docker-swarm/clickhouse-setup/docker-compose.yaml b/deploy/docker-swarm/clickhouse-setup/docker-compose.yaml index bc58e956b5..4f27360876 100644 --- a/deploy/docker-swarm/clickhouse-setup/docker-compose.yaml +++ b/deploy/docker-swarm/clickhouse-setup/docker-compose.yaml @@ -2,12 +2,14 @@ version: "3.9" services: clickhouse: - image: yandex/clickhouse-server:21.12.3.32 + image: clickhouse/clickhouse-server:22.4.5-alpine # ports: # - "9000:9000" # - "8123:8123" volumes: - ./clickhouse-config.xml:/etc/clickhouse-server/config.xml + - ./clickhouse-users.xml:/etc/clickhouse-server/users.xml + # - ./clickhouse-storage.xml:/etc/clickhouse-server/config.d/storage.xml - ./data/clickhouse/:/var/lib/clickhouse/ deploy: restart_policy: @@ -37,7 +39,7 @@ services: condition: on-failure query-service: - image: signoz/query-service:0.8.2 + image: signoz/query-service:0.9.0 command: ["-config=/root/config/prometheus.yml"] # ports: # - "6060:6060" # pprof port @@ -65,7 +67,7 @@ services: - clickhouse frontend: - image: signoz/frontend:0.8.2 + image: signoz/frontend:0.9.0 deploy: restart_policy: condition: on-failure @@ -78,7 +80,7 @@ services: - ../common/nginx-config.conf:/etc/nginx/conf.d/default.conf otel-collector: - image: signoz/otelcontribcol:0.45.1-0.3 + image: signoz/otelcontribcol:0.45.1-1.0 command: ["--config=/etc/otel-collector-config.yaml"] volumes: - ./otel-collector-config.yaml:/etc/otel-collector-config.yaml @@ -104,7 +106,7 @@ services: - clickhouse otel-collector-metrics: - image: signoz/otelcontribcol:0.45.1-0.3 + image: signoz/otelcontribcol:0.45.1-1.0 command: ["--config=/etc/otel-collector-metrics-config.yaml"] volumes: - ./otel-collector-metrics-config.yaml:/etc/otel-collector-metrics-config.yaml diff --git a/deploy/docker-swarm/clickhouse-setup/otel-collector-config.yaml b/deploy/docker-swarm/clickhouse-setup/otel-collector-config.yaml index 5f65e6eb5c..a998d93ab9 100644 --- a/deploy/docker-swarm/clickhouse-setup/otel-collector-config.yaml +++ b/deploy/docker-swarm/clickhouse-setup/otel-collector-config.yaml @@ -12,7 +12,7 @@ receivers: grpc: thrift_http: hostmetrics: - collection_interval: 30s + collection_interval: 60s scrapers: cpu: load: @@ -22,7 +22,8 @@ receivers: network: processors: batch: - send_batch_size: 1000 + send_batch_size: 10000 + send_batch_max_size: 11000 timeout: 10s signozspanmetrics/prometheus: metrics_exporter: prometheus diff --git a/deploy/docker-swarm/clickhouse-setup/otel-collector-metrics-config.yaml b/deploy/docker-swarm/clickhouse-setup/otel-collector-metrics-config.yaml index 0563a397da..3aa39b5f7e 100644 --- a/deploy/docker-swarm/clickhouse-setup/otel-collector-metrics-config.yaml +++ b/deploy/docker-swarm/clickhouse-setup/otel-collector-metrics-config.yaml @@ -9,12 +9,13 @@ receivers: config: scrape_configs: - job_name: "otel-collector" - scrape_interval: 30s + scrape_interval: 60s static_configs: - targets: ["otel-collector:8889"] processors: batch: - send_batch_size: 1000 + send_batch_size: 10000 + send_batch_max_size: 11000 timeout: 10s # memory_limiter: # # 80% of maximum memory up to 2G diff --git a/deploy/docker/clickhouse-setup/clickhouse-config.xml b/deploy/docker/clickhouse-setup/clickhouse-config.xml index 7a5f40d299..3bb26a3a36 100644 --- a/deploy/docker/clickhouse-setup/clickhouse-config.xml +++ b/deploy/docker/clickhouse-setup/clickhouse-config.xml @@ -1,137 +1,567 @@ - + + - information - 1 + + trace + /var/log/clickhouse-server/clickhouse-server.log + /var/log/clickhouse-server/clickhouse-server.err.log + + 1000M + 10 + + + + + + + + + + + + + + + 8123 + + 9000 - - + + 9004 - - - - - /etc/clickhouse-server/server.crt - /etc/clickhouse-server/server.key - - /etc/clickhouse-server/dhparam.pem - none - true - true - sslv2,sslv3 - true - + + 9005 - - true - true - sslv2,sslv3 - true - - - - RejectCertificateHandler - - - + + - - + + + + - - + + 9009 - -9009 + + + If not specified, then it is determined analogous to 'hostname -f' command. + This setting could be used to switch replication to another network interface + (the server may be connected to multiple networks via multiple addresses) + --> + + example.clickhouse.com + --> - -:: - - + + - - + + -4096 -3 - -100 + + + + + + + + + + + + + + + 4096 + + + 3 + + + + + false + + + /path/to/ssl_cert_file + /path/to/ssl_key_file + + + false + + + /path/to/ssl_ca_cert_file + + + none + + + 0 + + + -1 + -1 + + + false + + + + + + + /etc/clickhouse-server/server.crt + /etc/clickhouse-server/server.key + + + none + true + true + sslv2,sslv3 + true + + + + true + true + sslv2,sslv3 + true + + + + RejectCertificateHandler + + + + + + + + + 100 + + + 0 + + + + 10000 + + + + + + 0.9 + + + 4194304 + + + 0 + correct maximum value. --> - 8589934592 + + Note: uncompressed cache can be pointless for lz4, because memory bandwidth + is slower than multi-core decompression on some server configurations. + Enabling it can sometimes paradoxically make queries slower. + --> + 8589934592 - 5368709120 + --> + 5368709120 - - /var/lib/clickhouse/ + + 1000 - - /var/lib/clickhouse/tmp/ + + 134217728 - - users.xml + + 10000 - - default + + /var/lib/clickhouse/ - - default + + /var/lib/clickhouse/tmp/ + + + + ` + + + + + + /var/lib/clickhouse/user_files/ + + + + + + + + + + + + + users.xml + + + + /var/lib/clickhouse/access/ + + + + + + + default + + + + + + + + + + + + default - + Example: Zulu is an alias for UTC. + --> + - + --> + + + + true + + + false + + ' | sed -e 's|.*>\(.*\)<.*|\1|') + wget https://github.com/ClickHouse/clickhouse-jdbc-bridge/releases/download/v$PKG_VER/clickhouse-jdbc-bridge_$PKG_VER-1_all.deb + apt install --no-install-recommends -f ./clickhouse-jdbc-bridge_$PKG_VER-1_all.deb + clickhouse-jdbc-bridge & + + * [CentOS/RHEL] + export MVN_URL=https://repo1.maven.org/maven2/ru/yandex/clickhouse/clickhouse-jdbc-bridge + export PKG_VER=$(curl -sL $MVN_URL/maven-metadata.xml | grep '' | sed -e 's|.*>\(.*\)<.*|\1|') + wget https://github.com/ClickHouse/clickhouse-jdbc-bridge/releases/download/v$PKG_VER/clickhouse-jdbc-bridge-$PKG_VER-1.noarch.rpm + yum localinstall -y clickhouse-jdbc-bridge-$PKG_VER-1.noarch.rpm + clickhouse-jdbc-bridge & + + Please refer to https://github.com/ClickHouse/clickhouse-jdbc-bridge#usage for more information. + ]]> + - + https://clickhouse.com/docs/en/operations/table_engines/distributed/ + --> + + + + + + + + + + + localhost + 9000 + + + + + + + + false + + 127.0.0.1 + 9000 + + + 127.0.0.2 + 9000 + + + 127.0.0.3 + 9000 + + + + + + + + localhost + 9000 + + + + + localhost + 9000 + + + + + + + 127.0.0.1 + 9000 + + + + + 127.0.0.2 + 9000 + + + + + + true + + 127.0.0.1 + 9000 + + + + true + + 127.0.0.2 + 9000 + + + + + + + localhost + 9440 + 1 + + + + localhost 9000 - + + + localhost + 1 + + + + + + + + + + Values for substitutions are specified in /clickhouse/name_of_substitution elements in that file. + --> - + See https://clickhouse.com/docs/en/engines/table-engines/mergetree-family/replication/ + --> + + - + See https://clickhouse.com/docs/en/engines/table-engines/mergetree-family/replication/#creating-replicated-tables + --> + - - 3600 + + 3600 - - 3600 + + 3600 - - 60 + + 60 - + + --> + + + - + true + true + true + true + + --> + + + + system + query_log
+ + toYYYYMM(event_date) + + + - system - query_log
- - 7500 -
+ + 7500 +
+ + + system + trace_log
- + + system + query_thread_log
+ toYYYYMM(event_date) + 7500 +
+ + + + system + query_views_log
+ toYYYYMM(event_date) + 7500 +
+ + system part_log
- + toYYYYMM(event_date) 7500
---> + + + + + + system + metric_log
+ 7500 + 1000 +
+ + + + system + asynchronous_metric_log
+ + 7000 +
+ + + + + + engine MergeTree + partition by toYYYYMM(finish_date) + order by (finish_date, finish_time_us, trace_id) + + system + opentelemetry_span_log
+ 7500 +
- + + + system + crash_log
- - + + 1000 +
- - + + + + + + system + processors_profile_log
+ + toYYYYMM(event_date) + 7500 +
+ + + + + + - *_dictionary.xml + https://clickhouse.com/docs/en/sql-reference/dictionaries/external-dictionaries/external-dicts + --> + *_dictionary.xml + + + *_function.xml - + --> - + + + + + + + + + + + + + + + + + + + + + + + + + Works only if ZooKeeper is enabled. Comment it if such functionality isn't required. --> /clickhouse/task_queue/ddl + + + + + + + + + + + + + + + + + @@ -304,239 +1149,156 @@ 5 ---> + --> - + --> + + - - - + + - ^carbon\. + click_cost any 0 + 3600 + + + 86400 60 - - 7776000 - 3600 - - - 10368000 - 21600 - - - 34560000 - 43200 - - - 63072000 - 86400 - - - 94608000 - 604800 - - - - ^collectd\. - any - - 0 - 10 - - - 43200 - 60 - - - 864000 - 900 - - - 1728000 - 1800 - - - 3456000 - 3600 - - - 10368000 - 21600 - - - 34560000 - 43200 - - - 63072000 - 86400 - - - 94608000 - 604800 - - - - - ^high\. - any - - 0 - 10 - - - 172800 - 60 - - - 864000 - 900 - - - 1728000 - 1800 - - - 3456000 - 3600 - - - 10368000 - 21600 - - - 34560000 - 43200 - - - 63072000 - 86400 - - - 94608000 - 604800 - - - - - ^medium\. - any - - 0 - 60 - - - 864000 - 900 - - - 1728000 - 1800 - - - 3456000 - 3600 - - - 10368000 - 21600 - - - 34560000 - 43200 - - - 63072000 - 86400 - - - 94608000 - 604800 - - - - - ^low\. - any - - 0 - 600 - - - 15552000 - 1800 - - - 31536000 - 3600 - - - 63072000 - 21600 - - - 126144000 - 43200 - - - 252288000 - 86400 - - - 315360000 - 604800 - - - - any + max 0 60 - 864000 - 900 + 3600 + 300 - 1728000 - 1800 - - - 3456000 + 86400 3600 - - 10368000 - 21600 - - - 34560000 - 43200 - - - 63072000 - 86400 - - - 94608000 - 604800 - - + - /var/lib/clickhouse/format_schemas/ -
+ --> + /var/lib/clickhouse/format_schemas/ + + + + + hide encrypt/decrypt arguments + ((?:aes_)?(?:encrypt|decrypt)(?:_mysql)?)\s*\(\s*(?:'(?:\\'|.)+'|.*?)\s*\) + + \1(???) + + + + + + + + + + false + + false + + + https://6f33034cfe684dd7a3ab9875e57b1c8d@o388870.ingest.sentry.io/5226277 + + + + + + + + + + + 268435456 + true + + diff --git a/deploy/docker/clickhouse-setup/clickhouse-storage.xml b/deploy/docker/clickhouse-setup/clickhouse-storage.xml new file mode 100644 index 0000000000..aab0c15da7 --- /dev/null +++ b/deploy/docker/clickhouse-setup/clickhouse-storage.xml @@ -0,0 +1,28 @@ + + + + + + 10485760 + + + s3 + https://BUCKET-NAME.s3.amazonaws.com/data/ + ACCESS-KEY-ID + SECRET-ACCESS-KEY + + + + + + + default + + + s3 + + + + + + diff --git a/deploy/docker/clickhouse-setup/clickhouse-users.xml b/deploy/docker/clickhouse-setup/clickhouse-users.xml new file mode 100644 index 0000000000..f18562071d --- /dev/null +++ b/deploy/docker/clickhouse-setup/clickhouse-users.xml @@ -0,0 +1,123 @@ + + + + + + + + + + 10000000000 + + + random + + + + + 1 + + + + + + + + + + + + + ::/0 + + + + default + + + default + + + + + + + + + + + + + + 3600 + + + 0 + 0 + 0 + 0 + 0 + + + + diff --git a/deploy/docker/clickhouse-setup/config.xml b/deploy/docker/clickhouse-setup/config.xml new file mode 100644 index 0000000000..3bb26a3a36 --- /dev/null +++ b/deploy/docker/clickhouse-setup/config.xml @@ -0,0 +1,1304 @@ + + + + + + trace + /var/log/clickhouse-server/clickhouse-server.log + /var/log/clickhouse-server/clickhouse-server.err.log + + 1000M + 10 + + + + + + + + + + + + + + + + + + 8123 + + + 9000 + + + 9004 + + + 9005 + + + + + + + + + + + + 9009 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 4096 + + + 3 + + + + + false + + + /path/to/ssl_cert_file + /path/to/ssl_key_file + + + false + + + /path/to/ssl_ca_cert_file + + + none + + + 0 + + + -1 + -1 + + + false + + + + + + + /etc/clickhouse-server/server.crt + /etc/clickhouse-server/server.key + + + none + true + true + sslv2,sslv3 + true + + + + true + true + sslv2,sslv3 + true + + + + RejectCertificateHandler + + + + + + + + + 100 + + + 0 + + + + 10000 + + + + + + 0.9 + + + 4194304 + + + 0 + + + + + + 8589934592 + + + 5368709120 + + + + 1000 + + + 134217728 + + + 10000 + + + /var/lib/clickhouse/ + + + /var/lib/clickhouse/tmp/ + + + + ` + + + + + + /var/lib/clickhouse/user_files/ + + + + + + + + + + + + + users.xml + + + + /var/lib/clickhouse/access/ + + + + + + + default + + + + + + + + + + + + default + + + + + + + + + true + + + false + + ' | sed -e 's|.*>\(.*\)<.*|\1|') + wget https://github.com/ClickHouse/clickhouse-jdbc-bridge/releases/download/v$PKG_VER/clickhouse-jdbc-bridge_$PKG_VER-1_all.deb + apt install --no-install-recommends -f ./clickhouse-jdbc-bridge_$PKG_VER-1_all.deb + clickhouse-jdbc-bridge & + + * [CentOS/RHEL] + export MVN_URL=https://repo1.maven.org/maven2/ru/yandex/clickhouse/clickhouse-jdbc-bridge + export PKG_VER=$(curl -sL $MVN_URL/maven-metadata.xml | grep '' | sed -e 's|.*>\(.*\)<.*|\1|') + wget https://github.com/ClickHouse/clickhouse-jdbc-bridge/releases/download/v$PKG_VER/clickhouse-jdbc-bridge-$PKG_VER-1.noarch.rpm + yum localinstall -y clickhouse-jdbc-bridge-$PKG_VER-1.noarch.rpm + clickhouse-jdbc-bridge & + + Please refer to https://github.com/ClickHouse/clickhouse-jdbc-bridge#usage for more information. + ]]> + + + + + + + + + + + + + + + + localhost + 9000 + + + + + + + + false + + 127.0.0.1 + 9000 + + + 127.0.0.2 + 9000 + + + 127.0.0.3 + 9000 + + + + + + + + localhost + 9000 + + + + + localhost + 9000 + + + + + + + 127.0.0.1 + 9000 + + + + + 127.0.0.2 + 9000 + + + + + + true + + 127.0.0.1 + 9000 + + + + true + + 127.0.0.2 + 9000 + + + + + + + localhost + 9440 + 1 + + + + + + + localhost + 9000 + + + + + localhost + 1 + + + + + + + + + + + + + + + + + + + + + + + + 3600 + + + + 3600 + + + 60 + + + + + + + + + + + + + system + query_log
+ + toYYYYMM(event_date) + + + + + + 7500 +
+ + + + system + trace_log
+ + toYYYYMM(event_date) + 7500 +
+ + + + system + query_thread_log
+ toYYYYMM(event_date) + 7500 +
+ + + + system + query_views_log
+ toYYYYMM(event_date) + 7500 +
+ + + + system + part_log
+ toYYYYMM(event_date) + 7500 +
+ + + + + + system + metric_log
+ 7500 + 1000 +
+ + + + system + asynchronous_metric_log
+ + 7000 +
+ + + + + + engine MergeTree + partition by toYYYYMM(finish_date) + order by (finish_date, finish_time_us, trace_id) + + system + opentelemetry_span_log
+ 7500 +
+ + + + + system + crash_log
+ + + 1000 +
+ + + + + + + system + processors_profile_log
+ + toYYYYMM(event_date) + 7500 +
+ + + + + + + + + *_dictionary.xml + + + *_function.xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + /clickhouse/task_queue/ddl + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + click_cost + any + + 0 + 3600 + + + 86400 + 60 + + + + max + + 0 + 60 + + + 3600 + 300 + + + 86400 + 3600 + + + + + + /var/lib/clickhouse/format_schemas/ + + + + + hide encrypt/decrypt arguments + ((?:aes_)?(?:encrypt|decrypt)(?:_mysql)?)\s*\(\s*(?:'(?:\\'|.)+'|.*?)\s*\) + + \1(???) + + + + + + + + + + false + + false + + + https://6f33034cfe684dd7a3ab9875e57b1c8d@o388870.ingest.sentry.io/5226277 + + + + + + + + + + + 268435456 + true + +
diff --git a/deploy/docker/clickhouse-setup/docker-compose.arm.yaml b/deploy/docker/clickhouse-setup/docker-compose.arm.yaml deleted file mode 100644 index c30bf82064..0000000000 --- a/deploy/docker/clickhouse-setup/docker-compose.arm.yaml +++ /dev/null @@ -1,133 +0,0 @@ -version: "2.4" - -services: - clickhouse: - image: altinity/clickhouse-server:21.12.3.32.altinitydev.arm - # ports: - # - "9000:9000" - # - "8123:8123" - volumes: - - ./clickhouse-config.xml:/etc/clickhouse-server/config.xml - - ./data/clickhouse/:/var/lib/clickhouse/ - restart: on-failure - logging: - options: - max-size: 50m - max-file: "3" - healthcheck: - # "clickhouse", "client", "-u ${CLICKHOUSE_USER}", "--password ${CLICKHOUSE_PASSWORD}", "-q 'SELECT 1'" - test: ["CMD", "wget", "--spider", "-q", "localhost:8123/ping"] - interval: 30s - timeout: 5s - retries: 3 - - alertmanager: - image: signoz/alertmanager:0.23.0-0.1 - volumes: - - ./data/alertmanager:/data - depends_on: - query-service: - condition: service_healthy - restart: on-failure - command: - - --queryService.url=http://query-service:8085 - - --storage.path=/data - -# Notes for Maintainers/Contributors who will change Line Numbers of Frontend & Query-Section. Please Update Line Numbers in `./scripts/commentLinesForSetup.sh` & `./CONTRIBUTING.md` - - - query-service: - image: signoz/query-service:0.8.2 - container_name: query-service - command: ["-config=/root/config/prometheus.yml"] - # ports: - # - "6060:6060" # pprof port - # - "8080:8080" # query-service port - volumes: - - ./prometheus.yml:/root/config/prometheus.yml - - ../dashboards:/root/config/dashboards - - ./data/signoz/:/var/lib/signoz/ - environment: - - ClickHouseUrl=tcp://clickhouse:9000/?database=signoz_traces - - STORAGE=clickhouse - - GODEBUG=netdns=go - - TELEMETRY_ENABLED=true - - DEPLOYMENT_TYPE=docker-standalone-arm - restart: on-failure - healthcheck: - test: ["CMD", "wget", "--spider", "-q", "localhost:8080/api/v1/version"] - interval: 30s - timeout: 5s - retries: 3 - depends_on: - clickhouse: - condition: service_healthy - - frontend: - image: signoz/frontend:0.8.2 - container_name: frontend - restart: on-failure - depends_on: - - alertmanager - - query-service - ports: - - "3301:3301" - volumes: - - ../common/nginx-config.conf:/etc/nginx/conf.d/default.conf - - otel-collector: - image: signoz/otelcontribcol:0.45.1-0.3 - command: ["--config=/etc/otel-collector-config.yaml"] - volumes: - - ./otel-collector-config.yaml:/etc/otel-collector-config.yaml - ports: - - "4317:4317" # OTLP gRPC receiver - - "4318:4318" # OTLP HTTP receiver - # - "8889:8889" # Prometheus metrics exposed by the agent - # - "13133:13133" # health_check - # - "14268:14268" # Jaeger receiver - # - "55678:55678" # OpenCensus receiver - # - "55679:55679" # zpages extension - # - "55680:55680" # OTLP gRPC legacy receiver - # - "55681:55681" # OTLP HTTP legacy receiver - mem_limit: 2000m - restart: on-failure - depends_on: - clickhouse: - condition: service_healthy - - otel-collector-metrics: - image: signoz/otelcontribcol:0.45.1-0.3 - command: ["--config=/etc/otel-collector-metrics-config.yaml"] - volumes: - - ./otel-collector-metrics-config.yaml:/etc/otel-collector-metrics-config.yaml - restart: on-failure - depends_on: - clickhouse: - condition: service_healthy - - hotrod: - image: jaegertracing/example-hotrod:1.30 - container_name: hotrod - logging: - options: - max-size: 50m - max-file: "3" - command: ["all"] - environment: - - JAEGER_ENDPOINT=http://otel-collector:14268/api/traces - - load-hotrod: - image: "grubykarol/locust:1.2.3-python3.9-alpine3.12" - container_name: load-hotrod - hostname: load-hotrod - environment: - ATTACKED_HOST: http://hotrod:8080 - LOCUST_MODE: standalone - NO_PROXY: standalone - TASK_DELAY_FROM: 5 - TASK_DELAY_TO: 30 - QUIET_MODE: "${QUIET_MODE:-false}" - LOCUST_OPTS: "--headless -u 10 -r 1" - volumes: - - ../common/locust-scripts:/locust diff --git a/deploy/docker/clickhouse-setup/docker-compose.yaml b/deploy/docker/clickhouse-setup/docker-compose.yaml index 44a0e25554..8ce015e298 100644 --- a/deploy/docker/clickhouse-setup/docker-compose.yaml +++ b/deploy/docker/clickhouse-setup/docker-compose.yaml @@ -2,12 +2,14 @@ version: "2.4" services: clickhouse: - image: yandex/clickhouse-server:21.12.3.32 + image: clickhouse/clickhouse-server:22.4.5-alpine # ports: # - "9000:9000" # - "8123:8123" volumes: - ./clickhouse-config.xml:/etc/clickhouse-server/config.xml + - ./clickhouse-users.xml:/etc/clickhouse-server/users.xml + # - ./clickhouse-storage.xml:/etc/clickhouse-server/config.d/storage.xml - ./data/clickhouse/:/var/lib/clickhouse/ restart: on-failure logging: @@ -36,7 +38,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:0.8.2 + image: signoz/query-service:0.9.0 container_name: query-service command: ["-config=/root/config/prometheus.yml"] # ports: @@ -63,7 +65,7 @@ services: condition: service_healthy frontend: - image: signoz/frontend:0.8.2 + image: signoz/frontend:0.9.0 container_name: frontend restart: on-failure depends_on: @@ -75,7 +77,7 @@ services: - ../common/nginx-config.conf:/etc/nginx/conf.d/default.conf otel-collector: - image: signoz/otelcontribcol:0.45.1-0.3 + image: signoz/otelcontribcol:0.45.1-1.0 command: ["--config=/etc/otel-collector-config.yaml"] volumes: - ./otel-collector-config.yaml:/etc/otel-collector-config.yaml @@ -96,7 +98,7 @@ services: condition: service_healthy otel-collector-metrics: - image: signoz/otelcontribcol:0.45.1-0.3 + image: signoz/otelcontribcol:0.45.1-1.0 command: ["--config=/etc/otel-collector-metrics-config.yaml"] volumes: - ./otel-collector-metrics-config.yaml:/etc/otel-collector-metrics-config.yaml diff --git a/deploy/docker/clickhouse-setup/otel-collector-config.yaml b/deploy/docker/clickhouse-setup/otel-collector-config.yaml index bcf7ce58ce..e363f015df 100644 --- a/deploy/docker/clickhouse-setup/otel-collector-config.yaml +++ b/deploy/docker/clickhouse-setup/otel-collector-config.yaml @@ -12,7 +12,7 @@ receivers: grpc: thrift_http: hostmetrics: - collection_interval: 30s + collection_interval: 60s scrapers: cpu: load: @@ -22,7 +22,8 @@ receivers: network: processors: batch: - send_batch_size: 1000 + send_batch_size: 10000 + send_batch_max_size: 11000 timeout: 10s signozspanmetrics/prometheus: metrics_exporter: prometheus diff --git a/deploy/docker/clickhouse-setup/otel-collector-metrics-config.yaml b/deploy/docker/clickhouse-setup/otel-collector-metrics-config.yaml index cd5ede2358..26c629ba60 100644 --- a/deploy/docker/clickhouse-setup/otel-collector-metrics-config.yaml +++ b/deploy/docker/clickhouse-setup/otel-collector-metrics-config.yaml @@ -9,12 +9,13 @@ receivers: config: scrape_configs: - job_name: "otel-collector" - scrape_interval: 30s + scrape_interval: 60s static_configs: - targets: ["otel-collector:8889"] processors: batch: - send_batch_size: 1000 + send_batch_size: 10000 + send_batch_max_size: 11000 timeout: 10s # memory_limiter: # # 80% of maximum memory up to 2G diff --git a/deploy/docker/clickhouse-setup/users.xml b/deploy/docker/clickhouse-setup/users.xml new file mode 100644 index 0000000000..f18562071d --- /dev/null +++ b/deploy/docker/clickhouse-setup/users.xml @@ -0,0 +1,123 @@ + + + + + + + + + + 10000000000 + + + random + + + + + 1 + + + + + + + + + + + + + ::/0 + + + + default + + + default + + + + + + + + + + + + + + 3600 + + + 0 + 0 + 0 + 0 + 0 + + + + diff --git a/deploy/docker/common/nginx-config.conf b/deploy/docker/common/nginx-config.conf index 705656bb6e..99615f1f60 100644 --- a/deploy/docker/common/nginx-config.conf +++ b/deploy/docker/common/nginx-config.conf @@ -11,6 +11,11 @@ server { gzip_buffers 16 8k; gzip_http_version 1.1; + # to handle uri issue 414 from nginx + client_max_body_size 24M; + + large_client_header_buffers 8 16k; + location / { if ( $uri = '/index.html' ) { add_header Cache-Control no-store always; diff --git a/deploy/install.sh b/deploy/install.sh index 12814c8980..492336a566 100755 --- a/deploy/install.sh +++ b/deploy/install.sh @@ -36,9 +36,9 @@ is_mac() { [[ $OSTYPE == darwin* ]] } -is_arm64(){ - [[ `uname -m` == 'arm64' ]] -} +# is_arm64(){ +# [[ `uname -m` == 'arm64' ]] +# } check_os() { if is_mac; then @@ -237,11 +237,7 @@ bye() { # Prints a friendly good bye message and exits the script. echo "🔴 The containers didn't seem to start correctly. Please run the following command to check containers that may have errored out:" echo "" - if is_arm64; then - echo -e "$sudo_cmd docker-compose -f ./docker/clickhouse-setup/docker-compose.arm.yaml ps -a" - else - echo -e "$sudo_cmd docker-compose -f ./docker/clickhouse-setup/docker-compose.yaml ps -a" - fi + echo -e "$sudo_cmd docker-compose -f ./docker/clickhouse-setup/docker-compose.yaml ps -a" # echo "Please read our troubleshooting guide https://signoz.io/docs/deployment/docker#troubleshooting" echo "or reach us for support in #help channel in our Slack Community https://signoz.io/slack" @@ -466,22 +462,14 @@ start_docker echo "" echo -e "\n🟡 Pulling the latest container images for SigNoz.\n" -if is_arm64; then - $sudo_cmd docker-compose -f ./docker/clickhouse-setup/docker-compose.arm.yaml pull -else - $sudo_cmd docker-compose -f ./docker/clickhouse-setup/docker-compose.yaml pull -fi +$sudo_cmd docker-compose -f ./docker/clickhouse-setup/docker-compose.yaml pull echo "" echo "🟡 Starting the SigNoz containers. It may take a few minutes ..." echo # The docker-compose command does some nasty stuff for the `--detach` functionality. So we add a `|| true` so that the # script doesn't exit because this command looks like it failed to do it's thing. -if is_arm64; then - $sudo_cmd docker-compose -f ./docker/clickhouse-setup/docker-compose.arm.yaml up --detach --remove-orphans || true -else - $sudo_cmd docker-compose -f ./docker/clickhouse-setup/docker-compose.yaml up --detach --remove-orphans || true -fi +$sudo_cmd docker-compose -f ./docker/clickhouse-setup/docker-compose.yaml up --detach --remove-orphans || true wait_for_containers_start 60 echo "" @@ -510,11 +498,7 @@ else echo -e "🟢 Your frontend is running on http://localhost:3301" echo "" - if is_arm64; then - echo "ℹ️ To bring down SigNoz and clean volumes : $sudo_cmd docker-compose -f ./docker/clickhouse-setup/docker-compose.arm.yaml down -v" - else - echo "ℹ️ To bring down SigNoz and clean volumes : $sudo_cmd docker-compose -f ./docker/clickhouse-setup/docker-compose.yaml down -v" - fi + echo "ℹ️ To bring down SigNoz and clean volumes : $sudo_cmd docker-compose -f ./docker/clickhouse-setup/docker-compose.yaml down -v" echo "" echo "+++++++++++++++++++++++++++++++++++++++++++++++++" diff --git a/frontend/jest.setup.ts b/frontend/jest.setup.ts index 6557f780cf..b3b8061422 100644 --- a/frontend/jest.setup.ts +++ b/frontend/jest.setup.ts @@ -2,3 +2,4 @@ * Adds custom matchers from the react testing library to all tests */ import '@testing-library/jest-dom'; +import 'jest-styled-components'; diff --git a/frontend/package.json b/frontend/package.json index ebaffb5fae..f93bc9684c 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -159,6 +159,7 @@ "husky": "^7.0.4", "is-ci": "^3.0.1", "jest-playwright-preset": "^1.7.0", + "jest-styled-components": "^7.0.8", "less-plugin-npm-import": "^2.1.0", "lint-staged": "^12.3.7", "portfinder-sync": "^0.0.2", diff --git a/frontend/playwright.config.ts b/frontend/playwright.config.ts index 3fc61908c7..98fccbcb7f 100644 --- a/frontend/playwright.config.ts +++ b/frontend/playwright.config.ts @@ -11,7 +11,7 @@ const config: PlaywrightTestConfig = { testDir: './tests', use: { trace: 'retain-on-failure', - baseURL: process.env.FRONTEND_API_ENDPOINT, + baseURL: process.env.PLAYWRIGHT_TEST_BASE_URL || 'http://localhost:3301', }, updateSnapshots: 'all', fullyParallel: false, diff --git a/frontend/src/api/metrics/getMetricName.ts b/frontend/src/api/metrics/getMetricName.ts new file mode 100644 index 0000000000..f3bff5a921 --- /dev/null +++ b/frontend/src/api/metrics/getMetricName.ts @@ -0,0 +1,27 @@ +import { ApiV2Instance as axios } from 'api'; +import { ErrorResponseHandler } from 'api/ErrorResponseHandler'; +import { AxiosError } from 'axios'; +import { ErrorResponse, SuccessResponse } from 'types/api'; +import { + MetricNameProps, + MetricNamesPayloadProps, +} from 'types/api/metrics/getMetricName'; + +export const getMetricName = async ( + props: MetricNameProps, +): Promise | ErrorResponse> => { + try { + const response = await axios.get( + `/metrics/autocomplete/list?match=${props || ''}`, + ); + + return { + statusCode: 200, + error: null, + message: response.data.status, + payload: response.data, + }; + } catch (error) { + return ErrorResponseHandler(error as AxiosError); + } +}; diff --git a/frontend/src/api/metrics/getQueryRange.ts b/frontend/src/api/metrics/getQueryRange.ts new file mode 100644 index 0000000000..b6715f85e6 --- /dev/null +++ b/frontend/src/api/metrics/getQueryRange.ts @@ -0,0 +1,25 @@ +import { ApiV2Instance as axios } from 'api'; +import { ErrorResponseHandler } from 'api/ErrorResponseHandler'; +import { AxiosError } from 'axios'; +import { ErrorResponse, SuccessResponse } from 'types/api'; +import { + MetricRangePayloadProps, + MetricsRangeProps, +} from 'types/api/metrics/getQueryRange'; + +export const getMetricsQueryRange = async ( + props: MetricsRangeProps, +): Promise | ErrorResponse> => { + try { + const response = await axios.post(`/metrics/query_range`, props); + + return { + statusCode: 200, + error: null, + message: response.data.status, + payload: response.data, + }; + } catch (error) { + return ErrorResponseHandler(error as AxiosError); + } +}; diff --git a/frontend/src/api/metrics/getResourceAttributes.ts b/frontend/src/api/metrics/getResourceAttributes.ts index 5be45af6f1..66524bf8f7 100644 --- a/frontend/src/api/metrics/getResourceAttributes.ts +++ b/frontend/src/api/metrics/getResourceAttributes.ts @@ -3,17 +3,20 @@ import { ErrorResponseHandler } from 'api/ErrorResponseHandler'; import { AxiosError } from 'axios'; import { ErrorResponse, SuccessResponse } from 'types/api'; import { + TagKeyProps, TagKeysPayloadProps, TagValueProps, TagValuesPayloadProps, } from 'types/api/metrics/getResourceAttributes'; -export const getResourceAttributesTagKeys = async (): Promise< - SuccessResponse | ErrorResponse -> => { +export const getResourceAttributesTagKeys = async ( + props: TagKeyProps, +): Promise | ErrorResponse> => { try { const response = await axios.get( - '/metrics/autocomplete/tagKey?metricName=signoz_calls_total&match=resource_', + `/metrics/autocomplete/tagKey?metricName=${props.metricName}${ + props.match ? `&match=${props.match}` : '' + }`, ); return { @@ -32,7 +35,7 @@ export const getResourceAttributesTagValues = async ( ): Promise | ErrorResponse> => { try { const response = await axios.get( - `/metrics/autocomplete/tagValue?metricName=signoz_calls_total&tagKey=${props}`, + `/metrics/autocomplete/tagValue?metricName=${props.metricName}&tagKey=${props.tagKey}`, ); return { diff --git a/frontend/src/components/Editor/index.tsx b/frontend/src/components/Editor/index.tsx index 0ed486e248..92033b0830 100644 --- a/frontend/src/components/Editor/index.tsx +++ b/frontend/src/components/Editor/index.tsx @@ -1,38 +1,46 @@ -import MEditor from '@monaco-editor/react'; +import MEditor, { EditorProps } from '@monaco-editor/react'; import React from 'react'; +import { useSelector } from 'react-redux'; +import { AppState } from 'store/reducers'; +import AppReducer from 'types/reducer/app'; function Editor({ value, - language = 'yaml', + language, onChange, - readOnly = false, -}: EditorProps): JSX.Element { + readOnly, + height, + options, +}: MEditorProps): JSX.Element { + const { isDarkMode } = useSelector((state) => state.app); return ( { - if (newValue) { - onChange(newValue); - } + if (typeof newValue === 'string') onChange(newValue); }} /> ); } -interface EditorProps { +interface MEditorProps { value: string; language?: string; onChange: (value: string) => void; readOnly?: boolean; + height?: string; + options?: EditorProps['options']; } Editor.defaultProps = { - language: undefined, + language: 'yaml', readOnly: false, + height: '40vh', + options: {}, }; export default Editor; diff --git a/frontend/src/components/Graph/Plugin/Legend.ts b/frontend/src/components/Graph/Plugin/Legend.ts index b8ec2facf9..51ec58df2e 100644 --- a/frontend/src/components/Graph/Plugin/Legend.ts +++ b/frontend/src/components/Graph/Plugin/Legend.ts @@ -22,7 +22,6 @@ const getOrCreateLegendList = ( listContainer.style.height = '100%'; listContainer.style.flexWrap = 'wrap'; listContainer.style.justifyContent = 'center'; - legendContainer?.appendChild(listContainer); } diff --git a/frontend/src/components/Graph/index.tsx b/frontend/src/components/Graph/index.tsx index 2194387dd4..4bb76276c0 100644 --- a/frontend/src/components/Graph/index.tsx +++ b/frontend/src/components/Graph/index.tsx @@ -182,11 +182,10 @@ function Graph({ }; const chartHasData = hasData(data); const chartPlugins = []; - if (chartHasData) { - chartPlugins.push(legend(name, data.datasets.length > 3)); - } else { - chartPlugins.push(emptyGraph); - } + + if (!chartHasData) chartPlugins.push(emptyGraph); + chartPlugins.push(legend(name, data.datasets.length > 3)); + lineChartRef.current = new Chart(chartRef.current, { type, data, diff --git a/frontend/src/components/Graph/xAxisConfig.ts b/frontend/src/components/Graph/xAxisConfig.ts index 565b60f7e0..d14d9bba09 100644 --- a/frontend/src/components/Graph/xAxisConfig.ts +++ b/frontend/src/components/Graph/xAxisConfig.ts @@ -109,14 +109,14 @@ export const useXAxisTimeUnit = (data: Chart['data']): IAxisTimeConfig => { let minTime = Number.POSITIVE_INFINITY; let maxTime = Number.NEGATIVE_INFINITY; data?.labels?.forEach((timeStamp: unknown): void => { - const getTimeStamp = (time: string | number): Date | number | string => { - if (typeof timeStamp === 'string') { - return Date.parse(timeStamp); + const getTimeStamp = (time: Date | number): Date | number | string => { + if (time instanceof Date) { + return Date.parse(time.toString()); } return time; }; - const time = getTimeStamp(timeStamp as string | number); + const time = getTimeStamp(timeStamp as Date | number); minTime = Math.min(parseInt(time.toString(), 10), minTime); maxTime = Math.max(parseInt(time.toString(), 10), maxTime); diff --git a/frontend/src/components/Graph/yAxisConfig.ts b/frontend/src/components/Graph/yAxisConfig.ts index 5d1eeb5da7..44377b6fc5 100644 --- a/frontend/src/components/Graph/yAxisConfig.ts +++ b/frontend/src/components/Graph/yAxisConfig.ts @@ -7,13 +7,17 @@ export const getYAxisFormattedValue = ( let decimalPrecision: number | undefined; const parsedValue = getValueFormat(format)( parseFloat(value), - undefined, - undefined, + 12, + 12, undefined, ); + try { const decimalSplitted = parsedValue.text.split('.'); - if (decimalSplitted.length === 1) { + if ( + decimalSplitted.length === 1 || + parseFloat(parsedValue.text) === parseInt(parsedValue.text, 10) + ) { decimalPrecision = 0; } else { const decimalDigits = decimalSplitted[1].split(''); diff --git a/frontend/src/components/NotFound/__snapshots__/NotFound.test.tsx.snap b/frontend/src/components/NotFound/__snapshots__/NotFound.test.tsx.snap index 0e9ce92e30..9da91a31bd 100644 --- a/frontend/src/components/NotFound/__snapshots__/NotFound.test.tsx.snap +++ b/frontend/src/components/NotFound/__snapshots__/NotFound.test.tsx.snap @@ -2,8 +2,102 @@ exports[`Not Found page test should render Not Found page without errors 1`] = ` -

Ah, seems like we reached a dead end!

Page Not Found

diff --git a/frontend/src/components/TextToolTip/index.tsx b/frontend/src/components/TextToolTip/index.tsx index 051d48c30d..60032ab5c9 100644 --- a/frontend/src/components/TextToolTip/index.tsx +++ b/frontend/src/components/TextToolTip/index.tsx @@ -10,9 +10,11 @@ function TextToolTip({ text, url }: TextToolTipProps): JSX.Element { return ( ); }} @@ -22,8 +24,11 @@ function TextToolTip({ text, url }: TextToolTipProps): JSX.Element { ); } +TextToolTip.defaultProps = { + url: '', +}; interface TextToolTipProps { - url: string; + url?: string; text: string; } diff --git a/frontend/src/constants/dashboard.ts b/frontend/src/constants/dashboard.ts new file mode 100644 index 0000000000..3aa495d6b8 --- /dev/null +++ b/frontend/src/constants/dashboard.ts @@ -0,0 +1,33 @@ +import { EAggregateOperator, EReduceOperator } from 'types/common/dashboard'; + +export const PromQLQueryTemplate = { + query: '', + legend: '', + disabled: false, +}; + +export const ClickHouseQueryTemplate = { + rawQuery: '', + legend: '', + disabled: false, +}; + +export const QueryBuilderQueryTemplate = { + metricName: null, + aggregateOperator: EAggregateOperator.NOOP, + tagFilters: { + op: 'AND', + items: [], + }, + legend: '', + disabled: false, + // Specific to TIME_SERIES type graph + groupBy: [], + // Specific to VALUE type graph + reduceTo: EReduceOperator['Latest of values in timeframe'], +}; + +export const QueryBuilderFormulaTemplate = { + expression: '', + disabled: false, +}; diff --git a/frontend/src/constants/routes.ts b/frontend/src/constants/routes.ts index 636a3b0758..506474af97 100644 --- a/frontend/src/constants/routes.ts +++ b/frontend/src/constants/routes.ts @@ -12,7 +12,7 @@ const ROUTES = { ALL_DASHBOARD: '/dashboard', DASHBOARD: '/dashboard/:dashboardId', DASHBOARD_WIDGET: '/dashboard/:dashboardId/:widgetId', - EDIT_ALERTS: '/alerts/edit/:ruleId', + EDIT_ALERTS: '/alerts/edit', LIST_ALL_ALERT: '/alerts', ALERTS_NEW: '/alerts/new', ALL_CHANNELS: '/settings/channels', diff --git a/frontend/src/container/GridGraphLayout/Graph/FullView/index.metricsBuilder.tsx b/frontend/src/container/GridGraphLayout/Graph/FullView/index.metricsBuilder.tsx new file mode 100644 index 0000000000..8fe3b259c1 --- /dev/null +++ b/frontend/src/container/GridGraphLayout/Graph/FullView/index.metricsBuilder.tsx @@ -0,0 +1,132 @@ +import { Button, Typography } from 'antd'; +import { GraphOnClickHandler } from 'components/Graph'; +import Spinner from 'components/Spinner'; +import TimePreference from 'components/TimePreferenceDropDown'; +import GridGraphComponent from 'container/GridGraphComponent'; +import { + timeItems, + timePreferance, +} from 'container/NewWidget/RightContainer/timeItems'; +import getChartData from 'lib/getChartData'; +import React, { useCallback, useState } from 'react'; +import { useQuery } from 'react-query'; +import { useSelector } from 'react-redux'; +import { GetMetricQueryRange } from 'store/actions/dashboard/getQueryResults'; +import { AppState } from 'store/reducers'; +import { ErrorResponse, SuccessResponse } from 'types/api'; +import { Widgets } from 'types/api/dashboard/getAll'; +import { MetricRangePayloadProps } from 'types/api/metrics/getQueryRange'; +import { GlobalReducer } from 'types/reducer/globalTime'; + +import { NotFoundContainer, TimeContainer } from './styles'; + +function FullView({ + widget, + fullViewOptions = true, + onClickHandler, + name, + yAxisUnit, +}: FullViewProps): JSX.Element { + const { selectedTime: globalSelectedTime } = useSelector< + AppState, + GlobalReducer + >((state) => state.globalTime); + + const getSelectedTime = useCallback( + () => + timeItems.find((e) => e.enum === (widget?.timePreferance || 'GLOBAL_TIME')), + [widget], + ); + + const [selectedTime, setSelectedTime] = useState({ + name: getSelectedTime()?.name || '', + enum: widget?.timePreferance || 'GLOBAL_TIME', + }); + const response = useQuery< + SuccessResponse | ErrorResponse + >( + `FullViewGetMetricsQueryRange-${selectedTime.enum}-${globalSelectedTime}`, + () => + GetMetricQueryRange({ + selectedTime: selectedTime.enum, + graphType: widget.panelTypes, + query: widget.query, + globalSelectedInterval: globalSelectedTime, + }), + ); + + const isError = response?.error; + const isLoading = response.isLoading === true; + const errorMessage = isError instanceof Error ? isError?.message : ''; + + if (isLoading) { + return ; + } + if (isError || !response?.data?.payload?.data?.result) { + return ( + + {errorMessage} + + ); + } + + return ( + <> + {fullViewOptions && ( + + + + + )} + + + + ); +} + +interface FullViewProps { + widget: Widgets; + fullViewOptions?: boolean; + onClickHandler?: GraphOnClickHandler; + name: string; + yAxisUnit?: string; +} + +FullView.defaultProps = { + fullViewOptions: undefined, + onClickHandler: undefined, + yAxisUnit: undefined, +}; + +export default FullView; diff --git a/frontend/src/container/GridGraphLayout/Graph/FullView/index.tsx b/frontend/src/container/GridGraphLayout/Graph/FullView/index.tsx index e4b4bc8183..ad228f642e 100644 --- a/frontend/src/container/GridGraphLayout/Graph/FullView/index.tsx +++ b/frontend/src/container/GridGraphLayout/Graph/FullView/index.tsx @@ -19,7 +19,7 @@ import React, { useCallback, useState } from 'react'; import { useQueries } from 'react-query'; import { useSelector } from 'react-redux'; import { AppState } from 'store/reducers'; -import { Widgets } from 'types/api/dashboard/getAll'; +import { PromQLWidgets } from 'types/api/dashboard/getAll'; import { GlobalReducer } from 'types/reducer/globalTime'; import { NotFoundContainer, TimeContainer } from './styles'; @@ -57,7 +57,10 @@ function FullView({ time: timePreferenceType, ): { min: string | number; max: string | number } => { if (time === 'GLOBAL_TIME') { - const minMax = GetMinMax(globalSelectedTime); + const minMax = GetMinMax(globalSelectedTime, [ + minTime / 1000000, + maxTime / 1000000, + ]); return { min: convertToNanoSecondsToSecond(minMax.minTime / 1000), max: convertToNanoSecondsToSecond(minMax.maxTime / 1000), @@ -170,7 +173,7 @@ function FullView({ } interface FullViewProps { - widget: Widgets; + widget: PromQLWidgets; fullViewOptions?: boolean; onClickHandler?: GraphOnClickHandler; name: string; diff --git a/frontend/src/container/GridGraphLayout/Graph/index.tsx b/frontend/src/container/GridGraphLayout/Graph/index.tsx index a57a396fd0..f39d64cb76 100644 --- a/frontend/src/container/GridGraphLayout/Graph/index.tsx +++ b/frontend/src/container/GridGraphLayout/Graph/index.tsx @@ -1,14 +1,12 @@ import { Typography } from 'antd'; -import getQueryResult from 'api/widgets/getQuery'; +import { AxiosError } from 'axios'; +import { ChartData } from 'chart.js'; import Spinner from 'components/Spinner'; import GridGraphComponent from 'container/GridGraphComponent'; import getChartData from 'lib/getChartData'; -import GetMaxMinTime from 'lib/getMaxMinTime'; -import GetStartAndEndTime from 'lib/getStartAndEndTime'; import isEmpty from 'lodash-es/isEmpty'; -import React, { memo, useCallback, useState } from 'react'; +import React, { memo, useCallback, useEffect, useState } from 'react'; import { Layout } from 'react-grid-layout'; -import { useQueries } from 'react-query'; import { connect, useSelector } from 'react-redux'; import { bindActionCreators, Dispatch } from 'redux'; import { ThunkDispatch } from 'redux-thunk'; @@ -16,15 +14,17 @@ import { DeleteWidget, DeleteWidgetProps, } from 'store/actions/dashboard/deleteWidget'; +import { GetMetricQueryRange } from 'store/actions/dashboard/getQueryResults'; import { AppState } from 'store/reducers'; import AppActions from 'types/actions'; import { GlobalTime } from 'types/actions/globalTime'; import { Widgets } from 'types/api/dashboard/getAll'; +import { GlobalReducer } from 'types/reducer/globalTime'; import { LayoutProps } from '..'; import EmptyWidget from '../EmptyWidget'; import WidgetHeader from '../WidgetHeader'; -import FullView from './FullView'; +import FullView from './FullView/index.metricsBuilder'; import { ErrorContainer, FullViewContainer, Modal } from './styles'; function GridCardGraph({ @@ -35,60 +35,118 @@ function GridCardGraph({ layout = [], setLayout, }: GridCardGraphProps): JSX.Element { + const [state, setState] = useState({ + loading: true, + errorMessage: '', + error: false, + payload: undefined, + }); const [hovered, setHovered] = useState(false); const [modal, setModal] = useState(false); + const [deleteModal, setDeleteModal] = useState(false); + const { minTime, maxTime } = useSelector( (state) => state.globalTime, ); - const [deleteModal, setDeleteModal] = useState(false); + const { selectedTime: globalSelectedInterval } = useSelector< + AppState, + GlobalReducer + >((state) => state.globalTime); - const getMaxMinTime = GetMaxMinTime({ - graphType: widget?.panelTypes, - maxTime, - minTime, - }); + // const getMaxMinTime = GetMaxMinTime({ + // graphType: widget?.panelTypes, + // maxTime, + // minTime, + // }); - const { start, end } = GetStartAndEndTime({ - type: widget?.timePreferance, - maxTime: getMaxMinTime.maxTime, - minTime: getMaxMinTime.minTime, - }); + // const { start, end } = GetStartAndEndTime({ + // type: widget?.timePreferance, + // maxTime: getMaxMinTime.maxTime, + // minTime: getMaxMinTime.minTime, + // }); - const queryLength = widget?.query?.filter((e) => e.query.length !== 0) || []; + // const queryLength = widget?.query?.filter((e) => e.query.length !== 0) || []; - const response = useQueries( - queryLength?.map((query) => { - return { - // eslint-disable-next-line @typescript-eslint/explicit-function-return-type - queryFn: () => { - return getQueryResult({ - end, - query: query?.query, - start, - step: '60', + // const response = useQueries( + // queryLength?.map((query) => { + // return { + // // eslint-disable-next-line @typescript-eslint/explicit-function-return-type + // queryFn: () => { + // return getQueryResult({ + // end, + // query: query?.query, + // start, + // step: '60', + // }); + // }, + // queryHash: `${query?.query}-${query?.legend}-${start}-${end}`, + // retryOnMount: false, + // }; + // }), + // ); + + // const isError = + // response.find((e) => e?.data?.statusCode !== 200) !== undefined || + // response.some((e) => e.isError === true); + + // const isLoading = response.some((e) => e.isLoading === true); + + // const errorMessage = response.find((e) => e.data?.error !== null)?.data?.error; + + // const data = response.map((responseOfQuery) => + // responseOfQuery?.data?.payload?.result.map((e, index) => ({ + // query: queryLength[index]?.query, + // queryData: e, + // legend: queryLength[index]?.legend, + // })), + // ); + + useEffect(() => { + (async (): Promise => { + try { + const response = await GetMetricQueryRange({ + selectedTime: widget.timePreferance, + graphType: widget.panelTypes, + query: widget.query, + globalSelectedInterval, + }); + + const isError = response.error; + + if (isError != null) { + setState((state) => ({ + ...state, + error: true, + errorMessage: isError || 'Something went wrong', + loading: false, + })); + } else { + const chartDataSet = getChartData({ + queryData: [ + { + queryData: response.payload?.data?.result + ? response.payload?.data?.result + : [], + }, + ], }); - }, - queryHash: `${query?.query}-${query?.legend}-${start}-${end}`, - retryOnMount: false, - }; - }), - ); - const isError = - response.find((e) => e?.data?.statusCode !== 200) !== undefined || - response.some((e) => e.isError === true); - - const isLoading = response.some((e) => e.isLoading === true); - - const errorMessage = response.find((e) => e.data?.error !== null)?.data?.error; - - const data = response.map((responseOfQuery) => - responseOfQuery?.data?.payload?.result.map((e, index) => ({ - query: queryLength[index]?.query, - queryData: e, - legend: queryLength[index]?.legend, - })), - ); + setState((state) => ({ + ...state, + loading: false, + payload: chartDataSet, + })); + } + } catch (error) { + setState((state) => ({ + ...state, + error: true, + errorMessage: (error as AxiosError).toString(), + loading: false, + })); + } + })(); + }, [widget, maxTime, minTime, globalSelectedInterval]); const onToggleModal = useCallback( (func: React.Dispatch>) => { @@ -144,14 +202,7 @@ function GridCardGraph({ const isEmptyLayout = widget?.id === 'empty' || isEmpty(widget); - if (isLoading) { - return ; - } - - if ( - (isError || data === undefined || data[0] === undefined) && - !isEmptyLayout - ) { + if (state.error && !isEmptyLayout) { return ( <> {getModals()} @@ -163,18 +214,17 @@ function GridCardGraph({ onDelete={(): void => onToggleModal(setDeleteModal)} /> - {errorMessage} + {state.errorMessage} ); } - const chartData = getChartData({ - queryData: data.map((e) => ({ - query: e?.map((e) => e.query).join(' ') || '', - queryData: e?.map((e) => e.queryData) || [], - legend: e?.map((e) => e.legend).join('') || '', - })), - }); + if ( + (state.loading === true || state.payload === undefined) && + !isEmptyLayout + ) { + return ; + } return ( ({ ...state, @@ -134,6 +135,10 @@ function GridGraph(props: Props): JSX.Element { errorMessage: '', loading: false, })); + dispatch({ + type: UPDATE_DASHBOARD, + payload: updatedDashboard, + }); } else { setSaveLayoutState((state) => ({ ...state, @@ -153,8 +158,9 @@ function GridGraph(props: Props): JSX.Element { data.tags, data.title, data.widgets, + dispatch, saveLayoutPermission, - selectedDashboard.uuid, + selectedDashboard, ], ); @@ -218,7 +224,7 @@ function GridGraph(props: Props): JSX.Element { const onLayoutChangeHandler = async (layout: Layout[]): Promise => { setLayoutFunction(layout); - await onLayoutSaveHandler(layout); + // await onLayoutSaveHandler(layout); }; const onAddPanelHandler = useCallback(() => { diff --git a/frontend/src/container/GridGraphLayout/utils.ts b/frontend/src/container/GridGraphLayout/utils.ts index 67b854368c..0d7320f6f5 100644 --- a/frontend/src/container/GridGraphLayout/utils.ts +++ b/frontend/src/container/GridGraphLayout/utils.ts @@ -1,9 +1,16 @@ import { notification } from 'antd'; import updateDashboardApi from 'api/dashboard/update'; +import { + ClickHouseQueryTemplate, + PromQLQueryTemplate, + QueryBuilderQueryTemplate, +} from 'constants/dashboard'; import { GRAPH_TYPES } from 'container/NewDashboard/ComponentsSlider'; +import GetQueryName from 'lib/query/GetQueryName'; import { Layout } from 'react-grid-layout'; import store from 'store'; import { Dashboard } from 'types/api/dashboard/getAll'; +import { EQueryType } from 'types/common/dashboard'; export const UpdateDashboard = async ({ data, @@ -29,14 +36,32 @@ export const UpdateDashboard = async ({ nullZeroValues: '', opacity: '', panelTypes: graphType, - query: [ - { - query: '', - legend: '', + query: { + queryType: EQueryType.QUERY_BUILDER, + promQL: [ + { + name: GetQueryName([]) || '', + ...PromQLQueryTemplate, + }, + ], + clickHouse: [ + { + name: GetQueryName([]) || '', + ...ClickHouseQueryTemplate, + }, + ], + metricsBuilder: { + formulas: [], + queryBuilder: [ + { + name: GetQueryName([]) || '', + ...QueryBuilderQueryTemplate, + }, + ], }, - ], + }, queryData: { - data: [], + data: { queryData: [] }, error: false, errorMessage: '', loading: false, diff --git a/frontend/src/container/ListAlertRules/ListAlert.tsx b/frontend/src/container/ListAlertRules/ListAlert.tsx index 8ec1fa9987..b851b0829a 100644 --- a/frontend/src/container/ListAlertRules/ListAlert.tsx +++ b/frontend/src/container/ListAlertRules/ListAlert.tsx @@ -11,7 +11,6 @@ import React, { useCallback, useState } from 'react'; import { useTranslation } from 'react-i18next'; import { UseQueryResult } from 'react-query'; import { useSelector } from 'react-redux'; -import { generatePath } from 'react-router-dom'; import { AppState } from 'store/reducers'; import { ErrorResponse, SuccessResponse } from 'types/api'; import { Alerts } from 'types/api/alerts/getAll'; @@ -51,11 +50,7 @@ function ListAlert({ allAlertRules, refetch }: ListAlertProps): JSX.Element { const [notifications, Element] = notification.useNotification(); const onEditHandler = (id: string): void => { - history.push( - generatePath(ROUTES.EDIT_ALERTS, { - ruleId: id, - }), - ); + history.push(`${ROUTES.EDIT_ALERTS}?ruleId=${id}`); }; const columns: ColumnsType = [ diff --git a/frontend/src/container/ListOfDashboard/ImportJSON/index.tsx b/frontend/src/container/ListOfDashboard/ImportJSON/index.tsx index 99f5fb0eeb..021a5f9805 100644 --- a/frontend/src/container/ListOfDashboard/ImportJSON/index.tsx +++ b/frontend/src/container/ListOfDashboard/ImportJSON/index.tsx @@ -73,10 +73,7 @@ function ImportJSON({ ...e, queryData: { ...e.queryData, - data: e.queryData.data.map((queryData) => ({ - ...queryData, - queryData: [], - })), + data: e.queryData.data, error: false, errorMessage: '', loading: false, diff --git a/frontend/src/container/ListOfDashboard/SearchFilter/__tests__/utils.test.ts b/frontend/src/container/ListOfDashboard/SearchFilter/__tests__/utils.test.ts new file mode 100644 index 0000000000..db9825b677 --- /dev/null +++ b/frontend/src/container/ListOfDashboard/SearchFilter/__tests__/utils.test.ts @@ -0,0 +1,58 @@ +import { Dashboard } from 'types/api/dashboard/getAll'; +import { v4 as uuid } from 'uuid'; + +import { TOperator } from '../types'; +import { executeSearchQueries } from '../utils'; + +describe('executeSearchQueries', () => { + const firstDashboard: Dashboard = { + id: 11111, + uuid: uuid(), + created_at: '', + updated_at: '', + data: { + title: 'first dashboard', + }, + }; + const secondDashboard: Dashboard = { + id: 22222, + uuid: uuid(), + created_at: '', + updated_at: '', + data: { + title: 'second dashboard', + }, + }; + const thirdDashboard: Dashboard = { + id: 333333, + uuid: uuid(), + created_at: '', + updated_at: '', + data: { + title: 'third dashboard (with special characters +?\\)', + }, + }; + const dashboards = [firstDashboard, secondDashboard, thirdDashboard]; + + it('should filter dashboards based on title', () => { + const query = { + category: 'title', + id: 'someid', + operator: '=' as TOperator, + value: 'first dashboard', + }; + + expect(executeSearchQueries([query], dashboards)).toEqual([firstDashboard]); + }); + + it('should filter dashboards with special characters', () => { + const query = { + category: 'title', + id: 'someid', + operator: '=' as TOperator, + value: 'third dashboard (with special characters +?\\)', + }; + + expect(executeSearchQueries([query], dashboards)).toEqual([thirdDashboard]); + }); +}); diff --git a/frontend/src/container/ListOfDashboard/SearchFilter/utils.ts b/frontend/src/container/ListOfDashboard/SearchFilter/utils.ts index 5f9b37cc3e..6487ccd789 100644 --- a/frontend/src/container/ListOfDashboard/SearchFilter/utils.ts +++ b/frontend/src/container/ListOfDashboard/SearchFilter/utils.ts @@ -42,6 +42,8 @@ export const executeSearchQueries = ( if (!searchData.length || !queries.length) { return searchData; } + const escapeRegExp = (regExp: string): string => + regExp.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); queries.forEach((query: IQueryStructure) => { const { operator } = query; @@ -61,7 +63,7 @@ export const executeSearchQueries = ( for (const searchSpaceItem of searchSpace) { if (searchSpaceItem) for (const queryValue of value) { - if (searchSpaceItem.match(queryValue)) { + if (searchSpaceItem.match(escapeRegExp(queryValue))) { return resolveOperator(true, operator); } } diff --git a/frontend/src/container/MetricsApplication/ResourceAttributesFilter/utils.ts b/frontend/src/container/MetricsApplication/ResourceAttributesFilter/utils.ts index e8dd7bb503..aa16f160ac 100644 --- a/frontend/src/container/MetricsApplication/ResourceAttributesFilter/utils.ts +++ b/frontend/src/container/MetricsApplication/ResourceAttributesFilter/utils.ts @@ -21,7 +21,10 @@ export const GetTagKeys = async (): Promise => { // resolve(TagKeysCache); // }); // } - const { payload } = await getResourceAttributesTagKeys(); + const { payload } = await getResourceAttributesTagKeys({ + metricName: 'signoz_calls_total', + match: 'resource_', + }); if (!payload || !payload?.data) { return []; } @@ -32,12 +35,15 @@ export const GetTagKeys = async (): Promise => { }; export const GetTagValues = async (tagKey: string): Promise => { - const { payload } = await getResourceAttributesTagValues(tagKey); + const { payload } = await getResourceAttributesTagValues({ + tagKey, + metricName: 'signoz_calls_total', + }); if (!payload || !payload?.data) { return []; } - return payload.data.filter(Boolean).map((tagValue: string) => ({ + return payload.data.map((tagValue: string) => ({ label: tagValue, value: tagValue, })); diff --git a/frontend/src/container/MetricsApplication/Tabs/DBCall.tsx b/frontend/src/container/MetricsApplication/Tabs/DBCall.tsx index ba0af031cd..60441b7876 100644 --- a/frontend/src/container/MetricsApplication/Tabs/DBCall.tsx +++ b/frontend/src/container/MetricsApplication/Tabs/DBCall.tsx @@ -4,7 +4,7 @@ import React from 'react'; import { useSelector } from 'react-redux'; import { useParams } from 'react-router-dom'; import { AppState } from 'store/reducers'; -import { Widgets } from 'types/api/dashboard/getAll'; +import { PromQLWidgets } from 'types/api/dashboard/getAll'; import MetricReducer from 'types/reducer/metrics'; import { Card, GraphContainer, GraphTitle, Row } from '../styles'; @@ -58,7 +58,7 @@ function DBCall({ getWidget }: DBCallProps): JSX.Element { } interface DBCallProps { - getWidget: (query: Widgets['query']) => Widgets; + getWidget: (query: PromQLWidgets['query']) => PromQLWidgets; } export default DBCall; diff --git a/frontend/src/container/MetricsApplication/Tabs/External.tsx b/frontend/src/container/MetricsApplication/Tabs/External.tsx index 73eca09600..9811e2f269 100644 --- a/frontend/src/container/MetricsApplication/Tabs/External.tsx +++ b/frontend/src/container/MetricsApplication/Tabs/External.tsx @@ -4,7 +4,7 @@ import React from 'react'; import { useSelector } from 'react-redux'; import { useParams } from 'react-router-dom'; import { AppState } from 'store/reducers'; -import { Widgets } from 'types/api/dashboard/getAll'; +import { PromQLWidgets } from 'types/api/dashboard/getAll'; import MetricReducer from 'types/reducer/metrics'; import { Card, GraphContainer, GraphTitle, Row } from '../styles'; @@ -29,7 +29,7 @@ function External({ getWidget }: ExternalProps): JSX.Element { widget={getWidget([ { query: `max((sum(rate(signoz_external_call_latency_count{service_name="${servicename}", status_code="STATUS_CODE_ERROR"${resourceAttributePromQLQuery}}[1m]) OR rate(signoz_external_call_latency_count{service_name="${servicename}", http_status_code=~"5.."${resourceAttributePromQLQuery}}[1m]) OR vector(0)) by (http_url))*100/sum(rate(signoz_external_call_latency_count{service_name="${servicename}"${resourceAttributePromQLQuery}}[1m])) by (http_url)) < 1000 OR vector(0)`, - legend, + legend: 'External Call Error Percentage', }, ])} yAxisUnit="%" @@ -102,7 +102,7 @@ function External({ getWidget }: ExternalProps): JSX.Element { } interface ExternalProps { - getWidget: (query: Widgets['query']) => Widgets; + getWidget: (query: PromQLWidgets['query']) => PromQLWidgets; } export default External; diff --git a/frontend/src/container/MetricsApplication/Tabs/Overview.tsx b/frontend/src/container/MetricsApplication/Tabs/Overview.tsx index fbc1a855ac..a53714d05d 100644 --- a/frontend/src/container/MetricsApplication/Tabs/Overview.tsx +++ b/frontend/src/container/MetricsApplication/Tabs/Overview.tsx @@ -11,7 +11,7 @@ import React, { useRef } from 'react'; import { useSelector } from 'react-redux'; import { useParams } from 'react-router-dom'; import { AppState } from 'store/reducers'; -import { Widgets } from 'types/api/dashboard/getAll'; +import { PromQLWidgets } from 'types/api/dashboard/getAll'; import MetricReducer from 'types/reducer/metrics'; import { Card, Col, GraphContainer, GraphTitle, Row } from '../styles'; @@ -248,7 +248,7 @@ function Application({ getWidget }: DashboardProps): JSX.Element { } interface DashboardProps { - getWidget: (query: Widgets['query']) => Widgets; + getWidget: (query: PromQLWidgets['query']) => PromQLWidgets; } export default Application; diff --git a/frontend/src/container/MetricsApplication/index.tsx b/frontend/src/container/MetricsApplication/index.tsx index 9922fbb8c2..f6305358b3 100644 --- a/frontend/src/container/MetricsApplication/index.tsx +++ b/frontend/src/container/MetricsApplication/index.tsx @@ -3,14 +3,14 @@ import ROUTES from 'constants/routes'; import React from 'react'; import { generatePath, useParams } from 'react-router-dom'; import { useLocation } from 'react-use'; -import { Widgets } from 'types/api/dashboard/getAll'; +import { PromQLWidgets } from 'types/api/dashboard/getAll'; import ResourceAttributesFilter from './ResourceAttributesFilter'; import DBCall from './Tabs/DBCall'; import External from './Tabs/External'; import Overview from './Tabs/Overview'; -const getWidget = (query: Widgets['query']): Widgets => { +const getWidget = (query: PromQLWidgets['query']): PromQLWidgets => { return { description: '', id: '', @@ -20,7 +20,7 @@ const getWidget = (query: Widgets['query']): Widgets => { panelTypes: 'TIME_SERIES', query, queryData: { - data: [], + data: { queryData: [] }, error: false, errorMessage: '', loading: false, diff --git a/frontend/src/container/NewWidget/LeftContainer/QuerySection/Query.tsx b/frontend/src/container/NewWidget/LeftContainer/QuerySection/Query.tsx deleted file mode 100644 index 916771eece..0000000000 --- a/frontend/src/container/NewWidget/LeftContainer/QuerySection/Query.tsx +++ /dev/null @@ -1,151 +0,0 @@ -import { Button, Divider } from 'antd'; -import Input from 'components/Input'; -import TextToolTip from 'components/TextToolTip'; -import { timePreferance } from 'container/NewWidget/RightContainer/timeItems'; -import React, { useCallback, useMemo, useState } from 'react'; -import { connect, useSelector } from 'react-redux'; -import { useLocation } from 'react-router-dom'; -import { bindActionCreators, Dispatch } from 'redux'; -import { ThunkDispatch } from 'redux-thunk'; -import { DeleteQuery } from 'store/actions'; -import { - UpdateQuery, - UpdateQueryProps, -} from 'store/actions/dashboard/updateQuery'; -import { AppState } from 'store/reducers'; -import AppActions from 'types/actions'; -import { DeleteQueryProps } from 'types/actions/dashboard'; -import { Widgets } from 'types/api/dashboard/getAll'; -import DashboardReducer from 'types/reducer/dashboards'; - -import { - ButtonContainer, - Container, - InputContainer, - QueryWrapper, -} from './styles'; - -function Query({ - currentIndex, - preLegend, - preQuery, - updateQuery, - deleteQuery, -}: QueryProps): JSX.Element { - const [promqlQuery, setPromqlQuery] = useState(preQuery); - const [legendFormat, setLegendFormat] = useState(preLegend); - const { search } = useLocation(); - const { dashboards } = useSelector( - (state) => state.dashboards, - ); - - const [selectedDashboards] = dashboards; - const { widgets } = selectedDashboards.data; - - const query = new URLSearchParams(search); - const widgetId = query.get('widgetId') || ''; - - const urlQuery = useMemo(() => { - return new URLSearchParams(search); - }, [search]); - - const getWidget = useCallback(() => { - const widgetId = urlQuery.get('widgetId'); - return widgets?.find((e) => e.id === widgetId); - }, [widgets, urlQuery]); - - const selectedWidget = getWidget() as Widgets; - - const onChangeHandler = useCallback( - (setFunc: React.Dispatch>, value: string) => { - setFunc(value); - }, - [], - ); - - const onBlurHandler = (): void => { - updateQuery({ - currentIndex, - legend: legendFormat, - query: promqlQuery, - widgetId, - yAxisUnit: selectedWidget.yAxisUnit, - }); - }; - - const onDeleteQueryHandler = (): void => { - deleteQuery({ - widgetId, - currentIndex, - }); - }; - - return ( - <> - - - - - onChangeHandler(setPromqlQuery, event.target.value) - } - size="middle" - value={promqlQuery} - addonBefore="PromQL Query" - onBlur={(): void => onBlurHandler()} - /> - - - - - onChangeHandler(setLegendFormat, event.target.value) - } - size="middle" - value={legendFormat} - addonBefore="Legend Format" - onBlur={(): void => onBlurHandler()} - /> - - - - - - - - - - - - ); -} - -interface DispatchProps { - updateQuery: ( - props: UpdateQueryProps, - ) => (dispatch: Dispatch) => void; - deleteQuery: ( - props: DeleteQueryProps, - ) => (dispatch: Dispatch) => void; -} - -const mapDispatchToProps = ( - dispatch: ThunkDispatch, -): DispatchProps => ({ - updateQuery: bindActionCreators(UpdateQuery, dispatch), - deleteQuery: bindActionCreators(DeleteQuery, dispatch), -}); - -interface QueryProps extends DispatchProps { - selectedTime: timePreferance; - currentIndex: number; - preQuery: string; - preLegend: string; -} - -export default connect(null, mapDispatchToProps)(Query); diff --git a/frontend/src/container/NewWidget/LeftContainer/QuerySection/QueryBuilder/Options.ts b/frontend/src/container/NewWidget/LeftContainer/QuerySection/QueryBuilder/Options.ts new file mode 100644 index 0000000000..38d9094dcc --- /dev/null +++ b/frontend/src/container/NewWidget/LeftContainer/QuerySection/QueryBuilder/Options.ts @@ -0,0 +1,20 @@ +import { EAggregateOperator } from 'types/common/dashboard'; + +export const AggregateFunctions = Object.keys(EAggregateOperator) + .filter((key) => Number.isNaN(parseInt(key, 10))) + .map((key) => { + return { + label: key, + value: EAggregateOperator[key as keyof typeof EAggregateOperator], + }; + }); + +export const TagKeyOperator = [ + { label: 'In', value: 'IN' }, + { label: 'Not In', value: 'NIN' }, + { label: 'Like', value: 'LIKE' }, + { label: 'Not Like', value: 'NLIKE' }, + // { label: 'Equal', value: 'EQ' }, + // { label: 'Not Equal', value: 'NEQ' }, + // { label: 'REGEX', value: 'REGEX' }, +]; diff --git a/frontend/src/container/NewWidget/LeftContainer/QuerySection/QueryBuilder/QueryHeader.tsx b/frontend/src/container/NewWidget/LeftContainer/QuerySection/QueryBuilder/QueryHeader.tsx new file mode 100644 index 0000000000..6584cdc390 --- /dev/null +++ b/frontend/src/container/NewWidget/LeftContainer/QuerySection/QueryBuilder/QueryHeader.tsx @@ -0,0 +1,54 @@ +import { + DeleteOutlined, + DownOutlined, + EyeFilled, + EyeInvisibleFilled, + RightOutlined, +} from '@ant-design/icons'; +import { Button, Row } from 'antd'; +import React, { useState } from 'react'; + +import { QueryWrapper } from '../styles'; + +interface IQueryHeaderProps { + disabled: boolean; + onDisable: VoidFunction; + name: string; + onDelete: VoidFunction; + children: React.ReactNode; +} + +function QueryHeader({ + disabled, + onDisable, + name, + onDelete, + children, +}: IQueryHeaderProps): JSX.Element { + const [collapse, setCollapse] = useState(false); + return ( + + + + +