Compare commits
423 Commits
feat/gener
...
v0.58.0-on
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
068f2097c4 | ||
|
|
2c9398497e | ||
|
|
7e803ddf0b | ||
|
|
44887084ba | ||
|
|
af2d24e096 | ||
|
|
58b82bd06f | ||
|
|
d7b38ebfb3 | ||
|
|
c641ca5e48 | ||
|
|
d7788315c0 | ||
|
|
87580656c6 | ||
|
|
952ab58023 | ||
|
|
3ca2fff5c5 | ||
|
|
ef3a9adb48 | ||
|
|
975f141604 | ||
|
|
c206f4fa5c | ||
|
|
e88e24e434 | ||
|
|
94e0423479 | ||
|
|
5891fbc229 | ||
|
|
8137ec54ba | ||
|
|
f7b80524a5 | ||
|
|
4be0508dd2 | ||
|
|
a31c4b8339 | ||
|
|
d7846338ce | ||
|
|
5dac1ad20a | ||
|
|
8d704c331c | ||
|
|
f8e47496fa | ||
|
|
6fef9d9676 | ||
|
|
190767fd0a | ||
|
|
1e78786cae | ||
|
|
6448fb17e7 | ||
|
|
f2e33d7ca9 | ||
|
|
6c7167a224 | ||
|
|
00421235b0 | ||
|
|
0e2b67059b | ||
|
|
910c44cefc | ||
|
|
8bad036423 | ||
|
|
a21830132f | ||
|
|
9419f56e95 | ||
|
|
347868c18b | ||
|
|
17e20e7f41 | ||
|
|
2b0da82f94 | ||
|
|
911362cecf | ||
|
|
481f9620d3 | ||
|
|
e5be431f18 | ||
|
|
503ed45a99 | ||
|
|
28818fbaac | ||
|
|
c0e40614bf | ||
|
|
2d732ae4a9 | ||
|
|
8466e31e02 | ||
|
|
efdaf7ee43 | ||
|
|
0dec94a5c6 | ||
|
|
204728ff60 | ||
|
|
e51f4d986d | ||
|
|
337a941d0d | ||
|
|
fc4b55cb34 | ||
|
|
96cb8053df | ||
|
|
5651d69485 | ||
|
|
a6e492880d | ||
|
|
80b3c3e256 | ||
|
|
0806420dd7 | ||
|
|
18e240e3d1 | ||
|
|
d0965a24c5 | ||
|
|
7ed689693f | ||
|
|
90ae55264a | ||
|
|
bf4c792cdb | ||
|
|
dd097821d1 | ||
|
|
701b8803ac | ||
|
|
2728ddd255 | ||
|
|
5187ed58a0 | ||
|
|
2180118094 | ||
|
|
ecae842fa1 | ||
|
|
291b3ba357 | ||
|
|
78d1e19e60 | ||
|
|
fa9e89bfe7 | ||
|
|
16f49a1d25 | ||
|
|
c95c0f9a15 | ||
|
|
5588c7dd3f | ||
|
|
679b5db5a2 | ||
|
|
64feff3539 | ||
|
|
1720d616f6 | ||
|
|
155a2ea557 | ||
|
|
d5c38ed0a4 | ||
|
|
b70d50f2b3 | ||
|
|
728f699051 | ||
|
|
3bbbc759d3 | ||
|
|
2230ca1740 | ||
|
|
440fd4e02b | ||
|
|
78a924d378 | ||
|
|
b03fadc2ec | ||
|
|
4b79d3b785 | ||
|
|
a24fb5d84f | ||
|
|
137059ded6 | ||
|
|
f1ce82ac25 | ||
|
|
4aeed392d7 | ||
|
|
4356ddae8c | ||
|
|
76e7de3aed | ||
|
|
ae5e63cc64 | ||
|
|
5ef05891ce | ||
|
|
c452e23b18 | ||
|
|
69aab87d72 | ||
|
|
a60674cf1b | ||
|
|
022b9226a7 | ||
|
|
36e2404814 | ||
|
|
2eb3f6cb06 | ||
|
|
98cbdf570f | ||
|
|
d380894c35 | ||
|
|
ea0263cc73 | ||
|
|
f38a1d9f1c | ||
|
|
9390a815a8 | ||
|
|
4f76e13dbe | ||
|
|
6a4643558c | ||
|
|
a98c8db949 | ||
|
|
5ba9c9d48c | ||
|
|
e1ca71dcea | ||
|
|
266ed58908 | ||
|
|
1411ae41c3 | ||
|
|
bc8891d2f8 | ||
|
|
3b7455ac4c | ||
|
|
5a0a7c2c60 | ||
|
|
794d6fc0ca | ||
|
|
4c95df44d5 | ||
|
|
717545e14c | ||
|
|
e4d1452f5f | ||
|
|
88ace79a64 | ||
|
|
9b42326f80 | ||
|
|
44a3469b9b | ||
|
|
ef4b70f67b | ||
|
|
7a125e31ec | ||
|
|
c7bd7566c5 | ||
|
|
f4fbe62169 | ||
|
|
6e3141a4ce | ||
|
|
fc8391c5aa | ||
|
|
87499d1ead | ||
|
|
5fa8686fcf | ||
|
|
dc2db524c7 | ||
|
|
b3545b767a | ||
|
|
55f653d92e | ||
|
|
35f8e133a9 | ||
|
|
58d6487f77 | ||
|
|
6685482ea6 | ||
|
|
708158f50f | ||
|
|
0feab5aa93 | ||
|
|
b49ed913c7 | ||
|
|
419d2da363 | ||
|
|
df2844ea74 | ||
|
|
5e5f0f167f | ||
|
|
a6b05f0a3d | ||
|
|
f69aaa2cfb | ||
|
|
3866f89d3e | ||
|
|
f9ac41b865 | ||
|
|
c5b5bfe540 | ||
|
|
f3c01a5155 | ||
|
|
033b64a62a | ||
|
|
4aabfe7cf5 | ||
|
|
0218f701b2 | ||
|
|
f6d3f95768 | ||
|
|
cb1cd3555b | ||
|
|
ced72f86a4 | ||
|
|
54d5666b92 | ||
|
|
4edc6dbeae | ||
|
|
e203276678 | ||
|
|
8eb2cf144e | ||
|
|
2f7d208eb5 | ||
|
|
70fb5af19f | ||
|
|
fc7a94fa66 | ||
|
|
0077714cb0 | ||
|
|
723c31f6c5 | ||
|
|
1024483e58 | ||
|
|
cbcef2c880 | ||
|
|
0711c8855e | ||
|
|
72cbc1a9e7 | ||
|
|
a9841755a7 | ||
|
|
03e6c33f82 | ||
|
|
3c5aa86ee2 | ||
|
|
06a89b21da | ||
|
|
8c891f0e87 | ||
|
|
49dd5f2ef7 | ||
|
|
83d01e7a0d | ||
|
|
f8e97c9c5c | ||
|
|
b78ade2cf2 | ||
|
|
1b59719891 | ||
|
|
540a2c6712 | ||
|
|
481c4e1271 | ||
|
|
fe0d2a967f | ||
|
|
e77a6f4d7a | ||
|
|
a023a7514e | ||
|
|
3573c0863c | ||
|
|
b444c1e6b1 | ||
|
|
5698628839 | ||
|
|
3596f73fb1 | ||
|
|
5b22490d6d | ||
|
|
39f9fc6900 | ||
|
|
f854cdd9d3 | ||
|
|
011b2167ba | ||
|
|
a5f3a189f8 | ||
|
|
3fdfb51e02 | ||
|
|
43577c7ead | ||
|
|
6661aa7686 | ||
|
|
8d54e3b766 | ||
|
|
6c446226eb | ||
|
|
90b5f88413 | ||
|
|
381a4de88a | ||
|
|
10ebd0cad6 | ||
|
|
6e7f04b492 | ||
|
|
20ac75e3d2 | ||
|
|
d6b75d76ca | ||
|
|
41d3342a42 | ||
|
|
f3cb3b9840 | ||
|
|
08f3b089f4 | ||
|
|
1d8e5b6c0f | ||
|
|
0dcded59e5 | ||
|
|
4799d3147b | ||
|
|
b60b26189f | ||
|
|
c79520c874 | ||
|
|
2cc2a43e17 | ||
|
|
47d42e6a57 | ||
|
|
573d369d4b | ||
|
|
3c151e3adb | ||
|
|
ee1e2b824f | ||
|
|
6f0cf03371 | ||
|
|
b8d228a339 | ||
|
|
c6ba2b4598 | ||
|
|
36adc17a34 | ||
|
|
3e32dabf46 | ||
|
|
74c994fbab | ||
|
|
7844522691 | ||
|
|
bfb63ca8c4 | ||
|
|
71e24483dd | ||
|
|
12f2f80958 | ||
|
|
7b5ff54f47 | ||
|
|
afc97511af | ||
|
|
ae857d3fcd | ||
|
|
0db2784d6b | ||
|
|
317c41a166 | ||
|
|
47d1caf078 | ||
|
|
292b3f418e | ||
|
|
4eb533fff8 | ||
|
|
7a10fe2b8c | ||
|
|
4214e36d22 | ||
|
|
b9ab6d3fd4 | ||
|
|
23704b00ce | ||
|
|
266894b0f8 | ||
|
|
4a9847abdd | ||
|
|
ba95ca682b | ||
|
|
5942c758f0 | ||
|
|
e97d0ea51c | ||
|
|
6019b38da5 | ||
|
|
3544ffdcc6 | ||
|
|
be7a687088 | ||
|
|
ed4613cb1b | ||
|
|
1066b217cb | ||
|
|
709c286086 | ||
|
|
e4753e6b44 | ||
|
|
6c06fea1aa | ||
|
|
6f7999acb2 | ||
|
|
6bc2f9125c | ||
|
|
16738ea7e3 | ||
|
|
6b096576ee | ||
|
|
262beef8f9 | ||
|
|
5dc5b2e366 | ||
|
|
43cc6dea92 | ||
|
|
6684640abe | ||
|
|
363fb7bc34 | ||
|
|
dde4485839 | ||
|
|
44598e304d | ||
|
|
4295a2756a | ||
|
|
0a146910d6 | ||
|
|
690ed0f7f1 | ||
|
|
2f0d98ae51 | ||
|
|
fb92ddc822 | ||
|
|
15b0569b56 | ||
|
|
140533b790 | ||
|
|
532f274bd6 | ||
|
|
3200fd054e | ||
|
|
8468cc863e | ||
|
|
71911687bf | ||
|
|
9644297d28 | ||
|
|
faa6fdfcde | ||
|
|
aabf364cc6 | ||
|
|
4b861b2169 | ||
|
|
8d655bf419 | ||
|
|
90cb8ba9a1 | ||
|
|
f508ee7521 | ||
|
|
413caad0d8 | ||
|
|
666f601ecd | ||
|
|
5cdcbef00c | ||
|
|
c2f607ab6b | ||
|
|
2ca10bb87c | ||
|
|
6fb2a6d4c9 | ||
|
|
464589e0ca | ||
|
|
3b94dab3ce | ||
|
|
9f481aacff | ||
|
|
22f2e68db2 | ||
|
|
706f967246 | ||
|
|
1685f0e74f | ||
|
|
74162456e5 | ||
|
|
b798518aa9 | ||
|
|
d7fd1d032b | ||
|
|
a2ac49bfc2 | ||
|
|
33541a2ac0 | ||
|
|
947b5bdefb | ||
|
|
bd7d14b1ca | ||
|
|
43ed49f9d9 | ||
|
|
758b10f1bf | ||
|
|
ab1caf13fc | ||
|
|
96b81817e0 | ||
|
|
bfeceb0ed2 | ||
|
|
c322fc72d9 | ||
|
|
e7b5410c5b | ||
|
|
072693d57d | ||
|
|
a20794040a | ||
|
|
ab4a8dfbea | ||
|
|
fa0a065b95 | ||
|
|
abc8096a39 | ||
|
|
7cff07333f | ||
|
|
5796d6cb8c | ||
|
|
98367fd054 | ||
|
|
ff8df5dc36 | ||
|
|
f0c9f12897 | ||
|
|
5bcf7de440 | ||
|
|
79e96e544f | ||
|
|
871e5ada9e | ||
|
|
0401c27dbc | ||
|
|
57c45f22d6 | ||
|
|
29f1883edd | ||
|
|
5d903b5487 | ||
|
|
1b9683d699 | ||
|
|
65280cf4e1 | ||
|
|
703983a5f9 | ||
|
|
766a2123c5 | ||
|
|
1308f0f15f | ||
|
|
6c634b99d0 | ||
|
|
9856335840 | ||
|
|
e85b405396 | ||
|
|
e2e965bc7f | ||
|
|
7811fdd17a | ||
|
|
0dca1237b9 | ||
|
|
f3d73f6d44 | ||
|
|
187927403a | ||
|
|
0157b47424 | ||
|
|
156905afc7 | ||
|
|
a4878f6430 | ||
|
|
4489df6f39 | ||
|
|
06c075466b | ||
|
|
62be3e7c13 | ||
|
|
bb84960442 | ||
|
|
52199361d5 | ||
|
|
f031845300 | ||
|
|
6f73bb6eca | ||
|
|
fe398bcc49 | ||
|
|
6781c29082 | ||
|
|
eb146491f2 | ||
|
|
ae325ec1ca | ||
|
|
fd6f0574f5 | ||
|
|
b819a90c80 | ||
|
|
a6848f6abd | ||
|
|
abe65975c9 | ||
|
|
5cedd57aa2 | ||
|
|
80a7b9d16d | ||
|
|
9f7b2542ec | ||
|
|
4a4c9f26a2 | ||
|
|
c957c0f757 | ||
|
|
3ff0aa4b4b | ||
|
|
063c9adba6 | ||
|
|
5c3ce146fa | ||
|
|
481bb6e8b8 | ||
|
|
61e6316736 | ||
|
|
f9d1494657 | ||
|
|
0021b4d784 | ||
|
|
a5d5800871 | ||
|
|
16dc90bbd1 | ||
|
|
fff61379fe | ||
|
|
08a415032c | ||
|
|
3783ffdd4c | ||
|
|
a8e4359d95 | ||
|
|
d9e94a4067 | ||
|
|
ae19eaa76a | ||
|
|
fff9954da2 | ||
|
|
a476c68f7e | ||
|
|
fc15aa6f1c | ||
|
|
220edd139a | ||
|
|
4192fd573d | ||
|
|
ca13d80205 | ||
|
|
59121bd932 | ||
|
|
aef935a817 | ||
|
|
f300518d61 | ||
|
|
18b608a1d8 | ||
|
|
738d62c9cf | ||
|
|
38e694cd36 | ||
|
|
1281330c52 | ||
|
|
7b7cca7db7 | ||
|
|
3134e8c1cf | ||
|
|
d00024b64a | ||
|
|
4360cd0397 | ||
|
|
a688b6c60e | ||
|
|
522e73b48e | ||
|
|
ba7e6fcf23 | ||
|
|
eefccafa5b | ||
|
|
05bd6d52f1 | ||
|
|
d60daef171 | ||
|
|
d50530f58c | ||
|
|
6957bd71ca | ||
|
|
ef8b50c19e | ||
|
|
1585065fff | ||
|
|
99c68ddbcd | ||
|
|
b08e859426 | ||
|
|
89fd3e4f55 | ||
|
|
a2492b0135 | ||
|
|
eb8ca5a7ca | ||
|
|
80133240ca | ||
|
|
7d7d112f40 | ||
|
|
add2d19614 | ||
|
|
adfe20e88a | ||
|
|
8d84ce8f06 | ||
|
|
09ea7b9eb5 | ||
|
|
d3b83f5a41 | ||
|
|
77eba9a558 | ||
|
|
43e73e06fe | ||
|
|
840d8b2e49 | ||
|
|
df751c7f38 | ||
|
|
cd07c743b6 | ||
|
|
46e6c34e51 | ||
|
|
42f7905b3b |
6
.github/CODEOWNERS
vendored
@@ -5,6 +5,6 @@
|
||||
/frontend/ @YounixM
|
||||
/frontend/src/container/MetricsApplication @srikanthccv
|
||||
/frontend/src/container/NewWidget/RightContainer/types.ts @srikanthccv
|
||||
/deploy/ @prashant-shahi
|
||||
/sample-apps/ @prashant-shahi
|
||||
.github @prashant-shahi
|
||||
/deploy/ @SigNoz/devops
|
||||
/sample-apps/ @SigNoz/devops
|
||||
.github @SigNoz/devops
|
||||
|
||||
49
.github/ISSUE_TEMPLATE/request_dashboard.md
vendored
Normal file
@@ -0,0 +1,49 @@
|
||||
---
|
||||
name: Request Dashboard
|
||||
about: Request a new dashboard for the SigNoz Dashboards repository
|
||||
title: '[Dashboard Request] '
|
||||
labels: 'dashboard-template'
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
<!-- Use this template to request a new dashboard for the SigNoz Dashboards repository. Providing detailed information will help us understand your needs better and speed up the dashboard creation process. -->
|
||||
|
||||
## Dashboard Name
|
||||
|
||||
<!-- Provide the name for the requested dashboard. Be specific (e.g., "MySQL Monitoring Dashboard"). -->
|
||||
|
||||
## Expected Dashboard Sections and Panels
|
||||
|
||||
(Can be tweaked (add or remove panels/sections) according to available metrics)
|
||||
|
||||
### Section Name
|
||||
|
||||
<!-- Brief description of what this section should display (e.g., "Resource usage metrics for MySQL database"). -->
|
||||
|
||||
### Panel Name
|
||||
|
||||
<!-- Description of the panel (e.g., "Displays current CPU usage, memory usage, etc."). -->
|
||||
|
||||
<!-- - **Example:**
|
||||
- **Section**: Resource Metrics
|
||||
- **Panel**: CPU Usage - Displays the current CPU usage across all database instances.
|
||||
- **Panel**: Memory Usage - Displays the total memory used by the MySQL process. -->
|
||||
|
||||
<!-- Repeat this format for any additional sections or panels. -->
|
||||
|
||||
## Expected Dashboard Variables
|
||||
|
||||
<!-- List any dashboard variables that should be included in the dashboard. Examples could be `deployment.environment`, `hostname`, `region`, etc. -->
|
||||
|
||||
## Additional Comments or Requirements
|
||||
|
||||
<!-- Include any other details, special requirements, or specific visualizations you'd like to request for this dashboard. -->
|
||||
|
||||
## References or Screenshots
|
||||
|
||||
<!-- Add any references or screenshots of requested dashboard if available. -->
|
||||
|
||||
## 📋 Notes
|
||||
|
||||
Please review the [CONTRIBUTING.md](https://github.com/SigNoz/dashboards/blob/main/CONTRIBUTING.md) for guidelines on dashboard structure, naming conventions, and how to submit a pull request.
|
||||
8
.github/workflows/build.yaml
vendored
@@ -8,6 +8,13 @@ on:
|
||||
- release/v*
|
||||
|
||||
jobs:
|
||||
check-no-ee-references:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Run check
|
||||
run: make check-no-ee-references
|
||||
|
||||
build-frontend:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
@@ -36,7 +43,6 @@ jobs:
|
||||
run: |
|
||||
echo 'INTERCOM_APP_ID="${{ secrets.INTERCOM_APP_ID }}"' > frontend/.env
|
||||
echo 'SEGMENT_ID="${{ secrets.SEGMENT_ID }}"' >> frontend/.env
|
||||
echo 'CLARITY_PROJECT_ID="${{ secrets.CLARITY_PROJECT_ID }}"' >> frontend/.env
|
||||
- name: Install dependencies
|
||||
run: cd frontend && yarn install
|
||||
- name: Run ESLint
|
||||
|
||||
2
.github/workflows/push.yaml
vendored
@@ -9,7 +9,6 @@ on:
|
||||
- v*
|
||||
|
||||
jobs:
|
||||
|
||||
image-build-and-push-query-service:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
@@ -151,7 +150,6 @@ jobs:
|
||||
run: |
|
||||
echo 'INTERCOM_APP_ID="${{ secrets.INTERCOM_APP_ID }}"' > frontend/.env
|
||||
echo 'SEGMENT_ID="${{ secrets.SEGMENT_ID }}"' >> frontend/.env
|
||||
echo 'CLARITY_PROJECT_ID="${{ secrets.CLARITY_PROJECT_ID }}"' >> frontend/.env
|
||||
echo 'SENTRY_AUTH_TOKEN="${{ secrets.SENTRY_AUTH_TOKEN }}"' >> frontend/.env
|
||||
echo 'SENTRY_ORG="${{ secrets.SENTRY_ORG }}"' >> frontend/.env
|
||||
echo 'SENTRY_PROJECT_ID="${{ secrets.SENTRY_PROJECT_ID }}"' >> frontend/.env
|
||||
|
||||
4
.github/workflows/staging-deployment.yaml
vendored
@@ -30,6 +30,8 @@ jobs:
|
||||
GCP_PROJECT: ${{ secrets.GCP_PROJECT }}
|
||||
GCP_ZONE: ${{ secrets.GCP_ZONE }}
|
||||
GCP_INSTANCE: ${{ secrets.GCP_INSTANCE }}
|
||||
CLOUDSDK_CORE_DISABLE_PROMPTS: 1
|
||||
KAFKA_SPAN_EVAL: true
|
||||
run: |
|
||||
read -r -d '' COMMAND <<EOF || true
|
||||
echo "GITHUB_BRANCH: ${GITHUB_BRANCH}"
|
||||
@@ -51,4 +53,4 @@ jobs:
|
||||
make build-frontend-amd64
|
||||
make run-testing
|
||||
EOF
|
||||
gcloud compute ssh ${GCP_INSTANCE} --zone ${GCP_ZONE} --ssh-key-expire-after=15m --tunnel-through-iap --project ${GCP_PROJECT} --command "${COMMAND}"
|
||||
gcloud beta compute ssh ${GCP_INSTANCE} --zone ${GCP_ZONE} --ssh-key-expire-after=15m --tunnel-through-iap --project ${GCP_PROJECT} --command "${COMMAND}"
|
||||
|
||||
3
.github/workflows/testing-deployment.yaml
vendored
@@ -30,6 +30,7 @@ jobs:
|
||||
GCP_PROJECT: ${{ secrets.GCP_PROJECT }}
|
||||
GCP_ZONE: ${{ secrets.GCP_ZONE }}
|
||||
GCP_INSTANCE: ${{ secrets.GCP_INSTANCE }}
|
||||
CLOUDSDK_CORE_DISABLE_PROMPTS: 1
|
||||
run: |
|
||||
read -r -d '' COMMAND <<EOF || true
|
||||
echo "GITHUB_BRANCH: ${GITHUB_BRANCH}"
|
||||
@@ -52,4 +53,4 @@ jobs:
|
||||
make build-frontend-amd64
|
||||
make run-testing
|
||||
EOF
|
||||
gcloud compute ssh ${GCP_INSTANCE} --zone ${GCP_ZONE} --ssh-key-expire-after=15m --tunnel-through-iap --project ${GCP_PROJECT} --command "${COMMAND}"
|
||||
gcloud beta compute ssh ${GCP_INSTANCE} --zone ${GCP_ZONE} --ssh-key-expire-after=15m --tunnel-through-iap --project ${GCP_PROJECT} --command "${COMMAND}"
|
||||
|
||||
3
.gitignore
vendored
@@ -67,3 +67,6 @@ e2e/.auth
|
||||
# go
|
||||
vendor/
|
||||
**/main/**
|
||||
|
||||
# git-town
|
||||
.git-branches.toml
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
# It Comments out the Line Query-Service & Frontend Section of deploy/docker/clickhouse-setup/docker-compose.yaml
|
||||
# Update the Line Numbers when deploy/docker/clickhouse-setup/docker-compose.yaml chnages.
|
||||
# Docs Ref.: https://github.com/SigNoz/signoz/blob/main/CONTRIBUTING.md#contribute-to-frontend-with-docker-installation-of-signoz
|
||||
|
||||
sed -i 38,62's/.*/# &/' .././deploy/docker/clickhouse-setup/docker-compose.yaml
|
||||
@@ -30,6 +30,7 @@ Also, have a look at these [good first issues label](https://github.com/SigNoz/s
|
||||
- [To run ClickHouse setup](#41-to-run-clickhouse-setup-recommended-for-local-development)
|
||||
- [Contribute to SigNoz Helm Chart](#5-contribute-to-signoz-helm-chart-)
|
||||
- [To run helm chart for local development](#51-to-run-helm-chart-for-local-development)
|
||||
- [Contribute to Dashboards](#6-contribute-to-dashboards-)
|
||||
- [Other Ways to Contribute](#other-ways-to-contribute)
|
||||
|
||||
# 1. General Instructions 📝
|
||||
@@ -37,7 +38,7 @@ Also, have a look at these [good first issues label](https://github.com/SigNoz/s
|
||||
## 1.1 For Creating Issue(s)
|
||||
Before making any significant changes and before filing a new issue, please check [existing open](https://github.com/SigNoz/signoz/issues?q=is%3Aopen+is%3Aissue), or [recently closed](https://github.com/SigNoz/signoz/issues?q=is%3Aissue+is%3Aclosed) issues to make sure somebody else hasn't already reported the issue. Please try to include as much information as you can.
|
||||
|
||||
**Issue Types** - [Bug Report](https://github.com/SigNoz/signoz/issues/new?assignees=&labels=&template=bug_report.md&title=) | [Feature Request](https://github.com/SigNoz/signoz/issues/new?assignees=&labels=&template=feature_request.md&title=) | [Performance Issue Report](https://github.com/SigNoz/signoz/issues/new?assignees=&labels=&template=performance-issue-report.md&title=) | [Report a Security Vulnerability](https://github.com/SigNoz/signoz/security/policy)
|
||||
**Issue Types** - [Bug Report](https://github.com/SigNoz/signoz/issues/new?assignees=&labels=&template=bug_report.md&title=) | [Feature Request](https://github.com/SigNoz/signoz/issues/new?assignees=&labels=&template=feature_request.md&title=) | [Performance Issue Report](https://github.com/SigNoz/signoz/issues/new?assignees=&labels=&template=performance-issue-report.md&title=) | [Request Dashboard](https://github.com/SigNoz/signoz/issues/new?assignees=&labels=dashboard-template&projects=&template=request_dashboard.md&title=%5BDashboard+Request%5D+) | [Report a Security Vulnerability](https://github.com/SigNoz/signoz/security/policy)
|
||||
|
||||
#### Details like these are incredibly useful:
|
||||
|
||||
@@ -56,7 +57,7 @@ Before making any significant changes and before filing a new issue, please chec
|
||||
Discussing your proposed changes ahead of time will make the contribution
|
||||
process smooth for everyone 🙌.
|
||||
|
||||
**[`^top^`](#)**
|
||||
**[`^top^`](#contributing-guidelines)**
|
||||
|
||||
<hr>
|
||||
|
||||
@@ -97,13 +98,14 @@ GitHub provides additional document on [forking a repository](https://help.githu
|
||||
stability and quality of the component.
|
||||
|
||||
|
||||
You can always reach out to `ankit@signoz.io` to understand more about the repo and product. We are very responsive over email and [SLACK](https://signoz.io/slack).
|
||||
You can always reach out to `ankit@signoz.io` to understand more about the repo and product. We are very responsive over email and [slack community](https://signoz.io/slack).
|
||||
|
||||
### Pointers:
|
||||
- If you find any **bugs** → please create an [**issue.**](https://github.com/SigNoz/signoz/issues/new?assignees=&labels=&template=bug_report.md&title=)
|
||||
- If you find anything **missing** in documentation → you can create an issue with the label **`documentation`**.
|
||||
- If you want to build any **new feature** → please create an [issue with the label **`enhancement`**.](https://github.com/SigNoz/signoz/issues/new?assignees=&labels=&template=feature_request.md&title=)
|
||||
- If you want to **discuss** something about the product, start a new [**discussion**.](https://github.com/SigNoz/signoz/discussions)
|
||||
- If you want to request a new **dashboard template** → please create an issue [here](https://github.com/SigNoz/signoz/issues/new?assignees=&labels=dashboard-template&projects=&template=request_dashboard.md&title=%5BDashboard+Request%5D+).
|
||||
|
||||
<hr>
|
||||
|
||||
@@ -117,7 +119,7 @@ e.g. If you are submitting a fix for an issue in frontend, the PR name should be
|
||||
|
||||
- Feel free to ping us on [`#contributing`](https://signoz-community.slack.com/archives/C01LWQ8KS7M) or [`#contributing-frontend`](https://signoz-community.slack.com/archives/C027134DM8B) on our slack community if you need any help on this :)
|
||||
|
||||
**[`^top^`](#)**
|
||||
**[`^top^`](#contributing-guidelines)**
|
||||
|
||||
<hr>
|
||||
|
||||
@@ -127,14 +129,13 @@ e.g. If you are submitting a fix for an issue in frontend, the PR name should be
|
||||
|
||||
- [**Frontend**](#3-develop-frontend-) (Written in Typescript, React)
|
||||
- [**Backend**](#4-contribute-to-backend-query-service-) (Query Service, written in Go)
|
||||
- [**Dashboard Templates**](#6-contribute-to-dashboards-) (JSON dashboard templates built with SigNoz)
|
||||
|
||||
Depending upon your area of expertise & interest, you can choose one or more to contribute. Below are detailed instructions to contribute in each area.
|
||||
|
||||
**Please note:** If you want to work on an issue, please ask the maintainers to assign the issue to you before starting work on it. This would help us understand who is working on an issue and prevent duplicate work. 🙏🏻
|
||||
**Please note:** If you want to work on an issue, please add a brief description of your solution on the issue before starting work on it.
|
||||
|
||||
⚠️ If you just raise a PR, without the corresponding issue being assigned to you - it may not be accepted.
|
||||
|
||||
**[`^top^`](#)**
|
||||
**[`^top^`](#contributing-guidelines)**
|
||||
|
||||
<hr>
|
||||
|
||||
@@ -188,7 +189,7 @@ Also, have a look at [Frontend README.md](https://github.com/SigNoz/signoz/blob/
|
||||
### Important Notes:
|
||||
The Maintainers / Contributors who will change Line Numbers of `Frontend` & `Query-Section`, please update line numbers in [`/.scripts/commentLinesForSetup.sh`](https://github.com/SigNoz/signoz/blob/develop/.scripts/commentLinesForSetup.sh)
|
||||
|
||||
**[`^top^`](#)**
|
||||
**[`^top^`](#contributing-guidelines)**
|
||||
|
||||
## 3.2 Contribute to Frontend without installing SigNoz backend
|
||||
|
||||
@@ -209,7 +210,7 @@ Please ping us in the [`#contributing`](https://signoz-community.slack.com/archi
|
||||
|
||||
**Frontend should now be accessible at** [`http://localhost:3301/services`](http://localhost:3301/services)
|
||||
|
||||
**[`^top^`](#)**
|
||||
**[`^top^`](#contributing-guidelines)**
|
||||
|
||||
<hr>
|
||||
|
||||
@@ -309,7 +310,7 @@ Click the button below. A workspace with all required environments will be creat
|
||||
|
||||
> To use it on your forked repo, edit the 'Open in Gitpod' button URL to `https://gitpod.io/#https://github.com/<your-github-username>/signoz` -->
|
||||
|
||||
**[`^top^`](#)**
|
||||
**[`^top^`](#contributing-guidelines)**
|
||||
|
||||
<hr>
|
||||
|
||||
@@ -365,10 +366,21 @@ curl -sL https://github.com/SigNoz/signoz/raw/develop/sample-apps/hotrod/hotrod-
|
||||
| HOTROD_NAMESPACE=sample-application bash
|
||||
```
|
||||
|
||||
**[`^top^`](#)**
|
||||
**[`^top^`](#contributing-guidelines)**
|
||||
|
||||
---
|
||||
|
||||
# 6. Contribute to Dashboards 📈
|
||||
|
||||
**Need to Update: [https://github.com/SigNoz/dashboards](https://github.com/SigNoz/dashboards)**
|
||||
|
||||
To contribute a new dashboard template for any service, follow the contribution guidelines in the [Dashboard Contributing Guide](https://github.com/SigNoz/dashboards/blob/main/CONTRIBUTING.md). In brief:
|
||||
|
||||
1. Create a dashboard JSON file.
|
||||
2. Add a README file explaining the dashboard, the metrics ingested, and the configurations needed.
|
||||
3. Include screenshots of the dashboard in the `assets/` directory.
|
||||
4. Submit a pull request for review.
|
||||
|
||||
## Other Ways to Contribute
|
||||
|
||||
There are many other ways to get involved with the community and to participate in this project:
|
||||
@@ -379,7 +391,6 @@ There are many other ways to get involved with the community and to participate
|
||||
- Help answer questions on forums such as Stack Overflow and [SigNoz Community Slack Channel](https://signoz.io/slack).
|
||||
- Tell others about the project on Twitter, your blog, etc.
|
||||
|
||||
|
||||
Again, Feel free to ping us on [`#contributing`](https://signoz-community.slack.com/archives/C01LWQ8KS7M) or [`#contributing-frontend`](https://signoz-community.slack.com/archives/C027134DM8B) on our slack community if you need any help on this :)
|
||||
|
||||
Thank You!
|
||||
|
||||
22
Makefile
@@ -79,7 +79,7 @@ build-query-service-static:
|
||||
@if [ $(DEV_BUILD) != "" ]; then \
|
||||
cd $(QUERY_SERVICE_DIRECTORY) && \
|
||||
CGO_ENABLED=1 go build -tags timetzdata -a -o ./bin/query-service-${GOOS}-${GOARCH} \
|
||||
-ldflags "-linkmode external -extldflags '-static' -s -w ${LD_FLAGS} ${DEV_LD_FLAGS}"; \
|
||||
-ldflags "-linkmode external -extldflags '-static' -s -w ${LD_FLAGS} ${DEV_LD_FLAGS}"; \
|
||||
else \
|
||||
cd $(QUERY_SERVICE_DIRECTORY) && \
|
||||
CGO_ENABLED=1 go build -tags timetzdata -a -o ./bin/query-service-${GOOS}-${GOARCH} \
|
||||
@@ -178,14 +178,14 @@ clear-swarm-ch:
|
||||
@docker run --rm -v "$(PWD)/$(SWARM_DIRECTORY)/data:/pwd" busybox \
|
||||
sh -c "cd /pwd && rm -rf clickhouse*/* zookeeper-*/*"
|
||||
|
||||
check-no-ee-references:
|
||||
@echo "Checking for 'ee' package references in 'pkg' directory..."
|
||||
@if grep -R --include="*.go" '.*/ee/.*' pkg/; then \
|
||||
echo "Error: Found references to 'ee' packages in 'pkg' directory"; \
|
||||
exit 1; \
|
||||
else \
|
||||
echo "No references to 'ee' packages found in 'pkg' directory"; \
|
||||
fi
|
||||
|
||||
test:
|
||||
go test ./pkg/query-service/app/metrics/...
|
||||
go test ./pkg/query-service/cache/...
|
||||
go test ./pkg/query-service/app/...
|
||||
go test ./pkg/query-service/app/querier/...
|
||||
go test ./pkg/query-service/converter/...
|
||||
go test ./pkg/query-service/formatter/...
|
||||
go test ./pkg/query-service/tests/integration/...
|
||||
go test ./pkg/query-service/rules/...
|
||||
go test ./pkg/query-service/collectorsimulator/...
|
||||
go test ./pkg/query-service/postprocess/...
|
||||
go test ./pkg/query-service/...
|
||||
|
||||
200
README.md
@@ -1,8 +1,11 @@
|
||||
<p align="center">
|
||||
<img src="https://res.cloudinary.com/dcv3epinx/image/upload/v1618904450/signoz-images/LogoGithub_sigfbu.svg" alt="SigNoz-logo" width="240" />
|
||||
<h1 align="center" style="border-bottom: none">
|
||||
<a href="https://signoz.io" target="_blank">
|
||||
<img alt="SigNoz" src="https://github.com/user-attachments/assets/ef9a33f7-12d7-4c94-8908-0a02b22f0c18" width="100" height="100">
|
||||
</a>
|
||||
<br>SigNoz
|
||||
</h1>
|
||||
|
||||
<p align="center">Monitor your applications and troubleshoot problems in your deployed applications, an open-source alternative to DataDog, New Relic, etc.</p>
|
||||
</p>
|
||||
<p align="center">All your logs, metrics, and traces in one place. Monitor your application, spot issues before they occur and troubleshoot downtime quickly with rich context. SigNoz is a cost-effective open-source alternative to Datadog and New Relic. Visit <a href="https://signoz.io" target="_blank">signoz.io</a> for the full documentation, tutorials, and guide.</p>
|
||||
|
||||
<p align="center">
|
||||
<img alt="Downloads" src="https://img.shields.io/docker/pulls/signoz/query-service?label=Docker Downloads"> </a>
|
||||
@@ -21,55 +24,115 @@
|
||||
<a href="https://twitter.com/SigNozHq"><b>Twitter</b></a>
|
||||
</h3>
|
||||
|
||||
##
|
||||
|
||||
SigNoz helps developers monitor applications and troubleshoot problems in their deployed applications. With SigNoz, you can:
|
||||
|
||||
👉 Visualise Metrics, Traces and Logs in a single pane of glass
|
||||
|
||||
👉 You can see metrics like p99 latency, error rates for your services, external API calls and individual end points.
|
||||
|
||||
👉 You can find the root cause of the problem by going to the exact traces which are causing the problem and see detailed flamegraphs of individual request traces.
|
||||
|
||||
👉 Run aggregates on trace data to get business relevant metrics
|
||||
|
||||
👉 Filter and query logs, build dashboards and alerts based on attributes in logs
|
||||
|
||||
👉 Record exceptions automatically in Python, Java, Ruby, and Javascript
|
||||
|
||||
👉 Easy to set alerts with DIY query builder
|
||||
## Features
|
||||
|
||||
|
||||
### Application Metrics
|
||||
### Application Performance Monitoring
|
||||
|
||||

|
||||
Use SigNoz APM to monitor your applications and services. It comes with out-of-box charts for key application metrics like p99 latency, error rate, Apdex and operations per second. You can also monitor the database and external calls made from your application. Read [more](https://signoz.io/application-performance-monitoring/).
|
||||
|
||||
You can [instrument](https://signoz.io/docs/instrumentation/) your application with OpenTelemetry to get started.
|
||||
|
||||
### Distributed Tracing
|
||||
<img width="2068" alt="distributed_tracing_2 2" src="https://user-images.githubusercontent.com/83692067/226536447-bae58321-6a22-4ed3-af80-e3e964cb3489.png">
|
||||

|
||||
|
||||
<img width="2068" alt="distributed_tracing_1" src="https://user-images.githubusercontent.com/83692067/226536462-939745b6-4f9d-45a6-8016-814837e7f7b4.png">
|
||||
|
||||
### Logs Management
|
||||
|
||||
<img width="2068" alt="logs_management" src="https://user-images.githubusercontent.com/83692067/226536482-b8a5c4af-b69c-43d5-969c-338bd5eaf1a5.png">
|
||||
SigNoz can be used as a centralized log management solution. We use ClickHouse (used by likes of Uber & Cloudflare) as a datastore, ⎯ an extremely fast and highly optimized storage for logs data. Instantly search through all your logs using quick filters and a powerful query builder.
|
||||
|
||||
### Infrastructure Monitoring
|
||||
You can also create charts on your logs and monitor them with customized dashboards. Read [more](https://signoz.io/log-management/).
|
||||
|
||||
<img width="2068" alt="infrastructure_monitoring" src="https://user-images.githubusercontent.com/83692067/226536496-f38c4dbf-e03c-4158-8be0-32d4a61158c7.png">
|
||||

|
||||
|
||||
### Exceptions Monitoring
|
||||
|
||||

|
||||
### Distributed Tracing
|
||||
|
||||
Distributed Tracing is essential to troubleshoot issues in microservices applications. Powered by OpenTelemetry, distributed tracing in SigNoz can help you track user requests across services to help you identify performance bottlenecks.
|
||||
|
||||
See user requests in a detailed breakdown with the help of Flamegraphs and Gantt Charts. Click on any span to see the entire trace represented beautifully, which will help you make sense of where issues actually occurred in the flow of requests.
|
||||
|
||||
Read [more](https://signoz.io/distributed-tracing/).
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
### Metrics and Dashboards
|
||||
|
||||
Ingest metrics from your infrastructure or applications and create customized dashboards to monitor them. Create visualization that suits your needs with a variety of panel types like pie chart, time-series, bar chart, etc.
|
||||
|
||||
Create queries on your metrics data quickly with an easy-to-use metrics query builder. Add multiple queries and combine those queries with formulae to create really complex queries quickly.
|
||||
|
||||
Read [more](https://signoz.io/metrics-and-dashboards/).
|
||||
|
||||

|
||||
|
||||
### Alerts
|
||||
|
||||
<img width="2068" alt="alerts_management" src="https://user-images.githubusercontent.com/83692067/226536548-2c81e2e8-c12d-47e8-bad7-c6be79055def.png">
|
||||
Use alerts in SigNoz to get notified when anything unusual happens in your application. You can set alerts on any type of telemetry signal (logs, metrics, traces), create thresholds and set up a notification channel to get notified. Advanced features like alert history and anomaly detection can help you create smarter alerts.
|
||||
|
||||
Alerts in SigNoz help you identify issues proactively so that you can address them before they reach your customers.
|
||||
|
||||
Read [more](https://signoz.io/alerts-management/).
|
||||
|
||||

|
||||
|
||||
### Exceptions Monitoring
|
||||
|
||||
Monitor exceptions automatically in Python, Java, Ruby, and Javascript. For other languages, just drop in a few lines of code and start monitoring exceptions.
|
||||
|
||||
See the detailed stack trace for all exceptions caught in your application. You can also log in custom attributes to add more context to your exceptions. For example, you can add attributes to identify users for which exceptions occurred.
|
||||
|
||||
Read [more](https://signoz.io/exceptions-monitoring/).
|
||||
|
||||
|
||||

|
||||
|
||||
|
||||
<br /><br />
|
||||
|
||||
## Why SigNoz?
|
||||
|
||||
SigNoz is a single tool for all your monitoring and observability needs. Here are a few reasons why you should choose SigNoz:
|
||||
|
||||
- Single tool for observability(logs, metrics, and traces)
|
||||
|
||||
- Built on top of [OpenTelemetry](https://opentelemetry.io/), the open-source standard which frees you from any type of vendor lock-in
|
||||
|
||||
- Correlated logs, metrics and traces for much richer context while debugging
|
||||
|
||||
- Uses ClickHouse (used by likes of Uber & Cloudflare) as datastore - an extremely fast and highly optimized storage for observability data
|
||||
|
||||
- DIY Query builder, PromQL, and ClickHouse queries to fulfill all your use-cases around querying observability data
|
||||
|
||||
- Open-Source - you can use open-source, our [cloud service](https://signoz.io/teams/) or a mix of both based on your use case
|
||||
|
||||
|
||||
## Getting Started
|
||||
|
||||
### Create a SigNoz Cloud Account
|
||||
|
||||
SigNoz cloud is the easiest way to get started with SigNoz. Our cloud service is for those users who want to spend more time in getting insights for their application performance without worrying about maintenance.
|
||||
|
||||
[Get started for free](https://signoz.io/teams/)
|
||||
|
||||
### Deploy using Docker(self-hosted)
|
||||
|
||||
Please follow the steps listed [here](https://signoz.io/docs/install/docker/) to install using docker
|
||||
|
||||
The [troubleshooting instructions](https://signoz.io/docs/install/troubleshooting/) may be helpful if you face any issues.
|
||||
|
||||
<p>  </p>
|
||||
|
||||
|
||||
### Deploy in Kubernetes using Helm(self-hosted)
|
||||
|
||||
Please follow the steps listed [here](https://signoz.io/docs/deployment/helm_chart) to install using helm charts
|
||||
|
||||
<br /><br />
|
||||
|
||||
We also offer managed services in your infra. Check our [pricing plans](https://signoz.io/pricing/) for all details.
|
||||
|
||||
|
||||
## Join our Slack community
|
||||
|
||||
@@ -78,64 +141,22 @@ Come say Hi to us on [Slack](https://signoz.io/slack) 👋
|
||||
<br /><br />
|
||||
|
||||
|
||||
## Features:
|
||||
|
||||
- Unified UI for metrics, traces and logs. No need to switch from Prometheus to Jaeger to debug issues, or use a logs tool like Elastic separate from your metrics and traces stack.
|
||||
- Application overview metrics like RPS, 50th/90th/99th Percentile latencies, and Error Rate
|
||||
- Slowest endpoints in your application
|
||||
- See exact request trace to figure out issues in downstream services, slow DB queries, call to 3rd party services like payment gateways, etc
|
||||
- Filter traces by service name, operation, latency, error, tags/annotations.
|
||||
- Run aggregates on trace data (events/spans) to get business relevant metrics. e.g. You can get error rate and 99th percentile latency of `customer_type: gold` or `deployment_version: v2` or `external_call: paypal`
|
||||
- Native support for OpenTelemetry Logs, advanced log query builder, and automatic log collection from k8s cluster
|
||||
- Lightning quick log analytics ([Logs Perf. Benchmark](https://signoz.io/blog/logs-performance-benchmark/))
|
||||
- End-to-End visibility into infrastructure performance, ingest metrics from all kinds of host environments
|
||||
- Easy to set alerts with DIY query builder
|
||||
|
||||
<br /><br />
|
||||
|
||||
|
||||
## Why SigNoz?
|
||||
|
||||
Being developers, we found it annoying to rely on closed source SaaS vendors for every small feature we wanted. Closed source vendors often surprise you with huge month end bills without any transparency.
|
||||
|
||||
We wanted to make a self-hosted & open source version of tools like DataDog, NewRelic for companies that have privacy and security concerns about having customer data going to third party services.
|
||||
|
||||
Being open source also gives you complete control of your configuration, sampling, uptimes. You can also build modules over SigNoz to extend business specific capabilities
|
||||
|
||||
### Languages supported:
|
||||
|
||||
We support [OpenTelemetry](https://opentelemetry.io) as the library which you can use to instrument your applications. So any framework and language supported by OpenTelemetry is also supported by SigNoz. Some of the main supported languages are:
|
||||
SigNoz supports all major programming languages for monitoring. Any framework and language supported by OpenTelemetry is supported by SigNoz. Find instructions for instrumenting different languages below:
|
||||
|
||||
- Java
|
||||
- Python
|
||||
- Node.js
|
||||
- Go
|
||||
- PHP
|
||||
- .NET
|
||||
- Ruby
|
||||
- Elixir
|
||||
- Rust
|
||||
- [Java](https://signoz.io/docs/instrumentation/java/)
|
||||
- [Python](https://signoz.io/docs/instrumentation/python/)
|
||||
- [Node.js or Javascript](https://signoz.io/docs/instrumentation/javascript/)
|
||||
- [Go](https://signoz.io/docs/instrumentation/golang/)
|
||||
- [PHP](https://signoz.io/docs/instrumentation/php/)
|
||||
- [.NET](https://signoz.io/docs/instrumentation/dotnet/)
|
||||
- [Ruby](https://signoz.io/docs/instrumentation/ruby-on-rails/)
|
||||
- [Elixir](https://signoz.io/docs/instrumentation/elixir/)
|
||||
- [Rust](https://signoz.io/docs/instrumentation/rust/)
|
||||
- [Swift](https://signoz.io/docs/instrumentation/swift/)
|
||||
|
||||
|
||||
You can find the complete list of languages here - https://opentelemetry.io/docs/
|
||||
|
||||
<br /><br />
|
||||
|
||||
|
||||
## Getting Started
|
||||
|
||||
### Deploy using Docker
|
||||
|
||||
Please follow the steps listed [here](https://signoz.io/docs/install/docker/) to install using docker
|
||||
|
||||
The [troubleshooting instructions](https://signoz.io/docs/install/troubleshooting/) may be helpful if you face any issues.
|
||||
|
||||
<p>  </p>
|
||||
|
||||
|
||||
### Deploy in Kubernetes using Helm
|
||||
|
||||
Please follow the steps listed [here](https://signoz.io/docs/deployment/helm_chart) to install using helm charts
|
||||
You can find our entire documentation [here](https://signoz.io/docs/introduction/).
|
||||
|
||||
<br /><br />
|
||||
|
||||
@@ -144,9 +165,11 @@ Please follow the steps listed [here](https://signoz.io/docs/deployment/helm_cha
|
||||
|
||||
### SigNoz vs Prometheus
|
||||
|
||||
Prometheus is good if you want to do just metrics. But if you want to have a seamless experience between metrics and traces, then current experience of stitching together Prometheus & Jaeger is not great.
|
||||
Prometheus is good if you want to do just metrics. But if you want to have a seamless experience between metrics, logs and traces, then current experience of stitching together Prometheus & other tools is not great.
|
||||
|
||||
Our goal is to provide an integrated UI between metrics & traces - similar to what SaaS vendors like Datadog provides - and give advanced filtering and aggregation over traces, something which Jaeger currently lack.
|
||||
SigNoz is a one-stop solution for metrics and other telemetry signals. And because you will use the same standard(OpenTelemetry) to collect all telemetry signals, you can also correlate these signals to troubleshoot quickly.
|
||||
|
||||
For example, if you see that there are issues with infrastructure metrics of your k8s cluster at a timestamp, you can jump to other signals like logs and traces to understand the issue quickly.
|
||||
|
||||
<p>  </p>
|
||||
|
||||
@@ -158,6 +181,7 @@ Moreover, SigNoz has few more advanced features wrt Jaeger:
|
||||
|
||||
- Jaegar UI doesn’t show any metrics on traces or on filtered traces
|
||||
- Jaeger can’t get aggregates on filtered traces. For example, p99 latency of requests which have tag - customer_type='premium'. This can be done easily on SigNoz
|
||||
- You can also go from traces to logs easily in SigNoz
|
||||
|
||||
<p>  </p>
|
||||
|
||||
|
||||
@@ -23,6 +23,9 @@
|
||||
[1]: https://github.com/pocoproject/poco/blob/poco-1.9.4-release/Foundation/include/Poco/Logger.h#L105-L114
|
||||
-->
|
||||
<level>information</level>
|
||||
<formatting>
|
||||
<type>json</type>
|
||||
</formatting>
|
||||
<log>/var/log/clickhouse-server/clickhouse-server.log</log>
|
||||
<errorlog>/var/log/clickhouse-server/clickhouse-server.err.log</errorlog>
|
||||
<!-- Rotation policy
|
||||
@@ -649,12 +652,12 @@
|
||||
|
||||
See https://clickhouse.com/docs/en/engines/table-engines/mergetree-family/replication/#creating-replicated-tables
|
||||
-->
|
||||
<!--
|
||||
|
||||
<macros>
|
||||
<shard>01</shard>
|
||||
<replica>example01-01-1</replica>
|
||||
</macros>
|
||||
-->
|
||||
|
||||
|
||||
|
||||
<!-- Reloading interval for embedded dictionaries, in seconds. Default: 3600. -->
|
||||
|
||||
@@ -133,7 +133,7 @@ services:
|
||||
# - ./data/clickhouse-3/:/var/lib/clickhouse/
|
||||
|
||||
alertmanager:
|
||||
image: signoz/alertmanager:0.23.5
|
||||
image: signoz/alertmanager:0.23.7
|
||||
volumes:
|
||||
- ./data/alertmanager:/data
|
||||
command:
|
||||
@@ -146,11 +146,11 @@ services:
|
||||
condition: on-failure
|
||||
|
||||
query-service:
|
||||
image: signoz/query-service:0.49.1
|
||||
image: signoz/query-service:0.56.0
|
||||
command:
|
||||
[
|
||||
"-config=/root/config/prometheus.yml",
|
||||
# "--prefer-delta=true"
|
||||
"--use-logs-new-schema=true"
|
||||
]
|
||||
# ports:
|
||||
# - "6060:6060" # pprof port
|
||||
@@ -186,7 +186,7 @@ services:
|
||||
<<: *db-depend
|
||||
|
||||
frontend:
|
||||
image: signoz/frontend:0.48.0
|
||||
image: signoz/frontend:0.56.0
|
||||
deploy:
|
||||
restart_policy:
|
||||
condition: on-failure
|
||||
@@ -199,7 +199,7 @@ services:
|
||||
- ../common/nginx-config.conf:/etc/nginx/conf.d/default.conf
|
||||
|
||||
otel-collector:
|
||||
image: signoz/signoz-otel-collector:0.102.2
|
||||
image: signoz/signoz-otel-collector:0.111.5
|
||||
command:
|
||||
[
|
||||
"--config=/etc/otel-collector-config.yaml",
|
||||
@@ -211,9 +211,9 @@ services:
|
||||
- ./otel-collector-config.yaml:/etc/otel-collector-config.yaml
|
||||
- ./otel-collector-opamp-config.yaml:/etc/manager-config.yaml
|
||||
- /var/lib/docker/containers:/var/lib/docker/containers:ro
|
||||
- /:/hostfs:ro
|
||||
environment:
|
||||
- OTEL_RESOURCE_ATTRIBUTES=host.name={{.Node.Hostname}},os.type={{.Node.Platform.OS}},dockerswarm.service.name={{.Service.Name}},dockerswarm.task.name={{.Task.Name}}
|
||||
- DOCKER_MULTI_NODE_CLUSTER=false
|
||||
- LOW_CARDINAL_EXCEPTION_GROUPING=false
|
||||
ports:
|
||||
# - "1777:1777" # pprof extension
|
||||
@@ -237,7 +237,7 @@ services:
|
||||
- query-service
|
||||
|
||||
otel-collector-migrator:
|
||||
image: signoz/signoz-schema-migrator:0.102.2
|
||||
image: signoz/signoz-schema-migrator:0.111.5
|
||||
deploy:
|
||||
restart_policy:
|
||||
condition: on-failure
|
||||
|
||||
@@ -36,6 +36,7 @@ receivers:
|
||||
# endpoint: 0.0.0.0:6832
|
||||
hostmetrics:
|
||||
collection_interval: 30s
|
||||
root_path: /hostfs
|
||||
scrapers:
|
||||
cpu: {}
|
||||
load: {}
|
||||
@@ -130,8 +131,7 @@ processors:
|
||||
exporters:
|
||||
clickhousetraces:
|
||||
datasource: tcp://clickhouse:9000/signoz_traces
|
||||
docker_multi_node_cluster: ${DOCKER_MULTI_NODE_CLUSTER}
|
||||
low_cardinal_exception_grouping: ${LOW_CARDINAL_EXCEPTION_GROUPING}
|
||||
low_cardinal_exception_grouping: ${env:LOW_CARDINAL_EXCEPTION_GROUPING}
|
||||
clickhousemetricswrite:
|
||||
endpoint: tcp://clickhouse:9000/signoz_metrics
|
||||
resource_to_telemetry_conversion:
|
||||
@@ -141,8 +141,8 @@ exporters:
|
||||
# logging: {}
|
||||
clickhouselogsexporter:
|
||||
dsn: tcp://clickhouse:9000/signoz_logs
|
||||
docker_multi_node_cluster: ${DOCKER_MULTI_NODE_CLUSTER}
|
||||
timeout: 10s
|
||||
use_new_schema: true
|
||||
extensions:
|
||||
health_check:
|
||||
endpoint: 0.0.0.0:13133
|
||||
@@ -153,6 +153,8 @@ extensions:
|
||||
|
||||
service:
|
||||
telemetry:
|
||||
logs:
|
||||
encoding: json
|
||||
metrics:
|
||||
address: 0.0.0.0:8888
|
||||
extensions: [health_check, zpages, pprof]
|
||||
|
||||
@@ -23,6 +23,9 @@
|
||||
[1]: https://github.com/pocoproject/poco/blob/poco-1.9.4-release/Foundation/include/Poco/Logger.h#L105-L114
|
||||
-->
|
||||
<level>information</level>
|
||||
<formatting>
|
||||
<type>json</type>
|
||||
</formatting>
|
||||
<log>/var/log/clickhouse-server/clickhouse-server.log</log>
|
||||
<errorlog>/var/log/clickhouse-server/clickhouse-server.err.log</errorlog>
|
||||
<!-- Rotation policy
|
||||
@@ -649,12 +652,12 @@
|
||||
|
||||
See https://clickhouse.com/docs/en/engines/table-engines/mergetree-family/replication/#creating-replicated-tables
|
||||
-->
|
||||
<!--
|
||||
|
||||
<macros>
|
||||
<shard>01</shard>
|
||||
<replica>example01-01-1</replica>
|
||||
</macros>
|
||||
-->
|
||||
|
||||
|
||||
|
||||
<!-- Reloading interval for embedded dictionaries, in seconds. Default: 3600. -->
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
version: "2.4"
|
||||
|
||||
include:
|
||||
- test-app-docker-compose.yaml
|
||||
|
||||
services:
|
||||
zookeeper-1:
|
||||
image: bitnami/zookeeper:3.7.1
|
||||
@@ -54,7 +57,7 @@ services:
|
||||
|
||||
alertmanager:
|
||||
container_name: signoz-alertmanager
|
||||
image: signoz/alertmanager:0.23.5
|
||||
image: signoz/alertmanager:0.23.7
|
||||
volumes:
|
||||
- ./data/alertmanager:/data
|
||||
depends_on:
|
||||
@@ -66,7 +69,7 @@ services:
|
||||
- --storage.path=/data
|
||||
|
||||
otel-collector-migrator:
|
||||
image: signoz/signoz-schema-migrator:${OTELCOL_TAG:-0.102.2}
|
||||
image: signoz/signoz-schema-migrator:${OTELCOL_TAG:-0.111.5}
|
||||
container_name: otel-migrator
|
||||
command:
|
||||
- "--dsn=tcp://clickhouse:9000"
|
||||
@@ -81,7 +84,7 @@ services:
|
||||
# Notes for Maintainers/Contributors who will change Line Numbers of Frontend & Query-Section. Please Update Line Numbers in `./scripts/commentLinesForSetup.sh` & `./CONTRIBUTING.md`
|
||||
otel-collector:
|
||||
container_name: signoz-otel-collector
|
||||
image: signoz/signoz-otel-collector:0.102.2
|
||||
image: signoz/signoz-otel-collector:0.111.5
|
||||
command:
|
||||
[
|
||||
"--config=/etc/otel-collector-config.yaml",
|
||||
@@ -93,6 +96,8 @@ services:
|
||||
volumes:
|
||||
- ./otel-collector-config.yaml:/etc/otel-collector-config.yaml
|
||||
- ./otel-collector-opamp-config.yaml:/etc/manager-config.yaml
|
||||
- /var/lib/docker/containers:/var/lib/docker/containers:ro
|
||||
- /:/hostfs:ro
|
||||
environment:
|
||||
- OTEL_RESOURCE_ATTRIBUTES=host.name=signoz-host,os.type=linux
|
||||
ports:
|
||||
@@ -126,29 +131,3 @@ services:
|
||||
depends_on:
|
||||
- otel-collector
|
||||
restart: on-failure
|
||||
|
||||
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: "signoz/locust:1.2.3"
|
||||
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
|
||||
|
||||
@@ -25,7 +25,7 @@ services:
|
||||
command:
|
||||
[
|
||||
"-config=/root/config/prometheus.yml",
|
||||
# "--prefer-delta=true"
|
||||
"--use-logs-new-schema=true"
|
||||
]
|
||||
ports:
|
||||
- "6060:6060"
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
version: "2.4"
|
||||
|
||||
x-clickhouse-defaults: &clickhouse-defaults
|
||||
restart: on-failure
|
||||
# addding non LTS version due to this fix https://github.com/ClickHouse/ClickHouse/commit/32caf8716352f45c1b617274c7508c86b7d1afab
|
||||
image: clickhouse/clickhouse-server:24.1.2-alpine
|
||||
tty: true
|
||||
depends_on:
|
||||
@@ -35,7 +34,7 @@ x-db-depend: &db-depend
|
||||
depends_on:
|
||||
clickhouse:
|
||||
condition: service_healthy
|
||||
otel-collector-migrator:
|
||||
otel-collector-migrator-sync:
|
||||
condition: service_completed_successfully
|
||||
# clickhouse-2:
|
||||
# condition: service_healthy
|
||||
@@ -43,9 +42,11 @@ x-db-depend: &db-depend
|
||||
# condition: service_healthy
|
||||
|
||||
services:
|
||||
|
||||
zookeeper-1:
|
||||
image: bitnami/zookeeper:3.7.1
|
||||
container_name: signoz-zookeeper-1
|
||||
hostname: zookeeper-1
|
||||
user: root
|
||||
ports:
|
||||
- "2181:2181"
|
||||
@@ -55,7 +56,6 @@ services:
|
||||
- ./data/zookeeper-1:/bitnami/zookeeper
|
||||
environment:
|
||||
- ZOO_SERVER_ID=1
|
||||
- ZOO_SERVERS=0.0.0.0:2888:3888
|
||||
# - ZOO_SERVERS=0.0.0.0:2888:3888,zookeeper-2:2888:3888,zookeeper-3:2888:3888
|
||||
- ALLOW_ANONYMOUS_LOGIN=yes
|
||||
- ZOO_AUTOPURGE_INTERVAL=1
|
||||
@@ -63,6 +63,7 @@ services:
|
||||
# zookeeper-2:
|
||||
# image: bitnami/zookeeper:3.7.0
|
||||
# container_name: signoz-zookeeper-2
|
||||
# hostname: zookeeper-2
|
||||
# user: root
|
||||
# ports:
|
||||
# - "2182:2181"
|
||||
@@ -79,6 +80,7 @@ services:
|
||||
# zookeeper-3:
|
||||
# image: bitnami/zookeeper:3.7.0
|
||||
# container_name: signoz-zookeeper-3
|
||||
# hostname: zookeeper-3
|
||||
# user: root
|
||||
# ports:
|
||||
# - "2183:2181"
|
||||
@@ -103,9 +105,11 @@ services:
|
||||
volumes:
|
||||
- ./clickhouse-config.xml:/etc/clickhouse-server/config.xml
|
||||
- ./clickhouse-users.xml:/etc/clickhouse-server/users.xml
|
||||
- ./custom-function.xml:/etc/clickhouse-server/custom-function.xml
|
||||
- ./clickhouse-cluster.xml:/etc/clickhouse-server/config.d/cluster.xml
|
||||
# - ./clickhouse-storage.xml:/etc/clickhouse-server/config.d/storage.xml
|
||||
- ./data/clickhouse/:/var/lib/clickhouse/
|
||||
- ./user_scripts:/var/lib/clickhouse/user_scripts/
|
||||
|
||||
# clickhouse-2:
|
||||
# <<: *clickhouse-defaults
|
||||
@@ -118,9 +122,12 @@ services:
|
||||
# volumes:
|
||||
# - ./clickhouse-config.xml:/etc/clickhouse-server/config.xml
|
||||
# - ./clickhouse-users.xml:/etc/clickhouse-server/users.xml
|
||||
# - ./custom-function.xml:/etc/clickhouse-server/custom-function.xml
|
||||
# - ./clickhouse-cluster.xml:/etc/clickhouse-server/config.d/cluster.xml
|
||||
# # - ./clickhouse-storage.xml:/etc/clickhouse-server/config.d/storage.xml
|
||||
# - ./data/clickhouse-2/:/var/lib/clickhouse/
|
||||
# - ./user_scripts:/var/lib/clickhouse/user_scripts/
|
||||
|
||||
|
||||
# clickhouse-3:
|
||||
# <<: *clickhouse-defaults
|
||||
@@ -133,12 +140,14 @@ services:
|
||||
# volumes:
|
||||
# - ./clickhouse-config.xml:/etc/clickhouse-server/config.xml
|
||||
# - ./clickhouse-users.xml:/etc/clickhouse-server/users.xml
|
||||
# - ./custom-function.xml:/etc/clickhouse-server/custom-function.xml
|
||||
# - ./clickhouse-cluster.xml:/etc/clickhouse-server/config.d/cluster.xml
|
||||
# # - ./clickhouse-storage.xml:/etc/clickhouse-server/config.d/storage.xml
|
||||
# - ./data/clickhouse-3/:/var/lib/clickhouse/
|
||||
# - ./user_scripts:/var/lib/clickhouse/user_scripts/
|
||||
|
||||
alertmanager:
|
||||
image: signoz/alertmanager:0.23.5
|
||||
image: signoz/alertmanager:${ALERTMANAGER_TAG:-0.23.7}
|
||||
container_name: signoz-alertmanager
|
||||
volumes:
|
||||
- ./data/alertmanager:/data
|
||||
@@ -153,12 +162,12 @@ 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:latest
|
||||
image: signoz/query-service:${DOCKER_TAG:-0.56.0}
|
||||
container_name: signoz-query-service
|
||||
command:
|
||||
[
|
||||
"-config=/root/config/prometheus.yml",
|
||||
# "--prefer-delta=true"
|
||||
"--use-logs-new-schema=true"
|
||||
]
|
||||
# ports:
|
||||
# - "6060:6060" # pprof port
|
||||
@@ -191,11 +200,25 @@ services:
|
||||
retries: 3
|
||||
<<: *db-depend
|
||||
|
||||
otel-collector-migrator:
|
||||
image: signoz/signoz-schema-migrator:${OTELCOL_TAG:-0.102.2}
|
||||
container_name: otel-migrator
|
||||
frontend:
|
||||
image: signoz/frontend:${DOCKER_TAG:-0.56.0}
|
||||
container_name: signoz-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-migrator-sync:
|
||||
image: signoz/signoz-schema-migrator:${OTELCOL_TAG:-0.111.5}
|
||||
container_name: otel-migrator-sync
|
||||
command:
|
||||
- "sync"
|
||||
- "--dsn=tcp://clickhouse:9000"
|
||||
- "--up="
|
||||
depends_on:
|
||||
clickhouse:
|
||||
condition: service_healthy
|
||||
@@ -204,8 +227,25 @@ services:
|
||||
# clickhouse-3:
|
||||
# condition: service_healthy
|
||||
|
||||
otel-collector-migrator-async:
|
||||
image: signoz/signoz-schema-migrator:${OTELCOL_TAG:-0.111.5}
|
||||
container_name: otel-migrator-async
|
||||
command:
|
||||
- "async"
|
||||
- "--dsn=tcp://clickhouse:9000"
|
||||
- "--up="
|
||||
depends_on:
|
||||
clickhouse:
|
||||
condition: service_healthy
|
||||
otel-collector-migrator-sync:
|
||||
condition: service_completed_successfully
|
||||
# clickhouse-2:
|
||||
# condition: service_healthy
|
||||
# clickhouse-3:
|
||||
# condition: service_healthy
|
||||
|
||||
otel-collector:
|
||||
image: signoz/signoz-otel-collector:0.102.2
|
||||
image: signoz/signoz-otel-collector:${OTELCOL_TAG:-0.111.5}
|
||||
container_name: signoz-otel-collector
|
||||
command:
|
||||
[
|
||||
@@ -219,9 +259,9 @@ services:
|
||||
- ./otel-collector-config.yaml:/etc/otel-collector-config.yaml
|
||||
- ./otel-collector-opamp-config.yaml:/etc/manager-config.yaml
|
||||
- /var/lib/docker/containers:/var/lib/docker/containers:ro
|
||||
- /:/hostfs:ro
|
||||
environment:
|
||||
- OTEL_RESOURCE_ATTRIBUTES=host.name=signoz-host,os.type=linux
|
||||
- DOCKER_MULTI_NODE_CLUSTER=false
|
||||
- LOW_CARDINAL_EXCEPTION_GROUPING=false
|
||||
ports:
|
||||
# - "1777:1777" # pprof extension
|
||||
@@ -239,7 +279,7 @@ services:
|
||||
depends_on:
|
||||
clickhouse:
|
||||
condition: service_healthy
|
||||
otel-collector-migrator:
|
||||
otel-collector-migrator-sync:
|
||||
condition: service_completed_successfully
|
||||
query-service:
|
||||
condition: service_healthy
|
||||
@@ -254,29 +294,3 @@ services:
|
||||
depends_on:
|
||||
- otel-collector
|
||||
restart: on-failure
|
||||
|
||||
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: "signoz/locust:1.2.3"
|
||||
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
|
||||
@@ -1,5 +1,8 @@
|
||||
version: "2.4"
|
||||
|
||||
include:
|
||||
- test-app-docker-compose.yaml
|
||||
|
||||
x-clickhouse-defaults: &clickhouse-defaults
|
||||
restart: on-failure
|
||||
# addding non LTS version due to this fix https://github.com/ClickHouse/ClickHouse/commit/32caf8716352f45c1b617274c7508c86b7d1afab
|
||||
@@ -149,7 +152,7 @@ services:
|
||||
# - ./user_scripts:/var/lib/clickhouse/user_scripts/
|
||||
|
||||
alertmanager:
|
||||
image: signoz/alertmanager:${ALERTMANAGER_TAG:-0.23.5}
|
||||
image: signoz/alertmanager:${ALERTMANAGER_TAG:-0.23.7}
|
||||
container_name: signoz-alertmanager
|
||||
volumes:
|
||||
- ./data/alertmanager:/data
|
||||
@@ -164,13 +167,13 @@ services:
|
||||
# Notes for Maintainers/Contributors who will change Line Numbers of Frontend & Query-Section. Please Update Line Numbers in `./scripts/commentLinesForSetup.sh` & `./CONTRIBUTING.md`
|
||||
|
||||
query-service:
|
||||
image: signoz/query-service:${DOCKER_TAG:-0.49.1}
|
||||
image: signoz/query-service:${DOCKER_TAG:-0.56.0}
|
||||
container_name: signoz-query-service
|
||||
command:
|
||||
[
|
||||
"-config=/root/config/prometheus.yml",
|
||||
"-gateway-url=https://api.staging.signoz.cloud"
|
||||
# "--prefer-delta=true"
|
||||
"-gateway-url=https://api.staging.signoz.cloud",
|
||||
"--use-logs-new-schema=true"
|
||||
]
|
||||
# ports:
|
||||
# - "6060:6060" # pprof port
|
||||
@@ -204,7 +207,7 @@ services:
|
||||
<<: *db-depend
|
||||
|
||||
frontend:
|
||||
image: signoz/frontend:${DOCKER_TAG:-0.49.1}
|
||||
image: signoz/frontend:${DOCKER_TAG:-0.56.0}
|
||||
container_name: signoz-frontend
|
||||
restart: on-failure
|
||||
depends_on:
|
||||
@@ -216,7 +219,7 @@ services:
|
||||
- ../common/nginx-config.conf:/etc/nginx/conf.d/default.conf
|
||||
|
||||
otel-collector-migrator:
|
||||
image: signoz/signoz-schema-migrator:${OTELCOL_TAG:-0.102.2}
|
||||
image: signoz/signoz-schema-migrator:${OTELCOL_TAG:-0.111.5}
|
||||
container_name: otel-migrator
|
||||
command:
|
||||
- "--dsn=tcp://clickhouse:9000"
|
||||
@@ -230,7 +233,7 @@ services:
|
||||
|
||||
|
||||
otel-collector:
|
||||
image: signoz/signoz-otel-collector:${OTELCOL_TAG:-0.102.2}
|
||||
image: signoz/signoz-otel-collector:${OTELCOL_TAG:-0.111.5}
|
||||
container_name: signoz-otel-collector
|
||||
command:
|
||||
[
|
||||
@@ -244,9 +247,9 @@ services:
|
||||
- ./otel-collector-config.yaml:/etc/otel-collector-config.yaml
|
||||
- ./otel-collector-opamp-config.yaml:/etc/manager-config.yaml
|
||||
- /var/lib/docker/containers:/var/lib/docker/containers:ro
|
||||
- /:/hostfs:ro
|
||||
environment:
|
||||
- OTEL_RESOURCE_ATTRIBUTES=host.name=signoz-host,os.type=linux
|
||||
- DOCKER_MULTI_NODE_CLUSTER=false
|
||||
- LOW_CARDINAL_EXCEPTION_GROUPING=false
|
||||
ports:
|
||||
# - "1777:1777" # pprof extension
|
||||
@@ -279,29 +282,3 @@ services:
|
||||
depends_on:
|
||||
- otel-collector
|
||||
restart: on-failure
|
||||
|
||||
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: "signoz/locust:1.2.3"
|
||||
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
|
||||
|
||||
@@ -1,306 +1,3 @@
|
||||
version: "2.4"
|
||||
|
||||
x-clickhouse-defaults: &clickhouse-defaults
|
||||
restart: on-failure
|
||||
# addding non LTS version due to this fix https://github.com/ClickHouse/ClickHouse/commit/32caf8716352f45c1b617274c7508c86b7d1afab
|
||||
image: clickhouse/clickhouse-server:24.1.2-alpine
|
||||
tty: true
|
||||
depends_on:
|
||||
- zookeeper-1
|
||||
# - zookeeper-2
|
||||
# - zookeeper-3
|
||||
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",
|
||||
"0.0.0.0:8123/ping"
|
||||
]
|
||||
interval: 30s
|
||||
timeout: 5s
|
||||
retries: 3
|
||||
ulimits:
|
||||
nproc: 65535
|
||||
nofile:
|
||||
soft: 262144
|
||||
hard: 262144
|
||||
|
||||
x-db-depend: &db-depend
|
||||
depends_on:
|
||||
clickhouse:
|
||||
condition: service_healthy
|
||||
otel-collector-migrator:
|
||||
condition: service_completed_successfully
|
||||
# clickhouse-2:
|
||||
# condition: service_healthy
|
||||
# clickhouse-3:
|
||||
# condition: service_healthy
|
||||
|
||||
services:
|
||||
|
||||
zookeeper-1:
|
||||
image: bitnami/zookeeper:3.7.1
|
||||
container_name: signoz-zookeeper-1
|
||||
hostname: zookeeper-1
|
||||
user: root
|
||||
ports:
|
||||
- "2181:2181"
|
||||
- "2888:2888"
|
||||
- "3888:3888"
|
||||
volumes:
|
||||
- ./data/zookeeper-1:/bitnami/zookeeper
|
||||
environment:
|
||||
- ZOO_SERVER_ID=1
|
||||
# - ZOO_SERVERS=0.0.0.0:2888:3888,zookeeper-2:2888:3888,zookeeper-3:2888:3888
|
||||
- ALLOW_ANONYMOUS_LOGIN=yes
|
||||
- ZOO_AUTOPURGE_INTERVAL=1
|
||||
|
||||
# zookeeper-2:
|
||||
# image: bitnami/zookeeper:3.7.0
|
||||
# container_name: signoz-zookeeper-2
|
||||
# hostname: zookeeper-2
|
||||
# user: root
|
||||
# ports:
|
||||
# - "2182:2181"
|
||||
# - "2889:2888"
|
||||
# - "3889:3888"
|
||||
# volumes:
|
||||
# - ./data/zookeeper-2:/bitnami/zookeeper
|
||||
# environment:
|
||||
# - ZOO_SERVER_ID=2
|
||||
# - ZOO_SERVERS=zookeeper-1:2888:3888,0.0.0.0:2888:3888,zookeeper-3:2888:3888
|
||||
# - ALLOW_ANONYMOUS_LOGIN=yes
|
||||
# - ZOO_AUTOPURGE_INTERVAL=1
|
||||
|
||||
# zookeeper-3:
|
||||
# image: bitnami/zookeeper:3.7.0
|
||||
# container_name: signoz-zookeeper-3
|
||||
# hostname: zookeeper-3
|
||||
# user: root
|
||||
# ports:
|
||||
# - "2183:2181"
|
||||
# - "2890:2888"
|
||||
# - "3890:3888"
|
||||
# volumes:
|
||||
# - ./data/zookeeper-3:/bitnami/zookeeper
|
||||
# environment:
|
||||
# - ZOO_SERVER_ID=3
|
||||
# - ZOO_SERVERS=zookeeper-1:2888:3888,zookeeper-2:2888:3888,0.0.0.0:2888:3888
|
||||
# - ALLOW_ANONYMOUS_LOGIN=yes
|
||||
# - ZOO_AUTOPURGE_INTERVAL=1
|
||||
|
||||
clickhouse:
|
||||
<<: *clickhouse-defaults
|
||||
container_name: signoz-clickhouse
|
||||
hostname: clickhouse
|
||||
ports:
|
||||
- "9000:9000"
|
||||
- "8123:8123"
|
||||
- "9181:9181"
|
||||
volumes:
|
||||
- ./clickhouse-config.xml:/etc/clickhouse-server/config.xml
|
||||
- ./clickhouse-users.xml:/etc/clickhouse-server/users.xml
|
||||
- ./custom-function.xml:/etc/clickhouse-server/custom-function.xml
|
||||
- ./clickhouse-cluster.xml:/etc/clickhouse-server/config.d/cluster.xml
|
||||
# - ./clickhouse-storage.xml:/etc/clickhouse-server/config.d/storage.xml
|
||||
- ./data/clickhouse/:/var/lib/clickhouse/
|
||||
- ./user_scripts:/var/lib/clickhouse/user_scripts/
|
||||
|
||||
# clickhouse-2:
|
||||
# <<: *clickhouse-defaults
|
||||
# container_name: signoz-clickhouse-2
|
||||
# hostname: clickhouse-2
|
||||
# ports:
|
||||
# - "9001:9000"
|
||||
# - "8124:8123"
|
||||
# - "9182:9181"
|
||||
# volumes:
|
||||
# - ./clickhouse-config.xml:/etc/clickhouse-server/config.xml
|
||||
# - ./clickhouse-users.xml:/etc/clickhouse-server/users.xml
|
||||
# - ./custom-function.xml:/etc/clickhouse-server/custom-function.xml
|
||||
# - ./clickhouse-cluster.xml:/etc/clickhouse-server/config.d/cluster.xml
|
||||
# # - ./clickhouse-storage.xml:/etc/clickhouse-server/config.d/storage.xml
|
||||
# - ./data/clickhouse-2/:/var/lib/clickhouse/
|
||||
# - ./user_scripts:/var/lib/clickhouse/user_scripts/
|
||||
|
||||
|
||||
# clickhouse-3:
|
||||
# <<: *clickhouse-defaults
|
||||
# container_name: signoz-clickhouse-3
|
||||
# hostname: clickhouse-3
|
||||
# ports:
|
||||
# - "9002:9000"
|
||||
# - "8125:8123"
|
||||
# - "9183:9181"
|
||||
# volumes:
|
||||
# - ./clickhouse-config.xml:/etc/clickhouse-server/config.xml
|
||||
# - ./clickhouse-users.xml:/etc/clickhouse-server/users.xml
|
||||
# - ./custom-function.xml:/etc/clickhouse-server/custom-function.xml
|
||||
# - ./clickhouse-cluster.xml:/etc/clickhouse-server/config.d/cluster.xml
|
||||
# # - ./clickhouse-storage.xml:/etc/clickhouse-server/config.d/storage.xml
|
||||
# - ./data/clickhouse-3/:/var/lib/clickhouse/
|
||||
# - ./user_scripts:/var/lib/clickhouse/user_scripts/
|
||||
|
||||
alertmanager:
|
||||
image: signoz/alertmanager:${ALERTMANAGER_TAG:-0.23.5}
|
||||
container_name: signoz-alertmanager
|
||||
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:${DOCKER_TAG:-0.49.1}
|
||||
container_name: signoz-query-service
|
||||
command:
|
||||
[
|
||||
"-config=/root/config/prometheus.yml"
|
||||
# "--prefer-delta=true"
|
||||
]
|
||||
# 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
|
||||
- ALERTMANAGER_API_PREFIX=http://alertmanager:9093/api/
|
||||
- SIGNOZ_LOCAL_DB_PATH=/var/lib/signoz/signoz.db
|
||||
- DASHBOARDS_PATH=/root/config/dashboards
|
||||
- STORAGE=clickhouse
|
||||
- GODEBUG=netdns=go
|
||||
- TELEMETRY_ENABLED=true
|
||||
- DEPLOYMENT_TYPE=docker-standalone-amd
|
||||
restart: on-failure
|
||||
healthcheck:
|
||||
test:
|
||||
[
|
||||
"CMD",
|
||||
"wget",
|
||||
"--spider",
|
||||
"-q",
|
||||
"localhost:8080/api/v1/health"
|
||||
]
|
||||
interval: 30s
|
||||
timeout: 5s
|
||||
retries: 3
|
||||
<<: *db-depend
|
||||
|
||||
frontend:
|
||||
image: signoz/frontend:${DOCKER_TAG:-0.49.1}
|
||||
container_name: signoz-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-migrator:
|
||||
image: signoz/signoz-schema-migrator:${OTELCOL_TAG:-0.102.2}
|
||||
container_name: otel-migrator
|
||||
command:
|
||||
- "--dsn=tcp://clickhouse:9000"
|
||||
depends_on:
|
||||
clickhouse:
|
||||
condition: service_healthy
|
||||
# clickhouse-2:
|
||||
# condition: service_healthy
|
||||
# clickhouse-3:
|
||||
# condition: service_healthy
|
||||
|
||||
|
||||
otel-collector:
|
||||
image: signoz/signoz-otel-collector:${OTELCOL_TAG:-0.102.2}
|
||||
container_name: signoz-otel-collector
|
||||
command:
|
||||
[
|
||||
"--config=/etc/otel-collector-config.yaml",
|
||||
"--manager-config=/etc/manager-config.yaml",
|
||||
"--copy-path=/var/tmp/collector-config.yaml",
|
||||
"--feature-gates=-pkg.translator.prometheus.NormalizeName"
|
||||
]
|
||||
user: root # required for reading docker container logs
|
||||
volumes:
|
||||
- ./otel-collector-config.yaml:/etc/otel-collector-config.yaml
|
||||
- ./otel-collector-opamp-config.yaml:/etc/manager-config.yaml
|
||||
- /var/lib/docker/containers:/var/lib/docker/containers:ro
|
||||
environment:
|
||||
- OTEL_RESOURCE_ATTRIBUTES=host.name=signoz-host,os.type=linux
|
||||
- DOCKER_MULTI_NODE_CLUSTER=false
|
||||
- LOW_CARDINAL_EXCEPTION_GROUPING=false
|
||||
ports:
|
||||
# - "1777:1777" # pprof extension
|
||||
- "4317:4317" # OTLP gRPC receiver
|
||||
- "4318:4318" # OTLP HTTP receiver
|
||||
# - "8888:8888" # OtelCollector internal metrics
|
||||
# - "8889:8889" # signoz spanmetrics exposed by the agent
|
||||
# - "9411:9411" # Zipkin port
|
||||
# - "13133:13133" # health check extension
|
||||
# - "14250:14250" # Jaeger gRPC
|
||||
# - "14268:14268" # Jaeger thrift HTTP
|
||||
# - "55678:55678" # OpenCensus receiver
|
||||
# - "55679:55679" # zPages extension
|
||||
restart: on-failure
|
||||
depends_on:
|
||||
clickhouse:
|
||||
condition: service_healthy
|
||||
otel-collector-migrator:
|
||||
condition: service_completed_successfully
|
||||
query-service:
|
||||
condition: service_healthy
|
||||
|
||||
logspout:
|
||||
image: "gliderlabs/logspout:v3.2.14"
|
||||
container_name: signoz-logspout
|
||||
volumes:
|
||||
- /etc/hostname:/etc/host_hostname:ro
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
command: syslog+tcp://otel-collector:2255
|
||||
depends_on:
|
||||
- otel-collector
|
||||
restart: on-failure
|
||||
|
||||
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: "signoz/locust:1.2.3"
|
||||
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
|
||||
include:
|
||||
- test-app-docker-compose.yaml
|
||||
- docker-compose-minimal.yaml
|
||||
|
||||
@@ -36,6 +36,7 @@ receivers:
|
||||
# endpoint: 0.0.0.0:6832
|
||||
hostmetrics:
|
||||
collection_interval: 30s
|
||||
root_path: /hostfs
|
||||
scrapers:
|
||||
cpu: {}
|
||||
load: {}
|
||||
@@ -141,8 +142,7 @@ extensions:
|
||||
exporters:
|
||||
clickhousetraces:
|
||||
datasource: tcp://clickhouse:9000/signoz_traces
|
||||
docker_multi_node_cluster: ${DOCKER_MULTI_NODE_CLUSTER}
|
||||
low_cardinal_exception_grouping: ${LOW_CARDINAL_EXCEPTION_GROUPING}
|
||||
low_cardinal_exception_grouping: ${env:LOW_CARDINAL_EXCEPTION_GROUPING}
|
||||
clickhousemetricswrite:
|
||||
endpoint: tcp://clickhouse:9000/signoz_metrics
|
||||
resource_to_telemetry_conversion:
|
||||
@@ -151,12 +151,14 @@ exporters:
|
||||
endpoint: tcp://clickhouse:9000/signoz_metrics
|
||||
clickhouselogsexporter:
|
||||
dsn: tcp://clickhouse:9000/signoz_logs
|
||||
docker_multi_node_cluster: ${DOCKER_MULTI_NODE_CLUSTER}
|
||||
timeout: 10s
|
||||
use_new_schema: true
|
||||
# logging: {}
|
||||
|
||||
service:
|
||||
telemetry:
|
||||
logs:
|
||||
encoding: json
|
||||
metrics:
|
||||
address: 0.0.0.0:8888
|
||||
extensions:
|
||||
|
||||
26
deploy/docker/clickhouse-setup/test-app-docker-compose.yaml
Normal file
@@ -0,0 +1,26 @@
|
||||
services:
|
||||
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: "signoz/locust:1.2.3"
|
||||
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
|
||||
@@ -1,3 +1,8 @@
|
||||
map $http_upgrade $connection_upgrade {
|
||||
default upgrade;
|
||||
'' close;
|
||||
}
|
||||
|
||||
server {
|
||||
listen 3301;
|
||||
server_name _;
|
||||
@@ -42,6 +47,14 @@ server {
|
||||
proxy_read_timeout 600s;
|
||||
}
|
||||
|
||||
location /ws {
|
||||
proxy_pass http://query-service:8080/ws;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade "websocket";
|
||||
proxy_set_header Connection "upgrade";
|
||||
proxy_read_timeout 86400;
|
||||
}
|
||||
|
||||
# redirect server error pages to the static page /50x.html
|
||||
#
|
||||
error_page 500 502 503 504 /50x.html;
|
||||
|
||||
44
ee/query-service/anomaly/daily.go
Normal file
@@ -0,0 +1,44 @@
|
||||
package anomaly
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
querierV2 "go.signoz.io/signoz/pkg/query-service/app/querier/v2"
|
||||
"go.signoz.io/signoz/pkg/query-service/app/queryBuilder"
|
||||
)
|
||||
|
||||
type DailyProvider struct {
|
||||
BaseSeasonalProvider
|
||||
}
|
||||
|
||||
var _ BaseProvider = (*DailyProvider)(nil)
|
||||
|
||||
func (dp *DailyProvider) GetBaseSeasonalProvider() *BaseSeasonalProvider {
|
||||
return &dp.BaseSeasonalProvider
|
||||
}
|
||||
|
||||
// NewDailyProvider uses the same generic option type
|
||||
func NewDailyProvider(opts ...GenericProviderOption[*DailyProvider]) *DailyProvider {
|
||||
dp := &DailyProvider{
|
||||
BaseSeasonalProvider: BaseSeasonalProvider{},
|
||||
}
|
||||
|
||||
for _, opt := range opts {
|
||||
opt(dp)
|
||||
}
|
||||
|
||||
dp.querierV2 = querierV2.NewQuerier(querierV2.QuerierOptions{
|
||||
Reader: dp.reader,
|
||||
Cache: dp.cache,
|
||||
KeyGenerator: queryBuilder.NewKeyGenerator(),
|
||||
FluxInterval: dp.fluxInterval,
|
||||
FeatureLookup: dp.ff,
|
||||
})
|
||||
|
||||
return dp
|
||||
}
|
||||
|
||||
func (p *DailyProvider) GetAnomalies(ctx context.Context, req *GetAnomaliesRequest) (*GetAnomaliesResponse, error) {
|
||||
req.Seasonality = SeasonalityDaily
|
||||
return p.getAnomalies(ctx, req)
|
||||
}
|
||||
44
ee/query-service/anomaly/hourly.go
Normal file
@@ -0,0 +1,44 @@
|
||||
package anomaly
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
querierV2 "go.signoz.io/signoz/pkg/query-service/app/querier/v2"
|
||||
"go.signoz.io/signoz/pkg/query-service/app/queryBuilder"
|
||||
)
|
||||
|
||||
type HourlyProvider struct {
|
||||
BaseSeasonalProvider
|
||||
}
|
||||
|
||||
var _ BaseProvider = (*HourlyProvider)(nil)
|
||||
|
||||
func (hp *HourlyProvider) GetBaseSeasonalProvider() *BaseSeasonalProvider {
|
||||
return &hp.BaseSeasonalProvider
|
||||
}
|
||||
|
||||
// NewHourlyProvider now uses the generic option type
|
||||
func NewHourlyProvider(opts ...GenericProviderOption[*HourlyProvider]) *HourlyProvider {
|
||||
hp := &HourlyProvider{
|
||||
BaseSeasonalProvider: BaseSeasonalProvider{},
|
||||
}
|
||||
|
||||
for _, opt := range opts {
|
||||
opt(hp)
|
||||
}
|
||||
|
||||
hp.querierV2 = querierV2.NewQuerier(querierV2.QuerierOptions{
|
||||
Reader: hp.reader,
|
||||
Cache: hp.cache,
|
||||
KeyGenerator: queryBuilder.NewKeyGenerator(),
|
||||
FluxInterval: hp.fluxInterval,
|
||||
FeatureLookup: hp.ff,
|
||||
})
|
||||
|
||||
return hp
|
||||
}
|
||||
|
||||
func (p *HourlyProvider) GetAnomalies(ctx context.Context, req *GetAnomaliesRequest) (*GetAnomaliesResponse, error) {
|
||||
req.Seasonality = SeasonalityHourly
|
||||
return p.getAnomalies(ctx, req)
|
||||
}
|
||||
248
ee/query-service/anomaly/params.go
Normal file
@@ -0,0 +1,248 @@
|
||||
package anomaly
|
||||
|
||||
import (
|
||||
"math"
|
||||
"time"
|
||||
|
||||
"go.signoz.io/signoz/pkg/query-service/common"
|
||||
v3 "go.signoz.io/signoz/pkg/query-service/model/v3"
|
||||
)
|
||||
|
||||
type Seasonality string
|
||||
|
||||
const (
|
||||
SeasonalityHourly Seasonality = "hourly"
|
||||
SeasonalityDaily Seasonality = "daily"
|
||||
SeasonalityWeekly Seasonality = "weekly"
|
||||
)
|
||||
|
||||
func (s Seasonality) String() string {
|
||||
return string(s)
|
||||
}
|
||||
|
||||
var (
|
||||
oneWeekOffset = 24 * 7 * time.Hour.Milliseconds()
|
||||
oneDayOffset = 24 * time.Hour.Milliseconds()
|
||||
oneHourOffset = time.Hour.Milliseconds()
|
||||
fiveMinOffset = 5 * time.Minute.Milliseconds()
|
||||
)
|
||||
|
||||
func (s Seasonality) IsValid() bool {
|
||||
switch s {
|
||||
case SeasonalityHourly, SeasonalityDaily, SeasonalityWeekly:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
type GetAnomaliesRequest struct {
|
||||
Params *v3.QueryRangeParamsV3
|
||||
Seasonality Seasonality
|
||||
}
|
||||
|
||||
type GetAnomaliesResponse struct {
|
||||
Results []*v3.Result
|
||||
}
|
||||
|
||||
// anomalyParams is the params for anomaly detection
|
||||
// prediction = avg(past_period_query) + avg(current_season_query) - mean(past_season_query, past2_season_query, past3_season_query)
|
||||
//
|
||||
// ^ ^
|
||||
// | |
|
||||
// (rounded value for past peiod) + (seasonal growth)
|
||||
//
|
||||
// score = abs(value - prediction) / stddev (current_season_query)
|
||||
type anomalyQueryParams struct {
|
||||
// CurrentPeriodQuery is the query range params for period user is looking at or eval window
|
||||
// Example: (now-5m, now), (now-30m, now), (now-1h, now)
|
||||
// The results obtained from this query are used to compare with predicted values
|
||||
// and to detect anomalies
|
||||
CurrentPeriodQuery *v3.QueryRangeParamsV3
|
||||
// PastPeriodQuery is the query range params for past seasonal period
|
||||
// Example: For weekly seasonality, (now-1w-5m, now-1w)
|
||||
// : For daily seasonality, (now-1d-5m, now-1d)
|
||||
// : For hourly seasonality, (now-1h-5m, now-1h)
|
||||
PastPeriodQuery *v3.QueryRangeParamsV3
|
||||
// CurrentSeasonQuery is the query range params for current period (seasonal)
|
||||
// Example: For weekly seasonality, this is the query range params for the (now-1w-5m, now)
|
||||
// : For daily seasonality, this is the query range params for the (now-1d-5m, now)
|
||||
// : For hourly seasonality, this is the query range params for the (now-1h-5m, now)
|
||||
CurrentSeasonQuery *v3.QueryRangeParamsV3
|
||||
// PastSeasonQuery is the query range params for past seasonal period to the current season
|
||||
// Example: For weekly seasonality, this is the query range params for the (now-2w-5m, now-1w)
|
||||
// : For daily seasonality, this is the query range params for the (now-2d-5m, now-1d)
|
||||
// : For hourly seasonality, this is the query range params for the (now-2h-5m, now-1h)
|
||||
PastSeasonQuery *v3.QueryRangeParamsV3
|
||||
|
||||
// Past2SeasonQuery is the query range params for past 2 seasonal period to the current season
|
||||
// Example: For weekly seasonality, this is the query range params for the (now-3w-5m, now-2w)
|
||||
// : For daily seasonality, this is the query range params for the (now-3d-5m, now-2d)
|
||||
// : For hourly seasonality, this is the query range params for the (now-3h-5m, now-2h)
|
||||
Past2SeasonQuery *v3.QueryRangeParamsV3
|
||||
// Past3SeasonQuery is the query range params for past 3 seasonal period to the current season
|
||||
// Example: For weekly seasonality, this is the query range params for the (now-4w-5m, now-3w)
|
||||
// : For daily seasonality, this is the query range params for the (now-4d-5m, now-3d)
|
||||
// : For hourly seasonality, this is the query range params for the (now-4h-5m, now-3h)
|
||||
Past3SeasonQuery *v3.QueryRangeParamsV3
|
||||
}
|
||||
|
||||
func updateStepInterval(req *v3.QueryRangeParamsV3) {
|
||||
start := req.Start
|
||||
end := req.End
|
||||
|
||||
req.Step = int64(math.Max(float64(common.MinAllowedStepInterval(start, end)), 60))
|
||||
for _, q := range req.CompositeQuery.BuilderQueries {
|
||||
// If the step interval is less than the minimum allowed step interval, set it to the minimum allowed step interval
|
||||
if minStep := common.MinAllowedStepInterval(start, end); q.StepInterval < minStep {
|
||||
q.StepInterval = minStep
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func prepareAnomalyQueryParams(req *v3.QueryRangeParamsV3, seasonality Seasonality) *anomalyQueryParams {
|
||||
start := req.Start
|
||||
end := req.End
|
||||
|
||||
currentPeriodQuery := &v3.QueryRangeParamsV3{
|
||||
Start: start,
|
||||
End: end,
|
||||
CompositeQuery: req.CompositeQuery.Clone(),
|
||||
Variables: make(map[string]interface{}, 0),
|
||||
NoCache: false,
|
||||
}
|
||||
updateStepInterval(currentPeriodQuery)
|
||||
|
||||
var pastPeriodStart, pastPeriodEnd int64
|
||||
|
||||
switch seasonality {
|
||||
// for one week period, we fetch the data from the past week with 5 min offset
|
||||
case SeasonalityWeekly:
|
||||
pastPeriodStart = start - oneWeekOffset - fiveMinOffset
|
||||
pastPeriodEnd = end - oneWeekOffset
|
||||
// for one day period, we fetch the data from the past day with 5 min offset
|
||||
case SeasonalityDaily:
|
||||
pastPeriodStart = start - oneDayOffset - fiveMinOffset
|
||||
pastPeriodEnd = end - oneDayOffset
|
||||
// for one hour period, we fetch the data from the past hour with 5 min offset
|
||||
case SeasonalityHourly:
|
||||
pastPeriodStart = start - oneHourOffset - fiveMinOffset
|
||||
pastPeriodEnd = end - oneHourOffset
|
||||
}
|
||||
|
||||
pastPeriodQuery := &v3.QueryRangeParamsV3{
|
||||
Start: pastPeriodStart,
|
||||
End: pastPeriodEnd,
|
||||
CompositeQuery: req.CompositeQuery.Clone(),
|
||||
Variables: make(map[string]interface{}, 0),
|
||||
NoCache: false,
|
||||
}
|
||||
updateStepInterval(pastPeriodQuery)
|
||||
|
||||
// seasonality growth trend
|
||||
var currentGrowthPeriodStart, currentGrowthPeriodEnd int64
|
||||
switch seasonality {
|
||||
case SeasonalityWeekly:
|
||||
currentGrowthPeriodStart = start - oneWeekOffset
|
||||
currentGrowthPeriodEnd = end
|
||||
case SeasonalityDaily:
|
||||
currentGrowthPeriodStart = start - oneDayOffset
|
||||
currentGrowthPeriodEnd = end
|
||||
case SeasonalityHourly:
|
||||
currentGrowthPeriodStart = start - oneHourOffset
|
||||
currentGrowthPeriodEnd = end
|
||||
}
|
||||
|
||||
currentGrowthQuery := &v3.QueryRangeParamsV3{
|
||||
Start: currentGrowthPeriodStart,
|
||||
End: currentGrowthPeriodEnd,
|
||||
CompositeQuery: req.CompositeQuery.Clone(),
|
||||
Variables: make(map[string]interface{}, 0),
|
||||
NoCache: false,
|
||||
}
|
||||
updateStepInterval(currentGrowthQuery)
|
||||
|
||||
var pastGrowthPeriodStart, pastGrowthPeriodEnd int64
|
||||
switch seasonality {
|
||||
case SeasonalityWeekly:
|
||||
pastGrowthPeriodStart = start - 2*oneWeekOffset
|
||||
pastGrowthPeriodEnd = start - 1*oneWeekOffset
|
||||
case SeasonalityDaily:
|
||||
pastGrowthPeriodStart = start - 2*oneDayOffset
|
||||
pastGrowthPeriodEnd = start - 1*oneDayOffset
|
||||
case SeasonalityHourly:
|
||||
pastGrowthPeriodStart = start - 2*oneHourOffset
|
||||
pastGrowthPeriodEnd = start - 1*oneHourOffset
|
||||
}
|
||||
|
||||
pastGrowthQuery := &v3.QueryRangeParamsV3{
|
||||
Start: pastGrowthPeriodStart,
|
||||
End: pastGrowthPeriodEnd,
|
||||
CompositeQuery: req.CompositeQuery.Clone(),
|
||||
Variables: make(map[string]interface{}, 0),
|
||||
NoCache: false,
|
||||
}
|
||||
updateStepInterval(pastGrowthQuery)
|
||||
|
||||
var past2GrowthPeriodStart, past2GrowthPeriodEnd int64
|
||||
switch seasonality {
|
||||
case SeasonalityWeekly:
|
||||
past2GrowthPeriodStart = start - 3*oneWeekOffset
|
||||
past2GrowthPeriodEnd = start - 2*oneWeekOffset
|
||||
case SeasonalityDaily:
|
||||
past2GrowthPeriodStart = start - 3*oneDayOffset
|
||||
past2GrowthPeriodEnd = start - 2*oneDayOffset
|
||||
case SeasonalityHourly:
|
||||
past2GrowthPeriodStart = start - 3*oneHourOffset
|
||||
past2GrowthPeriodEnd = start - 2*oneHourOffset
|
||||
}
|
||||
|
||||
past2GrowthQuery := &v3.QueryRangeParamsV3{
|
||||
Start: past2GrowthPeriodStart,
|
||||
End: past2GrowthPeriodEnd,
|
||||
CompositeQuery: req.CompositeQuery.Clone(),
|
||||
Variables: make(map[string]interface{}, 0),
|
||||
NoCache: false,
|
||||
}
|
||||
updateStepInterval(past2GrowthQuery)
|
||||
|
||||
var past3GrowthPeriodStart, past3GrowthPeriodEnd int64
|
||||
switch seasonality {
|
||||
case SeasonalityWeekly:
|
||||
past3GrowthPeriodStart = start - 4*oneWeekOffset
|
||||
past3GrowthPeriodEnd = start - 3*oneWeekOffset
|
||||
case SeasonalityDaily:
|
||||
past3GrowthPeriodStart = start - 4*oneDayOffset
|
||||
past3GrowthPeriodEnd = start - 3*oneDayOffset
|
||||
case SeasonalityHourly:
|
||||
past3GrowthPeriodStart = start - 4*oneHourOffset
|
||||
past3GrowthPeriodEnd = start - 3*oneHourOffset
|
||||
}
|
||||
|
||||
past3GrowthQuery := &v3.QueryRangeParamsV3{
|
||||
Start: past3GrowthPeriodStart,
|
||||
End: past3GrowthPeriodEnd,
|
||||
CompositeQuery: req.CompositeQuery.Clone(),
|
||||
Variables: make(map[string]interface{}, 0),
|
||||
NoCache: false,
|
||||
}
|
||||
updateStepInterval(past3GrowthQuery)
|
||||
|
||||
return &anomalyQueryParams{
|
||||
CurrentPeriodQuery: currentPeriodQuery,
|
||||
PastPeriodQuery: pastPeriodQuery,
|
||||
CurrentSeasonQuery: currentGrowthQuery,
|
||||
PastSeasonQuery: pastGrowthQuery,
|
||||
Past2SeasonQuery: past2GrowthQuery,
|
||||
Past3SeasonQuery: past3GrowthQuery,
|
||||
}
|
||||
}
|
||||
|
||||
type anomalyQueryResults struct {
|
||||
CurrentPeriodResults []*v3.Result
|
||||
PastPeriodResults []*v3.Result
|
||||
CurrentSeasonResults []*v3.Result
|
||||
PastSeasonResults []*v3.Result
|
||||
Past2SeasonResults []*v3.Result
|
||||
Past3SeasonResults []*v3.Result
|
||||
}
|
||||
9
ee/query-service/anomaly/provider.go
Normal file
@@ -0,0 +1,9 @@
|
||||
package anomaly
|
||||
|
||||
import (
|
||||
"context"
|
||||
)
|
||||
|
||||
type Provider interface {
|
||||
GetAnomalies(ctx context.Context, req *GetAnomaliesRequest) (*GetAnomaliesResponse, error)
|
||||
}
|
||||
466
ee/query-service/anomaly/seasonal.go
Normal file
@@ -0,0 +1,466 @@
|
||||
package anomaly
|
||||
|
||||
import (
|
||||
"context"
|
||||
"math"
|
||||
"time"
|
||||
|
||||
"go.signoz.io/signoz/pkg/query-service/cache"
|
||||
"go.signoz.io/signoz/pkg/query-service/interfaces"
|
||||
v3 "go.signoz.io/signoz/pkg/query-service/model/v3"
|
||||
"go.signoz.io/signoz/pkg/query-service/postprocess"
|
||||
"go.signoz.io/signoz/pkg/query-service/utils/labels"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
var (
|
||||
// TODO(srikanthccv): make this configurable?
|
||||
movingAvgWindowSize = 7
|
||||
)
|
||||
|
||||
// BaseProvider is an interface that includes common methods for all provider types
|
||||
type BaseProvider interface {
|
||||
GetBaseSeasonalProvider() *BaseSeasonalProvider
|
||||
}
|
||||
|
||||
// GenericProviderOption is a generic type for provider options
|
||||
type GenericProviderOption[T BaseProvider] func(T)
|
||||
|
||||
func WithCache[T BaseProvider](cache cache.Cache) GenericProviderOption[T] {
|
||||
return func(p T) {
|
||||
p.GetBaseSeasonalProvider().cache = cache
|
||||
}
|
||||
}
|
||||
|
||||
func WithKeyGenerator[T BaseProvider](keyGenerator cache.KeyGenerator) GenericProviderOption[T] {
|
||||
return func(p T) {
|
||||
p.GetBaseSeasonalProvider().keyGenerator = keyGenerator
|
||||
}
|
||||
}
|
||||
|
||||
func WithFeatureLookup[T BaseProvider](ff interfaces.FeatureLookup) GenericProviderOption[T] {
|
||||
return func(p T) {
|
||||
p.GetBaseSeasonalProvider().ff = ff
|
||||
}
|
||||
}
|
||||
|
||||
func WithReader[T BaseProvider](reader interfaces.Reader) GenericProviderOption[T] {
|
||||
return func(p T) {
|
||||
p.GetBaseSeasonalProvider().reader = reader
|
||||
}
|
||||
}
|
||||
|
||||
type BaseSeasonalProvider struct {
|
||||
querierV2 interfaces.Querier
|
||||
reader interfaces.Reader
|
||||
fluxInterval time.Duration
|
||||
cache cache.Cache
|
||||
keyGenerator cache.KeyGenerator
|
||||
ff interfaces.FeatureLookup
|
||||
}
|
||||
|
||||
func (p *BaseSeasonalProvider) getQueryParams(req *GetAnomaliesRequest) *anomalyQueryParams {
|
||||
if !req.Seasonality.IsValid() {
|
||||
req.Seasonality = SeasonalityDaily
|
||||
}
|
||||
return prepareAnomalyQueryParams(req.Params, req.Seasonality)
|
||||
}
|
||||
|
||||
func (p *BaseSeasonalProvider) getResults(ctx context.Context, params *anomalyQueryParams) (*anomalyQueryResults, error) {
|
||||
zap.L().Info("fetching results for current period", zap.Any("currentPeriodQuery", params.CurrentPeriodQuery))
|
||||
currentPeriodResults, _, err := p.querierV2.QueryRange(ctx, params.CurrentPeriodQuery)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
currentPeriodResults, err = postprocess.PostProcessResult(currentPeriodResults, params.CurrentPeriodQuery)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
zap.L().Info("fetching results for past period", zap.Any("pastPeriodQuery", params.PastPeriodQuery))
|
||||
pastPeriodResults, _, err := p.querierV2.QueryRange(ctx, params.PastPeriodQuery)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
pastPeriodResults, err = postprocess.PostProcessResult(pastPeriodResults, params.PastPeriodQuery)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
zap.L().Info("fetching results for current season", zap.Any("currentSeasonQuery", params.CurrentSeasonQuery))
|
||||
currentSeasonResults, _, err := p.querierV2.QueryRange(ctx, params.CurrentSeasonQuery)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
currentSeasonResults, err = postprocess.PostProcessResult(currentSeasonResults, params.CurrentSeasonQuery)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
zap.L().Info("fetching results for past season", zap.Any("pastSeasonQuery", params.PastSeasonQuery))
|
||||
pastSeasonResults, _, err := p.querierV2.QueryRange(ctx, params.PastSeasonQuery)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
pastSeasonResults, err = postprocess.PostProcessResult(pastSeasonResults, params.PastSeasonQuery)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
zap.L().Info("fetching results for past 2 season", zap.Any("past2SeasonQuery", params.Past2SeasonQuery))
|
||||
past2SeasonResults, _, err := p.querierV2.QueryRange(ctx, params.Past2SeasonQuery)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
past2SeasonResults, err = postprocess.PostProcessResult(past2SeasonResults, params.Past2SeasonQuery)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
zap.L().Info("fetching results for past 3 season", zap.Any("past3SeasonQuery", params.Past3SeasonQuery))
|
||||
past3SeasonResults, _, err := p.querierV2.QueryRange(ctx, params.Past3SeasonQuery)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
past3SeasonResults, err = postprocess.PostProcessResult(past3SeasonResults, params.Past3SeasonQuery)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &anomalyQueryResults{
|
||||
CurrentPeriodResults: currentPeriodResults,
|
||||
PastPeriodResults: pastPeriodResults,
|
||||
CurrentSeasonResults: currentSeasonResults,
|
||||
PastSeasonResults: pastSeasonResults,
|
||||
Past2SeasonResults: past2SeasonResults,
|
||||
Past3SeasonResults: past3SeasonResults,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// getMatchingSeries gets the matching series from the query result
|
||||
// for the given series
|
||||
func (p *BaseSeasonalProvider) getMatchingSeries(queryResult *v3.Result, series *v3.Series) *v3.Series {
|
||||
if queryResult == nil || len(queryResult.Series) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
for _, curr := range queryResult.Series {
|
||||
currLabels := labels.FromMap(curr.Labels)
|
||||
seriesLabels := labels.FromMap(series.Labels)
|
||||
if currLabels.Hash() == seriesLabels.Hash() {
|
||||
return curr
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *BaseSeasonalProvider) getAvg(series *v3.Series) float64 {
|
||||
if series == nil || len(series.Points) == 0 {
|
||||
return 0
|
||||
}
|
||||
var sum float64
|
||||
for _, smpl := range series.Points {
|
||||
sum += smpl.Value
|
||||
}
|
||||
return sum / float64(len(series.Points))
|
||||
}
|
||||
|
||||
func (p *BaseSeasonalProvider) getStdDev(series *v3.Series) float64 {
|
||||
if series == nil || len(series.Points) == 0 {
|
||||
return 0
|
||||
}
|
||||
avg := p.getAvg(series)
|
||||
var sum float64
|
||||
for _, smpl := range series.Points {
|
||||
sum += math.Pow(smpl.Value-avg, 2)
|
||||
}
|
||||
return math.Sqrt(sum / float64(len(series.Points)))
|
||||
}
|
||||
|
||||
// getMovingAvg gets the moving average for the given series
|
||||
// for the given window size and start index
|
||||
func (p *BaseSeasonalProvider) getMovingAvg(series *v3.Series, movingAvgWindowSize, startIdx int) float64 {
|
||||
if series == nil || len(series.Points) == 0 {
|
||||
return 0
|
||||
}
|
||||
if startIdx >= len(series.Points)-movingAvgWindowSize {
|
||||
startIdx = int(math.Max(0, float64(len(series.Points)-movingAvgWindowSize)))
|
||||
}
|
||||
var sum float64
|
||||
points := series.Points[startIdx:]
|
||||
for i := 0; i < movingAvgWindowSize && i < len(points); i++ {
|
||||
sum += points[i].Value
|
||||
}
|
||||
avg := sum / float64(movingAvgWindowSize)
|
||||
return avg
|
||||
}
|
||||
|
||||
func (p *BaseSeasonalProvider) getMean(floats ...float64) float64 {
|
||||
if len(floats) == 0 {
|
||||
return 0
|
||||
}
|
||||
var sum float64
|
||||
for _, f := range floats {
|
||||
sum += f
|
||||
}
|
||||
return sum / float64(len(floats))
|
||||
}
|
||||
|
||||
func (p *BaseSeasonalProvider) getPredictedSeries(
|
||||
series, prevSeries, currentSeasonSeries, pastSeasonSeries, past2SeasonSeries, past3SeasonSeries *v3.Series,
|
||||
) *v3.Series {
|
||||
predictedSeries := &v3.Series{
|
||||
Labels: series.Labels,
|
||||
LabelsArray: series.LabelsArray,
|
||||
Points: []v3.Point{},
|
||||
}
|
||||
|
||||
// for each point in the series, get the predicted value
|
||||
// the predicted value is the moving average (with window size = 7) of the previous period series
|
||||
// plus the average of the current season series
|
||||
// minus the mean of the past season series, past2 season series and past3 season series
|
||||
for idx, curr := range series.Points {
|
||||
predictedValue :=
|
||||
p.getMovingAvg(prevSeries, movingAvgWindowSize, idx) +
|
||||
p.getAvg(currentSeasonSeries) -
|
||||
p.getMean(p.getAvg(pastSeasonSeries), p.getAvg(past2SeasonSeries), p.getAvg(past3SeasonSeries))
|
||||
|
||||
if predictedValue < 0 {
|
||||
predictedValue = p.getMovingAvg(prevSeries, movingAvgWindowSize, idx)
|
||||
}
|
||||
|
||||
zap.L().Info("predictedSeries",
|
||||
zap.Float64("movingAvg", p.getMovingAvg(prevSeries, movingAvgWindowSize, idx)),
|
||||
zap.Float64("avg", p.getAvg(currentSeasonSeries)),
|
||||
zap.Float64("mean", p.getMean(p.getAvg(pastSeasonSeries), p.getAvg(past2SeasonSeries), p.getAvg(past3SeasonSeries))),
|
||||
zap.Any("labels", series.Labels),
|
||||
zap.Float64("predictedValue", predictedValue),
|
||||
)
|
||||
predictedSeries.Points = append(predictedSeries.Points, v3.Point{
|
||||
Timestamp: curr.Timestamp,
|
||||
Value: predictedValue,
|
||||
})
|
||||
}
|
||||
|
||||
return predictedSeries
|
||||
}
|
||||
|
||||
// getBounds gets the upper and lower bounds for the given series
|
||||
// for the given z score threshold
|
||||
// moving avg of the previous period series + z score threshold * std dev of the series
|
||||
// moving avg of the previous period series - z score threshold * std dev of the series
|
||||
func (p *BaseSeasonalProvider) getBounds(
|
||||
series, predictedSeries *v3.Series,
|
||||
zScoreThreshold float64,
|
||||
) (*v3.Series, *v3.Series) {
|
||||
upperBoundSeries := &v3.Series{
|
||||
Labels: series.Labels,
|
||||
LabelsArray: series.LabelsArray,
|
||||
Points: []v3.Point{},
|
||||
}
|
||||
|
||||
lowerBoundSeries := &v3.Series{
|
||||
Labels: series.Labels,
|
||||
LabelsArray: series.LabelsArray,
|
||||
Points: []v3.Point{},
|
||||
}
|
||||
|
||||
for idx, curr := range series.Points {
|
||||
upperBound := p.getMovingAvg(predictedSeries, movingAvgWindowSize, idx) + zScoreThreshold*p.getStdDev(series)
|
||||
lowerBound := p.getMovingAvg(predictedSeries, movingAvgWindowSize, idx) - zScoreThreshold*p.getStdDev(series)
|
||||
upperBoundSeries.Points = append(upperBoundSeries.Points, v3.Point{
|
||||
Timestamp: curr.Timestamp,
|
||||
Value: upperBound,
|
||||
})
|
||||
lowerBoundSeries.Points = append(lowerBoundSeries.Points, v3.Point{
|
||||
Timestamp: curr.Timestamp,
|
||||
Value: math.Max(lowerBound, 0),
|
||||
})
|
||||
}
|
||||
|
||||
return upperBoundSeries, lowerBoundSeries
|
||||
}
|
||||
|
||||
// getExpectedValue gets the expected value for the given series
|
||||
// for the given index
|
||||
// prevSeriesAvg + currentSeasonSeriesAvg - mean of past season series, past2 season series and past3 season series
|
||||
func (p *BaseSeasonalProvider) getExpectedValue(
|
||||
_, prevSeries, currentSeasonSeries, pastSeasonSeries, past2SeasonSeries, past3SeasonSeries *v3.Series, idx int,
|
||||
) float64 {
|
||||
prevSeriesAvg := p.getMovingAvg(prevSeries, movingAvgWindowSize, idx)
|
||||
currentSeasonSeriesAvg := p.getAvg(currentSeasonSeries)
|
||||
pastSeasonSeriesAvg := p.getAvg(pastSeasonSeries)
|
||||
past2SeasonSeriesAvg := p.getAvg(past2SeasonSeries)
|
||||
past3SeasonSeriesAvg := p.getAvg(past3SeasonSeries)
|
||||
return prevSeriesAvg + currentSeasonSeriesAvg - p.getMean(pastSeasonSeriesAvg, past2SeasonSeriesAvg, past3SeasonSeriesAvg)
|
||||
}
|
||||
|
||||
// getScore gets the anomaly score for the given series
|
||||
// for the given index
|
||||
// (value - expectedValue) / std dev of the series
|
||||
func (p *BaseSeasonalProvider) getScore(
|
||||
series, prevSeries, weekSeries, weekPrevSeries, past2SeasonSeries, past3SeasonSeries *v3.Series, value float64, idx int,
|
||||
) float64 {
|
||||
expectedValue := p.getExpectedValue(series, prevSeries, weekSeries, weekPrevSeries, past2SeasonSeries, past3SeasonSeries, idx)
|
||||
return (value - expectedValue) / p.getStdDev(weekSeries)
|
||||
}
|
||||
|
||||
// getAnomalyScores gets the anomaly scores for the given series
|
||||
// for the given index
|
||||
// (value - expectedValue) / std dev of the series
|
||||
func (p *BaseSeasonalProvider) getAnomalyScores(
|
||||
series, prevSeries, currentSeasonSeries, pastSeasonSeries, past2SeasonSeries, past3SeasonSeries *v3.Series,
|
||||
) *v3.Series {
|
||||
anomalyScoreSeries := &v3.Series{
|
||||
Labels: series.Labels,
|
||||
LabelsArray: series.LabelsArray,
|
||||
Points: []v3.Point{},
|
||||
}
|
||||
|
||||
for idx, curr := range series.Points {
|
||||
anomalyScore := p.getScore(series, prevSeries, currentSeasonSeries, pastSeasonSeries, past2SeasonSeries, past3SeasonSeries, curr.Value, idx)
|
||||
anomalyScoreSeries.Points = append(anomalyScoreSeries.Points, v3.Point{
|
||||
Timestamp: curr.Timestamp,
|
||||
Value: anomalyScore,
|
||||
})
|
||||
}
|
||||
|
||||
return anomalyScoreSeries
|
||||
}
|
||||
|
||||
func (p *BaseSeasonalProvider) getAnomalies(ctx context.Context, req *GetAnomaliesRequest) (*GetAnomaliesResponse, error) {
|
||||
anomalyParams := p.getQueryParams(req)
|
||||
anomalyQueryResults, err := p.getResults(ctx, anomalyParams)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
currentPeriodResultsMap := make(map[string]*v3.Result)
|
||||
for _, result := range anomalyQueryResults.CurrentPeriodResults {
|
||||
currentPeriodResultsMap[result.QueryName] = result
|
||||
}
|
||||
|
||||
pastPeriodResultsMap := make(map[string]*v3.Result)
|
||||
for _, result := range anomalyQueryResults.PastPeriodResults {
|
||||
pastPeriodResultsMap[result.QueryName] = result
|
||||
}
|
||||
|
||||
currentSeasonResultsMap := make(map[string]*v3.Result)
|
||||
for _, result := range anomalyQueryResults.CurrentSeasonResults {
|
||||
currentSeasonResultsMap[result.QueryName] = result
|
||||
}
|
||||
|
||||
pastSeasonResultsMap := make(map[string]*v3.Result)
|
||||
for _, result := range anomalyQueryResults.PastSeasonResults {
|
||||
pastSeasonResultsMap[result.QueryName] = result
|
||||
}
|
||||
|
||||
past2SeasonResultsMap := make(map[string]*v3.Result)
|
||||
for _, result := range anomalyQueryResults.Past2SeasonResults {
|
||||
past2SeasonResultsMap[result.QueryName] = result
|
||||
}
|
||||
|
||||
past3SeasonResultsMap := make(map[string]*v3.Result)
|
||||
for _, result := range anomalyQueryResults.Past3SeasonResults {
|
||||
past3SeasonResultsMap[result.QueryName] = result
|
||||
}
|
||||
|
||||
for _, result := range currentPeriodResultsMap {
|
||||
funcs := req.Params.CompositeQuery.BuilderQueries[result.QueryName].Functions
|
||||
|
||||
var zScoreThreshold float64
|
||||
for _, f := range funcs {
|
||||
if f.Name == v3.FunctionNameAnomaly {
|
||||
value, ok := f.NamedArgs["z_score_threshold"]
|
||||
if ok {
|
||||
zScoreThreshold = value.(float64)
|
||||
} else {
|
||||
zScoreThreshold = 3
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
pastPeriodResult, ok := pastPeriodResultsMap[result.QueryName]
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
currentSeasonResult, ok := currentSeasonResultsMap[result.QueryName]
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
pastSeasonResult, ok := pastSeasonResultsMap[result.QueryName]
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
past2SeasonResult, ok := past2SeasonResultsMap[result.QueryName]
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
past3SeasonResult, ok := past3SeasonResultsMap[result.QueryName]
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
for _, series := range result.Series {
|
||||
stdDev := p.getStdDev(series)
|
||||
zap.L().Info("stdDev", zap.Float64("stdDev", stdDev), zap.Any("labels", series.Labels))
|
||||
|
||||
pastPeriodSeries := p.getMatchingSeries(pastPeriodResult, series)
|
||||
currentSeasonSeries := p.getMatchingSeries(currentSeasonResult, series)
|
||||
pastSeasonSeries := p.getMatchingSeries(pastSeasonResult, series)
|
||||
past2SeasonSeries := p.getMatchingSeries(past2SeasonResult, series)
|
||||
past3SeasonSeries := p.getMatchingSeries(past3SeasonResult, series)
|
||||
|
||||
prevSeriesAvg := p.getAvg(pastPeriodSeries)
|
||||
currentSeasonSeriesAvg := p.getAvg(currentSeasonSeries)
|
||||
pastSeasonSeriesAvg := p.getAvg(pastSeasonSeries)
|
||||
past2SeasonSeriesAvg := p.getAvg(past2SeasonSeries)
|
||||
past3SeasonSeriesAvg := p.getAvg(past3SeasonSeries)
|
||||
zap.L().Info("getAvg", zap.Float64("prevSeriesAvg", prevSeriesAvg), zap.Float64("currentSeasonSeriesAvg", currentSeasonSeriesAvg), zap.Float64("pastSeasonSeriesAvg", pastSeasonSeriesAvg), zap.Float64("past2SeasonSeriesAvg", past2SeasonSeriesAvg), zap.Float64("past3SeasonSeriesAvg", past3SeasonSeriesAvg), zap.Any("labels", series.Labels))
|
||||
|
||||
predictedSeries := p.getPredictedSeries(
|
||||
series,
|
||||
pastPeriodSeries,
|
||||
currentSeasonSeries,
|
||||
pastSeasonSeries,
|
||||
past2SeasonSeries,
|
||||
past3SeasonSeries,
|
||||
)
|
||||
result.PredictedSeries = append(result.PredictedSeries, predictedSeries)
|
||||
|
||||
upperBoundSeries, lowerBoundSeries := p.getBounds(
|
||||
series,
|
||||
predictedSeries,
|
||||
zScoreThreshold,
|
||||
)
|
||||
result.UpperBoundSeries = append(result.UpperBoundSeries, upperBoundSeries)
|
||||
result.LowerBoundSeries = append(result.LowerBoundSeries, lowerBoundSeries)
|
||||
|
||||
anomalyScoreSeries := p.getAnomalyScores(
|
||||
series,
|
||||
pastPeriodSeries,
|
||||
currentSeasonSeries,
|
||||
pastSeasonSeries,
|
||||
past2SeasonSeries,
|
||||
past3SeasonSeries,
|
||||
)
|
||||
result.AnomalyScores = append(result.AnomalyScores, anomalyScoreSeries)
|
||||
}
|
||||
}
|
||||
|
||||
results := make([]*v3.Result, 0, len(currentPeriodResultsMap))
|
||||
for _, result := range currentPeriodResultsMap {
|
||||
results = append(results, result)
|
||||
}
|
||||
|
||||
return &GetAnomaliesResponse{
|
||||
Results: results,
|
||||
}, nil
|
||||
}
|
||||
43
ee/query-service/anomaly/weekly.go
Normal file
@@ -0,0 +1,43 @@
|
||||
package anomaly
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
querierV2 "go.signoz.io/signoz/pkg/query-service/app/querier/v2"
|
||||
"go.signoz.io/signoz/pkg/query-service/app/queryBuilder"
|
||||
)
|
||||
|
||||
type WeeklyProvider struct {
|
||||
BaseSeasonalProvider
|
||||
}
|
||||
|
||||
var _ BaseProvider = (*WeeklyProvider)(nil)
|
||||
|
||||
func (wp *WeeklyProvider) GetBaseSeasonalProvider() *BaseSeasonalProvider {
|
||||
return &wp.BaseSeasonalProvider
|
||||
}
|
||||
|
||||
func NewWeeklyProvider(opts ...GenericProviderOption[*WeeklyProvider]) *WeeklyProvider {
|
||||
wp := &WeeklyProvider{
|
||||
BaseSeasonalProvider: BaseSeasonalProvider{},
|
||||
}
|
||||
|
||||
for _, opt := range opts {
|
||||
opt(wp)
|
||||
}
|
||||
|
||||
wp.querierV2 = querierV2.NewQuerier(querierV2.QuerierOptions{
|
||||
Reader: wp.reader,
|
||||
Cache: wp.cache,
|
||||
KeyGenerator: queryBuilder.NewKeyGenerator(),
|
||||
FluxInterval: wp.fluxInterval,
|
||||
FeatureLookup: wp.ff,
|
||||
})
|
||||
|
||||
return wp
|
||||
}
|
||||
|
||||
func (p *WeeklyProvider) GetAnomalies(ctx context.Context, req *GetAnomaliesRequest) (*GetAnomaliesResponse, error) {
|
||||
req.Seasonality = SeasonalityWeekly
|
||||
return p.getAnomalies(ctx, req)
|
||||
}
|
||||
@@ -38,7 +38,8 @@ type APIHandlerOptions struct {
|
||||
Cache cache.Cache
|
||||
Gateway *httputil.ReverseProxy
|
||||
// Querier Influx Interval
|
||||
FluxInterval time.Duration
|
||||
FluxInterval time.Duration
|
||||
UseLogsNewSchema bool
|
||||
}
|
||||
|
||||
type APIHandler struct {
|
||||
@@ -63,6 +64,7 @@ func NewAPIHandler(opts APIHandlerOptions) (*APIHandler, error) {
|
||||
LogsParsingPipelineController: opts.LogsParsingPipelineController,
|
||||
Cache: opts.Cache,
|
||||
FluxInterval: opts.FluxInterval,
|
||||
UseLogsNewSchema: opts.UseLogsNewSchema,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
@@ -175,6 +177,8 @@ func (ah *APIHandler) RegisterRoutes(router *mux.Router, am *baseapp.AuthMiddlew
|
||||
am.ViewAccess(ah.listLicensesV2)).
|
||||
Methods(http.MethodGet)
|
||||
|
||||
router.HandleFunc("/api/v4/query_range", am.ViewAccess(ah.queryRangeV4)).Methods(http.MethodPost)
|
||||
|
||||
// Gateway
|
||||
router.PathPrefix(gateway.RoutePrefix).HandlerFunc(am.AdminAccess(ah.ServeGatewayHTTP))
|
||||
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
"go.signoz.io/signoz/pkg/query-service/app/dashboards"
|
||||
@@ -29,6 +31,10 @@ func (ah *APIHandler) lockUnlockDashboard(w http.ResponseWriter, r *http.Request
|
||||
|
||||
// Get the dashboard UUID from the request
|
||||
uuid := mux.Vars(r)["uuid"]
|
||||
if strings.HasPrefix(uuid,"integration") {
|
||||
RespondError(w, &model.ApiError{Typ: model.ErrorForbidden, Err: errors.New("dashboards created by integrations cannot be unlocked")}, "You are not authorized to lock/unlock this dashboard")
|
||||
return
|
||||
}
|
||||
dashboard, err := dashboards.GetDashboard(r.Context(), uuid)
|
||||
if err != nil {
|
||||
RespondError(w, &model.ApiError{Typ: model.ErrorInternal, Err: err}, err.Error())
|
||||
|
||||
@@ -1,17 +1,48 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"go.signoz.io/signoz/ee/query-service/constants"
|
||||
basemodel "go.signoz.io/signoz/pkg/query-service/model"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
func (ah *APIHandler) getFeatureFlags(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
featureSet, err := ah.FF().GetFeatureFlags()
|
||||
if err != nil {
|
||||
ah.HandleError(w, err, http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
if constants.FetchFeatures == "true" {
|
||||
zap.L().Debug("fetching license")
|
||||
license, err := ah.LM().GetRepo().GetActiveLicense(ctx)
|
||||
if err != nil {
|
||||
zap.L().Error("failed to fetch license", zap.Error(err))
|
||||
} else if license == nil {
|
||||
zap.L().Debug("no active license found")
|
||||
} else {
|
||||
licenseKey := license.Key
|
||||
|
||||
zap.L().Debug("fetching zeus features")
|
||||
zeusFeatures, err := fetchZeusFeatures(constants.ZeusFeaturesURL, licenseKey)
|
||||
if err == nil {
|
||||
zap.L().Debug("fetched zeus features", zap.Any("features", zeusFeatures))
|
||||
// merge featureSet and zeusFeatures in featureSet with higher priority to zeusFeatures
|
||||
featureSet = MergeFeatureSets(zeusFeatures, featureSet)
|
||||
} else {
|
||||
zap.L().Error("failed to fetch zeus features", zap.Error(err))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ah.opts.PreferSpanMetrics {
|
||||
for idx := range featureSet {
|
||||
feature := &featureSet[idx]
|
||||
@@ -20,5 +51,96 @@ func (ah *APIHandler) getFeatureFlags(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ah.Respond(w, featureSet)
|
||||
}
|
||||
|
||||
// fetchZeusFeatures makes an HTTP GET request to the /zeusFeatures endpoint
|
||||
// and returns the FeatureSet.
|
||||
func fetchZeusFeatures(url, licenseKey string) (basemodel.FeatureSet, error) {
|
||||
// Check if the URL is empty
|
||||
if url == "" {
|
||||
return nil, fmt.Errorf("url is empty")
|
||||
}
|
||||
|
||||
// Check if the licenseKey is empty
|
||||
if licenseKey == "" {
|
||||
return nil, fmt.Errorf("licenseKey is empty")
|
||||
}
|
||||
|
||||
// Creating an HTTP client with a timeout for better control
|
||||
client := &http.Client{
|
||||
Timeout: 10 * time.Second,
|
||||
}
|
||||
// Creating a new GET request
|
||||
req, err := http.NewRequest("GET", url, nil)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create request: %w", err)
|
||||
}
|
||||
|
||||
// Setting the custom header
|
||||
req.Header.Set("X-Signoz-Cloud-Api-Key", licenseKey)
|
||||
|
||||
// Making the GET request
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to make GET request: %w", err)
|
||||
}
|
||||
defer func() {
|
||||
if resp != nil {
|
||||
resp.Body.Close()
|
||||
}
|
||||
}()
|
||||
|
||||
// Check for non-OK status code
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return nil, fmt.Errorf("%w: %d %s", errors.New("received non-OK HTTP status code"), resp.StatusCode, http.StatusText(resp.StatusCode))
|
||||
}
|
||||
|
||||
// Reading and decoding the response body
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to read response body: %w", err)
|
||||
}
|
||||
|
||||
var zeusResponse ZeusFeaturesResponse
|
||||
if err := json.Unmarshal(body, &zeusResponse); err != nil {
|
||||
return nil, fmt.Errorf("%w: %v", errors.New("failed to decode response body"), err)
|
||||
}
|
||||
|
||||
if zeusResponse.Status != "success" {
|
||||
return nil, fmt.Errorf("%w: %s", errors.New("failed to fetch zeus features"), zeusResponse.Status)
|
||||
}
|
||||
|
||||
return zeusResponse.Data, nil
|
||||
}
|
||||
|
||||
type ZeusFeaturesResponse struct {
|
||||
Status string `json:"status"`
|
||||
Data basemodel.FeatureSet `json:"data"`
|
||||
}
|
||||
|
||||
// MergeFeatureSets merges two FeatureSet arrays with precedence to zeusFeatures.
|
||||
func MergeFeatureSets(zeusFeatures, internalFeatures basemodel.FeatureSet) basemodel.FeatureSet {
|
||||
// Create a map to store the merged features
|
||||
featureMap := make(map[string]basemodel.Feature)
|
||||
|
||||
// Add all features from the otherFeatures set to the map
|
||||
for _, feature := range internalFeatures {
|
||||
featureMap[feature.Name] = feature
|
||||
}
|
||||
|
||||
// Add all features from the zeusFeatures set to the map
|
||||
// If a feature already exists (i.e., same name), the zeusFeature will overwrite it
|
||||
for _, feature := range zeusFeatures {
|
||||
featureMap[feature.Name] = feature
|
||||
}
|
||||
|
||||
// Convert the map back to a FeatureSet slice
|
||||
var mergedFeatures basemodel.FeatureSet
|
||||
for _, feature := range featureMap {
|
||||
mergedFeatures = append(mergedFeatures, feature)
|
||||
}
|
||||
|
||||
return mergedFeatures
|
||||
}
|
||||
|
||||
88
ee/query-service/app/api/featureFlags_test.go
Normal file
@@ -0,0 +1,88 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
basemodel "go.signoz.io/signoz/pkg/query-service/model"
|
||||
)
|
||||
|
||||
func TestMergeFeatureSets(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
zeusFeatures basemodel.FeatureSet
|
||||
internalFeatures basemodel.FeatureSet
|
||||
expected basemodel.FeatureSet
|
||||
}{
|
||||
{
|
||||
name: "empty zeusFeatures and internalFeatures",
|
||||
zeusFeatures: basemodel.FeatureSet{},
|
||||
internalFeatures: basemodel.FeatureSet{},
|
||||
expected: basemodel.FeatureSet{},
|
||||
},
|
||||
{
|
||||
name: "non-empty zeusFeatures and empty internalFeatures",
|
||||
zeusFeatures: basemodel.FeatureSet{
|
||||
{Name: "Feature1", Active: true},
|
||||
{Name: "Feature2", Active: false},
|
||||
},
|
||||
internalFeatures: basemodel.FeatureSet{},
|
||||
expected: basemodel.FeatureSet{
|
||||
{Name: "Feature1", Active: true},
|
||||
{Name: "Feature2", Active: false},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "empty zeusFeatures and non-empty internalFeatures",
|
||||
zeusFeatures: basemodel.FeatureSet{},
|
||||
internalFeatures: basemodel.FeatureSet{
|
||||
{Name: "Feature1", Active: true},
|
||||
{Name: "Feature2", Active: false},
|
||||
},
|
||||
expected: basemodel.FeatureSet{
|
||||
{Name: "Feature1", Active: true},
|
||||
{Name: "Feature2", Active: false},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "non-empty zeusFeatures and non-empty internalFeatures with no conflicts",
|
||||
zeusFeatures: basemodel.FeatureSet{
|
||||
{Name: "Feature1", Active: true},
|
||||
{Name: "Feature3", Active: false},
|
||||
},
|
||||
internalFeatures: basemodel.FeatureSet{
|
||||
{Name: "Feature2", Active: true},
|
||||
{Name: "Feature4", Active: false},
|
||||
},
|
||||
expected: basemodel.FeatureSet{
|
||||
{Name: "Feature1", Active: true},
|
||||
{Name: "Feature2", Active: true},
|
||||
{Name: "Feature3", Active: false},
|
||||
{Name: "Feature4", Active: false},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "non-empty zeusFeatures and non-empty internalFeatures with conflicts",
|
||||
zeusFeatures: basemodel.FeatureSet{
|
||||
{Name: "Feature1", Active: true},
|
||||
{Name: "Feature2", Active: false},
|
||||
},
|
||||
internalFeatures: basemodel.FeatureSet{
|
||||
{Name: "Feature1", Active: false},
|
||||
{Name: "Feature3", Active: true},
|
||||
},
|
||||
expected: basemodel.FeatureSet{
|
||||
{Name: "Feature1", Active: true},
|
||||
{Name: "Feature2", Active: false},
|
||||
{Name: "Feature3", Active: true},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
actual := MergeFeatureSets(test.zeusFeatures, test.internalFeatures)
|
||||
assert.ElementsMatch(t, test.expected, actual)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -9,7 +9,15 @@ import (
|
||||
|
||||
func (ah *APIHandler) ServeGatewayHTTP(rw http.ResponseWriter, req *http.Request) {
|
||||
ctx := req.Context()
|
||||
if !strings.HasPrefix(req.URL.Path, gateway.RoutePrefix+gateway.AllowedPrefix) {
|
||||
validPath := false
|
||||
for _, allowedPrefix := range gateway.AllowedPrefix {
|
||||
if strings.HasPrefix(req.URL.Path, gateway.RoutePrefix+allowedPrefix) {
|
||||
validPath = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !validPath {
|
||||
rw.WriteHeader(http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
|
||||
129
ee/query-service/app/api/queryrange.go
Normal file
@@ -0,0 +1,129 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
|
||||
"go.signoz.io/signoz/ee/query-service/anomaly"
|
||||
baseapp "go.signoz.io/signoz/pkg/query-service/app"
|
||||
"go.signoz.io/signoz/pkg/query-service/app/queryBuilder"
|
||||
"go.signoz.io/signoz/pkg/query-service/model"
|
||||
v3 "go.signoz.io/signoz/pkg/query-service/model/v3"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
func (aH *APIHandler) queryRangeV4(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
bodyBytes, _ := io.ReadAll(r.Body)
|
||||
r.Body = io.NopCloser(bytes.NewBuffer(bodyBytes))
|
||||
|
||||
queryRangeParams, apiErrorObj := baseapp.ParseQueryRangeParams(r)
|
||||
|
||||
if apiErrorObj != nil {
|
||||
zap.L().Error("error parsing metric query range params", zap.Error(apiErrorObj.Err))
|
||||
RespondError(w, apiErrorObj, nil)
|
||||
return
|
||||
}
|
||||
queryRangeParams.Version = "v4"
|
||||
|
||||
// add temporality for each metric
|
||||
temporalityErr := aH.PopulateTemporality(r.Context(), queryRangeParams)
|
||||
if temporalityErr != nil {
|
||||
zap.L().Error("Error while adding temporality for metrics", zap.Error(temporalityErr))
|
||||
RespondError(w, &model.ApiError{Typ: model.ErrorInternal, Err: temporalityErr}, nil)
|
||||
return
|
||||
}
|
||||
|
||||
anomalyQueryExists := false
|
||||
anomalyQuery := &v3.BuilderQuery{}
|
||||
if queryRangeParams.CompositeQuery.QueryType == v3.QueryTypeBuilder {
|
||||
for _, query := range queryRangeParams.CompositeQuery.BuilderQueries {
|
||||
for _, fn := range query.Functions {
|
||||
if fn.Name == v3.FunctionNameAnomaly {
|
||||
anomalyQueryExists = true
|
||||
anomalyQuery = query
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if anomalyQueryExists {
|
||||
// ensure all queries have metric data source, and there should be only one anomaly query
|
||||
for _, query := range queryRangeParams.CompositeQuery.BuilderQueries {
|
||||
// What is query.QueryName == query.Expression doing here?
|
||||
// In the current implementation, the way to recognize if a query is a formula is by
|
||||
// checking if the expression is the same as the query name. if the expression is different
|
||||
// then it is a formula. otherwise, it is simple builder query.
|
||||
if query.DataSource != v3.DataSourceMetrics && query.QueryName == query.Expression {
|
||||
RespondError(w, &model.ApiError{Typ: model.ErrorBadData, Err: fmt.Errorf("all queries must have metric data source")}, nil)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// get the threshold, and seasonality from the anomaly query
|
||||
var seasonality anomaly.Seasonality
|
||||
for _, fn := range anomalyQuery.Functions {
|
||||
if fn.Name == v3.FunctionNameAnomaly {
|
||||
seasonalityStr, ok := fn.NamedArgs["seasonality"].(string)
|
||||
if !ok {
|
||||
seasonalityStr = "daily"
|
||||
}
|
||||
if seasonalityStr == "weekly" {
|
||||
seasonality = anomaly.SeasonalityWeekly
|
||||
} else if seasonalityStr == "daily" {
|
||||
seasonality = anomaly.SeasonalityDaily
|
||||
} else {
|
||||
seasonality = anomaly.SeasonalityHourly
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
var provider anomaly.Provider
|
||||
switch seasonality {
|
||||
case anomaly.SeasonalityWeekly:
|
||||
provider = anomaly.NewWeeklyProvider(
|
||||
anomaly.WithCache[*anomaly.WeeklyProvider](aH.opts.Cache),
|
||||
anomaly.WithKeyGenerator[*anomaly.WeeklyProvider](queryBuilder.NewKeyGenerator()),
|
||||
anomaly.WithReader[*anomaly.WeeklyProvider](aH.opts.DataConnector),
|
||||
anomaly.WithFeatureLookup[*anomaly.WeeklyProvider](aH.opts.FeatureFlags),
|
||||
)
|
||||
case anomaly.SeasonalityDaily:
|
||||
provider = anomaly.NewDailyProvider(
|
||||
anomaly.WithCache[*anomaly.DailyProvider](aH.opts.Cache),
|
||||
anomaly.WithKeyGenerator[*anomaly.DailyProvider](queryBuilder.NewKeyGenerator()),
|
||||
anomaly.WithReader[*anomaly.DailyProvider](aH.opts.DataConnector),
|
||||
anomaly.WithFeatureLookup[*anomaly.DailyProvider](aH.opts.FeatureFlags),
|
||||
)
|
||||
case anomaly.SeasonalityHourly:
|
||||
provider = anomaly.NewHourlyProvider(
|
||||
anomaly.WithCache[*anomaly.HourlyProvider](aH.opts.Cache),
|
||||
anomaly.WithKeyGenerator[*anomaly.HourlyProvider](queryBuilder.NewKeyGenerator()),
|
||||
anomaly.WithReader[*anomaly.HourlyProvider](aH.opts.DataConnector),
|
||||
anomaly.WithFeatureLookup[*anomaly.HourlyProvider](aH.opts.FeatureFlags),
|
||||
)
|
||||
default:
|
||||
provider = anomaly.NewDailyProvider(
|
||||
anomaly.WithCache[*anomaly.DailyProvider](aH.opts.Cache),
|
||||
anomaly.WithKeyGenerator[*anomaly.DailyProvider](queryBuilder.NewKeyGenerator()),
|
||||
anomaly.WithReader[*anomaly.DailyProvider](aH.opts.DataConnector),
|
||||
anomaly.WithFeatureLookup[*anomaly.DailyProvider](aH.opts.FeatureFlags),
|
||||
)
|
||||
}
|
||||
anomalies, err := provider.GetAnomalies(r.Context(), &anomaly.GetAnomaliesRequest{Params: queryRangeParams})
|
||||
if err != nil {
|
||||
RespondError(w, &model.ApiError{Typ: model.ErrorInternal, Err: err}, nil)
|
||||
return
|
||||
}
|
||||
resp := v3.QueryRangeResponse{
|
||||
Result: anomalies.Results,
|
||||
ResultType: "anomaly",
|
||||
}
|
||||
aH.Respond(w, resp)
|
||||
} else {
|
||||
r.Body = io.NopCloser(bytes.NewBuffer(bodyBytes))
|
||||
aH.QueryRangeV4(w, r)
|
||||
}
|
||||
}
|
||||
@@ -1,401 +0,0 @@
|
||||
package db
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/md5"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"regexp"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"go.signoz.io/signoz/ee/query-service/model"
|
||||
baseconst "go.signoz.io/signoz/pkg/query-service/constants"
|
||||
basemodel "go.signoz.io/signoz/pkg/query-service/model"
|
||||
"go.signoz.io/signoz/pkg/query-service/utils"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
// GetMetricResultEE runs the query and returns list of time series
|
||||
func (r *ClickhouseReader) GetMetricResultEE(ctx context.Context, query string) ([]*basemodel.Series, string, error) {
|
||||
|
||||
defer utils.Elapsed("GetMetricResult", nil)()
|
||||
zap.L().Info("Executing metric result query: ", zap.String("query", query))
|
||||
|
||||
var hash string
|
||||
// If getSubTreeSpans function is used in the clickhouse query
|
||||
if strings.Contains(query, "getSubTreeSpans(") {
|
||||
var err error
|
||||
query, hash, err = r.getSubTreeSpansCustomFunction(ctx, query, hash)
|
||||
if err == fmt.Errorf("no spans found for the given query") {
|
||||
return nil, "", nil
|
||||
}
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
}
|
||||
|
||||
rows, err := r.conn.Query(ctx, query)
|
||||
if err != nil {
|
||||
zap.L().Error("Error in processing query", zap.Error(err))
|
||||
return nil, "", fmt.Errorf("error in processing query")
|
||||
}
|
||||
|
||||
var (
|
||||
columnTypes = rows.ColumnTypes()
|
||||
columnNames = rows.Columns()
|
||||
vars = make([]interface{}, len(columnTypes))
|
||||
)
|
||||
for i := range columnTypes {
|
||||
vars[i] = reflect.New(columnTypes[i].ScanType()).Interface()
|
||||
}
|
||||
// when group by is applied, each combination of cartesian product
|
||||
// of attributes is separate series. each item in metricPointsMap
|
||||
// represent a unique series.
|
||||
metricPointsMap := make(map[string][]basemodel.MetricPoint)
|
||||
// attribute key-value pairs for each group selection
|
||||
attributesMap := make(map[string]map[string]string)
|
||||
|
||||
defer rows.Close()
|
||||
for rows.Next() {
|
||||
if err := rows.Scan(vars...); err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
var groupBy []string
|
||||
var metricPoint basemodel.MetricPoint
|
||||
groupAttributes := make(map[string]string)
|
||||
// Assuming that the end result row contains a timestamp, value and option labels
|
||||
// Label key and value are both strings.
|
||||
for idx, v := range vars {
|
||||
colName := columnNames[idx]
|
||||
switch v := v.(type) {
|
||||
case *string:
|
||||
// special case for returning all labels
|
||||
if colName == "fullLabels" {
|
||||
var metric map[string]string
|
||||
err := json.Unmarshal([]byte(*v), &metric)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
for key, val := range metric {
|
||||
groupBy = append(groupBy, val)
|
||||
groupAttributes[key] = val
|
||||
}
|
||||
} else {
|
||||
groupBy = append(groupBy, *v)
|
||||
groupAttributes[colName] = *v
|
||||
}
|
||||
case *time.Time:
|
||||
metricPoint.Timestamp = v.UnixMilli()
|
||||
case *float64:
|
||||
metricPoint.Value = *v
|
||||
case **float64:
|
||||
// ch seems to return this type when column is derived from
|
||||
// SELECT count(*)/ SELECT count(*)
|
||||
floatVal := *v
|
||||
if floatVal != nil {
|
||||
metricPoint.Value = *floatVal
|
||||
}
|
||||
case *float32:
|
||||
float32Val := float32(*v)
|
||||
metricPoint.Value = float64(float32Val)
|
||||
case *uint8, *uint64, *uint16, *uint32:
|
||||
if _, ok := baseconst.ReservedColumnTargetAliases[colName]; ok {
|
||||
metricPoint.Value = float64(reflect.ValueOf(v).Elem().Uint())
|
||||
} else {
|
||||
groupBy = append(groupBy, fmt.Sprintf("%v", reflect.ValueOf(v).Elem().Uint()))
|
||||
groupAttributes[colName] = fmt.Sprintf("%v", reflect.ValueOf(v).Elem().Uint())
|
||||
}
|
||||
case *int8, *int16, *int32, *int64:
|
||||
if _, ok := baseconst.ReservedColumnTargetAliases[colName]; ok {
|
||||
metricPoint.Value = float64(reflect.ValueOf(v).Elem().Int())
|
||||
} else {
|
||||
groupBy = append(groupBy, fmt.Sprintf("%v", reflect.ValueOf(v).Elem().Int()))
|
||||
groupAttributes[colName] = fmt.Sprintf("%v", reflect.ValueOf(v).Elem().Int())
|
||||
}
|
||||
default:
|
||||
zap.L().Error("invalid var found in metric builder query result", zap.Any("var", v), zap.String("colName", colName))
|
||||
}
|
||||
}
|
||||
sort.Strings(groupBy)
|
||||
key := strings.Join(groupBy, "")
|
||||
attributesMap[key] = groupAttributes
|
||||
metricPointsMap[key] = append(metricPointsMap[key], metricPoint)
|
||||
}
|
||||
|
||||
var seriesList []*basemodel.Series
|
||||
for key := range metricPointsMap {
|
||||
points := metricPointsMap[key]
|
||||
// first point in each series could be invalid since the
|
||||
// aggregations are applied with point from prev series
|
||||
if len(points) != 0 && len(points) > 1 {
|
||||
points = points[1:]
|
||||
}
|
||||
attributes := attributesMap[key]
|
||||
series := basemodel.Series{Labels: attributes, Points: points}
|
||||
seriesList = append(seriesList, &series)
|
||||
}
|
||||
// err = r.conn.Exec(ctx, "DROP TEMPORARY TABLE IF EXISTS getSubTreeSpans"+hash)
|
||||
// if err != nil {
|
||||
// zap.L().Error("Error in dropping temporary table: ", err)
|
||||
// return nil, err
|
||||
// }
|
||||
if hash == "" {
|
||||
return seriesList, hash, nil
|
||||
} else {
|
||||
return seriesList, "getSubTreeSpans" + hash, nil
|
||||
}
|
||||
}
|
||||
|
||||
func (r *ClickhouseReader) getSubTreeSpansCustomFunction(ctx context.Context, query string, hash string) (string, string, error) {
|
||||
|
||||
zap.L().Debug("Executing getSubTreeSpans function")
|
||||
|
||||
// str1 := `select fromUnixTimestamp64Milli(intDiv( toUnixTimestamp64Milli ( timestamp ), 100) * 100) AS interval, toFloat64(count()) as count from (select timestamp, spanId, parentSpanId, durationNano from getSubTreeSpans(select * from signoz_traces.signoz_index_v2 where serviceName='frontend' and name='/driver.DriverService/FindNearest' and traceID='00000000000000004b0a863cb5ed7681') where name='FindDriverIDs' group by interval order by interval asc;`
|
||||
|
||||
// process the query to fetch subTree query
|
||||
var subtreeInput string
|
||||
query, subtreeInput, hash = processQuery(query, hash)
|
||||
|
||||
err := r.conn.Exec(ctx, "DROP TABLE IF EXISTS getSubTreeSpans"+hash)
|
||||
if err != nil {
|
||||
zap.L().Error("Error in dropping temporary table", zap.Error(err))
|
||||
return query, hash, err
|
||||
}
|
||||
|
||||
// Create temporary table to store the getSubTreeSpans() results
|
||||
zap.L().Debug("Creating temporary table getSubTreeSpans", zap.String("hash", hash))
|
||||
err = r.conn.Exec(ctx, "CREATE TABLE IF NOT EXISTS "+"getSubTreeSpans"+hash+" (timestamp DateTime64(9) CODEC(DoubleDelta, LZ4), traceID FixedString(32) CODEC(ZSTD(1)), spanID String CODEC(ZSTD(1)), parentSpanID String CODEC(ZSTD(1)), rootSpanID String CODEC(ZSTD(1)), serviceName LowCardinality(String) CODEC(ZSTD(1)), name LowCardinality(String) CODEC(ZSTD(1)), rootName LowCardinality(String) CODEC(ZSTD(1)), durationNano UInt64 CODEC(T64, ZSTD(1)), kind Int8 CODEC(T64, ZSTD(1)), tagMap Map(LowCardinality(String), String) CODEC(ZSTD(1)), events Array(String) CODEC(ZSTD(2))) ENGINE = MergeTree() ORDER BY (timestamp)")
|
||||
if err != nil {
|
||||
zap.L().Error("Error in creating temporary table", zap.Error(err))
|
||||
return query, hash, err
|
||||
}
|
||||
|
||||
var getSpansSubQueryDBResponses []model.GetSpansSubQueryDBResponse
|
||||
getSpansSubQuery := subtreeInput
|
||||
// Execute the subTree query
|
||||
zap.L().Debug("Executing subTree query", zap.String("query", getSpansSubQuery))
|
||||
err = r.conn.Select(ctx, &getSpansSubQueryDBResponses, getSpansSubQuery)
|
||||
|
||||
// zap.L().Info(getSpansSubQuery)
|
||||
|
||||
if err != nil {
|
||||
zap.L().Error("Error in processing sql query", zap.Error(err))
|
||||
return query, hash, fmt.Errorf("error in processing sql query")
|
||||
}
|
||||
|
||||
var searchScanResponses []basemodel.SearchSpanDBResponseItem
|
||||
|
||||
// TODO : @ankit: I think the algorithm does not need to assume that subtrees are from the same TraceID. We can take this as an improvement later.
|
||||
// Fetch all the spans from of same TraceID so that we can build subtree
|
||||
modelQuery := fmt.Sprintf("SELECT timestamp, traceID, model FROM %s.%s WHERE traceID=$1", r.TraceDB, r.SpansTable)
|
||||
|
||||
if len(getSpansSubQueryDBResponses) == 0 {
|
||||
return query, hash, fmt.Errorf("no spans found for the given query")
|
||||
}
|
||||
zap.L().Debug("Executing query to fetch all the spans from the same TraceID: ", zap.String("modelQuery", modelQuery))
|
||||
err = r.conn.Select(ctx, &searchScanResponses, modelQuery, getSpansSubQueryDBResponses[0].TraceID)
|
||||
|
||||
if err != nil {
|
||||
zap.L().Error("Error in processing sql query", zap.Error(err))
|
||||
return query, hash, fmt.Errorf("error in processing sql query")
|
||||
}
|
||||
|
||||
// Process model to fetch the spans
|
||||
zap.L().Debug("Processing model to fetch the spans")
|
||||
searchSpanResponses := []basemodel.SearchSpanResponseItem{}
|
||||
for _, item := range searchScanResponses {
|
||||
var jsonItem basemodel.SearchSpanResponseItem
|
||||
json.Unmarshal([]byte(item.Model), &jsonItem)
|
||||
jsonItem.TimeUnixNano = uint64(item.Timestamp.UnixNano())
|
||||
if jsonItem.Events == nil {
|
||||
jsonItem.Events = []string{}
|
||||
}
|
||||
searchSpanResponses = append(searchSpanResponses, jsonItem)
|
||||
}
|
||||
// Build the subtree and store all the subtree spans in temporary table getSubTreeSpans+hash
|
||||
// Use map to store pointer to the spans to avoid duplicates and save memory
|
||||
zap.L().Debug("Building the subtree to store all the subtree spans in temporary table getSubTreeSpans", zap.String("hash", hash))
|
||||
|
||||
treeSearchResponse, err := getSubTreeAlgorithm(searchSpanResponses, getSpansSubQueryDBResponses)
|
||||
if err != nil {
|
||||
zap.L().Error("Error in getSubTreeAlgorithm function", zap.Error(err))
|
||||
return query, hash, err
|
||||
}
|
||||
zap.L().Debug("Preparing batch to store subtree spans in temporary table getSubTreeSpans", zap.String("hash", hash))
|
||||
statement, err := r.conn.PrepareBatch(context.Background(), fmt.Sprintf("INSERT INTO getSubTreeSpans"+hash))
|
||||
if err != nil {
|
||||
zap.L().Error("Error in preparing batch statement", zap.Error(err))
|
||||
return query, hash, err
|
||||
}
|
||||
for _, span := range treeSearchResponse {
|
||||
var parentID string
|
||||
if len(span.References) > 0 && span.References[0].RefType == "CHILD_OF" {
|
||||
parentID = span.References[0].SpanId
|
||||
}
|
||||
err = statement.Append(
|
||||
time.Unix(0, int64(span.TimeUnixNano)),
|
||||
span.TraceID,
|
||||
span.SpanID,
|
||||
parentID,
|
||||
span.RootSpanID,
|
||||
span.ServiceName,
|
||||
span.Name,
|
||||
span.RootName,
|
||||
uint64(span.DurationNano),
|
||||
int8(span.Kind),
|
||||
span.TagMap,
|
||||
span.Events,
|
||||
)
|
||||
if err != nil {
|
||||
zap.L().Error("Error in processing sql query", zap.Error(err))
|
||||
return query, hash, err
|
||||
}
|
||||
}
|
||||
zap.L().Debug("Inserting the subtree spans in temporary table getSubTreeSpans", zap.String("hash", hash))
|
||||
err = statement.Send()
|
||||
if err != nil {
|
||||
zap.L().Error("Error in sending statement", zap.Error(err))
|
||||
return query, hash, err
|
||||
}
|
||||
return query, hash, nil
|
||||
}
|
||||
|
||||
//lint:ignore SA4009 return hash is feeded to the query
|
||||
func processQuery(query string, hash string) (string, string, string) {
|
||||
re3 := regexp.MustCompile(`getSubTreeSpans`)
|
||||
|
||||
submatchall3 := re3.FindAllStringIndex(query, -1)
|
||||
getSubtreeSpansMatchIndex := submatchall3[0][1]
|
||||
|
||||
query2countParenthesis := query[getSubtreeSpansMatchIndex:]
|
||||
|
||||
sqlCompleteIndex := 0
|
||||
countParenthesisImbalance := 0
|
||||
for i, char := range query2countParenthesis {
|
||||
|
||||
if string(char) == "(" {
|
||||
countParenthesisImbalance += 1
|
||||
}
|
||||
if string(char) == ")" {
|
||||
countParenthesisImbalance -= 1
|
||||
}
|
||||
if countParenthesisImbalance == 0 {
|
||||
sqlCompleteIndex = i
|
||||
break
|
||||
}
|
||||
}
|
||||
subtreeInput := query2countParenthesis[1:sqlCompleteIndex]
|
||||
|
||||
// hash the subtreeInput
|
||||
hmd5 := md5.Sum([]byte(subtreeInput))
|
||||
hash = fmt.Sprintf("%x", hmd5)
|
||||
|
||||
// Reformat the query to use the getSubTreeSpans function
|
||||
query = query[:getSubtreeSpansMatchIndex] + hash + " " + query2countParenthesis[sqlCompleteIndex+1:]
|
||||
return query, subtreeInput, hash
|
||||
}
|
||||
|
||||
// getSubTreeAlgorithm is an algorithm to build the subtrees of the spans and return the list of spans
|
||||
func getSubTreeAlgorithm(payload []basemodel.SearchSpanResponseItem, getSpansSubQueryDBResponses []model.GetSpansSubQueryDBResponse) (map[string]*basemodel.SearchSpanResponseItem, error) {
|
||||
|
||||
var spans []*model.SpanForTraceDetails
|
||||
for _, spanItem := range payload {
|
||||
var parentID string
|
||||
if len(spanItem.References) > 0 && spanItem.References[0].RefType == "CHILD_OF" {
|
||||
parentID = spanItem.References[0].SpanId
|
||||
}
|
||||
span := &model.SpanForTraceDetails{
|
||||
TimeUnixNano: spanItem.TimeUnixNano,
|
||||
SpanID: spanItem.SpanID,
|
||||
TraceID: spanItem.TraceID,
|
||||
ServiceName: spanItem.ServiceName,
|
||||
Name: spanItem.Name,
|
||||
Kind: spanItem.Kind,
|
||||
DurationNano: spanItem.DurationNano,
|
||||
TagMap: spanItem.TagMap,
|
||||
ParentID: parentID,
|
||||
Events: spanItem.Events,
|
||||
HasError: spanItem.HasError,
|
||||
}
|
||||
spans = append(spans, span)
|
||||
}
|
||||
|
||||
zap.L().Debug("Building Tree")
|
||||
roots, err := buildSpanTrees(&spans)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
searchSpansResult := make(map[string]*basemodel.SearchSpanResponseItem)
|
||||
// Every span which was fetched from getSubTree Input SQL query is considered root
|
||||
// For each root, get the subtree spans
|
||||
for _, getSpansSubQueryDBResponse := range getSpansSubQueryDBResponses {
|
||||
targetSpan := &model.SpanForTraceDetails{}
|
||||
// zap.L().Debug("Building tree for span id: " + getSpansSubQueryDBResponse.SpanID + " " + strconv.Itoa(i+1) + " of " + strconv.Itoa(len(getSpansSubQueryDBResponses)))
|
||||
// Search target span object in the tree
|
||||
for _, root := range roots {
|
||||
targetSpan, err = breadthFirstSearch(root, getSpansSubQueryDBResponse.SpanID)
|
||||
if targetSpan != nil {
|
||||
break
|
||||
}
|
||||
if err != nil {
|
||||
zap.L().Error("Error during BreadthFirstSearch()", zap.Error(err))
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if targetSpan == nil {
|
||||
return nil, nil
|
||||
}
|
||||
// Build subtree for the target span
|
||||
// Mark the target span as root by setting parent ID as empty string
|
||||
targetSpan.ParentID = ""
|
||||
preParents := []*model.SpanForTraceDetails{targetSpan}
|
||||
children := []*model.SpanForTraceDetails{}
|
||||
|
||||
// Get the subtree child spans
|
||||
for i := 0; len(preParents) != 0; i++ {
|
||||
parents := []*model.SpanForTraceDetails{}
|
||||
for _, parent := range preParents {
|
||||
children = append(children, parent.Children...)
|
||||
parents = append(parents, parent.Children...)
|
||||
}
|
||||
preParents = parents
|
||||
}
|
||||
|
||||
resultSpans := children
|
||||
// Add the target span to the result spans
|
||||
resultSpans = append(resultSpans, targetSpan)
|
||||
|
||||
for _, item := range resultSpans {
|
||||
references := []basemodel.OtelSpanRef{
|
||||
{
|
||||
TraceId: item.TraceID,
|
||||
SpanId: item.ParentID,
|
||||
RefType: "CHILD_OF",
|
||||
},
|
||||
}
|
||||
|
||||
if item.Events == nil {
|
||||
item.Events = []string{}
|
||||
}
|
||||
searchSpansResult[item.SpanID] = &basemodel.SearchSpanResponseItem{
|
||||
TimeUnixNano: item.TimeUnixNano,
|
||||
SpanID: item.SpanID,
|
||||
TraceID: item.TraceID,
|
||||
ServiceName: item.ServiceName,
|
||||
Name: item.Name,
|
||||
Kind: item.Kind,
|
||||
References: references,
|
||||
DurationNano: item.DurationNano,
|
||||
TagMap: item.TagMap,
|
||||
Events: item.Events,
|
||||
HasError: item.HasError,
|
||||
RootSpanID: getSpansSubQueryDBResponse.SpanID,
|
||||
RootName: targetSpan.Name,
|
||||
}
|
||||
}
|
||||
}
|
||||
return searchSpansResult, nil
|
||||
}
|
||||
@@ -25,8 +25,9 @@ func NewDataConnector(
|
||||
maxOpenConns int,
|
||||
dialTimeout time.Duration,
|
||||
cluster string,
|
||||
useLogsNewSchema bool,
|
||||
) *ClickhouseReader {
|
||||
ch := basechr.NewReader(localDB, promConfigPath, lm, maxIdleConns, maxOpenConns, dialTimeout, cluster)
|
||||
ch := basechr.NewReader(localDB, promConfigPath, lm, maxIdleConns, maxOpenConns, dialTimeout, cluster, useLogsNewSchema)
|
||||
return &ClickhouseReader{
|
||||
conn: ch.GetConn(),
|
||||
appdb: localDB,
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/http/httputil"
|
||||
_ "net/http/pprof" // http profiler
|
||||
"os"
|
||||
"regexp"
|
||||
@@ -27,7 +28,10 @@ import (
|
||||
"go.signoz.io/signoz/ee/query-service/dao"
|
||||
"go.signoz.io/signoz/ee/query-service/integrations/gateway"
|
||||
"go.signoz.io/signoz/ee/query-service/interfaces"
|
||||
"go.signoz.io/signoz/ee/query-service/rules"
|
||||
baseauth "go.signoz.io/signoz/pkg/query-service/auth"
|
||||
"go.signoz.io/signoz/pkg/query-service/migrate"
|
||||
"go.signoz.io/signoz/pkg/query-service/model"
|
||||
v3 "go.signoz.io/signoz/pkg/query-service/model/v3"
|
||||
|
||||
licensepkg "go.signoz.io/signoz/ee/query-service/license"
|
||||
@@ -41,6 +45,7 @@ import (
|
||||
"go.signoz.io/signoz/pkg/query-service/app/logparsingpipeline"
|
||||
"go.signoz.io/signoz/pkg/query-service/app/opamp"
|
||||
opAmpModel "go.signoz.io/signoz/pkg/query-service/app/opamp/model"
|
||||
"go.signoz.io/signoz/pkg/query-service/app/preferences"
|
||||
"go.signoz.io/signoz/pkg/query-service/cache"
|
||||
baseconst "go.signoz.io/signoz/pkg/query-service/constants"
|
||||
"go.signoz.io/signoz/pkg/query-service/healthcheck"
|
||||
@@ -48,7 +53,7 @@ import (
|
||||
baseint "go.signoz.io/signoz/pkg/query-service/interfaces"
|
||||
basemodel "go.signoz.io/signoz/pkg/query-service/model"
|
||||
pqle "go.signoz.io/signoz/pkg/query-service/pqlEngine"
|
||||
rules "go.signoz.io/signoz/pkg/query-service/rules"
|
||||
baserules "go.signoz.io/signoz/pkg/query-service/rules"
|
||||
"go.signoz.io/signoz/pkg/query-service/telemetry"
|
||||
"go.signoz.io/signoz/pkg/query-service/utils"
|
||||
"go.uber.org/zap"
|
||||
@@ -72,12 +77,13 @@ type ServerOptions struct {
|
||||
FluxInterval string
|
||||
Cluster string
|
||||
GatewayUrl string
|
||||
UseLogsNewSchema bool
|
||||
}
|
||||
|
||||
// Server runs HTTP api service
|
||||
type Server struct {
|
||||
serverOptions *ServerOptions
|
||||
ruleManager *rules.Manager
|
||||
ruleManager *baserules.Manager
|
||||
|
||||
// public http router
|
||||
httpConn net.Listener
|
||||
@@ -110,6 +116,10 @@ func NewServer(serverOptions *ServerOptions) (*Server, error) {
|
||||
|
||||
baseexplorer.InitWithDSN(baseconst.RELATIONAL_DATASOURCE_PATH)
|
||||
|
||||
if err := preferences.InitDB(baseconst.RELATIONAL_DATASOURCE_PATH); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
localDB, err := dashboards.InitDB(baseconst.RELATIONAL_DATASOURCE_PATH)
|
||||
|
||||
if err != nil {
|
||||
@@ -118,33 +128,13 @@ func NewServer(serverOptions *ServerOptions) (*Server, error) {
|
||||
|
||||
localDB.SetMaxOpenConns(10)
|
||||
|
||||
gatewayFeature := basemodel.Feature{
|
||||
Name: "GATEWAY",
|
||||
Active: false,
|
||||
Usage: 0,
|
||||
UsageLimit: -1,
|
||||
Route: "",
|
||||
}
|
||||
|
||||
//Activate this feature if the url is not empty
|
||||
var gatewayProxy *httputil.ReverseProxy
|
||||
if serverOptions.GatewayUrl == "" {
|
||||
gatewayFeature.Active = false
|
||||
gatewayProxy, err = gateway.NewNoopProxy()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
zap.L().Info("Enabling gateway feature flag ...")
|
||||
gatewayFeature.Active = true
|
||||
gatewayProxy, err = gateway.NewProxy(serverOptions.GatewayUrl, gateway.RoutePrefix)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
gatewayProxy, err := gateway.NewProxy(serverOptions.GatewayUrl, gateway.RoutePrefix)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// initiate license manager
|
||||
lm, err := licensepkg.StartManager("sqlite", localDB, gatewayFeature)
|
||||
lm, err := licensepkg.StartManager("sqlite", localDB)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -165,6 +155,7 @@ func NewServer(serverOptions *ServerOptions) (*Server, error) {
|
||||
serverOptions.MaxOpenConns,
|
||||
serverOptions.DialTimeout,
|
||||
serverOptions.Cluster,
|
||||
serverOptions.UseLogsNewSchema,
|
||||
)
|
||||
go qb.Start(readerReady)
|
||||
reader = qb
|
||||
@@ -179,6 +170,14 @@ func NewServer(serverOptions *ServerOptions) (*Server, error) {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
var c cache.Cache
|
||||
if serverOptions.CacheConfigPath != "" {
|
||||
cacheOpts, err := cache.LoadFromYAMLCacheConfigFile(serverOptions.CacheConfigPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
c = cache.NewCache(cacheOpts)
|
||||
}
|
||||
|
||||
<-readerReady
|
||||
rm, err := makeRulesManager(serverOptions.PromConfigPath,
|
||||
@@ -186,13 +185,23 @@ func NewServer(serverOptions *ServerOptions) (*Server, error) {
|
||||
serverOptions.RuleRepoURL,
|
||||
localDB,
|
||||
reader,
|
||||
c,
|
||||
serverOptions.DisableRules,
|
||||
lm)
|
||||
lm,
|
||||
serverOptions.UseLogsNewSchema,
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
go func() {
|
||||
err = migrate.ClickHouseMigrate(reader.GetConn(), serverOptions.Cluster)
|
||||
if err != nil {
|
||||
zap.L().Error("error while running clickhouse migrations", zap.Error(err))
|
||||
}
|
||||
}()
|
||||
|
||||
// initiate opamp
|
||||
_, err = opAmpModel.InitDB(localDB)
|
||||
if err != nil {
|
||||
@@ -237,15 +246,6 @@ func NewServer(serverOptions *ServerOptions) (*Server, error) {
|
||||
telemetry.GetInstance().SetReader(reader)
|
||||
telemetry.GetInstance().SetSaasOperator(constants.SaasSegmentKey)
|
||||
|
||||
var c cache.Cache
|
||||
if serverOptions.CacheConfigPath != "" {
|
||||
cacheOpts, err := cache.LoadFromYAMLCacheConfigFile(serverOptions.CacheConfigPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
c = cache.NewCache(cacheOpts)
|
||||
}
|
||||
|
||||
fluxInterval, err := time.ParseDuration(serverOptions.FluxInterval)
|
||||
|
||||
if err != nil {
|
||||
@@ -269,6 +269,7 @@ func NewServer(serverOptions *ServerOptions) (*Server, error) {
|
||||
Cache: c,
|
||||
FluxInterval: fluxInterval,
|
||||
Gateway: gatewayProxy,
|
||||
UseLogsNewSchema: serverOptions.UseLogsNewSchema,
|
||||
}
|
||||
|
||||
apiHandler, err := api.NewAPIHandler(apiOpts)
|
||||
@@ -323,7 +324,7 @@ func (s *Server) createPrivateServer(apiHandler *api.APIHandler) (*http.Server,
|
||||
// ip here for alert manager
|
||||
AllowedOrigins: []string{"*"},
|
||||
AllowedMethods: []string{"GET", "DELETE", "POST", "PUT", "PATCH"},
|
||||
AllowedHeaders: []string{"Accept", "Authorization", "Content-Type", "SIGNOZ-API-KEY"},
|
||||
AllowedHeaders: []string{"Accept", "Authorization", "Content-Type", "SIGNOZ-API-KEY", "X-SIGNOZ-QUERY-ID", "Sec-WebSocket-Protocol"},
|
||||
})
|
||||
|
||||
handler := c.Handler(r)
|
||||
@@ -340,7 +341,17 @@ func (s *Server) createPublicServer(apiHandler *api.APIHandler) (*http.Server, e
|
||||
|
||||
// add auth middleware
|
||||
getUserFromRequest := func(r *http.Request) (*basemodel.UserPayload, error) {
|
||||
return auth.GetUserFromRequest(r, apiHandler)
|
||||
user, err := auth.GetUserFromRequest(r, apiHandler)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if user.User.OrgId == "" {
|
||||
return nil, model.UnauthorizedError(errors.New("orgId is missing in the claims"))
|
||||
}
|
||||
|
||||
return user, nil
|
||||
}
|
||||
am := baseapp.NewAuthMiddleware(getUserFromRequest)
|
||||
|
||||
@@ -353,12 +364,15 @@ func (s *Server) createPublicServer(apiHandler *api.APIHandler) (*http.Server, e
|
||||
apiHandler.RegisterLogsRoutes(r, am)
|
||||
apiHandler.RegisterIntegrationRoutes(r, am)
|
||||
apiHandler.RegisterQueryRangeV3Routes(r, am)
|
||||
apiHandler.RegisterInfraMetricsRoutes(r, am)
|
||||
apiHandler.RegisterQueryRangeV4Routes(r, am)
|
||||
apiHandler.RegisterWebSocketPaths(r, am)
|
||||
apiHandler.RegisterMessagingQueuesRoutes(r, am)
|
||||
|
||||
c := cors.New(cors.Options{
|
||||
AllowedOrigins: []string{"*"},
|
||||
AllowedMethods: []string{"GET", "DELETE", "POST", "PUT", "PATCH", "OPTIONS"},
|
||||
AllowedHeaders: []string{"Accept", "Authorization", "Content-Type", "cache-control"},
|
||||
AllowedHeaders: []string{"Accept", "Authorization", "Content-Type", "cache-control", "X-SIGNOZ-QUERY-ID", "Sec-WebSocket-Protocol"},
|
||||
})
|
||||
|
||||
handler := c.Handler(r)
|
||||
@@ -370,6 +384,7 @@ func (s *Server) createPublicServer(apiHandler *api.APIHandler) (*http.Server, e
|
||||
}, nil
|
||||
}
|
||||
|
||||
// TODO(remove): Implemented at pkg/http/middleware/logging.go
|
||||
// loggingMiddleware is used for logging public api calls
|
||||
func loggingMiddleware(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
@@ -381,6 +396,7 @@ func loggingMiddleware(next http.Handler) http.Handler {
|
||||
})
|
||||
}
|
||||
|
||||
// TODO(remove): Implemented at pkg/http/middleware/logging.go
|
||||
// loggingMiddlewarePrivate is used for logging private api calls
|
||||
// from internal services like alert manager
|
||||
func loggingMiddlewarePrivate(next http.Handler) http.Handler {
|
||||
@@ -393,27 +409,41 @@ func loggingMiddlewarePrivate(next http.Handler) http.Handler {
|
||||
})
|
||||
}
|
||||
|
||||
// TODO(remove): Implemented at pkg/http/middleware/logging.go
|
||||
type loggingResponseWriter struct {
|
||||
http.ResponseWriter
|
||||
statusCode int
|
||||
}
|
||||
|
||||
// TODO(remove): Implemented at pkg/http/middleware/logging.go
|
||||
func NewLoggingResponseWriter(w http.ResponseWriter) *loggingResponseWriter {
|
||||
// WriteHeader(int) is not called if our response implicitly returns 200 OK, so
|
||||
// we default to that status code.
|
||||
return &loggingResponseWriter{w, http.StatusOK}
|
||||
}
|
||||
|
||||
// TODO(remove): Implemented at pkg/http/middleware/logging.go
|
||||
func (lrw *loggingResponseWriter) WriteHeader(code int) {
|
||||
lrw.statusCode = code
|
||||
lrw.ResponseWriter.WriteHeader(code)
|
||||
}
|
||||
|
||||
// TODO(remove): Implemented at pkg/http/middleware/logging.go
|
||||
// Flush implements the http.Flush interface.
|
||||
func (lrw *loggingResponseWriter) Flush() {
|
||||
lrw.ResponseWriter.(http.Flusher).Flush()
|
||||
}
|
||||
|
||||
// TODO(remove): Implemented at pkg/http/middleware/logging.go
|
||||
// Support websockets
|
||||
func (lrw *loggingResponseWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) {
|
||||
h, ok := lrw.ResponseWriter.(http.Hijacker)
|
||||
if !ok {
|
||||
return nil, nil, errors.New("hijack not supported")
|
||||
}
|
||||
return h.Hijack()
|
||||
}
|
||||
|
||||
func extractQueryRangeData(path string, r *http.Request) (map[string]interface{}, bool) {
|
||||
pathToExtractBodyFromV3 := "/api/v3/query_range"
|
||||
pathToExtractBodyFromV4 := "/api/v4/query_range"
|
||||
@@ -550,6 +580,7 @@ func (s *Server) analyticsMiddleware(next http.Handler) http.Handler {
|
||||
})
|
||||
}
|
||||
|
||||
// TODO(remove): Implemented at pkg/http/middleware/timeout.go
|
||||
func setTimeoutMiddleware(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
@@ -702,8 +733,10 @@ func makeRulesManager(
|
||||
ruleRepoURL string,
|
||||
db *sqlx.DB,
|
||||
ch baseint.Reader,
|
||||
cache cache.Cache,
|
||||
disableRules bool,
|
||||
fm baseint.FeatureLookup) (*rules.Manager, error) {
|
||||
fm baseint.FeatureLookup,
|
||||
useLogsNewSchema bool) (*baserules.Manager, error) {
|
||||
|
||||
// create engine
|
||||
pqle, err := pqle.FromConfigPath(promConfigPath)
|
||||
@@ -719,23 +752,25 @@ func makeRulesManager(
|
||||
}
|
||||
|
||||
// create manager opts
|
||||
managerOpts := &rules.ManagerOptions{
|
||||
managerOpts := &baserules.ManagerOptions{
|
||||
NotifierOpts: notifierOpts,
|
||||
Queriers: &rules.Queriers{
|
||||
PqlEngine: pqle,
|
||||
Ch: ch.GetConn(),
|
||||
},
|
||||
PqlEngine: pqle,
|
||||
RepoURL: ruleRepoURL,
|
||||
DBConn: db,
|
||||
Context: context.Background(),
|
||||
Logger: nil,
|
||||
Logger: zap.L(),
|
||||
DisableRules: disableRules,
|
||||
FeatureFlags: fm,
|
||||
Reader: ch,
|
||||
Cache: cache,
|
||||
EvalDelay: baseconst.GetEvalDelay(),
|
||||
|
||||
PrepareTaskFunc: rules.PrepareTaskFunc,
|
||||
UseLogsNewSchema: useLogsNewSchema,
|
||||
}
|
||||
|
||||
// create Manager
|
||||
manager, err := rules.NewManager(managerOpts)
|
||||
manager, err := baserules.NewManager(managerOpts)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("rule manager error: %v", err)
|
||||
}
|
||||
|
||||
@@ -11,8 +11,8 @@ const (
|
||||
var LicenseSignozIo = "https://license.signoz.io/api/v1"
|
||||
var LicenseAPIKey = GetOrDefaultEnv("SIGNOZ_LICENSE_API_KEY", "")
|
||||
var SaasSegmentKey = GetOrDefaultEnv("SIGNOZ_SAAS_SEGMENT_KEY", "")
|
||||
var SpanRenderLimitStr = GetOrDefaultEnv("SPAN_RENDER_LIMIT", "2500")
|
||||
var MaxSpansInTraceStr = GetOrDefaultEnv("MAX_SPANS_IN_TRACE", "250000")
|
||||
var FetchFeatures = GetOrDefaultEnv("FETCH_FEATURES", "false")
|
||||
var ZeusFeaturesURL = GetOrDefaultEnv("ZEUS_FEATURES_URL", "ZeusFeaturesURL")
|
||||
|
||||
func GetOrDefaultEnv(key string, fallback string) string {
|
||||
v := os.Getenv(key)
|
||||
|
||||
@@ -20,11 +20,14 @@ import (
|
||||
func (m *modelDao) createUserForSAMLRequest(ctx context.Context, email string) (*basemodel.User, basemodel.BaseApiError) {
|
||||
// get auth domain from email domain
|
||||
domain, apierr := m.GetDomainByEmail(ctx, email)
|
||||
|
||||
if apierr != nil {
|
||||
zap.L().Error("failed to get domain from email", zap.Error(apierr))
|
||||
return nil, model.InternalErrorStr("failed to get domain from email")
|
||||
}
|
||||
if domain == nil {
|
||||
zap.L().Error("email domain does not match any authenticated domain", zap.String("email", email))
|
||||
return nil, model.InternalErrorStr("email domain does not match any authenticated domain")
|
||||
}
|
||||
|
||||
hash, err := baseauth.PasswordHash(utils.GeneratePassowrd())
|
||||
if err != nil {
|
||||
|
||||
@@ -5,5 +5,5 @@ import (
|
||||
)
|
||||
|
||||
func NewNoopProxy() (*httputil.ReverseProxy, error) {
|
||||
return nil, nil
|
||||
return &httputil.ReverseProxy{}, nil
|
||||
}
|
||||
|
||||
@@ -8,9 +8,9 @@ import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
RoutePrefix string = "/api/gateway"
|
||||
AllowedPrefix string = "/v1/workspaces/me"
|
||||
var (
|
||||
RoutePrefix string = "/api/gateway"
|
||||
AllowedPrefix []string = []string{"/v1/workspaces/me", "/v2/profiles/me", "/v2/deployments/me"}
|
||||
)
|
||||
|
||||
type proxy struct {
|
||||
|
||||
@@ -147,7 +147,7 @@ func (lm *Manager) GetLicenses(ctx context.Context) (response []model.License, a
|
||||
for _, l := range licenses {
|
||||
l.ParsePlan()
|
||||
|
||||
if l.Key == lm.activeLicense.Key {
|
||||
if lm.activeLicense != nil && l.Key == lm.activeLicense.Key {
|
||||
l.IsCurrent = true
|
||||
}
|
||||
|
||||
|
||||
@@ -20,6 +20,8 @@ import (
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/credentials/insecure"
|
||||
|
||||
prommodel "github.com/prometheus/common/model"
|
||||
|
||||
zapotlpencoder "github.com/SigNoz/zap_otlp/zap_otlp_encoder"
|
||||
zapotlpsync "github.com/SigNoz/zap_otlp/zap_otlp_sync"
|
||||
|
||||
@@ -77,6 +79,10 @@ func initZapLog(enableQueryServiceLogOTLPExport bool) *zap.Logger {
|
||||
return logger
|
||||
}
|
||||
|
||||
func init() {
|
||||
prommodel.NameValidationScheme = prommodel.UTF8Validation
|
||||
}
|
||||
|
||||
func main() {
|
||||
var promConfigPath, skipTopLvlOpsPath string
|
||||
|
||||
@@ -87,6 +93,7 @@ func main() {
|
||||
var ruleRepoURL string
|
||||
var cluster string
|
||||
|
||||
var useLogsNewSchema bool
|
||||
var cacheConfigPath, fluxInterval string
|
||||
var enableQueryServiceLogOTLPExport bool
|
||||
var preferSpanMetrics bool
|
||||
@@ -96,6 +103,7 @@ func main() {
|
||||
var dialTimeout time.Duration
|
||||
var gatewayUrl string
|
||||
|
||||
flag.BoolVar(&useLogsNewSchema, "use-logs-new-schema", false, "use logs_v2 schema for logs")
|
||||
flag.StringVar(&promConfigPath, "config", "./config/prometheus.yml", "(prometheus config to read metrics)")
|
||||
flag.StringVar(&skipTopLvlOpsPath, "skip-top-level-ops", "", "(config file to skip top level operations)")
|
||||
flag.BoolVar(&disableRules, "rules.disable", false, "(disable rule evaluation)")
|
||||
@@ -134,6 +142,7 @@ func main() {
|
||||
FluxInterval: fluxInterval,
|
||||
Cluster: cluster,
|
||||
GatewayUrl: gatewayUrl,
|
||||
UseLogsNewSchema: useLogsNewSchema,
|
||||
}
|
||||
|
||||
// Read the jwt secret key
|
||||
|
||||
@@ -11,6 +11,8 @@ const Enterprise = "ENTERPRISE_PLAN"
|
||||
const DisableUpsell = "DISABLE_UPSELL"
|
||||
const Onboarding = "ONBOARDING"
|
||||
const ChatSupport = "CHAT_SUPPORT"
|
||||
const Gateway = "GATEWAY"
|
||||
const PremiumSupport = "PREMIUM_SUPPORT"
|
||||
|
||||
var BasicPlan = basemodel.FeatureSet{
|
||||
basemodel.Feature{
|
||||
@@ -111,6 +113,27 @@ var BasicPlan = basemodel.FeatureSet{
|
||||
UsageLimit: -1,
|
||||
Route: "",
|
||||
},
|
||||
basemodel.Feature{
|
||||
Name: Gateway,
|
||||
Active: false,
|
||||
Usage: 0,
|
||||
UsageLimit: -1,
|
||||
Route: "",
|
||||
},
|
||||
basemodel.Feature{
|
||||
Name: PremiumSupport,
|
||||
Active: false,
|
||||
Usage: 0,
|
||||
UsageLimit: -1,
|
||||
Route: "",
|
||||
},
|
||||
basemodel.Feature{
|
||||
Name: basemodel.AnomalyDetection,
|
||||
Active: false,
|
||||
Usage: 0,
|
||||
UsageLimit: -1,
|
||||
Route: "",
|
||||
},
|
||||
}
|
||||
|
||||
var ProPlan = basemodel.FeatureSet{
|
||||
@@ -205,6 +228,27 @@ var ProPlan = basemodel.FeatureSet{
|
||||
UsageLimit: -1,
|
||||
Route: "",
|
||||
},
|
||||
basemodel.Feature{
|
||||
Name: Gateway,
|
||||
Active: true,
|
||||
Usage: 0,
|
||||
UsageLimit: -1,
|
||||
Route: "",
|
||||
},
|
||||
basemodel.Feature{
|
||||
Name: PremiumSupport,
|
||||
Active: true,
|
||||
Usage: 0,
|
||||
UsageLimit: -1,
|
||||
Route: "",
|
||||
},
|
||||
basemodel.Feature{
|
||||
Name: basemodel.AnomalyDetection,
|
||||
Active: true,
|
||||
Usage: 0,
|
||||
UsageLimit: -1,
|
||||
Route: "",
|
||||
},
|
||||
}
|
||||
|
||||
var EnterprisePlan = basemodel.FeatureSet{
|
||||
@@ -313,4 +357,25 @@ var EnterprisePlan = basemodel.FeatureSet{
|
||||
UsageLimit: -1,
|
||||
Route: "",
|
||||
},
|
||||
basemodel.Feature{
|
||||
Name: Gateway,
|
||||
Active: true,
|
||||
Usage: 0,
|
||||
UsageLimit: -1,
|
||||
Route: "",
|
||||
},
|
||||
basemodel.Feature{
|
||||
Name: PremiumSupport,
|
||||
Active: true,
|
||||
Usage: 0,
|
||||
UsageLimit: -1,
|
||||
Route: "",
|
||||
},
|
||||
basemodel.Feature{
|
||||
Name: basemodel.AnomalyDetection,
|
||||
Active: true,
|
||||
Usage: 0,
|
||||
UsageLimit: -1,
|
||||
Route: "",
|
||||
},
|
||||
}
|
||||
|
||||
393
ee/query-service/rules/anomaly.go
Normal file
@@ -0,0 +1,393 @@
|
||||
package rules
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"math"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"go.uber.org/zap"
|
||||
|
||||
"go.signoz.io/signoz/ee/query-service/anomaly"
|
||||
"go.signoz.io/signoz/pkg/query-service/cache"
|
||||
"go.signoz.io/signoz/pkg/query-service/common"
|
||||
"go.signoz.io/signoz/pkg/query-service/model"
|
||||
|
||||
querierV2 "go.signoz.io/signoz/pkg/query-service/app/querier/v2"
|
||||
"go.signoz.io/signoz/pkg/query-service/app/queryBuilder"
|
||||
"go.signoz.io/signoz/pkg/query-service/interfaces"
|
||||
v3 "go.signoz.io/signoz/pkg/query-service/model/v3"
|
||||
"go.signoz.io/signoz/pkg/query-service/utils/labels"
|
||||
"go.signoz.io/signoz/pkg/query-service/utils/times"
|
||||
"go.signoz.io/signoz/pkg/query-service/utils/timestamp"
|
||||
|
||||
"go.signoz.io/signoz/pkg/query-service/formatter"
|
||||
|
||||
baserules "go.signoz.io/signoz/pkg/query-service/rules"
|
||||
|
||||
yaml "gopkg.in/yaml.v2"
|
||||
)
|
||||
|
||||
const (
|
||||
RuleTypeAnomaly = "anomaly_rule"
|
||||
)
|
||||
|
||||
type AnomalyRule struct {
|
||||
*baserules.BaseRule
|
||||
|
||||
mtx sync.Mutex
|
||||
|
||||
reader interfaces.Reader
|
||||
|
||||
// querierV2 is used for alerts created after the introduction of new metrics query builder
|
||||
querierV2 interfaces.Querier
|
||||
|
||||
provider anomaly.Provider
|
||||
|
||||
seasonality anomaly.Seasonality
|
||||
}
|
||||
|
||||
func NewAnomalyRule(
|
||||
id string,
|
||||
p *baserules.PostableRule,
|
||||
featureFlags interfaces.FeatureLookup,
|
||||
reader interfaces.Reader,
|
||||
cache cache.Cache,
|
||||
opts ...baserules.RuleOption,
|
||||
) (*AnomalyRule, error) {
|
||||
|
||||
zap.L().Info("creating new AnomalyRule", zap.String("id", id), zap.Any("opts", opts))
|
||||
|
||||
baseRule, err := baserules.NewBaseRule(id, p, reader, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
t := AnomalyRule{
|
||||
BaseRule: baseRule,
|
||||
}
|
||||
|
||||
switch strings.ToLower(p.RuleCondition.Seasonality) {
|
||||
case "hourly":
|
||||
t.seasonality = anomaly.SeasonalityHourly
|
||||
case "daily":
|
||||
t.seasonality = anomaly.SeasonalityDaily
|
||||
case "weekly":
|
||||
t.seasonality = anomaly.SeasonalityWeekly
|
||||
default:
|
||||
t.seasonality = anomaly.SeasonalityDaily
|
||||
}
|
||||
|
||||
zap.L().Info("using seasonality", zap.String("seasonality", t.seasonality.String()))
|
||||
|
||||
querierOptsV2 := querierV2.QuerierOptions{
|
||||
Reader: reader,
|
||||
Cache: cache,
|
||||
KeyGenerator: queryBuilder.NewKeyGenerator(),
|
||||
FeatureLookup: featureFlags,
|
||||
}
|
||||
|
||||
t.querierV2 = querierV2.NewQuerier(querierOptsV2)
|
||||
t.reader = reader
|
||||
if t.seasonality == anomaly.SeasonalityHourly {
|
||||
t.provider = anomaly.NewHourlyProvider(
|
||||
anomaly.WithCache[*anomaly.HourlyProvider](cache),
|
||||
anomaly.WithKeyGenerator[*anomaly.HourlyProvider](queryBuilder.NewKeyGenerator()),
|
||||
anomaly.WithReader[*anomaly.HourlyProvider](reader),
|
||||
anomaly.WithFeatureLookup[*anomaly.HourlyProvider](featureFlags),
|
||||
)
|
||||
} else if t.seasonality == anomaly.SeasonalityDaily {
|
||||
t.provider = anomaly.NewDailyProvider(
|
||||
anomaly.WithCache[*anomaly.DailyProvider](cache),
|
||||
anomaly.WithKeyGenerator[*anomaly.DailyProvider](queryBuilder.NewKeyGenerator()),
|
||||
anomaly.WithReader[*anomaly.DailyProvider](reader),
|
||||
anomaly.WithFeatureLookup[*anomaly.DailyProvider](featureFlags),
|
||||
)
|
||||
} else if t.seasonality == anomaly.SeasonalityWeekly {
|
||||
t.provider = anomaly.NewWeeklyProvider(
|
||||
anomaly.WithCache[*anomaly.WeeklyProvider](cache),
|
||||
anomaly.WithKeyGenerator[*anomaly.WeeklyProvider](queryBuilder.NewKeyGenerator()),
|
||||
anomaly.WithReader[*anomaly.WeeklyProvider](reader),
|
||||
anomaly.WithFeatureLookup[*anomaly.WeeklyProvider](featureFlags),
|
||||
)
|
||||
}
|
||||
return &t, nil
|
||||
}
|
||||
|
||||
func (r *AnomalyRule) Type() baserules.RuleType {
|
||||
return RuleTypeAnomaly
|
||||
}
|
||||
|
||||
func (r *AnomalyRule) prepareQueryRange(ts time.Time) (*v3.QueryRangeParamsV3, error) {
|
||||
|
||||
zap.L().Info("prepareQueryRange", zap.Int64("ts", ts.UnixMilli()), zap.Int64("evalWindow", r.EvalWindow().Milliseconds()), zap.Int64("evalDelay", r.EvalDelay().Milliseconds()))
|
||||
|
||||
start := ts.Add(-time.Duration(r.EvalWindow())).UnixMilli()
|
||||
end := ts.UnixMilli()
|
||||
|
||||
if r.EvalDelay() > 0 {
|
||||
start = start - int64(r.EvalDelay().Milliseconds())
|
||||
end = end - int64(r.EvalDelay().Milliseconds())
|
||||
}
|
||||
// round to minute otherwise we could potentially miss data
|
||||
start = start - (start % (60 * 1000))
|
||||
end = end - (end % (60 * 1000))
|
||||
|
||||
compositeQuery := r.Condition().CompositeQuery
|
||||
|
||||
if compositeQuery.PanelType != v3.PanelTypeGraph {
|
||||
compositeQuery.PanelType = v3.PanelTypeGraph
|
||||
}
|
||||
|
||||
// default mode
|
||||
return &v3.QueryRangeParamsV3{
|
||||
Start: start,
|
||||
End: end,
|
||||
Step: int64(math.Max(float64(common.MinAllowedStepInterval(start, end)), 60)),
|
||||
CompositeQuery: compositeQuery,
|
||||
Variables: make(map[string]interface{}, 0),
|
||||
NoCache: false,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (r *AnomalyRule) GetSelectedQuery() string {
|
||||
return r.Condition().GetSelectedQueryName()
|
||||
}
|
||||
|
||||
func (r *AnomalyRule) buildAndRunQuery(ctx context.Context, ts time.Time) (baserules.Vector, error) {
|
||||
|
||||
params, err := r.prepareQueryRange(ts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = r.PopulateTemporality(ctx, params)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("internal error while setting temporality")
|
||||
}
|
||||
|
||||
anomalies, err := r.provider.GetAnomalies(ctx, &anomaly.GetAnomaliesRequest{
|
||||
Params: params,
|
||||
Seasonality: r.seasonality,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var queryResult *v3.Result
|
||||
for _, result := range anomalies.Results {
|
||||
if result.QueryName == r.GetSelectedQuery() {
|
||||
queryResult = result
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
var resultVector baserules.Vector
|
||||
|
||||
scoresJSON, _ := json.Marshal(queryResult.AnomalyScores)
|
||||
zap.L().Info("anomaly scores", zap.String("scores", string(scoresJSON)))
|
||||
|
||||
for _, series := range queryResult.AnomalyScores {
|
||||
smpl, shouldAlert := r.ShouldAlert(*series)
|
||||
if shouldAlert {
|
||||
resultVector = append(resultVector, smpl)
|
||||
}
|
||||
}
|
||||
return resultVector, nil
|
||||
}
|
||||
|
||||
func (r *AnomalyRule) Eval(ctx context.Context, ts time.Time) (interface{}, error) {
|
||||
|
||||
prevState := r.State()
|
||||
|
||||
valueFormatter := formatter.FromUnit(r.Unit())
|
||||
res, err := r.buildAndRunQuery(ctx, ts)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
r.mtx.Lock()
|
||||
defer r.mtx.Unlock()
|
||||
|
||||
resultFPs := map[uint64]struct{}{}
|
||||
var alerts = make(map[uint64]*baserules.Alert, len(res))
|
||||
|
||||
for _, smpl := range res {
|
||||
l := make(map[string]string, len(smpl.Metric))
|
||||
for _, lbl := range smpl.Metric {
|
||||
l[lbl.Name] = lbl.Value
|
||||
}
|
||||
|
||||
value := valueFormatter.Format(smpl.V, r.Unit())
|
||||
threshold := valueFormatter.Format(r.TargetVal(), r.Unit())
|
||||
zap.L().Debug("Alert template data for rule", zap.String("name", r.Name()), zap.String("formatter", valueFormatter.Name()), zap.String("value", value), zap.String("threshold", threshold))
|
||||
|
||||
tmplData := baserules.AlertTemplateData(l, value, threshold)
|
||||
// Inject some convenience variables that are easier to remember for users
|
||||
// who are not used to Go's templating system.
|
||||
defs := "{{$labels := .Labels}}{{$value := .Value}}{{$threshold := .Threshold}}"
|
||||
|
||||
// utility function to apply go template on labels and annotations
|
||||
expand := func(text string) string {
|
||||
|
||||
tmpl := baserules.NewTemplateExpander(
|
||||
ctx,
|
||||
defs+text,
|
||||
"__alert_"+r.Name(),
|
||||
tmplData,
|
||||
times.Time(timestamp.FromTime(ts)),
|
||||
nil,
|
||||
)
|
||||
result, err := tmpl.Expand()
|
||||
if err != nil {
|
||||
result = fmt.Sprintf("<error expanding template: %s>", err)
|
||||
zap.L().Error("Expanding alert template failed", zap.Error(err), zap.Any("data", tmplData))
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
lb := labels.NewBuilder(smpl.Metric).Del(labels.MetricNameLabel).Del(labels.TemporalityLabel)
|
||||
resultLabels := labels.NewBuilder(smpl.Metric).Del(labels.MetricNameLabel).Del(labels.TemporalityLabel).Labels()
|
||||
|
||||
for name, value := range r.Labels().Map() {
|
||||
lb.Set(name, expand(value))
|
||||
}
|
||||
|
||||
lb.Set(labels.AlertNameLabel, r.Name())
|
||||
lb.Set(labels.AlertRuleIdLabel, r.ID())
|
||||
lb.Set(labels.RuleSourceLabel, r.GeneratorURL())
|
||||
|
||||
annotations := make(labels.Labels, 0, len(r.Annotations().Map()))
|
||||
for name, value := range r.Annotations().Map() {
|
||||
annotations = append(annotations, labels.Label{Name: name, Value: expand(value)})
|
||||
}
|
||||
if smpl.IsMissing {
|
||||
lb.Set(labels.AlertNameLabel, "[No data] "+r.Name())
|
||||
}
|
||||
|
||||
lbs := lb.Labels()
|
||||
h := lbs.Hash()
|
||||
resultFPs[h] = struct{}{}
|
||||
|
||||
if _, ok := alerts[h]; ok {
|
||||
zap.L().Error("the alert query returns duplicate records", zap.String("ruleid", r.ID()), zap.Any("alert", alerts[h]))
|
||||
err = fmt.Errorf("duplicate alert found, vector contains metrics with the same labelset after applying alert labels")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
alerts[h] = &baserules.Alert{
|
||||
Labels: lbs,
|
||||
QueryResultLables: resultLabels,
|
||||
Annotations: annotations,
|
||||
ActiveAt: ts,
|
||||
State: model.StatePending,
|
||||
Value: smpl.V,
|
||||
GeneratorURL: r.GeneratorURL(),
|
||||
Receivers: r.PreferredChannels(),
|
||||
Missing: smpl.IsMissing,
|
||||
}
|
||||
}
|
||||
|
||||
zap.L().Info("number of alerts found", zap.String("name", r.Name()), zap.Int("count", len(alerts)))
|
||||
|
||||
// alerts[h] is ready, add or update active list now
|
||||
for h, a := range alerts {
|
||||
// Check whether we already have alerting state for the identifying label set.
|
||||
// Update the last value and annotations if so, create a new alert entry otherwise.
|
||||
if alert, ok := r.Active[h]; ok && alert.State != model.StateInactive {
|
||||
|
||||
alert.Value = a.Value
|
||||
alert.Annotations = a.Annotations
|
||||
alert.Receivers = r.PreferredChannels()
|
||||
continue
|
||||
}
|
||||
|
||||
r.Active[h] = a
|
||||
}
|
||||
|
||||
itemsToAdd := []model.RuleStateHistory{}
|
||||
|
||||
// Check if any pending alerts should be removed or fire now. Write out alert timeseries.
|
||||
for fp, a := range r.Active {
|
||||
labelsJSON, err := json.Marshal(a.QueryResultLables)
|
||||
if err != nil {
|
||||
zap.L().Error("error marshaling labels", zap.Error(err), zap.Any("labels", a.Labels))
|
||||
}
|
||||
if _, ok := resultFPs[fp]; !ok {
|
||||
// If the alert was previously firing, keep it around for a given
|
||||
// retention time so it is reported as resolved to the AlertManager.
|
||||
if a.State == model.StatePending || (!a.ResolvedAt.IsZero() && ts.Sub(a.ResolvedAt) > baserules.ResolvedRetention) {
|
||||
delete(r.Active, fp)
|
||||
}
|
||||
if a.State != model.StateInactive {
|
||||
a.State = model.StateInactive
|
||||
a.ResolvedAt = ts
|
||||
itemsToAdd = append(itemsToAdd, model.RuleStateHistory{
|
||||
RuleID: r.ID(),
|
||||
RuleName: r.Name(),
|
||||
State: model.StateInactive,
|
||||
StateChanged: true,
|
||||
UnixMilli: ts.UnixMilli(),
|
||||
Labels: model.LabelsString(labelsJSON),
|
||||
Fingerprint: a.QueryResultLables.Hash(),
|
||||
Value: a.Value,
|
||||
})
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
if a.State == model.StatePending && ts.Sub(a.ActiveAt) >= r.HoldDuration() {
|
||||
a.State = model.StateFiring
|
||||
a.FiredAt = ts
|
||||
state := model.StateFiring
|
||||
if a.Missing {
|
||||
state = model.StateNoData
|
||||
}
|
||||
itemsToAdd = append(itemsToAdd, model.RuleStateHistory{
|
||||
RuleID: r.ID(),
|
||||
RuleName: r.Name(),
|
||||
State: state,
|
||||
StateChanged: true,
|
||||
UnixMilli: ts.UnixMilli(),
|
||||
Labels: model.LabelsString(labelsJSON),
|
||||
Fingerprint: a.QueryResultLables.Hash(),
|
||||
Value: a.Value,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
currentState := r.State()
|
||||
|
||||
overallStateChanged := currentState != prevState
|
||||
for idx, item := range itemsToAdd {
|
||||
item.OverallStateChanged = overallStateChanged
|
||||
item.OverallState = currentState
|
||||
itemsToAdd[idx] = item
|
||||
}
|
||||
|
||||
r.RecordRuleStateHistory(ctx, prevState, currentState, itemsToAdd)
|
||||
|
||||
return len(r.Active), nil
|
||||
}
|
||||
|
||||
func (r *AnomalyRule) String() string {
|
||||
|
||||
ar := baserules.PostableRule{
|
||||
AlertName: r.Name(),
|
||||
RuleCondition: r.Condition(),
|
||||
EvalWindow: baserules.Duration(r.EvalWindow()),
|
||||
Labels: r.Labels().Map(),
|
||||
Annotations: r.Annotations().Map(),
|
||||
PreferredChannels: r.PreferredChannels(),
|
||||
}
|
||||
|
||||
byt, err := yaml.Marshal(ar)
|
||||
if err != nil {
|
||||
return fmt.Sprintf("error marshaling alerting rule: %s", err.Error())
|
||||
}
|
||||
|
||||
return string(byt)
|
||||
}
|
||||
89
ee/query-service/rules/manager.go
Normal file
@@ -0,0 +1,89 @@
|
||||
package rules
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
baserules "go.signoz.io/signoz/pkg/query-service/rules"
|
||||
)
|
||||
|
||||
func PrepareTaskFunc(opts baserules.PrepareTaskOptions) (baserules.Task, error) {
|
||||
|
||||
rules := make([]baserules.Rule, 0)
|
||||
var task baserules.Task
|
||||
|
||||
ruleId := baserules.RuleIdFromTaskName(opts.TaskName)
|
||||
if opts.Rule.RuleType == baserules.RuleTypeThreshold {
|
||||
// create a threshold rule
|
||||
tr, err := baserules.NewThresholdRule(
|
||||
ruleId,
|
||||
opts.Rule,
|
||||
opts.FF,
|
||||
opts.Reader,
|
||||
opts.UseLogsNewSchema,
|
||||
baserules.WithEvalDelay(opts.ManagerOpts.EvalDelay),
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
return task, err
|
||||
}
|
||||
|
||||
rules = append(rules, tr)
|
||||
|
||||
// create ch rule task for evalution
|
||||
task = newTask(baserules.TaskTypeCh, opts.TaskName, time.Duration(opts.Rule.Frequency), rules, opts.ManagerOpts, opts.NotifyFunc, opts.RuleDB)
|
||||
|
||||
} else if opts.Rule.RuleType == baserules.RuleTypeProm {
|
||||
|
||||
// create promql rule
|
||||
pr, err := baserules.NewPromRule(
|
||||
ruleId,
|
||||
opts.Rule,
|
||||
opts.Logger,
|
||||
opts.Reader,
|
||||
opts.ManagerOpts.PqlEngine,
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
return task, err
|
||||
}
|
||||
|
||||
rules = append(rules, pr)
|
||||
|
||||
// create promql rule task for evalution
|
||||
task = newTask(baserules.TaskTypeProm, opts.TaskName, time.Duration(opts.Rule.Frequency), rules, opts.ManagerOpts, opts.NotifyFunc, opts.RuleDB)
|
||||
|
||||
} else if opts.Rule.RuleType == baserules.RuleTypeAnomaly {
|
||||
// create anomaly rule
|
||||
ar, err := NewAnomalyRule(
|
||||
ruleId,
|
||||
opts.Rule,
|
||||
opts.FF,
|
||||
opts.Reader,
|
||||
opts.Cache,
|
||||
baserules.WithEvalDelay(opts.ManagerOpts.EvalDelay),
|
||||
)
|
||||
if err != nil {
|
||||
return task, err
|
||||
}
|
||||
|
||||
rules = append(rules, ar)
|
||||
|
||||
// create anomaly rule task for evalution
|
||||
task = newTask(baserules.TaskTypeCh, opts.TaskName, time.Duration(opts.Rule.Frequency), rules, opts.ManagerOpts, opts.NotifyFunc, opts.RuleDB)
|
||||
|
||||
} else {
|
||||
return nil, fmt.Errorf("unsupported rule type %s. Supported types: %s, %s", opts.Rule.RuleType, baserules.RuleTypeProm, baserules.RuleTypeThreshold)
|
||||
}
|
||||
|
||||
return task, nil
|
||||
}
|
||||
|
||||
// newTask returns an appropriate group for
|
||||
// rule type
|
||||
func newTask(taskType baserules.TaskType, name string, frequency time.Duration, rules []baserules.Rule, opts *baserules.ManagerOptions, notify baserules.NotifyFunc, ruleDB baserules.RuleDB) baserules.Task {
|
||||
if taskType == baserules.TaskTypeCh {
|
||||
return baserules.NewRuleTask(name, "", frequency, rules, opts, notify, ruleDB)
|
||||
}
|
||||
return baserules.NewPromRuleTask(name, "", frequency, rules, opts, notify, ruleDB)
|
||||
}
|
||||
@@ -51,7 +51,7 @@
|
||||
"ansi-to-html": "0.7.2",
|
||||
"antd": "5.11.0",
|
||||
"antd-table-saveas-excel": "2.2.1",
|
||||
"axios": "1.6.4",
|
||||
"axios": "1.7.4",
|
||||
"babel-eslint": "^10.1.0",
|
||||
"babel-jest": "^29.6.4",
|
||||
"babel-loader": "9.1.3",
|
||||
@@ -68,7 +68,7 @@
|
||||
"css-loader": "5.0.0",
|
||||
"css-minimizer-webpack-plugin": "5.0.1",
|
||||
"dayjs": "^1.10.7",
|
||||
"dompurify": "3.0.0",
|
||||
"dompurify": "3.1.3",
|
||||
"dotenv": "8.2.0",
|
||||
"event-source-polyfill": "1.0.31",
|
||||
"eventemitter3": "5.0.1",
|
||||
@@ -88,7 +88,7 @@
|
||||
"lucide-react": "0.379.0",
|
||||
"mini-css-extract-plugin": "2.4.5",
|
||||
"papaparse": "5.4.1",
|
||||
"posthog-js": "1.142.1",
|
||||
"posthog-js": "1.160.3",
|
||||
"rc-tween-one": "3.0.6",
|
||||
"react": "18.2.0",
|
||||
"react-addons-update": "15.6.3",
|
||||
@@ -110,6 +110,8 @@
|
||||
"react-syntax-highlighter": "15.5.0",
|
||||
"react-use": "^17.3.2",
|
||||
"react-virtuoso": "4.0.3",
|
||||
"overlayscrollbars-react": "^0.5.6",
|
||||
"overlayscrollbars": "^2.8.1",
|
||||
"redux": "^4.0.5",
|
||||
"redux-thunk": "^2.3.0",
|
||||
"rehype-raw": "7.0.0",
|
||||
@@ -205,7 +207,6 @@
|
||||
"eslint-plugin-sonarjs": "^0.12.0",
|
||||
"husky": "^7.0.4",
|
||||
"is-ci": "^3.0.1",
|
||||
"jest-playwright-preset": "^1.7.2",
|
||||
"jest-styled-components": "^7.0.8",
|
||||
"lint-staged": "^12.5.0",
|
||||
"msw": "1.3.2",
|
||||
@@ -238,6 +239,7 @@
|
||||
"debug": "4.3.4",
|
||||
"semver": "7.5.4",
|
||||
"xml2js": "0.5.0",
|
||||
"phin": "^3.7.1"
|
||||
"phin": "^3.7.1",
|
||||
"body-parser": "1.20.3"
|
||||
}
|
||||
}
|
||||
|
||||
1
frontend/public/Icons/groupBy.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg width="14" height="14" fill="none" xmlns="http://www.w3.org/2000/svg"><g clip-path="url(#prefix__clip0_4344_1236)" stroke="#C0C1C3" stroke-width="1.167" stroke-linecap="round" stroke-linejoin="round"><path d="M4.667 1.167H2.333c-.644 0-1.166.522-1.166 1.166v2.334c0 .644.522 1.166 1.166 1.166h2.334c.644 0 1.166-.522 1.166-1.166V2.333c0-.644-.522-1.166-1.166-1.166zM8.167 1.167a1.17 1.17 0 011.166 1.166v2.334a1.17 1.17 0 01-1.166 1.166M11.667 1.167a1.17 1.17 0 011.166 1.166v2.334a1.17 1.17 0 01-1.166 1.166M5.833 10.5H2.917c-.992 0-1.75-.758-1.75-1.75v-.583"/><path d="M4.083 12.25l1.75-1.75-1.75-1.75M11.667 8.167H9.333c-.644 0-1.166.522-1.166 1.166v2.334c0 .644.522 1.166 1.166 1.166h2.334c.644 0 1.166-.522 1.166-1.166V9.333c0-.644-.522-1.166-1.166-1.166z"/></g><defs><clipPath id="prefix__clip0_4344_1236"><path fill="#fff" d="M0 0h14v14H0z"/></clipPath></defs></svg>
|
||||
|
After Width: | Height: | Size: 878 B |
1
frontend/public/Icons/solid-x-circle.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg width="14" height="14" fill="none" xmlns="http://www.w3.org/2000/svg"><g clip-path="url(#prefix__clip0_4062_7291)" stroke-width="1.167" stroke-linecap="round" stroke-linejoin="round"><path d="M7 12.833A5.833 5.833 0 107 1.167a5.833 5.833 0 000 11.666z" fill="#E5484D" stroke="#E5484D"/><path d="M8.75 5.25l-3.5 3.5M5.25 5.25l3.5 3.5" stroke="#121317"/></g><defs><clipPath id="prefix__clip0_4062_7291"><path fill="#fff" d="M0 0h14v14H0z"/></clipPath></defs></svg>
|
||||
|
After Width: | Height: | Size: 467 B |
BIN
frontend/public/Images/signoz-hero-image.webp
Normal file
|
After Width: | Height: | Size: 62 KiB |
10
frontend/public/Logos/hippa.svg
Normal file
|
After Width: | Height: | Size: 15 KiB |
30
frontend/public/Logos/signoz-brand-logo-new.svg
Normal file
@@ -0,0 +1,30 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 18 18" fill="none">
|
||||
<rect y="0.25" width="17.5" height="17.5" rx="3.5" fill="url(#paint0_radial_274_16499)"/>
|
||||
<g filter="url(#filter0_di_274_16499)">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M1.92383 8.98972L1.92392 8.98924L1.92413 8.98821L1.92462 8.98579L1.92593 8.97961C1.92695 8.9749 1.92827 8.96901 1.92993 8.96197C1.93325 8.94788 1.93793 8.9292 1.94429 8.9062C1.95702 8.8602 1.97646 8.79692 2.00515 8.71856C2.06254 8.56178 2.15683 8.34494 2.30807 8.08559C2.6111 7.56595 3.13965 6.88108 4.04917 6.16856C4.96329 5.45246 5.85086 5.06731 6.51337 4.861C6.84464 4.75784 7.12019 4.69922 7.3156 4.66621C7.41335 4.6497 7.49117 4.63958 7.54605 4.63349C7.5735 4.63045 7.59522 4.62841 7.61085 4.62709C7.61866 4.62643 7.62495 4.62595 7.62966 4.62561L7.63556 4.6252L7.63761 4.62507L7.63876 4.625C7.63876 4.625 7.63906 4.62498 7.66199 5.01301C7.68491 5.40105 7.68518 5.40103 7.68518 5.40103L7.68483 5.40106C7.68326 5.40117 7.68017 5.40141 7.67559 5.40179C7.66643 5.40257 7.65136 5.40396 7.63073 5.40625C7.58948 5.41082 7.52607 5.41898 7.44345 5.43293C7.30197 5.45683 7.10452 5.49768 6.86568 5.56652C6.85832 5.56899 6.85091 5.57151 6.84345 5.57406C6.36305 5.73839 5.67696 6.05963 4.87486 6.68728C4.07477 7.31337 3.62509 7.90371 3.37636 8.33106C3.25185 8.54497 3.1773 8.71874 3.13432 8.83664C3.11283 8.89561 3.09922 8.94064 3.09121 8.96977C3.08746 8.98339 3.08494 8.99353 3.08341 9C3.08494 9.00647 3.08746 9.01661 3.09121 9.03023C3.09922 9.05936 3.11283 9.10439 3.13432 9.16336C3.1773 9.28126 3.25185 9.45503 3.37636 9.66894C3.62509 10.0963 4.07477 10.6866 4.87486 11.3127C5.67696 11.9404 6.36305 12.2616 6.84345 12.4259C6.85091 12.4285 6.85832 12.431 6.86568 12.4335C7.10452 12.5023 7.30197 12.5432 7.44345 12.5671C7.52607 12.581 7.58948 12.5892 7.63073 12.5938C7.65136 12.596 7.66643 12.5974 7.67559 12.5982C7.68017 12.5986 7.68326 12.5988 7.68483 12.5989L7.68518 12.599C7.68518 12.599 7.68491 12.599 7.66199 12.987C7.63906 13.375 7.63876 13.375 7.63876 13.375L7.63841 13.375L7.63761 13.3749L7.63556 13.3748L7.62966 13.3744C7.62495 13.3741 7.61866 13.3736 7.61085 13.3729C7.59522 13.3716 7.5735 13.3696 7.54605 13.3665C7.49117 13.3604 7.41335 13.3503 7.3156 13.3338C7.12019 13.3008 6.84464 13.2422 6.51337 13.139C5.85086 12.9327 4.96329 12.5475 4.04917 11.8314C3.13965 11.1189 2.6111 10.434 2.30807 9.91441C2.15683 9.65506 2.06254 9.43822 2.00515 9.28144C1.97646 9.20308 1.95702 9.1398 1.94429 9.0938C1.93793 9.0708 1.93325 9.05212 1.92993 9.03803C1.92827 9.03099 1.92695 9.0251 1.92593 9.02039L1.92462 9.01421L1.92413 9.01179L1.92392 9.01076L1.92383 9.01028V8.98972Z" fill="white"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M15.5738 8.98972L15.5737 8.98924L15.5735 8.98821L15.573 8.98579L15.5717 8.97961C15.5707 8.9749 15.5694 8.96901 15.5677 8.96197C15.5644 8.94788 15.5597 8.9292 15.5534 8.9062C15.5406 8.8602 15.5212 8.79692 15.4925 8.71856C15.4351 8.56178 15.3408 8.34494 15.1896 8.08559C14.8866 7.56595 14.358 6.88108 13.4485 6.16856C12.5344 5.45246 11.6468 5.06731 10.9843 4.861C10.653 4.75784 10.3775 4.69922 10.1821 4.66621C10.0843 4.6497 10.0065 4.63958 9.9516 4.63349C9.92416 4.63045 9.90243 4.62841 9.88681 4.62709C9.879 4.62643 9.87271 4.62595 9.86799 4.62561L9.8621 4.6252L9.86004 4.62507L9.8589 4.625C9.8589 4.625 9.85859 4.62498 9.83567 5.01301C9.81275 5.40105 9.81248 5.40103 9.81248 5.40103L9.81282 5.40106C9.81439 5.40117 9.81749 5.40141 9.82207 5.40179C9.83122 5.40257 9.8463 5.40396 9.86692 5.40625C9.90818 5.41082 9.97158 5.41898 10.0542 5.43293C10.1957 5.45683 10.3931 5.49768 10.632 5.56652C10.6393 5.56899 10.6467 5.57151 10.6542 5.57406C11.1346 5.73839 11.8207 6.05963 12.6228 6.68728C13.4229 7.31337 13.8726 7.90371 14.1213 8.33106C14.2458 8.54497 14.3204 8.71874 14.3633 8.83664C14.3848 8.89561 14.3984 8.94064 14.4064 8.96977C14.4102 8.98339 14.4127 8.99353 14.4142 9C14.4127 9.00647 14.4102 9.01661 14.4064 9.03023C14.3984 9.05936 14.3848 9.10439 14.3633 9.16336C14.3204 9.28126 14.2458 9.45503 14.1213 9.66894C13.8726 10.0963 13.4229 10.6866 12.6228 11.3127C11.8207 11.9404 11.1346 12.2616 10.6542 12.4259C10.6467 12.4285 10.6393 12.431 10.632 12.4335C10.3931 12.5023 10.1957 12.5432 10.0542 12.5671C9.97158 12.581 9.90818 12.5892 9.86692 12.5938C9.8463 12.596 9.83122 12.5974 9.82207 12.5982C9.81749 12.5986 9.81439 12.5988 9.81282 12.5989L9.81248 12.599C9.81248 12.599 9.81275 12.599 9.83567 12.987C9.85859 13.375 9.8589 13.375 9.8589 13.375L9.85924 13.375L9.86004 13.3749L9.8621 13.3748L9.86799 13.3744C9.87271 13.3741 9.879 13.3736 9.88681 13.3729C9.90243 13.3716 9.92416 13.3696 9.9516 13.3665C10.0065 13.3604 10.0843 13.3503 10.1821 13.3338C10.3775 13.3008 10.653 13.2422 10.9843 13.139C11.6468 12.9327 12.5344 12.5475 13.4485 11.8314C14.358 11.1189 14.8866 10.434 15.1896 9.91441C15.3408 9.65506 15.4351 9.43822 15.4925 9.28144C15.5212 9.20308 15.5406 9.1398 15.5534 9.0938C15.5597 9.0708 15.5644 9.05212 15.5677 9.03803C15.5694 9.03099 15.5707 9.0251 15.5717 9.02039L15.573 9.01421L15.5735 9.01179L15.5737 9.01076L15.5738 9.01028V8.98972Z" fill="white"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M11.9587 8.99965C11.9587 10.7227 10.5719 12.1194 8.86125 12.1194C7.15057 12.1194 5.76379 10.7227 5.76379 8.99965C5.76379 7.27663 7.15057 5.87985 8.86125 5.87985C10.5719 5.87985 11.9587 7.27663 11.9587 8.99965ZM8.08689 7.24476C8.08689 7.24476 7.7147 7.68363 7.60291 8.02471C7.53083 8.24463 7.50611 8.60967 7.50611 8.60967H6.53816C6.53816 8.60967 6.53816 8.31719 6.73175 7.82972C6.92534 7.34225 7.11893 7.24476 7.11893 7.24476H8.08689ZM7.60291 9.97458C7.7147 10.3157 8.08689 10.7545 8.08689 10.7545H7.11893C7.11893 10.7545 6.92534 10.657 6.73175 10.1696C6.53816 9.6821 6.53816 9.38962 6.53816 9.38962H7.50611C7.50611 9.38962 7.53083 9.75466 7.60291 9.97458Z" fill="white"/>
|
||||
</g>
|
||||
<defs>
|
||||
<filter id="filter0_di_274_16499" x="0.873828" y="4.275" width="15.7504" height="10.85" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
|
||||
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
|
||||
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
|
||||
<feOffset dy="0.7"/>
|
||||
<feGaussianBlur stdDeviation="0.525"/>
|
||||
<feComposite in2="hardAlpha" operator="out"/>
|
||||
<feColorMatrix type="matrix" values="0 0 0 0 0.368384 0 0 0 0 0.0623777 0 0 0 0 0.0623777 0 0 0 0.25 0"/>
|
||||
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_274_16499"/>
|
||||
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_274_16499" result="shape"/>
|
||||
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
|
||||
<feOffset dy="0.7"/>
|
||||
<feGaussianBlur stdDeviation="0.525"/>
|
||||
<feComposite in2="hardAlpha" operator="arithmetic" k2="-1" k3="1"/>
|
||||
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.06 0"/>
|
||||
<feBlend mode="normal" in2="shape" result="effect2_innerShadow_274_16499"/>
|
||||
</filter>
|
||||
<radialGradient id="paint0_radial_274_16499" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(8.75 9) rotate(45.6903) scale(10.2715)">
|
||||
<stop offset="0.329632" stop-color="#FF5E19"/>
|
||||
<stop offset="1" stop-color="#FF2929"/>
|
||||
</radialGradient>
|
||||
</defs>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 7.2 KiB |
@@ -1,11 +1,7 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g clip-path="url(#clip0_2048_2251)">
|
||||
<path opacity="0.9" d="M8.02226 15.9866C3.56539 15.9866 -6.10352e-05 12.4896 -6.10352e-05 8.11832C-6.10352e-05 3.79075 3.56539 0.25 8.02226 0.25H13.0584C14.7075 0.25 15.9999 1.56139 15.9999 3.13506V8.11832C15.9999 12.4896 12.4345 15.9866 8.02226 15.9866Z" fill="#F25733"/>
|
||||
<path d="M7.95919 4.71207C4.63025 4.71207 2.75514 7.46868 2.67693 7.58603C2.48413 7.87508 2.48413 8.24888 2.67707 8.53816C2.75514 8.65528 4.63025 11.4119 7.95919 11.4119C11.2881 11.4119 13.1633 8.65528 13.2414 8.53792C13.4342 8.24888 13.4342 7.87508 13.2413 7.58582C13.1632 7.46868 11.2881 4.71207 7.95919 4.71207ZM3.13771 8.23088C3.06925 8.12832 3.06925 7.99571 3.13771 7.89307C3.20059 7.79867 4.53564 5.83764 6.92256 5.36723C5.84092 5.78476 5.07127 6.83485 5.07127 8.062C5.07127 9.28912 5.84092 10.3392 6.92256 10.7567C4.53564 10.2863 3.20059 8.32528 3.13771 8.23088ZM6.62838 8.062C6.62838 8.21488 6.50443 8.3388 6.35151 8.3388C6.19859 8.3388 6.07465 8.21488 6.07465 8.062C6.07465 7.02287 6.92003 6.17748 7.95916 6.17748C8.11207 6.17748 8.23599 6.30141 8.23599 6.45434C8.23599 6.60727 8.11207 6.73119 7.95916 6.73119C7.22535 6.73119 6.62838 7.32815 6.62838 8.062ZM7.95919 8.73504C7.58803 8.73504 7.2861 8.43312 7.2861 8.062C7.2861 7.69085 7.58803 7.3889 7.95919 7.3889C8.33039 7.3889 8.63231 7.69083 8.63231 8.062C8.63231 8.43312 8.33039 8.73504 7.95919 8.73504ZM12.7806 8.23088C12.7178 8.32528 11.3827 10.2863 8.99583 10.7567C10.0775 10.3392 10.8471 9.28912 10.8471 8.062C10.8471 6.83487 10.0775 5.78477 8.99583 5.36724C11.3827 5.83768 12.7178 7.7987 12.7806 7.89307C12.8491 7.99571 12.8491 8.12832 12.7806 8.23088Z" fill="#F9F2F9"/>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0_2048_2251">
|
||||
<rect width="16" height="16" fill="white"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100" fill="none"><rect width="100" height="100" fill="url(#a)" rx="20"/><g fill="#fff" fill-rule="evenodd" clip-rule="evenodd" filter="url(#b)"><path d="M11 49.941v-.003l.002-.005.003-.014.007-.035a8.37 8.37 0 0 1 .105-.42c.073-.263.184-.624.348-1.072.328-.896.866-2.135 1.73-3.617 1.732-2.97 4.753-6.883 9.95-10.955 5.223-4.092 10.295-6.293 14.08-7.471a35.328 35.328 0 0 1 4.585-1.114 23.628 23.628 0 0 1 1.687-.223 9.17 9.17 0 0 1 .108-.009l.034-.002h.011l.007-.001s.002 0 .133 2.217c.13 2.218.132 2.218.132 2.218h-.002l-.053.004a19.098 19.098 0 0 0-1.326.178c-.809.136-1.937.37-3.302.763l-.127.043c-2.745.94-6.666 2.775-11.249 6.362-4.572 3.577-7.142 6.95-8.563 9.393-.711 1.222-1.137 2.215-1.383 2.889a9.995 9.995 0 0 0-.29.933c.008.037.022.095.044.173.046.166.123.423.246.76.246.674.672 1.667 1.383 2.89 1.421 2.441 3.991 5.815 8.563 9.392 4.584 3.587 8.504 5.423 11.25 6.362l.126.043c1.365.393 2.493.627 3.302.763a19.098 19.098 0 0 0 1.326.178l.053.004h.002s-.002 0-.133 2.218C43.66 75 43.657 75 43.657 75h-.007l-.011-.001-.034-.002a9.17 9.17 0 0 1-.478-.046 23.628 23.628 0 0 1-1.317-.186 35.328 35.328 0 0 1-4.584-1.114c-3.786-1.178-8.858-3.38-14.081-7.471-5.197-4.072-8.218-7.985-9.95-10.955-.864-1.482-1.402-2.72-1.73-3.617-.164-.448-.275-.81-.348-1.072a8.37 8.37 0 0 1-.105-.42l-.007-.035-.003-.014-.002-.005v-.121Zm78 0v-.003l-.002-.005-.002-.014-.008-.035a8.532 8.532 0 0 0-.105-.42 14.049 14.049 0 0 0-.348-1.072c-.328-.896-.866-2.135-1.73-3.617-1.732-2.97-4.753-6.883-9.95-10.955-5.223-4.092-10.295-6.293-14.08-7.471a35.328 35.328 0 0 0-4.585-1.114 23.628 23.628 0 0 0-1.687-.223 9.17 9.17 0 0 0-.108-.009l-.034-.002h-.011L56.343 25s-.002 0-.133 2.217c-.13 2.218-.132 2.218-.132 2.218h.002l.053.004a19.098 19.098 0 0 1 1.326.178c.809.136 1.937.37 3.302.763l.127.043c2.745.94 6.666 2.775 11.249 6.362 4.572 3.577 7.141 6.95 8.563 9.393.711 1.222 1.137 2.215 1.383 2.889a9.995 9.995 0 0 1 .29.933 9.995 9.995 0 0 1-.29.934c-.246.673-.672 1.666-1.383 2.888-1.422 2.442-3.991 5.816-8.563 9.393-4.584 3.587-8.504 5.423-11.25 6.362l-.126.043a30.108 30.108 0 0 1-3.302.763 19.098 19.098 0 0 1-1.326.178l-.053.004h-.002s.002 0 .133 2.218C56.34 75 56.343 75 56.343 75h.007l.011-.001.034-.002a9.17 9.17 0 0 0 .478-.046c.314-.034.758-.092 1.317-.186a35.328 35.328 0 0 0 4.584-1.114c3.786-1.178 8.858-3.38 14.081-7.471 5.197-4.072 8.218-7.985 9.95-10.955.864-1.482 1.402-2.72 1.73-3.617.164-.448.275-.81.348-1.072a8.532 8.532 0 0 0 .105-.42l.008-.035.002-.014.001-.005.001-.003v-.118Z"/><path d="M68.342 49.998c0 9.846-7.924 17.827-17.7 17.827-9.775 0-17.7-7.981-17.7-17.827 0-9.846 7.925-17.827 17.7-17.827 9.776 0 17.7 7.981 17.7 17.827ZM46.218 39.97s-2.127 2.508-2.766 4.457c-.412 1.257-.553 3.343-.553 3.343h-5.531s0-1.672 1.106-4.457c1.106-2.786 2.212-3.343 2.212-3.343h5.532Zm-2.766 15.6c.639 1.949 2.766 4.457 2.766 4.457h-5.532s-1.106-.557-2.212-3.343c-1.106-2.785-1.106-4.457-1.106-4.457h5.53s.142 2.086.554 3.343Z"/></g><defs><radialGradient id="a" cx="0" cy="0" r="1" gradientTransform="matrix(40.99997 42 -42 40.99997 50 50)" gradientUnits="userSpaceOnUse"><stop offset=".33" stop-color="#F76526"/><stop offset="1" stop-color="#F43030"/></radialGradient><filter id="b" width="90" height="62" x="5" y="23" color-interpolation-filters="sRGB" filterUnits="userSpaceOnUse"><feFlood flood-opacity="0" result="BackgroundImageFix"/><feColorMatrix in="SourceAlpha" result="hardAlpha" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0"/><feOffset dy="4"/><feGaussianBlur stdDeviation="3"/><feComposite in2="hardAlpha" operator="out"/><feColorMatrix values="0 0 0 0 0.368384 0 0 0 0 0.0623777 0 0 0 0 0.0623777 0 0 0 0.25 0"/><feBlend in2="BackgroundImageFix" result="effect1_dropShadow_3909_18731"/><feBlend in="SourceGraphic" in2="effect1_dropShadow_3909_18731" result="shape"/><feColorMatrix in="SourceAlpha" result="hardAlpha" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0"/><feOffset dy="4"/><feGaussianBlur stdDeviation="3"/><feComposite in2="hardAlpha" k2="-1" k3="1" operator="arithmetic"/><feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.06 0"/><feBlend in2="shape" result="effect2_innerShadow_3909_18731"/></filter></defs></svg>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 4.1 KiB |
72
frontend/public/Logos/soc2.svg
Normal file
@@ -0,0 +1,72 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="17" viewBox="0 0 18 17" fill="none">
|
||||
<g clip-path="url(#clip0_349_4942)">
|
||||
<path d="M8.88797 0.741002C9.94502 0.741002 10.9731 0.941804 11.9399 1.34027C12.8745 1.72619 13.7125 2.27526 14.4311 2.97494C15.1498 3.6746 15.717 4.4935 16.1102 5.40024C16.5195 6.34152 16.7257 7.33927 16.7257 8.37151C16.7257 9.17473 16.6 9.95907 16.3486 10.7152L14.7566 9.90887C14.8952 9.41001 14.9628 8.89232 14.9628 8.37151C14.9628 7.57144 14.8018 6.79645 14.4858 6.06853C14.1797 5.36575 13.7415 4.73194 13.1839 4.18915C12.6264 3.64636 11.9754 3.21966 11.2535 2.92159C10.5058 2.61412 9.70977 2.45724 8.88797 2.45724C8.06614 2.45724 7.27014 2.61412 6.52245 2.92159C5.80055 3.21966 5.14954 3.64636 4.59201 4.18915C4.03448 4.73194 3.59619 5.36575 3.29002 6.06853C2.97419 6.79645 2.81306 7.57144 2.81306 8.37151C2.81306 8.89547 2.88394 9.41313 3.0193 9.91202L1.42727 10.7184C1.17589 9.96226 1.0502 9.17473 1.0502 8.37151C1.0502 7.34239 1.25646 6.34152 1.66575 5.40024C2.06215 4.49035 2.62613 3.6746 3.3448 2.97494C4.06348 2.27526 4.90462 1.72305 5.83601 1.34027C6.80284 0.941804 7.83088 0.741002 8.88797 0.741002ZM8.88797 0.527649C4.43731 0.527649 0.831055 4.03855 0.831055 8.37151C0.831055 9.3002 0.998638 10.1913 1.30158 11.0196L3.27713 10.0219C3.11277 9.49165 3.02899 8.9394 3.02899 8.37466C3.02899 7.60278 3.18367 6.8561 3.48984 6.1564C3.78632 5.47869 4.20851 4.86689 4.74671 4.3429C5.2849 3.81894 5.91336 3.40791 6.60946 3.11926C7.33136 2.82119 8.09836 2.67059 8.88797 2.67059C9.67755 2.67059 10.4478 2.82119 11.1664 3.11926C11.8626 3.40791 12.491 3.81894 13.0292 4.3429C13.5674 4.86689 13.9895 5.47869 14.2861 6.1564C14.5922 6.85921 14.7469 7.60593 14.7469 8.37466C14.7469 8.9394 14.6632 9.49165 14.4988 10.0219L16.4743 11.0196C16.7805 10.1913 16.9448 9.3002 16.9448 8.37151C16.9448 4.03855 13.3386 0.527649 8.88797 0.527649Z" fill="#F5F5F5"/>
|
||||
<path d="M8.88813 16.2152C12.3848 16.2152 15.3595 14.0471 16.4745 11.0162L14.499 10.0185C14.4378 10.213 14.3701 10.4044 14.2862 10.5895C13.9898 11.2673 13.5676 11.8791 13.0294 12.4031C12.4912 12.927 11.8627 13.338 11.1666 13.6267C10.4447 13.9248 9.67771 14.0754 8.88813 14.0754C8.09853 14.0754 7.32832 13.9248 6.60963 13.6267C5.91352 13.338 5.2851 12.927 4.74687 12.4031C4.20868 11.8791 3.7865 11.2673 3.49002 10.5895C3.40945 10.4013 3.33854 10.213 3.2773 10.0185L1.30176 11.0162C2.41683 14.0471 5.39142 16.2152 8.88813 16.2152Z" fill="#414141"/>
|
||||
<path d="M5.0172 7.46759H4.78516L5.68755 5.43448H5.89383L6.78973 7.46759H6.55447L6.32564 6.93424H5.24603L5.0172 7.46759ZM5.32338 6.74279H6.24508L5.78423 5.6635L5.32338 6.74279Z" fill="#F5F5F5"/>
|
||||
<path d="M7.05078 7.46762V5.43451H7.26346V7.46762H7.05078Z" fill="#F5F5F5"/>
|
||||
<path d="M9.5196 7.13834C9.48417 7.18861 9.44226 7.23878 9.3907 7.28583C9.33908 7.33288 9.28113 7.3737 9.2167 7.40818C9.15217 7.4427 9.07809 7.47095 8.9975 7.49293C8.91691 7.51173 8.82996 7.5243 8.73648 7.5243C8.5786 7.5243 8.43351 7.49605 8.30143 7.4427C8.16604 7.38938 8.05326 7.31408 7.95657 7.21994C7.85986 7.12578 7.78578 7.01287 7.73095 6.88107C7.67622 6.75248 7.65039 6.60812 7.65039 6.4544C7.65039 6.30064 7.6794 6.15631 7.73416 6.02769C7.78899 5.89904 7.86634 5.7861 7.963 5.68881C8.05968 5.59471 8.17574 5.51938 8.30782 5.46606C8.44 5.41274 8.585 5.38449 8.73969 5.38449C8.81704 5.38449 8.89118 5.39076 8.96525 5.40644C9.03942 5.42213 9.10707 5.44411 9.17478 5.47233C9.23922 5.50058 9.29726 5.53509 9.35199 5.57273C9.40361 5.61351 9.44868 5.65745 9.48417 5.70765L9.30686 5.83315C9.28435 5.80178 9.25534 5.76727 9.21991 5.7359C9.18442 5.70453 9.13935 5.67313 9.09094 5.65118C9.04263 5.62608 8.98783 5.60725 8.92982 5.59156C8.87181 5.57588 8.81059 5.56958 8.74291 5.56958C8.60755 5.56958 8.48513 5.59471 8.37875 5.64176C8.27242 5.68885 8.18216 5.7547 8.10481 5.83627C8.03065 5.91787 7.9727 6.012 7.93399 6.11867C7.89535 6.22534 7.87598 6.33828 7.87598 6.45754C7.87598 6.57675 7.89535 6.68972 7.9372 6.79638C7.97912 6.90309 8.03392 6.99719 8.1113 7.07873C8.18537 7.16036 8.2756 7.22309 8.38517 7.27329C8.49156 7.32031 8.614 7.34545 8.74612 7.34545C8.86539 7.34545 8.98138 7.32031 9.08773 7.27329C9.1973 7.22621 9.28756 7.14779 9.35848 7.04424L9.5196 7.13834Z" fill="#F5F5F5"/>
|
||||
<path d="M9.80664 5.43451H10.3964C10.5027 5.43451 10.5994 5.44704 10.6864 5.46903C10.7735 5.49098 10.8476 5.52549 10.9089 5.56943C10.97 5.61336 11.0184 5.66983 11.0506 5.73886C11.0829 5.80787 11.1022 5.88629 11.1022 5.9773C11.1022 6.06829 11.086 6.14986 11.0506 6.21574C11.0151 6.28478 10.9668 6.34124 10.9056 6.38518C10.8443 6.42911 10.7703 6.46363 10.68 6.48873C10.5929 6.51068 10.4963 6.52321 10.3899 6.52321H10.0193V7.46762H9.80664V5.43451ZM10.3803 6.34754C10.5478 6.34754 10.6735 6.31614 10.7606 6.25341C10.8476 6.19064 10.8895 6.09966 10.8895 5.9773C10.8895 5.8518 10.8443 5.75767 10.7541 5.7012C10.6639 5.64158 10.5382 5.61336 10.377 5.61336H10.0161V6.34754H10.3803Z" fill="#F5F5F5"/>
|
||||
<path d="M11.2183 7.46762H10.9863L11.8887 5.43451H12.0949L12.9909 7.46762H12.7556L12.5268 6.93427H11.4472L11.2183 7.46762ZM11.5246 6.74282H12.4462L11.9853 5.66353L11.5246 6.74282Z" fill="#F5F5F5"/>
|
||||
<path d="M5.86827 9.80213C5.82638 9.74878 5.76837 9.70491 5.69748 9.67345C5.62658 9.64208 5.5589 9.6264 5.49444 9.6264C5.46222 9.6264 5.42679 9.62958 5.39133 9.63585C5.35586 9.64208 5.32686 9.65153 5.29785 9.67033C5.26885 9.68602 5.2463 9.70803 5.22696 9.7331C5.20762 9.7582 5.19796 9.79272 5.19796 9.8335C5.19796 9.86799 5.20441 9.89624 5.2205 9.91825C5.23663 9.94017 5.25597 9.96218 5.28497 9.97787C5.31398 9.99355 5.3462 10.0124 5.38811 10.0249C5.42679 10.0406 5.47189 10.0532 5.52023 10.0689C5.59112 10.0908 5.66526 10.1159 5.74261 10.1442C5.81996 10.1723 5.88764 10.21 5.95207 10.2539C6.01654 10.301 6.06809 10.3575 6.10998 10.4234C6.15187 10.4923 6.17124 10.5771 6.17124 10.6775C6.17124 10.7936 6.14866 10.894 6.10356 10.9819C6.05843 11.0665 6.00041 11.1387 5.92631 11.1921C5.85217 11.2485 5.76516 11.2893 5.66847 11.3144C5.57182 11.3427 5.47189 11.3552 5.37199 11.3552C5.22375 11.3552 5.07872 11.3301 4.9369 11.2799C4.79833 11.2297 4.68231 11.1575 4.58887 11.0634L4.92081 10.7372C4.97237 10.7999 5.04005 10.8501 5.12382 10.8909C5.20762 10.9316 5.29143 10.9536 5.37199 10.9536C5.41066 10.9536 5.44609 10.9505 5.48156 10.941C5.51702 10.9348 5.54924 10.9222 5.57503 10.9034C5.60079 10.8878 5.62337 10.8626 5.63947 10.8344C5.65559 10.8061 5.66205 10.7716 5.66205 10.7308C5.66205 10.6932 5.65238 10.6586 5.63301 10.6336C5.6137 10.6053 5.58467 10.5834 5.54924 10.5614C5.51377 10.5395 5.46868 10.5206 5.41388 10.5018C5.35908 10.483 5.29785 10.4642 5.23017 10.4422C5.16249 10.4202 5.09806 10.3951 5.03359 10.3669C4.96915 10.3386 4.91114 10.301 4.8628 10.2571C4.81121 10.2132 4.77257 10.1567 4.74032 10.0939C4.71131 10.0312 4.69519 9.95274 4.69519 9.85863C4.69519 9.74563 4.71777 9.64841 4.76611 9.56999C4.81446 9.48836 4.87568 9.42251 4.95303 9.37234C5.03038 9.32208 5.11739 9.28132 5.21405 9.25931C5.31073 9.23421 5.40742 9.22482 5.50735 9.22482C5.62658 9.22482 5.74582 9.24677 5.86827 9.28756C5.99078 9.32841 6.10031 9.39111 6.19057 9.4758L5.86827 9.80213Z" fill="#F5F5F5"/>
|
||||
<path d="M8.61766 10.2823C8.61766 10.4422 8.58865 10.5897 8.53064 10.7246C8.47266 10.8564 8.39531 10.9725 8.29217 11.0666C8.1923 11.1608 8.06982 11.2361 7.93122 11.2863C7.79265 11.3364 7.64113 11.3647 7.47683 11.3647C7.31243 11.3647 7.16422 11.3395 7.02237 11.2863C6.8838 11.2361 6.76457 11.1608 6.66142 11.0666C6.56153 10.9725 6.48097 10.8564 6.42295 10.7246C6.36494 10.5928 6.33594 10.4453 6.33594 10.2823C6.33594 10.1191 6.36494 9.97162 6.42295 9.83988C6.48097 9.70808 6.55831 9.59826 6.66142 9.50409C6.76135 9.41311 6.8838 9.34099 7.02237 9.29076C7.16095 9.24055 7.31243 9.21545 7.47683 9.21545C7.64113 9.21545 7.79265 9.24055 7.93122 9.29076C8.06982 9.34099 8.1923 9.40999 8.29217 9.50409C8.39204 9.59508 8.47266 9.70808 8.53064 9.83988C8.58865 9.97162 8.61766 10.1191 8.61766 10.2823ZM8.07622 10.2823C8.07622 10.1944 8.06012 10.1128 8.03112 10.0344C8.00211 9.95902 7.96022 9.89317 7.90864 9.83667C7.85708 9.78338 7.79265 9.73945 7.71851 9.70808C7.64437 9.67668 7.56381 9.66103 7.47355 9.66103C7.38335 9.66103 7.30604 9.67668 7.2319 9.70808C7.15777 9.73945 7.09651 9.78338 7.04174 9.83667C6.99016 9.89005 6.94827 9.95593 6.91926 10.0344C6.89026 10.1097 6.87738 10.1944 6.87738 10.2823C6.87738 10.3732 6.89347 10.4579 6.92248 10.5364C6.95151 10.6148 6.9934 10.6807 7.04495 10.7372C7.09651 10.7936 7.16095 10.8375 7.2319 10.8689C7.30604 10.9003 7.38657 10.9161 7.47355 10.9161C7.5606 10.9161 7.64116 10.9003 7.7153 10.8689C7.78943 10.8375 7.85066 10.7936 7.90543 10.7372C7.95698 10.6807 7.9989 10.6148 8.0279 10.5364C8.06012 10.4579 8.07622 10.3732 8.07622 10.2823Z" fill="#F5F5F5"/>
|
||||
<path d="M10.3932 11.2704C10.2578 11.33 10.0999 11.3614 9.92265 11.3614C9.76146 11.3614 9.61326 11.3362 9.47468 11.283C9.33929 11.2327 9.22012 11.1574 9.12016 11.0633C9.02026 10.9692 8.93967 10.8562 8.8849 10.7244C8.82689 10.5926 8.79785 10.4484 8.79785 10.2883C8.79785 10.1251 8.82689 9.97773 8.8849 9.84593C8.94294 9.71412 9.02347 9.60119 9.12658 9.50708C9.22972 9.41292 9.34899 9.34395 9.48756 9.29375C9.62617 9.24351 9.77438 9.21844 9.93229 9.21844C10.0806 9.21844 10.2256 9.24351 10.3674 9.29375C10.5092 9.34395 10.6252 9.41922 10.7155 9.51647L10.3706 9.84904C10.3222 9.78631 10.261 9.73926 10.1836 9.70789C10.1063 9.67652 10.0289 9.66081 9.94838 9.66081C9.86139 9.66081 9.77759 9.67652 9.70352 9.70789C9.62935 9.73926 9.56494 9.78319 9.51333 9.83969C9.46177 9.89613 9.41985 9.96204 9.39085 10.0373C9.3619 10.1126 9.34578 10.1973 9.34578 10.2852C9.34578 10.3762 9.3619 10.4609 9.39085 10.5394C9.41985 10.6147 9.46177 10.6805 9.51333 10.737C9.56494 10.7903 9.62935 10.8342 9.70024 10.8656C9.77438 10.897 9.85173 10.9127 9.93877 10.9127C10.0386 10.9127 10.1257 10.8938 10.1998 10.8562C10.2739 10.8185 10.3352 10.7684 10.3803 10.7056L10.7316 11.0288C10.6413 11.1292 10.5286 11.2108 10.3932 11.2704Z" fill="#F5F5F5"/>
|
||||
<path d="M11.6731 10.9035L12.4884 10.1881C12.54 10.141 12.5819 10.0908 12.6109 10.0407C12.6431 9.99041 12.6593 9.93709 12.6593 9.87438C12.6593 9.8022 12.6366 9.74258 12.5883 9.69865C12.54 9.65472 12.4787 9.63276 12.3982 9.63276C12.3143 9.63276 12.2467 9.66101 12.1952 9.71745C12.1435 9.77395 12.1113 9.84922 12.1017 9.94024L11.6279 9.87747C11.6408 9.77395 11.6698 9.68293 11.7149 9.6014C11.7601 9.5198 11.8181 9.45079 11.889 9.39429C11.9599 9.33779 12.0405 9.29389 12.1339 9.2657C12.2242 9.23431 12.3208 9.22177 12.424 9.22177C12.5206 9.22177 12.6141 9.23431 12.7044 9.25937C12.7946 9.28451 12.8751 9.32214 12.946 9.37549C13.017 9.42566 13.0749 9.49161 13.1169 9.57003C13.1588 9.64845 13.1813 9.73943 13.1813 9.84613C13.1813 9.91832 13.1717 9.98417 13.1523 10.0438C13.1329 10.1034 13.1039 10.1567 13.0717 10.207C13.0363 10.2571 12.9976 10.3042 12.9525 10.345C12.9074 10.3889 12.8623 10.4296 12.814 10.4736L12.3305 10.8941H13.1845V11.3145H11.6731V10.9035Z" fill="#F5F5F5"/>
|
||||
<path d="M12.9903 8.32452H4.78516V8.41233H12.9903V8.32452Z" fill="#F5F5F5"/>
|
||||
<path d="M2.4424 8.12685L2.43596 8.2053L1.7334 7.84445L1.73984 7.77541L2.49396 7.52759L2.48752 7.60912L2.29093 7.67192L2.26193 8.03898L2.4424 8.12685ZM2.19103 8.00443L2.21681 7.69073L1.81719 7.81623L2.19103 8.00443Z" fill="#F5F5F5"/>
|
||||
<path d="M2.52356 7.37037L2.51067 7.44249L1.79199 7.33582L1.80488 7.2637L2.52356 7.37037Z" fill="#F5F5F5"/>
|
||||
<path d="M2.57107 6.59571C2.58718 6.6114 2.60008 6.63023 2.61297 6.64906C2.62586 6.66783 2.63553 6.69297 2.64197 6.71492C2.64842 6.74002 2.65165 6.76515 2.65487 6.7934C2.65487 6.82159 2.65165 6.84984 2.64519 6.8812C2.63231 6.93456 2.61297 6.97849 2.58396 7.0193C2.55496 7.06006 2.51951 7.09143 2.47761 7.11653C2.43572 7.14166 2.3906 7.15737 2.34226 7.16361C2.29392 7.16984 2.23913 7.16984 2.18757 7.15737C2.136 7.14478 2.08443 7.12597 2.04576 7.09454C2.00387 7.06636 1.97164 7.03181 1.94585 6.99105C1.92008 6.95024 1.90396 6.9063 1.89429 6.85928C1.88463 6.8122 1.88785 6.76203 1.90074 6.70865C1.90719 6.68355 1.91685 6.65848 1.92652 6.63647C1.93941 6.61452 1.9523 6.59257 1.9652 6.57373C1.98131 6.55493 1.99742 6.5361 2.01354 6.52356C2.03287 6.50785 2.05221 6.49846 2.07154 6.48901L2.10055 6.55805C2.08766 6.5612 2.07477 6.57061 2.05866 6.58003C2.04576 6.58942 2.02965 6.60198 2.01676 6.61452C2.00387 6.63023 1.9942 6.64592 1.98131 6.6616C1.97164 6.6804 1.9652 6.69923 1.95875 6.72122C1.94908 6.76515 1.94585 6.80908 1.95553 6.84672C1.9652 6.8875 1.97808 6.92199 2.00065 6.95339C2.0232 6.98476 2.05221 7.00986 2.08443 7.03181C2.11989 7.05379 2.15534 7.06951 2.19723 7.07886C2.23913 7.08828 2.28103 7.09142 2.3197 7.08519C2.36159 7.07886 2.39704 7.06951 2.4325 7.05067C2.46795 7.03181 2.49695 7.00674 2.52273 6.97537C2.54851 6.944 2.56463 6.9063 2.57752 6.86237C2.58718 6.82159 2.58718 6.78395 2.58074 6.74317C2.57107 6.70241 2.55173 6.66784 2.52273 6.63647L2.57107 6.59571Z" fill="#F5F5F5"/>
|
||||
<path d="M2.02637 6.31033L2.09404 6.11891C2.10693 6.08442 2.11983 6.05617 2.13916 6.02795C2.15527 6.00282 2.17461 5.98087 2.19717 5.96834C2.21973 5.95262 2.24551 5.94323 2.2713 5.94009C2.29707 5.93694 2.32608 5.94009 2.35831 5.9495C2.39054 5.95892 2.41632 5.9746 2.43565 5.9934C2.45499 6.01227 2.46788 6.03422 2.47755 6.05932C2.48722 6.08442 2.49045 6.11267 2.48722 6.14401C2.48399 6.17541 2.47755 6.20677 2.46466 6.24129L2.42276 6.36053L2.74504 6.4672L2.72248 6.5362L2.02637 6.31033ZM2.36154 6.34484L2.40343 6.22873C2.42276 6.17541 2.42598 6.13147 2.4131 6.09384C2.40021 6.05932 2.37442 6.03422 2.33253 6.02165C2.29063 6.00597 2.25196 6.01227 2.22295 6.03422C2.19395 6.05617 2.16817 6.09384 2.15205 6.14716L2.11015 6.26327L2.36154 6.34484Z" fill="#F5F5F5"/>
|
||||
<path d="M2.87737 6.08738L2.84513 6.15954L2.30371 5.59167L2.33271 5.52576L3.12874 5.53202L3.09651 5.60421L2.88703 5.60106L2.73556 5.93678L2.87737 6.08738ZM2.68399 5.88973L2.81291 5.60421L2.39394 5.59479L2.68399 5.88973Z" fill="#F5F5F5"/>
|
||||
<path d="M2.96127 4.63788C2.9355 4.641 2.90972 4.6473 2.88392 4.65983C2.85814 4.67237 2.83881 4.69435 2.81946 4.7226C2.8098 4.73828 2.80337 4.75397 2.79692 4.7728C2.79047 4.7916 2.79047 4.81044 2.79047 4.82612C2.79368 4.84495 2.79692 4.86064 2.80658 4.87947C2.81625 4.89515 2.83236 4.91084 2.85171 4.92337C2.87104 4.93594 2.89037 4.94221 2.90648 4.94221C2.9226 4.94221 2.94194 4.93909 2.95806 4.93279C2.97417 4.92652 2.99029 4.9171 3.0064 4.90457C3.02249 4.892 3.03863 4.87947 3.05474 4.8669C3.07407 4.85122 3.09663 4.83242 3.1192 4.8167C3.14174 4.80102 3.1643 4.78848 3.18687 4.77907C3.20943 4.76965 3.23521 4.7665 3.26422 4.7665C3.29 4.7665 3.31899 4.77907 3.35122 4.79787C3.38345 4.8167 3.40601 4.83865 3.42213 4.86375C3.43824 4.88889 3.4479 4.91399 3.4479 4.94221C3.45114 4.97046 3.4479 4.99556 3.44145 5.02381C3.43502 5.05202 3.42212 5.07712 3.40601 5.10222C3.39311 5.12106 3.38023 5.13674 3.36412 5.15243C3.34801 5.16811 3.33189 5.18379 3.31256 5.19324C3.29321 5.20578 3.27389 5.21516 3.25454 5.22146C3.23521 5.22773 3.21264 5.23403 3.19008 5.23403L3.18365 5.15558C3.21264 5.15558 3.24487 5.14931 3.27389 5.13359C3.30288 5.11791 3.32868 5.09596 3.34801 5.06459C3.35767 5.04887 3.36412 5.03319 3.37057 5.01439C3.377 4.99556 3.377 4.97672 3.37378 4.95792C3.37057 4.93909 3.36733 4.92025 3.35446 4.90457C3.34477 4.88889 3.32868 4.8732 3.30933 4.86064C3.28676 4.8481 3.26744 4.8418 3.24809 4.8418C3.22876 4.8418 3.20943 4.84495 3.19008 4.85437C3.17075 4.86375 3.15464 4.8732 3.13531 4.88574C3.1192 4.8983 3.09985 4.91399 3.08052 4.92967C3.06117 4.94535 3.04184 4.96104 3.02249 4.97672C3.00316 4.99241 2.98062 5.00182 2.95806 5.00809C2.93549 5.01439 2.90972 5.01751 2.88715 5.01751C2.86138 5.01439 2.83558 5.00497 2.80658 4.98926C2.77757 4.97046 2.75503 4.94847 2.7389 4.92652C2.72601 4.90142 2.71635 4.87632 2.71312 4.8481C2.7099 4.81985 2.71312 4.79475 2.72279 4.7665C2.72923 4.7414 2.74212 4.7163 2.75503 4.69435C2.78081 4.65357 2.8098 4.6222 2.84526 4.60336C2.87749 4.58453 2.90972 4.57197 2.93871 4.56885L2.96127 4.63788Z" fill="#F5F5F5"/>
|
||||
<path d="M3.64816 4.2986C3.65137 4.30172 3.65461 4.30487 3.66106 4.30799C3.66427 4.31113 3.67072 4.31428 3.67394 4.32052L3.43546 4.63429C3.45479 4.64686 3.47736 4.65624 3.49992 4.66254C3.52246 4.66881 3.54503 4.66881 3.56759 4.66566C3.59015 4.66254 3.60948 4.65624 3.63205 4.64371C3.65137 4.63117 3.67072 4.61861 3.68362 4.59666C3.70617 4.56841 3.71583 4.54016 3.71907 4.50879C3.72228 4.47742 3.71907 4.45232 3.7094 4.42722L3.77384 4.41154C3.78674 4.45547 3.78674 4.49625 3.78031 4.53074C3.77384 4.56529 3.75774 4.59977 3.73197 4.63117C3.7094 4.65939 3.68684 4.68134 3.65782 4.69703C3.62883 4.71274 3.59982 4.72528 3.56759 4.72843C3.53536 4.73158 3.50314 4.73158 3.47091 4.72216C3.43868 4.71274 3.40645 4.70018 3.37746 4.67823C3.34844 4.65624 3.32588 4.63117 3.30655 4.60607C3.29044 4.57782 3.27754 4.5496 3.27109 4.51821C3.26464 4.48684 3.26788 4.45859 3.27432 4.42722C3.28077 4.39585 3.29687 4.3676 3.31622 4.3425C3.33878 4.31428 3.36456 4.28915 3.39034 4.27662C3.41935 4.26093 3.44513 4.25152 3.47412 4.25152C3.50314 4.24837 3.53215 4.25152 3.56114 4.26093C3.59337 4.2672 3.61915 4.27974 3.64816 4.2986ZM3.58692 4.3425C3.54826 4.3174 3.50959 4.30799 3.47091 4.31113C3.43223 4.31428 3.39679 4.33624 3.36456 4.37702C3.35166 4.39585 3.34199 4.41465 3.33555 4.43664C3.32912 4.45859 3.32912 4.47742 3.33233 4.49937C3.33554 4.52136 3.34199 4.54016 3.35166 4.55584C3.36134 4.57467 3.37422 4.59039 3.39034 4.60292L3.58692 4.3425Z" fill="#F5F5F5"/>
|
||||
<path d="M3.60663 4.09183C3.59052 4.07926 3.5744 4.06673 3.56152 4.05731L3.60342 4.01023C3.61308 4.01649 3.62598 4.02594 3.63886 4.03536C3.65176 4.04474 3.66142 4.05416 3.66787 4.06046C3.65497 4.03221 3.65176 4.00396 3.65497 3.97259C3.65821 3.94122 3.67432 3.91297 3.69686 3.88787C3.70331 3.88161 3.70976 3.87531 3.71298 3.86907C3.71943 3.86277 3.72266 3.85962 3.72909 3.85651L3.77422 3.90671C3.771 3.90986 3.76455 3.91297 3.75811 3.91924C3.75166 3.92554 3.74523 3.93181 3.73876 3.93808C3.72588 3.95064 3.71621 3.96633 3.71298 3.98513C3.70655 4.00081 3.70655 4.01968 3.70976 4.03848C3.71298 4.05731 3.71943 4.07614 3.73233 4.09809C3.74523 4.12008 3.76455 4.13888 3.7871 4.16086L3.97403 4.31773L3.9289 4.37105L3.64209 4.13261C3.63564 4.11378 3.62274 4.10436 3.60663 4.09183Z" fill="#F5F5F5"/>
|
||||
<path d="M3.7378 3.59283C3.74748 3.60224 3.75391 3.6148 3.75391 3.62736C3.75391 3.63989 3.7507 3.65246 3.74103 3.66185C3.73137 3.67126 3.7217 3.67441 3.7088 3.67756C3.6959 3.67756 3.68303 3.67441 3.67334 3.665C3.66368 3.65558 3.65723 3.64304 3.65723 3.63048C3.65723 3.61793 3.66046 3.60539 3.67013 3.59598C3.67979 3.58655 3.68948 3.58342 3.70235 3.58029C3.71525 3.58029 3.72813 3.58342 3.7378 3.59283ZM4.21476 4.04777L4.16642 4.09797L3.81515 3.77482L3.86349 3.72461L4.21476 4.04777Z" fill="#F5F5F5"/>
|
||||
<path d="M4.47611 3.79704L4.42131 3.85039L3.94434 3.6433L4.00235 3.58996L4.39876 3.77194L4.23115 3.37661L4.28595 3.32642L4.47611 3.79704Z" fill="#F5F5F5"/>
|
||||
<path d="M4.7052 3.12898C4.68587 3.1227 4.6601 3.1227 4.63752 3.12583C4.61176 3.13211 4.58918 3.14152 4.56988 3.15721C4.54729 3.17604 4.5312 3.19486 4.52153 3.21683C4.51186 3.2388 4.50541 3.26074 4.50216 3.28271C4.50216 3.30468 4.50541 3.32977 4.51186 3.35174C4.52153 3.37371 4.53441 3.39567 4.55051 3.41762C4.56663 3.43959 4.58597 3.45528 4.60855 3.46783C4.63107 3.48037 4.65365 3.48665 4.6762 3.49293C4.69878 3.49608 4.72454 3.49608 4.74712 3.48978C4.76967 3.48352 4.79222 3.47096 4.81477 3.45528C4.83735 3.43646 4.85669 3.41449 4.86311 3.39253C4.87278 3.37056 4.87603 3.34861 4.87603 3.32664L4.94049 3.32351C4.94049 3.35487 4.93404 3.38625 4.92112 3.41762C4.90824 3.449 4.88569 3.47411 4.85348 3.50234C4.82444 3.52744 4.79222 3.54314 4.76 3.55255C4.72775 3.56196 4.69554 3.56509 4.66332 3.56196C4.6311 3.55881 4.60209 3.5494 4.57309 3.53371C4.54408 3.51803 4.51829 3.49608 4.49574 3.46783C4.47319 3.43959 4.45706 3.41136 4.4474 3.37998C4.43773 3.34861 4.43452 3.31723 4.43773 3.28586C4.44094 3.25448 4.45061 3.22624 4.46673 3.19486C4.48286 3.16662 4.50541 3.13839 4.53763 3.11329C4.56342 3.09446 4.59242 3.07877 4.62785 3.06936C4.66332 3.05995 4.69554 3.05682 4.731 3.06623L4.7052 3.12898Z" fill="#F5F5F5"/>
|
||||
<path d="M5.26582 2.87764C5.26904 2.88077 5.27228 2.88705 5.27549 2.89018C5.2787 2.89331 5.28195 2.89959 5.28516 2.90587L4.95646 3.1255C4.96934 3.14432 4.98868 3.16 5.00802 3.17256C5.02735 3.1851 5.04669 3.19138 5.06924 3.19766C5.09179 3.20081 5.11437 3.20081 5.13692 3.19766C5.1595 3.19453 5.18205 3.1851 5.20139 3.16941C5.23036 3.1506 5.25294 3.1255 5.26582 3.09725C5.2787 3.06903 5.28195 3.04391 5.28195 3.01568L5.34963 3.01881C5.34642 3.06275 5.33675 3.10353 5.31738 3.13491C5.29807 3.16628 5.27228 3.19453 5.24006 3.21647C5.21106 3.23531 5.17881 3.251 5.14659 3.25728C5.11437 3.26354 5.08212 3.26354 5.0499 3.25728C5.01768 3.251 4.98868 3.23844 4.95967 3.22275C4.93067 3.20394 4.90812 3.18197 4.88554 3.15375C4.8662 3.1255 4.85008 3.09412 4.84365 3.06275C4.83719 3.03137 4.83398 3 4.84044 2.96862C4.84686 2.93724 4.85653 2.909 4.87266 2.8839C4.88878 2.85881 4.91133 2.83371 4.94034 2.81487C4.97255 2.79292 5.00156 2.78037 5.03378 2.77409C5.06603 2.76781 5.09503 2.76781 5.12404 2.77409C5.15304 2.78037 5.17881 2.79292 5.2046 2.81174C5.22715 2.82743 5.24973 2.8494 5.26582 2.87764ZM5.19493 2.89646C5.16593 2.86193 5.13368 2.83999 5.09503 2.83058C5.05636 2.82115 5.01447 2.83058 4.97255 2.85881C4.95322 2.87136 4.93709 2.88705 4.92746 2.90587C4.91454 2.92469 4.90812 2.94352 4.90487 2.96234C4.90163 2.98118 4.90163 3.00313 4.90487 3.02196C4.90812 3.04078 4.91454 3.05962 4.92746 3.07843L5.19493 2.89646Z" fill="#F5F5F5"/>
|
||||
<path d="M6.22916 2.25345C6.25492 2.30364 6.26783 2.35071 6.27104 2.40091C6.27426 2.45111 6.26783 2.49818 6.25171 2.54209C6.23561 2.58603 6.21303 2.62681 6.1776 2.66447C6.14535 2.70212 6.10347 2.73035 6.05512 2.75545C6.00678 2.77741 5.95844 2.7931 5.90688 2.79625C5.85533 2.79938 5.8102 2.7931 5.76185 2.77741C5.71672 2.76172 5.67484 2.73976 5.63616 2.70525C5.59749 2.67388 5.56848 2.63309 5.54269 2.5829C5.51693 2.53268 5.50402 2.48562 5.5008 2.43542C5.49759 2.38522 5.50401 2.33816 5.52014 2.29423C5.53626 2.25031 5.55881 2.20952 5.59428 2.17187C5.62649 2.13422 5.66841 2.10598 5.71672 2.08088C5.76507 2.05892 5.81341 2.04323 5.865 2.04009C5.91655 2.03695 5.96165 2.04323 6.00999 2.05892C6.05512 2.0746 6.09701 2.09657 6.13568 2.13108C6.17436 2.16559 6.20658 2.20638 6.22916 2.25345ZM6.15823 2.28796C6.13893 2.25031 6.11635 2.21893 6.08734 2.19069C6.05834 2.16245 6.02612 2.1405 5.98744 2.12794C5.95201 2.11226 5.91331 2.10598 5.87142 2.10912C5.82953 2.10912 5.78762 2.12167 5.74573 2.1405C5.70384 2.15932 5.66841 2.18756 5.64259 2.21579C5.61683 2.24717 5.59749 2.28169 5.58782 2.3162C5.57815 2.35384 5.57494 2.3915 5.57815 2.42915C5.5814 2.46993 5.59428 2.50759 5.61361 2.54524C5.63295 2.5829 5.6555 2.61425 5.68451 2.6425C5.71351 2.67073 5.74573 2.68956 5.78119 2.70525C5.81665 2.71781 5.85533 2.72722 5.89721 2.72409C5.9391 2.72409 5.98099 2.71153 6.02291 2.69269C6.06479 2.67388 6.10025 2.64563 6.12602 2.6174C6.15181 2.58603 6.17115 2.55152 6.18081 2.517C6.19048 2.47934 6.1937 2.4417 6.19048 2.40405C6.19048 2.36326 6.1776 2.32561 6.15823 2.28796Z" fill="#F5F5F5"/>
|
||||
<path d="M6.35556 2.14993C6.3491 2.1311 6.33943 2.11542 6.33301 2.09973L6.39423 2.07777C6.40066 2.09032 6.40711 2.10286 6.41357 2.11542C6.42002 2.1311 6.42324 2.14052 6.42969 2.14993H6.43291C6.43612 2.11856 6.44579 2.09032 6.46512 2.06522C6.48446 2.04012 6.51025 2.0213 6.54247 2.00874C6.55214 2.0056 6.5586 2.00247 6.56505 2.00247C6.57148 1.99933 6.5779 1.99933 6.58757 1.99933L6.6037 2.06208C6.60048 2.06208 6.59403 2.06208 6.58436 2.06522C6.57469 2.06836 6.56505 2.0715 6.55535 2.07463C6.53926 2.08091 6.52314 2.09032 6.51025 2.10286C6.49734 2.11542 6.48767 2.1311 6.48125 2.14679C6.47479 2.16562 6.47158 2.18444 6.47158 2.20955C6.47158 2.23464 6.478 2.25975 6.49092 2.28799L6.5779 2.51388L6.51347 2.53898L6.37489 2.19386C6.37168 2.18444 6.36523 2.16876 6.35556 2.14993Z" fill="#F5F5F5"/>
|
||||
<path d="M6.87778 2.50409C6.90357 2.52293 6.93579 2.53547 6.97125 2.54174C7.00668 2.54802 7.04536 2.54802 7.08082 2.53547C7.11301 2.52606 7.13883 2.5135 7.16135 2.49783C7.18075 2.48212 7.19684 2.46331 7.20648 2.44448C7.21615 2.42566 7.21936 2.4037 7.21936 2.37859C7.21936 2.35663 7.21615 2.33153 7.20976 2.30643L7.18075 2.22172H7.17747C7.16784 2.25623 7.1485 2.28447 7.12271 2.30956C7.0937 2.33467 7.06469 2.35035 7.02923 2.36291C6.9938 2.37232 6.95834 2.37859 6.92612 2.37546C6.89387 2.37232 6.8649 2.36291 6.83586 2.35035C6.8101 2.33467 6.78431 2.31584 6.76497 2.29074C6.74563 2.26564 6.72954 2.23741 6.71987 2.20289C6.7102 2.17151 6.70696 2.14014 6.7102 2.10877C6.71341 2.07739 6.72308 2.04915 6.73596 2.02091C6.74884 1.99267 6.77143 1.97071 6.79719 1.94875C6.82298 1.92679 6.85523 1.9111 6.89066 1.90168C6.92291 1.89227 6.95834 1.88914 6.99701 1.89541C7.03248 1.90168 7.0647 1.91738 7.0937 1.93933H7.09691L7.07436 1.8609L7.14201 1.84207L7.2774 2.2876C7.28383 2.31271 7.29032 2.3378 7.29032 2.36918C7.29032 2.39742 7.28707 2.42879 7.27419 2.45703C7.26128 2.48527 7.24197 2.5135 7.21615 2.53547C7.18714 2.56056 7.1485 2.5794 7.09691 2.59509C7.05503 2.60763 7.00993 2.61078 6.96801 2.60763C6.92291 2.60137 6.8842 2.58881 6.84877 2.56999L6.87778 2.50409ZM6.79076 2.17779C6.79719 2.20289 6.8101 2.22172 6.82298 2.24054C6.83586 2.25936 6.85523 2.27506 6.87457 2.2876C6.89387 2.30015 6.91645 2.30643 6.94222 2.30956C6.96801 2.31271 6.9938 2.30956 7.01956 2.30329C7.04536 2.29702 7.06791 2.28447 7.08724 2.26878C7.10661 2.25309 7.12271 2.23741 7.13241 2.21544C7.14201 2.19348 7.15171 2.17465 7.15171 2.14955C7.15496 2.12445 7.15171 2.09935 7.14201 2.07425C7.13562 2.04915 7.12271 2.03033 7.10661 2.0115C7.09049 1.99267 7.07436 1.97699 7.05181 1.96757C7.03248 1.95503 7.00993 1.94875 6.98413 1.94561C6.95834 1.94247 6.93579 1.94561 6.91 1.95189C6.88099 1.9613 6.85844 1.97071 6.83911 1.9864C6.81977 2.00209 6.80689 2.02091 6.79719 2.03974C6.78755 2.05857 6.78109 2.08053 6.78109 2.10563C6.78109 2.13072 6.78431 2.15583 6.79076 2.17779Z" fill="#F5F5F5"/>
|
||||
<path d="M7.6533 1.90192C7.6436 1.86114 7.62747 1.83604 7.60168 1.82035C7.57595 1.80466 7.5437 1.80152 7.50181 1.81093C7.47277 1.81722 7.44698 1.82663 7.42443 1.84231C7.40185 1.858 7.38576 1.87369 7.36963 1.89251L7.32129 1.85486C7.33741 1.8329 7.35999 1.81093 7.38903 1.79211C7.41797 1.77329 7.45347 1.76073 7.49532 1.75132C7.52112 1.74505 7.54691 1.74505 7.56946 1.74819C7.59204 1.75132 7.61459 1.7576 7.6339 1.76701C7.6533 1.77642 7.66942 1.79211 7.68551 1.81093C7.69833 1.82976 7.70803 1.85486 7.71452 1.8831L7.75637 2.0839C7.75959 2.10273 7.76607 2.11841 7.76929 2.13724C7.77568 2.15607 7.77896 2.17175 7.78541 2.18431L7.72416 2.19685C7.72094 2.18744 7.71452 2.17489 7.71124 2.16234C7.70803 2.14979 7.70482 2.13724 7.70161 2.12469H7.69833C7.68224 2.1592 7.66293 2.18744 7.64038 2.20627C7.61459 2.2251 7.58555 2.23764 7.54694 2.24705C7.5276 2.25019 7.50824 2.25333 7.4889 2.25019C7.46956 2.25019 7.45026 2.24392 7.43089 2.23764C7.41155 2.22823 7.39543 2.21881 7.38254 2.20313C7.36963 2.18744 7.35999 2.16548 7.35351 2.14038C7.34711 2.10586 7.35029 2.07449 7.36324 2.04939C7.37612 2.02429 7.39864 2.00547 7.42764 1.98978C7.45668 1.97409 7.49211 1.9584 7.53082 1.94898C7.56946 1.93957 7.61138 1.92702 7.6533 1.92075V1.90192ZM7.64681 1.97409C7.6178 1.98036 7.58876 1.98664 7.56303 1.99291C7.53403 2.00233 7.50824 2.01174 7.4889 2.02115C7.46638 2.0337 7.45026 2.04625 7.43737 2.06194C7.42443 2.07763 7.42125 2.09645 7.42443 2.11841C7.42764 2.1341 7.43416 2.14665 7.44377 2.1592C7.45347 2.16861 7.46311 2.17489 7.47599 2.18117C7.4889 2.18744 7.50181 2.18744 7.51469 2.18744C7.5276 2.18744 7.54042 2.18744 7.55655 2.18431C7.58234 2.17803 7.60168 2.17175 7.6178 2.1592C7.6339 2.14665 7.65002 2.1341 7.65969 2.11528C7.66942 2.09959 7.67581 2.08076 7.67903 2.06194C7.68224 2.04312 7.68224 2.02115 7.67581 2.00233L7.66942 1.96781L7.64681 1.97409Z" fill="#F5F5F5"/>
|
||||
<path d="M7.93093 1.68827C7.93414 1.70082 7.93742 1.71337 7.9406 1.72907C7.94381 1.74475 7.94381 1.7573 7.94705 1.76671H7.95027C7.95994 1.73848 7.97927 1.71337 8.00828 1.69141C8.03728 1.66945 8.06953 1.66003 8.10172 1.65376C8.16297 1.64748 8.21132 1.66003 8.24354 1.69141C8.27897 1.72278 8.29837 1.76671 8.30476 1.82633L8.34019 2.11184L8.26933 2.12125L8.23711 1.86398C8.2339 1.83887 8.23062 1.81692 8.2242 1.79809C8.21777 1.77926 8.20811 1.76357 8.19841 1.74789C8.18552 1.73534 8.17264 1.72593 8.15327 1.71965C8.13718 1.71337 8.11463 1.71337 8.08884 1.71337C8.06953 1.71651 8.05341 1.71965 8.03728 1.72907C8.02119 1.73848 8.00507 1.75102 7.9954 1.76671C7.98245 1.7824 7.97606 1.80436 7.96964 1.82633C7.96315 1.85142 7.96315 1.87653 7.96636 1.9079L7.9954 2.14636L7.92451 2.15577L7.87941 1.79181C7.87941 1.77926 7.87616 1.76357 7.87289 1.74161C7.86967 1.72278 7.86649 1.70396 7.86328 1.68827H7.93093Z" fill="#F5F5F5"/>
|
||||
<path d="M8.53415 1.45298C8.53415 1.46553 8.53094 1.47808 8.52127 1.48749C8.51164 1.4969 8.50194 1.50318 8.48902 1.50318C8.47621 1.50318 8.46651 1.50004 8.45363 1.49063C8.44392 1.48122 8.4375 1.47181 8.4375 1.45612C8.4375 1.44357 8.44071 1.43101 8.45041 1.4216C8.46008 1.41219 8.46972 1.40591 8.48263 1.40591C8.49554 1.40591 8.50515 1.40905 8.51806 1.41846C8.52776 1.42788 8.53415 1.44043 8.53415 1.45298ZM8.55998 2.10559L8.48902 2.10872L8.46329 1.63809L8.53415 1.63495L8.55998 2.10559Z" fill="#F5F5F5"/>
|
||||
<path d="M9.03238 1.67236L8.74875 2.03945L9.04847 2.03318V2.0928L8.65527 2.09907V2.05201L8.93566 1.68177L8.66176 1.68492V1.62844L9.02917 1.62216L9.03238 1.67236Z" fill="#F5F5F5"/>
|
||||
<path d="M9.48067 1.81736C9.48394 1.77657 9.47424 1.7452 9.45494 1.72323C9.4356 1.70127 9.40338 1.68872 9.36146 1.68558C9.33246 1.68244 9.30666 1.68558 9.28093 1.695C9.25511 1.70441 9.23259 1.71382 9.21647 1.72951L9.18097 1.68244C9.20355 1.66362 9.22931 1.65107 9.26153 1.63852C9.29375 1.62911 9.33246 1.62283 9.37438 1.62597C9.40011 1.62911 9.42593 1.63224 9.44524 1.64166C9.46785 1.65107 9.48715 1.66362 9.50325 1.67617C9.51937 1.69185 9.53228 1.71068 9.53871 1.73264C9.54838 1.75461 9.54838 1.77971 9.54838 1.80795L9.53228 2.01189C9.53228 2.03071 9.52907 2.04953 9.52907 2.06836C9.52907 2.08719 9.52907 2.10288 9.53228 2.11856L9.47106 2.11542C9.47106 2.10288 9.46785 2.09032 9.46785 2.07777C9.46785 2.06522 9.46785 2.05267 9.46785 2.03699H9.46457C9.43881 2.06836 9.41302 2.08719 9.38398 2.09974C9.35497 2.11229 9.32276 2.11542 9.28093 2.11229C9.26153 2.11229 9.2422 2.10601 9.22289 2.09974C9.20355 2.09346 9.18746 2.08405 9.17133 2.0715C9.15521 2.05895 9.14233 2.04326 9.13584 2.02444C9.1262 2.00561 9.12299 1.98365 9.1262 1.95855C9.12942 1.9209 9.13912 1.8958 9.16167 1.87384C9.18097 1.85501 9.20677 1.83932 9.2422 1.83305C9.27441 1.82363 9.30994 1.82049 9.35179 1.82049C9.39368 1.82049 9.4356 1.82049 9.48067 1.82363V1.81736ZM9.45494 1.88325C9.42593 1.88011 9.39692 1.88011 9.36789 1.88011C9.33888 1.88011 9.31312 1.88325 9.28733 1.88952C9.26153 1.8958 9.2422 1.90521 9.22607 1.91462C9.20998 1.92717 9.20028 1.94286 9.20028 1.96482C9.20028 1.98051 9.20028 1.9962 9.20677 2.00875C9.21319 2.0213 9.21968 2.03071 9.23259 2.03699C9.2422 2.04326 9.25511 2.04953 9.26799 2.05581C9.28093 2.06209 9.29375 2.06209 9.30994 2.06209C9.33567 2.06522 9.35825 2.06209 9.37759 2.05267C9.39692 2.0464 9.41302 2.03385 9.42911 2.0213C9.44202 2.00875 9.45494 1.99306 9.46136 1.97424C9.47106 1.95541 9.47424 1.93658 9.47424 1.91462L9.47745 1.88011L9.45494 1.88325Z" fill="#F5F5F5"/>
|
||||
<path d="M9.95459 1.76359L9.81923 1.74476L9.78052 2.01772C9.77734 2.03655 9.77734 2.0491 9.78052 2.06165C9.7838 2.07421 9.78701 2.08362 9.79022 2.08989C9.79665 2.09616 9.80313 2.10244 9.8128 2.10557C9.82244 2.10871 9.83214 2.11186 9.84178 2.11186C9.85148 2.11186 9.86115 2.11186 9.874 2.11186C9.88366 2.11186 9.89658 2.10871 9.90628 2.10557L9.89979 2.16519C9.88688 2.16833 9.874 2.17147 9.86115 2.17147C9.84827 2.17147 9.83214 2.17147 9.81602 2.16833C9.80313 2.16519 9.79022 2.16205 9.77734 2.15892C9.76443 2.15264 9.75158 2.14636 9.73867 2.13381C9.729 2.1244 9.71936 2.10871 9.71287 2.09303C9.70645 2.07734 9.70645 2.05538 9.70966 2.03028L9.7483 1.73848L9.64844 1.72594L9.65483 1.66946L9.75479 1.68201L9.7741 1.55023L9.84505 1.55964L9.82565 1.69142L9.96104 1.71025L9.95459 1.76359Z" fill="#F5F5F5"/>
|
||||
<path d="M10.0619 2.19985L9.99414 2.1873L10.078 1.72294L10.1456 1.73549L10.0619 2.19985ZM10.1908 1.56293C10.1875 1.57548 10.1811 1.58803 10.1682 1.5943C10.1553 1.60057 10.1456 1.60371 10.1327 1.60057C10.1199 1.59744 10.1102 1.59116 10.1005 1.58175C10.0909 1.57234 10.0876 1.55979 10.0909 1.5441C10.0941 1.53155 10.1005 1.519 10.1134 1.51272C10.1263 1.50645 10.136 1.50331 10.1488 1.50645C10.1617 1.50959 10.1715 1.51587 10.1811 1.52528C10.1908 1.53469 10.194 1.54724 10.1908 1.56293Z" fill="#F5F5F5"/>
|
||||
<path d="M10.7342 2.10898C10.7246 2.14349 10.7117 2.17487 10.6924 2.19997C10.673 2.22507 10.6505 2.24704 10.6214 2.26272C10.5924 2.27841 10.5634 2.28782 10.528 2.2941C10.4926 2.30037 10.4603 2.29723 10.4216 2.28782C10.3862 2.27841 10.354 2.26586 10.325 2.24704C10.2959 2.22821 10.2766 2.20311 10.2573 2.17801C10.2412 2.14977 10.2283 2.12153 10.2251 2.09016C10.2186 2.05879 10.2218 2.02427 10.2315 1.98976C10.2412 1.95524 10.254 1.92387 10.2734 1.89877C10.2927 1.87367 10.3153 1.85171 10.3443 1.83602C10.3733 1.82032 10.4023 1.81091 10.4377 1.80464C10.47 1.8015 10.5055 1.8015 10.5441 1.81091C10.5795 1.82032 10.6117 1.83288 10.6408 1.85171C10.6698 1.87053 10.6891 1.89563 10.7085 1.92073C10.7246 1.94897 10.7374 1.97721 10.7407 2.00858C10.7471 2.03996 10.7439 2.07447 10.7342 2.10898ZM10.6634 2.09016C10.6698 2.06506 10.673 2.03996 10.6698 2.01486C10.6666 1.98976 10.6601 1.96779 10.6505 1.94897C10.6408 1.93014 10.6247 1.91132 10.6054 1.89563C10.586 1.87995 10.5634 1.87053 10.5344 1.86425C10.5055 1.85798 10.4796 1.85798 10.457 1.86112C10.4313 1.86425 10.412 1.87367 10.3926 1.88622C10.3733 1.89877 10.3572 1.91445 10.3411 1.93642C10.3282 1.95838 10.3153 1.98034 10.3121 2.00544C10.3056 2.03055 10.3024 2.05565 10.3056 2.08074C10.3088 2.10585 10.3153 2.12781 10.325 2.14664C10.3346 2.16546 10.3508 2.18428 10.3701 2.19997C10.3894 2.21566 10.412 2.22507 10.441 2.23135C10.47 2.23762 10.4958 2.23762 10.5183 2.23448C10.5441 2.23135 10.5634 2.22193 10.5828 2.20938C10.6021 2.19684 10.6182 2.18114 10.6344 2.15918C10.6472 2.14035 10.6569 2.11526 10.6634 2.09016Z" fill="#F5F5F5"/>
|
||||
<path d="M11.005 1.94564C11.0018 1.95819 10.9985 1.97074 10.9953 1.98642C10.9921 2.00211 10.9857 2.01466 10.9824 2.02407H10.9857C11.0082 2.00211 11.0372 1.98957 11.0727 1.98329C11.1081 1.97701 11.1403 1.98015 11.1726 1.98957C11.2306 2.00839 11.2693 2.03977 11.2854 2.08369C11.3015 2.12762 11.3015 2.17468 11.2822 2.23115L11.1854 2.50412L11.1178 2.48215L11.2048 2.23743C11.2145 2.21547 11.2177 2.1935 11.221 2.17154C11.2241 2.15271 11.2241 2.13389 11.2177 2.11506C11.2145 2.09938 11.2048 2.08369 11.1919 2.07114C11.179 2.05859 11.1597 2.04918 11.1371 2.03977C11.121 2.03349 11.1017 2.03035 11.0824 2.03349C11.0631 2.03349 11.0437 2.03977 11.0275 2.04918C11.0082 2.05859 10.9921 2.07427 10.976 2.0931C10.9599 2.11193 10.947 2.13703 10.9373 2.16526L10.8567 2.39431L10.7891 2.37234L10.9115 2.02407C10.9148 2.01153 10.9212 1.99584 10.9277 1.97701C10.9341 1.95819 10.9373 1.93936 10.9438 1.92368L11.005 1.94564Z" fill="#F5F5F5"/>
|
||||
<path d="M12.1721 2.82742C12.1527 2.83683 12.1301 2.84623 12.1076 2.85251C12.085 2.85879 12.0592 2.86192 12.0335 2.86192C12.0077 2.86192 11.9786 2.85879 11.9529 2.85251C11.9239 2.84623 11.8949 2.83683 11.8659 2.82114C11.8175 2.79604 11.7756 2.76467 11.7434 2.72701C11.7112 2.68936 11.6854 2.64857 11.6725 2.60466C11.6564 2.56072 11.6531 2.51366 11.6564 2.46346C11.6596 2.41326 11.6757 2.3662 11.7015 2.316C11.7273 2.26894 11.7595 2.22815 11.7982 2.19677C11.8368 2.16539 11.8788 2.1403 11.9239 2.12775C11.969 2.11206 12.0173 2.10892 12.0689 2.11206C12.1204 2.11519 12.1688 2.13089 12.2172 2.15284C12.2397 2.16539 12.2622 2.17795 12.2848 2.19363C12.3041 2.20932 12.3235 2.22815 12.3396 2.24697C12.3558 2.2658 12.3686 2.28462 12.3783 2.30658C12.388 2.32855 12.3944 2.34737 12.3976 2.36933L12.3202 2.38188C12.3202 2.36933 12.3138 2.35365 12.3106 2.33796C12.3041 2.32227 12.2945 2.30658 12.2848 2.29089C12.2751 2.27521 12.259 2.25952 12.2461 2.24697C12.23 2.23442 12.2139 2.22187 12.1914 2.20932C12.1495 2.18736 12.1076 2.17795 12.0657 2.17481C12.0238 2.17167 11.9851 2.17795 11.9496 2.19363C11.9142 2.20618 11.8788 2.22815 11.8498 2.25638C11.8208 2.28462 11.7949 2.316 11.7756 2.35365C11.7563 2.3913 11.7434 2.42895 11.7402 2.46973C11.7338 2.51053 11.737 2.54817 11.7466 2.58582C11.7563 2.62348 11.7756 2.65798 11.8014 2.68936C11.8272 2.72073 11.8594 2.74583 11.9013 2.7678C11.94 2.78663 11.9786 2.79604 12.0205 2.79917C12.0625 2.80232 12.1043 2.78976 12.143 2.77095L12.1721 2.82742Z" fill="#F5F5F5"/>
|
||||
<path d="M12.7329 3.04037C12.7135 3.07175 12.6878 3.09372 12.662 3.11253C12.633 3.13137 12.604 3.14391 12.575 3.15019C12.5427 3.15647 12.5105 3.15647 12.4783 3.15019C12.446 3.14391 12.4106 3.13137 12.3816 3.10941C12.3494 3.09059 12.3236 3.06547 12.3043 3.04037C12.2849 3.01215 12.272 2.9839 12.2656 2.95253C12.2591 2.92115 12.2591 2.88978 12.2656 2.8584C12.272 2.82702 12.2849 2.79565 12.3043 2.76427C12.3236 2.73603 12.3461 2.71093 12.3752 2.69211C12.4042 2.6733 12.4331 2.66074 12.4621 2.65446C12.4944 2.64818 12.5266 2.64818 12.5589 2.65446C12.5911 2.66074 12.6233 2.6733 12.6556 2.69211C12.6878 2.71093 12.7135 2.73603 12.7329 2.76427C12.7522 2.79252 12.7651 2.82074 12.7716 2.85212C12.778 2.8835 12.778 2.91487 12.7716 2.94625C12.7651 2.97762 12.7522 3.009 12.7329 3.04037ZM12.6717 2.99959C12.6878 2.97762 12.6974 2.95566 12.7007 2.93056C12.7071 2.90546 12.7071 2.8835 12.7039 2.86153C12.7007 2.83958 12.691 2.81762 12.6781 2.79565C12.6652 2.77368 12.6458 2.75799 12.6233 2.74231C12.6007 2.72662 12.575 2.71721 12.5524 2.71406C12.5266 2.71093 12.5041 2.71093 12.4815 2.71721C12.4589 2.72349 12.4364 2.7329 12.417 2.74859C12.3977 2.76427 12.3784 2.78309 12.3655 2.80506C12.3494 2.82702 12.3397 2.84899 12.3365 2.87409C12.3301 2.89919 12.3301 2.92115 12.3333 2.94312C12.3365 2.96509 12.3461 2.98703 12.3591 3.00587C12.372 3.02469 12.3913 3.04352 12.4138 3.05919C12.4364 3.07488 12.4621 3.08431 12.4847 3.08744C12.5105 3.09059 12.5331 3.09059 12.5556 3.08431C12.5782 3.07803 12.6007 3.06862 12.62 3.05293C12.6394 3.04037 12.6556 3.02156 12.6717 2.99959Z" fill="#F5F5F5"/>
|
||||
<path d="M13.0416 2.97169C13.0351 2.9811 13.0254 2.99366 13.0157 3.00622C13.006 3.01876 12.9996 3.02816 12.9932 3.03759H12.9964C13.0254 3.02503 13.0576 3.01876 13.0931 3.02503C13.1285 3.03131 13.1607 3.04387 13.1866 3.06269C13.2349 3.10034 13.2607 3.14113 13.2607 3.18819C13.2639 3.23525 13.2446 3.27917 13.2091 3.32623L13.0254 3.55214L12.9706 3.51136L13.135 3.30742C13.1511 3.2886 13.1639 3.26976 13.1736 3.25094C13.1833 3.2321 13.1898 3.21329 13.1898 3.1976C13.1898 3.17878 13.1866 3.1631 13.1801 3.14741C13.1704 3.13172 13.1575 3.11603 13.1382 3.10034C13.1221 3.08778 13.106 3.08151 13.0899 3.07523C13.0705 3.06897 13.0512 3.06897 13.0319 3.0721C13.0125 3.07523 12.9899 3.08466 12.9706 3.09719C12.9481 3.10975 12.9287 3.12857 12.9094 3.15367L12.7579 3.34507L12.7031 3.30427L12.9352 3.01563C12.9416 3.00622 12.9545 2.99366 12.9642 2.97484C12.977 2.95915 12.9867 2.94346 12.9964 2.93091L13.0416 2.97169Z" fill="#F5F5F5"/>
|
||||
<path d="M13.5834 3.48957L13.4835 3.40172L13.2966 3.60565C13.2837 3.61821 13.2773 3.63076 13.2708 3.64017C13.2644 3.64959 13.2644 3.66213 13.2644 3.66843C13.2644 3.67784 13.2676 3.68723 13.2741 3.69353C13.2804 3.69976 13.2869 3.70921 13.2934 3.71548C13.2998 3.72174 13.3094 3.72801 13.3191 3.73116C13.3288 3.73743 13.3385 3.74058 13.3481 3.7437L13.3094 3.79078C13.2966 3.78763 13.2837 3.78136 13.2741 3.77195C13.2611 3.76568 13.2514 3.75626 13.2385 3.74684C13.2289 3.73743 13.2192 3.72801 13.2128 3.71548C13.2031 3.70291 13.1999 3.69038 13.1967 3.67469C13.1934 3.65898 13.1967 3.6433 13.1999 3.62761C13.2063 3.61193 13.216 3.59311 13.2353 3.57429L13.4352 3.35466L13.361 3.28876L13.3997 3.24485L13.4738 3.31073L13.564 3.21347L13.6156 3.26053L13.5254 3.35779L13.6253 3.44564L13.5834 3.48957Z" fill="#F5F5F5"/>
|
||||
<path d="M13.6711 3.56511C13.684 3.54942 13.6969 3.53688 13.7098 3.52432L13.7549 3.57138C13.7452 3.58079 13.7388 3.59335 13.7259 3.60276C13.7162 3.61532 13.7065 3.62473 13.7001 3.63099C13.7291 3.62158 13.7613 3.61845 13.7935 3.62473C13.8258 3.63099 13.8548 3.64669 13.8773 3.6718C13.8838 3.67807 13.8902 3.68436 13.8934 3.6906C13.8967 3.6969 13.9031 3.70317 13.9064 3.70943L13.8516 3.75022C13.8484 3.74707 13.8451 3.74083 13.8387 3.73453C13.8323 3.72827 13.8258 3.71885 13.8194 3.71258C13.8065 3.70002 13.7904 3.6906 13.7742 3.68436C13.7581 3.67807 13.7388 3.67492 13.7194 3.67492C13.7001 3.67492 13.6808 3.68121 13.6582 3.69375C13.6356 3.70317 13.6131 3.722 13.5905 3.74395L13.4165 3.91339L13.3682 3.86633L13.6324 3.60589C13.6453 3.59335 13.655 3.58079 13.6711 3.56511Z" fill="#F5F5F5"/>
|
||||
<path d="M14.1026 4.28974C14.0736 4.31172 14.0446 4.33052 14.0124 4.33994C13.9802 4.34936 13.9479 4.35562 13.9157 4.35251C13.8834 4.34936 13.8512 4.34306 13.8222 4.3274C13.7932 4.31172 13.7642 4.28974 13.7384 4.26149C13.7126 4.23327 13.6965 4.20502 13.6836 4.17365C13.674 4.14229 13.6675 4.11089 13.6708 4.07952C13.674 4.04815 13.6804 4.01678 13.6965 3.98853C13.7126 3.96028 13.732 3.93206 13.761 3.91011C13.79 3.88813 13.819 3.8693 13.8512 3.85988C13.8834 3.8505 13.9157 3.8442 13.9479 3.84735C13.9802 3.8505 14.0124 3.85676 14.0414 3.87245C14.0704 3.88813 14.0994 3.91011 14.1219 3.93521C14.1477 3.96343 14.1639 3.99168 14.1767 4.02305C14.1864 4.05442 14.1928 4.08579 14.1896 4.11718C14.1864 4.14855 14.1799 4.17992 14.1639 4.20814C14.1542 4.23954 14.1315 4.26779 14.1026 4.28974ZM14.0542 4.23639C14.0736 4.2207 14.0897 4.19875 14.1026 4.17992C14.1154 4.15797 14.1219 4.13599 14.1251 4.11404C14.1284 4.09208 14.1251 4.06695 14.1187 4.045C14.1122 4.02305 14.0994 4.00107 14.08 3.97912C14.0607 3.95717 14.0414 3.9446 14.0188 3.93206C13.9962 3.92265 13.9737 3.91635 13.9511 3.91635C13.9285 3.91635 13.9028 3.9195 13.8802 3.92892C13.8577 3.93833 13.8351 3.9509 13.8158 3.96658C13.7964 3.98227 13.7803 4.00422 13.7674 4.02305C13.7545 4.045 13.7481 4.06695 13.7449 4.08893C13.7416 4.11089 13.7449 4.13599 13.7513 4.15797C13.7577 4.17992 13.7706 4.2019 13.79 4.22385C13.8093 4.24581 13.8286 4.26149 13.8512 4.27091C13.8738 4.28032 13.8963 4.28659 13.9189 4.28659C13.9414 4.28659 13.9672 4.28347 13.9898 4.27405C14.0124 4.26464 14.0349 4.25207 14.0542 4.23639Z" fill="#F5F5F5"/>
|
||||
<path d="M14.0341 4.59694L13.9922 4.54362L14.611 4.0824L14.6529 4.13575L14.0341 4.59694Z" fill="#F5F5F5"/>
|
||||
<path d="M14.3248 4.9985L14.2861 4.93576L14.9114 4.56552L15.0242 4.74437C15.0435 4.77259 15.0564 4.80399 15.0661 4.83221C15.0757 4.86046 15.0789 4.88871 15.0789 4.91378C15.0789 4.93891 15.0693 4.96401 15.0532 4.98911C15.0371 5.01106 15.0145 5.03305 14.9855 5.05185C14.9629 5.06438 14.9404 5.07383 14.9146 5.07695C14.892 5.0801 14.8663 5.0801 14.8437 5.07383C14.8211 5.06753 14.7985 5.05815 14.7792 5.04558C14.7599 5.03305 14.7406 5.01421 14.7245 4.99223L14.5375 5.34679L14.4892 5.27148L14.6762 4.92949L14.6116 4.82594L14.3248 4.9985ZM14.6729 4.79458L14.7406 4.90124C14.7728 4.95144 14.805 4.98281 14.8405 4.9985C14.8759 5.01421 14.9114 5.01106 14.9501 4.98911C14.9694 4.97658 14.9855 4.96401 14.9952 4.94833C15.0049 4.93264 15.0081 4.91693 15.0113 4.89809C15.0113 4.87929 15.0081 4.86046 15.0016 4.83851C14.9951 4.81653 14.9823 4.79457 14.9694 4.77259L14.9017 4.66281L14.6729 4.79458Z" fill="#F5F5F5"/>
|
||||
<path d="M15.0044 5.69187C15.0012 5.69499 14.9947 5.69499 14.9914 5.69814C14.985 5.70126 14.9818 5.70126 14.9753 5.70441L14.7981 5.35615C14.7755 5.36868 14.7594 5.38125 14.7433 5.39693C14.7272 5.41262 14.7175 5.43145 14.7111 5.4534C14.7047 5.47535 14.7014 5.49419 14.7014 5.51929C14.7014 5.54127 14.7079 5.56322 14.7208 5.58517C14.7369 5.61654 14.7594 5.64164 14.7852 5.65735C14.8109 5.67301 14.84 5.68245 14.8658 5.68557L14.8529 5.74834C14.8077 5.73892 14.7691 5.72324 14.7401 5.69814C14.7111 5.67616 14.6853 5.64479 14.6691 5.6103C14.6531 5.5789 14.6434 5.5475 14.6434 5.51617C14.6402 5.4848 14.6466 5.4534 14.6563 5.42515C14.6659 5.39693 14.6821 5.36868 14.7047 5.34358C14.7272 5.31848 14.753 5.29965 14.7884 5.28396C14.8207 5.26828 14.8529 5.25886 14.8883 5.25571C14.9206 5.2526 14.9528 5.25572 14.9818 5.26516C15.0108 5.27458 15.0398 5.29026 15.0624 5.30907C15.0881 5.3279 15.1075 5.35615 15.1236 5.38437C15.1397 5.41888 15.1494 5.45025 15.1494 5.4785C15.1494 5.50987 15.1461 5.53812 15.1364 5.56322C15.1268 5.58832 15.1107 5.61342 15.0881 5.63537C15.0591 5.66047 15.0334 5.67616 15.0044 5.69187ZM14.9914 5.61969C15.0302 5.59774 15.0591 5.56949 15.072 5.53185C15.0881 5.49419 15.0817 5.4534 15.0624 5.41262C15.0527 5.39067 15.0398 5.37498 15.0205 5.36242C15.0044 5.34985 14.9851 5.33732 14.9657 5.33105C14.9463 5.32475 14.9238 5.32163 14.9044 5.32163C14.8851 5.32163 14.8625 5.32475 14.8432 5.3342L14.9914 5.61969Z" fill="#F5F5F5"/>
|
||||
<path d="M14.6147 6.05627L14.5889 5.9935L15.2721 5.73935L15.2979 5.80212L15.2206 5.83033V5.83348C15.256 5.83975 15.2882 5.85543 15.3172 5.88054C15.343 5.90564 15.3656 5.93389 15.3752 5.96525C15.3881 5.99977 15.3946 6.03429 15.3946 6.06566C15.3946 6.09705 15.3849 6.12842 15.372 6.15664C15.3591 6.18489 15.3397 6.20999 15.314 6.23194C15.2882 6.25392 15.2592 6.26961 15.227 6.28214C15.1947 6.29471 15.1593 6.30098 15.1271 6.30098C15.0948 6.30098 15.0626 6.29471 15.0336 6.28214C15.0046 6.26961 14.9788 6.25392 14.9563 6.22882C14.9337 6.20684 14.9144 6.17547 14.9014 6.14096C14.8886 6.10959 14.8853 6.07507 14.8886 6.04056C14.8918 6.00604 14.9047 5.97155 14.924 5.9433V5.94015L14.6147 6.05627ZM15.2012 6.21314C15.227 6.20369 15.2495 6.19116 15.2689 6.17547C15.2882 6.15979 15.3043 6.14096 15.314 6.12212C15.3236 6.10332 15.3301 6.07822 15.3333 6.05627C15.3333 6.03117 15.3301 6.00604 15.3204 5.98094C15.3107 5.95584 15.2978 5.937 15.2785 5.9182C15.2624 5.90252 15.2399 5.88683 15.2173 5.88054C15.1947 5.87112 15.1722 5.868 15.1464 5.868C15.1206 5.868 15.0948 5.87112 15.0691 5.88368C15.0433 5.8931 15.0207 5.90564 15.0013 5.92447C14.982 5.94015 14.9691 5.95899 14.9595 5.98094C14.9498 6.00292 14.9434 6.02487 14.9434 6.04997C14.9434 6.07507 14.9466 6.09705 14.9563 6.12212C14.9659 6.14722 14.982 6.16921 14.9981 6.18801C15.0143 6.20369 15.0368 6.21626 15.0562 6.22567C15.0787 6.23509 15.1013 6.23824 15.1271 6.23509C15.1496 6.22568 15.1754 6.22256 15.2012 6.21314Z" fill="#F5F5F5"/>
|
||||
<path d="M15.3977 6.86548C15.3622 6.87493 15.3268 6.87804 15.2946 6.87493C15.2623 6.87181 15.2301 6.86236 15.2043 6.84668C15.1753 6.83099 15.1528 6.80907 15.1302 6.78394C15.1109 6.75884 15.0948 6.72744 15.0851 6.68984C15.0754 6.65532 15.0722 6.62077 15.0754 6.5894C15.0786 6.55492 15.0883 6.52667 15.1044 6.49842C15.1206 6.4702 15.1399 6.44822 15.1689 6.42627C15.1947 6.40743 15.2269 6.39175 15.2623 6.38233C15.2978 6.37292 15.3333 6.36977 15.3655 6.37292C15.3977 6.37607 15.4299 6.38548 15.4557 6.40117C15.4847 6.41685 15.5073 6.4388 15.5298 6.4639C15.5524 6.48903 15.5652 6.52037 15.5749 6.55492C15.5846 6.5894 15.5879 6.62392 15.5846 6.65847C15.5814 6.69296 15.5717 6.7212 15.5556 6.74942C15.5395 6.77767 15.5202 6.79962 15.4912 6.82161C15.4654 6.84044 15.4332 6.85612 15.3977 6.86548ZM15.3783 6.79651C15.4042 6.79018 15.4267 6.77767 15.4493 6.76514C15.4686 6.74942 15.488 6.73374 15.4976 6.71491C15.5105 6.69607 15.5169 6.67415 15.5234 6.64902C15.5266 6.62392 15.5266 6.59882 15.5169 6.57372C15.5105 6.54862 15.4976 6.52352 15.4815 6.50784C15.4654 6.48903 15.4461 6.47647 15.4267 6.4639C15.4042 6.45448 15.3816 6.44822 15.3558 6.4451C15.33 6.44195 15.3043 6.4451 15.2785 6.45137C15.2527 6.45763 15.2301 6.4702 15.2076 6.48273C15.1882 6.49842 15.1689 6.51413 15.1592 6.53294C15.1463 6.55177 15.1399 6.57372 15.1335 6.59882C15.1302 6.62392 15.1302 6.6459 15.1399 6.67415C15.1463 6.69919 15.1592 6.72432 15.1753 6.74312C15.1915 6.76202 15.2108 6.77767 15.2301 6.78706C15.2527 6.79651 15.2752 6.80277 15.3011 6.80586C15.3268 6.80586 15.3526 6.80277 15.3783 6.79651Z" fill="#F5F5F5"/>
|
||||
<path d="M15.6081 6.95638C15.6274 6.95327 15.6468 6.947 15.6629 6.94382L15.6758 7.00662C15.6629 7.00977 15.65 7.01285 15.6339 7.01912C15.6178 7.0223 15.6049 7.02542 15.5953 7.02854V7.03168C15.6243 7.03798 15.6533 7.05367 15.6758 7.07874C15.6984 7.10072 15.7145 7.12897 15.7209 7.16349C15.7241 7.1729 15.7241 7.17917 15.7241 7.18541C15.7241 7.19174 15.7241 7.20109 15.7241 7.20742L15.6565 7.21054C15.6565 7.20742 15.6565 7.19797 15.6565 7.18859C15.6565 7.17917 15.6533 7.16972 15.6533 7.16037C15.65 7.14147 15.6436 7.12579 15.6339 7.1101C15.6243 7.09442 15.6113 7.08192 15.592 7.0725C15.5759 7.06305 15.5533 7.05679 15.5308 7.05367C15.5082 7.05049 15.4793 7.05049 15.4469 7.05679L15.2053 7.10387L15.1924 7.03802L15.563 6.96583C15.5727 6.96583 15.5888 6.96268 15.6081 6.95638Z" fill="#F5F5F5"/>
|
||||
<path d="M15.7102 7.58093L15.6909 7.44913L15.4105 7.48676C15.3911 7.48991 15.3783 7.49306 15.3686 7.49618C15.3589 7.50242 15.3493 7.5056 15.3428 7.51498C15.3364 7.52128 15.3332 7.53067 15.3332 7.54012C15.3332 7.54953 15.3332 7.55892 15.3332 7.56836C15.3332 7.57772 15.3364 7.58717 15.3428 7.59661C15.346 7.60597 15.3525 7.61542 15.3589 7.6248L15.2977 7.63734C15.2912 7.6248 15.2849 7.61542 15.2816 7.60285C15.2784 7.59028 15.2752 7.57772 15.2719 7.56203C15.2687 7.54953 15.2687 7.537 15.2719 7.52128C15.2719 7.5056 15.2784 7.49306 15.2849 7.4805C15.2912 7.46793 15.3042 7.45537 15.3203 7.44598C15.3364 7.43656 15.3557 7.43033 15.3815 7.42712L15.6812 7.38639L15.6683 7.28908L15.7263 7.27969L15.7392 7.37695L15.8745 7.35814L15.8842 7.42712L15.7489 7.44598L15.7683 7.57772L15.7102 7.58093Z" fill="#F5F5F5"/>
|
||||
<path d="M15.6913 7.97263C15.7106 7.96012 15.7267 7.94444 15.7363 7.92246C15.746 7.90051 15.7525 7.87852 15.7492 7.85027C15.7492 7.83771 15.746 7.82524 15.7428 7.81579C15.7396 7.80322 15.7331 7.79384 15.7267 7.78439C15.7202 7.77497 15.7106 7.76874 15.7009 7.76247C15.6913 7.75614 15.6784 7.75614 15.6655 7.75614C15.6429 7.75929 15.6268 7.76874 15.6171 7.78754C15.6075 7.80634 15.5978 7.83459 15.5945 7.87541C15.5881 7.93187 15.572 7.97263 15.5527 8.00088C15.5333 8.02913 15.5043 8.04481 15.4656 8.04793C15.4366 8.05114 15.4141 8.04793 15.3948 8.03854C15.3754 8.02913 15.3593 8.01656 15.3464 8.00088C15.3336 7.98519 15.3239 7.96639 15.3174 7.94759C15.3109 7.92558 15.3077 7.90677 15.3045 7.88482C15.3013 7.85027 15.3077 7.81579 15.3174 7.7813C15.3303 7.74672 15.3529 7.71854 15.3819 7.69344L15.427 7.7436C15.4076 7.75614 15.3915 7.77497 15.3787 7.80007C15.3658 7.82524 15.3593 7.85027 15.3625 7.87852C15.3625 7.89421 15.3658 7.90677 15.369 7.91934C15.3722 7.93187 15.3787 7.94444 15.3851 7.95383C15.3915 7.96327 15.4012 7.96951 15.4141 7.97581C15.427 7.98207 15.4398 7.98208 15.4559 7.98208C15.4818 7.97896 15.4979 7.96639 15.5108 7.94126C15.5205 7.91619 15.5301 7.88164 15.5366 7.83459C15.5398 7.81891 15.543 7.80634 15.5462 7.78754C15.5494 7.77185 15.5559 7.75614 15.5656 7.7436C15.5752 7.73104 15.5849 7.71854 15.601 7.70912C15.6139 7.69967 15.6332 7.69344 15.6558 7.69029C15.6816 7.68717 15.7009 7.69029 15.7202 7.69967C15.7396 7.70912 15.7525 7.71854 15.7654 7.73422C15.7782 7.7499 15.7879 7.76559 15.7944 7.78439C15.8008 7.80322 15.8073 7.82524 15.8073 7.84716C15.8105 7.87852 15.804 7.91301 15.7912 7.94444C15.7782 7.97581 15.7589 8.00088 15.7331 8.01971L15.6913 7.97263Z" fill="#F5F5F5"/>
|
||||
<path d="M6.02239 14.6058C6.03851 14.5681 6.04172 14.5367 6.03206 14.5085C6.02239 14.4803 5.99659 14.4583 5.95792 14.4426C5.93216 14.4301 5.90637 14.4238 5.87736 14.4238C5.8516 14.4238 5.8258 14.4269 5.80325 14.4332L5.78713 14.3767C5.81289 14.3673 5.84514 14.3642 5.88057 14.3642C5.91603 14.3673 5.9515 14.3767 5.99017 14.3924C6.01272 14.4018 6.03527 14.4175 6.05136 14.4332C6.06752 14.4489 6.08361 14.4677 6.09328 14.4865C6.10295 14.5054 6.10616 14.5274 6.10616 14.5524C6.10616 14.5744 6.09974 14.5995 6.08686 14.6277L5.99659 14.8129C5.99017 14.8285 5.9805 14.8474 5.97404 14.8662C5.96759 14.885 5.96116 14.9007 5.95792 14.9132L5.89991 14.8882C5.90315 14.8756 5.90636 14.8662 5.91279 14.8536C5.91603 14.841 5.92249 14.8285 5.92891 14.816H5.9257C5.89348 14.8348 5.85802 14.8443 5.82902 14.8474C5.7968 14.8474 5.76455 14.841 5.72909 14.8254C5.71299 14.8191 5.6969 14.8066 5.68074 14.794C5.66465 14.7815 5.65177 14.7658 5.6421 14.7501C5.63243 14.7344 5.62598 14.7156 5.62598 14.6937C5.62598 14.6716 5.62919 14.6497 5.6421 14.6277C5.65823 14.5963 5.67753 14.5713 5.70657 14.5619C5.73233 14.5493 5.76134 14.5462 5.7968 14.5493C5.82902 14.5524 5.86445 14.5619 5.90315 14.5775C5.94183 14.5932 5.9805 14.6089 6.01918 14.6246L6.02239 14.6058ZM5.97404 14.6623C5.94825 14.6497 5.92249 14.6403 5.89348 14.6309C5.86445 14.6215 5.83869 14.6152 5.8161 14.612C5.79034 14.6089 5.771 14.6089 5.74846 14.6152C5.72909 14.6215 5.71299 14.634 5.70333 14.6528C5.6969 14.6685 5.69366 14.6811 5.69366 14.6937C5.69366 14.7062 5.70011 14.7187 5.70657 14.7281C5.71299 14.7376 5.72266 14.7501 5.73233 14.7564C5.742 14.7658 5.75491 14.7721 5.76779 14.7783C5.79034 14.7878 5.81289 14.794 5.83223 14.794C5.85481 14.794 5.87415 14.7909 5.89027 14.7846C5.90958 14.7783 5.9257 14.7658 5.93861 14.7533C5.9515 14.7407 5.96438 14.7219 5.97404 14.703L5.99017 14.6716L5.97404 14.6623Z" fill="#F5F5F5"/>
|
||||
<path d="M6.19432 15.0075L6.12988 14.9824L6.31034 14.5463L6.37481 14.5714L6.19432 15.0075ZM6.45861 14.4082C6.45216 14.4208 6.44249 14.4301 6.42958 14.4334C6.4167 14.4365 6.40381 14.4396 6.39415 14.4334C6.38123 14.4301 6.37481 14.4208 6.36838 14.4082C6.36193 14.3957 6.36193 14.3831 6.36838 14.3705C6.37481 14.358 6.38448 14.3486 6.39736 14.3455C6.41027 14.3423 6.42315 14.3392 6.43282 14.3455C6.4457 14.3486 6.45216 14.358 6.45861 14.3705C6.46183 14.3831 6.46183 14.3957 6.45861 14.4082Z" fill="#F5F5F5"/>
|
||||
<path d="M6.82934 14.8412C6.82288 14.8193 6.81321 14.8005 6.79712 14.7816C6.781 14.7628 6.75841 14.7503 6.73265 14.7409C6.70686 14.7314 6.6811 14.7283 6.6553 14.7314C6.62951 14.7346 6.60696 14.7409 6.58762 14.7503C6.56508 14.7628 6.54898 14.7754 6.53283 14.7974C6.51673 14.8162 6.50385 14.8381 6.49739 14.8632C6.48773 14.8884 6.48451 14.9134 6.48451 14.9385C6.48451 14.9636 6.49094 14.9856 6.50061 15.0075C6.51028 15.0295 6.52316 15.0484 6.54253 15.064C6.56186 15.0797 6.58441 15.0923 6.61017 15.1017C6.63921 15.1111 6.66497 15.1142 6.69077 15.1111C6.71332 15.1079 6.7359 15.0985 6.7552 15.086L6.79388 15.1393C6.76487 15.155 6.7359 15.1676 6.70365 15.1707C6.67143 15.1738 6.63276 15.1707 6.59408 15.1581C6.55541 15.1456 6.5264 15.1299 6.50061 15.1079C6.47481 15.086 6.45551 15.0609 6.43938 15.0327C6.42647 15.0044 6.41683 14.973 6.41683 14.9417C6.41362 14.9103 6.42005 14.8758 6.43293 14.8412C6.44584 14.8068 6.46196 14.7785 6.48451 14.7534C6.50706 14.7283 6.52961 14.7095 6.55862 14.6969C6.58762 14.6844 6.61984 14.675 6.65209 14.6718C6.68755 14.6687 6.72298 14.675 6.75841 14.6875C6.79066 14.6969 6.81646 14.7157 6.84543 14.7378C6.87126 14.7597 6.89056 14.7879 6.90344 14.8193L6.82934 14.8412Z" fill="#F5F5F5"/>
|
||||
<path d="M6.9222 15.497L6.85449 15.4813L7.02853 14.791L7.09621 14.8067L7.07687 14.8851H7.08011C7.10591 14.8601 7.13812 14.8444 7.17355 14.8349C7.20902 14.8287 7.24448 14.8287 7.27673 14.8349C7.31213 14.8444 7.34438 14.8569 7.37338 14.8757C7.39911 14.8945 7.42172 14.9197 7.43785 14.9447C7.45394 14.9698 7.46364 15.0012 7.46686 15.0326C7.47007 15.064 7.47007 15.0985 7.46037 15.133C7.45073 15.1675 7.43785 15.1957 7.41851 15.224C7.39911 15.2491 7.37659 15.271 7.3508 15.2899C7.32507 15.3056 7.29603 15.3181 7.2606 15.3212C7.22832 15.3275 7.19289 15.3244 7.15746 15.315C7.12521 15.3056 7.09299 15.293 7.06399 15.2679C7.03498 15.2459 7.01564 15.2177 7.00276 15.1832H6.99952L6.9222 15.497ZM7.38951 15.1173C7.39593 15.0922 7.39911 15.0671 7.39593 15.042C7.39272 15.0169 7.38629 14.995 7.37659 14.9761C7.36693 14.9573 7.3508 14.9385 7.33146 14.9228C7.31213 14.9071 7.28955 14.8977 7.2606 14.8914C7.23481 14.8851 7.20902 14.8851 7.18325 14.8882C7.15746 14.8914 7.13488 14.9008 7.11554 14.9133C7.09621 14.9259 7.07687 14.9416 7.06399 14.9635C7.04786 14.9824 7.03819 15.0075 7.03177 15.0326C7.02531 15.0577 7.0221 15.0828 7.02853 15.1079C7.03498 15.133 7.03819 15.155 7.05111 15.1738C7.06399 15.1926 7.08011 15.2114 7.09945 15.2271C7.11876 15.2428 7.14134 15.2522 7.16713 15.2585C7.1961 15.2647 7.2219 15.2679 7.24448 15.2616C7.27024 15.2585 7.28955 15.2491 7.30895 15.2365C7.32825 15.224 7.34438 15.2083 7.35726 15.1863C7.37338 15.1644 7.38302 15.1424 7.38951 15.1173Z" fill="#F5F5F5"/>
|
||||
<path d="M7.94004 15.1391C7.94652 15.0983 7.94004 15.0669 7.9207 15.045C7.90139 15.023 7.87239 15.0073 7.83047 15.001C7.80143 14.9979 7.7757 14.9979 7.74991 15.0041C7.72412 15.0105 7.70157 15.0198 7.68226 15.0355L7.65004 14.9854C7.67256 14.9696 7.70157 14.9571 7.737 14.9508C7.77249 14.9445 7.80795 14.9414 7.84978 14.9477C7.8756 14.9508 7.89818 14.9571 7.9207 14.9696C7.94325 14.9791 7.95944 14.9948 7.97553 15.0105C7.99166 15.0261 8.00129 15.045 8.00775 15.0701C8.01417 15.092 8.01417 15.1172 8.01096 15.1454L7.97874 15.3493C7.97553 15.3681 7.97229 15.3869 7.97229 15.4058C7.96904 15.4246 7.96904 15.4403 7.97229 15.456L7.91103 15.4465C7.91103 15.434 7.91103 15.4215 7.91103 15.4089C7.91103 15.3963 7.91431 15.3838 7.91431 15.3712H7.91103C7.8853 15.3995 7.8563 15.4183 7.82726 15.4277C7.79825 15.4372 7.76282 15.4403 7.72412 15.434C7.70478 15.4308 7.68869 15.4246 7.66935 15.4183C7.65004 15.4089 7.63392 15.3995 7.62101 15.3869C7.60813 15.3744 7.59521 15.3556 7.58879 15.3367C7.5823 15.3179 7.57912 15.2959 7.5823 15.2677C7.58879 15.2332 7.6017 15.2049 7.62425 15.1861C7.64677 15.1673 7.67256 15.1548 7.70799 15.1516C7.74024 15.1454 7.77892 15.1454 7.81756 15.1485C7.85948 15.1516 7.90139 15.1548 7.94325 15.1642L7.94004 15.1391ZM7.90782 15.2049C7.87881 15.2018 7.84978 15.1987 7.82083 15.1956C7.79183 15.1924 7.76603 15.1956 7.74024 15.1987C7.71448 15.2018 7.69517 15.2081 7.67905 15.2207C7.66286 15.2332 7.65326 15.2489 7.64677 15.2709C7.64355 15.2866 7.64677 15.3022 7.65004 15.3148C7.65326 15.3274 7.66286 15.3367 7.67256 15.3461C7.68226 15.3556 7.69517 15.3619 7.70799 15.365C7.7209 15.3712 7.73378 15.3744 7.7467 15.3744C7.77249 15.3775 7.79504 15.3775 7.81435 15.3712C7.83368 15.365 7.85305 15.3556 7.86918 15.3461C7.8853 15.3336 7.89818 15.3179 7.90782 15.3022C7.91749 15.2834 7.92394 15.2645 7.92716 15.2457L7.93361 15.2113L7.90782 15.2049Z" fill="#F5F5F5"/>
|
||||
<path d="M8.2534 15.431C8.2534 15.4435 8.24698 15.4561 8.23407 15.4686C8.22115 15.478 8.20827 15.4843 8.19215 15.4812C8.17602 15.478 8.16321 15.4718 8.15351 15.4623C8.14384 15.4498 8.14062 15.4373 8.14062 15.4247C8.14062 15.4122 8.14711 15.3996 8.15993 15.387C8.17284 15.3745 8.18572 15.3714 8.20185 15.3745C8.21797 15.3745 8.23085 15.3839 8.24055 15.3933C8.25016 15.4027 8.25668 15.4153 8.2534 15.431Z" fill="#F5F5F5"/>
|
||||
<path d="M8.90759 15.2741C8.90759 15.3087 8.89789 15.3432 8.88498 15.3714C8.87213 15.3996 8.85276 15.4279 8.83024 15.4467C8.80763 15.4687 8.77869 15.4844 8.74641 15.4969C8.71419 15.5094 8.67873 15.5126 8.64009 15.5126C8.60141 15.5126 8.56916 15.5032 8.53694 15.4906C8.50473 15.4781 8.47893 15.4593 8.45638 15.4373C8.4338 15.4153 8.41768 15.3871 8.40483 15.3557C8.39195 15.3243 8.38867 15.293 8.38867 15.2553C8.38867 15.2208 8.39837 15.1863 8.41128 15.158C8.42417 15.1298 8.4435 15.1016 8.46602 15.0827C8.48863 15.0608 8.51764 15.0451 8.54986 15.0326C8.58207 15.02 8.61751 15.0169 8.65294 15.0169C8.69164 15.0169 8.72386 15.0263 8.75608 15.0388C8.78833 15.0514 8.81412 15.0702 8.83667 15.0922C8.85925 15.1141 8.87534 15.1423 8.88826 15.1737C8.90438 15.2051 8.91081 15.2365 8.90759 15.2741ZM8.83346 15.271C8.83346 15.2459 8.83024 15.2208 8.82373 15.1957C8.81733 15.1737 8.80442 15.1518 8.78833 15.133C8.7722 15.1141 8.75286 15.1016 8.73028 15.0891C8.70773 15.0796 8.68194 15.0733 8.65294 15.0702C8.62399 15.0702 8.5982 15.0733 8.57559 15.0827C8.55307 15.0922 8.53373 15.1047 8.51764 15.1204C8.50151 15.1361 8.48863 15.158 8.47893 15.18C8.4693 15.202 8.46281 15.2271 8.46281 15.2522C8.46281 15.2773 8.46602 15.3024 8.47251 15.3275C8.47893 15.3494 8.49181 15.3714 8.50794 15.3903C8.52403 15.4091 8.54337 15.4216 8.56274 15.431C8.58207 15.4404 8.61108 15.4467 8.63681 15.4467C8.66585 15.4467 8.69164 15.4436 8.71419 15.4341C8.73677 15.4248 8.75608 15.4122 8.7722 15.3965C8.78833 15.3808 8.80121 15.3589 8.81091 15.3369C8.83025 15.3212 8.83346 15.2961 8.83346 15.271Z" fill="#F5F5F5"/>
|
||||
<path d="M9.05825 15.0856C9.05825 15.0667 9.05503 15.0479 9.05176 15.0322L9.1195 15.0291C9.12271 15.0416 9.12271 15.0573 9.12271 15.0699C9.12271 15.0856 9.12589 15.0981 9.12589 15.1075H9.12911C9.14202 15.0793 9.16136 15.0573 9.18715 15.0385C9.21294 15.0196 9.24516 15.0103 9.27741 15.0103C9.28702 15.0103 9.2935 15.0103 9.3032 15.0103C9.30963 15.0103 9.3193 15.0103 9.32575 15.0134L9.3193 15.0793C9.31602 15.0793 9.30963 15.0761 9.29993 15.0761C9.29029 15.0761 9.28062 15.0761 9.27092 15.0761C9.25159 15.0761 9.23549 15.0793 9.21615 15.0887C9.20003 15.0949 9.18394 15.1075 9.17102 15.1232C9.15814 15.1388 9.14851 15.1577 9.14202 15.1797C9.13559 15.2016 9.13238 15.2299 9.13238 15.2612L9.14202 15.5028L9.07116 15.5059L9.05825 15.1388C9.05825 15.1232 9.05825 15.1075 9.05825 15.0856Z" fill="#F5F5F5"/>
|
||||
<path d="M9.50656 15.5752C9.52908 15.5972 9.55812 15.616 9.59355 15.6285C9.62904 15.6411 9.66447 15.6474 9.70311 15.6411C9.73861 15.638 9.76434 15.6285 9.79016 15.616C9.81268 15.6035 9.83205 15.5878 9.84499 15.5689C9.85781 15.5501 9.86751 15.5313 9.87072 15.5062C9.8739 15.4842 9.87718 15.4591 9.8739 15.4341L9.8643 15.3462H9.86108C9.84496 15.3776 9.82238 15.4027 9.79016 15.4215C9.75791 15.4403 9.72572 15.4529 9.69026 15.456C9.65156 15.4591 9.61934 15.4591 9.58712 15.4497C9.5549 15.4403 9.52587 15.4278 9.50335 15.409C9.48074 15.3901 9.45822 15.3681 9.44534 15.3399C9.42921 15.3117 9.41951 15.2803 9.4163 15.2458C9.41309 15.2113 9.4163 15.1799 9.42272 15.1485C9.43242 15.1172 9.44534 15.092 9.46464 15.0669C9.48395 15.0419 9.50656 15.023 9.53557 15.0073C9.5646 14.9916 9.59682 14.9822 9.63546 14.9759C9.67089 14.9728 9.70639 14.9759 9.74182 14.9885C9.77725 15.0011 9.80625 15.0199 9.82887 15.0481H9.83205L9.82238 14.9666L9.8933 14.9602L9.94486 15.4246C9.94804 15.4497 9.94804 15.4779 9.94486 15.5062C9.94165 15.5344 9.93195 15.5627 9.91264 15.5909C9.89652 15.616 9.87072 15.6411 9.83847 15.6599C9.80625 15.6788 9.76434 15.6914 9.7096 15.6976C9.66447 15.7039 9.62255 15.6976 9.5807 15.685C9.53878 15.6725 9.50007 15.6537 9.46785 15.6285L9.50656 15.5752ZM9.48074 15.2426C9.48395 15.2678 9.49047 15.2897 9.50007 15.3117C9.50977 15.3337 9.52587 15.3493 9.54199 15.365C9.55812 15.3807 9.5807 15.3901 9.60321 15.3995C9.62576 15.4058 9.65156 15.409 9.68059 15.4058C9.70639 15.4027 9.73212 15.3964 9.75152 15.3838C9.77404 15.3713 9.79016 15.3588 9.80625 15.3399C9.82238 15.3211 9.83205 15.3023 9.83847 15.2772C9.84496 15.2552 9.84817 15.2301 9.84499 15.2019C9.84172 15.1768 9.83526 15.1548 9.82238 15.1329C9.80947 15.1109 9.79659 15.0952 9.77725 15.0795C9.75791 15.0638 9.73861 15.0544 9.71278 15.045C9.69026 15.0387 9.66447 15.0356 9.63868 15.0387C9.60967 15.0419 9.58391 15.0481 9.5646 15.0607C9.54199 15.0732 9.52587 15.0889 9.51298 15.1077C9.50007 15.1266 9.49047 15.1454 9.48395 15.1705C9.48074 15.1925 9.47755 15.2175 9.48074 15.2426Z" fill="#F5F5F5"/>
|
||||
<path d="M10.1383 15.4183L10.0771 15.4089L10.2447 14.6371L10.3059 14.6465L10.1383 15.4183Z" fill="#F5F5F5"/>
|
||||
<path d="M10.6733 14.9194C10.6572 14.9037 10.6379 14.8912 10.6153 14.8848C10.5928 14.8786 10.567 14.8786 10.5411 14.8848C10.5283 14.888 10.5186 14.8912 10.5057 14.8974C10.4928 14.9037 10.4832 14.91 10.4767 14.9162C10.4703 14.9257 10.4638 14.9351 10.4606 14.9445C10.4574 14.9539 10.4574 14.9664 10.4606 14.979C10.4671 15.001 10.4799 15.0135 10.4993 15.0229C10.5186 15.0292 10.5509 15.0323 10.5928 15.0323C10.6507 15.0292 10.6958 15.0354 10.728 15.0511C10.7603 15.0668 10.7797 15.0919 10.7893 15.1264C10.7958 15.1516 10.7958 15.1767 10.7893 15.1955C10.7829 15.2143 10.7732 15.2331 10.7603 15.2488C10.7474 15.2645 10.728 15.277 10.7087 15.2865C10.6894 15.2959 10.6668 15.3053 10.6475 15.3084C10.6121 15.3178 10.5767 15.3178 10.5379 15.3116C10.5025 15.3053 10.4671 15.2896 10.4381 15.2645L10.4832 15.2112C10.4993 15.23 10.5218 15.2425 10.5476 15.2488C10.5734 15.2582 10.6024 15.2582 10.6314 15.252C10.6475 15.2488 10.6604 15.2425 10.6733 15.2394C10.6862 15.2331 10.6958 15.2269 10.7055 15.2174C10.7152 15.2081 10.7184 15.1986 10.7249 15.186C10.728 15.1735 10.728 15.161 10.7249 15.1453C10.7184 15.1202 10.7023 15.1045 10.6765 15.0982C10.6507 15.0919 10.6121 15.0888 10.5637 15.0888C10.5476 15.0888 10.5315 15.0888 10.5154 15.0888C10.4993 15.0888 10.4832 15.0825 10.4671 15.0762C10.451 15.07 10.4381 15.0606 10.4251 15.048C10.4123 15.0354 10.4026 15.0198 10.3993 14.9978C10.3929 14.9758 10.3929 14.9539 10.3993 14.9351C10.4058 14.9162 10.4123 14.9005 10.4251 14.8848C10.4381 14.8692 10.4542 14.8567 10.4735 14.8472C10.4928 14.8378 10.5121 14.8284 10.5347 14.8252C10.567 14.819 10.6024 14.8158 10.6346 14.8252C10.6701 14.8315 10.6958 14.8472 10.7184 14.8692L10.6733 14.9194Z" fill="#F5F5F5"/>
|
||||
<path d="M11.3724 14.8379C11.3853 14.8724 11.3885 14.9038 11.3853 14.9383C11.382 14.9697 11.3756 15.001 11.3595 15.0293C11.3466 15.0575 11.3241 15.0826 11.2983 15.1046C11.2725 15.1265 11.2402 15.1422 11.2048 15.1548C11.1694 15.1673 11.1339 15.1704 11.1016 15.1704C11.0662 15.1673 11.0372 15.1611 11.0082 15.1454C10.9792 15.1328 10.9534 15.1108 10.9309 15.0889C10.9083 15.0638 10.8922 15.0355 10.8793 15.001C10.8664 14.9665 10.8632 14.9351 10.8664 14.9006C10.8697 14.8692 10.8761 14.8379 10.8922 14.8096C10.9051 14.7814 10.9276 14.7563 10.9534 14.7343C10.9792 14.7124 11.0115 14.6967 11.0469 14.6841C11.0823 14.6716 11.1178 14.6684 11.1533 14.6684C11.1887 14.6716 11.2177 14.6779 11.2467 14.6936C11.2757 14.7061 11.3015 14.728 11.3241 14.75C11.3466 14.7751 11.3627 14.8034 11.3724 14.8379ZM11.3047 14.8598C11.2951 14.8347 11.2854 14.8128 11.2693 14.7939C11.2531 14.7751 11.237 14.7594 11.2145 14.7469C11.1951 14.7343 11.1726 14.728 11.1468 14.7249C11.1211 14.7218 11.0952 14.7249 11.0694 14.7343C11.0437 14.7437 11.0211 14.7563 11.0018 14.772C10.9824 14.7877 10.9696 14.8065 10.9599 14.8285C10.9502 14.8504 10.9437 14.8724 10.9437 14.8975C10.9437 14.9226 10.947 14.9477 10.9567 14.9728C10.9663 14.9979 10.976 15.0198 10.9921 15.0387C11.0082 15.0575 11.0243 15.0732 11.0469 15.0858C11.0662 15.0983 11.0888 15.1046 11.1146 15.1077C11.1404 15.1108 11.1629 15.1077 11.1919 15.0983C11.2177 15.0889 11.2402 15.0763 11.2596 15.0606C11.279 15.045 11.2918 15.0261 11.3015 15.0041C11.3111 14.9822 11.3144 14.9602 11.3176 14.9351C11.3144 14.91 11.3111 14.8849 11.3047 14.8598Z" fill="#F5F5F5"/>
|
||||
<path d="M11.7982 14.5243C11.7788 14.5117 11.7595 14.5054 11.7337 14.5023C11.7079 14.4992 11.6822 14.5054 11.6596 14.5149C11.6338 14.5243 11.6113 14.54 11.5951 14.5588C11.579 14.5776 11.5661 14.5964 11.5565 14.6184C11.55 14.6404 11.5468 14.6623 11.5468 14.6874C11.5468 14.7125 11.5533 14.7376 11.5661 14.7627C11.5758 14.7878 11.5919 14.8098 11.608 14.8254C11.6241 14.8443 11.6435 14.8568 11.6661 14.8663C11.6886 14.8757 11.7112 14.8819 11.7369 14.8819C11.7627 14.8819 11.7885 14.8757 11.8143 14.8663C11.8433 14.8537 11.8659 14.838 11.8787 14.8192C11.8948 14.8004 11.9045 14.7816 11.9077 14.7596L11.9722 14.7752C11.9626 14.8066 11.9497 14.8349 11.9271 14.86C11.9045 14.8851 11.8755 14.907 11.8369 14.9227C11.8014 14.9384 11.766 14.9447 11.7305 14.9478C11.6951 14.9478 11.6661 14.9447 11.6338 14.9321C11.6048 14.9196 11.579 14.9039 11.5533 14.8788C11.5307 14.8568 11.5114 14.8286 11.4953 14.7941C11.4824 14.7627 11.4727 14.7282 11.4727 14.6968C11.4727 14.6655 11.4759 14.6341 11.4888 14.6058C11.5017 14.5776 11.5178 14.5493 11.5436 14.5274C11.5661 14.5023 11.5983 14.4835 11.6338 14.4709C11.6628 14.4584 11.6951 14.4521 11.7337 14.4521C11.7724 14.4521 11.8014 14.4615 11.8337 14.4772L11.7982 14.5243Z" fill="#F5F5F5"/>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0_349_4942">
|
||||
<rect width="16.3767" height="15.7468" fill="white" transform="translate(0.730469 0.5)"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 66 KiB |
1
frontend/public/css/uPlot.min.css
vendored
Normal file
@@ -0,0 +1 @@
|
||||
.uplot, .uplot *, .uplot *::before, .uplot *::after {box-sizing: border-box;}.uplot {font-family: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";line-height: 1.5;width: min-content;}.u-title {text-align: center;font-size: 18px;font-weight: bold;}.u-wrap {position: relative;user-select: none;}.u-over, .u-under {position: absolute;}.u-under {overflow: hidden;}.uplot canvas {display: block;position: relative;width: 100%;height: 100%;}.u-axis {position: absolute;}.u-legend {font-size: 14px;margin: auto;text-align: center;}.u-inline {display: block;}.u-inline * {display: inline-block;}.u-inline tr {margin-right: 16px;}.u-legend th {font-weight: 600;}.u-legend th > * {vertical-align: middle;display: inline-block;}.u-legend .u-marker {width: 1em;height: 1em;margin-right: 4px;background-clip: padding-box !important;}.u-inline.u-live th::after {content: ":";vertical-align: middle;}.u-inline:not(.u-live) .u-value {display: none;}.u-series > * {padding: 4px;}.u-series th {cursor: pointer;}.u-legend .u-off > * {opacity: 0.3;}.u-select {background: rgba(0,0,0,0.07);position: absolute;pointer-events: none;}.u-cursor-x, .u-cursor-y {position: absolute;left: 0;top: 0;pointer-events: none;will-change: transform;}.u-hz .u-cursor-x, .u-vt .u-cursor-y {height: 100%;border-right: 1px dashed #607D8B;}.u-hz .u-cursor-y, .u-vt .u-cursor-x {width: 100%;border-bottom: 1px dashed #607D8B;}.u-cursor-pt {position: absolute;top: 0;left: 0;border-radius: 50%;border: 0 solid;pointer-events: none;will-change: transform;/*this has to be !important since we set inline "background" shorthand */background-clip: padding-box !important;}.u-axis.u-off, .u-select.u-off, .u-cursor-x.u-off, .u-cursor-y.u-off, .u-cursor-pt.u-off {display: none;}
|
||||
|
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 13 KiB |
BIN
frontend/public/fonts/FiraCode-VariableFont_wght.ttf
Normal file
BIN
frontend/public/fonts/Inter-VariableFont_opsz,wght.ttf
Normal file
BIN
frontend/public/fonts/Satoshi-Regular.woff2
Normal file
BIN
frontend/public/fonts/SpaceMono-Regular.ttf
Normal file
BIN
frontend/public/fonts/WorkSans-VariableFont_wght.ttf
Normal file
@@ -53,8 +53,10 @@
|
||||
"option_atleastonce": "at least once",
|
||||
"option_onaverage": "on average",
|
||||
"option_intotal": "in total",
|
||||
"option_last": "last",
|
||||
"option_above": "above",
|
||||
"option_below": "below",
|
||||
"option_above_below": "above/below",
|
||||
"option_equal": "is equal to",
|
||||
"option_notequal": "not equal to",
|
||||
"button_query": "Query",
|
||||
@@ -109,6 +111,8 @@
|
||||
"choose_alert_type": "Choose a type for the alert",
|
||||
"metric_based_alert": "Metric based Alert",
|
||||
"metric_based_alert_desc": "Send a notification when a condition occurs in the metric data.",
|
||||
"anomaly_based_alert": "Anomaly based Alert",
|
||||
"anomaly_based_alert_desc": "Send a notification when a condition occurs in the metric data.",
|
||||
"log_based_alert": "Log-based Alert",
|
||||
"log_based_alert_desc": "Send a notification when a condition occurs in the logs data.",
|
||||
"traces_based_alert": "Trace-based Alert",
|
||||
@@ -117,6 +121,8 @@
|
||||
"exceptions_based_alert_desc": "Send a notification when a condition occurs in the exceptions data.",
|
||||
"field_unit": "Threshold unit",
|
||||
"text_alert_on_absent": "Send a notification if data is missing for",
|
||||
"text_require_min_points": "Run alert evaluation only when there are minimum of",
|
||||
"text_num_points": "data points in each result group",
|
||||
"text_alert_frequency": "Run alert every",
|
||||
"text_for": "minutes",
|
||||
"selected_query_placeholder": "Select query"
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
{
|
||||
"breadcrumb": "Messaging Queues",
|
||||
"header": "Kafka / Overview",
|
||||
"overview": {
|
||||
"title": "Start sending data in as little as 20 minutes",
|
||||
"subtitle": "Connect and Monitor Your Data Streams"
|
||||
},
|
||||
"configureConsumer": {
|
||||
"title": "Configure Consumer",
|
||||
"description": "Add consumer data sources to gain insights and enhance monitoring.",
|
||||
"button": "Get Started"
|
||||
},
|
||||
"configureProducer": {
|
||||
"title": "Configure Producer",
|
||||
"description": "Add producer data sources to gain insights and enhance monitoring.",
|
||||
"button": "Get Started"
|
||||
},
|
||||
"monitorKafka": {
|
||||
"title": "Monitor kafka",
|
||||
"description": "Add your Kafka source to gain insights and enhance activity tracking.",
|
||||
"button": "Get Started"
|
||||
},
|
||||
"summarySection": {
|
||||
"viewDetailsButton": "View Details"
|
||||
},
|
||||
"confirmModal": {
|
||||
"content": "Before navigating to the details page, please make sure you have configured all the required setup to ensure correct data monitoring.",
|
||||
"okText": "Proceed"
|
||||
}
|
||||
}
|
||||
@@ -40,8 +40,10 @@
|
||||
"option_atleastonce": "at least once",
|
||||
"option_onaverage": "on average",
|
||||
"option_intotal": "in total",
|
||||
"option_last": "last",
|
||||
"option_above": "above",
|
||||
"option_below": "below",
|
||||
"option_above_below": "above/below",
|
||||
"option_equal": "is equal to",
|
||||
"option_notequal": "not equal to",
|
||||
"button_query": "Query",
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
{
|
||||
"rps_over_100": "You are sending data at more than 100 RPS, your ingestion may be rate limited. Please reach out to us via Intercom support."
|
||||
"rps_over_100": "You are sending data at more than 100 RPS, your ingestion may be rate limited. Please reach out to us via Intercom support or "
|
||||
}
|
||||
|
||||
@@ -38,5 +38,7 @@
|
||||
"LIST_LICENSES": "SigNoz | List of Licenses",
|
||||
"WORKSPACE_LOCKED": "SigNoz | Workspace Locked",
|
||||
"SUPPORT": "SigNoz | Support",
|
||||
"DEFAULT": "Open source Observability Platform | SigNoz"
|
||||
"DEFAULT": "Open source Observability Platform | SigNoz",
|
||||
"ALERT_HISTORY": "SigNoz | Alert Rule History",
|
||||
"ALERT_OVERVIEW": "SigNoz | Alert Rule Overview"
|
||||
}
|
||||
|
||||
22
frontend/public/locales/en-GB/workspaceLocked.json
Normal file
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"trialPlanExpired": "Trial Plan Expired",
|
||||
"gotQuestions": "Got Questions?",
|
||||
"contactUs": "Contact Us",
|
||||
"upgradeToContinue": "Upgrade to Continue",
|
||||
"upgradeNow": "Upgrade now to keep enjoying all the great features you’ve been using.",
|
||||
"yourDataIsSafe": "Your data is safe with us until",
|
||||
"actNow": "Act now to avoid any disruptions and continue where you left off.",
|
||||
"contactAdmin": "Contact your admin to proceed with the upgrade.",
|
||||
"continueMyJourney": "Continue My Journey",
|
||||
"needMoreTime": "Need More Time?",
|
||||
"extendTrial": "Extend Trial",
|
||||
"extendTrialMsgPart1": "If you have a specific reason why you were not able to finish your PoC in the trial period, please write to us on",
|
||||
"extendTrialMsgPart2": "with the reason. Sometimes we can extend trial by a few days on a case by case basis",
|
||||
"whyChooseSignoz": "Why choose Signoz",
|
||||
"enterpriseGradeObservability": "Enterprise-grade Observability",
|
||||
"observabilityDescription": "Get access to observability at any scale with advanced security and compliance.",
|
||||
"continueToUpgrade": "Continue to Upgrade",
|
||||
"youAreInGoodCompany": "You are in good company",
|
||||
"faqs": "FAQs",
|
||||
"somethingWentWrong": "Something went wrong"
|
||||
}
|
||||
@@ -13,9 +13,12 @@
|
||||
"button_no": "No",
|
||||
"remove_label_confirm": "This action will remove all the labels. Do you want to proceed?",
|
||||
"remove_label_success": "Labels cleared",
|
||||
"alert_form_step1": "Step 1 - Define the metric",
|
||||
"alert_form_step2": "Step 2 - Define Alert Conditions",
|
||||
"alert_form_step3": "Step 3 - Alert Configuration",
|
||||
"alert_form_step1": "Choose a detection method",
|
||||
"alert_form_step2": "Define the metric",
|
||||
"alert_form_step3": "Define Alert Conditions",
|
||||
"alert_form_step4": "Alert Configuration",
|
||||
"threshold_alert_desc": "An alert is triggered whenever a metric deviates from an expected threshold.",
|
||||
"anomaly_detection_alert_desc": "An alert is triggered whenever a metric deviates from an expected pattern.",
|
||||
"metric_query_max_limit": "Can not create query. You can create maximum of 5 queries",
|
||||
"confirm_save_title": "Save Changes",
|
||||
"confirm_save_content_part1": "Your alert built with",
|
||||
@@ -35,6 +38,7 @@
|
||||
"button_cancelchanges": "Cancel",
|
||||
"button_discard": "Discard",
|
||||
"text_condition1": "Send a notification when",
|
||||
"text_condition1_anomaly": "Send notification when the observed value for",
|
||||
"text_condition2": "the threshold",
|
||||
"text_condition3": "during the last",
|
||||
"option_1min": "1 min",
|
||||
@@ -53,8 +57,10 @@
|
||||
"option_atleastonce": "at least once",
|
||||
"option_onaverage": "on average",
|
||||
"option_intotal": "in total",
|
||||
"option_last": "last",
|
||||
"option_above": "above",
|
||||
"option_below": "below",
|
||||
"option_above_below": "above/below",
|
||||
"option_equal": "is equal to",
|
||||
"option_notequal": "not equal to",
|
||||
"button_query": "Query",
|
||||
@@ -108,7 +114,9 @@
|
||||
"user_tooltip_more_help": "More details on how to create alerts",
|
||||
"choose_alert_type": "Choose a type for the alert",
|
||||
"metric_based_alert": "Metric based Alert",
|
||||
"anomaly_based_alert": "Anomaly based Alert",
|
||||
"metric_based_alert_desc": "Send a notification when a condition occurs in the metric data.",
|
||||
"anomaly_based_alert_desc": "Send a notification when a condition occurs in the metric data.",
|
||||
"log_based_alert": "Log-based Alert",
|
||||
"log_based_alert_desc": "Send a notification when a condition occurs in the logs data.",
|
||||
"traces_based_alert": "Trace-based Alert",
|
||||
@@ -117,6 +125,8 @@
|
||||
"exceptions_based_alert_desc": "Send a notification when a condition occurs in the exceptions data.",
|
||||
"field_unit": "Threshold unit",
|
||||
"text_alert_on_absent": "Send a notification if data is missing for",
|
||||
"text_require_min_points": "Run alert evaluation only when there are minimum of",
|
||||
"text_num_points": "data points in each result group",
|
||||
"text_alert_frequency": "Run alert every",
|
||||
"text_for": "minutes",
|
||||
"selected_query_placeholder": "Select query"
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
{
|
||||
"create_dashboard": "Create Dashboard",
|
||||
"import_json": "Import Dashboard JSON",
|
||||
"view_template": "View templates",
|
||||
"import_grafana_json": "Import Grafana JSON",
|
||||
"copy_to_clipboard": "Copy To ClipBoard",
|
||||
"download_json": "Download JSON",
|
||||
|
||||
30
frontend/public/locales/en/messagingQueuesKafkaOverview.json
Normal file
@@ -0,0 +1,30 @@
|
||||
{
|
||||
"breadcrumb": "Messaging Queues",
|
||||
"header": "Kafka / Overview",
|
||||
"overview": {
|
||||
"title": "Start sending data in as little as 20 minutes",
|
||||
"subtitle": "Connect and Monitor Your Data Streams"
|
||||
},
|
||||
"configureConsumer": {
|
||||
"title": "Configure Consumer",
|
||||
"description": "Add consumer data sources to gain insights and enhance monitoring.",
|
||||
"button": "Get Started"
|
||||
},
|
||||
"configureProducer": {
|
||||
"title": "Configure Producer",
|
||||
"description": "Add producer data sources to gain insights and enhance monitoring.",
|
||||
"button": "Get Started"
|
||||
},
|
||||
"monitorKafka": {
|
||||
"title": "Monitor kafka",
|
||||
"description": "Add your Kafka source to gain insights and enhance activity tracking.",
|
||||
"button": "Get Started"
|
||||
},
|
||||
"summarySection": {
|
||||
"viewDetailsButton": "View Details"
|
||||
},
|
||||
"confirmModal": {
|
||||
"content": "Before navigating to the details page, please make sure you have configured all the required setup to ensure correct data monitoring.",
|
||||
"okText": "Proceed"
|
||||
}
|
||||
}
|
||||
@@ -40,8 +40,10 @@
|
||||
"option_atleastonce": "at least once",
|
||||
"option_onaverage": "on average",
|
||||
"option_intotal": "in total",
|
||||
"option_last": "last",
|
||||
"option_above": "above",
|
||||
"option_below": "below",
|
||||
"option_above_below": "above/below",
|
||||
"option_equal": "is equal to",
|
||||
"option_notequal": "not equal to",
|
||||
"button_query": "Query",
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
{
|
||||
"rps_over_100": "You are sending data at more than 100 RPS, your ingestion may be rate limited. Please reach out to us via Intercom support."
|
||||
"rps_over_100": "You are sending data at more than 100 RPS, your ingestion may be rate limited. Please reach out to us via Intercom support or "
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
"SERVICE_METRICS": "SigNoz | Service Metrics",
|
||||
"SERVICE_MAP": "SigNoz | Service Map",
|
||||
"GET_STARTED": "SigNoz | Get Started",
|
||||
"ONBOARDING": "SigNoz | Get Started",
|
||||
"GET_STARTED_APPLICATION_MONITORING": "SigNoz | Get Started | APM",
|
||||
"GET_STARTED_LOGS_MANAGEMENT": "SigNoz | Get Started | Logs",
|
||||
"GET_STARTED_INFRASTRUCTURE_MONITORING": "SigNoz | Get Started | Infrastructure",
|
||||
@@ -49,5 +50,8 @@
|
||||
"TRACES_SAVE_VIEWS": "SigNoz | Traces Saved Views",
|
||||
"DEFAULT": "Open source Observability Platform | SigNoz",
|
||||
"SHORTCUTS": "SigNoz | Shortcuts",
|
||||
"INTEGRATIONS": "SigNoz | Integrations"
|
||||
"INTEGRATIONS": "SigNoz | Integrations",
|
||||
"ALERT_HISTORY": "SigNoz | Alert Rule History",
|
||||
"ALERT_OVERVIEW": "SigNoz | Alert Rule Overview",
|
||||
"MESSAGING_QUEUES": "SigNoz | Messaging Queues"
|
||||
}
|
||||
|
||||
22
frontend/public/locales/en/workspaceLocked.json
Normal file
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"trialPlanExpired": "Trial Plan Expired",
|
||||
"gotQuestions": "Got Questions?",
|
||||
"contactUs": "Contact Us",
|
||||
"upgradeToContinue": "Upgrade to Continue",
|
||||
"upgradeNow": "Upgrade now to keep enjoying all the great features you’ve been using.",
|
||||
"yourDataIsSafe": "Your data is safe with us until",
|
||||
"actNow": "Act now to avoid any disruptions and continue where you left off.",
|
||||
"contactAdmin": "Contact your admin to proceed with the upgrade.",
|
||||
"continueMyJourney": "Continue My Journey",
|
||||
"needMoreTime": "Need More Time?",
|
||||
"extendTrial": "Extend Trial",
|
||||
"extendTrialMsgPart1": "If you have a specific reason why you were not able to finish your PoC in the trial period, please write to us on",
|
||||
"extendTrialMsgPart2": "with the reason. Sometimes we can extend trial by a few days on a case by case basis",
|
||||
"whyChooseSignoz": "Why choose Signoz",
|
||||
"enterpriseGradeObservability": "Enterprise-grade Observability",
|
||||
"observabilityDescription": "Get access to observability at any scale with advanced security and compliance.",
|
||||
"continueToUpgrade": "Continue to Upgrade",
|
||||
"youAreInGoodCompany": "You are in good company",
|
||||
"faqs": "FAQs",
|
||||
"somethingWentWrong": "Something went wrong"
|
||||
}
|
||||
|
Before Width: | Height: | Size: 10 KiB |
@@ -76,9 +76,8 @@ function PrivateRoute({ children }: PrivateRouteProps): JSX.Element {
|
||||
isUserFetching: false,
|
||||
},
|
||||
});
|
||||
|
||||
if (!isLoggedIn) {
|
||||
history.push(ROUTES.LOGIN);
|
||||
history.push(ROUTES.LOGIN, { from: pathname });
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { ConfigProvider } from 'antd';
|
||||
import getLocalStorageApi from 'api/browser/localstorage/get';
|
||||
import setLocalStorageApi from 'api/browser/localstorage/set';
|
||||
import logEvent from 'api/common/logEvent';
|
||||
import NotFound from 'components/NotFound';
|
||||
import Spinner from 'components/Spinner';
|
||||
import { FeatureKeys } from 'constants/features';
|
||||
@@ -11,6 +12,7 @@ import useAnalytics from 'hooks/analytics/useAnalytics';
|
||||
import { KeyboardHotkeysProvider } from 'hooks/hotkeys/useKeyboardHotkeys';
|
||||
import { useIsDarkMode, useThemeConfig } from 'hooks/useDarkMode';
|
||||
import { THEME_MODE } from 'hooks/useDarkMode/constant';
|
||||
import useFeatureFlags from 'hooks/useFeatureFlag';
|
||||
import useGetFeatureFlag from 'hooks/useGetFeatureFlag';
|
||||
import useLicense, { LICENSE_PLAN_KEY } from 'hooks/useLicense';
|
||||
import { NotificationProvider } from 'hooks/useNotifications';
|
||||
@@ -18,6 +20,7 @@ import { ResourceProvider } from 'hooks/useResourceAttribute';
|
||||
import history from 'lib/history';
|
||||
import { identity, pick, pickBy } from 'lodash-es';
|
||||
import posthog from 'posthog-js';
|
||||
import AlertRuleProvider from 'providers/Alert';
|
||||
import { DashboardProvider } from 'providers/Dashboard/Dashboard';
|
||||
import { QueryBuilderProvider } from 'providers/QueryBuilder';
|
||||
import { Suspense, useEffect, useState } from 'react';
|
||||
@@ -48,7 +51,7 @@ function App(): JSX.Element {
|
||||
|
||||
const dispatch = useDispatch<Dispatch<AppActions>>();
|
||||
|
||||
const { trackPageView, trackEvent } = useAnalytics();
|
||||
const { trackPageView } = useAnalytics();
|
||||
|
||||
const { hostname, pathname } = window.location;
|
||||
|
||||
@@ -56,15 +59,13 @@ function App(): JSX.Element {
|
||||
|
||||
const isDarkMode = useIsDarkMode();
|
||||
|
||||
const isChatSupportEnabled =
|
||||
useFeatureFlags(FeatureKeys.CHAT_SUPPORT)?.active || false;
|
||||
|
||||
const isPremiumSupportEnabled =
|
||||
useFeatureFlags(FeatureKeys.PREMIUM_SUPPORT)?.active || false;
|
||||
|
||||
const featureResponse = useGetFeatureFlag((allFlags) => {
|
||||
const isOnboardingEnabled =
|
||||
allFlags.find((flag) => flag.name === FeatureKeys.ONBOARDING)?.active ||
|
||||
false;
|
||||
|
||||
const isChatSupportEnabled =
|
||||
allFlags.find((flag) => flag.name === FeatureKeys.CHAT_SUPPORT)?.active ||
|
||||
false;
|
||||
|
||||
dispatch({
|
||||
type: UPDATE_FEATURE_FLAG_RESPONSE,
|
||||
payload: {
|
||||
@@ -73,6 +74,10 @@ function App(): JSX.Element {
|
||||
},
|
||||
});
|
||||
|
||||
const isOnboardingEnabled =
|
||||
allFlags.find((flag) => flag.name === FeatureKeys.ONBOARDING)?.active ||
|
||||
false;
|
||||
|
||||
if (!isOnboardingEnabled || !isCloudUserVal) {
|
||||
const newRoutes = routes.filter(
|
||||
(route) => route?.path !== ROUTES.GET_STARTED,
|
||||
@@ -80,16 +85,6 @@ function App(): JSX.Element {
|
||||
|
||||
setRoutes(newRoutes);
|
||||
}
|
||||
|
||||
if (isLoggedInState && isChatSupportEnabled) {
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
window.Intercom('boot', {
|
||||
app_id: process.env.INTERCOM_APP_ID,
|
||||
email: user?.email || '',
|
||||
name: user?.name || '',
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
const isOnBasicPlan =
|
||||
@@ -127,7 +122,6 @@ function App(): JSX.Element {
|
||||
|
||||
window.analytics.identify(email, sanitizedIdentifyPayload);
|
||||
window.analytics.group(domain, groupTraits);
|
||||
window.clarity('identify', email, name);
|
||||
|
||||
posthog?.identify(email, {
|
||||
email,
|
||||
@@ -192,6 +186,26 @@ function App(): JSX.Element {
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [pathname]);
|
||||
|
||||
useEffect(() => {
|
||||
const showAddCreditCardModal =
|
||||
!isPremiumSupportEnabled &&
|
||||
!licenseData?.payload?.trialConvertedToSubscription;
|
||||
|
||||
if (isLoggedInState && isChatSupportEnabled && !showAddCreditCardModal) {
|
||||
window.Intercom('boot', {
|
||||
app_id: process.env.INTERCOM_APP_ID,
|
||||
email: user?.email || '',
|
||||
name: user?.name || '',
|
||||
});
|
||||
}
|
||||
}, [
|
||||
isLoggedInState,
|
||||
isChatSupportEnabled,
|
||||
user,
|
||||
licenseData,
|
||||
isPremiumSupportEnabled,
|
||||
]);
|
||||
|
||||
useEffect(() => {
|
||||
if (user && user?.email && user?.userId && user?.name) {
|
||||
try {
|
||||
@@ -199,7 +213,7 @@ function App(): JSX.Element {
|
||||
LOCALSTORAGE.THEME_ANALYTICS_V1,
|
||||
);
|
||||
if (!isThemeAnalyticsSent) {
|
||||
trackEvent('Theme Analytics', {
|
||||
logEvent('Theme Analytics', {
|
||||
theme: isDarkMode ? THEME_MODE.DARK : THEME_MODE.LIGHT,
|
||||
user: pick(user, ['email', 'userId', 'name']),
|
||||
org,
|
||||
@@ -218,6 +232,10 @@ function App(): JSX.Element {
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [user]);
|
||||
|
||||
useEffect(() => {
|
||||
console.info('We are hiring! https://jobs.gem.com/signoz');
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<ConfigProvider theme={themeConfig}>
|
||||
<Router history={history}>
|
||||
@@ -227,22 +245,24 @@ function App(): JSX.Element {
|
||||
<QueryBuilderProvider>
|
||||
<DashboardProvider>
|
||||
<KeyboardHotkeysProvider>
|
||||
<AppLayout>
|
||||
<Suspense fallback={<Spinner size="large" tip="Loading..." />}>
|
||||
<Switch>
|
||||
{routes.map(({ path, component, exact }) => (
|
||||
<Route
|
||||
key={`${path}`}
|
||||
exact={exact}
|
||||
path={path}
|
||||
component={component}
|
||||
/>
|
||||
))}
|
||||
<AlertRuleProvider>
|
||||
<AppLayout>
|
||||
<Suspense fallback={<Spinner size="large" tip="Loading..." />}>
|
||||
<Switch>
|
||||
{routes.map(({ path, component, exact }) => (
|
||||
<Route
|
||||
key={`${path}`}
|
||||
exact={exact}
|
||||
path={path}
|
||||
component={component}
|
||||
/>
|
||||
))}
|
||||
|
||||
<Route path="*" component={NotFound} />
|
||||
</Switch>
|
||||
</Suspense>
|
||||
</AppLayout>
|
||||
<Route path="*" component={NotFound} />
|
||||
</Switch>
|
||||
</Suspense>
|
||||
</AppLayout>
|
||||
</AlertRuleProvider>
|
||||
</KeyboardHotkeysProvider>
|
||||
</DashboardProvider>
|
||||
</QueryBuilderProvider>
|
||||
|
||||
@@ -66,6 +66,10 @@ export const Onboarding = Loadable(
|
||||
() => import(/* webpackChunkName: "Onboarding" */ 'pages/OnboardingPage'),
|
||||
);
|
||||
|
||||
export const OnboardingV2 = Loadable(
|
||||
() => import(/* webpackChunkName: "Onboarding" */ 'pages/OnboardingPageV2'),
|
||||
);
|
||||
|
||||
export const DashboardPage = Loadable(
|
||||
() =>
|
||||
import(/* webpackChunkName: "DashboardPage" */ 'pages/DashboardsListPage'),
|
||||
@@ -92,6 +96,14 @@ export const CreateNewAlerts = Loadable(
|
||||
() => import(/* webpackChunkName: "Create Alerts" */ 'pages/CreateAlert'),
|
||||
);
|
||||
|
||||
export const AlertHistory = Loadable(
|
||||
() => import(/* webpackChunkName: "Alert History" */ 'pages/AlertList'),
|
||||
);
|
||||
|
||||
export const AlertOverview = Loadable(
|
||||
() => import(/* webpackChunkName: "Alert Overview" */ 'pages/AlertList'),
|
||||
);
|
||||
|
||||
export const CreateAlertChannelAlerts = Loadable(
|
||||
() =>
|
||||
import(/* webpackChunkName: "Create Channels" */ 'pages/AlertChannelCreate'),
|
||||
@@ -204,3 +216,15 @@ export const InstalledIntegrations = Loadable(
|
||||
/* webpackChunkName: "InstalledIntegrations" */ 'pages/IntegrationsModulePage'
|
||||
),
|
||||
);
|
||||
|
||||
export const MessagingQueues = Loadable(
|
||||
() =>
|
||||
import(/* webpackChunkName: "MessagingQueues" */ 'pages/MessagingQueues'),
|
||||
);
|
||||
|
||||
export const MQDetailPage = Loadable(
|
||||
() =>
|
||||
import(
|
||||
/* webpackChunkName: "MQDetailPage" */ 'pages/MessagingQueues/MQDetailPage'
|
||||
),
|
||||
);
|
||||
|
||||
@@ -2,6 +2,8 @@ import ROUTES from 'constants/routes';
|
||||
import { RouteProps } from 'react-router-dom';
|
||||
|
||||
import {
|
||||
AlertHistory,
|
||||
AlertOverview,
|
||||
AllAlertChannels,
|
||||
AllErrors,
|
||||
APIKeys,
|
||||
@@ -23,10 +25,13 @@ import {
|
||||
LogsExplorer,
|
||||
LogsIndexToFields,
|
||||
LogsSaveViews,
|
||||
MessagingQueues,
|
||||
MQDetailPage,
|
||||
MySettings,
|
||||
NewDashboardPage,
|
||||
OldLogsExplorer,
|
||||
Onboarding,
|
||||
OnboardingV2,
|
||||
OrganizationSettings,
|
||||
PasswordReset,
|
||||
PipelinePage,
|
||||
@@ -64,6 +69,13 @@ const routes: AppRoutes[] = [
|
||||
isPrivate: true,
|
||||
key: 'GET_STARTED',
|
||||
},
|
||||
{
|
||||
path: ROUTES.ONBOARDING,
|
||||
exact: false,
|
||||
component: OnboardingV2,
|
||||
isPrivate: true,
|
||||
key: 'ONBOARDING',
|
||||
},
|
||||
{
|
||||
component: LogsIndexToFields,
|
||||
path: ROUTES.LOGS_INDEX_FIELDS,
|
||||
@@ -169,6 +181,20 @@ const routes: AppRoutes[] = [
|
||||
isPrivate: true,
|
||||
key: 'ALERTS_NEW',
|
||||
},
|
||||
{
|
||||
path: ROUTES.ALERT_HISTORY,
|
||||
exact: true,
|
||||
component: AlertHistory,
|
||||
isPrivate: true,
|
||||
key: 'ALERT_HISTORY',
|
||||
},
|
||||
{
|
||||
path: ROUTES.ALERT_OVERVIEW,
|
||||
exact: true,
|
||||
component: AlertOverview,
|
||||
isPrivate: true,
|
||||
key: 'ALERT_OVERVIEW',
|
||||
},
|
||||
{
|
||||
path: ROUTES.TRACE,
|
||||
exact: true,
|
||||
@@ -351,6 +377,20 @@ const routes: AppRoutes[] = [
|
||||
isPrivate: true,
|
||||
key: 'INTEGRATIONS',
|
||||
},
|
||||
{
|
||||
path: ROUTES.MESSAGING_QUEUES,
|
||||
exact: true,
|
||||
component: MessagingQueues,
|
||||
key: 'MESSAGING_QUEUES',
|
||||
isPrivate: true,
|
||||
},
|
||||
{
|
||||
path: ROUTES.MESSAGING_QUEUES_DETAIL,
|
||||
exact: true,
|
||||
component: MQDetailPage,
|
||||
key: 'MESSAGING_QUEUES_DETAIL',
|
||||
isPrivate: true,
|
||||
},
|
||||
];
|
||||
|
||||
export const SUPPORT_ROUTE: AppRoutes = {
|
||||
|
||||
@@ -9,9 +9,9 @@ export function ErrorResponseHandler(error: AxiosError): ErrorResponse {
|
||||
// making the error status code as standard Error Status Code
|
||||
const statusCode = response.status as ErrorStatusCode;
|
||||
|
||||
if (statusCode >= 400 && statusCode < 500) {
|
||||
const { data } = response as AxiosResponse;
|
||||
const { data } = response as AxiosResponse;
|
||||
|
||||
if (statusCode >= 400 && statusCode < 500) {
|
||||
if (statusCode === 404) {
|
||||
return {
|
||||
statusCode,
|
||||
@@ -34,12 +34,11 @@ export function ErrorResponseHandler(error: AxiosError): ErrorResponse {
|
||||
body: JSON.stringify((response.data as any).data),
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
statusCode,
|
||||
payload: null,
|
||||
error: 'Something went wrong',
|
||||
message: null,
|
||||
message: data?.error,
|
||||
};
|
||||
}
|
||||
if (request) {
|
||||
|
||||
@@ -1,26 +1,20 @@
|
||||
import axios from 'api';
|
||||
import { ErrorResponseHandler } from 'api/ErrorResponseHandler';
|
||||
import { AxiosError } from 'axios';
|
||||
import { ErrorResponse, SuccessResponse } from 'types/api';
|
||||
import { PayloadProps, Props } from 'types/api/alerts/create';
|
||||
|
||||
const create = async (
|
||||
props: Props,
|
||||
): Promise<SuccessResponse<PayloadProps> | ErrorResponse> => {
|
||||
try {
|
||||
const response = await axios.post('/rules', {
|
||||
...props.data,
|
||||
});
|
||||
const response = await axios.post('/rules', {
|
||||
...props.data,
|
||||
});
|
||||
|
||||
return {
|
||||
statusCode: 200,
|
||||
error: null,
|
||||
message: response.data.status,
|
||||
payload: response.data.data,
|
||||
};
|
||||
} catch (error) {
|
||||
return ErrorResponseHandler(error as AxiosError);
|
||||
}
|
||||
return {
|
||||
statusCode: 200,
|
||||
error: null,
|
||||
message: response.data.status,
|
||||
payload: response.data.data,
|
||||
};
|
||||
};
|
||||
|
||||
export default create;
|
||||
|
||||
@@ -1,24 +1,18 @@
|
||||
import axios from 'api';
|
||||
import { ErrorResponseHandler } from 'api/ErrorResponseHandler';
|
||||
import { AxiosError } from 'axios';
|
||||
import { ErrorResponse, SuccessResponse } from 'types/api';
|
||||
import { PayloadProps, Props } from 'types/api/alerts/delete';
|
||||
|
||||
const deleteAlerts = async (
|
||||
props: Props,
|
||||
): Promise<SuccessResponse<PayloadProps> | ErrorResponse> => {
|
||||
try {
|
||||
const response = await axios.delete(`/rules/${props.id}`);
|
||||
const response = await axios.delete(`/rules/${props.id}`);
|
||||
|
||||
return {
|
||||
statusCode: 200,
|
||||
error: null,
|
||||
message: response.data.status,
|
||||
payload: response.data.data.rules,
|
||||
};
|
||||
} catch (error) {
|
||||
return ErrorResponseHandler(error as AxiosError);
|
||||
}
|
||||
return {
|
||||
statusCode: 200,
|
||||
error: null,
|
||||
message: response.data.status,
|
||||
payload: response.data.data.rules,
|
||||
};
|
||||
};
|
||||
|
||||
export default deleteAlerts;
|
||||
|
||||
@@ -1,24 +1,16 @@
|
||||
import axios from 'api';
|
||||
import { ErrorResponseHandler } from 'api/ErrorResponseHandler';
|
||||
import { AxiosError } from 'axios';
|
||||
import { ErrorResponse, SuccessResponse } from 'types/api';
|
||||
import { PayloadProps, Props } from 'types/api/alerts/get';
|
||||
|
||||
const get = async (
|
||||
props: Props,
|
||||
): Promise<SuccessResponse<PayloadProps> | ErrorResponse> => {
|
||||
try {
|
||||
const response = await axios.get(`/rules/${props.id}`);
|
||||
|
||||
return {
|
||||
statusCode: 200,
|
||||
error: null,
|
||||
message: response.data.status,
|
||||
payload: response.data,
|
||||
};
|
||||
} catch (error) {
|
||||
return ErrorResponseHandler(error as AxiosError);
|
||||
}
|
||||
const response = await axios.get(`/rules/${props.id}`);
|
||||
return {
|
||||
statusCode: 200,
|
||||
error: null,
|
||||
message: response.data.status,
|
||||
payload: response.data,
|
||||
};
|
||||
};
|
||||
|
||||
export default get;
|
||||
|
||||
@@ -1,26 +1,20 @@
|
||||
import axios from 'api';
|
||||
import { ErrorResponseHandler } from 'api/ErrorResponseHandler';
|
||||
import { AxiosError } from 'axios';
|
||||
import { ErrorResponse, SuccessResponse } from 'types/api';
|
||||
import { PayloadProps, Props } from 'types/api/alerts/patch';
|
||||
|
||||
const patch = async (
|
||||
props: Props,
|
||||
): Promise<SuccessResponse<PayloadProps> | ErrorResponse> => {
|
||||
try {
|
||||
const response = await axios.patch(`/rules/${props.id}`, {
|
||||
...props.data,
|
||||
});
|
||||
const response = await axios.patch(`/rules/${props.id}`, {
|
||||
...props.data,
|
||||
});
|
||||
|
||||
return {
|
||||
statusCode: 200,
|
||||
error: null,
|
||||
message: response.data.status,
|
||||
payload: response.data.data,
|
||||
};
|
||||
} catch (error) {
|
||||
return ErrorResponseHandler(error as AxiosError);
|
||||
}
|
||||
return {
|
||||
statusCode: 200,
|
||||
error: null,
|
||||
message: response.data.status,
|
||||
payload: response.data.data,
|
||||
};
|
||||
};
|
||||
|
||||
export default patch;
|
||||
|
||||
@@ -1,26 +1,20 @@
|
||||
import axios from 'api';
|
||||
import { ErrorResponseHandler } from 'api/ErrorResponseHandler';
|
||||
import { AxiosError } from 'axios';
|
||||
import { ErrorResponse, SuccessResponse } from 'types/api';
|
||||
import { PayloadProps, Props } from 'types/api/alerts/save';
|
||||
|
||||
const put = async (
|
||||
props: Props,
|
||||
): Promise<SuccessResponse<PayloadProps> | ErrorResponse> => {
|
||||
try {
|
||||
const response = await axios.put(`/rules/${props.id}`, {
|
||||
...props.data,
|
||||
});
|
||||
const response = await axios.put(`/rules/${props.id}`, {
|
||||
...props.data,
|
||||
});
|
||||
|
||||
return {
|
||||
statusCode: 200,
|
||||
error: null,
|
||||
message: response.data.status,
|
||||
payload: response.data.data,
|
||||
};
|
||||
} catch (error) {
|
||||
return ErrorResponseHandler(error as AxiosError);
|
||||
}
|
||||
return {
|
||||
statusCode: 200,
|
||||
error: null,
|
||||
message: response.data.status,
|
||||
payload: response.data.data,
|
||||
};
|
||||
};
|
||||
|
||||
export default put;
|
||||
|
||||
28
frontend/src/api/alerts/ruleStats.ts
Normal file
@@ -0,0 +1,28 @@
|
||||
import axios from 'api';
|
||||
import { ErrorResponseHandler } from 'api/ErrorResponseHandler';
|
||||
import { AxiosError } from 'axios';
|
||||
import { ErrorResponse, SuccessResponse } from 'types/api';
|
||||
import { AlertRuleStatsPayload } from 'types/api/alerts/def';
|
||||
import { RuleStatsProps } from 'types/api/alerts/ruleStats';
|
||||
|
||||
const ruleStats = async (
|
||||
props: RuleStatsProps,
|
||||
): Promise<SuccessResponse<AlertRuleStatsPayload> | ErrorResponse> => {
|
||||
try {
|
||||
const response = await axios.post(`/rules/${props.id}/history/stats`, {
|
||||
start: props.start,
|
||||
end: props.end,
|
||||
});
|
||||
|
||||
return {
|
||||
statusCode: 200,
|
||||
error: null,
|
||||
message: response.data.status,
|
||||
payload: response.data,
|
||||
};
|
||||
} catch (error) {
|
||||
return ErrorResponseHandler(error as AxiosError);
|
||||
}
|
||||
};
|
||||
|
||||
export default ruleStats;
|
||||
33
frontend/src/api/alerts/timelineGraph.ts
Normal file
@@ -0,0 +1,33 @@
|
||||
import axios from 'api';
|
||||
import { ErrorResponseHandler } from 'api/ErrorResponseHandler';
|
||||
import { AxiosError } from 'axios';
|
||||
import { ErrorResponse, SuccessResponse } from 'types/api';
|
||||
import { AlertRuleTimelineGraphResponsePayload } from 'types/api/alerts/def';
|
||||
import { GetTimelineGraphRequestProps } from 'types/api/alerts/timelineGraph';
|
||||
|
||||
const timelineGraph = async (
|
||||
props: GetTimelineGraphRequestProps,
|
||||
): Promise<
|
||||
SuccessResponse<AlertRuleTimelineGraphResponsePayload> | ErrorResponse
|
||||
> => {
|
||||
try {
|
||||
const response = await axios.post(
|
||||
`/rules/${props.id}/history/overall_status`,
|
||||
{
|
||||
start: props.start,
|
||||
end: props.end,
|
||||
},
|
||||
);
|
||||
|
||||
return {
|
||||
statusCode: 200,
|
||||
error: null,
|
||||
message: response.data.status,
|
||||
payload: response.data,
|
||||
};
|
||||
} catch (error) {
|
||||
return ErrorResponseHandler(error as AxiosError);
|
||||
}
|
||||
};
|
||||
|
||||
export default timelineGraph;
|
||||
36
frontend/src/api/alerts/timelineTable.ts
Normal file
@@ -0,0 +1,36 @@
|
||||
import axios from 'api';
|
||||
import { ErrorResponseHandler } from 'api/ErrorResponseHandler';
|
||||
import { AxiosError } from 'axios';
|
||||
import { ErrorResponse, SuccessResponse } from 'types/api';
|
||||
import { AlertRuleTimelineTableResponsePayload } from 'types/api/alerts/def';
|
||||
import { GetTimelineTableRequestProps } from 'types/api/alerts/timelineTable';
|
||||
|
||||
const timelineTable = async (
|
||||
props: GetTimelineTableRequestProps,
|
||||
): Promise<
|
||||
SuccessResponse<AlertRuleTimelineTableResponsePayload> | ErrorResponse
|
||||
> => {
|
||||
try {
|
||||
const response = await axios.post(`/rules/${props.id}/history/timeline`, {
|
||||
start: props.start,
|
||||
end: props.end,
|
||||
offset: props.offset,
|
||||
limit: props.limit,
|
||||
order: props.order,
|
||||
state: props.state,
|
||||
// TODO(shaheer): implement filters
|
||||
filters: props.filters,
|
||||
});
|
||||
|
||||
return {
|
||||
statusCode: 200,
|
||||
error: null,
|
||||
message: response.data.status,
|
||||
payload: response.data,
|
||||
};
|
||||
} catch (error) {
|
||||
return ErrorResponseHandler(error as AxiosError);
|
||||
}
|
||||
};
|
||||
|
||||
export default timelineTable;
|
||||
33
frontend/src/api/alerts/topContributors.ts
Normal file
@@ -0,0 +1,33 @@
|
||||
import axios from 'api';
|
||||
import { ErrorResponseHandler } from 'api/ErrorResponseHandler';
|
||||
import { AxiosError } from 'axios';
|
||||
import { ErrorResponse, SuccessResponse } from 'types/api';
|
||||
import { AlertRuleTopContributorsPayload } from 'types/api/alerts/def';
|
||||
import { TopContributorsProps } from 'types/api/alerts/topContributors';
|
||||
|
||||
const topContributors = async (
|
||||
props: TopContributorsProps,
|
||||
): Promise<
|
||||
SuccessResponse<AlertRuleTopContributorsPayload> | ErrorResponse
|
||||
> => {
|
||||
try {
|
||||
const response = await axios.post(
|
||||
`/rules/${props.id}/history/top_contributors`,
|
||||
{
|
||||
start: props.start,
|
||||
end: props.end,
|
||||
},
|
||||
);
|
||||
|
||||
return {
|
||||
statusCode: 200,
|
||||
error: null,
|
||||
message: response.data.status,
|
||||
payload: response.data,
|
||||
};
|
||||
} catch (error) {
|
||||
return ErrorResponseHandler(error as AxiosError);
|
||||
}
|
||||
};
|
||||
|
||||
export default topContributors;
|
||||
@@ -3,7 +3,8 @@ const apiV1 = '/api/v1/';
|
||||
export const apiV2 = '/api/v2/';
|
||||
export const apiV3 = '/api/v3/';
|
||||
export const apiV4 = '/api/v4/';
|
||||
export const gatewayApiV1 = '/api/gateway/v1';
|
||||
export const apiAlertManager = '/api/alertmanager';
|
||||
export const gatewayApiV1 = '/api/gateway/v1/';
|
||||
export const gatewayApiV2 = '/api/gateway/v2/';
|
||||
export const apiAlertManager = '/api/alertmanager/';
|
||||
|
||||
export default apiV1;
|
||||
|
||||
62
frontend/src/api/common/getQueryStats.ts
Normal file
@@ -0,0 +1,62 @@
|
||||
import getLocalStorageApi from 'api/browser/localstorage/get';
|
||||
import { ENVIRONMENT } from 'constants/env';
|
||||
import { LOCALSTORAGE } from 'constants/localStorage';
|
||||
import { isEmpty } from 'lodash-es';
|
||||
|
||||
export interface WsDataEvent {
|
||||
read_rows: number;
|
||||
read_bytes: number;
|
||||
elapsed_ms: number;
|
||||
}
|
||||
interface GetQueryStatsProps {
|
||||
queryId: string;
|
||||
setData: React.Dispatch<React.SetStateAction<WsDataEvent | undefined>>;
|
||||
}
|
||||
|
||||
function getURL(baseURL: string, queryId: string): URL | string {
|
||||
if (baseURL && !isEmpty(baseURL)) {
|
||||
return `${baseURL}/ws/query_progress?q=${queryId}`;
|
||||
}
|
||||
const url = new URL(`/ws/query_progress?q=${queryId}`, window.location.href);
|
||||
|
||||
if (window.location.protocol === 'http:') {
|
||||
url.protocol = 'ws';
|
||||
} else {
|
||||
url.protocol = 'wss';
|
||||
}
|
||||
|
||||
return url;
|
||||
}
|
||||
|
||||
export function getQueryStats(props: GetQueryStatsProps): void {
|
||||
const { queryId, setData } = props;
|
||||
|
||||
const token = getLocalStorageApi(LOCALSTORAGE.AUTH_TOKEN) || '';
|
||||
|
||||
// https://github.com/whatwg/websockets/issues/20 reason for not using the relative URLs
|
||||
const url = getURL(ENVIRONMENT.wsURL, queryId);
|
||||
|
||||
const socket = new WebSocket(url, token);
|
||||
|
||||
socket.addEventListener('message', (event) => {
|
||||
try {
|
||||
const parsedData = JSON.parse(event?.data);
|
||||
setData(parsedData);
|
||||
} catch {
|
||||
setData(event?.data);
|
||||
}
|
||||
});
|
||||
|
||||
socket.addEventListener('error', (event) => {
|
||||
console.error(event);
|
||||
});
|
||||
|
||||
socket.addEventListener('close', (event) => {
|
||||
// 1000 is a normal closure status code
|
||||
if (event.code !== 1000) {
|
||||
console.error('WebSocket closed with error:', event);
|
||||
} else {
|
||||
console.error('WebSocket closed normally.');
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
import axios from 'api';
|
||||
import { ApiBaseInstance as axios } from 'api';
|
||||
import { ErrorResponseHandler } from 'api/ErrorResponseHandler';
|
||||
import { AxiosError } from 'axios';
|
||||
import { ErrorResponse, SuccessResponse } from 'types/api';
|
||||
@@ -21,6 +21,7 @@ const logEvent = async (
|
||||
payload: response.data.data,
|
||||
};
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return ErrorResponseHandler(error as AxiosError);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import { ApiV2Instance as axios } from 'api';
|
||||
import { ErrorResponseHandler } from 'api/ErrorResponseHandler';
|
||||
import { AxiosError } from 'axios';
|
||||
import getStartEndRangeTime from 'lib/getStartEndRangeTime';
|
||||
import store from 'store';
|
||||
import { ErrorResponse, SuccessResponse } from 'types/api';
|
||||
import {
|
||||
Props,
|
||||
@@ -11,7 +13,26 @@ const dashboardVariablesQuery = async (
|
||||
props: Props,
|
||||
): Promise<SuccessResponse<VariableResponseProps> | ErrorResponse> => {
|
||||
try {
|
||||
const response = await axios.post(`/variables/query`, props);
|
||||
const { globalTime } = store.getState();
|
||||
const { start, end } = getStartEndRangeTime({
|
||||
type: 'GLOBAL_TIME',
|
||||
interval: globalTime.selectedTime,
|
||||
});
|
||||
|
||||
const timeVariables: Record<string, number> = {
|
||||
start_timestamp_ms: parseInt(start, 10) * 1e3,
|
||||
end_timestamp_ms: parseInt(end, 10) * 1e3,
|
||||
start_timestamp_nano: parseInt(start, 10) * 1e9,
|
||||
end_timestamp_nano: parseInt(end, 10) * 1e9,
|
||||
start_timestamp: parseInt(start, 10),
|
||||
end_timestamp: parseInt(end, 10),
|
||||
};
|
||||
|
||||
const payload = { ...props };
|
||||
|
||||
payload.variables = { ...payload.variables, ...timeVariables };
|
||||
|
||||
const response = await axios.post(`/variables/query`, payload);
|
||||
|
||||
return {
|
||||
statusCode: 200,
|
||||
|
||||
@@ -15,6 +15,7 @@ import apiV1, {
|
||||
apiV3,
|
||||
apiV4,
|
||||
gatewayApiV1,
|
||||
gatewayApiV2,
|
||||
} from './apiV1';
|
||||
import { Logout } from './utils';
|
||||
|
||||
@@ -96,6 +97,10 @@ const interceptorRejected = async (
|
||||
}
|
||||
};
|
||||
|
||||
const interceptorRejectedBase = async (
|
||||
value: AxiosResponse<any>,
|
||||
): Promise<AxiosResponse<any>> => Promise.reject(value);
|
||||
|
||||
const instance = axios.create({
|
||||
baseURL: `${ENVIRONMENT.baseURL}${apiV1}`,
|
||||
});
|
||||
@@ -140,6 +145,18 @@ ApiV4Instance.interceptors.response.use(
|
||||
ApiV4Instance.interceptors.request.use(interceptorsRequestResponse);
|
||||
//
|
||||
|
||||
// axios Base
|
||||
export const ApiBaseInstance = axios.create({
|
||||
baseURL: `${ENVIRONMENT.baseURL}${apiV1}`,
|
||||
});
|
||||
|
||||
ApiBaseInstance.interceptors.response.use(
|
||||
interceptorsResponse,
|
||||
interceptorRejectedBase,
|
||||
);
|
||||
ApiBaseInstance.interceptors.request.use(interceptorsRequestResponse);
|
||||
//
|
||||
|
||||
// gateway Api V1
|
||||
export const GatewayApiV1Instance = axios.create({
|
||||
baseURL: `${ENVIRONMENT.baseURL}${gatewayApiV1}`,
|
||||
@@ -153,6 +170,19 @@ GatewayApiV1Instance.interceptors.response.use(
|
||||
GatewayApiV1Instance.interceptors.request.use(interceptorsRequestResponse);
|
||||
//
|
||||
|
||||
// gateway Api V2
|
||||
export const GatewayApiV2Instance = axios.create({
|
||||
baseURL: `${ENVIRONMENT.baseURL}${gatewayApiV2}`,
|
||||
});
|
||||
|
||||
GatewayApiV2Instance.interceptors.response.use(
|
||||
interceptorsResponse,
|
||||
interceptorRejected,
|
||||
);
|
||||
|
||||
GatewayApiV2Instance.interceptors.request.use(interceptorsRequestResponse);
|
||||
//
|
||||
|
||||
AxiosAlertManagerInstance.interceptors.response.use(
|
||||
interceptorsResponse,
|
||||
interceptorRejected,
|
||||
|
||||
@@ -12,10 +12,13 @@ export const getMetricsQueryRange = async (
|
||||
props: QueryRangePayload,
|
||||
version: string,
|
||||
signal: AbortSignal,
|
||||
headers?: Record<string, string>,
|
||||
): Promise<SuccessResponse<MetricRangePayloadV3> | ErrorResponse> => {
|
||||
try {
|
||||
if (version && version === ENTITY_VERSION_V4) {
|
||||
const response = await ApiV4Instance.post('/query_range', props, { signal });
|
||||
const response = await ApiV4Instance.post('/query_range', props, {
|
||||
signal,
|
||||
});
|
||||
|
||||
return {
|
||||
statusCode: 200,
|
||||
@@ -26,7 +29,10 @@ export const getMetricsQueryRange = async (
|
||||
};
|
||||
}
|
||||
|
||||
const response = await ApiV3Instance.post('/query_range', props, { signal });
|
||||
const response = await ApiV3Instance.post('/query_range', props, {
|
||||
signal,
|
||||
headers,
|
||||
});
|
||||
|
||||
return {
|
||||
statusCode: 200,
|
||||
|
||||
@@ -1,7 +1,20 @@
|
||||
import axios from 'api';
|
||||
import { isNil } from 'lodash-es';
|
||||
|
||||
const getTopLevelOperations = async (): Promise<ServiceDataProps> => {
|
||||
const response = await axios.post(`/service/top_level_operations`);
|
||||
interface GetTopLevelOperationsProps {
|
||||
service?: string;
|
||||
start?: number;
|
||||
end?: number;
|
||||
}
|
||||
|
||||
const getTopLevelOperations = async (
|
||||
props: GetTopLevelOperationsProps,
|
||||
): Promise<ServiceDataProps> => {
|
||||
const response = await axios.post(`/service/top_level_operations`, {
|
||||
start: !isNil(props.start) ? `${props.start}` : undefined,
|
||||
end: !isNil(props.end) ? `${props.end}` : undefined,
|
||||
service: props.service,
|
||||
});
|
||||
return response.data;
|
||||
};
|
||||
|
||||
|
||||
20
frontend/src/api/onboarding/updateProfile.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
import { GatewayApiV2Instance } from 'api';
|
||||
import { ErrorResponse, SuccessResponse } from 'types/api';
|
||||
import { UpdateProfileProps } from 'types/api/onboarding/types';
|
||||
|
||||
const updateProfile = async (
|
||||
props: UpdateProfileProps,
|
||||
): Promise<SuccessResponse<UpdateProfileProps> | ErrorResponse> => {
|
||||
const response = await GatewayApiV2Instance.put('/profiles/me', {
|
||||
...props,
|
||||
});
|
||||
|
||||
return {
|
||||
statusCode: 200,
|
||||
error: null,
|
||||
message: response.data.status,
|
||||
payload: response.data.data,
|
||||
};
|
||||
};
|
||||
|
||||
export default updateProfile;
|
||||
@@ -1,6 +1,7 @@
|
||||
import axios from 'api';
|
||||
import { ErrorResponseHandler } from 'api/ErrorResponseHandler';
|
||||
import { AxiosError } from 'axios';
|
||||
import { Dayjs } from 'dayjs';
|
||||
import { ErrorResponse, SuccessResponse } from 'types/api';
|
||||
|
||||
import { Recurrence } from './getAllDowntimeSchedules';
|
||||
@@ -11,8 +12,8 @@ export interface DowntimeSchedulePayload {
|
||||
alertIds: string[];
|
||||
schedule: {
|
||||
timezone?: string;
|
||||
startTime?: string;
|
||||
endTime?: string;
|
||||
startTime?: string | Dayjs;
|
||||
endTime?: string | Dayjs;
|
||||
recurrence?: Recurrence;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import axios from 'api';
|
||||
import { AxiosError, AxiosResponse } from 'axios';
|
||||
import { Option } from 'container/PlannedDowntime/DropdownWithSubMenu/DropdownWithSubMenu';
|
||||
import { Option } from 'container/PlannedDowntime/PlannedDowntimeutils';
|
||||
import { useQuery, UseQueryResult } from 'react-query';
|
||||
|
||||
export type Recurrence = {
|
||||
@@ -28,6 +28,7 @@ export interface DowntimeSchedules {
|
||||
createdBy: string | null;
|
||||
updatedAt: string | null;
|
||||
updatedBy: string | null;
|
||||
kind: string | null;
|
||||
}
|
||||
export type PayloadProps = { data: DowntimeSchedules[] };
|
||||
|
||||
|
||||