Compare commits

..

17 Commits

Author SHA1 Message Date
Rajat-Dabade
ced74603c0 chore: updated test script 2023-12-15 13:46:16 +05:30
Rajat-Dabade
f59fb81109 refactor: updated test directory 2023-12-15 13:46:16 +05:30
Rajat-Dabade
507e68a0c1 refactor: reverted back as working directory is specified as frontend 2023-12-15 13:46:16 +05:30
Rajat-Dabade
4ad8a1f3ad refactor: shifted i18n to original location 2023-12-15 13:46:16 +05:30
Rajat-Dabade
19faf6a584 chore: updates 2023-12-15 13:46:16 +05:30
Rajat-Dabade
3978ada811 refactor: for push and pull request 2023-12-15 13:46:16 +05:30
Rajat-Dabade
0a04fc04a5 refactor: generate code coverage report on every push 2023-12-15 13:46:16 +05:30
Rajat-Dabade
7c9e333b84 refactor: added package-manager 2023-12-15 13:46:16 +05:30
Rajat-Dabade
dd78afb20f refactor: updated the working directory 2023-12-15 13:46:16 +05:30
Rajat-Dabade
237d765376 refactor: updated github flow 2023-12-15 13:46:16 +05:30
Rajat-Dabade
85e865fb1b refactor: updated token 2023-12-15 13:46:16 +05:30
Rajat-Dabade
975e5daf03 refactor: updated test case 2023-12-15 13:46:16 +05:30
Rajat-Dabade
8a532cca17 refactor: updated jest running command 2023-12-15 13:46:16 +05:30
Rajat-Dabade
b9c908719f refactor: updated the command for jest 2023-12-15 13:46:16 +05:30
Rajat-Dabade
63c7b5e9e1 chore: minor changes 2023-12-15 13:46:16 +05:30
Rajat-Dabade
32eeb3d106 refactor: done some changes 2023-12-15 13:46:16 +05:30
Rajat-Dabade
1a4ec2bf00 feat: jest code coverage report 2023-12-15 13:46:16 +05:30
1600 changed files with 12106 additions and 134087 deletions

3
.github/CODEOWNERS vendored
View File

@@ -1,8 +1,9 @@
# CODEOWNERS info: https://help.github.com/en/articles/about-code-owners # CODEOWNERS info: https://help.github.com/en/articles/about-code-owners
# Owners are automatically requested for review for PRs that changes code # Owners are automatically requested for review for PRs that changes code
# that they own. # that they own.
* @ankitnayan
/frontend/ @YounixM /frontend/ @palashgdev @YounixM
/frontend/src/container/MetricsApplication @srikanthccv /frontend/src/container/MetricsApplication @srikanthccv
/frontend/src/container/NewWidget/RightContainer/types.ts @srikanthccv /frontend/src/container/NewWidget/RightContainer/types.ts @srikanthccv
/deploy/ @prashant-shahi /deploy/ @prashant-shahi

View File

@@ -19,4 +19,4 @@ jobs:
- name: 'Dependency Review' - name: 'Dependency Review'
with: with:
fail-on-severity: high fail-on-severity: high
uses: actions/dependency-review-action@v3 uses: actions/dependency-review-action@v2

View File

@@ -15,11 +15,6 @@ jobs:
- name: Checkout code - name: Checkout code
uses: actions/checkout@v4 uses: actions/checkout@v4
- name: Setup golang
uses: actions/setup-go@v4
with:
go-version: "1.21"
- name: Build query-service image - name: Build query-service image
env: env:
DEV_BUILD: 1 DEV_BUILD: 1
@@ -70,9 +65,9 @@ jobs:
- name: Kick off a sample-app workload - name: Kick off a sample-app workload
run: | run: |
# start the locust swarm # start the locust swarm
kubectl --namespace sample-application run strzal --image=djbingham/curl \ kubectl -n sample-application run strzal --image=djbingham/curl \
--restart='OnFailure' -i --tty --rm --command -- curl -X POST -F \ --restart='OnFailure' -i --rm --command -- curl -X POST -F \
'user_count=6' -F 'spawn_rate=2' http://locust-master:8089/swarm 'locust_count=6' -F 'hatch_rate=2' http://locust-master:8089/swarm
- name: Get short commit SHA, display tunnel URL and IP Address of the worker node - name: Get short commit SHA, display tunnel URL and IP Address of the worker node
id: get-subdomain id: get-subdomain

View File

@@ -0,0 +1,32 @@
name: Code Coverage
on:
push:
branches:
- develop
- main
- release/v*
pull_request:
branches:
- develop
- main
- release/v*
jobs:
coverage:
runs-on: ubuntu-latest
permissions:
checks: write
pull-requests: write
contents: write
steps:
- name: Checkout Repository
uses: actions/checkout@v2
- uses: jwalton/gh-find-current-pr@v1
id: findPr
- uses: ArtiomTr/jest-coverage-report-action@v2
with:
package-manager: yarn
working-directory: frontend
test-script: yarn jest:coverage
github-token: ${{ secrets.GITHUB_TOKEN }}
output: comment
prnumber: ${{ steps.findPr.outputs.number }}

View File

