mirror of
https://git.mirrors.martin98.com/https://github.com/SigNoz/signoz
synced 2025-08-12 07:49:01 +08:00
Merge branch 'develop' into store-fix-1
This commit is contained in:
commit
2ed24df250
3
.github/CODEOWNERS
vendored
3
.github/CODEOWNERS
vendored
@ -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
|
||||
|
2
.github/workflows/build.yaml
vendored
2
.github/workflows/build.yaml
vendored
@ -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
|
||||
|
File diff suppressed because it is too large
Load Diff
28
deploy/docker-swarm/clickhouse-setup/clickhouse-storage.xml
Normal file
28
deploy/docker-swarm/clickhouse-setup/clickhouse-storage.xml
Normal file
@ -0,0 +1,28 @@
|
||||
<?xml version="1.0"?>
|
||||
<clickhouse>
|
||||
<storage_configuration>
|
||||
<disks>
|
||||
<default>
|
||||
<keep_free_space_bytes>10485760</keep_free_space_bytes>
|
||||
</default>
|
||||
<s3>
|
||||
<type>s3</type>
|
||||
<endpoint>https://BUCKET-NAME.s3.amazonaws.com/data/</endpoint>
|
||||
<access_key_id>ACCESS-KEY-ID</access_key_id>
|
||||
<secret_access_key>SECRET-ACCESS-KEY</secret_access_key>
|
||||
</s3>
|
||||
</disks>
|
||||
<policies>
|
||||
<tiered>
|
||||
<volumes>
|
||||
<default>
|
||||
<disk>default</disk>
|
||||
</default>
|
||||
<s3>
|
||||
<disk>s3</disk>
|
||||
</s3>
|
||||
</volumes>
|
||||
</tiered>
|
||||
</policies>
|
||||
</storage_configuration>
|
||||
</clickhouse>
|
123
deploy/docker-swarm/clickhouse-setup/clickhouse-users.xml
Normal file
123
deploy/docker-swarm/clickhouse-setup/clickhouse-users.xml
Normal file
@ -0,0 +1,123 @@
|
||||
<?xml version="1.0"?>
|
||||
<clickhouse>
|
||||
<!-- See also the files in users.d directory where the settings can be overridden. -->
|
||||
|
||||
<!-- Profiles of settings. -->
|
||||
<profiles>
|
||||
<!-- Default settings. -->
|
||||
<default>
|
||||
<!-- Maximum memory usage for processing single query, in bytes. -->
|
||||
<max_memory_usage>10000000000</max_memory_usage>
|
||||
|
||||
<!-- How to choose between replicas during distributed query processing.
|
||||
random - choose random replica from set of replicas with minimum number of errors
|
||||
nearest_hostname - from set of replicas with minimum number of errors, choose replica
|
||||
with minimum number of different symbols between replica's hostname and local hostname
|
||||
(Hamming distance).
|
||||
in_order - first live replica is chosen in specified order.
|
||||
first_or_random - if first replica one has higher number of errors, pick a random one from replicas with minimum number of errors.
|
||||
-->
|
||||
<load_balancing>random</load_balancing>
|
||||
</default>
|
||||
|
||||
<!-- Profile that allows only read queries. -->
|
||||
<readonly>
|
||||
<readonly>1</readonly>
|
||||
</readonly>
|
||||
</profiles>
|
||||
|
||||
<!-- Users and ACL. -->
|
||||
<users>
|
||||
<!-- If user name was not specified, 'default' user is used. -->
|
||||
<default>
|
||||
<!-- See also the files in users.d directory where the password can be overridden.
|
||||
|
||||
Password could be specified in plaintext or in SHA256 (in hex format).
|
||||
|
||||
If you want to specify password in plaintext (not recommended), place it in 'password' element.
|
||||
Example: <password>qwerty</password>.
|
||||
Password could be empty.
|
||||
|
||||
If you want to specify SHA256, place it in 'password_sha256_hex' element.
|
||||
Example: <password_sha256_hex>65e84be33532fb784c48129675f9eff3a682b27168c0ea744b2cf58ee02337c5</password_sha256_hex>
|
||||
Restrictions of SHA256: impossibility to connect to ClickHouse using MySQL JS client (as of July 2019).
|
||||
|
||||
If you want to specify double SHA1, place it in 'password_double_sha1_hex' element.
|
||||
Example: <password_double_sha1_hex>e395796d6546b1b65db9d665cd43f0e858dd4303</password_double_sha1_hex>
|
||||
|
||||
If you want to specify a previously defined LDAP server (see 'ldap_servers' in the main config) for authentication,
|
||||
place its name in 'server' element inside 'ldap' element.
|
||||
Example: <ldap><server>my_ldap_server</server></ldap>
|
||||
|
||||
If you want to authenticate the user via Kerberos (assuming Kerberos is enabled, see 'kerberos' in the main config),
|
||||
place 'kerberos' element instead of 'password' (and similar) elements.
|
||||
The name part of the canonical principal name of the initiator must match the user name for authentication to succeed.
|
||||
You can also place 'realm' element inside 'kerberos' element to further restrict authentication to only those requests
|
||||
whose initiator's realm matches it.
|
||||
Example: <kerberos />
|
||||
Example: <kerberos><realm>EXAMPLE.COM</realm></kerberos>
|
||||
|
||||
How to generate decent password:
|
||||
Execute: PASSWORD=$(base64 < /dev/urandom | head -c8); echo "$PASSWORD"; echo -n "$PASSWORD" | sha256sum | tr -d '-'
|
||||
In first line will be password and in second - corresponding SHA256.
|
||||
|
||||
How to generate double SHA1:
|
||||
Execute: PASSWORD=$(base64 < /dev/urandom | head -c8); echo "$PASSWORD"; echo -n "$PASSWORD" | sha1sum | tr -d '-' | xxd -r -p | sha1sum | tr -d '-'
|
||||
In first line will be password and in second - corresponding double SHA1.
|
||||
-->
|
||||
<password></password>
|
||||
|
||||
<!-- List of networks with open access.
|
||||
|
||||
To open access from everywhere, specify:
|
||||
<ip>::/0</ip>
|
||||
|
||||
To open access only from localhost, specify:
|
||||
<ip>::1</ip>
|
||||
<ip>127.0.0.1</ip>
|
||||
|
||||
Each element of list has one of the following forms:
|
||||
<ip> IP-address or network mask. Examples: 213.180.204.3 or 10.0.0.1/8 or 10.0.0.1/255.255.255.0
|
||||
2a02:6b8::3 or 2a02:6b8::3/64 or 2a02:6b8::3/ffff:ffff:ffff:ffff::.
|
||||
<host> Hostname. Example: server01.clickhouse.com.
|
||||
To check access, DNS query is performed, and all received addresses compared to peer address.
|
||||
<host_regexp> Regular expression for host names. Example, ^server\d\d-\d\d-\d\.clickhouse\.com$
|
||||
To check access, DNS PTR query is performed for peer address and then regexp is applied.
|
||||
Then, for result of PTR query, another DNS query is performed and all received addresses compared to peer address.
|
||||
Strongly recommended that regexp is ends with $
|
||||
All results of DNS requests are cached till server restart.
|
||||
-->
|
||||
<networks>
|
||||
<ip>::/0</ip>
|
||||
</networks>
|
||||
|
||||
<!-- Settings profile for user. -->
|
||||
<profile>default</profile>
|
||||
|
||||
<!-- Quota for user. -->
|
||||
<quota>default</quota>
|
||||
|
||||
<!-- User can create other users and grant rights to them. -->
|
||||
<!-- <access_management>1</access_management> -->
|
||||
</default>
|
||||
</users>
|
||||
|
||||
<!-- Quotas. -->
|
||||
<quotas>
|
||||
<!-- Name of quota. -->
|
||||
<default>
|
||||
<!-- Limits for time interval. You could specify many intervals with different limits. -->
|
||||
<interval>
|
||||
<!-- Length of interval. -->
|
||||
<duration>3600</duration>
|
||||
|
||||
<!-- No limits. Just calculate resource usage for time interval. -->
|
||||
<queries>0</queries>
|
||||
<errors>0</errors>
|
||||
<result_rows>0</result_rows>
|
||||
<read_rows>0</read_rows>
|
||||
<execution_time>0</execution_time>
|
||||
</interval>
|
||||
</default>
|
||||
</quotas>
|
||||
</clickhouse>
|
@ -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:
|
||||
|
File diff suppressed because it is too large
Load Diff
28
deploy/docker/clickhouse-setup/clickhouse-storage.xml
Normal file
28
deploy/docker/clickhouse-setup/clickhouse-storage.xml
Normal file
@ -0,0 +1,28 @@
|
||||
<?xml version="1.0"?>
|
||||
<clickhouse>
|
||||
<storage_configuration>
|
||||
<disks>
|
||||
<default>
|
||||
<keep_free_space_bytes>10485760</keep_free_space_bytes>
|
||||
</default>
|
||||
<s3>
|
||||
<type>s3</type>
|
||||
<endpoint>https://BUCKET-NAME.s3.amazonaws.com/data/</endpoint>
|
||||
<access_key_id>ACCESS-KEY-ID</access_key_id>
|
||||
<secret_access_key>SECRET-ACCESS-KEY</secret_access_key>
|
||||
</s3>
|
||||
</disks>
|
||||
<policies>
|
||||
<tiered>
|
||||
<volumes>
|
||||
<default>
|
||||
<disk>default</disk>
|
||||
</default>
|
||||
<s3>
|
||||
<disk>s3</disk>
|
||||
</s3>
|
||||
</volumes>
|
||||
</tiered>
|
||||
</policies>
|
||||
</storage_configuration>
|
||||
</clickhouse>
|
123
deploy/docker/clickhouse-setup/clickhouse-users.xml
Normal file
123
deploy/docker/clickhouse-setup/clickhouse-users.xml
Normal file
@ -0,0 +1,123 @@
|
||||
<?xml version="1.0"?>
|
||||
<clickhouse>
|
||||
<!-- See also the files in users.d directory where the settings can be overridden. -->
|
||||
|
||||
<!-- Profiles of settings. -->
|
||||
<profiles>
|
||||
<!-- Default settings. -->
|
||||
<default>
|
||||
<!-- Maximum memory usage for processing single query, in bytes. -->
|
||||
<max_memory_usage>10000000000</max_memory_usage>
|
||||
|
||||
<!-- How to choose between replicas during distributed query processing.
|
||||
random - choose random replica from set of replicas with minimum number of errors
|
||||
nearest_hostname - from set of replicas with minimum number of errors, choose replica
|
||||
with minimum number of different symbols between replica's hostname and local hostname
|
||||
(Hamming distance).
|
||||
in_order - first live replica is chosen in specified order.
|
||||
first_or_random - if first replica one has higher number of errors, pick a random one from replicas with minimum number of errors.
|
||||
-->
|
||||
<load_balancing>random</load_balancing>
|
||||
</default>
|
||||
|
||||
<!-- Profile that allows only read queries. -->
|
||||
<readonly>
|
||||
<readonly>1</readonly>
|
||||
</readonly>
|
||||
</profiles>
|
||||
|
||||
<!-- Users and ACL. -->
|
||||
<users>
|
||||
<!-- If user name was not specified, 'default' user is used. -->
|
||||
<default>
|
||||
<!-- See also the files in users.d directory where the password can be overridden.
|
||||
|
||||
Password could be specified in plaintext or in SHA256 (in hex format).
|
||||
|
||||
If you want to specify password in plaintext (not recommended), place it in 'password' element.
|
||||
Example: <password>qwerty</password>.
|
||||
Password could be empty.
|
||||
|
||||
If you want to specify SHA256, place it in 'password_sha256_hex' element.
|
||||
Example: <password_sha256_hex>65e84be33532fb784c48129675f9eff3a682b27168c0ea744b2cf58ee02337c5</password_sha256_hex>
|
||||
Restrictions of SHA256: impossibility to connect to ClickHouse using MySQL JS client (as of July 2019).
|
||||
|
||||
If you want to specify double SHA1, place it in 'password_double_sha1_hex' element.
|
||||
Example: <password_double_sha1_hex>e395796d6546b1b65db9d665cd43f0e858dd4303</password_double_sha1_hex>
|
||||
|
||||
If you want to specify a previously defined LDAP server (see 'ldap_servers' in the main config) for authentication,
|
||||
place its name in 'server' element inside 'ldap' element.
|
||||
Example: <ldap><server>my_ldap_server</server></ldap>
|
||||
|
||||
If you want to authenticate the user via Kerberos (assuming Kerberos is enabled, see 'kerberos' in the main config),
|
||||
place 'kerberos' element instead of 'password' (and similar) elements.
|
||||
The name part of the canonical principal name of the initiator must match the user name for authentication to succeed.
|
||||
You can also place 'realm' element inside 'kerberos' element to further restrict authentication to only those requests
|
||||
whose initiator's realm matches it.
|
||||
Example: <kerberos />
|
||||
Example: <kerberos><realm>EXAMPLE.COM</realm></kerberos>
|
||||
|
||||
How to generate decent password:
|
||||
Execute: PASSWORD=$(base64 < /dev/urandom | head -c8); echo "$PASSWORD"; echo -n "$PASSWORD" | sha256sum | tr -d '-'
|
||||
In first line will be password and in second - corresponding SHA256.
|
||||
|
||||
How to generate double SHA1:
|
||||
Execute: PASSWORD=$(base64 < /dev/urandom | head -c8); echo "$PASSWORD"; echo -n "$PASSWORD" | sha1sum | tr -d '-' | xxd -r -p | sha1sum | tr -d '-'
|
||||
In first line will be password and in second - corresponding double SHA1.
|
||||
-->
|
||||
<password></password>
|
||||
|
||||
<!-- List of networks with open access.
|
||||
|
||||
To open access from everywhere, specify:
|
||||
<ip>::/0</ip>
|
||||
|
||||
To open access only from localhost, specify:
|
||||
<ip>::1</ip>
|
||||
<ip>127.0.0.1</ip>
|
||||
|
||||
Each element of list has one of the following forms:
|
||||
<ip> IP-address or network mask. Examples: 213.180.204.3 or 10.0.0.1/8 or 10.0.0.1/255.255.255.0
|
||||
2a02:6b8::3 or 2a02:6b8::3/64 or 2a02:6b8::3/ffff:ffff:ffff:ffff::.
|
||||
<host> Hostname. Example: server01.clickhouse.com.
|
||||
To check access, DNS query is performed, and all received addresses compared to peer address.
|
||||
<host_regexp> Regular expression for host names. Example, ^server\d\d-\d\d-\d\.clickhouse\.com$
|
||||
To check access, DNS PTR query is performed for peer address and then regexp is applied.
|
||||
Then, for result of PTR query, another DNS query is performed and all received addresses compared to peer address.
|
||||
Strongly recommended that regexp is ends with $
|
||||
All results of DNS requests are cached till server restart.
|
||||
-->
|
||||
<networks>
|
||||
<ip>::/0</ip>
|
||||
</networks>
|
||||
|
||||
<!-- Settings profile for user. -->
|
||||
<profile>default</profile>
|
||||
|
||||
<!-- Quota for user. -->
|
||||
<quota>default</quota>
|
||||
|
||||
<!-- User can create other users and grant rights to them. -->
|
||||
<!-- <access_management>1</access_management> -->
|
||||
</default>
|
||||
</users>
|
||||
|
||||
<!-- Quotas. -->
|
||||
<quotas>
|
||||
<!-- Name of quota. -->
|
||||
<default>
|
||||
<!-- Limits for time interval. You could specify many intervals with different limits. -->
|
||||
<interval>
|
||||
<!-- Length of interval. -->
|
||||
<duration>3600</duration>
|
||||
|
||||
<!-- No limits. Just calculate resource usage for time interval. -->
|
||||
<queries>0</queries>
|
||||
<errors>0</errors>
|
||||
<result_rows>0</result_rows>
|
||||
<read_rows>0</read_rows>
|
||||
<execution_time>0</execution_time>
|
||||
</interval>
|
||||
</default>
|
||||
</quotas>
|
||||
</clickhouse>
|
1304
deploy/docker/clickhouse-setup/config.xml
Normal file
1304
deploy/docker/clickhouse-setup/config.xml
Normal file
File diff suppressed because it is too large
Load Diff
@ -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
|
@ -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:
|
||||
|
123
deploy/docker/clickhouse-setup/users.xml
Normal file
123
deploy/docker/clickhouse-setup/users.xml
Normal file
@ -0,0 +1,123 @@
|
||||
<?xml version="1.0"?>
|
||||
<clickhouse>
|
||||
<!-- See also the files in users.d directory where the settings can be overridden. -->
|
||||
|
||||
<!-- Profiles of settings. -->
|
||||
<profiles>
|
||||
<!-- Default settings. -->
|
||||
<default>
|
||||
<!-- Maximum memory usage for processing single query, in bytes. -->
|
||||
<max_memory_usage>10000000000</max_memory_usage>
|
||||
|
||||
<!-- How to choose between replicas during distributed query processing.
|
||||
random - choose random replica from set of replicas with minimum number of errors
|
||||
nearest_hostname - from set of replicas with minimum number of errors, choose replica
|
||||
with minimum number of different symbols between replica's hostname and local hostname
|
||||
(Hamming distance).
|
||||
in_order - first live replica is chosen in specified order.
|
||||
first_or_random - if first replica one has higher number of errors, pick a random one from replicas with minimum number of errors.
|
||||
-->
|
||||
<load_balancing>random</load_balancing>
|
||||
</default>
|
||||
|
||||
<!-- Profile that allows only read queries. -->
|
||||
<readonly>
|
||||
<readonly>1</readonly>
|
||||
</readonly>
|
||||
</profiles>
|
||||
|
||||
<!-- Users and ACL. -->
|
||||
<users>
|
||||
<!-- If user name was not specified, 'default' user is used. -->
|
||||
<default>
|
||||
<!-- See also the files in users.d directory where the password can be overridden.
|
||||
|
||||
Password could be specified in plaintext or in SHA256 (in hex format).
|
||||
|
||||
If you want to specify password in plaintext (not recommended), place it in 'password' element.
|
||||
Example: <password>qwerty</password>.
|
||||
Password could be empty.
|
||||
|
||||
If you want to specify SHA256, place it in 'password_sha256_hex' element.
|
||||
Example: <password_sha256_hex>65e84be33532fb784c48129675f9eff3a682b27168c0ea744b2cf58ee02337c5</password_sha256_hex>
|
||||
Restrictions of SHA256: impossibility to connect to ClickHouse using MySQL JS client (as of July 2019).
|
||||
|
||||
If you want to specify double SHA1, place it in 'password_double_sha1_hex' element.
|
||||
Example: <password_double_sha1_hex>e395796d6546b1b65db9d665cd43f0e858dd4303</password_double_sha1_hex>
|
||||
|
||||
If you want to specify a previously defined LDAP server (see 'ldap_servers' in the main config) for authentication,
|
||||
place its name in 'server' element inside 'ldap' element.
|
||||
Example: <ldap><server>my_ldap_server</server></ldap>
|
||||
|
||||
If you want to authenticate the user via Kerberos (assuming Kerberos is enabled, see 'kerberos' in the main config),
|
||||
place 'kerberos' element instead of 'password' (and similar) elements.
|
||||
The name part of the canonical principal name of the initiator must match the user name for authentication to succeed.
|
||||
You can also place 'realm' element inside 'kerberos' element to further restrict authentication to only those requests
|
||||
whose initiator's realm matches it.
|
||||
Example: <kerberos />
|
||||
Example: <kerberos><realm>EXAMPLE.COM</realm></kerberos>
|
||||
|
||||
How to generate decent password:
|
||||
Execute: PASSWORD=$(base64 < /dev/urandom | head -c8); echo "$PASSWORD"; echo -n "$PASSWORD" | sha256sum | tr -d '-'
|
||||
In first line will be password and in second - corresponding SHA256.
|
||||
|
||||
How to generate double SHA1:
|
||||
Execute: PASSWORD=$(base64 < /dev/urandom | head -c8); echo "$PASSWORD"; echo -n "$PASSWORD" | sha1sum | tr -d '-' | xxd -r -p | sha1sum | tr -d '-'
|
||||
In first line will be password and in second - corresponding double SHA1.
|
||||
-->
|
||||
<password></password>
|
||||
|
||||
<!-- List of networks with open access.
|
||||
|
||||
To open access from everywhere, specify:
|
||||
<ip>::/0</ip>
|
||||
|
||||
To open access only from localhost, specify:
|
||||
<ip>::1</ip>
|
||||
<ip>127.0.0.1</ip>
|
||||
|
||||
Each element of list has one of the following forms:
|
||||
<ip> IP-address or network mask. Examples: 213.180.204.3 or 10.0.0.1/8 or 10.0.0.1/255.255.255.0
|
||||
2a02:6b8::3 or 2a02:6b8::3/64 or 2a02:6b8::3/ffff:ffff:ffff:ffff::.
|
||||
<host> Hostname. Example: server01.clickhouse.com.
|
||||
To check access, DNS query is performed, and all received addresses compared to peer address.
|
||||
<host_regexp> Regular expression for host names. Example, ^server\d\d-\d\d-\d\.clickhouse\.com$
|
||||
To check access, DNS PTR query is performed for peer address and then regexp is applied.
|
||||
Then, for result of PTR query, another DNS query is performed and all received addresses compared to peer address.
|
||||
Strongly recommended that regexp is ends with $
|
||||
All results of DNS requests are cached till server restart.
|
||||
-->
|
||||
<networks>
|
||||
<ip>::/0</ip>
|
||||
</networks>
|
||||
|
||||
<!-- Settings profile for user. -->
|
||||
<profile>default</profile>
|
||||
|
||||
<!-- Quota for user. -->
|
||||
<quota>default</quota>
|
||||
|
||||
<!-- User can create other users and grant rights to them. -->
|
||||
<!-- <access_management>1</access_management> -->
|
||||
</default>
|
||||
</users>
|
||||
|
||||
<!-- Quotas. -->
|
||||
<quotas>
|
||||
<!-- Name of quota. -->
|
||||
<default>
|
||||
<!-- Limits for time interval. You could specify many intervals with different limits. -->
|
||||
<interval>
|
||||
<!-- Length of interval. -->
|
||||
<duration>3600</duration>
|
||||
|
||||
<!-- No limits. Just calculate resource usage for time interval. -->
|
||||
<queries>0</queries>
|
||||
<errors>0</errors>
|
||||
<result_rows>0</result_rows>
|
||||
<read_rows>0</read_rows>
|
||||
<execution_time>0</execution_time>
|
||||
</interval>
|
||||
</default>
|
||||
</quotas>
|
||||
</clickhouse>
|
@ -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;
|
||||
|
@ -2,3 +2,4 @@
|
||||
* Adds custom matchers from the react testing library to all tests
|
||||
*/
|
||||
import '@testing-library/jest-dom';
|
||||
import 'jest-styled-components';
|
||||
|
@ -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",
|
||||
|
@ -2,8 +2,102 @@
|
||||
|
||||
exports[`Not Found page test should render Not Found page without errors 1`] = `
|
||||
<DocumentFragment>
|
||||
<div
|
||||
class="sc-gsDKAQ cLXpIa"
|
||||
.c3 {
|
||||
border: 2px solid #2f80ed;
|
||||
box-sizing: border-box;
|
||||
border-radius: 10px;
|
||||
width: 400px;
|
||||
background: inherit;
|
||||
font-style: normal;
|
||||
font-weight: normal;
|
||||
font-size: 24px;
|
||||
line-height: 20px;
|
||||
display: -webkit-box;
|
||||
display: -webkit-flex;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
-webkit-align-items: center;
|
||||
-webkit-box-align: center;
|
||||
-ms-flex-align: center;
|
||||
align-items: center;
|
||||
-webkit-box-pack: center;
|
||||
-webkit-justify-content: center;
|
||||
-ms-flex-pack: center;
|
||||
justify-content: center;
|
||||
padding-top: 14px;
|
||||
padding-bottom: 14px;
|
||||
color: #2f80ed;
|
||||
}
|
||||
|
||||
.c0 {
|
||||
min-height: 80vh;
|
||||
display: -webkit-box;
|
||||
display: -webkit-flex;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
-webkit-flex-direction: column;
|
||||
-ms-flex-direction: column;
|
||||
flex-direction: column;
|
||||
-webkit-box-pack: center;
|
||||
-webkit-justify-content: center;
|
||||
-ms-flex-pack: center;
|
||||
justify-content: center;
|
||||
-webkit-align-items: center;
|
||||
-webkit-box-align: center;
|
||||
-ms-flex-align: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.c2 {
|
||||
font-style: normal;
|
||||
font-weight: 300;
|
||||
font-size: 18px;
|
||||
line-height: 20px;
|
||||
display: -webkit-box;
|
||||
display: -webkit-flex;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
-webkit-align-items: center;
|
||||
-webkit-box-align: center;
|
||||
-ms-flex-align: center;
|
||||
align-items: center;
|
||||
text-align: center;
|
||||
color: #828282;
|
||||
text-align: center;
|
||||
margin: 0;
|
||||
display: -webkit-box;
|
||||
display: -webkit-flex;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
-webkit-box-pack: center;
|
||||
-webkit-justify-content: center;
|
||||
-ms-flex-pack: center;
|
||||
justify-content: center;
|
||||
-webkit-align-items: center;
|
||||
-webkit-box-align: center;
|
||||
-ms-flex-align: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.c1 {
|
||||
min-height: 50px;
|
||||
display: -webkit-box;
|
||||
display: -webkit-flex;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
-webkit-box-pack: justify;
|
||||
-webkit-justify-content: space-between;
|
||||
-ms-flex-pack: justify;
|
||||
justify-content: space-between;
|
||||
-webkit-flex-direction: column;
|
||||
-ms-flex-direction: column;
|
||||
flex-direction: column;
|
||||
margin-bottom: 30px;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
<div
|
||||
class="c0"
|
||||
>
|
||||
<svg
|
||||
fill="none"
|
||||
@ -272,21 +366,21 @@ exports[`Not Found page test should render Not Found page without errors 1`] = `
|
||||
</defs>
|
||||
</svg>
|
||||
<div
|
||||
class="sc-hKwDye foaleg"
|
||||
class="c1"
|
||||
>
|
||||
<p
|
||||
class="sc-dkPtRN fcyVIq"
|
||||
class="c2"
|
||||
>
|
||||
Ah, seems like we reached a dead end!
|
||||
</p>
|
||||
<p
|
||||
class="sc-dkPtRN fcyVIq"
|
||||
class="c2"
|
||||
>
|
||||
Page Not Found
|
||||
</p>
|
||||
</div>
|
||||
<a
|
||||
class="sc-bdvvtL dbTZkj"
|
||||
class="c3"
|
||||
href="/application"
|
||||
tabindex="0"
|
||||
>
|
||||
|
@ -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',
|
||||
|
@ -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),
|
||||
|
@ -218,7 +218,7 @@ function GridGraph(props: Props): JSX.Element {
|
||||
const onLayoutChangeHandler = async (layout: Layout[]): Promise<void> => {
|
||||
setLayoutFunction(layout);
|
||||
|
||||
await onLayoutSaveHandler(layout);
|
||||
// await onLayoutSaveHandler(layout);
|
||||
};
|
||||
|
||||
const onAddPanelHandler = useCallback(() => {
|
||||
|
@ -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<Alerts> = [
|
||||
|
@ -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]);
|
||||
});
|
||||
});
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -15,7 +15,7 @@ const menus: SidebarMenu[] = [
|
||||
{
|
||||
Icon: BarChartOutlined,
|
||||
to: ROUTES.APPLICATION,
|
||||
name: 'Metrics',
|
||||
name: 'Services',
|
||||
},
|
||||
{
|
||||
Icon: AlignLeftOutlined,
|
||||
|
@ -16,6 +16,7 @@ const breadcrumbNameMap = {
|
||||
[ROUTES.ORG_SETTINGS]: 'Organization Settings',
|
||||
[ROUTES.MY_SETTINGS]: 'My Settings',
|
||||
[ROUTES.ERROR_DETAIL]: 'Errors',
|
||||
[ROUTES.LIST_ALL_ALERT]: 'Alerts',
|
||||
};
|
||||
|
||||
function ShowBreadcrumbs(props: RouteComponentProps): JSX.Element {
|
||||
|
@ -1,12 +1,19 @@
|
||||
import React from 'react';
|
||||
import { useSelector } from 'react-redux';
|
||||
import { Button, Input } from 'antd';
|
||||
import React, { useState } from 'react';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import { Dispatch } from 'redux';
|
||||
import { AppState } from 'store/reducers';
|
||||
import { INITIAL_FILTER_VALUE } from 'store/reducers/trace';
|
||||
import AppActions from 'types/actions';
|
||||
import { UPDATE_SPAN_UPDATE_FILTER_DISPLAY_VALUE } from 'types/actions/trace';
|
||||
import { TraceFilterEnum, TraceReducer } from 'types/reducer/trace';
|
||||
|
||||
import CheckBoxComponent from '../Common/Checkbox';
|
||||
|
||||
const { Search } = Input;
|
||||
|
||||
function CommonCheckBox(props: CommonCheckBoxProps): JSX.Element {
|
||||
const { filter } = useSelector<AppState, TraceReducer>(
|
||||
const { filter, filterDisplayValue } = useSelector<AppState, TraceReducer>(
|
||||
(state) => state.traces,
|
||||
);
|
||||
|
||||
@ -15,9 +22,40 @@ function CommonCheckBox(props: CommonCheckBoxProps): JSX.Element {
|
||||
const status = filter.get(name) || {};
|
||||
|
||||
const statusObj = Object.keys(status);
|
||||
const numberOfFilters = filterDisplayValue.get(name) || 0;
|
||||
const dispatch = useDispatch<Dispatch<AppActions>>();
|
||||
const [searchFilter, setSearchFilter] = useState<string>('');
|
||||
|
||||
const onClickMoreHandler = (): void => {
|
||||
const newFilterDisplayValue = new Map(filterDisplayValue);
|
||||
const preValue =
|
||||
(newFilterDisplayValue.get(name) || 0) + INITIAL_FILTER_VALUE;
|
||||
|
||||
newFilterDisplayValue.set(name, preValue);
|
||||
|
||||
dispatch({
|
||||
type: UPDATE_SPAN_UPDATE_FILTER_DISPLAY_VALUE,
|
||||
payload: newFilterDisplayValue,
|
||||
});
|
||||
};
|
||||
|
||||
const isMoreButtonAvilable = Boolean(
|
||||
numberOfFilters && statusObj.length > numberOfFilters,
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
{statusObj.length > 0 && (
|
||||
<Search
|
||||
value={searchFilter}
|
||||
onChange={(e): void => setSearchFilter(e.target.value)}
|
||||
style={{
|
||||
padding: '0 3%',
|
||||
}}
|
||||
placeholder="Filter Values"
|
||||
/>
|
||||
)}
|
||||
|
||||
{statusObj
|
||||
.sort((a, b) => {
|
||||
const countA = +status[a];
|
||||
@ -28,6 +66,15 @@ function CommonCheckBox(props: CommonCheckBoxProps): JSX.Element {
|
||||
}
|
||||
return countA - countB;
|
||||
})
|
||||
.filter((filter) => {
|
||||
if (searchFilter.length === 0) {
|
||||
return true;
|
||||
}
|
||||
return filter
|
||||
.toLocaleLowerCase()
|
||||
.includes(searchFilter.toLocaleLowerCase());
|
||||
})
|
||||
.filter((_, index) => index < numberOfFilters)
|
||||
.map((e) => (
|
||||
<CheckBoxComponent
|
||||
key={e}
|
||||
@ -38,6 +85,12 @@ function CommonCheckBox(props: CommonCheckBoxProps): JSX.Element {
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
|
||||
{isMoreButtonAvilable && (
|
||||
<Button onClick={onClickMoreHandler} type="link">
|
||||
More
|
||||
</Button>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
@ -1,11 +1,14 @@
|
||||
/* eslint-disable react/no-unstable-nested-components */
|
||||
import { Input, Slider } from 'antd';
|
||||
import { Slider } from 'antd';
|
||||
import { SliderRangeProps } from 'antd/lib/slider';
|
||||
import getFilters from 'api/trace/getFilters';
|
||||
import dayjs from 'dayjs';
|
||||
import durationPlugin from 'dayjs/plugin/duration';
|
||||
import useDebouncedFn from 'hooks/useDebouncedFunction';
|
||||
import React, { useEffect, useMemo, useRef, useState } from 'react';
|
||||
import React, {
|
||||
useCallback,
|
||||
useEffect,
|
||||
useMemo,
|
||||
useRef,
|
||||
useState,
|
||||
} from 'react';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import { Dispatch } from 'redux';
|
||||
import { getFilter, updateURL } from 'store/actions/trace/util';
|
||||
@ -15,19 +18,8 @@ import { UPDATE_ALL_FILTERS } from 'types/actions/trace';
|
||||
import { GlobalReducer } from 'types/reducer/globalTime';
|
||||
import { TraceReducer } from 'types/reducer/trace';
|
||||
|
||||
import { Container, InputContainer, Text } from './styles';
|
||||
|
||||
dayjs.extend(durationPlugin);
|
||||
|
||||
const getMs = (value: string): string => {
|
||||
return parseFloat(
|
||||
dayjs
|
||||
.duration({
|
||||
milliseconds: parseInt(value, 10) / 1000000,
|
||||
})
|
||||
.format('SSS'),
|
||||
).toFixed(2);
|
||||
};
|
||||
import { Container, InputComponent, InputContainer, Text } from './styles';
|
||||
import { getMs } from './util';
|
||||
|
||||
function Duration(): JSX.Element {
|
||||
const {
|
||||
@ -77,17 +69,18 @@ function Duration(): JSX.Element {
|
||||
preLocalMinDuration.current = parseFloat(minDuration);
|
||||
}
|
||||
|
||||
setPreMax(maxDuration);
|
||||
setPreMin(minDuration);
|
||||
setPreMax(getMs(maxDuration));
|
||||
setPreMin(getMs(minDuration));
|
||||
}, [getDuration]);
|
||||
|
||||
const defaultValue = [parseFloat(preMin), parseFloat(preMax)];
|
||||
|
||||
const updatedUrl = async (min: number, max: number): Promise<void> => {
|
||||
const preSelectedFilter = new Map(selectedFilter);
|
||||
const preUserSelected = new Map(userSelectedFilter);
|
||||
|
||||
preSelectedFilter.set('duration', [String(max), String(min)]);
|
||||
preSelectedFilter.set('duration', [
|
||||
String(max * 1000000),
|
||||
String(min * 1000000),
|
||||
]);
|
||||
|
||||
const response = await getFilters({
|
||||
end: String(globalTime.maxTime),
|
||||
@ -137,18 +130,18 @@ function Duration(): JSX.Element {
|
||||
}
|
||||
};
|
||||
|
||||
const onRangeSliderHandler = (number: [number, number]): void => {
|
||||
const onRangeSliderHandler = (number: [string, string]): void => {
|
||||
const [min, max] = number;
|
||||
|
||||
setPreMin(min.toString());
|
||||
setPreMax(max.toString());
|
||||
setPreMin(min);
|
||||
setPreMax(max);
|
||||
};
|
||||
|
||||
const debouncedFunction = useDebouncedFn(
|
||||
(min, max) => {
|
||||
updatedUrl(min as number, max as number);
|
||||
},
|
||||
500,
|
||||
1500,
|
||||
undefined,
|
||||
);
|
||||
|
||||
@ -156,8 +149,8 @@ function Duration(): JSX.Element {
|
||||
event,
|
||||
) => {
|
||||
const { value } = event.target;
|
||||
const min = parseFloat(preMin);
|
||||
const max = parseFloat(value) * 1000000;
|
||||
const min = preMin;
|
||||
const max = value;
|
||||
|
||||
onRangeSliderHandler([min, max]);
|
||||
debouncedFunction(min, max);
|
||||
@ -167,8 +160,9 @@ function Duration(): JSX.Element {
|
||||
event,
|
||||
) => {
|
||||
const { value } = event.target;
|
||||
const min = parseFloat(value) * 1000000;
|
||||
const max = parseFloat(preMax);
|
||||
const min = value;
|
||||
const max = preMax;
|
||||
|
||||
onRangeSliderHandler([min, max]);
|
||||
debouncedFunction(min, max);
|
||||
};
|
||||
@ -177,45 +171,48 @@ function Duration(): JSX.Element {
|
||||
updatedUrl(min, max);
|
||||
};
|
||||
|
||||
const TipComponent = useCallback((value) => {
|
||||
if (value === undefined) {
|
||||
return <div />;
|
||||
}
|
||||
return <div>{`${getMs(value?.toString())}ms`}</div>;
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Container>
|
||||
<InputContainer>
|
||||
<Text>Min</Text>
|
||||
</InputContainer>
|
||||
<Input
|
||||
<InputComponent
|
||||
addonAfter="ms"
|
||||
type="number"
|
||||
onChange={onChangeMinHandler}
|
||||
value={getMs(preMin)}
|
||||
value={preMin}
|
||||
/>
|
||||
|
||||
<InputContainer>
|
||||
<Text>Max</Text>
|
||||
</InputContainer>
|
||||
<Input
|
||||
<InputComponent
|
||||
addonAfter="ms"
|
||||
type="number"
|
||||
onChange={onChangeMaxHandler}
|
||||
value={getMs(preMax)}
|
||||
value={preMax}
|
||||
/>
|
||||
</Container>
|
||||
|
||||
<Container>
|
||||
<Slider
|
||||
defaultValue={[defaultValue[0], defaultValue[1]]}
|
||||
min={parseFloat((preLocalMinDuration.current || 0).toString())}
|
||||
max={parseFloat((preLocalMaxDuration.current || 0).toString())}
|
||||
min={Number(getMs(String(preLocalMinDuration.current || 0)))}
|
||||
max={Number(getMs(String(preLocalMaxDuration.current || 0)))}
|
||||
range
|
||||
tipFormatter={(value): JSX.Element => {
|
||||
if (value === undefined) {
|
||||
return <div />;
|
||||
}
|
||||
return <div>{`${getMs(value?.toString())}ms`}</div>;
|
||||
}}
|
||||
tipFormatter={TipComponent}
|
||||
onChange={([min, max]): void => {
|
||||
onRangeSliderHandler([min, max]);
|
||||
onRangeSliderHandler([String(min), String(max)]);
|
||||
}}
|
||||
onAfterChange={onRangeHandler}
|
||||
value={[parseFloat(preMin), parseFloat(preMax)]}
|
||||
value={[Number(preMin), Number(preMax)]}
|
||||
/>
|
||||
</Container>
|
||||
</div>
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { Typography } from 'antd';
|
||||
import { Input, Typography } from 'antd';
|
||||
import styled from 'styled-components';
|
||||
|
||||
export const DurationText = styled.div`
|
||||
@ -9,6 +9,19 @@ export const DurationText = styled.div`
|
||||
flex-direction: column;
|
||||
`;
|
||||
|
||||
export const InputComponent = styled(Input)`
|
||||
input::-webkit-outer-spin-button,
|
||||
input::-webkit-inner-spin-button {
|
||||
-webkit-appearance: none;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/* Firefox */
|
||||
input[type='number'] {
|
||||
-moz-appearance: textfield;
|
||||
}
|
||||
`;
|
||||
|
||||
export const InputContainer = styled.div`
|
||||
width: 100%;
|
||||
margin-top: 0.5rem;
|
||||
|
@ -0,0 +1,13 @@
|
||||
import dayjs from 'dayjs';
|
||||
import durationPlugin from 'dayjs/plugin/duration';
|
||||
|
||||
dayjs.extend(durationPlugin);
|
||||
|
||||
export const getMs = (value: string): string =>
|
||||
parseFloat(
|
||||
dayjs
|
||||
.duration({
|
||||
milliseconds: parseInt(value, 10) / 1000000,
|
||||
})
|
||||
.format('SSS'),
|
||||
).toFixed(2);
|
@ -73,11 +73,24 @@ function TagsKey(props: TagsKeysProps): JSX.Element {
|
||||
<AutoComplete
|
||||
dropdownClassName="certain-category-search-dropdown"
|
||||
dropdownMatchSelectWidth={500}
|
||||
style={{ width: 300 }}
|
||||
options={options}
|
||||
style={{ width: '100%' }}
|
||||
value={selectedKey}
|
||||
onChange={(value): void => {
|
||||
if (options && options.find((option) => option.value === value)) {
|
||||
allowClear
|
||||
showSearch
|
||||
options={options?.map((e) => ({
|
||||
label: e.label?.toString(),
|
||||
value: e.value,
|
||||
}))}
|
||||
filterOption={(inputValue, option): boolean =>
|
||||
option?.label?.toUpperCase().indexOf(inputValue.toUpperCase()) !== -1
|
||||
}
|
||||
onChange={(e): void => setSelectedKey(e)}
|
||||
onSelect={(value: unknown): void => {
|
||||
if (
|
||||
typeof value === 'string' &&
|
||||
options &&
|
||||
options.find((option) => option.value === value)
|
||||
) {
|
||||
setSelectedKey(value);
|
||||
|
||||
setLocalSelectedTags((tags) => [
|
||||
@ -89,8 +102,6 @@ function TagsKey(props: TagsKeysProps): JSX.Element {
|
||||
},
|
||||
...tags.slice(index + 1, tags.length),
|
||||
]);
|
||||
} else {
|
||||
setSelectedKey('');
|
||||
}
|
||||
}}
|
||||
>
|
||||
|
@ -1,13 +1,13 @@
|
||||
import { Select } from 'antd';
|
||||
import getTagValue from 'api/trace/getTagValue';
|
||||
import React from 'react';
|
||||
import React, { useState } from 'react';
|
||||
import { useQuery } from 'react-query';
|
||||
import { useSelector } from 'react-redux';
|
||||
import { AppState } from 'store/reducers';
|
||||
import { GlobalReducer } from 'types/reducer/globalTime';
|
||||
import { TraceReducer } from 'types/reducer/trace';
|
||||
|
||||
import { SelectComponent } from './styles';
|
||||
import { AutoCompleteComponent } from './styles';
|
||||
|
||||
function TagValue(props: TagValueProps): JSX.Element {
|
||||
const { tag, setLocalSelectedTags, index, tagKey } = props;
|
||||
@ -16,6 +16,7 @@ function TagValue(props: TagValueProps): JSX.Element {
|
||||
Operator: selectedOperator,
|
||||
Values: selectedValues,
|
||||
} = tag;
|
||||
const [localValue, setLocalValue] = useState<string>(selectedValues[0]);
|
||||
|
||||
const globalReducer = useSelector<AppState, GlobalReducer>(
|
||||
(state) => state.globalTime,
|
||||
@ -34,22 +35,38 @@ function TagValue(props: TagValueProps): JSX.Element {
|
||||
);
|
||||
|
||||
return (
|
||||
<SelectComponent
|
||||
value={selectedValues[0]}
|
||||
<AutoCompleteComponent
|
||||
options={data?.payload?.map((e) => ({
|
||||
label: e.tagValues,
|
||||
value: e.tagValues,
|
||||
}))}
|
||||
allowClear
|
||||
defaultOpen
|
||||
showSearch
|
||||
filterOption={(inputValue, option): boolean =>
|
||||
option?.label.toUpperCase().indexOf(inputValue.toUpperCase()) !== -1
|
||||
}
|
||||
disabled={isLoading}
|
||||
value={localValue}
|
||||
onChange={(values): void => {
|
||||
if (typeof values === 'string') {
|
||||
setLocalValue(values);
|
||||
}
|
||||
}}
|
||||
onSelect={(value: unknown): void => {
|
||||
if (typeof value === 'string') {
|
||||
setLocalValue(value);
|
||||
setLocalSelectedTags((tags) => [
|
||||
...tags.slice(0, index),
|
||||
{
|
||||
Key: selectedKey,
|
||||
Operator: selectedOperator,
|
||||
Values: [...selectedValues, value],
|
||||
Values: [value],
|
||||
},
|
||||
...tags.slice(index + 1, tags.length),
|
||||
]);
|
||||
}
|
||||
}}
|
||||
loading={isLoading || false}
|
||||
>
|
||||
{data &&
|
||||
data.payload &&
|
||||
@ -58,7 +75,7 @@ function TagValue(props: TagValueProps): JSX.Element {
|
||||
{suggestion.tagValues}
|
||||
</Select.Option>
|
||||
))}
|
||||
</SelectComponent>
|
||||
</AutoCompleteComponent>
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { Select, Space } from 'antd';
|
||||
import { AutoComplete, Select, Space } from 'antd';
|
||||
import styled from 'styled-components';
|
||||
|
||||
export const SpaceComponent = styled(Space)`
|
||||
@ -9,18 +9,23 @@ export const SpaceComponent = styled(Space)`
|
||||
|
||||
export const SelectComponent = styled(Select)`
|
||||
&&& {
|
||||
min-width: 170px;
|
||||
margin-right: 21.91px;
|
||||
margin-left: 21.92px;
|
||||
width: 100%;
|
||||
}
|
||||
`;
|
||||
|
||||
export const Container = styled.div`
|
||||
export const Container = styled(Space)`
|
||||
&&& {
|
||||
display: flex;
|
||||
margin-top: 1rem;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.ant-space-item:not(:last-child, :nth-child(2)) {
|
||||
width: 100%;
|
||||
}
|
||||
.ant-space-item:nth-child(2) {
|
||||
width: 50%;
|
||||
}
|
||||
`;
|
||||
|
||||
export const IconContainer = styled.div`
|
||||
@ -31,3 +36,9 @@ export const IconContainer = styled.div`
|
||||
|
||||
margin-left: 1.125rem;
|
||||
`;
|
||||
|
||||
export const AutoCompleteComponent = styled(AutoComplete)`
|
||||
&&& {
|
||||
width: 100%;
|
||||
}
|
||||
`;
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { Space, Tabs, Typography } from 'antd';
|
||||
import { Tabs, Tooltip, Typography } from 'antd';
|
||||
import { StyledSpace } from 'components/Styled';
|
||||
import useThemeMode from 'hooks/useThemeMode';
|
||||
import React from 'react';
|
||||
import React, { useMemo } from 'react';
|
||||
import { ITraceTree } from 'types/api/trace/getTraceItem';
|
||||
|
||||
import ErrorTag from './ErrorTag';
|
||||
@ -19,29 +19,38 @@ const { TabPane } = Tabs;
|
||||
function SelectedSpanDetails(props: SelectedSpanDetailsProps): JSX.Element {
|
||||
const { tree } = props;
|
||||
const { isDarkMode } = useThemeMode();
|
||||
|
||||
const OverLayComponentName = useMemo(() => tree?.name, [tree?.name]);
|
||||
const OverLayComponentServiceName = useMemo(() => tree?.serviceName, [
|
||||
tree?.serviceName,
|
||||
]);
|
||||
|
||||
if (!tree) {
|
||||
return <div />;
|
||||
}
|
||||
|
||||
const { name, tags, serviceName } = tree;
|
||||
const { tags } = tree;
|
||||
|
||||
return (
|
||||
<CardContainer>
|
||||
<StyledSpace
|
||||
styledclass={[styles.selectedSpanDetailsContainer]}
|
||||
styledclass={[styles.selectedSpanDetailsContainer, styles.overflow]}
|
||||
direction="vertical"
|
||||
style={{ marginLeft: '0.5rem' }}
|
||||
>
|
||||
<strong> Details for selected Span </strong>
|
||||
<Space direction="vertical" size={2}>
|
||||
<CustomTitle>Service</CustomTitle>
|
||||
<CustomText>{serviceName}</CustomText>
|
||||
</Space>
|
||||
<Space direction="vertical" size={2}>
|
||||
<CustomTitle>Operation</CustomTitle>
|
||||
<CustomText>{name}</CustomText>
|
||||
</Space>
|
||||
|
||||
<CustomTitle>Service</CustomTitle>
|
||||
<Tooltip overlay={OverLayComponentServiceName}>
|
||||
<CustomText ellipsis>{tree.serviceName}</CustomText>
|
||||
</Tooltip>
|
||||
|
||||
<CustomTitle>Operation</CustomTitle>
|
||||
<Tooltip overlay={OverLayComponentName}>
|
||||
<CustomText ellipsis>{tree.name}</CustomText>
|
||||
</Tooltip>
|
||||
</StyledSpace>
|
||||
|
||||
<Tabs defaultActiveKey="1">
|
||||
<TabPane tab="Tags" key="1">
|
||||
{tags.length !== 0 ? (
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { Typography } from 'antd';
|
||||
import { Space, Typography } from 'antd';
|
||||
import styled, { css } from 'styled-components';
|
||||
|
||||
const { Text, Title, Paragraph } = Typography;
|
||||
const { Title, Paragraph } = Typography;
|
||||
|
||||
export const CustomTitle = styled(Title)`
|
||||
&&& {
|
||||
@ -9,7 +9,7 @@ export const CustomTitle = styled(Title)`
|
||||
}
|
||||
`;
|
||||
|
||||
export const CustomText = styled(Text)`
|
||||
export const CustomText = styled(Paragraph)`
|
||||
&&& {
|
||||
color: #2d9cdb;
|
||||
}
|
||||
@ -17,7 +17,6 @@ export const CustomText = styled(Text)`
|
||||
|
||||
export const CustomSubTitle = styled(Title)`
|
||||
&&& {
|
||||
/* color: #bdbdbd; */
|
||||
font-size: 14px;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
@ -44,6 +43,17 @@ export const CardContainer = styled.div`
|
||||
width: 100%;
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
`;
|
||||
|
||||
export const CustomSpace = styled(Space)`
|
||||
&&& {
|
||||
.ant-space-item {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const removeMargin = css`
|
||||
@ -60,9 +70,21 @@ const selectedSpanDetailsContainer = css`
|
||||
const spanEventsTabsContainer = css`
|
||||
margin-top: 1rem;
|
||||
`;
|
||||
|
||||
const overflow = css`
|
||||
width: 95%;
|
||||
|
||||
> div.ant-space-item:nth-child(4) {
|
||||
overflow-x: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
`;
|
||||
|
||||
export const styles = {
|
||||
removeMargin,
|
||||
removePadding,
|
||||
selectedSpanDetailsContainer,
|
||||
spanEventsTabsContainer,
|
||||
overflow,
|
||||
};
|
||||
|
@ -2,12 +2,30 @@
|
||||
|
||||
exports[`loads and displays greeting 1`] = `
|
||||
<DocumentFragment>
|
||||
<div
|
||||
class="sc-gsDKAQ jFDWPs"
|
||||
.c1 {
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
left: NaN%;
|
||||
width: Infinity%;
|
||||
height: 10px;
|
||||
margin: 1px 0;
|
||||
background-color: hsl(282.9,100%,60.7%);
|
||||
border-radius: 5px;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.c0 {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 120px;
|
||||
}
|
||||
|
||||
<div
|
||||
class="c0"
|
||||
height="0"
|
||||
>
|
||||
<div
|
||||
class="sc-bdvvtL fyFVjh"
|
||||
class="c1"
|
||||
title=""
|
||||
width="Infinity"
|
||||
/>
|
||||
|
@ -1,23 +1,45 @@
|
||||
import { notification } from 'antd';
|
||||
import get from 'api/alerts/get';
|
||||
import Spinner from 'components/Spinner';
|
||||
import ROUTES from 'constants/routes';
|
||||
import EditRulesContainer from 'container/EditRules';
|
||||
import React from 'react';
|
||||
import history from 'lib/history';
|
||||
import React, { useEffect } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useQuery } from 'react-query';
|
||||
import { useParams } from 'react-router-dom';
|
||||
import { useLocation } from 'react-router-dom';
|
||||
|
||||
function EditRules(): JSX.Element {
|
||||
const { ruleId } = useParams<EditRulesParam>();
|
||||
const { search } = useLocation();
|
||||
const params = new URLSearchParams(search);
|
||||
const ruleId = params.get('ruleId');
|
||||
|
||||
const { t } = useTranslation('common');
|
||||
|
||||
const isValidRuleId = ruleId !== null && String(ruleId).length !== 0;
|
||||
|
||||
const { isLoading, data, isError } = useQuery(['ruleId', ruleId], {
|
||||
queryFn: () =>
|
||||
get({
|
||||
id: parseInt(ruleId, 10),
|
||||
id: parseInt(ruleId || '', 10),
|
||||
}),
|
||||
enabled: isValidRuleId,
|
||||
});
|
||||
|
||||
if (isError) {
|
||||
useEffect(() => {
|
||||
if (!isValidRuleId) {
|
||||
notification.error({
|
||||
message: 'Rule Id is required',
|
||||
});
|
||||
history.replace(ROUTES.LIST_ALL_ALERT);
|
||||
}
|
||||
}, [isValidRuleId, ruleId]);
|
||||
|
||||
if (
|
||||
(isError && !isValidRuleId) ||
|
||||
ruleId == null ||
|
||||
(data?.payload?.data === undefined && !isLoading)
|
||||
) {
|
||||
return <div>{data?.error || t('something_went_wrong')}</div>;
|
||||
}
|
||||
|
||||
@ -28,8 +50,4 @@ function EditRules(): JSX.Element {
|
||||
return <EditRulesContainer ruleId={ruleId} initialData={data.payload.data} />;
|
||||
}
|
||||
|
||||
interface EditRulesParam {
|
||||
ruleId: string;
|
||||
}
|
||||
|
||||
export default EditRules;
|
||||
|
@ -11,6 +11,7 @@ import {
|
||||
UPDATE_SELECTED_TAGS,
|
||||
UPDATE_SPAN_ORDER,
|
||||
UPDATE_SPAN_ORDER_PARAMS,
|
||||
UPDATE_SPAN_UPDATE_FILTER_DISPLAY_VALUE,
|
||||
UPDATE_SPANS_AGGREGATE,
|
||||
UPDATE_SPANS_AGGREGATE_PAGE_NUMBER,
|
||||
UPDATE_SPANS_AGGREGATE_PAGE_SIZE,
|
||||
@ -23,6 +24,8 @@ import {
|
||||
} from 'types/actions/trace';
|
||||
import { TraceFilterEnum, TraceReducer } from 'types/reducer/trace';
|
||||
|
||||
export const INITIAL_FILTER_VALUE = 8;
|
||||
|
||||
const initialValue: TraceReducer = {
|
||||
filter: new Map(),
|
||||
filterToFetchData: ['duration', 'status', 'serviceName'],
|
||||
@ -53,6 +56,17 @@ const initialValue: TraceReducer = {
|
||||
loading: true,
|
||||
payload: { items: {} },
|
||||
},
|
||||
filterDisplayValue: new Map<TraceFilterEnum, number>([
|
||||
['component', INITIAL_FILTER_VALUE],
|
||||
['duration', INITIAL_FILTER_VALUE],
|
||||
['httpCode', INITIAL_FILTER_VALUE],
|
||||
['httpHost', INITIAL_FILTER_VALUE],
|
||||
['httpMethod', INITIAL_FILTER_VALUE],
|
||||
['httpUrl', INITIAL_FILTER_VALUE],
|
||||
['operation', INITIAL_FILTER_VALUE],
|
||||
['serviceName', INITIAL_FILTER_VALUE],
|
||||
['status', INITIAL_FILTER_VALUE],
|
||||
]),
|
||||
};
|
||||
|
||||
const traceReducer = (
|
||||
@ -251,6 +265,13 @@ const traceReducer = (
|
||||
};
|
||||
}
|
||||
|
||||
case UPDATE_SPAN_UPDATE_FILTER_DISPLAY_VALUE: {
|
||||
return {
|
||||
...state,
|
||||
filterDisplayValue: action.payload,
|
||||
};
|
||||
}
|
||||
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
|
@ -31,6 +31,8 @@ export const UPDATE_SPANS_AGGREGATE_PAGE_NUMBER =
|
||||
export const UPDATE_SPANS_AGGREGATE_PAGE_SIZE =
|
||||
'UPDATE_SPANS_AGGREGATE_PAGE_SIZE';
|
||||
export const UPDATE_SPAN_ORDER_PARAMS = 'UPDATE_SPAN_ORDER_PARAMS';
|
||||
export const UPDATE_SPAN_UPDATE_FILTER_DISPLAY_VALUE =
|
||||
'UPDATE_SPAN_UPDATE_FILTER_DISPLAY_VALUE';
|
||||
|
||||
export interface UpdateFilter {
|
||||
type: typeof UPDATE_TRACE_FILTER;
|
||||
@ -187,6 +189,11 @@ export interface UpdateSpanParams {
|
||||
};
|
||||
}
|
||||
|
||||
export interface UpdateTraceFilterDisplayValue {
|
||||
type: typeof UPDATE_SPAN_UPDATE_FILTER_DISPLAY_VALUE;
|
||||
payload: TraceReducer['filterDisplayValue'];
|
||||
}
|
||||
|
||||
export type TraceActions =
|
||||
| UpdateFilter
|
||||
| GetTraceFilter
|
||||
@ -208,4 +215,5 @@ export type TraceActions =
|
||||
| UpdateSpanOrder
|
||||
| UpdateSpansAggregatePageNumber
|
||||
| UpdateSpanSize
|
||||
| UpdateSpanParams;
|
||||
| UpdateSpanParams
|
||||
| UpdateTraceFilterDisplayValue;
|
||||
|
@ -32,6 +32,7 @@ export interface TraceReducer {
|
||||
payload: PayloadProps;
|
||||
};
|
||||
yAxisUnit: string | undefined;
|
||||
filterDisplayValue: Map<TraceFilterEnum, number>;
|
||||
}
|
||||
|
||||
interface SpansAggregateData {
|
||||
|
@ -35,6 +35,7 @@
|
||||
"playwright.config.ts",
|
||||
"./commitlint.config.js",
|
||||
"./webpack.config.js",
|
||||
"./webpack.config.prod.js"
|
||||
"./webpack.config.prod.js",
|
||||
"./jest.setup.ts"
|
||||
]
|
||||
}
|
||||
|
@ -8128,6 +8128,13 @@ jest-snapshot@^27.5.1:
|
||||
pretty-format "^27.5.1"
|
||||
semver "^7.3.2"
|
||||
|
||||
jest-styled-components@^7.0.8:
|
||||
version "7.0.8"
|
||||
resolved "https://registry.yarnpkg.com/jest-styled-components/-/jest-styled-components-7.0.8.tgz#9ea3b43f002de060b4638fde3b422d14b3e3ec9f"
|
||||
integrity sha512-0KE54d0yIzKcvtOv8eikyjG3rFRtKYUyQovaoha3nondtZzXYGB3bhsvYgEegU08Iry0ndWx2+g9f5ZzD4I+0Q==
|
||||
dependencies:
|
||||
css "^3.0.0"
|
||||
|
||||
jest-util@^26.6.2:
|
||||
version "26.6.2"
|
||||
resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-26.6.2.tgz#907535dbe4d5a6cb4c47ac9b926f6af29576cbc1"
|
||||
|
@ -592,21 +592,45 @@ func (r *ClickHouseReader) GetRulesFromDB() (*[]model.RuleResponseItem, *model.A
|
||||
|
||||
func (r *ClickHouseReader) GetRule(id string) (*model.RuleResponseItem, *model.ApiError) {
|
||||
|
||||
idInt, _ := strconv.Atoi(id)
|
||||
idInt, err := strconv.Atoi(id)
|
||||
if err != nil {
|
||||
zap.S().Debug("Error in parsing param: ", err)
|
||||
return nil, &model.ApiError{Typ: model.ErrorBadData, Err: err}
|
||||
}
|
||||
|
||||
rule := &model.RuleResponseItem{}
|
||||
|
||||
query := fmt.Sprintf("SELECT id, updated_at, data FROM rules WHERE id=%d", idInt)
|
||||
|
||||
err := r.localDB.Get(rule, query)
|
||||
|
||||
zap.S().Info(query)
|
||||
query := "SELECT id, updated_at, data FROM rules WHERE id=?"
|
||||
rows, err := r.localDB.Query(query, idInt)
|
||||
|
||||
if err != nil {
|
||||
zap.S().Debug("Error in processing sql query: ", err)
|
||||
return nil, &model.ApiError{Typ: model.ErrorInternal, Err: err}
|
||||
}
|
||||
|
||||
count := 0
|
||||
// iterate over each row
|
||||
for rows.Next() {
|
||||
err = rows.Scan(&rule.Id, &rule.UpdatedAt, &rule.Data)
|
||||
if err != nil {
|
||||
zap.S().Debug(err)
|
||||
return nil, &model.ApiError{Typ: model.ErrorInternal, Err: err}
|
||||
}
|
||||
count += 1
|
||||
|
||||
}
|
||||
|
||||
if count == 0 {
|
||||
err = fmt.Errorf("no rule with id %d found", idInt)
|
||||
zap.S().Debug(err)
|
||||
return nil, &model.ApiError{Typ: model.ErrorNotFound, Err: err}
|
||||
}
|
||||
if count > 1 {
|
||||
err = fmt.Errorf("multiple rules with id %d found", idInt)
|
||||
zap.S().Debug(err)
|
||||
return nil, &model.ApiError{Typ: model.ErrorConflict, Err: err}
|
||||
}
|
||||
|
||||
return rule, nil
|
||||
}
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
28
pkg/query-service/tests/test-deploy/clickhouse-storage.xml
Normal file
28
pkg/query-service/tests/test-deploy/clickhouse-storage.xml
Normal file
@ -0,0 +1,28 @@
|
||||
<?xml version="1.0"?>
|
||||
<clickhouse>
|
||||
<storage_configuration>
|
||||
<disks>
|
||||
<default>
|
||||
<keep_free_space_bytes>10485760</keep_free_space_bytes>
|
||||
</default>
|
||||
<s3>
|
||||
<type>s3</type>
|
||||
<endpoint>http://172.17.0.1:9100/test//</endpoint>
|
||||
<access_key_id>ash</access_key_id>
|
||||
<secret_access_key>password</secret_access_key>
|
||||
</s3>
|
||||
</disks>
|
||||
<policies>
|
||||
<tiered>
|
||||
<volumes>
|
||||
<default>
|
||||
<disk>default</disk>
|
||||
</default>
|
||||
<s3>
|
||||
<disk>s3</disk>
|
||||
</s3>
|
||||
</volumes>
|
||||
</tiered>
|
||||
</policies>
|
||||
</storage_configuration>
|
||||
</clickhouse>
|
123
pkg/query-service/tests/test-deploy/clickhouse-users.xml
Normal file
123
pkg/query-service/tests/test-deploy/clickhouse-users.xml
Normal file
@ -0,0 +1,123 @@
|
||||
<?xml version="1.0"?>
|
||||
<clickhouse>
|
||||
<!-- See also the files in users.d directory where the settings can be overridden. -->
|
||||
|
||||
<!-- Profiles of settings. -->
|
||||
<profiles>
|
||||
<!-- Default settings. -->
|
||||
<default>
|
||||
<!-- Maximum memory usage for processing single query, in bytes. -->
|
||||
<max_memory_usage>10000000000</max_memory_usage>
|
||||
|
||||
<!-- How to choose between replicas during distributed query processing.
|
||||
random - choose random replica from set of replicas with minimum number of errors
|
||||
nearest_hostname - from set of replicas with minimum number of errors, choose replica
|
||||
with minimum number of different symbols between replica's hostname and local hostname
|
||||
(Hamming distance).
|
||||
in_order - first live replica is chosen in specified order.
|
||||
first_or_random - if first replica one has higher number of errors, pick a random one from replicas with minimum number of errors.
|
||||
-->
|
||||
<load_balancing>random</load_balancing>
|
||||
</default>
|
||||
|
||||
<!-- Profile that allows only read queries. -->
|
||||
<readonly>
|
||||
<readonly>1</readonly>
|
||||
</readonly>
|
||||
</profiles>
|
||||
|
||||
<!-- Users and ACL. -->
|
||||
<users>
|
||||
<!-- If user name was not specified, 'default' user is used. -->
|
||||
<default>
|
||||
<!-- See also the files in users.d directory where the password can be overridden.
|
||||
|
||||
Password could be specified in plaintext or in SHA256 (in hex format).
|
||||
|
||||
If you want to specify password in plaintext (not recommended), place it in 'password' element.
|
||||
Example: <password>qwerty</password>.
|
||||
Password could be empty.
|
||||
|
||||
If you want to specify SHA256, place it in 'password_sha256_hex' element.
|
||||
Example: <password_sha256_hex>65e84be33532fb784c48129675f9eff3a682b27168c0ea744b2cf58ee02337c5</password_sha256_hex>
|
||||
Restrictions of SHA256: impossibility to connect to ClickHouse using MySQL JS client (as of July 2019).
|
||||
|
||||
If you want to specify double SHA1, place it in 'password_double_sha1_hex' element.
|
||||
Example: <password_double_sha1_hex>e395796d6546b1b65db9d665cd43f0e858dd4303</password_double_sha1_hex>
|
||||
|
||||
If you want to specify a previously defined LDAP server (see 'ldap_servers' in the main config) for authentication,
|
||||
place its name in 'server' element inside 'ldap' element.
|
||||
Example: <ldap><server>my_ldap_server</server></ldap>
|
||||
|
||||
If you want to authenticate the user via Kerberos (assuming Kerberos is enabled, see 'kerberos' in the main config),
|
||||
place 'kerberos' element instead of 'password' (and similar) elements.
|
||||
The name part of the canonical principal name of the initiator must match the user name for authentication to succeed.
|
||||
You can also place 'realm' element inside 'kerberos' element to further restrict authentication to only those requests
|
||||
whose initiator's realm matches it.
|
||||
Example: <kerberos />
|
||||
Example: <kerberos><realm>EXAMPLE.COM</realm></kerberos>
|
||||
|
||||
How to generate decent password:
|
||||
Execute: PASSWORD=$(base64 < /dev/urandom | head -c8); echo "$PASSWORD"; echo -n "$PASSWORD" | sha256sum | tr -d '-'
|
||||
In first line will be password and in second - corresponding SHA256.
|
||||
|
||||
How to generate double SHA1:
|
||||
Execute: PASSWORD=$(base64 < /dev/urandom | head -c8); echo "$PASSWORD"; echo -n "$PASSWORD" | sha1sum | tr -d '-' | xxd -r -p | sha1sum | tr -d '-'
|
||||
In first line will be password and in second - corresponding double SHA1.
|
||||
-->
|
||||
<password></password>
|
||||
|
||||
<!-- List of networks with open access.
|
||||
|
||||
To open access from everywhere, specify:
|
||||
<ip>::/0</ip>
|
||||
|
||||
To open access only from localhost, specify:
|
||||
<ip>::1</ip>
|
||||
<ip>127.0.0.1</ip>
|
||||
|
||||
Each element of list has one of the following forms:
|
||||
<ip> IP-address or network mask. Examples: 213.180.204.3 or 10.0.0.1/8 or 10.0.0.1/255.255.255.0
|
||||
2a02:6b8::3 or 2a02:6b8::3/64 or 2a02:6b8::3/ffff:ffff:ffff:ffff::.
|
||||
<host> Hostname. Example: server01.clickhouse.com.
|
||||
To check access, DNS query is performed, and all received addresses compared to peer address.
|
||||
<host_regexp> Regular expression for host names. Example, ^server\d\d-\d\d-\d\.clickhouse\.com$
|
||||
To check access, DNS PTR query is performed for peer address and then regexp is applied.
|
||||
Then, for result of PTR query, another DNS query is performed and all received addresses compared to peer address.
|
||||
Strongly recommended that regexp is ends with $
|
||||
All results of DNS requests are cached till server restart.
|
||||
-->
|
||||
<networks>
|
||||
<ip>::/0</ip>
|
||||
</networks>
|
||||
|
||||
<!-- Settings profile for user. -->
|
||||
<profile>default</profile>
|
||||
|
||||
<!-- Quota for user. -->
|
||||
<quota>default</quota>
|
||||
|
||||
<!-- User can create other users and grant rights to them. -->
|
||||
<!-- <access_management>1</access_management> -->
|
||||
</default>
|
||||
</users>
|
||||
|
||||
<!-- Quotas. -->
|
||||
<quotas>
|
||||
<!-- Name of quota. -->
|
||||
<default>
|
||||
<!-- Limits for time interval. You could specify many intervals with different limits. -->
|
||||
<interval>
|
||||
<!-- Length of interval. -->
|
||||
<duration>3600</duration>
|
||||
|
||||
<!-- No limits. Just calculate resource usage for time interval. -->
|
||||
<queries>0</queries>
|
||||
<errors>0</errors>
|
||||
<result_rows>0</result_rows>
|
||||
<read_rows>0</read_rows>
|
||||
<execution_time>0</execution_time>
|
||||
</interval>
|
||||
</default>
|
||||
</quotas>
|
||||
</clickhouse>
|
@ -1,99 +0,0 @@
|
||||
version: "2.4"
|
||||
|
||||
services:
|
||||
clickhouse:
|
||||
image: altinity/clickhouse-server:21.12.3.32.altinitydev.arm
|
||||
volumes:
|
||||
- ./clickhouse-config.xml:/etc/clickhouse-server/config.xml
|
||||
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
|
||||
depends_on:
|
||||
- query-service
|
||||
restart: on-failure
|
||||
command:
|
||||
- --queryService.url=http://query-service:8085
|
||||
- --storage.path=/data
|
||||
|
||||
query-service:
|
||||
image: signoz/query-service:latest
|
||||
container_name: query-service
|
||||
command: ["-config=/root/config/prometheus.yml"]
|
||||
volumes:
|
||||
- ./prometheus.yml:/root/config/prometheus.yml
|
||||
- ../dashboards:/root/config/dashboards
|
||||
- ./data:/var/lib/signoz
|
||||
ports:
|
||||
- "8180:8080"
|
||||
environment:
|
||||
- ClickHouseUrl=tcp://clickhouse:9000/?database=signoz_traces
|
||||
- STORAGE=clickhouse
|
||||
- GODEBUG=netdns=go
|
||||
- TELEMETRY_ENABLED=true
|
||||
healthcheck:
|
||||
test: ["CMD", "wget", "--spider", "-q", "localhost:8080/api/v1/version"]
|
||||
interval: 30s
|
||||
timeout: 5s
|
||||
retries: 3
|
||||
depends_on:
|
||||
clickhouse:
|
||||
condition: service_healthy
|
||||
|
||||
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
|
||||
mem_limit: 2000m
|
||||
restart: always
|
||||
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
|
||||
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:
|
||||
- ../../../../deploy/docker/common/locust-scripts:/locust
|
@ -2,9 +2,11 @@ version: "2.4"
|
||||
|
||||
services:
|
||||
clickhouse:
|
||||
image: yandex/clickhouse-server:21.12.3.32
|
||||
image: clickhouse/clickhouse-server:22.4.5-alpine
|
||||
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
|
||||
restart: on-failure
|
||||
logging:
|
||||
options:
|
||||
@ -17,8 +19,8 @@ services:
|
||||
timeout: 5s
|
||||
retries: 3
|
||||
ports:
|
||||
- "9000:9000"
|
||||
- "8123:8123"
|
||||
- "9000:9000"
|
||||
- "8123:8123"
|
||||
|
||||
alertmanager:
|
||||
image: signoz/alertmanager:0.23.0-0.1
|
||||
|
Loading…
x
Reference in New Issue
Block a user