diff --git a/README.md b/README.md index f9c7d1e816..094415aadb 100644 --- a/README.md +++ b/README.md @@ -32,7 +32,6 @@ SigNoz helps developers monitor applications and troubleshoot problems in their 👉 Run aggregates on trace data to get business relevant metrics - ![screenzy-1644432902955](https://user-images.githubusercontent.com/504541/153270713-1b2156e6-ec03-42de-975b-3c02b8ec1836.png)
![screenzy-1644432986784](https://user-images.githubusercontent.com/504541/153270725-0efb73b3-06ed-4207-bf13-9b7e2e17c4b8.png) @@ -88,8 +87,7 @@ You can find the complete list of languages here - https://opentelemetry.io/docs ## Getting Started - - + ### Deploy using Docker Please follow the steps listed [here](https://signoz.io/docs/deployment/docker/) to install using docker @@ -102,7 +100,6 @@ The [troubleshooting instructions](https://signoz.io/docs/deployment/troubleshoo ### Deploy in Kubernetes using Helm Please follow the steps listed [here](https://signoz.io/docs/deployment/helm_chart) to install using helm charts -

@@ -112,7 +109,7 @@ Please follow the steps listed [here](https://signoz.io/docs/deployment/helm_cha ### SigNoz vs Prometheus -Prometheus is good if you want to do just metrics. But if you want to have a seamless experience between metrics and traces, then current experience of stitching together Prometheus & Jaeger is not great. +Prometheus is good if you want to do just metrics. But if you want to have a seamless experience between metrics and traces, then current experience of stitching together Prometheus & Jaeger is not great. Our goal is to provide an integrated UI between metrics & traces - similar to what SaaS vendors like Datadog provides - and give advanced filtering and aggregation over traces, something which Jaeger currently lack. @@ -133,11 +130,28 @@ Moreover, SigNoz has few more advanced features wrt Jaeger: ## Contributing - -We ❤️ contributions big or small. Please read [CONTRIBUTING.md](CONTRIBUTING.md) to get started with making contributions to SigNoz. +We ❤️ contributions big or small. Please read [CONTRIBUTING.md](CONTRIBUTING.md) to get started with making contributions to SigNoz. Not sure how to get started? Just ping us on `#contributing` in our [slack community](https://signoz.io/slack) +### Project maintainers + +#### Backend + +- [Ankit Nayan](https://github.com/ankitnayan) +- [Nityananda Gohain](https://github.com/nityanandagohain) +- [Srikanth Chekuri](https://github.com/srikanthccv) +- [Vishal Sharma](https://github.com/makeavish) + +#### Frontend + +- [Palash Gupta](https://github.com/palashgdev) +- [Pranshu Chittora](https://github.com/pranshuchittora) + +#### DevOps + +- [Prashant Shahi](https://github.com/prashant-shahi) +

@@ -156,11 +170,8 @@ Join the [slack community](https://signoz.io/slack) to know more about distribut If you have any ideas, questions, or any feedback, please share on our [Github Discussions](https://github.com/SigNoz/signoz/discussions) -As always, thanks to our amazing contributors! +As always, thanks to our amazing contributors! - - - diff --git a/deploy/docker-swarm/clickhouse-setup/docker-compose.yaml b/deploy/docker-swarm/clickhouse-setup/docker-compose.yaml index 7ee41ca768..2bd2a48bde 100644 --- a/deploy/docker-swarm/clickhouse-setup/docker-compose.yaml +++ b/deploy/docker-swarm/clickhouse-setup/docker-compose.yaml @@ -40,7 +40,7 @@ services: condition: on-failure query-service: - image: signoz/query-service:0.9.1 + image: signoz/query-service:0.9.2 command: ["-config=/root/config/prometheus.yml"] # ports: # - "6060:6060" # pprof port @@ -68,7 +68,7 @@ services: - clickhouse frontend: - image: signoz/frontend:0.9.1 + image: signoz/frontend:0.9.2 deploy: restart_policy: condition: on-failure diff --git a/deploy/docker/clickhouse-setup/docker-compose.yaml b/deploy/docker/clickhouse-setup/docker-compose.yaml index 102be2fe49..f8c2954446 100644 --- a/deploy/docker/clickhouse-setup/docker-compose.yaml +++ b/deploy/docker/clickhouse-setup/docker-compose.yaml @@ -39,7 +39,7 @@ services: # Notes for Maintainers/Contributors who will change Line Numbers of Frontend & Query-Section. Please Update Line Numbers in `./scripts/commentLinesForSetup.sh` & `./CONTRIBUTING.md` query-service: - image: signoz/query-service:0.9.1 + image: signoz/query-service:0.9.2 container_name: query-service command: ["-config=/root/config/prometheus.yml"] # ports: @@ -66,7 +66,7 @@ services: condition: service_healthy frontend: - image: signoz/frontend:0.9.1 + image: signoz/frontend:0.9.2 container_name: frontend restart: on-failure depends_on: diff --git a/frontend/commitlint.config.js b/frontend/commitlint.config.js deleted file mode 100644 index 422b19445b..0000000000 --- a/frontend/commitlint.config.js +++ /dev/null @@ -1 +0,0 @@ -module.exports = { extends: ['@commitlint/config-conventional'] }; diff --git a/frontend/commitlint.config.ts b/frontend/commitlint.config.ts new file mode 100644 index 0000000000..3f5e287f9e --- /dev/null +++ b/frontend/commitlint.config.ts @@ -0,0 +1 @@ +export default { extends: ['@commitlint/config-conventional'] }; diff --git a/frontend/src/api/index.ts b/frontend/src/api/index.ts index 82f4bdc010..b59a224cdc 100644 --- a/frontend/src/api/index.ts +++ b/frontend/src/api/index.ts @@ -102,6 +102,11 @@ export const AxiosAlertManagerInstance = axios.create({ export const ApiV2Instance = axios.create({ baseURL: `${ENVIRONMENT.baseURL}${apiV2}`, }); +ApiV2Instance.interceptors.response.use( + interceptorsResponse, + interceptorRejected, +); +ApiV2Instance.interceptors.request.use(interceptorsRequestResponse); AxiosAlertManagerInstance.interceptors.response.use( interceptorsResponse, diff --git a/frontend/src/container/ListOfDashboard/ImportJSON/index.tsx b/frontend/src/container/ListOfDashboard/ImportJSON/index.tsx index 021a5f9805..e1107fd9f2 100644 --- a/frontend/src/container/ListOfDashboard/ImportJSON/index.tsx +++ b/frontend/src/container/ListOfDashboard/ImportJSON/index.tsx @@ -15,7 +15,11 @@ import ROUTES from 'constants/routes'; import history from 'lib/history'; import React, { useState } from 'react'; import { useTranslation } from 'react-i18next'; +import { useDispatch } from 'react-redux'; import { generatePath } from 'react-router-dom'; +import { Dispatch } from 'redux'; +import AppActions from 'types/actions'; +import { FLUSH_DASHBOARD } from 'types/actions/dashboard'; import { DashboardData } from 'types/api/dashboard/getAll'; import { EditorContainer, FooterContainer } from './styles'; @@ -30,6 +34,8 @@ function ImportJSON({ const [isCreateDashboardError, setIsCreateDashboardError] = useState( false, ); + const dispatch = useDispatch>(); + const [dashboardCreating, setDashboardCreating] = useState(false); const [editorValue, setEditorValue] = useState(''); @@ -86,6 +92,9 @@ function ImportJSON({ }); if (response.statusCode === 200) { + dispatch({ + type: FLUSH_DASHBOARD, + }); setTimeout(() => { history.push( generatePath(ROUTES.DASHBOARD, { diff --git a/frontend/src/index.tsx b/frontend/src/index.tsx index 08c6668775..c65c4570ec 100644 --- a/frontend/src/index.tsx +++ b/frontend/src/index.tsx @@ -5,6 +5,7 @@ import AppRoutes from 'AppRoutes'; import React from 'react'; import ReactDOM from 'react-dom'; import { QueryClient, QueryClientProvider } from 'react-query'; +import { ReactQueryDevtools } from 'react-query/devtools'; import { Provider } from 'react-redux'; import reportWebVitals from 'reportWebVitals'; import store from 'store'; @@ -28,6 +29,9 @@ ReactDOM.render( + {process.env.NODE_ENV === 'development' && ( + + )} , document.querySelector('#root'), ); diff --git a/frontend/src/store/actions/dashboard/getQueryResults.ts b/frontend/src/store/actions/dashboard/getQueryResults.ts index f1143a1431..17137b13c1 100644 --- a/frontend/src/store/actions/dashboard/getQueryResults.ts +++ b/frontend/src/store/actions/dashboard/getQueryResults.ts @@ -143,17 +143,23 @@ export async function GetMetricQueryRange({ `API responded with ${response.statusCode} - ${response.error}`, ); } - if (response.payload?.data?.result) { response.payload.data.result = response.payload.data.result.map( (queryData) => { const newQueryData = queryData; - newQueryData.legend = legendMap[queryData.queryName]; + newQueryData.legend = legendMap[queryData.queryName]; // Adds the legend if it is already defined by the user. + // If metric names is an empty object if (isEmpty(queryData.metric)) { - newQueryData.metric[queryData.queryName] = queryData.queryName; - newQueryData.legend = queryData.queryName; + // If metrics list is empty && the user haven't defined a legend then add the legend equal to the name of the query. + if (!newQueryData.legend) { + newQueryData.legend = queryData.queryName; + } + // If name of the query and the legend if inserted is same then add the same to the metrics object. + if (queryData.queryName === newQueryData.legend) { + newQueryData.metric[queryData.queryName] = queryData.queryName; + } } - return queryData; + return newQueryData; }, ); } diff --git a/frontend/tsconfig.json b/frontend/tsconfig.json index a10bce6e81..ca86de66b0 100644 --- a/frontend/tsconfig.json +++ b/frontend/tsconfig.json @@ -32,8 +32,8 @@ "./conf/default.conf", "./public", "./tests", - "playwright.config.ts", - "./commitlint.config.js", + "./playwright.config.ts", + "./commitlint.config.ts", "./webpack.config.js", "./webpack.config.prod.js", "./jest.setup.ts" diff --git a/pkg/query-service/app/clickhouseReader/reader.go b/pkg/query-service/app/clickhouseReader/reader.go index 17f3e5b047..8a6e2e6d36 100644 --- a/pkg/query-service/app/clickhouseReader/reader.go +++ b/pkg/query-service/app/clickhouseReader/reader.go @@ -2906,3 +2906,77 @@ func (r *ClickHouseReader) GetMetricResult(ctx context.Context, query string) ([ } return seriesList, nil } + +func (r *ClickHouseReader) GetTotalSpans(ctx context.Context) (uint64, error) { + + var totalSpans uint64 + + queryStr := fmt.Sprintf("SELECT count() from %s.%s;", signozTraceDBName, signozTraceTableName) + r.db.QueryRow(ctx, queryStr).Scan(&totalSpans) + + return totalSpans, nil +} + +func (r *ClickHouseReader) GetSpansInLastHeartBeatInterval(ctx context.Context) (uint64, error) { + + var spansInLastHeartBeatInterval uint64 + + queryStr := fmt.Sprintf("SELECT count() from %s.%s where timestamp > toUnixTimestamp(now()-toIntervalMinute(%d));", signozTraceDBName, signozSpansTable, 30) + + r.db.QueryRow(ctx, queryStr).Scan(&spansInLastHeartBeatInterval) + + return spansInLastHeartBeatInterval, nil +} + +// func sum(array []tsByMetricName) uint64 { +// var result uint64 +// result = 0 +// for _, v := range array { +// result += v.count +// } +// return result +// } + +func (r *ClickHouseReader) GetTimeSeriesInfo(ctx context.Context) (map[string]interface{}, error) { + + queryStr := fmt.Sprintf("SELECT count() as count from %s.%s group by metric_name order by count desc;", signozMetricDBName, signozTSTableName) + + // r.db.Select(ctx, &tsByMetricName, queryStr) + + rows, _ := r.db.Query(ctx, queryStr) + + var totalTS uint64 + totalTS = 0 + + var maxTS uint64 + maxTS = 0 + + count := 0 + for rows.Next() { + + var value uint64 + rows.Scan(&value) + totalTS += value + if count == 0 { + maxTS = value + } + count += 1 + } + + timeSeriesData := map[string]interface{}{} + timeSeriesData["totalTS"] = totalTS + timeSeriesData["maxTS"] = maxTS + + return timeSeriesData, nil +} + +func (r *ClickHouseReader) GetSamplesInfoInLastHeartBeatInterval(ctx context.Context) (uint64, error) { + + var totalSamples uint64 + + queryStr := fmt.Sprintf("select count() from %s.%s where timestamp_ms > toUnixTimestamp(now()-toIntervalMinute(%d))*1000;", signozMetricDBName, signozSampleTableName, 30) + + r.db.QueryRow(ctx, queryStr).Scan(&totalSamples) + + return totalSamples, nil +} diff --git a/pkg/query-service/app/http_handler.go b/pkg/query-service/app/http_handler.go index 400c9f2de4..51ff99a8a9 100644 --- a/pkg/query-service/app/http_handler.go +++ b/pkg/query-service/app/http_handler.go @@ -22,6 +22,7 @@ import ( "go.signoz.io/query-service/constants" "go.signoz.io/query-service/dao" am "go.signoz.io/query-service/integrations/alertManager" + "go.signoz.io/query-service/interfaces" "go.signoz.io/query-service/model" "go.signoz.io/query-service/telemetry" "go.signoz.io/query-service/version" @@ -46,14 +47,14 @@ type APIHandler struct { // queryParser queryParser basePath string apiPrefix string - reader *Reader + reader *interfaces.Reader relationalDB dao.ModelDao alertManager am.Manager ready func(http.HandlerFunc) http.HandlerFunc } // NewAPIHandler returns an APIHandler -func NewAPIHandler(reader *Reader, relationalDB dao.ModelDao) (*APIHandler, error) { +func NewAPIHandler(reader *interfaces.Reader, relationalDB dao.ModelDao) (*APIHandler, error) { alertManager := am.New("") aH := &APIHandler{ diff --git a/pkg/query-service/app/server.go b/pkg/query-service/app/server.go index 7904e813e2..5bccea66e2 100644 --- a/pkg/query-service/app/server.go +++ b/pkg/query-service/app/server.go @@ -19,6 +19,7 @@ import ( "go.signoz.io/query-service/constants" "go.signoz.io/query-service/dao" "go.signoz.io/query-service/healthcheck" + "go.signoz.io/query-service/interfaces" "go.signoz.io/query-service/telemetry" "go.signoz.io/query-service/utils" "go.uber.org/zap" @@ -65,7 +66,7 @@ func NewServer(serverOptions *ServerOptions) (*Server, error) { localDB.SetMaxOpenConns(10) - var reader Reader + var reader interfaces.Reader storage := os.Getenv("STORAGE") if storage == "clickhouse" { zap.S().Info("Using ClickHouse as datastore ...") @@ -76,6 +77,8 @@ func NewServer(serverOptions *ServerOptions) (*Server, error) { return nil, fmt.Errorf("Storage type: %s is not supported in query service", storage) } + telemetry.GetInstance().SetReader(reader) + apiHandler, err := NewAPIHandler(&reader, dao.DB()) if err != nil { return nil, err diff --git a/pkg/query-service/go.mod b/pkg/query-service/go.mod index 2effc47563..1d5dfa8e8d 100644 --- a/pkg/query-service/go.mod +++ b/pkg/query-service/go.mod @@ -140,4 +140,4 @@ require ( k8s.io/client-go v8.0.0+incompatible // indirect ) -replace github.com/prometheus/prometheus => github.com/SigNoz/prometheus v1.9.72 +replace github.com/prometheus/prometheus => github.com/SigNoz/prometheus v1.9.73 diff --git a/pkg/query-service/go.sum b/pkg/query-service/go.sum index 17a4a6e144..d69fb82481 100644 --- a/pkg/query-service/go.sum +++ b/pkg/query-service/go.sum @@ -57,8 +57,8 @@ github.com/OneOfOne/xxhash v1.2.8 h1:31czK/TI9sNkxIKfaUfGlU47BAxQ0ztGgd9vPyqimf8 github.com/OneOfOne/xxhash v1.2.8/go.mod h1:eZbhyaAYD41SGSSsnmcpxVoRiQ/MPUTjUdIIOT9Um7Q= github.com/SigNoz/govaluate v0.0.0-20220522085550-d19c08c206cb h1:bneLSKPf9YUSFmafKx32bynV6QrzViL/s+ZDvQxH1E4= github.com/SigNoz/govaluate v0.0.0-20220522085550-d19c08c206cb/go.mod h1:JznGDNg9x1cujDKa22RaQOimOvvEfy3nxzDGd8XDgmA= -github.com/SigNoz/prometheus v1.9.72 h1:0p4ZN/NUb5jChB3blqpKKmANCAMWLp7N5L9YyyV7SQs= -github.com/SigNoz/prometheus v1.9.72/go.mod h1:Y4J9tGDmacMC+EcOTp+EIAn2C1sN+9kE+idyVKadiVM= +github.com/SigNoz/prometheus v1.9.73 h1:f6PjQrJGoCot9iJp/tWoKwgy0HTIqicYave4K3fT9ro= +github.com/SigNoz/prometheus v1.9.73/go.mod h1:Y4J9tGDmacMC+EcOTp+EIAn2C1sN+9kE+idyVKadiVM= github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= diff --git a/pkg/query-service/app/interface.go b/pkg/query-service/interfaces/interface.go similarity index 92% rename from pkg/query-service/app/interface.go rename to pkg/query-service/interfaces/interface.go index fadbcd1e79..9c52a4497d 100644 --- a/pkg/query-service/app/interface.go +++ b/pkg/query-service/interfaces/interface.go @@ -1,4 +1,4 @@ -package app +package interfaces import ( "context" @@ -54,4 +54,9 @@ type Reader interface { GetMetricAutocompleteTagKey(ctx context.Context, params *model.MetricAutocompleteTagParams) (*[]string, *model.ApiError) GetMetricAutocompleteTagValue(ctx context.Context, params *model.MetricAutocompleteTagParams) (*[]string, *model.ApiError) GetMetricResult(ctx context.Context, query string) ([]*model.Series, error) + + GetTotalSpans(ctx context.Context) (uint64, error) + GetSpansInLastHeartBeatInterval(ctx context.Context) (uint64, error) + GetTimeSeriesInfo(ctx context.Context) (map[string]interface{}, error) + GetSamplesInfoInLastHeartBeatInterval(ctx context.Context) (uint64, error) } diff --git a/pkg/query-service/telemetry/ignoredPaths.go b/pkg/query-service/telemetry/ignoredPaths.go index 00ceb1c79a..e564cce2a2 100644 --- a/pkg/query-service/telemetry/ignoredPaths.go +++ b/pkg/query-service/telemetry/ignoredPaths.go @@ -2,8 +2,11 @@ package telemetry func IgnoredPaths() map[string]struct{} { ignoredPaths := map[string]struct{}{ - "/api/v1/tags": {}, - "/api/v1/version": {}, + "/api/v1/tags": {}, + "/api/v1/version": {}, + "/api/v1/query_range": {}, + "/api/v2/metrics/query_range": {}, + "/api/v1/services/list": {}, } return ignoredPaths diff --git a/pkg/query-service/telemetry/telemetry.go b/pkg/query-service/telemetry/telemetry.go index 1f5360fa40..ca402e4da8 100644 --- a/pkg/query-service/telemetry/telemetry.go +++ b/pkg/query-service/telemetry/telemetry.go @@ -1,6 +1,7 @@ package telemetry import ( + "context" "io/ioutil" "net/http" "os" @@ -8,6 +9,7 @@ import ( "time" "go.signoz.io/query-service/constants" + "go.signoz.io/query-service/interfaces" "go.signoz.io/query-service/model" "go.signoz.io/query-service/version" "gopkg.in/segmentio/analytics-go.v3" @@ -25,6 +27,10 @@ const ( const api_key = "4Gmoa4ixJAUHx2BpJxsjwA1bEfnwEeRz" const IP_NOT_FOUND_PLACEHOLDER = "NA" +const HEART_BEAT_DURATION = 6 * time.Hour + +// const HEART_BEAT_DURATION = 10 * time.Second + var telemetry *Telemetry var once sync.Once @@ -34,6 +40,7 @@ type Telemetry struct { isEnabled bool isAnonymous bool distinctId string + reader interfaces.Reader } func createTelemetry() { @@ -46,11 +53,24 @@ func createTelemetry() { telemetry.SetTelemetryEnabled(constants.IsTelemetryEnabled()) telemetry.SendEvent(TELEMETRY_EVENT_HEART_BEAT, data) - ticker := time.NewTicker(6 * time.Hour) + ticker := time.NewTicker(HEART_BEAT_DURATION) go func() { for { select { case <-ticker.C: + totalSpans, _ := telemetry.reader.GetTotalSpans(context.Background()) + spansInLastHeartBeatInterval, _ := telemetry.reader.GetSpansInLastHeartBeatInterval(context.Background()) + getSamplesInfoInLastHeartBeatInterval, _ := telemetry.reader.GetSamplesInfoInLastHeartBeatInterval(context.Background()) + tsInfo, _ := telemetry.reader.GetTimeSeriesInfo(context.Background()) + + data := map[string]interface{}{ + "totalSpans": totalSpans, + "spansInLastHeartBeatInterval": spansInLastHeartBeatInterval, + "getSamplesInfoInLastHeartBeatInterval": getSamplesInfoInLastHeartBeatInterval, + } + for key, value := range tsInfo { + data[key] = value + } telemetry.SendEvent(TELEMETRY_EVENT_HEART_BEAT, data) } } @@ -153,6 +173,10 @@ func (a *Telemetry) SetTelemetryEnabled(value bool) { a.isEnabled = value } +func (a *Telemetry) SetReader(reader interfaces.Reader) { + a.reader = reader +} + func GetInstance() *Telemetry { once.Do(func() {