@@ -1,31 +0,0 @@
name: Jest Coverage - changed files
on:
pull_request:
branches: develop
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
with:
ref: "refs/heads/develop"
token: ${{ secrets.GITHUB_TOKEN }} # Provide the GitHub token for authentication
- name: Fetch branch
run: git fetch origin ${{ github.event.pull_request.head.ref }}
- run: |
git checkout ${{ github.event.pull_request.head.sha }}
- uses: actions/setup-node@v4
with:
node-version: lts/*
- name: Install dependencies
run: cd frontend && npm install -g yarn && yarn
- name: npm run test:changedsince
run: cd frontend && npm run i18n:generate-hash && npm run test:changedsince

View File

@@ -20,13 +20,13 @@ jobs:
with: with:
go-version: "1.21" go-version: "1.21"
- name: Set up QEMU - name: Set up QEMU
uses: docker/setup-qemu-action@v3 uses: docker/setup-qemu-action@v2
- name: Set up Docker Buildx - name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3 uses: docker/setup-buildx-action@v2
with: with:
version: latest version: latest
- name: Login to DockerHub - name: Login to DockerHub
uses: docker/login-action@v3 uses: docker/login-action@v2
with: with:
username: ${{ secrets.DOCKERHUB_USERNAME }} username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }} password: ${{ secrets.DOCKERHUB_TOKEN }}
@@ -64,13 +64,13 @@ jobs:
with: with:
go-version: "1.21" go-version: "1.21"
- name: Set up QEMU - name: Set up QEMU
uses: docker/setup-qemu-action@v3 uses: docker/setup-qemu-action@v2
- name: Set up Docker Buildx - name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3 uses: docker/setup-buildx-action@v2
with: with:
version: latest version: latest
- name: Login to DockerHub - name: Login to DockerHub
uses: docker/login-action@v3 uses: docker/login-action@v2
with: with:
username: ${{ secrets.DOCKERHUB_USERNAME }} username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }} password: ${{ secrets.DOCKERHUB_TOKEN }}
@@ -115,11 +115,11 @@ jobs:
run: npm run lint run: npm run lint
continue-on-error: true continue-on-error: true
- name: Set up Docker Buildx - name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3 uses: docker/setup-buildx-action@v2
with: with:
version: latest version: latest
- name: Login to DockerHub - name: Login to DockerHub
uses: docker/login-action@v3 uses: docker/login-action@v2
with: with:
username: ${{ secrets.DOCKERHUB_USERNAME }} username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }} password: ${{ secrets.DOCKERHUB_TOKEN }}
@@ -152,12 +152,6 @@ jobs:
echo 'INTERCOM_APP_ID="${{ secrets.INTERCOM_APP_ID }}"' > frontend/.env echo 'INTERCOM_APP_ID="${{ secrets.INTERCOM_APP_ID }}"' > frontend/.env
echo 'SEGMENT_ID="${{ secrets.SEGMENT_ID }}"' >> frontend/.env echo 'SEGMENT_ID="${{ secrets.SEGMENT_ID }}"' >> frontend/.env
echo 'CLARITY_PROJECT_ID="${{ secrets.CLARITY_PROJECT_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
echo 'SENTRY_DSN="${{ secrets.SENTRY_DSN }}"' >> frontend/.env
echo 'TUNNEL_URL="${{ secrets.TUNNEL_URL }}"' >> frontend/.env
echo 'TUNNEL_DOMAIN="${{ secrets.TUNNEL_DOMAIN }}"' >> frontend/.env
- name: Install dependencies - name: Install dependencies
working-directory: frontend working-directory: frontend
run: yarn install run: yarn install
@@ -170,11 +164,11 @@ jobs:
run: npm run lint run: npm run lint
continue-on-error: true continue-on-error: true
- name: Set up Docker Buildx - name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3 uses: docker/setup-buildx-action@v2
with: with:
version: latest version: latest
- name: Login to DockerHub - name: Login to DockerHub
uses: docker/login-action@v3 uses: docker/login-action@v2
with: with:
username: ${{ secrets.DOCKERHUB_USERNAME }} username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }} password: ${{ secrets.DOCKERHUB_TOKEN }}

View File

@@ -9,46 +9,34 @@ jobs:
name: Deploy latest develop branch to staging name: Deploy latest develop branch to staging
runs-on: ubuntu-latest runs-on: ubuntu-latest
environment: staging environment: staging
permissions:
contents: 'read'
id-token: 'write'
steps: steps:
- id: 'auth' - name: Executing remote ssh commands using ssh key
uses: 'google-github-actions/auth@v2' uses: appleboy/ssh-action@v0.1.8
with:
workload_identity_provider: ${{ secrets.GCP_WORKLOAD_IDENTITY_PROVIDER }}
service_account: ${{ secrets.GCP_SERVICE_ACCOUNT }}
- name: 'sdk'
uses: 'google-github-actions/setup-gcloud@v2'
- name: 'ssh'
shell: bash
env: env:
GITHUB_BRANCH: ${{ github.head_ref || github.ref_name }} GITHUB_BRANCH: develop
GITHUB_SHA: ${{ github.sha }} GITHUB_SHA: ${{ github.sha }}
GCP_PROJECT: ${{ secrets.GCP_PROJECT }} with:
GCP_ZONE: ${{ secrets.GCP_ZONE }} host: ${{ secrets.HOST_DNS }}
GCP_INSTANCE: ${{ secrets.GCP_INSTANCE }} username: ${{ secrets.USERNAME }}
run: | key: ${{ secrets.SSH_KEY }}
read -r -d '' COMMAND <<EOF || true envs: GITHUB_BRANCH,GITHUB_SHA
echo "GITHUB_BRANCH: ${GITHUB_BRANCH}" command_timeout: 60m
echo "GITHUB_SHA: ${GITHUB_SHA}" script: |
export DOCKER_TAG="${GITHUB_SHA:0:7}" # needed for child process to access it echo "GITHUB_BRANCH: ${GITHUB_BRANCH}"
export OTELCOL_TAG="main" echo "GITHUB_SHA: ${GITHUB_SHA}"
export PATH="/usr/local/go/bin/:$PATH" # needed for Golang to work export DOCKER_TAG="${GITHUB_SHA:0:7}" # needed for child process to access it
docker system prune --force export OTELCOL_TAG="main"
docker pull signoz/signoz-otel-collector:main export PATH="/usr/local/go/bin/:$PATH" # needed for Golang to work
docker pull signoz/signoz-schema-migrator:main docker system prune --force
cd ~/signoz docker pull signoz/signoz-otel-collector:main
git status docker pull signoz/signoz-schema-migrator:main
git add . cd ~/signoz
git stash push -m "stashed on $(date --iso-8601=seconds)" git status
git fetch origin git add .
git checkout ${GITHUB_BRANCH} git stash push -m "stashed on $(date --iso-8601=seconds)"
git pull git fetch origin
make build-ee-query-service-amd64 git checkout ${GITHUB_BRANCH}
make build-frontend-amd64 git pull
make run-testing make build-ee-query-service-amd64
EOF make build-frontend-amd64
gcloud compute ssh ${GCP_INSTANCE} --zone ${GCP_ZONE} --ssh-key-expire-after=15m --tunnel-through-iap --project ${GCP_PROJECT} --command "${COMMAND}" make run-signoz

View File

@@ -9,47 +9,32 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
environment: testing environment: testing
if: ${{ github.event.label.name == 'testing-deploy' }} if: ${{ github.event.label.name == 'testing-deploy' }}
permissions:
contents: 'read'
id-token: 'write'
steps: steps:
- id: 'auth' - name: Executing remote ssh commands using ssh key
uses: 'google-github-actions/auth@v2' uses: appleboy/ssh-action@v0.1.8
with:
workload_identity_provider: ${{ secrets.GCP_WORKLOAD_IDENTITY_PROVIDER }}
service_account: ${{ secrets.GCP_SERVICE_ACCOUNT }}
- name: 'sdk'
uses: 'google-github-actions/setup-gcloud@v2'
- name: 'ssh'
shell: bash
env: env:
GITHUB_BRANCH: ${{ github.head_ref || github.ref_name }} GITHUB_BRANCH: ${{ github.head_ref || github.ref_name }}
GITHUB_SHA: ${{ github.sha }} GITHUB_SHA: ${{ github.sha }}
GCP_PROJECT: ${{ secrets.GCP_PROJECT }} with:
GCP_ZONE: ${{ secrets.GCP_ZONE }} host: ${{ secrets.HOST_DNS }}
GCP_INSTANCE: ${{ secrets.GCP_INSTANCE }} username: ${{ secrets.USERNAME }}
run: | key: ${{ secrets.SSH_KEY }}
read -r -d '' COMMAND <<EOF || true envs: GITHUB_BRANCH,GITHUB_SHA
echo "GITHUB_BRANCH: ${GITHUB_BRANCH}" command_timeout: 60m
echo "GITHUB_SHA: ${GITHUB_SHA}" script: |
export DOCKER_TAG="${GITHUB_SHA:0:7}" # needed for child process to access it echo "GITHUB_BRANCH: ${GITHUB_BRANCH}"
export DEV_BUILD="1" echo "GITHUB_SHA: ${GITHUB_SHA}"
export PATH="/usr/local/go/bin/:$PATH" # needed for Golang to work export DOCKER_TAG="${GITHUB_SHA:0:7}" # needed for child process to access it
docker system prune --force export DEV_BUILD="1"
cd ~/signoz export PATH="/usr/local/go/bin/:$PATH" # needed for Golang to work
git status docker system prune --force
git add . cd ~/signoz
git stash push -m "stashed on $(date --iso-8601=seconds)" git status
git fetch origin git add .
git checkout develop git stash push -m "stashed on $(date --iso-8601=seconds)"
git pull git fetch origin
# This is added to include the scenerio when new commit in PR is force-pushed git checkout ${GITHUB_BRANCH}
git branch -D ${GITHUB_BRANCH} git pull
git checkout --track origin/${GITHUB_BRANCH} make build-ee-query-service-amd64
make build-ee-query-service-amd64 make build-frontend-amd64
make build-frontend-amd64 make run-signoz
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}"

7
.gitignore vendored
View File

@@ -47,7 +47,6 @@ ee/query-service/signoz.db
ee/query-service/tests/test-deploy/data/ ee/query-service/tests/test-deploy/data/
# local data # local data
*.backup
*.db *.db
/deploy/docker/clickhouse-setup/data/ /deploy/docker/clickhouse-setup/data/
/deploy/docker-swarm/clickhouse-setup/data/ /deploy/docker-swarm/clickhouse-setup/data/
@@ -62,8 +61,4 @@ e2e/test-results/
e2e/playwright-report/ e2e/playwright-report/
e2e/blob-report/ e2e/blob-report/
e2e/playwright/.cache/ e2e/playwright/.cache/
e2e/.auth e2e/.auth
# go
vendor/
**/main/**

View File

@@ -156,9 +156,6 @@ pull-signoz:
run-signoz: run-signoz:
@docker-compose -f $(STANDALONE_DIRECTORY)/docker-compose.yaml up --build -d @docker-compose -f $(STANDALONE_DIRECTORY)/docker-compose.yaml up --build -d
run-testing:
@docker-compose -f $(STANDALONE_DIRECTORY)/docker-compose.testing.yaml up --build -d
down-signoz: down-signoz:
@docker-compose -f $(STANDALONE_DIRECTORY)/docker-compose.yaml down -v @docker-compose -f $(STANDALONE_DIRECTORY)/docker-compose.yaml down -v

View File

@@ -11,6 +11,7 @@
<img alt="tweet" src="https://img.shields.io/twitter/url/http/shields.io.svg?style=social"> </a> <img alt="tweet" src="https://img.shields.io/twitter/url/http/shields.io.svg?style=social"> </a>
</p> </p>
<h3 align="center"> <h3 align="center">
<a href="https://signoz.io/docs"><b>Dokumentation</b></a> &bull; <a href="https://signoz.io/docs"><b>Dokumentation</b></a> &bull;
<a href="https://github.com/SigNoz/signoz/blob/develop/README.md"><b>Readme auf Englisch </b></a> &bull; <a href="https://github.com/SigNoz/signoz/blob/develop/README.md"><b>Readme auf Englisch </b></a> &bull;
@@ -39,13 +40,12 @@ SigNoz hilft Entwicklern, Anwendungen zu überwachen und Probleme in ihren berei
👉 Einfache Einrichtung von Benachrichtigungen mit dem selbst erstellbaren Abfrage-Builder. 👉 Einfache Einrichtung von Benachrichtigungen mit dem selbst erstellbaren Abfrage-Builder.
## ##
### Anwendung Metriken ### Anwendung Metriken
![application_metrics](https://user-images.githubusercontent.com/83692067/226637410-900dbc5e-6705-4b11-a10c-bd0faeb2a92f.png) ![application_metrics](https://user-images.githubusercontent.com/83692067/226637410-900dbc5e-6705-4b11-a10c-bd0faeb2a92f.png)
### Verteiltes Tracing
### Verteiltes 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_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"> <img width="2068" alt="distributed_tracing_1" src="https://user-images.githubusercontent.com/83692067/226536462-939745b6-4f9d-45a6-8016-814837e7f7b4.png">
@@ -62,18 +62,22 @@ SigNoz hilft Entwicklern, Anwendungen zu überwachen und Probleme in ihren berei
![exceptions_light](https://user-images.githubusercontent.com/83692067/226637967-4188d024-3ac9-4799-be95-f5ea9c45436f.png) ![exceptions_light](https://user-images.githubusercontent.com/83692067/226637967-4188d024-3ac9-4799-be95-f5ea9c45436f.png)
### Alarme ### Alarme
<img width="2068" alt="alerts_management" src="https://user-images.githubusercontent.com/83692067/226536548-2c81e2e8-c12d-47e8-bad7-c6be79055def.png"> <img width="2068" alt="alerts_management" src="https://user-images.githubusercontent.com/83692067/226536548-2c81e2e8-c12d-47e8-bad7-c6be79055def.png">
<br /><br /> <br /><br />
## Werde Teil unserer Slack Community ## Werde Teil unserer Slack Community
Sag Hi zu uns auf [Slack](https://signoz.io/slack) 👋 Sag Hi zu uns auf [Slack](https://signoz.io/slack) 👋
<br /><br /> <br /><br />
## Funktionen: ## Funktionen:
- Einheitliche Benutzeroberfläche für Metriken, Traces und Logs. Keine Notwendigkeit, zwischen Prometheus und Jaeger zu wechseln, um Probleme zu debuggen oder ein separates Log-Tool wie Elastic neben Ihrer Metriken- und Traces-Stack zu verwenden. - Einheitliche Benutzeroberfläche für Metriken, Traces und Logs. Keine Notwendigkeit, zwischen Prometheus und Jaeger zu wechseln, um Probleme zu debuggen oder ein separates Log-Tool wie Elastic neben Ihrer Metriken- und Traces-Stack zu verwenden.
@@ -89,6 +93,7 @@ Sag Hi zu uns auf [Slack](https://signoz.io/slack) 👋
<br /><br /> <br /><br />
## Wieso SigNoz? ## Wieso SigNoz?
Als Entwickler fanden wir es anstrengend, uns für jede kleine Funktion, die wir haben wollten, auf Closed Source SaaS Anbieter verlassen zu müssen. Closed Source Anbieter überraschen ihre Kunden zum Monatsende oft mit hohen Rechnungen, die keine Transparenz bzgl. der Kostenaufteilung bieten. Als Entwickler fanden wir es anstrengend, uns für jede kleine Funktion, die wir haben wollten, auf Closed Source SaaS Anbieter verlassen zu müssen. Closed Source Anbieter überraschen ihre Kunden zum Monatsende oft mit hohen Rechnungen, die keine Transparenz bzgl. der Kostenaufteilung bieten.
@@ -111,10 +116,12 @@ Wir unterstützen [OpenTelemetry](https://opentelemetry.io) als Bibliothek, mit
- Elixir - Elixir
- Rust - Rust
Hier findest du die vollständige Liste von unterstützten Programmiersprachen - https://opentelemetry.io/docs/ Hier findest du die vollständige Liste von unterstützten Programmiersprachen - https://opentelemetry.io/docs/
<br /><br /> <br /><br />
## Erste Schritte mit SigNoz ## Erste Schritte mit SigNoz
### Bereitstellung mit Docker ### Bereitstellung mit Docker
@@ -131,6 +138,7 @@ Bitte folge den [hier](https://signoz.io/docs/deployment/helm_chart) aufgelistet
<br /><br /> <br /><br />
## Vergleiche mit bekannten Tools ## Vergleiche mit bekannten Tools
### SigNoz vs Prometheus ### SigNoz vs Prometheus
@@ -171,6 +179,7 @@ Wir haben Benchmarks veröffentlicht, die Loki mit SigNoz vergleichen. Schauen S
<br /><br /> <br /><br />
## Zum Projekt beitragen ## Zum Projekt beitragen
Wir ❤️ Beiträge zum Projekt, egal ob große oder kleine. Bitte lies dir zuerst die [CONTRIBUTING.md](CONTRIBUTING.md), durch, bevor du anfängst, Beiträge zu SigNoz zu machen. Wir ❤️ Beiträge zum Projekt, egal ob große oder kleine. Bitte lies dir zuerst die [CONTRIBUTING.md](CONTRIBUTING.md), durch, bevor du anfängst, Beiträge zu SigNoz zu machen.
@@ -188,8 +197,6 @@ Du bist dir nicht sicher, wie du anfangen sollst? Schreib uns einfach auf dem #c
#### Frontend #### Frontend
- [Palash Gupta](https://github.com/palashgdev) - [Palash Gupta](https://github.com/palashgdev)
- [Yunus M](https://github.com/YounixM)
- [Rajat Dabade](https://github.com/Rajat-Dabade)
#### DevOps #### DevOps
@@ -197,12 +204,16 @@ Du bist dir nicht sicher, wie du anfangen sollst? Schreib uns einfach auf dem #c
<br /><br /> <br /><br />
## Dokumentation ## Dokumentation
Du findest unsere Dokumentation unter https://signoz.io/docs/. Falls etwas unverständlich ist oder fehlt, öffne gerne ein Github Issue mit dem Label `documentation` oder schreib uns über den Community Slack Channel. Du findest unsere Dokumentation unter https://signoz.io/docs/. Falls etwas unverständlich ist oder fehlt, öffne gerne ein Github Issue mit dem Label `documentation` oder schreib uns über den Community Slack Channel.
<br /><br /> <br /><br />
## Gemeinschaft ## Gemeinschaft
Werde Teil der [slack community](https://signoz.io/slack) um mehr über verteilte Einzelschritt-Fehlersuche, Messung von Systemzuständen oder SigNoz zu erfahren und sich mit anderen Nutzern und Mitwirkenden in Verbindung zu setzen. Werde Teil der [slack community](https://signoz.io/slack) um mehr über verteilte Einzelschritt-Fehlersuche, Messung von Systemzuständen oder SigNoz zu erfahren und sich mit anderen Nutzern und Mitwirkenden in Verbindung zu setzen.

View File

@@ -108,7 +108,7 @@ We support [OpenTelemetry](https://opentelemetry.io) as the library which you ca
- Java - Java
- Python - Python
- Node.js - NodeJS
- Go - Go
- PHP - PHP
- .NET - .NET
@@ -199,13 +199,10 @@ Not sure how to get started? Just ping us on `#contributing` in our [slack commu
#### Frontend #### Frontend
- [Palash Gupta](https://github.com/palashgdev) - [Palash Gupta](https://github.com/palashgdev)
- [Yunus M](https://github.com/YounixM)
- [Rajat Dabade](https://github.com/Rajat-Dabade)
#### DevOps #### DevOps
- [Prashant Shahi](https://github.com/prashant-shahi) - [Prashant Shahi](https://github.com/prashant-shahi)
- [Dhawal Sanghvi](https://github.com/dhawal1248)
<br /><br /> <br /><br />

View File

@@ -19,7 +19,7 @@
<a href="https://twitter.com/SigNozHq"><b>Twitter</b></a> <a href="https://twitter.com/SigNozHq"><b>Twitter</b></a>
</h3> </h3>
## ##
SigNoz 帮助开发人员监控应用并排查已部署应用的问题。你可以使用 SigNoz 实现如下能力: SigNoz 帮助开发人员监控应用并排查已部署应用的问题。你可以使用 SigNoz 实现如下能力:
@@ -67,7 +67,7 @@ SigNoz 帮助开发人员监控应用并排查已部署应用的问题。你可
## 加入我们 Slack 社区 ## 加入我们 Slack 社区
来 [Slack](https://signoz.io/slack) 和我们打招呼吧 👋 来 [Slack](https://signoz.io/slack) 和我们打招呼吧 👋
<br /><br /> <br /><br />
@@ -83,7 +83,7 @@ SigNoz 帮助开发人员监控应用并排查已部署应用的问题。你可
- 通过 服务名、操作方式、延迟、错误、标签/注释 过滤 traces 数据 - 通过 服务名、操作方式、延迟、错误、标签/注释 过滤 traces 数据
- 通过聚合 trace 数据而获得业务相关的 metrics。 比如你可以通过 `customer_type: gold` 或者 `deployment_version: v2` 或者 `external_call: paypal` 获取错误率和 P99 延迟数据 - 通过聚合 trace 数据而获得业务相关的 metrics。 比如你可以通过 `customer_type: gold` 或者 `deployment_version: v2` 或者 `external_call: paypal` 获取错误率和 P99 延迟数据
- 原生支持 OpenTelemetry 日志,高级日志查询,自动收集 k8s 相关日志 - 原生支持 OpenTelemetry 日志,高级日志查询,自动收集 k8s 相关日志
@@ -101,7 +101,7 @@ SigNoz 帮助开发人员监控应用并排查已部署应用的问题。你可
我们想做一个自托管并且可开源的工具,像 DataDog 和 NewRelic 那样, 为那些担心数据隐私和安全的公司提供第三方服务。 我们想做一个自托管并且可开源的工具,像 DataDog 和 NewRelic 那样, 为那些担心数据隐私和安全的公司提供第三方服务。
作为开源的项目,你完全可以自己掌控你的配置、样本和更新。你同样可以基于 SigNoz 拓展特定的业务模块。 作为开源的项目,你完全可以自己掌控你的配置、样本和更新。你同样可以基于 SigNoz 拓展特定的业务模块。
### 支持的编程语言: ### 支持的编程语言:
@@ -153,9 +153,9 @@ Jaeger 仅仅是一个分布式追踪系统。 但是 SigNoz 可以提供 metric
而且, SigNoz 相较于 Jaeger 拥有更对的高级功能: 而且, SigNoz 相较于 Jaeger 拥有更对的高级功能:
- Jaegar UI 不能提供任何基于 traces 的 metrics 查询和过滤。 - Jaegar UI 不能提供任何基于 traces 的 metrics 查询和过滤。
- Jaeger 不能针对过滤的 traces 做聚合。 比如, p99 延迟的请求有个标签是 customer_type='premium'。 而这些在 SigNoz 可以轻松做到。 - Jaeger 不能针对过滤的 traces 做聚合。 比如, p99 延迟的请求有个标签是 customer_type='premium'。 而这些在 SigNoz 可以轻松做到。
<p>&nbsp </p> <p>&nbsp </p>
@@ -185,7 +185,7 @@ Jaeger 仅仅是一个分布式追踪系统。 但是 SigNoz 可以提供 metric
我们 ❤️ 你的贡献,无论大小。 请先阅读 [CONTRIBUTING.md](CONTRIBUTING.md) 再开始给 SigNoz 做贡献。 我们 ❤️ 你的贡献,无论大小。 请先阅读 [CONTRIBUTING.md](CONTRIBUTING.md) 再开始给 SigNoz 做贡献。
如果你不知道如何开始? 只需要在 [slack 社区](https://signoz.io/slack) 通过 `#contributing` 频道联系我们。 如果你不知道如何开始? 只需要在 [slack 社区](https://signoz.io/slack) 通过 `#contributing` 频道联系我们。
### 项目维护人员 ### 项目维护人员
@@ -199,8 +199,6 @@ Jaeger 仅仅是一个分布式追踪系统。 但是 SigNoz 可以提供 metric
#### 前端 #### 前端
- [Palash Gupta](https://github.com/palashgdev) - [Palash Gupta](https://github.com/palashgdev)
- [Yunus M](https://github.com/YounixM)
- [Rajat Dabade](https://github.com/Rajat-Dabade)
#### 运维开发 #### 运维开发

View File

@@ -1,7 +1,7 @@
version: "3.9" version: "3.9"
x-clickhouse-defaults: &clickhouse-defaults x-clickhouse-defaults: &clickhouse-defaults
image: clickhouse/clickhouse-server:24.1.2-alpine image: clickhouse/clickhouse-server:23.11.1-alpine
tty: true tty: true
deploy: deploy:
restart_policy: restart_policy:
@@ -22,7 +22,7 @@ x-clickhouse-defaults: &clickhouse-defaults
"wget", "wget",
"--spider", "--spider",
"-q", "-q",
"0.0.0.0:8123/ping" "localhost:8123/ping"
] ]
interval: 30s interval: 30s
timeout: 5s timeout: 5s
@@ -133,7 +133,7 @@ services:
# - ./data/clickhouse-3/:/var/lib/clickhouse/ # - ./data/clickhouse-3/:/var/lib/clickhouse/
alertmanager: alertmanager:
image: signoz/alertmanager:0.23.5 image: signoz/alertmanager:0.23.4
volumes: volumes:
- ./data/alertmanager:/data - ./data/alertmanager:/data
command: command:
@@ -146,11 +146,11 @@ services:
condition: on-failure condition: on-failure
query-service: query-service:
image: signoz/query-service:0.47.0 image: signoz/query-service:0.35.1
command: command:
[ [
"-config=/root/config/prometheus.yml", "-config=/root/config/prometheus.yml",
# "--prefer-delta=true" "--prefer-delta=true"
] ]
# ports: # ports:
# - "6060:6060" # pprof port # - "6060:6060" # pprof port
@@ -160,7 +160,7 @@ services:
- ../dashboards:/root/config/dashboards - ../dashboards:/root/config/dashboards
- ./data/signoz/:/var/lib/signoz/ - ./data/signoz/:/var/lib/signoz/
environment: environment:
- ClickHouseUrl=tcp://clickhouse:9000 - ClickHouseUrl=tcp://clickhouse:9000/?database=signoz_traces
- ALERTMANAGER_API_PREFIX=http://alertmanager:9093/api/ - ALERTMANAGER_API_PREFIX=http://alertmanager:9093/api/
- SIGNOZ_LOCAL_DB_PATH=/var/lib/signoz/signoz.db - SIGNOZ_LOCAL_DB_PATH=/var/lib/signoz/signoz.db
- DASHBOARDS_PATH=/root/config/dashboards - DASHBOARDS_PATH=/root/config/dashboards
@@ -186,7 +186,7 @@ services:
<<: *db-depend <<: *db-depend
frontend: frontend:
image: signoz/frontend:0.47.0 image: signoz/frontend:0.35.1
deploy: deploy:
restart_policy: restart_policy:
condition: on-failure condition: on-failure
@@ -199,7 +199,7 @@ services:
- ../common/nginx-config.conf:/etc/nginx/conf.d/default.conf - ../common/nginx-config.conf:/etc/nginx/conf.d/default.conf
otel-collector: otel-collector:
image: signoz/signoz-otel-collector:0.88.26 image: signoz/signoz-otel-collector:0.88.3
command: command:
[ [
"--config=/etc/otel-collector-config.yaml", "--config=/etc/otel-collector-config.yaml",
@@ -237,7 +237,7 @@ services:
- query-service - query-service
otel-collector-migrator: otel-collector-migrator:
image: signoz/signoz-schema-migrator:0.88.26 image: signoz/signoz-schema-migrator:0.88.3
deploy: deploy:
restart_policy: restart_policy:
condition: on-failure condition: on-failure
@@ -249,6 +249,25 @@ services:
# - clickhouse-2 # - clickhouse-2
# - clickhouse-3 # - clickhouse-3
otel-collector-metrics:
image: signoz/signoz-otel-collector:0.88.3
command:
[
"--config=/etc/otel-collector-metrics-config.yaml",
"--feature-gates=-pkg.translator.prometheus.NormalizeName"
]
volumes:
- ./otel-collector-metrics-config.yaml:/etc/otel-collector-metrics-config.yaml
# ports:
# - "1777:1777" # pprof extension
# - "8888:8888" # OtelCollector internal metrics
# - "13133:13133" # Health check extension
# - "55679:55679" # zPages extension
deploy:
restart_policy:
condition: on-failure
<<: *db-depend
logspout: logspout:
image: "gliderlabs/logspout:v3.2.14" image: "gliderlabs/logspout:v3.2.14"
volumes: volumes:

View File

@@ -15,9 +15,13 @@ receivers:
# please remove names from below if you want to collect logs from them # please remove names from below if you want to collect logs from them
- type: filter - type: filter
id: signoz_logs_filter id: signoz_logs_filter
expr: 'attributes.container_name matches "^signoz_(logspout|frontend|alertmanager|query-service|otel-collector|clickhouse|zookeeper)"' expr: 'attributes.container_name matches "^signoz_(logspout|frontend|alertmanager|query-service|otel-collector|otel-collector-metrics|clickhouse|zookeeper)"'
opencensus: opencensus:
endpoint: 0.0.0.0:55678 endpoint: 0.0.0.0:55678
otlp/spanmetrics:
protocols:
grpc:
endpoint: localhost:12345
otlp: otlp:
protocols: protocols:
grpc: grpc:
@@ -65,8 +69,8 @@ processors:
# Using OTEL_RESOURCE_ATTRIBUTES envvar, env detector adds custom labels. # Using OTEL_RESOURCE_ATTRIBUTES envvar, env detector adds custom labels.
detectors: [env, system] # include ec2 for AWS, gcp for GCP and azure for Azure. detectors: [env, system] # include ec2 for AWS, gcp for GCP and azure for Azure.
timeout: 2s timeout: 2s
signozspanmetrics/cumulative: signozspanmetrics/prometheus:
metrics_exporter: clickhousemetricswrite metrics_exporter: prometheus
latency_histogram_buckets: [100us, 1ms, 2ms, 6ms, 10ms, 50ms, 100ms, 250ms, 500ms, 1000ms, 1400ms, 2000ms, 5s, 10s, 20s, 40s, 60s ] latency_histogram_buckets: [100us, 1ms, 2ms, 6ms, 10ms, 50ms, 100ms, 250ms, 500ms, 1000ms, 1400ms, 2000ms, 5s, 10s, 20s, 40s, 60s ]
dimensions_cache_size: 100000 dimensions_cache_size: 100000
dimensions: dimensions:
@@ -93,38 +97,33 @@ processors:
# num_workers: 4 # num_workers: 4
# queue_size: 100 # queue_size: 100
# retry_on_failure: true # retry_on_failure: true
signozspanmetrics/delta:
metrics_exporter: clickhousemetricswrite
latency_histogram_buckets: [100us, 1ms, 2ms, 6ms, 10ms, 50ms, 100ms, 250ms, 500ms, 1000ms, 1400ms, 2000ms, 5s, 10s, 20s, 40s, 60s ]
dimensions_cache_size: 100000
aggregation_temporality: AGGREGATION_TEMPORALITY_DELTA
enable_exp_histogram: true
dimensions:
- name: service.namespace
default: default
- name: deployment.environment
default: default
# This is added to ensure the uniqueness of the timeseries
# Otherwise, identical timeseries produced by multiple replicas of
# collectors result in incorrect APM metrics
- name: signoz.collector.id
exporters: exporters:
clickhousetraces: clickhousetraces:
datasource: tcp://clickhouse:9000/signoz_traces datasource: tcp://clickhouse:9000/?database=signoz_traces
docker_multi_node_cluster: ${DOCKER_MULTI_NODE_CLUSTER} docker_multi_node_cluster: ${DOCKER_MULTI_NODE_CLUSTER}
low_cardinal_exception_grouping: ${LOW_CARDINAL_EXCEPTION_GROUPING} low_cardinal_exception_grouping: ${LOW_CARDINAL_EXCEPTION_GROUPING}
clickhousemetricswrite: clickhousemetricswrite:
endpoint: tcp://clickhouse:9000/signoz_metrics endpoint: tcp://clickhouse:9000/?database=signoz_metrics
resource_to_telemetry_conversion: resource_to_telemetry_conversion:
enabled: true enabled: true
clickhousemetricswrite/prometheus: clickhousemetricswrite/prometheus:
endpoint: tcp://clickhouse:9000/signoz_metrics endpoint: tcp://clickhouse:9000/?database=signoz_metrics
prometheus:
endpoint: 0.0.0.0:8889
# logging: {} # logging: {}
clickhouselogsexporter: clickhouselogsexporter:
dsn: tcp://clickhouse:9000/signoz_logs dsn: tcp://clickhouse:9000/
docker_multi_node_cluster: ${DOCKER_MULTI_NODE_CLUSTER} docker_multi_node_cluster: ${DOCKER_MULTI_NODE_CLUSTER}
timeout: 10s timeout: 5s
sending_queue:
queue_size: 100
retry_on_failure:
enabled: true
initial_interval: 5s
max_interval: 30s
max_elapsed_time: 300s
extensions: extensions:
health_check: health_check:
endpoint: 0.0.0.0:13133 endpoint: 0.0.0.0:13133
@@ -141,7 +140,7 @@ service:
pipelines: pipelines:
traces: traces:
receivers: [jaeger, otlp] receivers: [jaeger, otlp]
processors: [signozspanmetrics/cumulative, signozspanmetrics/delta, batch] processors: [signozspanmetrics/prometheus, batch]
exporters: [clickhousetraces] exporters: [clickhousetraces]
metrics: metrics:
receivers: [otlp] receivers: [otlp]
@@ -155,6 +154,9 @@ service:
receivers: [prometheus] receivers: [prometheus]
processors: [batch] processors: [batch]
exporters: [clickhousemetricswrite/prometheus] exporters: [clickhousemetricswrite/prometheus]
metrics/spanmetrics:
receivers: [otlp/spanmetrics]
exporters: [prometheus]
logs: logs:
receivers: [otlp, tcplog/docker] receivers: [otlp, tcplog/docker]
processors: [batch] processors: [batch]

View File

@@ -0,0 +1,64 @@
receivers:
prometheus:
config:
scrape_configs:
# otel-collector-metrics internal metrics
- job_name: otel-collector-metrics
scrape_interval: 60s
static_configs:
- targets:
- localhost:8888
labels:
job_name: otel-collector-metrics
# SigNoz span metrics
- job_name: signozspanmetrics-collector
scrape_interval: 60s
dns_sd_configs:
- names:
- tasks.otel-collector
type: A
port: 8889
processors:
batch:
send_batch_size: 10000
send_batch_max_size: 11000
timeout: 10s
# memory_limiter:
# # 80% of maximum memory up to 2G
# limit_mib: 1500
# # 25% of limit up to 2G
# spike_limit_mib: 512
# check_interval: 5s
#
# # 50% of the maximum memory
# limit_percentage: 50
# # 20% of max memory usage spike expected
# spike_limit_percentage: 20
# queued_retry:
# num_workers: 4
# queue_size: 100
# retry_on_failure: true
exporters:
clickhousemetricswrite:
endpoint: tcp://clickhouse:9000/?database=signoz_metrics
extensions:
health_check:
endpoint: 0.0.0.0:13133
zpages:
endpoint: 0.0.0.0:55679
pprof:
endpoint: 0.0.0.0:1777
service:
telemetry:
metrics:
address: 0.0.0.0:8888
extensions: [health_check, zpages, pprof]
pipelines:
metrics:
receivers: [prometheus]
processors: [batch]
exporters: [clickhousemetricswrite]

View File

@@ -22,4 +22,4 @@ rule_files:
scrape_configs: [] scrape_configs: []
remote_read: remote_read:
- url: tcp://clickhouse:9000/signoz_metrics - url: tcp://clickhouse:9000/?database=signoz_metrics

View File

@@ -19,7 +19,7 @@ services:
- ZOO_AUTOPURGE_INTERVAL=1 - ZOO_AUTOPURGE_INTERVAL=1
clickhouse: clickhouse:
image: clickhouse/clickhouse-server:24.1.2-alpine image: clickhouse/clickhouse-server:23.7.3-alpine
container_name: signoz-clickhouse container_name: signoz-clickhouse
# ports: # ports:
# - "9000:9000" # - "9000:9000"
@@ -46,7 +46,7 @@ services:
"wget", "wget",
"--spider", "--spider",
"-q", "-q",
"0.0.0.0:8123/ping" "localhost:8123/ping"
] ]
interval: 30s interval: 30s
timeout: 5s timeout: 5s
@@ -54,7 +54,7 @@ services:
alertmanager: alertmanager:
container_name: signoz-alertmanager container_name: signoz-alertmanager
image: signoz/alertmanager:0.23.5 image: signoz/alertmanager:0.23.4
volumes: volumes:
- ./data/alertmanager:/data - ./data/alertmanager:/data
depends_on: depends_on:
@@ -66,7 +66,7 @@ services:
- --storage.path=/data - --storage.path=/data
otel-collector-migrator: otel-collector-migrator:
image: signoz/signoz-schema-migrator:${OTELCOL_TAG:-0.88.26} image: signoz/signoz-schema-migrator:${OTELCOL_TAG:-0.88.3}
container_name: otel-migrator container_name: otel-migrator
command: command:
- "--dsn=tcp://clickhouse:9000" - "--dsn=tcp://clickhouse:9000"
@@ -81,7 +81,7 @@ services:
# Notes for Maintainers/Contributors who will change Line Numbers of Frontend & Query-Section. Please Update Line Numbers in `./scripts/commentLinesForSetup.sh` & `./CONTRIBUTING.md` # 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: otel-collector:
container_name: signoz-otel-collector container_name: signoz-otel-collector
image: signoz/signoz-otel-collector:0.88.26 image: signoz/signoz-otel-collector:0.88.3
command: command:
[ [
"--config=/etc/otel-collector-config.yaml", "--config=/etc/otel-collector-config.yaml",
@@ -116,6 +116,28 @@ services:
query-service: query-service:
condition: service_healthy condition: service_healthy
otel-collector-metrics:
container_name: signoz-otel-collector-metrics
image: signoz/signoz-otel-collector:0.88.3
command:
[
"--config=/etc/otel-collector-metrics-config.yaml",
"--feature-gates=-pkg.translator.prometheus.NormalizeName"
]
volumes:
- ./otel-collector-metrics-config.yaml:/etc/otel-collector-metrics-config.yaml
# ports:
# - "1777:1777" # pprof extension
# - "8888:8888" # OtelCollector internal metrics
# - "13133:13133" # Health check extension
# - "55679:55679" # zPages extension
restart: on-failure
depends_on:
clickhouse:
condition: service_healthy
otel-collector-migrator:
condition: service_completed_successfully
logspout: logspout:
image: "gliderlabs/logspout:v3.2.14" image: "gliderlabs/logspout:v3.2.14"
container_name: signoz-logspout container_name: signoz-logspout

View File

@@ -25,7 +25,7 @@ services:
command: command:
[ [
"-config=/root/config/prometheus.yml", "-config=/root/config/prometheus.yml",
# "--prefer-delta=true" "--prefer-delta=true"
] ]
ports: ports:
- "6060:6060" - "6060:6060"

View File

@@ -1,307 +0,0 @@
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.47.0}
container_name: signoz-query-service
command:
[
"-config=/root/config/prometheus.yml",
"-gateway-url=https://api.staging.signoz.cloud"
# "--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.47.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:
image: signoz/signoz-schema-migrator:${OTELCOL_TAG:-0.88.26}
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.88.26}
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

View File

@@ -3,7 +3,7 @@ version: "2.4"
x-clickhouse-defaults: &clickhouse-defaults x-clickhouse-defaults: &clickhouse-defaults
restart: on-failure restart: on-failure
# addding non LTS version due to this fix https://github.com/ClickHouse/ClickHouse/commit/32caf8716352f45c1b617274c7508c86b7d1afab # addding non LTS version due to this fix https://github.com/ClickHouse/ClickHouse/commit/32caf8716352f45c1b617274c7508c86b7d1afab
image: clickhouse/clickhouse-server:24.1.2-alpine image: clickhouse/clickhouse-server:23.11.1-alpine
tty: true tty: true
depends_on: depends_on:
- zookeeper-1 - zookeeper-1
@@ -21,7 +21,7 @@ x-clickhouse-defaults: &clickhouse-defaults
"wget", "wget",
"--spider", "--spider",
"-q", "-q",
"0.0.0.0:8123/ping" "localhost:8123/ping"
] ]
interval: 30s interval: 30s
timeout: 5s timeout: 5s
@@ -149,7 +149,7 @@ services:
# - ./user_scripts:/var/lib/clickhouse/user_scripts/ # - ./user_scripts:/var/lib/clickhouse/user_scripts/
alertmanager: alertmanager:
image: signoz/alertmanager:${ALERTMANAGER_TAG:-0.23.5} image: signoz/alertmanager:${ALERTMANAGER_TAG:-0.23.4}
container_name: signoz-alertmanager container_name: signoz-alertmanager
volumes: volumes:
- ./data/alertmanager:/data - ./data/alertmanager:/data
@@ -164,12 +164,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` # 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: query-service:
image: signoz/query-service:${DOCKER_TAG:-0.47.0} image: signoz/query-service:${DOCKER_TAG:-0.35.1}
container_name: signoz-query-service container_name: signoz-query-service
command: command:
[ [
"-config=/root/config/prometheus.yml" "-config=/root/config/prometheus.yml",
# "--prefer-delta=true" "--prefer-delta=true"
] ]
# ports: # ports:
# - "6060:6060" # pprof port # - "6060:6060" # pprof port
@@ -179,7 +179,7 @@ services:
- ../dashboards:/root/config/dashboards - ../dashboards:/root/config/dashboards
- ./data/signoz/:/var/lib/signoz/ - ./data/signoz/:/var/lib/signoz/
environment: environment:
- ClickHouseUrl=tcp://clickhouse:9000 - ClickHouseUrl=tcp://clickhouse:9000/?database=signoz_traces
- ALERTMANAGER_API_PREFIX=http://alertmanager:9093/api/ - ALERTMANAGER_API_PREFIX=http://alertmanager:9093/api/
- SIGNOZ_LOCAL_DB_PATH=/var/lib/signoz/signoz.db - SIGNOZ_LOCAL_DB_PATH=/var/lib/signoz/signoz.db
- DASHBOARDS_PATH=/root/config/dashboards - DASHBOARDS_PATH=/root/config/dashboards
@@ -203,7 +203,7 @@ services:
<<: *db-depend <<: *db-depend
frontend: frontend:
image: signoz/frontend:${DOCKER_TAG:-0.47.0} image: signoz/frontend:${DOCKER_TAG:-0.35.1}
container_name: signoz-frontend container_name: signoz-frontend
restart: on-failure restart: on-failure
depends_on: depends_on:
@@ -215,7 +215,7 @@ services:
- ../common/nginx-config.conf:/etc/nginx/conf.d/default.conf - ../common/nginx-config.conf:/etc/nginx/conf.d/default.conf
otel-collector-migrator: otel-collector-migrator:
image: signoz/signoz-schema-migrator:${OTELCOL_TAG:-0.88.26} image: signoz/signoz-schema-migrator:${OTELCOL_TAG:-0.88.3}
container_name: otel-migrator container_name: otel-migrator
command: command:
- "--dsn=tcp://clickhouse:9000" - "--dsn=tcp://clickhouse:9000"
@@ -229,7 +229,7 @@ services:
otel-collector: otel-collector:
image: signoz/signoz-otel-collector:${OTELCOL_TAG:-0.88.26} image: signoz/signoz-otel-collector:${OTELCOL_TAG:-0.88.3}
container_name: signoz-otel-collector container_name: signoz-otel-collector
command: command:
[ [
@@ -268,6 +268,24 @@ services:
query-service: query-service:
condition: service_healthy condition: service_healthy
otel-collector-metrics:
image: signoz/signoz-otel-collector:${OTELCOL_TAG:-0.88.3}
container_name: signoz-otel-collector-metrics
command:
[
"--config=/etc/otel-collector-metrics-config.yaml",
"--feature-gates=-pkg.translator.prometheus.NormalizeName"
]
volumes:
- ./otel-collector-metrics-config.yaml:/etc/otel-collector-metrics-config.yaml
# ports:
# - "1777:1777" # pprof extension
# - "8888:8888" # OtelCollector internal metrics
# - "13133:13133" # Health check extension
# - "55679:55679" # zPages extension
restart: on-failure
<<: *db-depend
logspout: logspout:
image: "gliderlabs/logspout:v3.2.14" image: "gliderlabs/logspout:v3.2.14"
container_name: signoz-logspout container_name: signoz-logspout

View File

@@ -1,64 +0,0 @@
<clickhouse>
<logger>
<!-- Possible levels [1]:
- none (turns off logging)
- fatal
- critical
- error
- warning
- notice
- information
- debug
- trace
[1]: https://github.com/pocoproject/poco/blob/poco-1.9.4-release/Foundation/include/Poco/Logger.h#L105-L114
-->
<level>information</level>
<log>/var/log/clickhouse-keeper/clickhouse-keeper.log</log>
<errorlog>/var/log/clickhouse-keeper/clickhouse-keeper.err.log</errorlog>
<!-- Rotation policy
See https://github.com/pocoproject/poco/blob/poco-1.9.4-release/Foundation/include/Poco/FileChannel.h#L54-L85
-->
<size>1000M</size>
<count>10</count>
<!-- <console>1</console> --> <!-- Default behavior is autodetection (log to console if not daemon mode and is tty) -->
</logger>
<listen_host>0.0.0.0</listen_host>
<max_connections>4096</max_connections>
<keeper_server>
<tcp_port>9181</tcp_port>
<!-- Must be unique among all keeper serves -->
<server_id>1</server_id>
<log_storage_path>/var/lib/clickhouse/coordination/logs</log_storage_path>
<snapshot_storage_path>/var/lib/clickhouse/coordination/snapshots</snapshot_storage_path>
<coordination_settings>
<operation_timeout_ms>10000</operation_timeout_ms>
<min_session_timeout_ms>10000</min_session_timeout_ms>
<session_timeout_ms>100000</session_timeout_ms>
<raft_logs_level>information</raft_logs_level>
<compress_logs>false</compress_logs>
<!-- All settings listed in https://github.com/ClickHouse/ClickHouse/blob/master/src/Coordination/CoordinationSettings.h -->
</coordination_settings>
<!-- enable sanity hostname checks for cluster configuration (e.g. if localhost is used with remote endpoints) -->
<hostname_checks_enabled>true</hostname_checks_enabled>
<raft_configuration>
<server>
<id>1</id>
<!-- Internal port and hostname -->
<hostname>clickhouses-keeper-1</hostname>
<port>9234</port>
</server>
<!-- Add more servers here -->
</raft_configuration>
</keeper_server>
</clickhouse>

View File

@@ -15,9 +15,13 @@ receivers:
# please remove names from below if you want to collect logs from them # please remove names from below if you want to collect logs from them
- type: filter - type: filter
id: signoz_logs_filter id: signoz_logs_filter
expr: 'attributes.container_name matches "^signoz-(logspout|frontend|alertmanager|query-service|otel-collector|clickhouse|zookeeper)"' expr: 'attributes.container_name matches "^signoz-(logspout|frontend|alertmanager|query-service|otel-collector|otel-collector-metrics|clickhouse|zookeeper)"'
opencensus: opencensus:
endpoint: 0.0.0.0:55678 endpoint: 0.0.0.0:55678
otlp/spanmetrics:
protocols:
grpc:
endpoint: localhost:12345
otlp: otlp:
protocols: protocols:
grpc: grpc:
@@ -62,9 +66,8 @@ processors:
send_batch_size: 10000 send_batch_size: 10000
send_batch_max_size: 11000 send_batch_max_size: 11000
timeout: 10s timeout: 10s
signozspanmetrics/cumulative: signozspanmetrics/prometheus:
metrics_exporter: clickhousemetricswrite metrics_exporter: prometheus
metrics_flush_interval: 60s
latency_histogram_buckets: [100us, 1ms, 2ms, 6ms, 10ms, 50ms, 100ms, 250ms, 500ms, 1000ms, 1400ms, 2000ms, 5s, 10s, 20s, 40s, 60s ] latency_histogram_buckets: [100us, 1ms, 2ms, 6ms, 10ms, 50ms, 100ms, 250ms, 500ms, 1000ms, 1400ms, 2000ms, 5s, 10s, 20s, 40s, 60s ]
dimensions_cache_size: 100000 dimensions_cache_size: 100000
dimensions: dimensions:
@@ -95,22 +98,6 @@ processors:
# Using OTEL_RESOURCE_ATTRIBUTES envvar, env detector adds custom labels. # Using OTEL_RESOURCE_ATTRIBUTES envvar, env detector adds custom labels.
detectors: [env, system] # include ec2 for AWS, gcp for GCP and azure for Azure. detectors: [env, system] # include ec2 for AWS, gcp for GCP and azure for Azure.
timeout: 2s timeout: 2s
signozspanmetrics/delta:
metrics_exporter: clickhousemetricswrite
metrics_flush_interval: 60s
latency_histogram_buckets: [100us, 1ms, 2ms, 6ms, 10ms, 50ms, 100ms, 250ms, 500ms, 1000ms, 1400ms, 2000ms, 5s, 10s, 20s, 40s, 60s ]
dimensions_cache_size: 100000
aggregation_temporality: AGGREGATION_TEMPORALITY_DELTA
enable_exp_histogram: true
dimensions:
- name: service.namespace
default: default
- name: deployment.environment
default: default
# This is added to ensure the uniqueness of the timeseries
# Otherwise, identical timeseries produced by multiple replicas of
# collectors result in incorrect APM metrics
- name: signoz.collector.id
extensions: extensions:
health_check: health_check:
@@ -122,21 +109,31 @@ extensions:
exporters: exporters:
clickhousetraces: clickhousetraces:
datasource: tcp://clickhouse:9000/signoz_traces datasource: tcp://clickhouse:9000/?database=signoz_traces
docker_multi_node_cluster: ${DOCKER_MULTI_NODE_CLUSTER} docker_multi_node_cluster: ${DOCKER_MULTI_NODE_CLUSTER}
low_cardinal_exception_grouping: ${LOW_CARDINAL_EXCEPTION_GROUPING} low_cardinal_exception_grouping: ${LOW_CARDINAL_EXCEPTION_GROUPING}
clickhousemetricswrite: clickhousemetricswrite:
endpoint: tcp://clickhouse:9000/signoz_metrics endpoint: tcp://clickhouse:9000/?database=signoz_metrics
resource_to_telemetry_conversion: resource_to_telemetry_conversion:
enabled: true enabled: true
clickhousemetricswrite/prometheus: clickhousemetricswrite/prometheus:
endpoint: tcp://clickhouse:9000/signoz_metrics endpoint: tcp://clickhouse:9000/?database=signoz_metrics
clickhouselogsexporter: prometheus:
dsn: tcp://clickhouse:9000/signoz_logs endpoint: 0.0.0.0:8889
docker_multi_node_cluster: ${DOCKER_MULTI_NODE_CLUSTER}
timeout: 10s
# logging: {} # logging: {}
clickhouselogsexporter:
dsn: tcp://clickhouse:9000/
docker_multi_node_cluster: ${DOCKER_MULTI_NODE_CLUSTER}
timeout: 5s
sending_queue:
queue_size: 100
retry_on_failure:
enabled: true
initial_interval: 5s
max_interval: 30s
max_elapsed_time: 300s
service: service:
telemetry: telemetry:
metrics: metrics:
@@ -148,7 +145,7 @@ service:
pipelines: pipelines:
traces: traces:
receivers: [jaeger, otlp] receivers: [jaeger, otlp]
processors: [signozspanmetrics/cumulative, signozspanmetrics/delta, batch] processors: [signozspanmetrics/prometheus, batch]
exporters: [clickhousetraces] exporters: [clickhousetraces]
metrics: metrics:
receivers: [otlp] receivers: [otlp]
@@ -162,6 +159,9 @@ service:
receivers: [prometheus] receivers: [prometheus]
processors: [batch] processors: [batch]
exporters: [clickhousemetricswrite/prometheus] exporters: [clickhousemetricswrite/prometheus]
metrics/spanmetrics:
receivers: [otlp/spanmetrics]
exporters: [prometheus]
logs: logs:
receivers: [otlp, tcplog/docker] receivers: [otlp, tcplog/docker]
processors: [batch] processors: [batch]

View File

@@ -0,0 +1,69 @@
receivers:
otlp:
protocols:
grpc:
http:
prometheus:
config:
scrape_configs:
# otel-collector-metrics internal metrics
- job_name: otel-collector-metrics
scrape_interval: 60s
static_configs:
- targets:
- localhost:8888
labels:
job_name: otel-collector-metrics
# SigNoz span metrics
- job_name: signozspanmetrics-collector
scrape_interval: 60s
static_configs:
- targets:
- otel-collector:8889
processors:
batch:
send_batch_size: 10000
send_batch_max_size: 11000
timeout: 10s
# memory_limiter:
# # 80% of maximum memory up to 2G
# limit_mib: 1500
# # 25% of limit up to 2G
# spike_limit_mib: 512
# check_interval: 5s
#
# # 50% of the maximum memory
# limit_percentage: 50
# # 20% of max memory usage spike expected
# spike_limit_percentage: 20
# queued_retry:
# num_workers: 4
# queue_size: 100
# retry_on_failure: true
extensions:
health_check:
endpoint: 0.0.0.0:13133
zpages:
endpoint: 0.0.0.0:55679
pprof:
endpoint: 0.0.0.0:1777
exporters:
clickhousemetricswrite:
endpoint: tcp://clickhouse:9000/?database=signoz_metrics
service:
telemetry:
metrics:
address: 0.0.0.0:8888
extensions:
- health_check
- zpages
- pprof
pipelines:
metrics:
receivers: [prometheus]
processors: [batch]
exporters: [clickhousemetricswrite]

View File

@@ -22,4 +22,4 @@ rule_files:
scrape_configs: [] scrape_configs: []
remote_read: remote_read:
- url: tcp://clickhouse:9000/signoz_metrics - url: tcp://clickhouse:9000/?database=signoz_metrics

View File

@@ -1,5 +1,5 @@
# use a minimal alpine image # use a minimal alpine image
FROM alpine:3.18.6 FROM alpine:3.18.5
# Add Maintainer Info # Add Maintainer Info
LABEL maintainer="signoz" LABEL maintainer="signoz"
@@ -18,7 +18,6 @@ COPY ee/query-service/bin/query-service-${TARGETOS}-${TARGETARCH} /root/query-se
# copy prometheus YAML config # copy prometheus YAML config
COPY pkg/query-service/config/prometheus.yml /root/config/prometheus.yml COPY pkg/query-service/config/prometheus.yml /root/config/prometheus.yml
COPY pkg/query-service/templates /root/templates
# Make query-service executable for non-root users # Make query-service executable for non-root users
RUN chmod 755 /root /root/query-service RUN chmod 755 /root /root/query-service

View File

@@ -2,17 +2,14 @@ package api
import ( import (
"net/http" "net/http"
"net/http/httputil"
"time" "time"
"github.com/gorilla/mux" "github.com/gorilla/mux"
"go.signoz.io/signoz/ee/query-service/dao" "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/interfaces"
"go.signoz.io/signoz/ee/query-service/license" "go.signoz.io/signoz/ee/query-service/license"
"go.signoz.io/signoz/ee/query-service/usage" "go.signoz.io/signoz/ee/query-service/usage"
baseapp "go.signoz.io/signoz/pkg/query-service/app" baseapp "go.signoz.io/signoz/pkg/query-service/app"
"go.signoz.io/signoz/pkg/query-service/app/integrations"
"go.signoz.io/signoz/pkg/query-service/app/logparsingpipeline" "go.signoz.io/signoz/pkg/query-service/app/logparsingpipeline"
"go.signoz.io/signoz/pkg/query-service/cache" "go.signoz.io/signoz/pkg/query-service/cache"
baseint "go.signoz.io/signoz/pkg/query-service/interfaces" baseint "go.signoz.io/signoz/pkg/query-service/interfaces"
@@ -34,10 +31,8 @@ type APIHandlerOptions struct {
UsageManager *usage.Manager UsageManager *usage.Manager
FeatureFlags baseint.FeatureLookup FeatureFlags baseint.FeatureLookup
LicenseManager *license.Manager LicenseManager *license.Manager
IntegrationsController *integrations.Controller
LogsParsingPipelineController *logparsingpipeline.LogParsingPipelineController LogsParsingPipelineController *logparsingpipeline.LogParsingPipelineController
Cache cache.Cache Cache cache.Cache
Gateway *httputil.ReverseProxy
// Querier Influx Interval // Querier Influx Interval
FluxInterval time.Duration FluxInterval time.Duration
} }
@@ -61,7 +56,6 @@ func NewAPIHandler(opts APIHandlerOptions) (*APIHandler, error) {
AppDao: opts.AppDao, AppDao: opts.AppDao,
RuleManager: opts.RulesManager, RuleManager: opts.RulesManager,
FeatureFlags: opts.FeatureFlags, FeatureFlags: opts.FeatureFlags,
IntegrationsController: opts.IntegrationsController,
LogsParsingPipelineController: opts.LogsParsingPipelineController, LogsParsingPipelineController: opts.LogsParsingPipelineController,
Cache: opts.Cache, Cache: opts.Cache,
FluxInterval: opts.FluxInterval, FluxInterval: opts.FluxInterval,
@@ -98,10 +92,6 @@ func (ah *APIHandler) AppDao() dao.ModelDao {
return ah.opts.AppDao return ah.opts.AppDao
} }
func (ah *APIHandler) Gateway() *httputil.ReverseProxy {
return ah.opts.Gateway
}
func (ah *APIHandler) CheckFeature(f string) bool { func (ah *APIHandler) CheckFeature(f string) bool {
err := ah.FF().CheckFeature(f) err := ah.FF().CheckFeature(f)
return err == nil return err == nil
@@ -159,12 +149,12 @@ func (ah *APIHandler) RegisterRoutes(router *mux.Router, am *baseapp.AuthMiddlew
router.HandleFunc("/api/v1/register", am.OpenAccess(ah.registerUser)).Methods(http.MethodPost) router.HandleFunc("/api/v1/register", am.OpenAccess(ah.registerUser)).Methods(http.MethodPost)
router.HandleFunc("/api/v1/login", am.OpenAccess(ah.loginUser)).Methods(http.MethodPost) router.HandleFunc("/api/v1/login", am.OpenAccess(ah.loginUser)).Methods(http.MethodPost)
router.HandleFunc("/api/v1/traces/{traceId}", am.ViewAccess(ah.searchTraces)).Methods(http.MethodGet) router.HandleFunc("/api/v1/traces/{traceId}", am.ViewAccess(ah.searchTraces)).Methods(http.MethodGet)
router.HandleFunc("/api/v2/metrics/query_range", am.ViewAccess(ah.queryRangeMetricsV2)).Methods(http.MethodPost)
// PAT APIs // PAT APIs
router.HandleFunc("/api/v1/pats", am.AdminAccess(ah.createPAT)).Methods(http.MethodPost) router.HandleFunc("/api/v1/pat", am.OpenAccess(ah.createPAT)).Methods(http.MethodPost)
router.HandleFunc("/api/v1/pats", am.AdminAccess(ah.getPATs)).Methods(http.MethodGet) router.HandleFunc("/api/v1/pat", am.OpenAccess(ah.getPATs)).Methods(http.MethodGet)
router.HandleFunc("/api/v1/pats/{id}", am.AdminAccess(ah.updatePAT)).Methods(http.MethodPut) router.HandleFunc("/api/v1/pat/{id}", am.OpenAccess(ah.deletePAT)).Methods(http.MethodDelete)
router.HandleFunc("/api/v1/pats/{id}", am.AdminAccess(ah.revokePAT)).Methods(http.MethodDelete)
router.HandleFunc("/api/v1/checkout", am.AdminAccess(ah.checkout)).Methods(http.MethodPost) router.HandleFunc("/api/v1/checkout", am.AdminAccess(ah.checkout)).Methods(http.MethodPost)
router.HandleFunc("/api/v1/billing", am.AdminAccess(ah.getBilling)).Methods(http.MethodGet) router.HandleFunc("/api/v1/billing", am.AdminAccess(ah.getBilling)).Methods(http.MethodGet)
@@ -177,9 +167,6 @@ func (ah *APIHandler) RegisterRoutes(router *mux.Router, am *baseapp.AuthMiddlew
am.ViewAccess(ah.listLicensesV2)). am.ViewAccess(ah.listLicensesV2)).
Methods(http.MethodGet) Methods(http.MethodGet)
// Gateway
router.PathPrefix(gateway.RoutePrefix).HandlerFunc(am.AdminAccess(ah.ServeGatewayHTTP))
ah.APIHandler.RegisterRoutes(router, am) ah.APIHandler.RegisterRoutes(router, am)
} }

View File

@@ -74,7 +74,7 @@ func (ah *APIHandler) registerUser(w http.ResponseWriter, r *http.Request) {
defer r.Body.Close() defer r.Body.Close()
requestBody, err := io.ReadAll(r.Body) requestBody, err := io.ReadAll(r.Body)
if err != nil { if err != nil {
zap.L().Error("received no input in api", zap.Error(err)) zap.S().Errorf("received no input in api\n", err)
RespondError(w, model.BadRequest(err), nil) RespondError(w, model.BadRequest(err), nil)
return return
} }
@@ -82,7 +82,7 @@ func (ah *APIHandler) registerUser(w http.ResponseWriter, r *http.Request) {
err = json.Unmarshal(requestBody, &req) err = json.Unmarshal(requestBody, &req)
if err != nil { if err != nil {
zap.L().Error("received invalid user registration request", zap.Error(err)) zap.S().Errorf("received invalid user registration request", zap.Error(err))
RespondError(w, model.BadRequest(fmt.Errorf("failed to register user")), nil) RespondError(w, model.BadRequest(fmt.Errorf("failed to register user")), nil)
return return
} }
@@ -90,13 +90,13 @@ func (ah *APIHandler) registerUser(w http.ResponseWriter, r *http.Request) {
// get invite object // get invite object
invite, err := baseauth.ValidateInvite(ctx, req) invite, err := baseauth.ValidateInvite(ctx, req)
if err != nil { if err != nil {
zap.L().Error("failed to validate invite token", zap.Error(err)) zap.S().Errorf("failed to validate invite token", err)
RespondError(w, model.BadRequest(err), nil) RespondError(w, model.BadRequest(err), nil)
return return
} }
if invite == nil { if invite == nil {
zap.L().Error("failed to validate invite token: it is either empty or invalid", zap.Error(err)) zap.S().Errorf("failed to validate invite token: it is either empty or invalid", err)
RespondError(w, model.BadRequest(basemodel.ErrSignupFailed{}), nil) RespondError(w, model.BadRequest(basemodel.ErrSignupFailed{}), nil)
return return
} }
@@ -104,7 +104,7 @@ func (ah *APIHandler) registerUser(w http.ResponseWriter, r *http.Request) {
// get auth domain from email domain // get auth domain from email domain
domain, apierr := ah.AppDao().GetDomainByEmail(ctx, invite.Email) domain, apierr := ah.AppDao().GetDomainByEmail(ctx, invite.Email)
if apierr != nil { if apierr != nil {
zap.L().Error("failed to get domain from email", zap.Error(apierr)) zap.S().Errorf("failed to get domain from email", apierr)
RespondError(w, model.InternalError(basemodel.ErrSignupFailed{}), nil) RespondError(w, model.InternalError(basemodel.ErrSignupFailed{}), nil)
} }
@@ -205,24 +205,24 @@ func (ah *APIHandler) receiveGoogleAuth(w http.ResponseWriter, r *http.Request)
ctx := context.Background() ctx := context.Background()
if !ah.CheckFeature(model.SSO) { if !ah.CheckFeature(model.SSO) {
zap.L().Error("[receiveGoogleAuth] sso requested but feature unavailable in org domain") zap.S().Errorf("[receiveGoogleAuth] sso requested but feature unavailable %s in org domain %s", model.SSO)
http.Redirect(w, r, fmt.Sprintf("%s?ssoerror=%s", redirectUri, "feature unavailable, please upgrade your billing plan to access this feature"), http.StatusMovedPermanently) http.Redirect(w, r, fmt.Sprintf("%s?ssoerror=%s", redirectUri, "feature unavailable, please upgrade your billing plan to access this feature"), http.StatusMovedPermanently)
return return
} }
q := r.URL.Query() q := r.URL.Query()
if errType := q.Get("error"); errType != "" { if errType := q.Get("error"); errType != "" {
zap.L().Error("[receiveGoogleAuth] failed to login with google auth", zap.String("error", errType), zap.String("error_description", q.Get("error_description"))) zap.S().Errorf("[receiveGoogleAuth] failed to login with google auth", q.Get("error_description"))
http.Redirect(w, r, fmt.Sprintf("%s?ssoerror=%s", redirectUri, "failed to login through SSO "), http.StatusMovedPermanently) http.Redirect(w, r, fmt.Sprintf("%s?ssoerror=%s", redirectUri, "failed to login through SSO "), http.StatusMovedPermanently)
return return
} }
relayState := q.Get("state") relayState := q.Get("state")
zap.L().Debug("[receiveGoogleAuth] relay state received", zap.String("state", relayState)) zap.S().Debug("[receiveGoogleAuth] relay state received", zap.String("state", relayState))
parsedState, err := url.Parse(relayState) parsedState, err := url.Parse(relayState)
if err != nil || relayState == "" { if err != nil || relayState == "" {
zap.L().Error("[receiveGoogleAuth] failed to process response - invalid response from IDP", zap.Error(err), zap.Any("request", r)) zap.S().Errorf("[receiveGoogleAuth] failed to process response - invalid response from IDP", err, r)
handleSsoError(w, r, redirectUri) handleSsoError(w, r, redirectUri)
return return
} }
@@ -244,14 +244,14 @@ func (ah *APIHandler) receiveGoogleAuth(w http.ResponseWriter, r *http.Request)
identity, err := callbackHandler.HandleCallback(r) identity, err := callbackHandler.HandleCallback(r)
if err != nil { if err != nil {
zap.L().Error("[receiveGoogleAuth] failed to process HandleCallback ", zap.String("domain", domain.String()), zap.Error(err)) zap.S().Errorf("[receiveGoogleAuth] failed to process HandleCallback ", domain.String(), zap.Error(err))
handleSsoError(w, r, redirectUri) handleSsoError(w, r, redirectUri)
return return
} }
nextPage, err := ah.AppDao().PrepareSsoRedirect(ctx, redirectUri, identity.Email) nextPage, err := ah.AppDao().PrepareSsoRedirect(ctx, redirectUri, identity.Email)
if err != nil { if err != nil {
zap.L().Error("[receiveGoogleAuth] failed to generate redirect URI after successful login ", zap.String("domain", domain.String()), zap.Error(err)) zap.S().Errorf("[receiveGoogleAuth] failed to generate redirect URI after successful login ", domain.String(), zap.Error(err))
handleSsoError(w, r, redirectUri) handleSsoError(w, r, redirectUri)
return return
} }
@@ -266,14 +266,14 @@ func (ah *APIHandler) receiveSAML(w http.ResponseWriter, r *http.Request) {
ctx := context.Background() ctx := context.Background()
if !ah.CheckFeature(model.SSO) { if !ah.CheckFeature(model.SSO) {
zap.L().Error("[receiveSAML] sso requested but feature unavailable in org domain") zap.S().Errorf("[receiveSAML] sso requested but feature unavailable %s in org domain %s", model.SSO)
http.Redirect(w, r, fmt.Sprintf("%s?ssoerror=%s", redirectUri, "feature unavailable, please upgrade your billing plan to access this feature"), http.StatusMovedPermanently) http.Redirect(w, r, fmt.Sprintf("%s?ssoerror=%s", redirectUri, "feature unavailable, please upgrade your billing plan to access this feature"), http.StatusMovedPermanently)
return return
} }
err := r.ParseForm() err := r.ParseForm()
if err != nil { if err != nil {
zap.L().Error("[receiveSAML] failed to process response - invalid response from IDP", zap.Error(err), zap.Any("request", r)) zap.S().Errorf("[receiveSAML] failed to process response - invalid response from IDP", err, r)
handleSsoError(w, r, redirectUri) handleSsoError(w, r, redirectUri)
return return
} }
@@ -281,11 +281,11 @@ func (ah *APIHandler) receiveSAML(w http.ResponseWriter, r *http.Request) {
// the relay state is sent when a login request is submitted to // the relay state is sent when a login request is submitted to
// Idp. // Idp.
relayState := r.FormValue("RelayState") relayState := r.FormValue("RelayState")
zap.L().Debug("[receiveML] relay state", zap.String("relayState", relayState)) zap.S().Debug("[receiveML] relay state", zap.String("relayState", relayState))
parsedState, err := url.Parse(relayState) parsedState, err := url.Parse(relayState)
if err != nil || relayState == "" { if err != nil || relayState == "" {
zap.L().Error("[receiveSAML] failed to process response - invalid response from IDP", zap.Error(err), zap.Any("request", r)) zap.S().Errorf("[receiveSAML] failed to process response - invalid response from IDP", err, r)
handleSsoError(w, r, redirectUri) handleSsoError(w, r, redirectUri)
return return
} }
@@ -302,34 +302,34 @@ func (ah *APIHandler) receiveSAML(w http.ResponseWriter, r *http.Request) {
sp, err := domain.PrepareSamlRequest(parsedState) sp, err := domain.PrepareSamlRequest(parsedState)
if err != nil { if err != nil {
zap.L().Error("[receiveSAML] failed to prepare saml request for domain", zap.String("domain", domain.String()), zap.Error(err)) zap.S().Errorf("[receiveSAML] failed to prepare saml request for domain (%s): %v", domain.String(), err)
handleSsoError(w, r, redirectUri) handleSsoError(w, r, redirectUri)
return return
} }
assertionInfo, err := sp.RetrieveAssertionInfo(r.FormValue("SAMLResponse")) assertionInfo, err := sp.RetrieveAssertionInfo(r.FormValue("SAMLResponse"))
if err != nil { if err != nil {
zap.L().Error("[receiveSAML] failed to retrieve assertion info from saml response", zap.String("domain", domain.String()), zap.Error(err)) zap.S().Errorf("[receiveSAML] failed to retrieve assertion info from saml response for organization (%s): %v", domain.String(), err)
handleSsoError(w, r, redirectUri) handleSsoError(w, r, redirectUri)
return return
} }
if assertionInfo.WarningInfo.InvalidTime { if assertionInfo.WarningInfo.InvalidTime {
zap.L().Error("[receiveSAML] expired saml response", zap.String("domain", domain.String()), zap.Error(err)) zap.S().Errorf("[receiveSAML] expired saml response for organization (%s): %v", domain.String(), err)
handleSsoError(w, r, redirectUri) handleSsoError(w, r, redirectUri)
return return
} }
email := assertionInfo.NameID email := assertionInfo.NameID
if email == "" { if email == "" {
zap.L().Error("[receiveSAML] invalid email in the SSO response", zap.String("domain", domain.String())) zap.S().Errorf("[receiveSAML] invalid email in the SSO response (%s)", domain.String())
handleSsoError(w, r, redirectUri) handleSsoError(w, r, redirectUri)
return return
} }
nextPage, err := ah.AppDao().PrepareSsoRedirect(ctx, redirectUri, email) nextPage, err := ah.AppDao().PrepareSsoRedirect(ctx, redirectUri, email)
if err != nil { if err != nil {
zap.L().Error("[receiveSAML] failed to generate redirect URI after successful login ", zap.String("domain", domain.String()), zap.Error(err)) zap.S().Errorf("[receiveSAML] failed to generate redirect URI after successful login ", domain.String(), zap.Error(err))
handleSsoError(w, r, redirectUri) handleSsoError(w, r, redirectUri)
return return
} }

View File

@@ -1,13 +1,12 @@
package api package api
import ( import (
"net/http"
"github.com/gorilla/mux" "github.com/gorilla/mux"
"go.signoz.io/signoz/pkg/query-service/app/dashboards" "go.signoz.io/signoz/pkg/query-service/app/dashboards"
"go.signoz.io/signoz/pkg/query-service/auth" "go.signoz.io/signoz/pkg/query-service/auth"
"go.signoz.io/signoz/pkg/query-service/common" "go.signoz.io/signoz/pkg/query-service/common"
"go.signoz.io/signoz/pkg/query-service/model" "go.signoz.io/signoz/pkg/query-service/model"
"net/http"
) )
func (ah *APIHandler) lockDashboard(w http.ResponseWriter, r *http.Request) { func (ah *APIHandler) lockDashboard(w http.ResponseWriter, r *http.Request) {

View File

@@ -1,34 +0,0 @@
package api
import (
"net/http"
"strings"
"go.signoz.io/signoz/ee/query-service/integrations/gateway"
)
func (ah *APIHandler) ServeGatewayHTTP(rw http.ResponseWriter, req *http.Request) {
ctx := req.Context()
if !strings.HasPrefix(req.URL.Path, gateway.RoutePrefix+gateway.AllowedPrefix) {
rw.WriteHeader(http.StatusNotFound)
return
}
license, err := ah.LM().GetRepo().GetActiveLicense(ctx)
if err != nil {
RespondError(rw, err, nil)
return
}
//Create headers
var licenseKey string
if license != nil {
licenseKey = license.Key
}
req.Header.Set("X-Signoz-Cloud-Api-Key", licenseKey)
req.Header.Set("X-Consumer-Username", "lid:00000000-0000-0000-0000-000000000000")
req.Header.Set("X-Consumer-Groups", "ns:default")
ah.Gateway().ServeHTTP(rw, req)
}

View File

@@ -12,20 +12,6 @@ import (
"go.uber.org/zap" "go.uber.org/zap"
) )
type DayWiseBreakdown struct {
Type string `json:"type"`
Breakdown []DayWiseData `json:"breakdown"`
}
type DayWiseData struct {
Timestamp int64 `json:"timestamp"`
Count float64 `json:"count"`
Size float64 `json:"size"`
UnitPrice float64 `json:"unitPrice"`
Quantity float64 `json:"quantity"`
Total float64 `json:"total"`
}
type tierBreakdown struct { type tierBreakdown struct {
UnitPrice float64 `json:"unitPrice"` UnitPrice float64 `json:"unitPrice"`
Quantity float64 `json:"quantity"` Quantity float64 `json:"quantity"`
@@ -35,10 +21,9 @@ type tierBreakdown struct {
} }
type usageResponse struct { type usageResponse struct {
Type string `json:"type"` Type string `json:"type"`
Unit string `json:"unit"` Unit string `json:"unit"`
Tiers []tierBreakdown `json:"tiers"` Tiers []tierBreakdown `json:"tiers"`
DayWiseBreakdown DayWiseBreakdown `json:"dayWiseBreakdown"`
} }
type details struct { type details struct {
@@ -55,7 +40,6 @@ type billingDetails struct {
BillingPeriodEnd int64 `json:"billingPeriodEnd"` BillingPeriodEnd int64 `json:"billingPeriodEnd"`
Details details `json:"details"` Details details `json:"details"`
Discount float64 `json:"discount"` Discount float64 `json:"discount"`
SubscriptionStatus string `json:"subscriptionStatus"`
} `json:"data"` } `json:"data"`
} }
@@ -191,7 +175,7 @@ func (ah *APIHandler) listLicensesV2(w http.ResponseWriter, r *http.Request) {
url := fmt.Sprintf("%s/trial?licenseKey=%s", constants.LicenseSignozIo, currentActiveLicenseKey) url := fmt.Sprintf("%s/trial?licenseKey=%s", constants.LicenseSignozIo, currentActiveLicenseKey)
req, err := http.NewRequest("GET", url, nil) req, err := http.NewRequest("GET", url, nil)
if err != nil { if err != nil {
zap.L().Error("Error while creating request for trial details", zap.Error(err)) zap.S().Error("Error while creating request for trial details", err)
// If there is an error in fetching trial details, we will still return the license details // If there is an error in fetching trial details, we will still return the license details
// to avoid blocking the UI // to avoid blocking the UI
ah.Respond(w, resp) ah.Respond(w, resp)
@@ -200,7 +184,7 @@ func (ah *APIHandler) listLicensesV2(w http.ResponseWriter, r *http.Request) {
req.Header.Add("X-SigNoz-SecretKey", constants.LicenseAPIKey) req.Header.Add("X-SigNoz-SecretKey", constants.LicenseAPIKey)
trialResp, err := hClient.Do(req) trialResp, err := hClient.Do(req)
if err != nil { if err != nil {
zap.L().Error("Error while fetching trial details", zap.Error(err)) zap.S().Error("Error while fetching trial details", err)
// If there is an error in fetching trial details, we will still return the license details // If there is an error in fetching trial details, we will still return the license details
// to avoid incorrectly blocking the UI // to avoid incorrectly blocking the UI
ah.Respond(w, resp) ah.Respond(w, resp)
@@ -211,7 +195,7 @@ func (ah *APIHandler) listLicensesV2(w http.ResponseWriter, r *http.Request) {
trialRespBody, err := io.ReadAll(trialResp.Body) trialRespBody, err := io.ReadAll(trialResp.Body)
if err != nil || trialResp.StatusCode != http.StatusOK { if err != nil || trialResp.StatusCode != http.StatusOK {
zap.L().Error("Error while fetching trial details", zap.Error(err)) zap.S().Error("Error while fetching trial details", err)
// If there is an error in fetching trial details, we will still return the license details // If there is an error in fetching trial details, we will still return the license details
// to avoid incorrectly blocking the UI // to avoid incorrectly blocking the UI
ah.Respond(w, resp) ah.Respond(w, resp)
@@ -222,7 +206,7 @@ func (ah *APIHandler) listLicensesV2(w http.ResponseWriter, r *http.Request) {
var trialRespData model.SubscriptionServerResp var trialRespData model.SubscriptionServerResp
if err := json.Unmarshal(trialRespBody, &trialRespData); err != nil { if err := json.Unmarshal(trialRespBody, &trialRespData); err != nil {
zap.L().Error("Error while decoding trial details", zap.Error(err)) zap.S().Error("Error while decoding trial details", err)
// If there is an error in fetching trial details, we will still return the license details // If there is an error in fetching trial details, we will still return the license details
// to avoid incorrectly blocking the UI // to avoid incorrectly blocking the UI
ah.Respond(w, resp) ah.Respond(w, resp)

View File

@@ -0,0 +1,236 @@
package api
import (
"bytes"
"fmt"
"net/http"
"sync"
"text/template"
"time"
"go.signoz.io/signoz/pkg/query-service/app/metrics"
"go.signoz.io/signoz/pkg/query-service/app/parser"
"go.signoz.io/signoz/pkg/query-service/constants"
basemodel "go.signoz.io/signoz/pkg/query-service/model"
querytemplate "go.signoz.io/signoz/pkg/query-service/utils/queryTemplate"
"go.uber.org/zap"
)
func (ah *APIHandler) queryRangeMetricsV2(w http.ResponseWriter, r *http.Request) {
if !ah.CheckFeature(basemodel.CustomMetricsFunction) {
zap.S().Info("CustomMetricsFunction feature is not enabled in this plan")
ah.APIHandler.QueryRangeMetricsV2(w, r)
return
}
metricsQueryRangeParams, apiErrorObj := parser.ParseMetricQueryRangeParams(r)
if apiErrorObj != nil {
zap.S().Errorf(apiErrorObj.Err.Error())
RespondError(w, apiErrorObj, nil)
return
}
// prometheus instant query needs same timestamp
if metricsQueryRangeParams.CompositeMetricQuery.PanelType == basemodel.QUERY_VALUE &&
metricsQueryRangeParams.CompositeMetricQuery.QueryType == basemodel.PROM {
metricsQueryRangeParams.Start = metricsQueryRangeParams.End
}
// round up the end to nearest multiple
if metricsQueryRangeParams.CompositeMetricQuery.QueryType == basemodel.QUERY_BUILDER {
end := (metricsQueryRangeParams.End) / 1000
step := metricsQueryRangeParams.Step
metricsQueryRangeParams.End = (end / step * step) * 1000
}
type channelResult struct {
Series []*basemodel.Series
TableName string
Err error
Name string
Query string
}
execClickHouseQueries := func(queries map[string]string) ([]*basemodel.Series, []string, error, map[string]string) {
var seriesList []*basemodel.Series
var tableName []string
ch := make(chan channelResult, len(queries))
var wg sync.WaitGroup
for name, query := range queries {
wg.Add(1)
go func(name, query string) {
defer wg.Done()
seriesList, tableName, err := ah.opts.DataConnector.GetMetricResultEE(r.Context(), query)
for _, series := range seriesList {
series.QueryName = name
}
if err != nil {
ch <- channelResult{Err: fmt.Errorf("error in query-%s: %v", name, err), Name: name, Query: query}
return
}
ch <- channelResult{Series: seriesList, TableName: tableName}
}(name, query)
}
wg.Wait()
close(ch)
var errs []error
errQuriesByName := make(map[string]string)
// read values from the channel
for r := range ch {
if r.Err != nil {
errs = append(errs, r.Err)
errQuriesByName[r.Name] = r.Query
continue
}
seriesList = append(seriesList, r.Series...)
tableName = append(tableName, r.TableName)
}
if len(errs) != 0 {
return nil, nil, fmt.Errorf("encountered multiple errors: %s", metrics.FormatErrs(errs, "\n")), errQuriesByName
}
return seriesList, tableName, nil, nil
}
execPromQueries := func(metricsQueryRangeParams *basemodel.QueryRangeParamsV2) ([]*basemodel.Series, error, map[string]string) {
var seriesList []*basemodel.Series
ch := make(chan channelResult, len(metricsQueryRangeParams.CompositeMetricQuery.PromQueries))
var wg sync.WaitGroup
for name, query := range metricsQueryRangeParams.CompositeMetricQuery.PromQueries {
if query.Disabled {
continue
}
wg.Add(1)
go func(name string, query *basemodel.PromQuery) {
var seriesList []*basemodel.Series
defer wg.Done()
tmpl := template.New("promql-query")
tmpl, tmplErr := tmpl.Parse(query.Query)
if tmplErr != nil {
ch <- channelResult{Err: fmt.Errorf("error in parsing query-%s: %v", name, tmplErr), Name: name, Query: query.Query}
return
}
var queryBuf bytes.Buffer
tmplErr = tmpl.Execute(&queryBuf, metricsQueryRangeParams.Variables)
if tmplErr != nil {
ch <- channelResult{Err: fmt.Errorf("error in parsing query-%s: %v", name, tmplErr), Name: name, Query: query.Query}
return
}
query.Query = queryBuf.String()
queryModel := basemodel.QueryRangeParams{
Start: time.UnixMilli(metricsQueryRangeParams.Start),
End: time.UnixMilli(metricsQueryRangeParams.End),
Step: time.Duration(metricsQueryRangeParams.Step * int64(time.Second)),
Query: query.Query,
}
promResult, _, err := ah.opts.DataConnector.GetQueryRangeResult(r.Context(), &queryModel)
if err != nil {
ch <- channelResult{Err: fmt.Errorf("error in query-%s: %v", name, err), Name: name, Query: query.Query}
return
}
matrix, _ := promResult.Matrix()
for _, v := range matrix {
var s basemodel.Series
s.QueryName = name
s.Labels = v.Metric.Copy().Map()
for _, p := range v.Floats {
s.Points = append(s.Points, basemodel.MetricPoint{Timestamp: p.T, Value: p.F})
}
seriesList = append(seriesList, &s)
}
ch <- channelResult{Series: seriesList}
}(name, query)
}
wg.Wait()
close(ch)
var errs []error
errQuriesByName := make(map[string]string)
// read values from the channel
for r := range ch {
if r.Err != nil {
errs = append(errs, r.Err)
errQuriesByName[r.Name] = r.Query
continue
}
seriesList = append(seriesList, r.Series...)
}
if len(errs) != 0 {
return nil, fmt.Errorf("encountered multiple errors: %s", metrics.FormatErrs(errs, "\n")), errQuriesByName
}
return seriesList, nil, nil
}
var seriesList []*basemodel.Series
var tableName []string
var err error
var errQuriesByName map[string]string
switch metricsQueryRangeParams.CompositeMetricQuery.QueryType {
case basemodel.QUERY_BUILDER:
runQueries := metrics.PrepareBuilderMetricQueries(metricsQueryRangeParams, constants.SIGNOZ_TIMESERIES_TABLENAME)
if runQueries.Err != nil {
RespondError(w, &basemodel.ApiError{Typ: basemodel.ErrorBadData, Err: runQueries.Err}, nil)
return
}
seriesList, tableName, err, errQuriesByName = execClickHouseQueries(runQueries.Queries)
case basemodel.CLICKHOUSE:
queries := make(map[string]string)
for name, chQuery := range metricsQueryRangeParams.CompositeMetricQuery.ClickHouseQueries {
if chQuery.Disabled {
continue
}
tmpl := template.New("clickhouse-query")
tmpl, err := tmpl.Parse(chQuery.Query)
if err != nil {
RespondError(w, &basemodel.ApiError{Typ: basemodel.ErrorBadData, Err: err}, nil)
return
}
var query bytes.Buffer
// replace go template variables
querytemplate.AssignReservedVars(metricsQueryRangeParams)
err = tmpl.Execute(&query, metricsQueryRangeParams.Variables)
if err != nil {
RespondError(w, &basemodel.ApiError{Typ: basemodel.ErrorBadData, Err: err}, nil)
return
}
queries[name] = query.String()
}
seriesList, tableName, err, errQuriesByName = execClickHouseQueries(queries)
case basemodel.PROM:
seriesList, err, errQuriesByName = execPromQueries(metricsQueryRangeParams)
default:
err = fmt.Errorf("invalid query type")
RespondError(w, &basemodel.ApiError{Typ: basemodel.ErrorBadData, Err: err}, errQuriesByName)
return
}
if err != nil {
apiErrObj := &basemodel.ApiError{Typ: basemodel.ErrorBadData, Err: err}
RespondError(w, apiErrObj, errQuriesByName)
return
}
if metricsQueryRangeParams.CompositeMetricQuery.PanelType == basemodel.QUERY_VALUE &&
len(seriesList) > 1 &&
(metricsQueryRangeParams.CompositeMetricQuery.QueryType == basemodel.QUERY_BUILDER ||
metricsQueryRangeParams.CompositeMetricQuery.QueryType == basemodel.CLICKHOUSE) {
RespondError(w, &basemodel.ApiError{Typ: basemodel.ErrorBadData, Err: fmt.Errorf("invalid: query resulted in more than one series for value type")}, nil)
return
}
type ResponseFormat struct {
ResultType string `json:"resultType"`
Result []*basemodel.Series `json:"result"`
TableName []string `json:"tableName"`
}
resp := ResponseFormat{ResultType: "matrix", Result: seriesList, TableName: tableName}
ah.Respond(w, resp)
}

View File

@@ -12,7 +12,6 @@ import (
"github.com/gorilla/mux" "github.com/gorilla/mux"
"go.signoz.io/signoz/ee/query-service/model" "go.signoz.io/signoz/ee/query-service/model"
"go.signoz.io/signoz/pkg/query-service/auth" "go.signoz.io/signoz/pkg/query-service/auth"
baseconstants "go.signoz.io/signoz/pkg/query-service/constants"
basemodel "go.signoz.io/signoz/pkg/query-service/model" basemodel "go.signoz.io/signoz/pkg/query-service/model"
"go.uber.org/zap" "go.uber.org/zap"
) )
@@ -29,74 +28,11 @@ func generatePATToken() string {
func (ah *APIHandler) createPAT(w http.ResponseWriter, r *http.Request) { func (ah *APIHandler) createPAT(w http.ResponseWriter, r *http.Request) {
ctx := context.Background() ctx := context.Background()
req := model.CreatePATRequestBody{}
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
RespondError(w, model.BadRequest(err), nil)
return
}
user, err := auth.GetUserFromRequest(r)
if err != nil {
RespondError(w, &model.ApiError{
Typ: model.ErrorUnauthorized,
Err: err,
}, nil)
return
}
pat := model.PAT{
Name: req.Name,
Role: req.Role,
ExpiresAt: req.ExpiresInDays,
}
err = validatePATRequest(pat)
if err != nil {
RespondError(w, model.BadRequest(err), nil)
return
}
// All the PATs are associated with the user creating the PAT.
pat.UserID = user.Id
pat.CreatedAt = time.Now().Unix()
pat.UpdatedAt = time.Now().Unix()
pat.LastUsed = 0
pat.Token = generatePATToken()
if pat.ExpiresAt != 0 {
// convert expiresAt to unix timestamp from days
pat.ExpiresAt = time.Now().Unix() + (pat.ExpiresAt * 24 * 60 * 60)
}
zap.L().Info("Got Create PAT request", zap.Any("pat", pat))
var apierr basemodel.BaseApiError
if pat, apierr = ah.AppDao().CreatePAT(ctx, pat); apierr != nil {
RespondError(w, apierr, nil)
return
}
ah.Respond(w, &pat)
}
func validatePATRequest(req model.PAT) error {
if req.Role == "" || (req.Role != baseconstants.ViewerGroup && req.Role != baseconstants.EditorGroup && req.Role != baseconstants.AdminGroup) {
return fmt.Errorf("valid role is required")
}
if req.ExpiresAt < 0 {
return fmt.Errorf("valid expiresAt is required")
}
if req.Name == "" {
return fmt.Errorf("valid name is required")
}
return nil
}
func (ah *APIHandler) updatePAT(w http.ResponseWriter, r *http.Request) {
ctx := context.Background()
req := model.PAT{} req := model.PAT{}
if err := json.NewDecoder(r.Body).Decode(&req); err != nil { if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
RespondError(w, model.BadRequest(err), nil) RespondError(w, model.BadRequest(err), nil)
return return
} }
user, err := auth.GetUserFromRequest(r) user, err := auth.GetUserFromRequest(r)
if err != nil { if err != nil {
RespondError(w, &model.ApiError{ RespondError(w, &model.ApiError{
@@ -106,23 +42,29 @@ func (ah *APIHandler) updatePAT(w http.ResponseWriter, r *http.Request) {
return return
} }
err = validatePATRequest(req) // All the PATs are associated with the user creating the PAT. Hence, the permissions
if err != nil { // associated with the PAT is also equivalent to that of the user.
RespondError(w, model.BadRequest(err), nil) req.UserID = user.Id
return req.CreatedAt = time.Now().Unix()
req.Token = generatePATToken()
// default expiry is 30 days
if req.ExpiresAt == 0 {
req.ExpiresAt = time.Now().AddDate(0, 0, 30).Unix()
}
// max expiry is 1 year
if req.ExpiresAt > time.Now().AddDate(1, 0, 0).Unix() {
req.ExpiresAt = time.Now().AddDate(1, 0, 0).Unix()
} }
req.UpdatedByUserID = user.Id zap.S().Debugf("Got PAT request: %+v", req)
id := mux.Vars(r)["id"]
req.UpdatedAt = time.Now().Unix()
zap.L().Info("Got Update PAT request", zap.Any("pat", req))
var apierr basemodel.BaseApiError var apierr basemodel.BaseApiError
if apierr = ah.AppDao().UpdatePAT(ctx, req, id); apierr != nil { if req, apierr = ah.AppDao().CreatePAT(ctx, req); apierr != nil {
RespondError(w, apierr, nil) RespondError(w, apierr, nil)
return return
} }
ah.Respond(w, map[string]string{"data": "pat updated successfully"}) ah.Respond(w, &req)
} }
func (ah *APIHandler) getPATs(w http.ResponseWriter, r *http.Request) { func (ah *APIHandler) getPATs(w http.ResponseWriter, r *http.Request) {
@@ -135,8 +77,8 @@ func (ah *APIHandler) getPATs(w http.ResponseWriter, r *http.Request) {
}, nil) }, nil)
return return
} }
zap.L().Info("Get PATs for user", zap.String("user_id", user.Id)) zap.S().Infof("Get PATs for user: %+v", user.Id)
pats, apierr := ah.AppDao().ListPATs(ctx) pats, apierr := ah.AppDao().ListPATs(ctx, user.Id)
if apierr != nil { if apierr != nil {
RespondError(w, apierr, nil) RespondError(w, apierr, nil)
return return
@@ -144,7 +86,7 @@ func (ah *APIHandler) getPATs(w http.ResponseWriter, r *http.Request) {
ah.Respond(w, pats) ah.Respond(w, pats)
} }
func (ah *APIHandler) revokePAT(w http.ResponseWriter, r *http.Request) { func (ah *APIHandler) deletePAT(w http.ResponseWriter, r *http.Request) {
ctx := context.Background() ctx := context.Background()
id := mux.Vars(r)["id"] id := mux.Vars(r)["id"]
user, err := auth.GetUserFromRequest(r) user, err := auth.GetUserFromRequest(r)
@@ -155,11 +97,22 @@ func (ah *APIHandler) revokePAT(w http.ResponseWriter, r *http.Request) {
}, nil) }, nil)
return return
} }
pat, apierr := ah.AppDao().GetPATByID(ctx, id)
zap.L().Info("Revoke PAT with id", zap.String("id", id)) if apierr != nil {
if apierr := ah.AppDao().RevokePAT(ctx, id, user.Id); apierr != nil {
RespondError(w, apierr, nil) RespondError(w, apierr, nil)
return return
} }
ah.Respond(w, map[string]string{"data": "pat revoked successfully"}) if pat.UserID != user.Id {
RespondError(w, &model.ApiError{
Typ: model.ErrorUnauthorized,
Err: fmt.Errorf("unauthorized PAT delete request"),
}, nil)
return
}
zap.S().Debugf("Delete PAT with id: %+v", id)
if apierr := ah.AppDao().DeletePAT(ctx, id); apierr != nil {
RespondError(w, apierr, nil)
return
}
ah.Respond(w, map[string]string{"data": "pat deleted successfully"})
} }

View File

@@ -2,8 +2,10 @@ package api
import ( import (
"net/http" "net/http"
"strconv"
"go.signoz.io/signoz/ee/query-service/app/db" "go.signoz.io/signoz/ee/query-service/app/db"
"go.signoz.io/signoz/ee/query-service/constants"
"go.signoz.io/signoz/ee/query-service/model" "go.signoz.io/signoz/ee/query-service/model"
baseapp "go.signoz.io/signoz/pkg/query-service/app" baseapp "go.signoz.io/signoz/pkg/query-service/app"
basemodel "go.signoz.io/signoz/pkg/query-service/model" basemodel "go.signoz.io/signoz/pkg/query-service/model"
@@ -13,17 +15,21 @@ import (
func (ah *APIHandler) searchTraces(w http.ResponseWriter, r *http.Request) { func (ah *APIHandler) searchTraces(w http.ResponseWriter, r *http.Request) {
if !ah.CheckFeature(basemodel.SmartTraceDetail) { if !ah.CheckFeature(basemodel.SmartTraceDetail) {
zap.L().Info("SmartTraceDetail feature is not enabled in this plan") zap.S().Info("SmartTraceDetail feature is not enabled in this plan")
ah.APIHandler.SearchTraces(w, r) ah.APIHandler.SearchTraces(w, r)
return return
} }
searchTracesParams, err := baseapp.ParseSearchTracesParams(r) traceId, spanId, levelUpInt, levelDownInt, err := baseapp.ParseSearchTracesParams(r)
if err != nil { if err != nil {
RespondError(w, &model.ApiError{Typ: model.ErrorBadData, Err: err}, "Error reading params") RespondError(w, &model.ApiError{Typ: model.ErrorBadData, Err: err}, "Error reading params")
return return
} }
spanLimit, err := strconv.Atoi(constants.SpanLimitStr)
result, err := ah.opts.DataConnector.SearchTraces(r.Context(), searchTracesParams, db.SmartTraceAlgorithm) if err != nil {
zap.S().Error("Error during strconv.Atoi() on SPAN_LIMIT env variable: ", err)
return
}
result, err := ah.opts.DataConnector.SearchTraces(r.Context(), traceId, spanId, levelUpInt, levelDownInt, spanLimit, db.SmartTraceAlgorithm)
if ah.HandleError(w, err, http.StatusBadRequest) { if ah.HandleError(w, err, http.StatusBadRequest) {
return return
} }

View File

@@ -22,7 +22,7 @@ import (
func (r *ClickhouseReader) GetMetricResultEE(ctx context.Context, query string) ([]*basemodel.Series, string, error) { func (r *ClickhouseReader) GetMetricResultEE(ctx context.Context, query string) ([]*basemodel.Series, string, error) {
defer utils.Elapsed("GetMetricResult")() defer utils.Elapsed("GetMetricResult")()
zap.L().Info("Executing metric result query: ", zap.String("query", query)) zap.S().Infof("Executing metric result query: %s", query)
var hash string var hash string
// If getSubTreeSpans function is used in the clickhouse query // If getSubTreeSpans function is used in the clickhouse query
@@ -38,8 +38,9 @@ func (r *ClickhouseReader) GetMetricResultEE(ctx context.Context, query string)
} }
rows, err := r.conn.Query(ctx, query) rows, err := r.conn.Query(ctx, query)
zap.S().Debug(query)
if err != nil { if err != nil {
zap.L().Error("Error in processing query", zap.Error(err)) zap.S().Debug("Error in processing query: ", err)
return nil, "", fmt.Errorf("error in processing query") return nil, "", fmt.Errorf("error in processing query")
} }
@@ -116,7 +117,7 @@ func (r *ClickhouseReader) GetMetricResultEE(ctx context.Context, query string)
groupAttributes[colName] = fmt.Sprintf("%v", reflect.ValueOf(v).Elem().Int()) groupAttributes[colName] = fmt.Sprintf("%v", reflect.ValueOf(v).Elem().Int())
} }
default: default:
zap.L().Error("invalid var found in metric builder query result", zap.Any("var", v), zap.String("colName", colName)) zap.S().Errorf("invalid var found in metric builder query result", v, colName)
} }
} }
sort.Strings(groupBy) sort.Strings(groupBy)
@@ -139,7 +140,7 @@ func (r *ClickhouseReader) GetMetricResultEE(ctx context.Context, query string)
} }
// err = r.conn.Exec(ctx, "DROP TEMPORARY TABLE IF EXISTS getSubTreeSpans"+hash) // err = r.conn.Exec(ctx, "DROP TEMPORARY TABLE IF EXISTS getSubTreeSpans"+hash)
// if err != nil { // if err != nil {
// zap.L().Error("Error in dropping temporary table: ", err) // zap.S().Error("Error in dropping temporary table: ", err)
// return nil, err // return nil, err
// } // }
if hash == "" { if hash == "" {
@@ -151,7 +152,7 @@ func (r *ClickhouseReader) GetMetricResultEE(ctx context.Context, query string)
func (r *ClickhouseReader) getSubTreeSpansCustomFunction(ctx context.Context, query string, hash string) (string, string, error) { func (r *ClickhouseReader) getSubTreeSpansCustomFunction(ctx context.Context, query string, hash string) (string, string, error) {
zap.L().Debug("Executing getSubTreeSpans function") zap.S().Debugf("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;` // 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;`
@@ -161,28 +162,28 @@ func (r *ClickhouseReader) getSubTreeSpansCustomFunction(ctx context.Context, qu
err := r.conn.Exec(ctx, "DROP TABLE IF EXISTS getSubTreeSpans"+hash) err := r.conn.Exec(ctx, "DROP TABLE IF EXISTS getSubTreeSpans"+hash)
if err != nil { if err != nil {
zap.L().Error("Error in dropping temporary table", zap.Error(err)) zap.S().Error("Error in dropping temporary table: ", err)
return query, hash, err return query, hash, err
} }
// Create temporary table to store the getSubTreeSpans() results // Create temporary table to store the getSubTreeSpans() results
zap.L().Debug("Creating temporary table getSubTreeSpans", zap.String("hash", hash)) zap.S().Debugf("Creating temporary table getSubTreeSpans%s", 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)") 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 { if err != nil {
zap.L().Error("Error in creating temporary table", zap.Error(err)) zap.S().Error("Error in creating temporary table: ", err)
return query, hash, err return query, hash, err
} }
var getSpansSubQueryDBResponses []model.GetSpansSubQueryDBResponse var getSpansSubQueryDBResponses []model.GetSpansSubQueryDBResponse
getSpansSubQuery := subtreeInput getSpansSubQuery := subtreeInput
// Execute the subTree query // Execute the subTree query
zap.L().Debug("Executing subTree query", zap.String("query", getSpansSubQuery)) zap.S().Debugf("Executing subTree query: %s", getSpansSubQuery)
err = r.conn.Select(ctx, &getSpansSubQueryDBResponses, getSpansSubQuery) err = r.conn.Select(ctx, &getSpansSubQueryDBResponses, getSpansSubQuery)
// zap.L().Info(getSpansSubQuery) // zap.S().Info(getSpansSubQuery)
if err != nil { if err != nil {
zap.L().Error("Error in processing sql query", zap.Error(err)) zap.S().Debug("Error in processing sql query: ", err)
return query, hash, fmt.Errorf("Error in processing sql query") return query, hash, fmt.Errorf("Error in processing sql query")
} }
@@ -195,16 +196,16 @@ func (r *ClickhouseReader) getSubTreeSpansCustomFunction(ctx context.Context, qu
if len(getSpansSubQueryDBResponses) == 0 { if len(getSpansSubQueryDBResponses) == 0 {
return query, hash, fmt.Errorf("No spans found for the given query") 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)) zap.S().Debugf("Executing query to fetch all the spans from the same TraceID: %s", modelQuery)
err = r.conn.Select(ctx, &searchScanResponses, modelQuery, getSpansSubQueryDBResponses[0].TraceID) err = r.conn.Select(ctx, &searchScanResponses, modelQuery, getSpansSubQueryDBResponses[0].TraceID)
if err != nil { if err != nil {
zap.L().Error("Error in processing sql query", zap.Error(err)) zap.S().Debug("Error in processing sql query: ", err)
return query, hash, fmt.Errorf("Error in processing sql query") return query, hash, fmt.Errorf("Error in processing sql query")
} }
// Process model to fetch the spans // Process model to fetch the spans
zap.L().Debug("Processing model to fetch the spans") zap.S().Debugf("Processing model to fetch the spans")
searchSpanResponses := []basemodel.SearchSpanResponseItem{} searchSpanResponses := []basemodel.SearchSpanResponseItem{}
for _, item := range searchScanResponses { for _, item := range searchScanResponses {
var jsonItem basemodel.SearchSpanResponseItem var jsonItem basemodel.SearchSpanResponseItem
@@ -217,17 +218,17 @@ func (r *ClickhouseReader) getSubTreeSpansCustomFunction(ctx context.Context, qu
} }
// Build the subtree and store all the subtree spans in temporary table getSubTreeSpans+hash // 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 // 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)) zap.S().Debugf("Building the subtree to store all the subtree spans in temporary table getSubTreeSpans%s", hash)
treeSearchResponse, err := getSubTreeAlgorithm(searchSpanResponses, getSpansSubQueryDBResponses) treeSearchResponse, err := getSubTreeAlgorithm(searchSpanResponses, getSpansSubQueryDBResponses)
if err != nil { if err != nil {
zap.L().Error("Error in getSubTreeAlgorithm function", zap.Error(err)) zap.S().Error("Error in getSubTreeAlgorithm function: ", err)
return query, hash, err return query, hash, err
} }
zap.L().Debug("Preparing batch to store subtree spans in temporary table getSubTreeSpans", zap.String("hash", hash)) zap.S().Debugf("Preparing batch to store subtree spans in temporary table getSubTreeSpans%s", hash)
statement, err := r.conn.PrepareBatch(context.Background(), fmt.Sprintf("INSERT INTO getSubTreeSpans"+hash)) statement, err := r.conn.PrepareBatch(context.Background(), fmt.Sprintf("INSERT INTO getSubTreeSpans"+hash))
if err != nil { if err != nil {
zap.L().Error("Error in preparing batch statement", zap.Error(err)) zap.S().Error("Error in preparing batch statement: ", err)
return query, hash, err return query, hash, err
} }
for _, span := range treeSearchResponse { for _, span := range treeSearchResponse {
@@ -250,14 +251,14 @@ func (r *ClickhouseReader) getSubTreeSpansCustomFunction(ctx context.Context, qu
span.Events, span.Events,
) )
if err != nil { if err != nil {
zap.L().Error("Error in processing sql query", zap.Error(err)) zap.S().Debug("Error in processing sql query: ", err)
return query, hash, err return query, hash, err
} }
} }
zap.L().Debug("Inserting the subtree spans in temporary table getSubTreeSpans", zap.String("hash", hash)) zap.S().Debugf("Inserting the subtree spans in temporary table getSubTreeSpans%s", hash)
err = statement.Send() err = statement.Send()
if err != nil { if err != nil {
zap.L().Error("Error in sending statement", zap.Error(err)) zap.S().Error("Error in sending statement: ", err)
return query, hash, err return query, hash, err
} }
return query, hash, nil return query, hash, nil
@@ -322,7 +323,7 @@ func getSubTreeAlgorithm(payload []basemodel.SearchSpanResponseItem, getSpansSub
spans = append(spans, span) spans = append(spans, span)
} }
zap.L().Debug("Building Tree") zap.S().Debug("Building Tree")
roots, err := buildSpanTrees(&spans) roots, err := buildSpanTrees(&spans)
if err != nil { if err != nil {
return nil, err return nil, err
@@ -332,7 +333,7 @@ func getSubTreeAlgorithm(payload []basemodel.SearchSpanResponseItem, getSpansSub
// For each root, get the subtree spans // For each root, get the subtree spans
for _, getSpansSubQueryDBResponse := range getSpansSubQueryDBResponses { for _, getSpansSubQueryDBResponse := range getSpansSubQueryDBResponses {
targetSpan := &model.SpanForTraceDetails{} targetSpan := &model.SpanForTraceDetails{}
// zap.L().Debug("Building tree for span id: " + getSpansSubQueryDBResponse.SpanID + " " + strconv.Itoa(i+1) + " of " + strconv.Itoa(len(getSpansSubQueryDBResponses))) // zap.S().Debug("Building tree for span id: " + getSpansSubQueryDBResponse.SpanID + " " + strconv.Itoa(i+1) + " of " + strconv.Itoa(len(getSpansSubQueryDBResponses)))
// Search target span object in the tree // Search target span object in the tree
for _, root := range roots { for _, root := range roots {
targetSpan, err = breadthFirstSearch(root, getSpansSubQueryDBResponse.SpanID) targetSpan, err = breadthFirstSearch(root, getSpansSubQueryDBResponse.SpanID)
@@ -340,7 +341,7 @@ func getSubTreeAlgorithm(payload []basemodel.SearchSpanResponseItem, getSpansSub
break break
} }
if err != nil { if err != nil {
zap.L().Error("Error during BreadthFirstSearch()", zap.Error(err)) zap.S().Error("Error during BreadthFirstSearch(): ", err)
return nil, err return nil, err
} }
} }

View File

@@ -13,11 +13,6 @@ import (
func SmartTraceAlgorithm(payload []basemodel.SearchSpanResponseItem, targetSpanId string, levelUp int, levelDown int, spanLimit int) ([]basemodel.SearchSpansResult, error) { func SmartTraceAlgorithm(payload []basemodel.SearchSpanResponseItem, targetSpanId string, levelUp int, levelDown int, spanLimit int) ([]basemodel.SearchSpansResult, error) {
var spans []*model.SpanForTraceDetails var spans []*model.SpanForTraceDetails
// if targetSpanId is null or not present then randomly select a span as targetSpanId
if (targetSpanId == "" || targetSpanId == "null") && len(payload) > 0 {
targetSpanId = payload[0].SpanID
}
// Build a slice of spans from the payload // Build a slice of spans from the payload
for _, spanItem := range payload { for _, spanItem := range payload {
var parentID string var parentID string
@@ -54,7 +49,7 @@ func SmartTraceAlgorithm(payload []basemodel.SearchSpanResponseItem, targetSpanI
break break
} }
if err != nil { if err != nil {
zap.L().Error("Error during BreadthFirstSearch()", zap.Error(err)) zap.S().Error("Error during BreadthFirstSearch(): ", err)
return nil, err return nil, err
} }
} }
@@ -120,7 +115,6 @@ func SmartTraceAlgorithm(payload []basemodel.SearchSpanResponseItem, targetSpanI
searchSpansResult := []basemodel.SearchSpansResult{{ searchSpansResult := []basemodel.SearchSpansResult{{
Columns: []string{"__time", "SpanId", "TraceId", "ServiceName", "Name", "Kind", "DurationNano", "TagsKeys", "TagsValues", "References", "Events", "HasError"}, Columns: []string{"__time", "SpanId", "TraceId", "ServiceName", "Name", "Kind", "DurationNano", "TagsKeys", "TagsValues", "References", "Events", "HasError"},
Events: make([][]interface{}, len(resultSpansSet)), Events: make([][]interface{}, len(resultSpansSet)),
IsSubTree: true,
}, },
} }
@@ -192,7 +186,7 @@ func buildSpanTrees(spansPtr *[]*model.SpanForTraceDetails) ([]*model.SpanForTra
// If the parent span is not found, add current span to list of roots // If the parent span is not found, add current span to list of roots
if parent == nil { if parent == nil {
// zap.L().Debug("Parent Span not found parent_id: ", span.ParentID) // zap.S().Debug("Parent Span not found parent_id: ", span.ParentID)
roots = append(roots, span) roots = append(roots, span)
span.ParentID = "" span.ParentID = ""
continue continue

View File

@@ -8,10 +8,8 @@ import (
"io" "io"
"net" "net"
"net/http" "net/http"
"net/http/httputil"
_ "net/http/pprof" // http profiler _ "net/http/pprof" // http profiler
"os" "os"
"regexp"
"time" "time"
"github.com/gorilla/handlers" "github.com/gorilla/handlers"
@@ -22,12 +20,10 @@ import (
"github.com/soheilhy/cmux" "github.com/soheilhy/cmux"
"go.signoz.io/signoz/ee/query-service/app/api" "go.signoz.io/signoz/ee/query-service/app/api"
"go.signoz.io/signoz/ee/query-service/app/db" "go.signoz.io/signoz/ee/query-service/app/db"
"go.signoz.io/signoz/ee/query-service/auth"
"go.signoz.io/signoz/ee/query-service/constants" "go.signoz.io/signoz/ee/query-service/constants"
"go.signoz.io/signoz/ee/query-service/dao" "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/interfaces"
baseauth "go.signoz.io/signoz/pkg/query-service/auth" "go.signoz.io/signoz/pkg/query-service/auth"
baseInterface "go.signoz.io/signoz/pkg/query-service/interfaces" baseInterface "go.signoz.io/signoz/pkg/query-service/interfaces"
v3 "go.signoz.io/signoz/pkg/query-service/model/v3" v3 "go.signoz.io/signoz/pkg/query-service/model/v3"
@@ -38,10 +34,10 @@ import (
baseapp "go.signoz.io/signoz/pkg/query-service/app" baseapp "go.signoz.io/signoz/pkg/query-service/app"
"go.signoz.io/signoz/pkg/query-service/app/dashboards" "go.signoz.io/signoz/pkg/query-service/app/dashboards"
baseexplorer "go.signoz.io/signoz/pkg/query-service/app/explorer" baseexplorer "go.signoz.io/signoz/pkg/query-service/app/explorer"
"go.signoz.io/signoz/pkg/query-service/app/integrations"
"go.signoz.io/signoz/pkg/query-service/app/logparsingpipeline" "go.signoz.io/signoz/pkg/query-service/app/logparsingpipeline"
"go.signoz.io/signoz/pkg/query-service/app/opamp" "go.signoz.io/signoz/pkg/query-service/app/opamp"
opAmpModel "go.signoz.io/signoz/pkg/query-service/app/opamp/model" opAmpModel "go.signoz.io/signoz/pkg/query-service/app/opamp/model"
baseauth "go.signoz.io/signoz/pkg/query-service/auth"
"go.signoz.io/signoz/pkg/query-service/cache" "go.signoz.io/signoz/pkg/query-service/cache"
baseconst "go.signoz.io/signoz/pkg/query-service/constants" baseconst "go.signoz.io/signoz/pkg/query-service/constants"
"go.signoz.io/signoz/pkg/query-service/healthcheck" "go.signoz.io/signoz/pkg/query-service/healthcheck"
@@ -73,7 +69,6 @@ type ServerOptions struct {
CacheConfigPath string CacheConfigPath string
FluxInterval string FluxInterval string
Cluster string Cluster string
GatewayUrl string
} }
// Server runs HTTP api service // Server runs HTTP api service
@@ -125,33 +120,8 @@ func NewServer(serverOptions *ServerOptions) (*Server, error) {
localDB.SetMaxOpenConns(10) 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
}
}
// initiate license manager // initiate license manager
lm, err := licensepkg.StartManager("sqlite", localDB, gatewayFeature) lm, err := licensepkg.StartManager("sqlite", localDB)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -163,7 +133,7 @@ func NewServer(serverOptions *ServerOptions) (*Server, error) {
var reader interfaces.DataConnector var reader interfaces.DataConnector
storage := os.Getenv("STORAGE") storage := os.Getenv("STORAGE")
if storage == "clickhouse" { if storage == "clickhouse" {
zap.L().Info("Using ClickHouse as datastore ...") zap.S().Info("Using ClickHouse as datastore ...")
qb := db.NewDataConnector( qb := db.NewDataConnector(
localDB, localDB,
serverOptions.PromConfigPath, serverOptions.PromConfigPath,
@@ -201,22 +171,13 @@ func NewServer(serverOptions *ServerOptions) (*Server, error) {
} }
// initiate opamp // initiate opamp
_, err = opAmpModel.InitDB(localDB) _, err = opAmpModel.InitDB(baseconst.RELATIONAL_DATASOURCE_PATH)
if err != nil { if err != nil {
return nil, err return nil, err
} }
integrationsController, err := integrations.NewController(localDB)
if err != nil {
return nil, fmt.Errorf(
"couldn't create integrations controller: %w", err,
)
}
// ingestion pipelines manager // ingestion pipelines manager
logParsingPipelineController, err := logparsingpipeline.NewLogParsingPipelinesController( logParsingPipelineController, err := logparsingpipeline.NewLogParsingPipelinesController(localDB, "sqlite")
localDB, "sqlite", integrationsController.GetPipelinesForInstalledIntegrations,
)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -232,7 +193,7 @@ func NewServer(serverOptions *ServerOptions) (*Server, error) {
} }
// start the usagemanager // start the usagemanager
usageManager, err := usage.New("sqlite", modelDao, lm.GetRepo(), reader.GetConn()) usageManager, err := usage.New("sqlite", localDB, lm.GetRepo(), reader.GetConn())
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -272,11 +233,9 @@ func NewServer(serverOptions *ServerOptions) (*Server, error) {
UsageManager: usageManager, UsageManager: usageManager,
FeatureFlags: lm, FeatureFlags: lm,
LicenseManager: lm, LicenseManager: lm,
IntegrationsController: integrationsController,
LogsParsingPipelineController: logParsingPipelineController, LogsParsingPipelineController: logParsingPipelineController,
Cache: c, Cache: c,
FluxInterval: fluxInterval, FluxInterval: fluxInterval,
Gateway: gatewayProxy,
} }
apiHandler, err := api.NewAPIHandler(apiOpts) apiHandler, err := api.NewAPIHandler(apiOpts)
@@ -319,7 +278,6 @@ func (s *Server) createPrivateServer(apiHandler *api.APIHandler) (*http.Server,
r := mux.NewRouter() r := mux.NewRouter()
r.Use(baseapp.LogCommentEnricher)
r.Use(setTimeoutMiddleware) r.Use(setTimeoutMiddleware)
r.Use(s.analyticsMiddleware) r.Use(s.analyticsMiddleware)
r.Use(loggingMiddlewarePrivate) r.Use(loggingMiddlewarePrivate)
@@ -346,22 +304,33 @@ func (s *Server) createPublicServer(apiHandler *api.APIHandler) (*http.Server, e
r := mux.NewRouter() r := mux.NewRouter()
// add auth middleware
getUserFromRequest := func(r *http.Request) (*basemodel.UserPayload, error) { getUserFromRequest := func(r *http.Request) (*basemodel.UserPayload, error) {
return auth.GetUserFromRequest(r, apiHandler) patToken := r.Header.Get("SIGNOZ-API-KEY")
if len(patToken) > 0 {
zap.S().Debugf("Received a non-zero length PAT token")
ctx := context.Background()
dao := apiHandler.AppDao()
user, err := dao.GetUserByPAT(ctx, patToken)
if err == nil && user != nil {
zap.S().Debugf("Found valid PAT user: %+v", user)
return user, nil
}
if err != nil {
zap.S().Debugf("Error while getting user for PAT: %+v", err)
}
}
return baseauth.GetUserFromRequest(r)
} }
am := baseapp.NewAuthMiddleware(getUserFromRequest) am := baseapp.NewAuthMiddleware(getUserFromRequest)
r.Use(baseapp.LogCommentEnricher)
r.Use(setTimeoutMiddleware) r.Use(setTimeoutMiddleware)
r.Use(s.analyticsMiddleware) r.Use(s.analyticsMiddleware)
r.Use(loggingMiddleware) r.Use(loggingMiddleware)
apiHandler.RegisterRoutes(r, am) apiHandler.RegisterRoutes(r, am)
apiHandler.RegisterMetricsRoutes(r, am)
apiHandler.RegisterLogsRoutes(r, am) apiHandler.RegisterLogsRoutes(r, am)
apiHandler.RegisterIntegrationRoutes(r, am)
apiHandler.RegisterQueryRangeV3Routes(r, am) apiHandler.RegisterQueryRangeV3Routes(r, am)
apiHandler.RegisterQueryRangeV4Routes(r, am)
c := cors.New(cors.Options{ c := cors.New(cors.Options{
AllowedOrigins: []string{"*"}, AllowedOrigins: []string{"*"},
@@ -422,14 +391,13 @@ func (lrw *loggingResponseWriter) Flush() {
lrw.ResponseWriter.(http.Flusher).Flush() lrw.ResponseWriter.(http.Flusher).Flush()
} }
func extractQueryRangeData(path string, r *http.Request) (map[string]interface{}, bool) { func extractQueryRangeV3Data(path string, r *http.Request) (map[string]interface{}, bool) {
pathToExtractBodyFromV3 := "/api/v3/query_range" pathToExtractBodyFrom := "/api/v3/query_range"
pathToExtractBodyFromV4 := "/api/v4/query_range"
data := map[string]interface{}{} data := map[string]interface{}{}
var postData *v3.QueryRangeParamsV3 var postData *v3.QueryRangeParamsV3
if (r.Method == "POST") && ((path == pathToExtractBodyFromV3) || (path == pathToExtractBodyFromV4)) { if path == pathToExtractBodyFrom && (r.Method == "POST") {
if r.Body != nil { if r.Body != nil {
bodyBytes, err := io.ReadAll(r.Body) bodyBytes, err := io.ReadAll(r.Body)
if err != nil { if err != nil {
@@ -447,68 +415,32 @@ func extractQueryRangeData(path string, r *http.Request) (map[string]interface{}
return nil, false return nil, false
} }
referrer := r.Header.Get("Referer")
dashboardMatched, err := regexp.MatchString(`/dashboard/[a-zA-Z0-9\-]+/(new|edit)(?:\?.*)?$`, referrer)
if err != nil {
zap.L().Error("error while matching the referrer", zap.Error(err))
}
alertMatched, err := regexp.MatchString(`/alerts/(new|edit)(?:\?.*)?$`, referrer)
if err != nil {
zap.L().Error("error while matching the alert: ", zap.Error(err))
}
logsExplorerMatched, err := regexp.MatchString(`/logs/logs-explorer(?:\?.*)?$`, referrer)
if err != nil {
zap.L().Error("error while matching the logs explorer: ", zap.Error(err))
}
traceExplorerMatched, err := regexp.MatchString(`/traces-explorer(?:\?.*)?$`, referrer)
if err != nil {
zap.L().Error("error while matching the trace explorer: ", zap.Error(err))
}
signozMetricsUsed := false signozMetricsUsed := false
signozLogsUsed := false signozLogsUsed := false
signozTracesUsed := false dataSources := []string{}
if postData != nil { if postData != nil {
if postData.CompositeQuery != nil { if postData.CompositeQuery != nil {
data["queryType"] = postData.CompositeQuery.QueryType data["queryType"] = postData.CompositeQuery.QueryType
data["panelType"] = postData.CompositeQuery.PanelType data["panelType"] = postData.CompositeQuery.PanelType
signozLogsUsed, signozMetricsUsed, signozTracesUsed = telemetry.GetInstance().CheckSigNozSignals(postData) signozLogsUsed, signozMetricsUsed = telemetry.GetInstance().CheckSigNozSignals(postData)
} }
} }
if signozMetricsUsed || signozLogsUsed || signozTracesUsed { if signozMetricsUsed || signozLogsUsed {
if signozMetricsUsed { if signozMetricsUsed {
dataSources = append(dataSources, "metrics")
telemetry.GetInstance().AddActiveMetricsUser() telemetry.GetInstance().AddActiveMetricsUser()
} }
if signozLogsUsed { if signozLogsUsed {
dataSources = append(dataSources, "logs")
telemetry.GetInstance().AddActiveLogsUser() telemetry.GetInstance().AddActiveLogsUser()
} }
if signozTracesUsed { data["dataSources"] = dataSources
telemetry.GetInstance().AddActiveTracesUser() userEmail, err := auth.GetEmailFromJwt(r.Context())
}
data["metricsUsed"] = signozMetricsUsed
data["logsUsed"] = signozLogsUsed
data["tracesUsed"] = signozTracesUsed
userEmail, err := baseauth.GetEmailFromJwt(r.Context())
if err == nil { if err == nil {
// switch case to set data["screen"] based on the referrer telemetry.GetInstance().SendEvent(telemetry.TELEMETRY_EVENT_QUERY_RANGE_V3, data, userEmail, true)
switch {
case dashboardMatched:
data["screen"] = "panel"
case alertMatched:
data["screen"] = "alert"
case logsExplorerMatched:
data["screen"] = "logs-explorer"
case traceExplorerMatched:
data["screen"] = "traces-explorer"
default:
data["screen"] = "unknown"
return data, true
}
telemetry.GetInstance().SendEvent(telemetry.TELEMETRY_EVENT_QUERY_RANGE_API, data, userEmail, true, false)
} }
} }
return data, true return data, true
@@ -530,12 +462,12 @@ func getActiveLogs(path string, r *http.Request) {
func (s *Server) analyticsMiddleware(next http.Handler) http.Handler { func (s *Server) analyticsMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
ctx := baseauth.AttachJwtToContext(r.Context(), r) ctx := auth.AttachJwtToContext(r.Context(), r)
r = r.WithContext(ctx) r = r.WithContext(ctx)
route := mux.CurrentRoute(r) route := mux.CurrentRoute(r)
path, _ := route.GetPathTemplate() path, _ := route.GetPathTemplate()
queryRangeData, metadataExists := extractQueryRangeData(path, r) queryRangeV3data, metadataExists := extractQueryRangeV3Data(path, r)
getActiveLogs(path, r) getActiveLogs(path, r)
lrw := NewLoggingResponseWriter(w) lrw := NewLoggingResponseWriter(w)
@@ -543,15 +475,15 @@ func (s *Server) analyticsMiddleware(next http.Handler) http.Handler {
data := map[string]interface{}{"path": path, "statusCode": lrw.statusCode} data := map[string]interface{}{"path": path, "statusCode": lrw.statusCode}
if metadataExists { if metadataExists {
for key, value := range queryRangeData { for key, value := range queryRangeV3data {
data[key] = value data[key] = value
} }
} }
if _, ok := telemetry.EnabledPaths()[path]; ok { if _, ok := telemetry.EnabledPaths()[path]; ok {
userEmail, err := baseauth.GetEmailFromJwt(r.Context()) userEmail, err := auth.GetEmailFromJwt(r.Context())
if err == nil { if err == nil {
telemetry.GetInstance().SendEvent(telemetry.TELEMETRY_EVENT_PATH, data, userEmail, true, false) telemetry.GetInstance().SendEvent(telemetry.TELEMETRY_EVENT_PATH, data, userEmail)
} }
} }
@@ -588,7 +520,7 @@ func (s *Server) initListeners() error {
return err return err
} }
zap.L().Info(fmt.Sprintf("Query server started listening on %s...", s.serverOptions.HTTPHostPort)) zap.S().Info(fmt.Sprintf("Query server started listening on %s...", s.serverOptions.HTTPHostPort))
// listen on private port to support internal services // listen on private port to support internal services
privateHostPort := s.serverOptions.PrivateHostPort privateHostPort := s.serverOptions.PrivateHostPort
@@ -601,7 +533,7 @@ func (s *Server) initListeners() error {
if err != nil { if err != nil {
return err return err
} }
zap.L().Info(fmt.Sprintf("Query server started listening on private port %s...", s.serverOptions.PrivateHostPort)) zap.S().Info(fmt.Sprintf("Query server started listening on private port %s...", s.serverOptions.PrivateHostPort))
return nil return nil
} }
@@ -613,7 +545,7 @@ func (s *Server) Start() error {
if !s.serverOptions.DisableRules { if !s.serverOptions.DisableRules {
s.ruleManager.Start() s.ruleManager.Start()
} else { } else {
zap.L().Info("msg: Rules disabled as rules.disable is set to TRUE") zap.S().Info("msg: Rules disabled as rules.disable is set to TRUE")
} }
err := s.initListeners() err := s.initListeners()
@@ -627,23 +559,23 @@ func (s *Server) Start() error {
} }
go func() { go func() {
zap.L().Info("Starting HTTP server", zap.Int("port", httpPort), zap.String("addr", s.serverOptions.HTTPHostPort)) zap.S().Info("Starting HTTP server", zap.Int("port", httpPort), zap.String("addr", s.serverOptions.HTTPHostPort))
switch err := s.httpServer.Serve(s.httpConn); err { switch err := s.httpServer.Serve(s.httpConn); err {
case nil, http.ErrServerClosed, cmux.ErrListenerClosed: case nil, http.ErrServerClosed, cmux.ErrListenerClosed:
// normal exit, nothing to do // normal exit, nothing to do
default: default:
zap.L().Error("Could not start HTTP server", zap.Error(err)) zap.S().Error("Could not start HTTP server", zap.Error(err))
} }
s.unavailableChannel <- healthcheck.Unavailable s.unavailableChannel <- healthcheck.Unavailable
}() }()
go func() { go func() {
zap.L().Info("Starting pprof server", zap.String("addr", baseconst.DebugHttpPort)) zap.S().Info("Starting pprof server", zap.String("addr", baseconst.DebugHttpPort))
err = http.ListenAndServe(baseconst.DebugHttpPort, nil) err = http.ListenAndServe(baseconst.DebugHttpPort, nil)
if err != nil { if err != nil {
zap.L().Error("Could not start pprof server", zap.Error(err)) zap.S().Error("Could not start pprof server", zap.Error(err))
} }
}() }()
@@ -653,14 +585,14 @@ func (s *Server) Start() error {
} }
go func() { go func() {
zap.L().Info("Starting Private HTTP server", zap.Int("port", privatePort), zap.String("addr", s.serverOptions.PrivateHostPort)) zap.S().Info("Starting Private HTTP server", zap.Int("port", privatePort), zap.String("addr", s.serverOptions.PrivateHostPort))
switch err := s.privateHTTP.Serve(s.privateConn); err { switch err := s.privateHTTP.Serve(s.privateConn); err {
case nil, http.ErrServerClosed, cmux.ErrListenerClosed: case nil, http.ErrServerClosed, cmux.ErrListenerClosed:
// normal exit, nothing to do // normal exit, nothing to do
zap.L().Info("private http server closed") zap.S().Info("private http server closed")
default: default:
zap.L().Error("Could not start private HTTP server", zap.Error(err)) zap.S().Error("Could not start private HTTP server", zap.Error(err))
} }
s.unavailableChannel <- healthcheck.Unavailable s.unavailableChannel <- healthcheck.Unavailable
@@ -668,10 +600,10 @@ func (s *Server) Start() error {
}() }()
go func() { go func() {
zap.L().Info("Starting OpAmp Websocket server", zap.String("addr", baseconst.OpAmpWsEndpoint)) zap.S().Info("Starting OpAmp Websocket server", zap.String("addr", baseconst.OpAmpWsEndpoint))
err := s.opampServer.Start(baseconst.OpAmpWsEndpoint) err := s.opampServer.Start(baseconst.OpAmpWsEndpoint)
if err != nil { if err != nil {
zap.L().Error("opamp ws server failed to start", zap.Error(err)) zap.S().Info("opamp ws server failed to start", err)
s.unavailableChannel <- healthcheck.Unavailable s.unavailableChannel <- healthcheck.Unavailable
} }
}() }()
@@ -739,7 +671,6 @@ func makeRulesManager(
Logger: nil, Logger: nil,
DisableRules: disableRules, DisableRules: disableRules,
FeatureFlags: fm, FeatureFlags: fm,
Reader: ch,
} }
// create Manager // create Manager
@@ -748,7 +679,7 @@ func makeRulesManager(
return nil, fmt.Errorf("rule manager error: %v", err) return nil, fmt.Errorf("rule manager error: %v", err)
} }
zap.L().Info("rules manager is ready") zap.S().Info("rules manager is ready")
return manager, nil return manager, nil
} }

View File

@@ -1,56 +0,0 @@
package auth
import (
"context"
"fmt"
"net/http"
"time"
"go.signoz.io/signoz/ee/query-service/app/api"
baseauth "go.signoz.io/signoz/pkg/query-service/auth"
basemodel "go.signoz.io/signoz/pkg/query-service/model"
"go.signoz.io/signoz/pkg/query-service/telemetry"
"go.uber.org/zap"
)
func GetUserFromRequest(r *http.Request, apiHandler *api.APIHandler) (*basemodel.UserPayload, error) {
patToken := r.Header.Get("SIGNOZ-API-KEY")
if len(patToken) > 0 {
zap.L().Debug("Received a non-zero length PAT token")
ctx := context.Background()
dao := apiHandler.AppDao()
pat, err := dao.GetPAT(ctx, patToken)
if err == nil && pat != nil {
zap.L().Debug("Found valid PAT: ", zap.Any("pat", pat))
if pat.ExpiresAt < time.Now().Unix() && pat.ExpiresAt != 0 {
zap.L().Info("PAT has expired: ", zap.Any("pat", pat))
return nil, fmt.Errorf("PAT has expired")
}
group, apiErr := dao.GetGroupByName(ctx, pat.Role)
if apiErr != nil {
zap.L().Error("Error while getting group for PAT: ", zap.Any("apiErr", apiErr))
return nil, apiErr
}
user, err := dao.GetUser(ctx, pat.UserID)
if err != nil {
zap.L().Error("Error while getting user for PAT: ", zap.Error(err))
return nil, err
}
telemetry.GetInstance().SetPatTokenUser()
dao.UpdatePATLastUsed(ctx, patToken, time.Now().Unix())
user.User.GroupId = group.Id
user.User.Id = pat.Id
return &basemodel.UserPayload{
User: user.User,
Role: pat.Role,
}, nil
}
if err != nil {
zap.L().Error("Error while getting user for PAT: ", zap.Error(err))
return nil, err
}
}
return baseauth.GetUserFromRequest(r)
}

View File

@@ -11,8 +11,7 @@ const (
var LicenseSignozIo = "https://license.signoz.io/api/v1" var LicenseSignozIo = "https://license.signoz.io/api/v1"
var LicenseAPIKey = GetOrDefaultEnv("SIGNOZ_LICENSE_API_KEY", "") var LicenseAPIKey = GetOrDefaultEnv("SIGNOZ_LICENSE_API_KEY", "")
var SaasSegmentKey = GetOrDefaultEnv("SIGNOZ_SAAS_SEGMENT_KEY", "") var SaasSegmentKey = GetOrDefaultEnv("SIGNOZ_SAAS_SEGMENT_KEY", "")
var SpanRenderLimitStr = GetOrDefaultEnv("SPAN_RENDER_LIMIT", "2500") var SpanLimitStr = GetOrDefaultEnv("SPAN_LIMIT", "5000")
var MaxSpansInTraceStr = GetOrDefaultEnv("MAX_SPANS_IN_TRACE", "250000")
func GetOrDefaultEnv(key string, fallback string) string { func GetOrDefaultEnv(key string, fallback string) string {
v := os.Getenv(key) v := os.Getenv(key)

View File

@@ -34,11 +34,9 @@ type ModelDao interface {
GetDomainByEmail(ctx context.Context, email string) (*model.OrgDomain, basemodel.BaseApiError) GetDomainByEmail(ctx context.Context, email string) (*model.OrgDomain, basemodel.BaseApiError)
CreatePAT(ctx context.Context, p model.PAT) (model.PAT, basemodel.BaseApiError) CreatePAT(ctx context.Context, p model.PAT) (model.PAT, basemodel.BaseApiError)
UpdatePAT(ctx context.Context, p model.PAT, id string) basemodel.BaseApiError
GetPAT(ctx context.Context, pat string) (*model.PAT, basemodel.BaseApiError) GetPAT(ctx context.Context, pat string) (*model.PAT, basemodel.BaseApiError)
UpdatePATLastUsed(ctx context.Context, pat string, lastUsed int64) basemodel.BaseApiError
GetPATByID(ctx context.Context, id string) (*model.PAT, basemodel.BaseApiError) GetPATByID(ctx context.Context, id string) (*model.PAT, basemodel.BaseApiError)
GetUserByPAT(ctx context.Context, token string) (*basemodel.UserPayload, basemodel.BaseApiError) GetUserByPAT(ctx context.Context, token string) (*basemodel.UserPayload, basemodel.BaseApiError)
ListPATs(ctx context.Context) ([]model.PAT, basemodel.BaseApiError) ListPATs(ctx context.Context, userID string) ([]model.PAT, basemodel.BaseApiError)
RevokePAT(ctx context.Context, id string, userID string) basemodel.BaseApiError DeletePAT(ctx context.Context, id string) basemodel.BaseApiError
} }

View File

@@ -22,19 +22,19 @@ func (m *modelDao) createUserForSAMLRequest(ctx context.Context, email string) (
domain, apierr := m.GetDomainByEmail(ctx, email) domain, apierr := m.GetDomainByEmail(ctx, email)
if apierr != nil { if apierr != nil {
zap.L().Error("failed to get domain from email", zap.Error(apierr)) zap.S().Errorf("failed to get domain from email", apierr)
return nil, model.InternalErrorStr("failed to get domain from email") return nil, model.InternalErrorStr("failed to get domain from email")
} }
hash, err := baseauth.PasswordHash(utils.GeneratePassowrd()) hash, err := baseauth.PasswordHash(utils.GeneratePassowrd())
if err != nil { if err != nil {
zap.L().Error("failed to generate password hash when registering a user via SSO redirect", zap.Error(err)) zap.S().Errorf("failed to generate password hash when registering a user via SSO redirect", zap.Error(err))
return nil, model.InternalErrorStr("failed to generate password hash") return nil, model.InternalErrorStr("failed to generate password hash")
} }
group, apiErr := m.GetGroupByName(ctx, baseconst.ViewerGroup) group, apiErr := m.GetGroupByName(ctx, baseconst.ViewerGroup)
if apiErr != nil { if apiErr != nil {
zap.L().Error("GetGroupByName failed", zap.Error(apiErr)) zap.S().Debugf("GetGroupByName failed, err: %v\n", apiErr.Err)
return nil, apiErr return nil, apiErr
} }
@@ -51,7 +51,7 @@ func (m *modelDao) createUserForSAMLRequest(ctx context.Context, email string) (
user, apiErr = m.CreateUser(ctx, user, false) user, apiErr = m.CreateUser(ctx, user, false)
if apiErr != nil { if apiErr != nil {
zap.L().Error("CreateUser failed", zap.Error(apiErr)) zap.S().Debugf("CreateUser failed, err: %v\n", apiErr.Err)
return nil, apiErr return nil, apiErr
} }
@@ -65,7 +65,7 @@ func (m *modelDao) PrepareSsoRedirect(ctx context.Context, redirectUri, email st
userPayload, apierr := m.GetUserByEmail(ctx, email) userPayload, apierr := m.GetUserByEmail(ctx, email)
if !apierr.IsNil() { if !apierr.IsNil() {
zap.L().Error("failed to get user with email received from auth provider", zap.String("error", apierr.Error())) zap.S().Errorf(" failed to get user with email received from auth provider", apierr.Error())
return "", model.BadRequestStr("invalid user email received from the auth provider") return "", model.BadRequestStr("invalid user email received from the auth provider")
} }
@@ -75,7 +75,7 @@ func (m *modelDao) PrepareSsoRedirect(ctx context.Context, redirectUri, email st
newUser, apiErr := m.createUserForSAMLRequest(ctx, email) newUser, apiErr := m.createUserForSAMLRequest(ctx, email)
user = newUser user = newUser
if apiErr != nil { if apiErr != nil {
zap.L().Error("failed to create user with email received from auth provider", zap.Error(apiErr)) zap.S().Errorf("failed to create user with email received from auth provider: %v", apierr.Error())
return "", apiErr return "", apiErr
} }
} else { } else {
@@ -84,7 +84,7 @@ func (m *modelDao) PrepareSsoRedirect(ctx context.Context, redirectUri, email st
tokenStore, err := baseauth.GenerateJWTForUser(user) tokenStore, err := baseauth.GenerateJWTForUser(user)
if err != nil { if err != nil {
zap.L().Error("failed to generate token for SSO login user", zap.Error(err)) zap.S().Errorf("failed to generate token for SSO login user", err)
return "", model.InternalErrorStr("failed to generate token for the user") return "", model.InternalErrorStr("failed to generate token for the user")
} }
@@ -143,8 +143,8 @@ func (m *modelDao) PrecheckLogin(ctx context.Context, email, sourceUrl string) (
// do nothing, just skip sso // do nothing, just skip sso
ssoAvailable = false ssoAvailable = false
default: default:
zap.L().Error("feature check failed", zap.String("featureKey", model.SSO), zap.Error(err)) zap.S().Errorf("feature check failed", zap.String("featureKey", model.SSO), zap.Error(err))
return resp, model.BadRequestStr(err.Error()) return resp, model.BadRequest(err)
} }
} }
@@ -160,7 +160,7 @@ func (m *modelDao) PrecheckLogin(ctx context.Context, email, sourceUrl string) (
if len(emailComponents) > 0 { if len(emailComponents) > 0 {
emailDomain = emailComponents[1] emailDomain = emailComponents[1]
} }
zap.L().Error("failed to get org domain from email", zap.String("emailDomain", emailDomain), zap.Error(apierr.ToError())) zap.S().Errorf("failed to get org domain from email", zap.String("emailDomain", emailDomain), apierr.ToError())
return resp, apierr return resp, apierr
} }
@@ -176,7 +176,7 @@ func (m *modelDao) PrecheckLogin(ctx context.Context, email, sourceUrl string) (
escapedUrl, _ := url.QueryUnescape(sourceUrl) escapedUrl, _ := url.QueryUnescape(sourceUrl)
siteUrl, err := url.Parse(escapedUrl) siteUrl, err := url.Parse(escapedUrl)
if err != nil { if err != nil {
zap.L().Error("failed to parse referer", zap.Error(err)) zap.S().Errorf("failed to parse referer", err)
return resp, model.InternalError(fmt.Errorf("failed to generate login request")) return resp, model.InternalError(fmt.Errorf("failed to generate login request"))
} }
@@ -185,7 +185,7 @@ func (m *modelDao) PrecheckLogin(ctx context.Context, email, sourceUrl string) (
resp.SsoUrl, err = orgDomain.BuildSsoUrl(siteUrl) resp.SsoUrl, err = orgDomain.BuildSsoUrl(siteUrl)
if err != nil { if err != nil {
zap.L().Error("failed to prepare saml request for domain", zap.String("domain", orgDomain.Name), zap.Error(err)) zap.S().Errorf("failed to prepare saml request for domain", zap.String("domain", orgDomain.Name), err)
return resp, model.InternalError(err) return resp, model.InternalError(err)
} }

View File

@@ -48,13 +48,13 @@ func (m *modelDao) GetDomainFromSsoResponse(ctx context.Context, relayState *url
if domainIdStr != "" { if domainIdStr != "" {
domainId, err := uuid.Parse(domainIdStr) domainId, err := uuid.Parse(domainIdStr)
if err != nil { if err != nil {
zap.L().Error("failed to parse domainId from relay state", zap.Error(err)) zap.S().Errorf("failed to parse domainId from relay state", err)
return nil, fmt.Errorf("failed to parse domainId from IdP response") return nil, fmt.Errorf("failed to parse domainId from IdP response")
} }
domain, err = m.GetDomain(ctx, domainId) domain, err = m.GetDomain(ctx, domainId)
if (err != nil) || domain == nil { if (err != nil) || domain == nil {
zap.L().Error("failed to find domain from domainId received in IdP response", zap.Error(err)) zap.S().Errorf("failed to find domain from domainId received in IdP response", err.Error())
return nil, fmt.Errorf("invalid credentials") return nil, fmt.Errorf("invalid credentials")
} }
} }
@@ -64,7 +64,7 @@ func (m *modelDao) GetDomainFromSsoResponse(ctx context.Context, relayState *url
domainFromDB, err := m.GetDomainByName(ctx, domainNameStr) domainFromDB, err := m.GetDomainByName(ctx, domainNameStr)
domain = domainFromDB domain = domainFromDB
if (err != nil) || domain == nil { if (err != nil) || domain == nil {
zap.L().Error("failed to find domain from domainName received in IdP response", zap.Error(err)) zap.S().Errorf("failed to find domain from domainName received in IdP response", err.Error())
return nil, fmt.Errorf("invalid credentials") return nil, fmt.Errorf("invalid credentials")
} }
} }
@@ -132,7 +132,7 @@ func (m *modelDao) ListDomains(ctx context.Context, orgId string) ([]model.OrgDo
for _, s := range stored { for _, s := range stored {
domain := model.OrgDomain{Id: s.Id, Name: s.Name, OrgId: s.OrgId} domain := model.OrgDomain{Id: s.Id, Name: s.Name, OrgId: s.OrgId}
if err := domain.LoadConfig(s.Data); err != nil { if err := domain.LoadConfig(s.Data); err != nil {
zap.L().Error("ListDomains() failed", zap.Error(err)) zap.S().Errorf("ListDomains() failed", zap.Error(err))
} }
domains = append(domains, domain) domains = append(domains, domain)
} }
@@ -153,7 +153,7 @@ func (m *modelDao) CreateDomain(ctx context.Context, domain *model.OrgDomain) ba
configJson, err := json.Marshal(domain) configJson, err := json.Marshal(domain)
if err != nil { if err != nil {
zap.L().Error("failed to unmarshal domain config", zap.Error(err)) zap.S().Errorf("failed to unmarshal domain config", zap.Error(err))
return model.InternalError(fmt.Errorf("domain creation failed")) return model.InternalError(fmt.Errorf("domain creation failed"))
} }
@@ -167,7 +167,7 @@ func (m *modelDao) CreateDomain(ctx context.Context, domain *model.OrgDomain) ba
time.Now().Unix()) time.Now().Unix())
if err != nil { if err != nil {
zap.L().Error("failed to insert domain in db", zap.Error(err)) zap.S().Errorf("failed to insert domain in db", zap.Error(err))
return model.InternalError(fmt.Errorf("domain creation failed")) return model.InternalError(fmt.Errorf("domain creation failed"))
} }
@@ -178,13 +178,13 @@ func (m *modelDao) CreateDomain(ctx context.Context, domain *model.OrgDomain) ba
func (m *modelDao) UpdateDomain(ctx context.Context, domain *model.OrgDomain) basemodel.BaseApiError { func (m *modelDao) UpdateDomain(ctx context.Context, domain *model.OrgDomain) basemodel.BaseApiError {
if domain.Id == uuid.Nil { if domain.Id == uuid.Nil {
zap.L().Error("domain update failed", zap.Error(fmt.Errorf("OrgDomain.Id is null"))) zap.S().Errorf("domain update failed", zap.Error(fmt.Errorf("OrgDomain.Id is null")))
return model.InternalError(fmt.Errorf("domain update failed")) return model.InternalError(fmt.Errorf("domain update failed"))
} }
configJson, err := json.Marshal(domain) configJson, err := json.Marshal(domain)
if err != nil { if err != nil {
zap.L().Error("domain update failed", zap.Error(err)) zap.S().Errorf("domain update failed", zap.Error(err))
return model.InternalError(fmt.Errorf("domain update failed")) return model.InternalError(fmt.Errorf("domain update failed"))
} }
@@ -195,7 +195,7 @@ func (m *modelDao) UpdateDomain(ctx context.Context, domain *model.OrgDomain) ba
domain.Id) domain.Id)
if err != nil { if err != nil {
zap.L().Error("domain update failed", zap.Error(err)) zap.S().Errorf("domain update failed", zap.Error(err))
return model.InternalError(fmt.Errorf("domain update failed")) return model.InternalError(fmt.Errorf("domain update failed"))
} }
@@ -206,7 +206,7 @@ func (m *modelDao) UpdateDomain(ctx context.Context, domain *model.OrgDomain) ba
func (m *modelDao) DeleteDomain(ctx context.Context, id uuid.UUID) basemodel.BaseApiError { func (m *modelDao) DeleteDomain(ctx context.Context, id uuid.UUID) basemodel.BaseApiError {
if id == uuid.Nil { if id == uuid.Nil {
zap.L().Error("domain delete failed", zap.Error(fmt.Errorf("OrgDomain.Id is null"))) zap.S().Errorf("domain delete failed", zap.Error(fmt.Errorf("OrgDomain.Id is null")))
return model.InternalError(fmt.Errorf("domain delete failed")) return model.InternalError(fmt.Errorf("domain delete failed"))
} }
@@ -215,7 +215,7 @@ func (m *modelDao) DeleteDomain(ctx context.Context, id uuid.UUID) basemodel.Bas
id) id)
if err != nil { if err != nil {
zap.L().Error("domain delete failed", zap.Error(err)) zap.S().Errorf("domain delete failed", zap.Error(err))
return model.InternalError(fmt.Errorf("domain delete failed")) return model.InternalError(fmt.Errorf("domain delete failed"))
} }

View File

@@ -7,7 +7,6 @@ import (
basedao "go.signoz.io/signoz/pkg/query-service/dao" basedao "go.signoz.io/signoz/pkg/query-service/dao"
basedsql "go.signoz.io/signoz/pkg/query-service/dao/sqlite" basedsql "go.signoz.io/signoz/pkg/query-service/dao/sqlite"
baseint "go.signoz.io/signoz/pkg/query-service/interfaces" baseint "go.signoz.io/signoz/pkg/query-service/interfaces"
"go.uber.org/zap"
) )
type modelDao struct { type modelDao struct {
@@ -29,41 +28,6 @@ func (m *modelDao) checkFeature(key string) error {
return m.flags.CheckFeature(key) return m.flags.CheckFeature(key)
} }
func columnExists(db *sqlx.DB, tableName, columnName string) bool {
query := fmt.Sprintf("PRAGMA table_info(%s);", tableName)
rows, err := db.Query(query)
if err != nil {
zap.L().Error("Failed to query table info", zap.Error(err))
return false
}
defer rows.Close()
var (
cid int
name string
ctype string
notnull int
dflt_value *string
pk int
)
for rows.Next() {
err := rows.Scan(&cid, &name, &ctype, &notnull, &dflt_value, &pk)
if err != nil {
zap.L().Error("Failed to scan table info", zap.Error(err))
return false
}
if name == columnName {
return true
}
}
err = rows.Err()
if err != nil {
zap.L().Error("Failed to scan table info", zap.Error(err))
return false
}
return false
}
// InitDB creates and extends base model DB repository // InitDB creates and extends base model DB repository
func InitDB(dataSourceName string) (*modelDao, error) { func InitDB(dataSourceName string) (*modelDao, error) {
dao, err := basedsql.InitDB(dataSourceName) dao, err := basedsql.InitDB(dataSourceName)
@@ -87,16 +51,11 @@ func InitDB(dataSourceName string) (*modelDao, error) {
); );
CREATE TABLE IF NOT EXISTS personal_access_tokens ( CREATE TABLE IF NOT EXISTS personal_access_tokens (
id INTEGER PRIMARY KEY AUTOINCREMENT, id INTEGER PRIMARY KEY AUTOINCREMENT,
role TEXT NOT NULL,
user_id TEXT NOT NULL, user_id TEXT NOT NULL,
token TEXT NOT NULL UNIQUE, token TEXT NOT NULL UNIQUE,
name TEXT NOT NULL, name TEXT NOT NULL,
created_at INTEGER NOT NULL, created_at INTEGER NOT NULL,
expires_at INTEGER NOT NULL, expires_at INTEGER NOT NULL,
updated_at INTEGER NOT NULL,
last_used INTEGER NOT NULL,
revoked BOOLEAN NOT NULL,
updated_by_user_id TEXT NOT NULL,
FOREIGN KEY(user_id) REFERENCES users(id) FOREIGN KEY(user_id) REFERENCES users(id)
); );
` `
@@ -106,36 +65,6 @@ func InitDB(dataSourceName string) (*modelDao, error) {
return nil, fmt.Errorf("error in creating tables: %v", err.Error()) return nil, fmt.Errorf("error in creating tables: %v", err.Error())
} }
if !columnExists(m.DB(), "personal_access_tokens", "role") {
_, err = m.DB().Exec("ALTER TABLE personal_access_tokens ADD COLUMN role TEXT NOT NULL DEFAULT 'ADMIN';")
if err != nil {
return nil, fmt.Errorf("error in adding column: %v", err.Error())
}
}
if !columnExists(m.DB(), "personal_access_tokens", "updated_at") {
_, err = m.DB().Exec("ALTER TABLE personal_access_tokens ADD COLUMN updated_at INTEGER NOT NULL DEFAULT 0;")
if err != nil {
return nil, fmt.Errorf("error in adding column: %v", err.Error())
}
}
if !columnExists(m.DB(), "personal_access_tokens", "last_used") {
_, err = m.DB().Exec("ALTER TABLE personal_access_tokens ADD COLUMN last_used INTEGER NOT NULL DEFAULT 0;")
if err != nil {
return nil, fmt.Errorf("error in adding column: %v", err.Error())
}
}
if !columnExists(m.DB(), "personal_access_tokens", "revoked") {
_, err = m.DB().Exec("ALTER TABLE personal_access_tokens ADD COLUMN revoked BOOLEAN NOT NULL DEFAULT FALSE;")
if err != nil {
return nil, fmt.Errorf("error in adding column: %v", err.Error())
}
}
if !columnExists(m.DB(), "personal_access_tokens", "updated_by_user_id") {
_, err = m.DB().Exec("ALTER TABLE personal_access_tokens ADD COLUMN updated_by_user_id TEXT NOT NULL DEFAULT '';")
if err != nil {
return nil, fmt.Errorf("error in adding column: %v", err.Error())
}
}
return m, nil return m, nil
} }

View File

@@ -4,7 +4,6 @@ import (
"context" "context"
"fmt" "fmt"
"strconv" "strconv"
"time"
"go.signoz.io/signoz/ee/query-service/model" "go.signoz.io/signoz/ee/query-service/model"
basemodel "go.signoz.io/signoz/pkg/query-service/model" basemodel "go.signoz.io/signoz/pkg/query-service/model"
@@ -13,124 +12,40 @@ import (
func (m *modelDao) CreatePAT(ctx context.Context, p model.PAT) (model.PAT, basemodel.BaseApiError) { func (m *modelDao) CreatePAT(ctx context.Context, p model.PAT) (model.PAT, basemodel.BaseApiError) {
result, err := m.DB().ExecContext(ctx, result, err := m.DB().ExecContext(ctx,
"INSERT INTO personal_access_tokens (user_id, token, role, name, created_at, expires_at, updated_at, updated_by_user_id, last_used, revoked) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)", "INSERT INTO personal_access_tokens (user_id, token, name, created_at, expires_at) VALUES ($1, $2, $3, $4, $5)",
p.UserID, p.UserID,
p.Token, p.Token,
p.Role,
p.Name, p.Name,
p.CreatedAt, p.CreatedAt,
p.ExpiresAt, p.ExpiresAt)
p.UpdatedAt,
p.UpdatedByUserID,
p.LastUsed,
p.Revoked,
)
if err != nil { if err != nil {
zap.L().Error("Failed to insert PAT in db, err: %v", zap.Error(err)) zap.S().Errorf("Failed to insert PAT in db, err: %v", zap.Error(err))
return model.PAT{}, model.InternalError(fmt.Errorf("PAT insertion failed")) return model.PAT{}, model.InternalError(fmt.Errorf("PAT insertion failed"))
} }
id, err := result.LastInsertId() id, err := result.LastInsertId()
if err != nil { if err != nil {
zap.L().Error("Failed to get last inserted id, err: %v", zap.Error(err)) zap.S().Errorf("Failed to get last inserted id, err: %v", zap.Error(err))
return model.PAT{}, model.InternalError(fmt.Errorf("PAT insertion failed")) return model.PAT{}, model.InternalError(fmt.Errorf("PAT insertion failed"))
} }
p.Id = strconv.Itoa(int(id)) p.Id = strconv.Itoa(int(id))
createdByUser, _ := m.GetUser(ctx, p.UserID)
if createdByUser == nil {
p.CreatedByUser = model.User{
NotFound: true,
}
} else {
p.CreatedByUser = model.User{
Id: createdByUser.Id,
Name: createdByUser.Name,
Email: createdByUser.Email,
CreatedAt: createdByUser.CreatedAt,
ProfilePictureURL: createdByUser.ProfilePictureURL,
NotFound: false,
}
}
return p, nil return p, nil
} }
func (m *modelDao) UpdatePAT(ctx context.Context, p model.PAT, id string) basemodel.BaseApiError { func (m *modelDao) ListPATs(ctx context.Context, userID string) ([]model.PAT, basemodel.BaseApiError) {
_, err := m.DB().ExecContext(ctx,
"UPDATE personal_access_tokens SET role=$1, name=$2, updated_at=$3, updated_by_user_id=$4 WHERE id=$5 and revoked=false;",
p.Role,
p.Name,
p.UpdatedAt,
p.UpdatedByUserID,
id)
if err != nil {
zap.L().Error("Failed to update PAT in db, err: %v", zap.Error(err))
return model.InternalError(fmt.Errorf("PAT update failed"))
}
return nil
}
func (m *modelDao) UpdatePATLastUsed(ctx context.Context, token string, lastUsed int64) basemodel.BaseApiError {
_, err := m.DB().ExecContext(ctx,
"UPDATE personal_access_tokens SET last_used=$1 WHERE token=$2 and revoked=false;",
lastUsed,
token)
if err != nil {
zap.L().Error("Failed to update PAT last used in db, err: %v", zap.Error(err))
return model.InternalError(fmt.Errorf("PAT last used update failed"))
}
return nil
}
func (m *modelDao) ListPATs(ctx context.Context) ([]model.PAT, basemodel.BaseApiError) {
pats := []model.PAT{} pats := []model.PAT{}
if err := m.DB().Select(&pats, "SELECT * FROM personal_access_tokens WHERE revoked=false ORDER by updated_at DESC;"); err != nil { if err := m.DB().Select(&pats, `SELECT * FROM personal_access_tokens WHERE user_id=?;`, userID); err != nil {
zap.L().Error("Failed to fetch PATs err: %v", zap.Error(err)) zap.S().Errorf("Failed to fetch PATs for user: %s, err: %v", userID, zap.Error(err))
return nil, model.InternalError(fmt.Errorf("failed to fetch PATs")) return nil, model.InternalError(fmt.Errorf("failed to fetch PATs"))
} }
for i := range pats {
createdByUser, _ := m.GetUser(ctx, pats[i].UserID)
if createdByUser == nil {
pats[i].CreatedByUser = model.User{
NotFound: true,
}
} else {
pats[i].CreatedByUser = model.User{
Id: createdByUser.Id,
Name: createdByUser.Name,
Email: createdByUser.Email,
CreatedAt: createdByUser.CreatedAt,
ProfilePictureURL: createdByUser.ProfilePictureURL,
NotFound: false,
}
}
updatedByUser, _ := m.GetUser(ctx, pats[i].UpdatedByUserID)
if updatedByUser == nil {
pats[i].UpdatedByUser = model.User{
NotFound: true,
}
} else {
pats[i].UpdatedByUser = model.User{
Id: updatedByUser.Id,
Name: updatedByUser.Name,
Email: updatedByUser.Email,
CreatedAt: updatedByUser.CreatedAt,
ProfilePictureURL: updatedByUser.ProfilePictureURL,
NotFound: false,
}
}
}
return pats, nil return pats, nil
} }
func (m *modelDao) RevokePAT(ctx context.Context, id string, userID string) basemodel.BaseApiError { func (m *modelDao) DeletePAT(ctx context.Context, id string) basemodel.BaseApiError {
updatedAt := time.Now().Unix() _, err := m.DB().ExecContext(ctx, `DELETE from personal_access_tokens where id=?;`, id)
_, err := m.DB().ExecContext(ctx,
"UPDATE personal_access_tokens SET revoked=true, updated_by_user_id = $1, updated_at=$2 WHERE id=$3",
userID, updatedAt, id)
if err != nil { if err != nil {
zap.L().Error("Failed to revoke PAT in db, err: %v", zap.Error(err)) zap.S().Errorf("Failed to delete PAT, err: %v", zap.Error(err))
return model.InternalError(fmt.Errorf("PAT revoke failed")) return model.InternalError(fmt.Errorf("failed to delete PAT"))
} }
return nil return nil
} }
@@ -138,7 +53,7 @@ func (m *modelDao) RevokePAT(ctx context.Context, id string, userID string) base
func (m *modelDao) GetPAT(ctx context.Context, token string) (*model.PAT, basemodel.BaseApiError) { func (m *modelDao) GetPAT(ctx context.Context, token string) (*model.PAT, basemodel.BaseApiError) {
pats := []model.PAT{} pats := []model.PAT{}
if err := m.DB().Select(&pats, `SELECT * FROM personal_access_tokens WHERE token=? and revoked=false;`, token); err != nil { if err := m.DB().Select(&pats, `SELECT * FROM personal_access_tokens WHERE token=?;`, token); err != nil {
return nil, model.InternalError(fmt.Errorf("failed to fetch PAT")) return nil, model.InternalError(fmt.Errorf("failed to fetch PAT"))
} }
@@ -155,7 +70,7 @@ func (m *modelDao) GetPAT(ctx context.Context, token string) (*model.PAT, basemo
func (m *modelDao) GetPATByID(ctx context.Context, id string) (*model.PAT, basemodel.BaseApiError) { func (m *modelDao) GetPATByID(ctx context.Context, id string) (*model.PAT, basemodel.BaseApiError) {
pats := []model.PAT{} pats := []model.PAT{}
if err := m.DB().Select(&pats, `SELECT * FROM personal_access_tokens WHERE id=? and revoked=false;`, id); err != nil { if err := m.DB().Select(&pats, `SELECT * FROM personal_access_tokens WHERE id=?;`, id); err != nil {
return nil, model.InternalError(fmt.Errorf("failed to fetch PAT")) return nil, model.InternalError(fmt.Errorf("failed to fetch PAT"))
} }
@@ -169,7 +84,6 @@ func (m *modelDao) GetPATByID(ctx context.Context, id string) (*model.PAT, basem
return &pats[0], nil return &pats[0], nil
} }
// deprecated
func (m *modelDao) GetUserByPAT(ctx context.Context, token string) (*basemodel.UserPayload, basemodel.BaseApiError) { func (m *modelDao) GetUserByPAT(ctx context.Context, token string) (*basemodel.UserPayload, basemodel.BaseApiError) {
users := []basemodel.UserPayload{} users := []basemodel.UserPayload{}

View File

@@ -1,9 +0,0 @@
package gateway
import (
"net/http/httputil"
)
func NewNoopProxy() (*httputil.ReverseProxy, error) {
return nil, nil
}

View File

@@ -1,66 +0,0 @@
package gateway
import (
"net/http"
"net/http/httputil"
"net/url"
"path"
"strings"
)
const (
RoutePrefix string = "/api/gateway"
AllowedPrefix string = "/v1/workspaces/me"
)
type proxy struct {
url *url.URL
stripPath string
}
func NewProxy(u string, stripPath string) (*httputil.ReverseProxy, error) {
url, err := url.Parse(u)
if err != nil {
return nil, err
}
proxy := &proxy{url: url, stripPath: stripPath}
return &httputil.ReverseProxy{
Rewrite: proxy.rewrite,
ModifyResponse: proxy.modifyResponse,
ErrorHandler: proxy.errorHandler,
}, nil
}
func (p *proxy) rewrite(pr *httputil.ProxyRequest) {
pr.SetURL(p.url)
pr.SetXForwarded()
pr.Out.URL.Path = cleanPath(strings.ReplaceAll(pr.Out.URL.Path, p.stripPath, ""))
}
func (p *proxy) modifyResponse(res *http.Response) error {
return nil
}
func (p *proxy) errorHandler(rw http.ResponseWriter, req *http.Request, err error) {
rw.WriteHeader(http.StatusBadGateway)
}
func cleanPath(p string) string {
if p == "" {
return "/"
}
if p[0] != '/' {
p = "/" + p
}
np := path.Clean(p)
if p[len(p)-1] == '/' && np != "/" {
if len(p) == len(np)+1 && strings.HasPrefix(p, np) {
np = p
} else {
np += "/"
}
}
return np
}

View File

@@ -1,61 +0,0 @@
package gateway
import (
"context"
"net/http"
"net/http/httputil"
"net/url"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestProxyRewrite(t *testing.T) {
testCases := []struct {
name string
url *url.URL
stripPath string
in *url.URL
expected *url.URL
}{
{
name: "SamePathAdded",
url: &url.URL{Scheme: "http", Host: "backend", Path: "/path1"},
stripPath: "/strip",
in: &url.URL{Scheme: "http", Host: "localhost", Path: "/strip/path1"},
expected: &url.URL{Scheme: "http", Host: "backend", Path: "/path1/path1"},
},
{
name: "NoStripPathInput",
url: &url.URL{Scheme: "http", Host: "backend"},
stripPath: "",
in: &url.URL{Scheme: "http", Host: "localhost", Path: "/strip/path1"},
expected: &url.URL{Scheme: "http", Host: "backend", Path: "/strip/path1"},
},
{
name: "NoStripPathPresentInReq",
url: &url.URL{Scheme: "http", Host: "backend"},
stripPath: "/not-found",
in: &url.URL{Scheme: "http", Host: "localhost", Path: "/strip/path1"},
expected: &url.URL{Scheme: "http", Host: "backend", Path: "/strip/path1"},
},
}
for _, tc := range testCases {
proxy, err := NewProxy(tc.url.String(), tc.stripPath)
require.NoError(t, err)
inReq, err := http.NewRequest(http.MethodGet, tc.in.String(), nil)
require.NoError(t, err)
proxyReq := &httputil.ProxyRequest{
In: inReq,
Out: inReq.Clone(context.Background()),
}
proxy.Rewrite(proxyReq)
assert.Equal(t, tc.expected.Host, proxyReq.Out.URL.Host)
assert.Equal(t, tc.expected.Scheme, proxyReq.Out.URL.Scheme)
assert.Equal(t, tc.expected.Path, proxyReq.Out.URL.Path)
assert.Equal(t, tc.expected.Query(), proxyReq.Out.URL.Query())
}
}

View File

@@ -47,13 +47,13 @@ func ActivateLicense(key, siteId string) (*ActivationResponse, *model.ApiError)
httpResponse, err := http.Post(C.Prefix+"/licenses/activate", APPLICATION_JSON, bytes.NewBuffer(reqString)) httpResponse, err := http.Post(C.Prefix+"/licenses/activate", APPLICATION_JSON, bytes.NewBuffer(reqString))
if err != nil { if err != nil {
zap.L().Error("failed to connect to license.signoz.io", zap.Error(err)) zap.S().Errorf("failed to connect to license.signoz.io", err)
return nil, model.BadRequest(fmt.Errorf("unable to connect with license.signoz.io, please check your network connection")) return nil, model.BadRequest(fmt.Errorf("unable to connect with license.signoz.io, please check your network connection"))
} }
httpBody, err := io.ReadAll(httpResponse.Body) httpBody, err := io.ReadAll(httpResponse.Body)
if err != nil { if err != nil {
zap.L().Error("failed to read activation response from license.signoz.io", zap.Error(err)) zap.S().Errorf("failed to read activation response from license.signoz.io", err)
return nil, model.BadRequest(fmt.Errorf("failed to read activation response from license.signoz.io")) return nil, model.BadRequest(fmt.Errorf("failed to read activation response from license.signoz.io"))
} }
@@ -63,7 +63,7 @@ func ActivateLicense(key, siteId string) (*ActivationResponse, *model.ApiError)
result := ActivationResult{} result := ActivationResult{}
err = json.Unmarshal(httpBody, &result) err = json.Unmarshal(httpBody, &result)
if err != nil { if err != nil {
zap.L().Error("failed to marshal activation response from license.signoz.io", zap.Error(err)) zap.S().Errorf("failed to marshal activation response from license.signoz.io", err)
return nil, model.InternalError(errors.Wrap(err, "failed to marshal license activation response")) return nil, model.InternalError(errors.Wrap(err, "failed to marshal license activation response"))
} }

View File

@@ -48,9 +48,8 @@ func (r *Repo) GetLicenses(ctx context.Context) ([]model.License, error) {
return licenses, nil return licenses, nil
} }
// GetActiveLicense fetches the latest active license from DB. // GetActiveLicense fetches the latest active license from DB
// If the license is not present, expect a nil license and a nil error in the output. func (r *Repo) GetActiveLicense(ctx context.Context) (*model.License, error) {
func (r *Repo) GetActiveLicense(ctx context.Context) (*model.License, *basemodel.ApiError) {
var err error var err error
licenses := []model.License{} licenses := []model.License{}
@@ -58,7 +57,7 @@ func (r *Repo) GetActiveLicense(ctx context.Context) (*model.License, *basemodel
err = r.db.Select(&licenses, query) err = r.db.Select(&licenses, query)
if err != nil { if err != nil {
return nil, basemodel.InternalError(fmt.Errorf("failed to get active licenses from db: %v", err)) return nil, fmt.Errorf("failed to get active licenses from db: %v", err)
} }
var active *model.License var active *model.License
@@ -98,7 +97,7 @@ func (r *Repo) InsertLicense(ctx context.Context, l *model.License) error {
l.ValidationMessage) l.ValidationMessage)
if err != nil { if err != nil {
zap.L().Error("error in inserting license data: ", zap.Error(err)) zap.S().Errorf("error in inserting license data: ", zap.Error(err))
return fmt.Errorf("failed to insert license in db: %v", err) return fmt.Errorf("failed to insert license in db: %v", err)
} }
@@ -122,7 +121,7 @@ func (r *Repo) UpdatePlanDetails(ctx context.Context,
_, err := r.db.ExecContext(ctx, query, planDetails, time.Now(), key) _, err := r.db.ExecContext(ctx, query, planDetails, time.Now(), key)
if err != nil { if err != nil {
zap.L().Error("error in updating license: ", zap.Error(err)) zap.S().Errorf("error in updating license: ", zap.Error(err))
return fmt.Errorf("failed to update license in db: %v", err) return fmt.Errorf("failed to update license in db: %v", err)
} }

View File

@@ -49,7 +49,8 @@ type Manager struct {
activeFeatures basemodel.FeatureSet activeFeatures basemodel.FeatureSet
} }
func StartManager(dbType string, db *sqlx.DB, features ...basemodel.Feature) (*Manager, error) { func StartManager(dbType string, db *sqlx.DB) (*Manager, error) {
if LM != nil { if LM != nil {
return LM, nil return LM, nil
} }
@@ -65,7 +66,7 @@ func StartManager(dbType string, db *sqlx.DB, features ...basemodel.Feature) (*M
repo: &repo, repo: &repo,
} }
if err := m.start(features...); err != nil { if err := m.start(); err != nil {
return m, err return m, err
} }
LM = m LM = m
@@ -73,8 +74,8 @@ func StartManager(dbType string, db *sqlx.DB, features ...basemodel.Feature) (*M
} }
// start loads active license in memory and initiates validator // start loads active license in memory and initiates validator
func (lm *Manager) start(features ...basemodel.Feature) error { func (lm *Manager) start() error {
err := lm.LoadActiveLicense(features...) err := lm.LoadActiveLicense()
return err return err
} }
@@ -84,7 +85,7 @@ func (lm *Manager) Stop() {
<-lm.terminated <-lm.terminated
} }
func (lm *Manager) SetActive(l *model.License, features ...basemodel.Feature) { func (lm *Manager) SetActive(l *model.License) {
lm.mutex.Lock() lm.mutex.Lock()
defer lm.mutex.Unlock() defer lm.mutex.Unlock()
@@ -93,13 +94,13 @@ func (lm *Manager) SetActive(l *model.License, features ...basemodel.Feature) {
} }
lm.activeLicense = l lm.activeLicense = l
lm.activeFeatures = append(l.FeatureSet, features...) lm.activeFeatures = l.FeatureSet
// set default features // set default features
setDefaultFeatures(lm) setDefaultFeatures(lm)
err := lm.InitFeatures(lm.activeFeatures) err := lm.InitFeatures(lm.activeFeatures)
if err != nil { if err != nil {
zap.L().Panic("Couldn't activate features", zap.Error(err)) zap.S().Panicf("Couldn't activate features: %v", err)
} }
if !lm.validatorRunning { if !lm.validatorRunning {
// we want to make sure only one validator runs, // we want to make sure only one validator runs,
@@ -115,21 +116,22 @@ func setDefaultFeatures(lm *Manager) {
} }
// LoadActiveLicense loads the most recent active license // LoadActiveLicense loads the most recent active license
func (lm *Manager) LoadActiveLicense(features ...basemodel.Feature) error { func (lm *Manager) LoadActiveLicense() error {
var err error
active, err := lm.repo.GetActiveLicense(context.Background()) active, err := lm.repo.GetActiveLicense(context.Background())
if err != nil { if err != nil {
return err return err
} }
if active != nil { if active != nil {
lm.SetActive(active, features...) lm.SetActive(active)
} else { } else {
zap.L().Info("No active license found, defaulting to basic plan") zap.S().Info("No active license found, defaulting to basic plan")
// if no active license is found, we default to basic(free) plan with all default features // if no active license is found, we default to basic(free) plan with all default features
lm.activeFeatures = model.BasicPlan lm.activeFeatures = model.BasicPlan
setDefaultFeatures(lm) setDefaultFeatures(lm)
err := lm.InitFeatures(lm.activeFeatures) err := lm.InitFeatures(lm.activeFeatures)
if err != nil { if err != nil {
zap.L().Error("Couldn't initialize features", zap.Error(err)) zap.S().Error("Couldn't initialize features: ", err)
return err return err
} }
} }
@@ -189,7 +191,7 @@ func (lm *Manager) Validator(ctx context.Context) {
// Validate validates the current active license // Validate validates the current active license
func (lm *Manager) Validate(ctx context.Context) (reterr error) { func (lm *Manager) Validate(ctx context.Context) (reterr error) {
zap.L().Info("License validation started") zap.S().Info("License validation started")
if lm.activeLicense == nil { if lm.activeLicense == nil {
return nil return nil
} }
@@ -199,12 +201,12 @@ func (lm *Manager) Validate(ctx context.Context) (reterr error) {
lm.lastValidated = time.Now().Unix() lm.lastValidated = time.Now().Unix()
if reterr != nil { if reterr != nil {
zap.L().Error("License validation completed with error", zap.Error(reterr)) zap.S().Errorf("License validation completed with error", reterr)
atomic.AddUint64(&lm.failedAttempts, 1) atomic.AddUint64(&lm.failedAttempts, 1)
telemetry.GetInstance().SendEvent(telemetry.TELEMETRY_LICENSE_CHECK_FAILED, telemetry.GetInstance().SendEvent(telemetry.TELEMETRY_LICENSE_CHECK_FAILED,
map[string]interface{}{"err": reterr.Error()}, "", true, false) map[string]interface{}{"err": reterr.Error()}, "")
} else { } else {
zap.L().Info("License validation completed with no errors") zap.S().Info("License validation completed with no errors")
} }
lm.mutex.Unlock() lm.mutex.Unlock()
@@ -212,7 +214,7 @@ func (lm *Manager) Validate(ctx context.Context) (reterr error) {
response, apiError := validate.ValidateLicense(lm.activeLicense.ActivationId) response, apiError := validate.ValidateLicense(lm.activeLicense.ActivationId)
if apiError != nil { if apiError != nil {
zap.L().Error("failed to validate license", zap.Error(apiError.Err)) zap.S().Errorf("failed to validate license", apiError)
return apiError.Err return apiError.Err
} }
@@ -233,7 +235,7 @@ func (lm *Manager) Validate(ctx context.Context) (reterr error) {
} }
if err := l.ParsePlan(); err != nil { if err := l.ParsePlan(); err != nil {
zap.L().Error("failed to parse updated license", zap.Error(err)) zap.S().Errorf("failed to parse updated license", zap.Error(err))
return err return err
} }
@@ -243,7 +245,7 @@ func (lm *Manager) Validate(ctx context.Context) (reterr error) {
if err != nil { if err != nil {
// unexpected db write issue but we can let the user continue // unexpected db write issue but we can let the user continue
// and wait for update to work in next cycle. // and wait for update to work in next cycle.
zap.L().Error("failed to validate license", zap.Error(err)) zap.S().Errorf("failed to validate license", zap.Error(err))
} }
} }
@@ -261,14 +263,14 @@ func (lm *Manager) Activate(ctx context.Context, key string) (licenseResponse *m
userEmail, err := auth.GetEmailFromJwt(ctx) userEmail, err := auth.GetEmailFromJwt(ctx)
if err == nil { if err == nil {
telemetry.GetInstance().SendEvent(telemetry.TELEMETRY_LICENSE_ACT_FAILED, telemetry.GetInstance().SendEvent(telemetry.TELEMETRY_LICENSE_ACT_FAILED,
map[string]interface{}{"err": errResponse.Err.Error()}, userEmail, true, false) map[string]interface{}{"err": errResponse.Err.Error()}, userEmail)
} }
} }
}() }()
response, apiError := validate.ActivateLicense(key, "") response, apiError := validate.ActivateLicense(key, "")
if apiError != nil { if apiError != nil {
zap.L().Error("failed to activate license", zap.Error(apiError.Err)) zap.S().Errorf("failed to activate license", zap.Error(apiError.Err))
return nil, apiError return nil, apiError
} }
@@ -282,14 +284,14 @@ func (lm *Manager) Activate(ctx context.Context, key string) (licenseResponse *m
err := l.ParsePlan() err := l.ParsePlan()
if err != nil { if err != nil {
zap.L().Error("failed to activate license", zap.Error(err)) zap.S().Errorf("failed to activate license", zap.Error(err))
return nil, model.InternalError(err) return nil, model.InternalError(err)
} }
// store the license before activating it // store the license before activating it
err = lm.repo.InsertLicense(ctx, l) err = lm.repo.InsertLicense(ctx, l)
if err != nil { if err != nil {
zap.L().Error("failed to activate license", zap.Error(err)) zap.S().Errorf("failed to activate license", zap.Error(err))
return nil, model.InternalError(err) return nil, model.InternalError(err)
} }

View File

@@ -16,10 +16,8 @@ import (
"go.signoz.io/signoz/pkg/query-service/auth" "go.signoz.io/signoz/pkg/query-service/auth"
"go.signoz.io/signoz/pkg/query-service/constants" "go.signoz.io/signoz/pkg/query-service/constants"
baseconst "go.signoz.io/signoz/pkg/query-service/constants" baseconst "go.signoz.io/signoz/pkg/query-service/constants"
"go.signoz.io/signoz/pkg/query-service/migrate"
"go.signoz.io/signoz/pkg/query-service/version" "go.signoz.io/signoz/pkg/query-service/version"
"google.golang.org/grpc" "google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"
zapotlpencoder "github.com/SigNoz/zap_otlp/zap_otlp_encoder" zapotlpencoder "github.com/SigNoz/zap_otlp/zap_otlp_encoder"
zapotlpsync "github.com/SigNoz/zap_otlp/zap_otlp_sync" zapotlpsync "github.com/SigNoz/zap_otlp/zap_otlp_sync"
@@ -29,19 +27,18 @@ import (
) )
func initZapLog(enableQueryServiceLogOTLPExport bool) *zap.Logger { func initZapLog(enableQueryServiceLogOTLPExport bool) *zap.Logger {
config := zap.NewProductionConfig() config := zap.NewDevelopmentConfig()
ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt) ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt)
defer stop() defer stop()
config.EncoderConfig.EncodeDuration = zapcore.MillisDurationEncoder config.EncoderConfig.EncodeDuration = zapcore.StringDurationEncoder
config.EncoderConfig.EncodeLevel = zapcore.CapitalLevelEncoder otlpEncoder := zapotlpencoder.NewOTLPEncoder(config.EncoderConfig)
consoleEncoder := zapcore.NewConsoleEncoder(config.EncoderConfig)
defaultLogLevel := zapcore.DebugLevel
config.EncoderConfig.EncodeLevel = zapcore.CapitalColorLevelEncoder
config.EncoderConfig.TimeKey = "timestamp" config.EncoderConfig.TimeKey = "timestamp"
config.EncoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder config.EncoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder
otlpEncoder := zapotlpencoder.NewOTLPEncoder(config.EncoderConfig)
consoleEncoder := zapcore.NewJSONEncoder(config.EncoderConfig)
defaultLogLevel := zapcore.InfoLevel
res := resource.NewWithAttributes( res := resource.NewWithAttributes(
semconv.SchemaURL, semconv.SchemaURL,
semconv.ServiceNameKey.String("query-service"), semconv.ServiceNameKey.String("query-service"),
@@ -51,15 +48,14 @@ func initZapLog(enableQueryServiceLogOTLPExport bool) *zap.Logger {
zapcore.NewCore(consoleEncoder, os.Stdout, defaultLogLevel), zapcore.NewCore(consoleEncoder, os.Stdout, defaultLogLevel),
) )
if enableQueryServiceLogOTLPExport { if enableQueryServiceLogOTLPExport == true {
ctx, _ := context.WithTimeout(ctx, time.Second*30) conn, err := grpc.DialContext(ctx, constants.OTLPTarget, grpc.WithBlock(), grpc.WithInsecure(), grpc.WithTimeout(time.Second*30))
conn, err := grpc.DialContext(ctx, baseconst.OTLPTarget, grpc.WithBlock(), grpc.WithTransportCredentials(insecure.NewCredentials()))
if err != nil { if err != nil {
log.Fatalf("failed to establish connection: %v", err) log.Println("failed to connect to otlp collector to export query service logs with error:", err)
} else { } else {
logExportBatchSizeInt, err := strconv.Atoi(baseconst.LogExportBatchSize) logExportBatchSizeInt, err := strconv.Atoi(baseconst.LogExportBatchSize)
if err != nil { if err != nil {
logExportBatchSizeInt = 512 logExportBatchSizeInt = 1000
} }
ws := zapcore.AddSync(zapotlpsync.NewOtlpSyncer(conn, zapotlpsync.Options{ ws := zapcore.AddSync(zapotlpsync.NewOtlpSyncer(conn, zapotlpsync.Options{
BatchSize: logExportBatchSizeInt, BatchSize: logExportBatchSizeInt,
@@ -95,7 +91,6 @@ func main() {
var maxIdleConns int var maxIdleConns int
var maxOpenConns int var maxOpenConns int
var dialTimeout time.Duration var dialTimeout time.Duration
var gatewayUrl string
flag.StringVar(&promConfigPath, "config", "./config/prometheus.yml", "(prometheus config to read metrics)") 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.StringVar(&skipTopLvlOpsPath, "skip-top-level-ops", "", "(config file to skip top level operations)")
@@ -110,7 +105,6 @@ func main() {
flag.StringVar(&fluxInterval, "flux-interval", "5m", "(cache config to use)") flag.StringVar(&fluxInterval, "flux-interval", "5m", "(cache config to use)")
flag.BoolVar(&enableQueryServiceLogOTLPExport, "enable.query.service.log.otlp.export", false, "(enable query service log otlp export)") flag.BoolVar(&enableQueryServiceLogOTLPExport, "enable.query.service.log.otlp.export", false, "(enable query service log otlp export)")
flag.StringVar(&cluster, "cluster", "cluster", "(cluster name - defaults to 'cluster')") flag.StringVar(&cluster, "cluster", "cluster", "(cluster name - defaults to 'cluster')")
flag.StringVar(&gatewayUrl, "gateway-url", "", "(url to the gateway)")
flag.Parse() flag.Parse()
@@ -119,6 +113,7 @@ func main() {
zap.ReplaceGlobals(loggerMgr) zap.ReplaceGlobals(loggerMgr)
defer loggerMgr.Sync() // flushes buffer, if any defer loggerMgr.Sync() // flushes buffer, if any
logger := loggerMgr.Sugar()
version.PrintVersion() version.PrintVersion()
serverOptions := &app.ServerOptions{ serverOptions := &app.ServerOptions{
@@ -136,35 +131,28 @@ func main() {
CacheConfigPath: cacheConfigPath, CacheConfigPath: cacheConfigPath,
FluxInterval: fluxInterval, FluxInterval: fluxInterval,
Cluster: cluster, Cluster: cluster,
GatewayUrl: gatewayUrl,
} }
// Read the jwt secret key // Read the jwt secret key
auth.JwtSecret = os.Getenv("SIGNOZ_JWT_SECRET") auth.JwtSecret = os.Getenv("SIGNOZ_JWT_SECRET")
if len(auth.JwtSecret) == 0 { if len(auth.JwtSecret) == 0 {
zap.L().Warn("No JWT secret key is specified.") zap.S().Warn("No JWT secret key is specified.")
} else { } else {
zap.L().Info("JWT secret key set successfully.") zap.S().Info("No JWT secret key set successfully.")
}
if err := migrate.Migrate(constants.RELATIONAL_DATASOURCE_PATH); err != nil {
zap.L().Error("Failed to migrate", zap.Error(err))
} else {
zap.L().Info("Migration successful")
} }
server, err := app.NewServer(serverOptions) server, err := app.NewServer(serverOptions)
if err != nil { if err != nil {
zap.L().Fatal("Failed to create server", zap.Error(err)) logger.Fatal("Failed to create server", zap.Error(err))
} }
if err := server.Start(); err != nil { if err := server.Start(); err != nil {
zap.L().Fatal("Could not start server", zap.Error(err)) logger.Fatal("Could not start servers", zap.Error(err))
} }
if err := auth.InitAuthCache(context.Background()); err != nil { if err := auth.InitAuthCache(context.Background()); err != nil {
zap.L().Fatal("Failed to initialize auth cache", zap.Error(err)) logger.Fatal("Failed to initialize auth cache", zap.Error(err))
} }
signalsChannel := make(chan os.Signal, 1) signalsChannel := make(chan os.Signal, 1)
@@ -173,9 +161,9 @@ func main() {
for { for {
select { select {
case status := <-server.HealthCheckStatus(): case status := <-server.HealthCheckStatus():
zap.L().Info("Received HealthCheck status: ", zap.Int("status", int(status))) logger.Info("Received HealthCheck status: ", zap.Int("status", int(status)))
case <-signalsChannel: case <-signalsChannel:
zap.L().Fatal("Received OS Interrupt Signal ... ") logger.Fatal("Received OS Interrupt Signal ... ")
server.Stop() server.Stop()
} }
} }

View File

@@ -9,8 +9,8 @@ import (
"github.com/google/uuid" "github.com/google/uuid"
"github.com/pkg/errors" "github.com/pkg/errors"
saml2 "github.com/russellhaering/gosaml2" saml2 "github.com/russellhaering/gosaml2"
"go.signoz.io/signoz/ee/query-service/sso"
"go.signoz.io/signoz/ee/query-service/sso/saml" "go.signoz.io/signoz/ee/query-service/sso/saml"
"go.signoz.io/signoz/ee/query-service/sso"
basemodel "go.signoz.io/signoz/pkg/query-service/model" basemodel "go.signoz.io/signoz/pkg/query-service/model"
"go.uber.org/zap" "go.uber.org/zap"
) )
@@ -24,16 +24,16 @@ const (
// OrgDomain identify org owned web domains for auth and other purposes // OrgDomain identify org owned web domains for auth and other purposes
type OrgDomain struct { type OrgDomain struct {
Id uuid.UUID `json:"id"` Id uuid.UUID `json:"id"`
Name string `json:"name"` Name string `json:"name"`
OrgId string `json:"orgId"` OrgId string `json:"orgId"`
SsoEnabled bool `json:"ssoEnabled"` SsoEnabled bool `json:"ssoEnabled"`
SsoType SSOType `json:"ssoType"` SsoType SSOType `json:"ssoType"`
SamlConfig *SamlConfig `json:"samlConfig"` SamlConfig *SamlConfig `json:"samlConfig"`
GoogleAuthConfig *GoogleOAuthConfig `json:"googleAuthConfig"` GoogleAuthConfig *GoogleOAuthConfig `json:"googleAuthConfig"`
Org *basemodel.Organization Org *basemodel.Organization
} }
func (od *OrgDomain) String() string { func (od *OrgDomain) String() string {
@@ -100,8 +100,8 @@ func (od *OrgDomain) GetSAMLCert() string {
return "" return ""
} }
// PrepareGoogleOAuthProvider creates GoogleProvider that is used in // PrepareGoogleOAuthProvider creates GoogleProvider that is used in
// requesting OAuth and also used in processing response from google // requesting OAuth and also used in processing response from google
func (od *OrgDomain) PrepareGoogleOAuthProvider(siteUrl *url.URL) (sso.OAuthCallbackProvider, error) { func (od *OrgDomain) PrepareGoogleOAuthProvider(siteUrl *url.URL) (sso.OAuthCallbackProvider, error) {
if od.GoogleAuthConfig == nil { if od.GoogleAuthConfig == nil {
return nil, fmt.Errorf("Google auth is not setup correctly for this domain") return nil, fmt.Errorf("Google auth is not setup correctly for this domain")
@@ -137,36 +137,38 @@ func (od *OrgDomain) PrepareSamlRequest(siteUrl *url.URL) (*saml2.SAMLServicePro
} }
func (od *OrgDomain) BuildSsoUrl(siteUrl *url.URL) (ssoUrl string, err error) { func (od *OrgDomain) BuildSsoUrl(siteUrl *url.URL) (ssoUrl string, err error) {
fmtDomainId := strings.Replace(od.Id.String(), "-", ":", -1) fmtDomainId := strings.Replace(od.Id.String(), "-", ":", -1)
// build redirect url from window.location sent by frontend // build redirect url from window.location sent by frontend
redirectURL := fmt.Sprintf("%s://%s%s", siteUrl.Scheme, siteUrl.Host, siteUrl.Path) redirectURL := fmt.Sprintf("%s://%s%s", siteUrl.Scheme, siteUrl.Host, siteUrl.Path)
// prepare state that gets relayed back when the auth provider // prepare state that gets relayed back when the auth provider
// calls back our url. here we pass the app url (where signoz runs) // calls back our url. here we pass the app url (where signoz runs)
// and the domain Id. The domain Id helps in identifying sso config // and the domain Id. The domain Id helps in identifying sso config
// when the call back occurs and the app url is useful in redirecting user // when the call back occurs and the app url is useful in redirecting user
// back to the right path. // back to the right path.
// why do we need to pass app url? the callback typically is handled by backend // why do we need to pass app url? the callback typically is handled by backend
// and sometimes backend might right at a different port or is unaware of frontend // and sometimes backend might right at a different port or is unaware of frontend
// endpoint (unless SITE_URL param is set). hence, we receive this build sso request // endpoint (unless SITE_URL param is set). hence, we receive this build sso request
// along with frontend window.location and use it to relay the information through // along with frontend window.location and use it to relay the information through
// auth provider to the backend (HandleCallback or HandleSSO method). // auth provider to the backend (HandleCallback or HandleSSO method).
relayState := fmt.Sprintf("%s?domainId=%s", redirectURL, fmtDomainId) relayState := fmt.Sprintf("%s?domainId=%s", redirectURL, fmtDomainId)
switch od.SsoType { switch (od.SsoType) {
case SAML: case SAML:
sp, err := od.PrepareSamlRequest(siteUrl) sp, err := od.PrepareSamlRequest(siteUrl)
if err != nil { if err != nil {
return "", err return "", err
} }
return sp.BuildAuthURL(relayState) return sp.BuildAuthURL(relayState)
case GoogleAuth: case GoogleAuth:
googleProvider, err := od.PrepareGoogleOAuthProvider(siteUrl) googleProvider, err := od.PrepareGoogleOAuthProvider(siteUrl)
if err != nil { if err != nil {
return "", err return "", err
@@ -174,8 +176,9 @@ func (od *OrgDomain) BuildSsoUrl(siteUrl *url.URL) (ssoUrl string, err error) {
return googleProvider.BuildAuthURL(relayState) return googleProvider.BuildAuthURL(relayState)
default: default:
zap.L().Error("found unsupported SSO config for the org domain", zap.String("orgDomain", od.Name)) zap.S().Errorf("found unsupported SSO config for the org domain", zap.String("orgDomain", od.Name))
return "", fmt.Errorf("unsupported SSO config for the domain") return "", fmt.Errorf("unsupported SSO config for the domain")
} }
} }

View File

@@ -1,32 +1,10 @@
package model package model
type User struct {
Id string `json:"id" db:"id"`
Name string `json:"name" db:"name"`
Email string `json:"email" db:"email"`
CreatedAt int64 `json:"createdAt" db:"created_at"`
ProfilePictureURL string `json:"profilePictureURL" db:"profile_picture_url"`
NotFound bool `json:"notFound"`
}
type CreatePATRequestBody struct {
Name string `json:"name"`
Role string `json:"role"`
ExpiresInDays int64 `json:"expiresInDays"`
}
type PAT struct { type PAT struct {
Id string `json:"id" db:"id"` Id string `json:"id" db:"id"`
UserID string `json:"userId" db:"user_id"` UserID string `json:"userId" db:"user_id"`
CreatedByUser User `json:"createdByUser"` Token string `json:"token" db:"token"`
UpdatedByUser User `json:"updatedByUser"` Name string `json:"name" db:"name"`
Token string `json:"token" db:"token"` CreatedAt int64 `json:"createdAt" db:"created_at"`
Role string `json:"role" db:"role"` ExpiresAt int64 `json:"expiresAt" db:"expires_at"`
Name string `json:"name" db:"name"`
CreatedAt int64 `json:"createdAt" db:"created_at"`
ExpiresAt int64 `json:"expiresAt" db:"expires_at"`
UpdatedAt int64 `json:"updatedAt" db:"updated_at"`
LastUsed int64 `json:"lastUsed" db:"last_used"`
Revoked bool `json:"revoked" db:"revoked"`
UpdatedByUserID string `json:"updatedByUserId" db:"updated_by_user_id"`
} }

View File

@@ -52,14 +52,14 @@ var BasicPlan = basemodel.FeatureSet{
Name: basemodel.QueryBuilderPanels, Name: basemodel.QueryBuilderPanels,
Active: true, Active: true,
Usage: 0, Usage: 0,
UsageLimit: -1, UsageLimit: 20,
Route: "", Route: "",
}, },
basemodel.Feature{ basemodel.Feature{
Name: basemodel.QueryBuilderAlerts, Name: basemodel.QueryBuilderAlerts,
Active: true, Active: true,
Usage: 0, Usage: 0,
UsageLimit: -1, UsageLimit: 10,
Route: "", Route: "",
}, },
basemodel.Feature{ basemodel.Feature{
@@ -90,13 +90,6 @@ var BasicPlan = basemodel.FeatureSet{
UsageLimit: -1, UsageLimit: -1,
Route: "", Route: "",
}, },
basemodel.Feature{
Name: basemodel.AlertChannelEmail,
Active: true,
Usage: 0,
UsageLimit: -1,
Route: "",
},
basemodel.Feature{ basemodel.Feature{
Name: basemodel.AlertChannelMsTeams, Name: basemodel.AlertChannelMsTeams,
Active: false, Active: false,
@@ -184,13 +177,6 @@ var ProPlan = basemodel.FeatureSet{
UsageLimit: -1, UsageLimit: -1,
Route: "", Route: "",
}, },
basemodel.Feature{
Name: basemodel.AlertChannelEmail,
Active: true,
Usage: 0,
UsageLimit: -1,
Route: "",
},
basemodel.Feature{ basemodel.Feature{
Name: basemodel.AlertChannelMsTeams, Name: basemodel.AlertChannelMsTeams,
Active: true, Active: true,
@@ -278,13 +264,6 @@ var EnterprisePlan = basemodel.FeatureSet{
UsageLimit: -1, UsageLimit: -1,
Route: "", Route: "",
}, },
basemodel.Feature{
Name: basemodel.AlertChannelEmail,
Active: true,
Usage: 0,
UsageLimit: -1,
Route: "",
},
basemodel.Feature{ basemodel.Feature{
Name: basemodel.AlertChannelMsTeams, Name: basemodel.AlertChannelMsTeams,
Active: true, Active: true,
@@ -300,17 +279,17 @@ var EnterprisePlan = basemodel.FeatureSet{
Route: "", Route: "",
}, },
basemodel.Feature{ basemodel.Feature{
Name: Onboarding, Name: Onboarding,
Active: true, Active: true,
Usage: 0, Usage: 0,
UsageLimit: -1, UsageLimit: -1,
Route: "", Route: "",
}, },
basemodel.Feature{ basemodel.Feature{
Name: ChatSupport, Name: ChatSupport,
Active: true, Active: true,
Usage: 0, Usage: 0,
UsageLimit: -1, UsageLimit: -1,
Route: "", Route: "",
}, },
} }

View File

@@ -20,8 +20,6 @@ type Usage struct {
TimeStamp time.Time `json:"timestamp"` TimeStamp time.Time `json:"timestamp"`
Count int64 `json:"count"` Count int64 `json:"count"`
Size int64 `json:"size"` Size int64 `json:"size"`
OrgName string `json:"orgName"`
TenantId string `json:"tenantId"`
} }
type UsageDB struct { type UsageDB struct {

View File

@@ -102,6 +102,6 @@ func PrepareRequest(issuer, acsUrl, audience, entity, idp, certString string) (*
IDPCertificateStore: certStore, IDPCertificateStore: certStore,
SPKeyStore: randomKeyStore, SPKeyStore: randomKeyStore,
} }
zap.L().Debug("SAML request", zap.Any("sp", sp)) zap.S().Debugf("SAML request:", sp)
return sp, nil return sp, nil
} }

View File

@@ -4,8 +4,6 @@ import (
"context" "context"
"encoding/json" "encoding/json"
"fmt" "fmt"
"os"
"regexp"
"strings" "strings"
"sync/atomic" "sync/atomic"
"time" "time"
@@ -13,10 +11,10 @@ import (
"github.com/ClickHouse/clickhouse-go/v2" "github.com/ClickHouse/clickhouse-go/v2"
"github.com/go-co-op/gocron" "github.com/go-co-op/gocron"
"github.com/google/uuid" "github.com/google/uuid"
"github.com/jmoiron/sqlx"
"go.uber.org/zap" "go.uber.org/zap"
"go.signoz.io/signoz/ee/query-service/dao"
licenseserver "go.signoz.io/signoz/ee/query-service/integrations/signozio" licenseserver "go.signoz.io/signoz/ee/query-service/integrations/signozio"
"go.signoz.io/signoz/ee/query-service/license" "go.signoz.io/signoz/ee/query-service/license"
"go.signoz.io/signoz/ee/query-service/model" "go.signoz.io/signoz/ee/query-service/model"
@@ -40,29 +38,15 @@ type Manager struct {
licenseRepo *license.Repo licenseRepo *license.Repo
scheduler *gocron.Scheduler scheduler *gocron.Scheduler
modelDao dao.ModelDao
tenantID string
} }
func New(dbType string, modelDao dao.ModelDao, licenseRepo *license.Repo, clickhouseConn clickhouse.Conn) (*Manager, error) { func New(dbType string, db *sqlx.DB, licenseRepo *license.Repo, clickhouseConn clickhouse.Conn) (*Manager, error) {
hostNameRegex := regexp.MustCompile(`tcp://(?P<hostname>.*):`)
hostNameRegexMatches := hostNameRegex.FindStringSubmatch(os.Getenv("ClickHouseUrl"))
tenantID := ""
if len(hostNameRegexMatches) == 2 {
tenantID = hostNameRegexMatches[1]
tenantID = strings.TrimRight(tenantID, "-clickhouse")
}
m := &Manager{ m := &Manager{
// repository: repo, // repository: repo,
clickhouseConn: clickhouseConn, clickhouseConn: clickhouseConn,
licenseRepo: licenseRepo, licenseRepo: licenseRepo,
scheduler: gocron.NewScheduler(time.UTC).Every(1).Day().At("00:00"), // send usage every at 00:00 UTC scheduler: gocron.NewScheduler(time.UTC).Every(1).Day().At("00:00"), // send usage every at 00:00 UTC
modelDao: modelDao,
tenantID: tenantID,
} }
return m, nil return m, nil
} }
@@ -91,12 +75,12 @@ func (lm *Manager) UploadUsage() {
// check if license is present or not // check if license is present or not
license, err := lm.licenseRepo.GetActiveLicense(ctx) license, err := lm.licenseRepo.GetActiveLicense(ctx)
if err != nil { if err != nil {
zap.L().Error("failed to get active license", zap.Error(err)) zap.S().Errorf("failed to get active license: %v", zap.Error(err))
return return
} }
if license == nil { if license == nil {
// we will not start the usage reporting if license is not present. // we will not start the usage reporting if license is not present.
zap.L().Info("no license present, skipping usage reporting") zap.S().Info("no license present, skipping usage reporting")
return return
} }
@@ -123,7 +107,7 @@ func (lm *Manager) UploadUsage() {
dbusages := []model.UsageDB{} dbusages := []model.UsageDB{}
err := lm.clickhouseConn.Select(ctx, &dbusages, fmt.Sprintf(query, db, db), time.Now().Add(-(24 * time.Hour))) err := lm.clickhouseConn.Select(ctx, &dbusages, fmt.Sprintf(query, db, db), time.Now().Add(-(24 * time.Hour)))
if err != nil && !strings.Contains(err.Error(), "doesn't exist") { if err != nil && !strings.Contains(err.Error(), "doesn't exist") {
zap.L().Error("failed to get usage from clickhouse: %v", zap.Error(err)) zap.S().Errorf("failed to get usage from clickhouse: %v", zap.Error(err))
return return
} }
for _, u := range dbusages { for _, u := range dbusages {
@@ -133,33 +117,24 @@ func (lm *Manager) UploadUsage() {
} }
if len(usages) <= 0 { if len(usages) <= 0 {
zap.L().Info("no snapshots to upload, skipping.") zap.S().Info("no snapshots to upload, skipping.")
return return
} }
zap.L().Info("uploading usage data") zap.S().Info("uploading usage data")
orgName := ""
orgNames, orgError := lm.modelDao.GetOrgs(ctx)
if orgError != nil {
zap.L().Error("failed to get org data: %v", zap.Error(orgError))
}
if len(orgNames) == 1 {
orgName = orgNames[0].Name
}
usagesPayload := []model.Usage{} usagesPayload := []model.Usage{}
for _, usage := range usages { for _, usage := range usages {
usageDataBytes, err := encryption.Decrypt([]byte(usage.ExporterID[:32]), []byte(usage.Data)) usageDataBytes, err := encryption.Decrypt([]byte(usage.ExporterID[:32]), []byte(usage.Data))
if err != nil { if err != nil {
zap.L().Error("error while decrypting usage data: %v", zap.Error(err)) zap.S().Errorf("error while decrypting usage data: %v", zap.Error(err))
return return
} }
usageData := model.Usage{} usageData := model.Usage{}
err = json.Unmarshal(usageDataBytes, &usageData) err = json.Unmarshal(usageDataBytes, &usageData)
if err != nil { if err != nil {
zap.L().Error("error while unmarshalling usage data: %v", zap.Error(err)) zap.S().Errorf("error while unmarshalling usage data: %v", zap.Error(err))
return return
} }
@@ -167,8 +142,6 @@ func (lm *Manager) UploadUsage() {
usageData.ExporterID = usage.ExporterID usageData.ExporterID = usage.ExporterID
usageData.Type = usage.Type usageData.Type = usage.Type
usageData.Tenant = usage.Tenant usageData.Tenant = usage.Tenant
usageData.OrgName = orgName
usageData.TenantId = lm.tenantID
usagesPayload = append(usagesPayload, usageData) usagesPayload = append(usagesPayload, usageData)
} }
@@ -184,13 +157,13 @@ func (lm *Manager) UploadUsageWithExponentalBackOff(ctx context.Context, payload
for i := 1; i <= MaxRetries; i++ { for i := 1; i <= MaxRetries; i++ {
apiErr := licenseserver.SendUsage(ctx, payload) apiErr := licenseserver.SendUsage(ctx, payload)
if apiErr != nil && i == MaxRetries { if apiErr != nil && i == MaxRetries {
zap.L().Error("retries stopped : %v", zap.Error(apiErr)) zap.S().Errorf("retries stopped : %v", zap.Error(apiErr))
// not returning error here since it is captured in the failed count // not returning error here since it is captured in the failed count
return return
} else if apiErr != nil { } else if apiErr != nil {
// sleeping for exponential backoff // sleeping for exponential backoff
sleepDuration := RetryInterval * time.Duration(i) sleepDuration := RetryInterval * time.Duration(i)
zap.L().Error("failed to upload snapshot retrying after %v secs : %v", zap.Duration("sleepDuration", sleepDuration), zap.Error(apiErr.Err)) zap.S().Errorf("failed to upload snapshot retrying after %v secs : %v", sleepDuration.Seconds(), zap.Error(apiErr.Err))
time.Sleep(sleepDuration) time.Sleep(sleepDuration)
} else { } else {
break break
@@ -201,7 +174,7 @@ func (lm *Manager) UploadUsageWithExponentalBackOff(ctx context.Context, payload
func (lm *Manager) Stop() { func (lm *Manager) Stop() {
lm.scheduler.Stop() lm.scheduler.Stop()
zap.L().Info("sending usage data before shutting down") zap.S().Debug("sending usage data before shutting down")
// send usage before shutting down // send usage before shutting down
lm.UploadUsage() lm.UploadUsage()

3
frontend/.gitignore vendored
View File

@@ -1,3 +0,0 @@
# Sentry Config File
.env.sentry-build-plugin

View File

@@ -1,4 +1,4 @@
FROM nginx:1.26-alpine FROM nginx:1.25.2-alpine
# Add Maintainer Info # Add Maintainer Info
LABEL maintainer="signoz" LABEL maintainer="signoz"

View File

@@ -4,7 +4,6 @@ const config: Config.InitialOptions = {
clearMocks: true, clearMocks: true,
coverageDirectory: 'coverage', coverageDirectory: 'coverage',
coverageReporters: ['text', 'cobertura', 'html', 'json-summary'], coverageReporters: ['text', 'cobertura', 'html', 'json-summary'],
collectCoverageFrom: ['src/**/*.{ts,tsx}'],
moduleFileExtensions: ['ts', 'tsx', 'js', 'json'], moduleFileExtensions: ['ts', 'tsx', 'js', 'json'],
modulePathIgnorePatterns: ['dist'], modulePathIgnorePatterns: ['dist'],
moduleNameMapper: { moduleNameMapper: {
@@ -23,7 +22,7 @@ const config: Config.InitialOptions = {
'^.+\\.(js|jsx)$': 'babel-jest', '^.+\\.(js|jsx)$': 'babel-jest',
}, },
transformIgnorePatterns: [ transformIgnorePatterns: [
'node_modules/(?!(lodash-es|react-dnd|core-dnd|@react-dnd|dnd-core|react-dnd-html5-backend|axios|@signozhq/design-tokens|d3-interpolate|d3-color)/)', 'node_modules/(?!(lodash-es|react-dnd|core-dnd|@react-dnd|dnd-core|react-dnd-html5-backend|axios)/)',
], ],
setupFilesAfterEnv: ['<rootDir>jest.setup.ts'], setupFilesAfterEnv: ['<rootDir>jest.setup.ts'],
testPathIgnorePatterns: ['/node_modules/', '/public/'], testPathIgnorePatterns: ['/node_modules/', '/public/'],
@@ -34,14 +33,6 @@ const config: Config.InitialOptions = {
browsers: ['chromium', 'firefox', 'webkit'], browsers: ['chromium', 'firefox', 'webkit'],
}, },
}, },
coverageThreshold: {
global: {
statements: 80,
branches: 65,
functions: 80,
lines: 80,
},
},
}; };
export default config; export default config;

View File

@@ -7,7 +7,6 @@
*/ */
import '@testing-library/jest-dom'; import '@testing-library/jest-dom';
import 'jest-styled-components'; import 'jest-styled-components';
import './src/styles.scss';
import { server } from './src/mocks-server/server'; import { server } from './src/mocks-server/server';
// Establish API mocking before all tests. // Establish API mocking before all tests.

View File

@@ -19,9 +19,7 @@
"playwright:codegen:local": "playwright codegen http://localhost:3301", "playwright:codegen:local": "playwright codegen http://localhost:3301",
"playwright:codegen:local:auth": "yarn playwright:codegen:local --load-storage=tests/auth.json", "playwright:codegen:local:auth": "yarn playwright:codegen:local --load-storage=tests/auth.json",
"husky:configure": "cd .. && husky install frontend/.husky && cd frontend && chmod ug+x .husky/*", "husky:configure": "cd .. && husky install frontend/.husky && cd frontend && chmod ug+x .husky/*",
"commitlint": "commitlint --edit $1", "commitlint": "commitlint --edit $1"
"test": "jest --coverage",
"test:changedsince": "jest --changedSince=develop --coverage --silent"
}, },
"engines": { "engines": {
"node": ">=16.15.0" "node": ">=16.15.0"
@@ -38,20 +36,12 @@
"@mdx-js/loader": "2.3.0", "@mdx-js/loader": "2.3.0",
"@mdx-js/react": "2.3.0", "@mdx-js/react": "2.3.0",
"@monaco-editor/react": "^4.3.1", "@monaco-editor/react": "^4.3.1",
"@radix-ui/react-tabs": "1.0.4",
"@radix-ui/react-tooltip": "1.0.7",
"@sentry/react": "7.102.1",
"@sentry/webpack-plugin": "2.16.0",
"@signozhq/design-tokens": "0.0.8",
"@uiw/react-md-editor": "3.23.5", "@uiw/react-md-editor": "3.23.5",
"@visx/group": "3.3.0",
"@visx/shape": "3.5.0",
"@visx/tooltip": "3.3.0",
"@xstate/react": "^3.0.0", "@xstate/react": "^3.0.0",
"ansi-to-html": "0.7.2", "ansi-to-html": "0.7.2",
"antd": "5.11.0", "antd": "5.11.0",
"antd-table-saveas-excel": "2.2.1", "antd-table-saveas-excel": "2.2.1",
"axios": "1.6.4", "axios": "1.6.2",
"babel-eslint": "^10.1.0", "babel-eslint": "^10.1.0",
"babel-jest": "^29.6.4", "babel-jest": "^29.6.4",
"babel-loader": "9.1.3", "babel-loader": "9.1.3",
@@ -76,7 +66,6 @@
"fontfaceobserver": "2.3.0", "fontfaceobserver": "2.3.0",
"history": "4.10.1", "history": "4.10.1",
"html-webpack-plugin": "5.5.0", "html-webpack-plugin": "5.5.0",
"http-proxy-middleware": "2.0.6",
"i18next": "^21.6.12", "i18next": "^21.6.12",
"i18next-browser-languagedetector": "^6.1.3", "i18next-browser-languagedetector": "^6.1.3",
"i18next-http-backend": "^1.3.2", "i18next-http-backend": "^1.3.2",
@@ -85,13 +74,11 @@
"less": "^4.1.2", "less": "^4.1.2",
"less-loader": "^10.2.0", "less-loader": "^10.2.0",
"lodash-es": "^4.17.21", "lodash-es": "^4.17.21",
"lucide-react": "0.379.0", "lucide-react": "0.288.0",
"mini-css-extract-plugin": "2.4.5", "mini-css-extract-plugin": "2.4.5",
"papaparse": "5.4.1", "papaparse": "5.4.1",
"rc-tween-one": "3.0.6",
"react": "18.2.0", "react": "18.2.0",
"react-addons-update": "15.6.3", "react-addons-update": "15.6.3",
"react-beautiful-dnd": "13.1.1",
"react-dnd": "16.0.1", "react-dnd": "16.0.1",
"react-dnd-html5-backend": "16.0.1", "react-dnd-html5-backend": "16.0.1",
"react-dom": "18.2.0", "react-dom": "18.2.0",
@@ -111,7 +98,6 @@
"react-virtuoso": "4.0.3", "react-virtuoso": "4.0.3",
"redux": "^4.0.5", "redux": "^4.0.5",
"redux-thunk": "^2.3.0", "redux-thunk": "^2.3.0",
"rehype-raw": "7.0.0",
"stream": "^0.0.2", "stream": "^0.0.2",
"style-loader": "1.3.0", "style-loader": "1.3.0",
"styled-components": "^5.3.11", "styled-components": "^5.3.11",
@@ -125,7 +111,6 @@
"web-vitals": "^0.2.4", "web-vitals": "^0.2.4",
"webpack": "5.88.2", "webpack": "5.88.2",
"webpack-dev-server": "^4.15.1", "webpack-dev-server": "^4.15.1",
"webpack-retry-chunk-load-plugin": "3.1.1",
"xstate": "^4.31.0" "xstate": "^4.31.0"
}, },
"browserslist": { "browserslist": {
@@ -167,7 +152,6 @@
"@types/papaparse": "5.3.7", "@types/papaparse": "5.3.7",
"@types/react": "18.0.26", "@types/react": "18.0.26",
"@types/react-addons-update": "0.14.21", "@types/react-addons-update": "0.14.21",
"@types/react-beautiful-dnd": "13.1.8",
"@types/react-dom": "18.0.10", "@types/react-dom": "18.0.10",
"@types/react-grid-layout": "^1.1.2", "@types/react-grid-layout": "^1.1.2",
"@types/react-helmet-async": "1.0.3", "@types/react-helmet-async": "1.0.3",
@@ -182,7 +166,7 @@
"@types/webpack-dev-server": "^4.7.2", "@types/webpack-dev-server": "^4.7.2",
"@typescript-eslint/eslint-plugin": "^4.33.0", "@typescript-eslint/eslint-plugin": "^4.33.0",
"@typescript-eslint/parser": "^4.33.0", "@typescript-eslint/parser": "^4.33.0",
"autoprefixer": "10.4.19", "autoprefixer": "^9.0.0",
"babel-plugin-styled-components": "^1.12.0", "babel-plugin-styled-components": "^1.12.0",
"compression-webpack-plugin": "9.0.0", "compression-webpack-plugin": "9.0.0",
"copy-webpack-plugin": "^8.1.0", "copy-webpack-plugin": "^8.1.0",
@@ -208,9 +192,7 @@
"jest-styled-components": "^7.0.8", "jest-styled-components": "^7.0.8",
"lint-staged": "^12.5.0", "lint-staged": "^12.5.0",
"msw": "1.3.2", "msw": "1.3.2",
"npm-run-all": "latest",
"portfinder-sync": "^0.0.2", "portfinder-sync": "^0.0.2",
"postcss": "8.4.38",
"prettier": "2.2.1", "prettier": "2.2.1",
"raw-loader": "4.0.2", "raw-loader": "4.0.2",
"react-hooks-testing-library": "0.6.0", "react-hooks-testing-library": "0.6.0",
@@ -227,8 +209,7 @@
}, },
"lint-staged": { "lint-staged": {
"*.(js|jsx|ts|tsx)": [ "*.(js|jsx|ts|tsx)": [
"eslint --fix", "eslint --fix"
"sh scripts/typecheck-staged.sh"
] ]
}, },
"resolutions": { "resolutions": {
@@ -236,7 +217,6 @@
"@types/react-dom": "18.0.10", "@types/react-dom": "18.0.10",
"debug": "4.3.4", "debug": "4.3.4",
"semver": "7.5.4", "semver": "7.5.4",
"xml2js": "0.5.0", "xml2js": "0.5.0"
"phin": "^3.7.1"
} }
} }

View File

@@ -1 +0,0 @@
<svg width="32" height="33" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M15.91 28.675c-6.199 0-12.888-3.888-12.888-12.421S9.711 3.832 15.911 3.832c3.444 0 6.621 1.134 8.977 3.2 2.555 2.267 3.91 5.466 3.91 9.222 0 3.755-1.355 6.933-3.91 9.2-2.356 2.066-5.555 3.221-8.977 3.221z" fill="url(#prefix__paint0_radial_2122_6520)"/><path d="M26.552 8.87c1.185 1.91 1.803 4.186 1.803 6.717 0 3.756-1.356 6.933-3.911 9.2-2.356 2.066-5.556 3.222-8.978 3.222-4.013 0-8.221-1.634-10.706-5.098 2.391 3.924 6.889 5.764 11.15 5.764 3.423 0 6.623-1.155 8.978-3.222 2.555-2.266 3.911-5.444 3.911-9.2 0-2.83-.771-5.346-2.247-7.383z" fill="#EB8F00"/><path d="M20.123 22.905c0 1.685-1.846 2.667-4.124 2.667-2.277 0-4.124-.989-4.124-2.667 0-1.677 1.847-3.522 4.124-3.522 2.278 0 4.124 1.838 4.124 3.522zM12.06 14.852l1.88-1.748c.267-.331.307-.778.038-1.045-.353-.355-.98-.269-1.32.136-.018.033-.03.042-.049.075l-1.333 1.938-1.804-1.682c-.027-.03-.042-.034-.067-.062-.42-.32-1.05-.267-1.315.157-.207.32-.07.745.264 1.011l2.313 1.372-1.96 1.833c-.262.326-.31.77-.04 1.044.351.358.978.276 1.32-.127.018-.033.031-.042.051-.075l1.405-2.031 1.706 1.609c.027.029.043.035.067.064.418.322 1.049.273 1.318-.149.206-.32.07-.746-.26-1.013l-2.213-1.307zM20.61 14.852l-1.879-1.748c-.267-.331-.307-.778-.036-1.045.354-.355.978-.269 1.318.136.018.033.034.042.051.075l1.334 1.938 1.806-1.682c.025-.03.04-.034.065-.062.422-.32 1.05-.267 1.317.157.205.32.067.745-.266 1.011L22 15.004l1.96 1.833c.268.33.313.775.042 1.044-.349.358-.976.276-1.318-.127-.02-.033-.033-.042-.051-.075l-1.404-2.031-1.71 1.609c-.024.029-.04.035-.066.064-.418.322-1.046.273-1.315-.149-.21-.32-.074-.746.257-1.013l2.216-1.307zM11.911 8.696c.511.044.711-.645.178-.8a4.07 4.07 0 00-1.289-.133A4.596 4.596 0 007.689 9.14c-.378.4.156.89.556.6a5.829 5.829 0 013.666-1.044zM20.044 8.696a5.85 5.85 0 013.689 1.044c.4.29.933-.2.555-.6a4.645 4.645 0 00-3.11-1.377 4.07 4.07 0 00-1.29.133.408.408 0 00-.282.504c.053.194.24.318.438.296z" fill="#422B0D"/><defs><radialGradient id="prefix__paint0_radial_2122_6520" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(15.91 16.254) scale(12.657)"><stop offset=".5" stop-color="#FDE030"/><stop offset=".92" stop-color="#F7C02B"/><stop offset="1" stop-color="#F4A223"/></radialGradient></defs></svg>

Before

Width:  |  Height:  |  Size: 2.3 KiB

View File

@@ -1 +0,0 @@
<svg width="16" height="16" fill="none" xmlns="http://www.w3.org/2000/svg"><g clip-path="url(#prefix__clip0_2022_1972)" stroke="#fff" stroke-width="1.333" stroke-linecap="round" stroke-linejoin="round"><path d="M6.667 2h.006M9.333 1.333h.007M1.333 6l13.334-3.333M8 8V4.333M11.333 8H4.667a2 2 0 00-2 2v2.667a2 2 0 002 2h6.666a2 2 0 002-2V10a2 2 0 00-2-2zM6 8v3.333M10 8v3.333M2.667 11.334h10.666"/></g><defs><clipPath id="prefix__clip0_2022_1972"><path fill="#fff" d="M0 0h16v16H0z"/></clipPath></defs></svg>

Before

Width:  |  Height:  |  Size: 507 B

View File

@@ -1 +0,0 @@
<svg width="16" height="16" fill="none" xmlns="http://www.w3.org/2000/svg"><g stroke="#C0C1C3" stroke-width="1.333" stroke-linecap="round"><path d="M9.71 4.745a.576.576 0 000 .806l.922.922a.576.576 0 00.806 0l2.171-2.171a3.455 3.455 0 01-4.572 4.572l-3.98 3.98a1.222 1.222 0 11-1.727-1.728l3.98-3.98a3.455 3.455 0 014.572-4.572L9.717 4.739l-.006.006z" stroke-linejoin="round"/><path d="M4 7L2.527 5.566a1.333 1.333 0 01-.013-1.898l.81-.81a1.333 1.333 0 011.991.119L5.333 3M10.75 10.988l1.179 1.178m0 0l-.138.138a.833.833 0 00.387 1.397v0a.833.833 0 00.792-.219l.446-.446a.833.833 0 00.176-.917v0a.833.833 0 00-1.355-.261l-.308.308z"/></g></svg>

Before

Width:  |  Height:  |  Size: 644 B

View File

@@ -1 +0,0 @@
<svg width="32" height="32" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M13.72 12.839l-9.054.92s.05.649.236.798c.178.142 5.617.066 11.048.088 5.433.023 10.82.125 10.944.072.249-.107.249-.992.249-.992l-13.424-.886zM16.55 7.787l-12.623-.32s.275.61.637.813c.523.29 3.71.889 11.518.918 7.808.028 10.635-.4 11.317-.678.58-.238 1.215-1.576 1.215-1.576l-12.064.843z" fill="#8A1E0C"/><path d="M21.95 8.658v1.335l2.176-.087V8.542l-2.176.116z" fill="#8A1E0C"/><path d="M21.948 9.566h2.177v16.797l-2.206.294.029-17.09z" fill="#EB2901"/><path d="M21.355 26.19c-.111.193-.111 2.297-.007 2.444.105.147 3.242.104 3.326 0 .085-.104.063-2.38 0-2.464-.062-.085-3.235-.125-3.32.02z" fill="#474C4F"/><path d="M8.462 9.85V8.488l2.042.125v1.22l-2.042.017z" fill="#8A1E0C"/><path d="M8.462 9.55l-.038 17.051 2.08-.207V9.566l-2.042-.015z" fill="#EB2901"/><path d="M7.804 25.919c-.073.073-.147 2.36-.02 2.464.125.104 3.14.129 3.244.024.105-.104.085-2.304.023-2.43-.063-.127-3.142-.163-3.247-.058z" fill="#474C4F"/><path d="M14.788 8.107v4.876l2.393-.33V8.108h-2.393z" fill="#EB2901"/><path d="M27.067 11.978c-.115-.16-.482-.138-.482-.138l-1.137-.013c.002-.398-.01-.913-.078-.996-.116-.137-4.542-.09-4.702.047-.091.078-.11.527-.107.898-2.738-.027-5.99-.058-8.83-.076 0-.384-.012-.849-.078-.915-.116-.116-4.22-.185-4.38-.07-.113.083-.136.647-.138.97-1.384.002-2.275.013-2.34.04-.322.137-.137 2.042-.137 2.042l22.476.16c.002.002.049-1.787-.067-1.95z" fill="#EB2901"/><path d="M3.93 6.942s-.646-.34-1.377-1.573c-.509-.858-.595-1.658-.387-1.778.21-.12 2.154 1.08 5.745 1.616a60.81 60.81 0 008.173.644c2.884.027 5.717-.135 8.397-.644 3.62-.689 4.906-1.436 5.264-1.316.36.12-.109 1.227-.369 1.78-.178.376-.944 1.77-1.515 1.87-.411.072-19.953-.09-19.953-.09l-3.977-.509z" fill="#474C4F"/><path d="M3.31 5.724c-.108.137-.057.457.212 1.06.107.237.415.782.529.917 0 0 2.982.756 11.977.7 8.995-.055 12.108-.62 12.108-.62s.911-1.277.745-1.32c-.096-.024-4.847.98-12.909.898C7.911 7.277 3.311 5.724 3.311 5.724z" fill="#EB2901"/></svg>

Before

Width:  |  Height:  |  Size: 2.0 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 5.2 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 5.6 KiB

View File

@@ -1 +0,0 @@
<svg width="16" height="16" fill="none" xmlns="http://www.w3.org/2000/svg"><g stroke="#C0C1C3" stroke-width="1.333" stroke-linecap="round" stroke-linejoin="round"><path d="M2 4.667V3.333C2 2.6 2.6 2 3.333 2h1.334M11.333 2h1.334C13.4 2 14 2.6 14 3.333v1.334M14 11.334v1.333C14 13.4 13.4 14 12.667 14h-1.334M4.667 14H3.333C2.6 14 2 13.4 2 12.667v-1.333M8.667 4.667H5.333a.667.667 0 00-.666.666v2c0 .368.298.667.666.667h3.334a.667.667 0 00.666-.667v-2a.667.667 0 00-.666-.667zM10.667 8H7.333a.667.667 0 00-.666.667v2c0 .368.298.666.666.666h3.334a.667.667 0 00.666-.666v-2A.667.667 0 0010.667 8z"/></g></svg>

Before

Width:  |  Height:  |  Size: 604 B

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 88 KiB

View File

@@ -1 +0,0 @@
<svg width="24" height="24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M23.06 17.526c-1.281.668-7.916 3.396-9.328 4.132-1.413.736-2.198.73-3.314.196C9.303 21.32 2.242 18.468.97 17.86c-.636-.303-.97-.56-.97-.802v-2.426s9.192-2.001 10.676-2.534c1.484-.532 1.999-.551 3.262-.089 1.263.463 8.814 1.826 10.062 2.283v2.391c0 .24-.288.503-.94.843z" fill="#912626"/><path d="M23.06 15.114c-1.281.668-7.916 3.396-9.329 4.132-1.412.737-2.197.73-3.313.196C9.302 18.91 2.242 16.056.97 15.45c-1.272-.608-1.298-1.027-.049-1.516 1.25-.49 8.271-3.244 9.755-3.776 1.484-.533 1.999-.552 3.262-.09 1.263.463 7.858 3.088 9.106 3.546 1.248.457 1.296.834.015 1.501z" fill="#C6302B"/><path d="M23.06 13.6c-1.281.668-7.916 3.396-9.328 4.133-1.413.736-2.198.73-3.314.196S2.242 14.543.97 13.935c-.636-.304-.97-.56-.97-.802v-2.426s9.192-2.001 10.676-2.534c1.484-.532 1.999-.551 3.262-.089C15.2 8.547 22.752 9.91 24 10.366v2.392c0 .24-.288.503-.94.843z" fill="#912626"/><path d="M23.06 11.19c-1.281.667-7.916 3.395-9.329 4.131-1.412.737-2.197.73-3.313.196-1.116-.533-8.176-3.386-9.448-3.993-1.272-.608-1.298-1.027-.049-1.516 1.25-.49 8.271-3.244 9.755-3.776 1.484-.533 1.999-.552 3.262-.09 1.263.463 7.858 3.088 9.106 3.545 1.248.458 1.296.835.015 1.502z" fill="#C6302B"/><path d="M23.06 9.53c-1.281.668-7.916 3.396-9.328 4.132-1.413.737-2.198.73-3.314.196-1.116-.533-8.176-3.386-9.448-3.993C.334 9.56 0 9.305 0 9.062V6.636s9.192-2 10.676-2.533c1.484-.533 1.999-.552 3.262-.09C15.2 4.477 22.752 5.84 24 6.297v2.392c0 .24-.288.502-.94.842z" fill="#912626"/><path d="M23.06 7.118c-1.281.668-7.916 3.396-9.329 4.132-1.412.737-2.197.73-3.313.196C9.303 10.913 2.242 8.061.97 7.453-.302 6.845-.328 6.427.921 5.937c1.25-.489 8.271-3.244 9.755-3.776 1.484-.532 1.999-.552 3.262-.089 1.263.463 7.858 3.088 9.106 3.545 1.248.457 1.296.834.015 1.501z" fill="#C6302B"/><path d="M14.933 4.758l-2.064.215-.462 1.111-.746-1.24L9.28 4.63l1.778-.641-.534-.985 1.665.651 1.569-.513-.424 1.017 1.6.6zm-2.649 5.393l-3.85-1.597 5.517-.847-1.667 2.444zM6.945 5.376c1.63 0 2.95.512 2.95 1.143 0 .632-1.32 1.144-2.95 1.144-1.629 0-2.95-.512-2.95-1.144 0-.63 1.321-1.143 2.95-1.143z" fill="#fff"/><path d="M17.371 5.062l3.266 1.29-3.263 1.29-.003-2.58z" fill="#621B1C"/><path d="M13.758 6.492l3.613-1.43.003 2.58-.354.139-3.262-1.29z" fill="#9A2928"/></svg>

Before

Width:  |  Height:  |  Size: 2.3 KiB

View File

@@ -1 +0,0 @@
<svg width="32" height="33" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M14.309 13.108l-6.704-3.32s-.016-.317.284-.477c.302-.16 5.053-2.107 5.435-2.107.383 0 2.62.431 4.249.793 1.629.363 5.933 1.287 5.953 1.57.02.281-4.404 4.806-4.404 4.806l-4.813-1.265z" fill="#C3FECE"/><path d="M20.423 11.037s-2.811-.826-5.546-1.469c-1.274-.3-5.016-1.084-5.016-1.084s.398-.173.698-.3c.305-.127.547-.193.547-.193s2.44.486 4.253.873c2.453.522 5.886 1.547 5.966 1.709.082.16-.902.464-.902.464z" fill="#fff"/><path d="M14.98 10.26c-.598.415-.011.666 1.09.924 1.207.282 2.127.698 2.903.247.7-.405-1.014-.845-1.8-1.014-.6-.129-1.731-.478-2.193-.158z" fill="#ACB1B2"/><path d="M17.17 11.095c-.005 0 .02-4.869.02-5.049 0-.18-.203-.342.02-.724.222-.382.804-.342.804-.342s2.416-.702 3.38-.945c.964-.242 3.098-.804 3.098-.804l.142 1.22s-2.236.631-3.342.913c-1.107.282-2.616.745-2.616.745l-.222.202.064 4.757s-.206.231-.668.231c-.45-.002-.68-.204-.68-.204z" fill="#FFD816"/><path d="M24.095 3.855c.018.38.22.616.46.616.24 0 .404-.307.369-.707-.038-.398-.296-.58-.516-.506-.22.073-.327.32-.313.597zM18.46 6.422a.209.209 0 01-.123-.038l-1.153-.769a.225.225 0 01-.063-.309.222.222 0 01.31-.062l1.153.769a.224.224 0 01.062.309.228.228 0 01-.187.1z" fill="#FEB804"/><path d="M18.636 6.235a.225.225 0 01-.178-.089c-.295-.393-.633-.84-.693-.909a.225.225 0 01-.031-.284.222.222 0 01.309-.062c.04.027.062.042.771.986.073.098.007.238-.091.312-.04.03-.04.046-.087.046z" fill="#FEB804"/><path d="M18.365 6.609c-.01 0-.022 0-.035-.003l-1.111-.175a.221.221 0 11.069-.438l1.11.176c.12.02.225.042.205.164-.016.107-.129.276-.238.276z" fill="#FEB804"/><path d="M7.596 9.764c.353 0 3.188.744 4.65 1.013 1.463.27 5.878 1.314 6.027 1.342.149.03.12 1.94.12 1.94s2.089 10.8 2.029 11.309c-.06.506-1.431 4.415-1.431 4.415s-.807.12-2.865-.478c-2.057-.598-7.488-2.089-7.817-2.506-.329-.418-.12-5.938-.298-9.338-.182-3.402-.415-7.697-.415-7.697z" fill="#79DD8A"/><path d="M24.06 27.036c.113-.375-.518-4.402-.607-8.101-.089-3.698.229-9.324.076-9.369-.154-.042-5.256 2.553-5.256 2.553s-.022 3.671.04 7.133c.08 4.48.438 10.41.676 10.53.238.12 2.302-1.035 2.924-1.372 1.102-.598 2.058-1.074 2.147-1.374z" fill="#02AB46"/><path d="M20.408 13.82l.011-2.787.914-.45.026 3.056-.422.74-.529-.56z" fill="#DBDFE1"/><path d="M12.322 14.797c-1.973-.211-3.34 1.549-3.233 3.842.127 2.709 1.91 4.704 3.842 5.102 1.93.398 3.802-.44 3.842-3.402.044-3.087-2.669-5.353-4.451-5.542z" fill="#FEFEFD"/><path d="M13.637 17.27s-.4-1.344-1.602-.986c-1.202.357-1.853 2.973.187 4.15 1.96 1.131 3.764-.944 3.133-2.288-.574-1.227-1.718-.876-1.718-.876z" fill="#EF5B44"/><path d="M13.18 15.626c-.136.049-.243.602-.1 1.13.106.396.446.939.643.903.158-.029.278-.651.13-1.173-.174-.602-.516-.918-.674-.86z" fill="#B8CF17"/><path d="M13.15 18.746c-.564-.171-1.2 1.769-.057 2.977 1.26 1.331 2.73.158 2.69-.1-.057-.358-1.044-.615-1.53-1.215-.487-.605-.774-1.562-1.102-1.662z" fill="#FD8F01"/><path d="M11.346 18.417s.113-.849-.673-.802c-.76.046-.574.944-.574.944s-.633.076-.526.778c.08.53.64.524.64.524s-.616.242-.336.945c.249.624.822.373.822.373s-.21.609.287.93c.42.272.787.043.787.043s-.023.52.557.616c.703.115 1.007-.74.507-1.136-.38-.3-.724-.067-.724-.067s.07-.166.004-.357c-.045-.125-.116-.171-.116-.171s.616-.058.516-.758c-.1-.702-.716-.616-.716-.616s.358-.286.216-.802c-.14-.518-.671-.444-.671-.444z" fill="#A281D0"/><path d="M21.04 14.595c-.511 0-2.691-2.167-2.711-2.189a.222.222 0 01.024-.313.224.224 0 01.314.022c.14.155 1.806 1.702 2.286 2 .311-.465 1.322-2.498 2.191-4.333a.224.224 0 01.296-.107.223.223 0 01.106.296c-2.142 4.526-2.353 4.586-2.466 4.617-.013.007-.027.007-.04.007z" fill="#2D802D"/></svg>

Before

Width:  |  Height:  |  Size: 3.6 KiB

View File

@@ -1 +0,0 @@
<svg width="14" height="14" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M1.305 13.063c.74.739 1.637.482 2.156-.109.53-.604.813-.956.813-.956.66-.973 3.392-4.227 5.724-6.568a2.638 2.638 0 002.74-.434 2.648 2.648 0 00.922-2.041.155.155 0 00-.23-.132l-1.607.927a1.64 1.64 0 01-1.076-1.864l1.6-.923a.153.153 0 00.077-.134.153.153 0 00-.077-.133 2.65 2.65 0 00-3.66 3.563C6.11 6.826 2.966 9.604 2.15 10.223c0 0-.492.356-.962.84-.464.476-.636 1.245.117 1.999zm.542-1.137a.592.592 0 111.184 0 .592.592 0 01-1.184 0z" fill="#82AEC0"/><path d="M8.334 4.61l.353-.35a2.63 2.63 0 01-.212-2.039c.073-.12.189-.249.262-.171-.03.946.245 1.931.902 2.611.327.338.752.582 1.207.696.224.057.458.082.69.069.137-.008.519-.149.596-.044v.004a2.656 2.656 0 01-2.135.043 38.176 38.176 0 00-1.903 2.05c.262-.495 1.034-1.408 1.241-1.757a.412.412 0 00-.036-.464c-.207-.255-.633-.493-.965-.649z" fill="#2F7889"/><path d="M5.186 8.529c.06-.062.004-.167-.08-.148-.158.035-.386.125-.657.345-.531.43-1.934 1.595-2.107 1.825-.173.23.522-.003.767-.047.2-.036 1.602-1.48 2.077-1.975zM10.048 1.104c-.296.212-.563.465-.84.701-.072.061-.177.122-.25.065-.08-.064-.03-.191.03-.274C9.512.874 10.493.358 11.442.563c-.5.161-.95.223-1.395.541z" fill="#B9E4EA"/><path d="M12.408 3.583a2.1 2.1 0 01-.371.19c-.112.031-.43-.092-.522-.166l1.183-.772c.043-.028.087-.056.137-.072a.546.546 0 01.185-.014c.087.004.51-.01.56.064.05.075-.126.149-.183.183-.33.197-.66.391-.99.587zM7.867 7.687L6.624 6.254c-.45.423-.895.835-1.321 1.225l.362-.078a.482.482 0 01.439.13l.58.65c.122.122.142.334.096.5l-.065.308c.367-.423.755-.862 1.152-1.302z" fill="#2F7889"/><g><path d="M13.378 12.86l-.744.643a.686.686 0 01-.968-.072L2.84 2.779l1.135-.853 9.459 9.976a.668.668 0 01-.057.957z" fill="#A06841"/><path d="M3.648 3.752l2.1 2.535c.328-.493.494-1.084.629-1.83l-2.028-2.14a1.838 1.838 0 00-.414.48 2.17 2.17 0 00-.287.955z" fill="#7D5133"/><path d="M7.81.438C5.885.416 5.17.588 4.098 1.515l-.966.835c-.35.302-.815.566-.742 1.089.027.19.086.384.05.573-.034.179-.242.268-.39.166-.139-.096-.292-.214-.463-.234a.588.588 0 00-.45.14l-.747.664s-.107.434.729 1.38c.835.946 1.373.878 1.373.878l.702-.618a.53.53 0 00.176-.412c-.003-.184-.11-.326-.174-.49-.013-.031-.083-.143.04-.244.109-.094.333-.062.46-.027.129.034.25.088.38.122.25.065.369-.051.543-.201L6.013 3.93c.619-.536-.325-1.474-.325-1.474C5.244 1.953 7.941.687 7.941.687c.198-.069.138-.246-.13-.249z" fill="#82AEC0"/><path d="M4.076 5.338a.504.504 0 00.14.016v-.02c-.011-.12-.077-.23-.144-.33A7.18 7.18 0 002.545 3.33a1.683 1.683 0 00-.154-.111.726.726 0 00-.002.22c.027.19.086.384.05.573-.038.196-.242.25-.399.177a3.27 3.27 0 011.011 1.027c.035.056.07.115.11.168a.2.2 0 01.075-.14c.109-.095.333-.063.46-.029.13.034.25.088.38.123zM1.778 5.573c.585.613.914 1.247.734 1.42-.179.17-.799-.186-1.384-.797C.542 5.584.21 4.92.388 4.748c.18-.171.804.213 1.39.825z" fill="#2F7889"/><path d="M4.057 2.41c.465-.198.88-.623 1.422-1.09A2.53 2.53 0 016.03.964c.076-.035.048-.149-.036-.148-.278.005-.527.09-.772.196-.342.149-.644.374-.935.608-.2.16-.67.555-.965.805-.055.047-.012.12.06.12.208.002.325.014.674-.135zM1.124 4.352c-.196.221.055.281.496.646.311.257.642.018.645-.223.003-.216-.052-.333-.366-.53-.315-.199-.597-.093-.775.107z" fill="#B9E4EA"/></g></svg>

Before

Width:  |  Height:  |  Size: 3.2 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 204 KiB

View File

@@ -1,19 +0,0 @@
<svg width="32" height="33" viewBox="0 0 32 33" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M9.36806 25.9481C5.93935 25.9481 3.15283 21.7098 3.15283 16.5002C3.15283 11.2907 5.94157 7.05238 9.36806 7.05238C12.7945 7.05238 15.5833 11.2907 15.5833 16.5002C15.5833 21.7098 12.7945 25.9481 9.36806 25.9481Z" fill="#FAFAFA"/>
<path d="M9.36815 7.49694C10.8414 7.49694 12.2524 8.38594 13.3391 10.0017C14.499 11.7241 15.139 14.0333 15.139 16.5003C15.139 18.9673 14.499 21.2764 13.3391 22.9989C12.2524 24.6146 10.8414 25.5036 9.36815 25.5036C7.89489 25.5036 6.48385 24.6146 5.39724 22.9989C4.23508 21.2764 3.59734 18.9673 3.59734 16.5003C3.59734 14.0333 4.23731 11.7241 5.39724 10.0017C6.48385 8.38594 7.89267 7.49694 9.36815 7.49694ZM9.36815 6.60794C5.69056 6.60794 2.7085 11.0374 2.7085 16.5003C2.7085 21.9632 5.69056 26.3926 9.36815 26.3926C13.0457 26.3926 16.0278 21.9632 16.0278 16.5003C16.0278 11.0374 13.0457 6.60794 9.36815 6.60794Z" fill="#B0BEC5"/>
<path d="M7.47266 15.5762C6.87269 15.0118 7.00602 13.8919 7.77487 13.0741C7.81486 13.0319 7.85486 12.9919 7.89708 12.9541C7.55488 12.7608 7.17934 12.6519 6.78381 12.6519C5.18611 12.6519 3.89062 14.414 3.89062 16.585C3.89062 18.756 5.18611 20.5182 6.78381 20.5182C8.3815 20.5182 9.67699 18.756 9.67699 16.585C9.67699 16.1962 9.63477 15.8184 9.55699 15.4629C8.83703 15.9806 7.97708 16.0495 7.47266 15.5762Z" fill="url(#paint0_linear_2122_5062)"/>
<path d="M22.6294 26.3932C26.3074 26.3932 29.289 21.9642 29.289 16.5008C29.289 11.0374 26.3074 6.60847 22.6294 6.60847C18.9514 6.60847 15.9697 11.0374 15.9697 16.5008C15.9697 21.9642 18.9514 26.3932 22.6294 26.3932Z" fill="#EEEEEE"/>
<path d="M22.6283 25.9493C19.2018 25.9493 16.4131 21.711 16.4131 16.5014C16.4131 11.2919 19.2018 7.05357 22.6283 7.05357C26.0548 7.05357 28.8435 11.2919 28.8435 16.5014C28.8435 21.711 26.057 25.9493 22.6283 25.9493Z" fill="#FAFAFA"/>
<path d="M22.6284 7.49816C24.1017 7.49816 25.5127 8.38716 26.5993 10.0029C27.7592 11.7254 28.3992 14.0345 28.3992 16.5015C28.3992 18.9685 27.7592 21.2777 26.5993 23.0001C25.5127 24.6159 24.1017 25.5049 22.6284 25.5049C21.1551 25.5049 19.7441 24.6159 18.6575 23.0001C17.4976 21.2777 16.8576 18.9685 16.8576 16.5015C16.8576 14.0345 17.4976 11.7254 18.6575 10.0029C19.7441 8.38716 21.1551 7.49816 22.6284 7.49816ZM22.6284 6.60916C18.9508 6.60916 15.9688 11.0386 15.9688 16.5015C15.9688 21.9644 18.9508 26.3939 22.6284 26.3939C26.306 26.3939 29.2881 21.9644 29.2881 16.5015C29.2881 11.0386 26.306 6.60916 22.6284 6.60916Z" fill="#B0BEC5"/>
<path d="M20.7339 15.5767C20.1339 15.0123 20.2672 13.8924 21.0361 13.0746C21.0761 13.0324 21.1161 12.9924 21.1583 12.9546C20.8161 12.7613 20.4406 12.6524 20.045 12.6524C18.4473 12.6524 17.1519 14.4146 17.1519 16.5856C17.1519 18.7566 18.4473 20.5187 20.045 20.5187C21.6427 20.5187 22.9382 18.7566 22.9382 16.5856C22.9382 16.1967 22.896 15.8189 22.8182 15.4634C22.1005 15.9812 21.2383 16.05 20.7339 15.5767Z" fill="url(#paint1_linear_2122_5062)"/>
<defs>
<linearGradient id="paint0_linear_2122_5062" x1="6.78232" y1="12.651" x2="6.78232" y2="20.5188" gradientUnits="userSpaceOnUse">
<stop stop-color="#424242"/>
<stop offset="1" stop-color="#212121"/>
</linearGradient>
<linearGradient id="paint1_linear_2122_5062" x1="20.0449" y1="12.6515" x2="20.0449" y2="20.5193" gradientUnits="userSpaceOnUse">
<stop stop-color="#424242"/>
<stop offset="1" stop-color="#212121"/>
</linearGradient>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 3.3 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 1.7 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.7 KiB

View File

@@ -1,18 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="80px" height="80px" viewBox="0 0 80 80" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 64 (93537) - https://sketch.com -->
<title>Icon-Architecture/64/Arch_Amazon-EC2_64</title>
<desc>Created with Sketch.</desc>
<defs>
<linearGradient x1="0%" y1="100%" x2="100%" y2="0%" id="linearGradient-1">
<stop stop-color="#C8511B" offset="0%"></stop>
<stop stop-color="#FF9900" offset="100%"></stop>
</linearGradient>
</defs>
<g id="Icon-Architecture/64/Arch_Amazon-EC2_64" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="Icon-Architecture-BG/64/Compute" fill="url(#linearGradient-1)">
<rect id="Rectangle" x="0" y="0" width="80" height="80"></rect>
</g>
<path d="M27,53 L52,53 L52,28 L27,28 L27,53 Z M54,28 L58,28 L58,30 L54,30 L54,34 L58,34 L58,36 L54,36 L54,39 L58,39 L58,41 L54,41 L54,45 L58,45 L58,47 L54,47 L54,51 L58,51 L58,53 L54,53 L54,53.136 C54,54.164 53.164,55 52.136,55 L52,55 L52,59 L50,59 L50,55 L46,55 L46,59 L44,59 L44,55 L41,55 L41,59 L39,59 L39,55 L35,55 L35,59 L33,59 L33,55 L29,55 L29,59 L27,59 L27,55 L26.864,55 C25.836,55 25,54.164 25,53.136 L25,53 L22,53 L22,51 L25,51 L25,47 L22,47 L22,45 L25,45 L25,41 L22,41 L22,39 L25,39 L25,36 L22,36 L22,34 L25,34 L25,30 L22,30 L22,28 L25,28 L25,27.864 C25,26.836 25.836,26 26.864,26 L27,26 L27,22 L29,22 L29,26 L33,26 L33,22 L35,22 L35,26 L39,26 L39,22 L41,22 L41,26 L44,26 L44,22 L46,22 L46,26 L50,26 L50,22 L52,22 L52,26 L52.136,26 C53.164,26 54,26.836 54,27.864 L54,28 Z M41,65.876 C41,65.944 40.944,66 40.876,66 L14.124,66 C14.056,66 14,65.944 14,65.876 L14,39.124 C14,39.056 14.056,39 14.124,39 L20,39 L20,37 L14.124,37 C12.953,37 12,37.953 12,39.124 L12,65.876 C12,67.047 12.953,68 14.124,68 L40.876,68 C42.047,68 43,67.047 43,65.876 L43,61 L41,61 L41,65.876 Z M68,14.124 L68,40.876 C68,42.047 67.047,43 65.876,43 L60,43 L60,41 L65.876,41 C65.944,41 66,40.944 66,40.876 L66,14.124 C66,14.056 65.944,14 65.876,14 L39.124,14 C39.056,14 39,14.056 39,14.124 L39,20 L37,20 L37,14.124 C37,12.953 37.953,12 39.124,12 L65.876,12 C67.047,12 68,12.953 68,14.124 L68,14.124 Z" id="Amazon-EC2_Icon_64_Squid" fill="#FFFFFF"></path>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 2.3 KiB

View File

@@ -1,18 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="80px" height="80px" viewBox="0 0 80 80" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 64 (93537) - https://sketch.com -->
<title>Icon-Architecture/64/Arch_Amazon-Elastic-Container-Service_64</title>
<desc>Created with Sketch.</desc>
<defs>
<linearGradient x1="0%" y1="100%" x2="100%" y2="0%" id="linearGradient-1">
<stop stop-color="#C8511B" offset="0%"></stop>
<stop stop-color="#FF9900" offset="100%"></stop>
</linearGradient>
</defs>
<g id="Icon-Architecture/64/Arch_Amazon-Elastic-Container-Service_64" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="Icon-Architecture-BG/64/Containers" fill="url(#linearGradient-1)">
<rect id="Rectangle" x="0" y="0" width="80" height="80"></rect>
</g>
<path d="M64,48.2340095 L56,43.4330117 L56,32.0000169 C56,31.6440171 55.812,31.3150172 55.504,31.1360173 L44,24.4260204 L44,14.7520248 L64,26.5710194 L64,48.2340095 Z M65.509,25.13902 L43.509,12.139026 C43.199,11.9560261 42.818,11.9540261 42.504,12.131026 C42.193,12.3090259 42,12.6410257 42,13.0000256 L42,25.0000201 C42,25.3550199 42.189,25.6840198 42.496,25.8640197 L54,32.5740166 L54,44.0000114 C54,44.3510113 54.185,44.6770111 54.486,44.857011 L64.486,50.8570083 C64.644,50.9520082 64.822,51 65,51 C65.17,51 65.34,50.9570082 65.493,50.8700083 C65.807,50.6930084 66,50.3600085 66,50 L66,26.0000196 C66,25.6460198 65.814,25.31902 65.509,25.13902 L65.509,25.13902 Z M40.445,66.863001 L17,54.3990067 L17,26.5710194 L37,14.7520248 L37,24.4510204 L26.463,31.1560173 C26.175,31.3400172 26,31.6580171 26,32.0000169 L26,49.0000091 C26,49.373009 26.208,49.7150088 26.538,49.8870087 L39.991,56.8870055 C40.28,57.0370055 40.624,57.0380055 40.912,56.8880055 L53.964,50.1440086 L61.996,54.9640064 L40.445,66.863001 Z M64.515,54.1420068 L54.515,48.1420095 C54.217,47.9640096 53.849,47.9520096 53.541,48.1120095 L40.455,54.8730065 L28,48.3930094 L28,32.5490167 L38.537,25.8440197 C38.825,25.6600198 39,25.3420199 39,25.0000201 L39,13.0000256 C39,12.6410257 38.808,12.3090259 38.496,12.131026 C38.184,11.9540261 37.802,11.9560261 37.491,12.139026 L15.491,25.13902 C15.187,25.31902 15,25.6460198 15,26.0000196 L15,55 C15,55.3690062 15.204,55.7090061 15.53,55.883006 L39.984,68.8830001 C40.131,68.961 40.292,69 40.453,69 C40.62,69 40.786,68.958 40.937,68.8750001 L64.484,55.875006 C64.797,55.7020061 64.993,55.3750062 65.0001416,55.0180064 C65.006,54.6600066 64.821,54.3260067 64.515,54.1420068 L64.515,54.1420068 Z" id="Amazon-Elastic-Container-Service_Icon_64_Squid" fill="#FFFFFF"></path>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 2.7 KiB

View File

@@ -1,2 +0,0 @@
<?xml version="1.0" encoding="utf-8"?><!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
<svg width="800px" height="800px" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" fill="none"><path fill="url(#amazon-eks-color-16__paint0_linear_879_141)" fill-rule="evenodd" d="M6.381 10.148h.897V8.121l1.837 2.027h1.164L7.997 7.642l2.169-2.195H8.963L7.278 7.146V5.447h-.897v4.701z" clip-rule="evenodd"/><path fill="url(#amazon-eks-color-16__paint1_linear_879_141)" d="M8.532 3.803l3.186 1.81a.173.173 0 01.088.149v3.62c0 .06.033.118.088.149l2.842 1.615a.176.176 0 00.264-.15V3.947a.173.173 0 00-.088-.15L8.708.274a.176.176 0 00-.264.15v3.23c0 .062.034.119.088.15z"/><path fill="url(#amazon-eks-color-16__paint2_linear_879_141)" d="M11.273 10.288l-3.185 1.81a.178.178 0 01-.176 0l-3.63-2.062a.173.173 0 01-.088-.15V5.762c0-.062.034-.119.088-.15l3.186-1.81a.172.172 0 00.088-.15V.424a.176.176 0 00-.264-.15L1.088 3.798a.173.173 0 00-.088.15V11.7c0 .061.033.118.088.15l6.824 3.876c.054.03.122.03.176 0l6.204-3.524a.172.172 0 000-.3l-2.843-1.615a.178.178 0 00-.176 0z"/><defs><linearGradient id="amazon-eks-color-16__paint0_linear_879_141" x1="10.691" x2="8.521" y1="9.879" y2="4.634" gradientUnits="userSpaceOnUse"><stop stop-color="#426DDB"/><stop offset="1" stop-color="#3B4BDB"/></linearGradient><linearGradient id="amazon-eks-color-16__paint1_linear_879_141" x1="15.693" x2="9.546" y1="10.544" y2="-.213" gradientUnits="userSpaceOnUse"><stop stop-color="#426DDB"/><stop offset="1" stop-color="#3B4BDB"/></linearGradient><linearGradient id="amazon-eks-color-16__paint2_linear_879_141" x1="9.433" x2="2.732" y1="14.904" y2="2.88" gradientUnits="userSpaceOnUse"><stop stop-color="#2775FF"/><stop offset="1" stop-color="#188DFF"/></linearGradient></defs></svg>

Before

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 957 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

@@ -1,11 +0,0 @@
<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>

Before

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 45 KiB

View File

@@ -37,16 +37,11 @@
"text_condition1": "Send a notification when", "text_condition1": "Send a notification when",
"text_condition2": "the threshold", "text_condition2": "the threshold",
"text_condition3": "during the last", "text_condition3": "during the last",
"option_1min": "1 min",
"option_5min": "5 mins", "option_5min": "5 mins",
"option_10min": "10 mins", "option_10min": "10 mins",
"option_15min": "15 mins", "option_15min": "15 mins",
"option_30min": "30 mins",
"option_60min": "60 mins", "option_60min": "60 mins",
"option_4hours": "4 hours", "option_4hours": "4 hours",
"option_3hours": "3 hours",
"option_6hours": "6 hours",
"option_12hours": "12 hours",
"option_24hours": "24 hours", "option_24hours": "24 hours",
"field_threshold": "Alert Threshold", "field_threshold": "Alert Threshold",
"option_allthetimes": "all the times", "option_allthetimes": "all the times",
@@ -67,7 +62,6 @@
"button_cancel": "No", "button_cancel": "No",
"field_promql_expr": "PromQL Expression", "field_promql_expr": "PromQL Expression",
"field_alert_name": "Alert Name", "field_alert_name": "Alert Name",
"field_notification_channel": "Notification Channel",
"field_alert_desc": "Alert Description", "field_alert_desc": "Alert Description",
"field_labels": "Labels", "field_labels": "Labels",
"field_severity": "Severity", "field_severity": "Severity",
@@ -106,7 +100,7 @@
"user_guide_ch_step3a": "Set alert severity, name and descriptions", "user_guide_ch_step3a": "Set alert severity, name and descriptions",
"user_guide_ch_step3b": "Add tags to the alert in the Label field if needed", "user_guide_ch_step3b": "Add tags to the alert in the Label field if needed",
"user_tooltip_more_help": "More details on how to create alerts", "user_tooltip_more_help": "More details on how to create alerts",
"choose_alert_type": "Choose a type for the alert", "choose_alert_type": "Choose a type for the alert:",
"metric_based_alert": "Metric based Alert", "metric_based_alert": "Metric based Alert",
"metric_based_alert_desc": "Send a notification when a condition occurs in the metric data", "metric_based_alert_desc": "Send a notification when a condition occurs in the metric data",
"log_based_alert": "Log-based Alert", "log_based_alert": "Log-based Alert",
@@ -116,8 +110,5 @@
"exceptions_based_alert": "Exceptions-based Alert", "exceptions_based_alert": "Exceptions-based Alert",
"exceptions_based_alert_desc": "Send a notification when a condition occurs in the exceptions data.", "exceptions_based_alert_desc": "Send a notification when a condition occurs in the exceptions data.",
"field_unit": "Threshold unit", "field_unit": "Threshold unit",
"text_alert_on_absent": "Send a notification if data is missing for",
"text_alert_frequency": "Run alert every",
"text_for": "minutes",
"selected_query_placeholder": "Select query" "selected_query_placeholder": "Select query"
} }

View File

@@ -15,7 +15,6 @@
"button_test_channel": "Test", "button_test_channel": "Test",
"button_return": "Back", "button_return": "Back",
"field_channel_name": "Name", "field_channel_name": "Name",
"field_send_resolved": "Send resolved alerts",
"field_channel_type": "Type", "field_channel_type": "Type",
"field_webhook_url": "Webhook URL", "field_webhook_url": "Webhook URL",
"field_slack_recipient": "Recipient", "field_slack_recipient": "Recipient",

View File

@@ -1,6 +1,6 @@
{ {
"create_dashboard": "Create Dashboard", "create_dashboard": "Create Dashboard",
"import_json": "Import Dashboard JSON", "import_json": "Import JSON",
"import_grafana_json": "Import Grafana JSON", "import_grafana_json": "Import Grafana JSON",
"copy_to_clipboard": "Copy To ClipBoard", "copy_to_clipboard": "Copy To ClipBoard",
"download_json": "Download JSON", "download_json": "Download JSON",
@@ -9,14 +9,13 @@
"upload_json_file": "Upload JSON file", "upload_json_file": "Upload JSON file",
"paste_json_below": "Paste JSON below", "paste_json_below": "Paste JSON below",
"error_upload_json": "Invalid JSON", "error_upload_json": "Invalid JSON",
"import_and_next": "Import and Next", "load_json": "Load JSON",
"import_dashboard_by_pasting": "Import dashboard by pasting JSON or importing JSON file", "import_dashboard_by_pasting": "Import dashboard by pasting JSON or importing JSON file",
"error_loading_json": "Error loading JSON file", "error_loading_json": "Error loading JSON file",
"empty_json_not_allowed": "Empty JSON is not allowed", "empty_json_not_allowed": "Empty JSON is not allowed",
"new_dashboard_title": "Sample Title", "new_dashboard_title": "Sample Title",
"layout_saved_successfully": "Layout saved successfully", "layout_saved_successfully": "Layout saved successfully",
"add_panel": "Add Panel", "add_panel": "Add Panel",
"add_row": "Add Row",
"save_layout": "Save Layout", "save_layout": "Save Layout",
"variable_updated_successfully": "Variable updated successfully", "variable_updated_successfully": "Variable updated successfully",
"error_while_updating_variable": "Error while updating variable", "error_while_updating_variable": "Error while updating variable",
@@ -26,5 +25,5 @@
"dashboard_unsave_changes": "There are unsaved changes in the Query builder, please stage and run the query or the changes will be lost. Press OK to discard.", "dashboard_unsave_changes": "There are unsaved changes in the Query builder, please stage and run the query or the changes will be lost. Press OK to discard.",
"dashboard_save_changes": "Your graph built with {{queryTag}} query will be saved. Press OK to confirm.", "dashboard_save_changes": "Your graph built with {{queryTag}} query will be saved. Press OK to confirm.",
"your_graph_build_with": "Your graph built with", "your_graph_build_with": "Your graph built with",
"dashboard_ok_confirm": "query will be saved. Press OK to confirm." "dashboar_ok_confirm": "query will be saved. Press OK to confirm."
} }

View File

@@ -1,3 +0,0 @@
{
"delete_confirm_message": "Are you sure you want to delete {{keyName}}? Deleting an ingestion key is irreversible and cannot be undone."
}

View File

@@ -14,5 +14,5 @@
"delete_domain_message": "Are you sure you want to delete this domain?", "delete_domain_message": "Are you sure you want to delete this domain?",
"delete_domain": "Delete Domain", "delete_domain": "Delete Domain",
"add_domain": "Add Domains", "add_domain": "Add Domains",
"saml_settings": "Your SAML settings have been saved, please login from incognito window to confirm that it has been set up correctly" "saml_settings":"Your SAML settings have been saved, please login from incognito window to confirm that it has been set up correctly"
} }

View File

@@ -3,7 +3,6 @@
"alert_channels": "Alert Channels", "alert_channels": "Alert Channels",
"organization_settings": "Organization Settings", "organization_settings": "Organization Settings",
"ingestion_settings": "Ingestion Settings", "ingestion_settings": "Ingestion Settings",
"api_keys": "Access Tokens",
"my_settings": "My Settings", "my_settings": "My Settings",
"overview_metrics": "Overview Metrics", "overview_metrics": "Overview Metrics",
"dbcall_metrics": "Database Calls", "dbcall_metrics": "Database Calls",

View File

@@ -54,7 +54,6 @@
"field_promql_expr": "PromQL Expression", "field_promql_expr": "PromQL Expression",
"field_alert_name": "Alert Name", "field_alert_name": "Alert Name",
"field_alert_desc": "Alert Description", "field_alert_desc": "Alert Description",
"field_notification_channel": "Notification Channel",
"field_labels": "Labels", "field_labels": "Labels",
"field_severity": "Severity", "field_severity": "Severity",
"option_critical": "Critical", "option_critical": "Critical",

View File

@@ -1,3 +0,0 @@
{
"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."
}

View File

@@ -26,7 +26,6 @@
"MY_SETTINGS": "SigNoz | My Settings", "MY_SETTINGS": "SigNoz | My Settings",
"ORG_SETTINGS": "SigNoz | Organization Settings", "ORG_SETTINGS": "SigNoz | Organization Settings",
"INGESTION_SETTINGS": "SigNoz | Ingestion Settings", "INGESTION_SETTINGS": "SigNoz | Ingestion Settings",
"API_KEYS": "SigNoz | Access Tokens",
"SOMETHING_WENT_WRONG": "SigNoz | Something Went Wrong", "SOMETHING_WENT_WRONG": "SigNoz | Something Went Wrong",
"UN_AUTHORIZED": "SigNoz | Unauthorized", "UN_AUTHORIZED": "SigNoz | Unauthorized",
"NOT_FOUND": "SigNoz | Page Not Found", "NOT_FOUND": "SigNoz | Page Not Found",

View File

@@ -37,16 +37,11 @@
"text_condition1": "Send a notification when", "text_condition1": "Send a notification when",
"text_condition2": "the threshold", "text_condition2": "the threshold",
"text_condition3": "during the last", "text_condition3": "during the last",
"option_1min": "1 min",
"option_5min": "5 mins", "option_5min": "5 mins",
"option_10min": "10 mins", "option_10min": "10 mins",
"option_15min": "15 mins", "option_15min": "15 mins",
"option_30min": "30 mins",
"option_60min": "60 mins", "option_60min": "60 mins",
"option_3hours": "3 hours",
"option_4hours": "4 hours", "option_4hours": "4 hours",
"option_6hours": "6 hours",
"option_12hours": "12 hours",
"option_24hours": "24 hours", "option_24hours": "24 hours",
"field_threshold": "Alert Threshold", "field_threshold": "Alert Threshold",
"option_allthetimes": "all the times", "option_allthetimes": "all the times",
@@ -68,7 +63,6 @@
"field_promql_expr": "PromQL Expression", "field_promql_expr": "PromQL Expression",
"field_alert_name": "Alert Name", "field_alert_name": "Alert Name",
"field_alert_desc": "Alert Description", "field_alert_desc": "Alert Description",
"field_notification_channel": "Notification Channel",
"field_labels": "Labels", "field_labels": "Labels",
"field_severity": "Severity", "field_severity": "Severity",
"option_critical": "Critical", "option_critical": "Critical",
@@ -106,7 +100,7 @@
"user_guide_ch_step3a": "Set alert severity, name and descriptions", "user_guide_ch_step3a": "Set alert severity, name and descriptions",
"user_guide_ch_step3b": "Add tags to the alert in the Label field if needed", "user_guide_ch_step3b": "Add tags to the alert in the Label field if needed",
"user_tooltip_more_help": "More details on how to create alerts", "user_tooltip_more_help": "More details on how to create alerts",
"choose_alert_type": "Choose a type for the alert", "choose_alert_type": "Choose a type for the alert:",
"metric_based_alert": "Metric based Alert", "metric_based_alert": "Metric based Alert",
"metric_based_alert_desc": "Send a notification when a condition occurs in the metric data", "metric_based_alert_desc": "Send a notification when a condition occurs in the metric data",
"log_based_alert": "Log-based Alert", "log_based_alert": "Log-based Alert",
@@ -116,8 +110,5 @@
"exceptions_based_alert": "Exceptions-based Alert", "exceptions_based_alert": "Exceptions-based Alert",
"exceptions_based_alert_desc": "Send a notification when a condition occurs in the exceptions data.", "exceptions_based_alert_desc": "Send a notification when a condition occurs in the exceptions data.",
"field_unit": "Threshold unit", "field_unit": "Threshold unit",
"text_alert_on_absent": "Send a notification if data is missing for",
"text_alert_frequency": "Run alert every",
"text_for": "minutes",
"selected_query_placeholder": "Select query" "selected_query_placeholder": "Select query"
} }

View File

@@ -1,3 +0,0 @@
{
"delete_confirm_message": "Are you sure you want to delete {{keyName}} token? Deleting a token is irreversible and cannot be undone."
}

View File

@@ -1,14 +0,0 @@
{
"days_remaining": "days remaining in your billing period.",
"billing": "Billing",
"manage_billing_and_costs": "Manage your billing information, invoices, and monitor costs.",
"enterprise_cloud": "Enterprise Cloud",
"enterprise": "Enterprise",
"card_details_recieved_and_billing_info": "We have received your card details, your billing will only start after the end of your free trial period.",
"upgrade_plan": "Upgrade Plan",
"manage_billing": "Manage Billing",
"upgrade_now_text": "Upgrade now to have uninterrupted access",
"billing_start_info": "Your billing will start only after the trial period",
"checkout_plans": "Check out features in paid plans",
"here": "here"
}

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