mirror of
https://git.mirrors.martin98.com/https://github.com/SigNoz/signoz
synced 2025-08-12 01:59:04 +08:00
commit
80171eddea
6
.github/workflows/staging-deployment.yaml
vendored
6
.github/workflows/staging-deployment.yaml
vendored
@ -11,21 +11,23 @@ jobs:
|
||||
environment: staging
|
||||
steps:
|
||||
- name: Executing remote ssh commands using ssh key
|
||||
uses: appleboy/ssh-action@v0.1.6
|
||||
uses: appleboy/ssh-action@v0.1.8
|
||||
env:
|
||||
GITHUB_BRANCH: develop
|
||||
GITHUB_SHA: ${{ github.sha }}
|
||||
with:
|
||||
host: ${{ secrets.HOST_DNS }}
|
||||
username: ${{ secrets.USERNAME }}
|
||||
key: ${{ secrets.EC2_SSH_KEY }}
|
||||
key: ${{ secrets.SSH_KEY }}
|
||||
envs: GITHUB_BRANCH,GITHUB_SHA
|
||||
command_timeout: 60m
|
||||
script: |
|
||||
echo "GITHUB_BRANCH: ${GITHUB_BRANCH}"
|
||||
echo "GITHUB_SHA: ${GITHUB_SHA}"
|
||||
export DOCKER_TAG="${GITHUB_SHA:0:7}" # needed for child process to access it
|
||||
export OTELCOL_TAG="main"
|
||||
docker system prune --force
|
||||
docker pull signoz/signoz-otel-collector:main
|
||||
cd ~/signoz
|
||||
git status
|
||||
git add .
|
||||
|
4
.github/workflows/testing-deployment.yaml
vendored
4
.github/workflows/testing-deployment.yaml
vendored
@ -11,14 +11,14 @@ jobs:
|
||||
if: ${{ github.event.label.name == 'testing-deploy' }}
|
||||
steps:
|
||||
- name: Executing remote ssh commands using ssh key
|
||||
uses: appleboy/ssh-action@v0.1.6
|
||||
uses: appleboy/ssh-action@v0.1.8
|
||||
env:
|
||||
GITHUB_BRANCH: ${{ github.head_ref || github.ref_name }}
|
||||
GITHUB_SHA: ${{ github.sha }}
|
||||
with:
|
||||
host: ${{ secrets.HOST_DNS }}
|
||||
username: ${{ secrets.USERNAME }}
|
||||
key: ${{ secrets.EC2_SSH_KEY }}
|
||||
key: ${{ secrets.SSH_KEY }}
|
||||
envs: GITHUB_BRANCH,GITHUB_SHA
|
||||
command_timeout: 60m
|
||||
script: |
|
||||
|
41
README.md
41
README.md
@ -35,14 +35,37 @@ SigNoz helps developers monitor applications and troubleshoot problems in their
|
||||
|
||||
👉 Filter and query logs, build dashboards and alerts based on attributes in logs
|
||||
|
||||

|
||||
<br />
|
||||

|
||||
<br />
|
||||

|
||||
<br />
|
||||

|
||||
👉 Record exceptions automatically in Python, Java, Ruby, and Javascript
|
||||
|
||||
👉 Easy to set alerts with DIY query builder
|
||||
|
||||
|
||||
### Application Metrics
|
||||
|
||||

|
||||
|
||||
|
||||
### Distributed Tracing
|
||||
<img width="2068" alt="distributed_tracing_2 2" src="https://user-images.githubusercontent.com/83692067/226536447-bae58321-6a22-4ed3-af80-e3e964cb3489.png">
|
||||
|
||||
<img width="2068" alt="distributed_tracing_1" src="https://user-images.githubusercontent.com/83692067/226536462-939745b6-4f9d-45a6-8016-814837e7f7b4.png">
|
||||
|
||||
### Logs Management
|
||||
|
||||
<img width="2068" alt="logs_management" src="https://user-images.githubusercontent.com/83692067/226536482-b8a5c4af-b69c-43d5-969c-338bd5eaf1a5.png">
|
||||
|
||||
### Infrastructure Monitoring
|
||||
|
||||
<img width="2068" alt="infrastructure_monitoring" src="https://user-images.githubusercontent.com/83692067/226536496-f38c4dbf-e03c-4158-8be0-32d4a61158c7.png">
|
||||
|
||||
### Exceptions Monitoring
|
||||
|
||||

|
||||
|
||||
|
||||
### Alerts
|
||||
|
||||
<img width="2068" alt="alerts_management" src="https://user-images.githubusercontent.com/83692067/226536548-2c81e2e8-c12d-47e8-bad7-c6be79055def.png">
|
||||
|
||||
|
||||
<br /><br />
|
||||
@ -65,6 +88,10 @@ Come say Hi to us on [Slack](https://signoz.io/slack) 👋
|
||||
- See exact request trace to figure out issues in downstream services, slow DB queries, call to 3rd party services like payment gateways, etc
|
||||
- Filter traces by service name, operation, latency, error, tags/annotations.
|
||||
- Run aggregates on trace data (events/spans) to get business relevant metrics. e.g. You can get error rate and 99th percentile latency of `customer_type: gold` or `deployment_version: v2` or `external_call: paypal`
|
||||
- Native support for OpenTelemetry Logs, advanced log query builder, and automatic log collection from k8s cluster
|
||||
- Lightening quick log analytics ([Logs Perf. Benchmark](https://signoz.io/blog/logs-performance-benchmark/))
|
||||
- End-to-End visibility into infrastructure performance, ingest metrics from all kinds of host environments
|
||||
- Easy to set alerts with DIY query builder
|
||||
|
||||
<br /><br />
|
||||
|
||||
|
@ -137,7 +137,7 @@ services:
|
||||
condition: on-failure
|
||||
|
||||
query-service:
|
||||
image: signoz/query-service:0.17.0
|
||||
image: signoz/query-service:0.18.0
|
||||
command: ["-config=/root/config/prometheus.yml"]
|
||||
# ports:
|
||||
# - "6060:6060" # pprof port
|
||||
@ -166,7 +166,7 @@ services:
|
||||
<<: *clickhouse-depend
|
||||
|
||||
frontend:
|
||||
image: signoz/frontend:0.17.0
|
||||
image: signoz/frontend:0.18.0
|
||||
deploy:
|
||||
restart_policy:
|
||||
condition: on-failure
|
||||
@ -179,7 +179,7 @@ services:
|
||||
- ../common/nginx-config.conf:/etc/nginx/conf.d/default.conf
|
||||
|
||||
otel-collector:
|
||||
image: signoz/signoz-otel-collector:0.66.6
|
||||
image: signoz/signoz-otel-collector:0.66.7
|
||||
command: ["--config=/etc/otel-collector-config.yaml"]
|
||||
user: root # required for reading docker container logs
|
||||
volumes:
|
||||
@ -208,7 +208,7 @@ services:
|
||||
<<: *clickhouse-depend
|
||||
|
||||
otel-collector-metrics:
|
||||
image: signoz/signoz-otel-collector:0.66.6
|
||||
image: signoz/signoz-otel-collector:0.66.7
|
||||
command: ["--config=/etc/otel-collector-metrics-config.yaml"]
|
||||
volumes:
|
||||
- ./otel-collector-metrics-config.yaml:/etc/otel-collector-metrics-config.yaml
|
||||
|
@ -41,7 +41,7 @@ services:
|
||||
# Notes for Maintainers/Contributors who will change Line Numbers of Frontend & Query-Section. Please Update Line Numbers in `./scripts/commentLinesForSetup.sh` & `./CONTRIBUTING.md`
|
||||
otel-collector:
|
||||
container_name: otel-collector
|
||||
image: signoz/signoz-otel-collector:0.66.6
|
||||
image: signoz/signoz-otel-collector:0.66.7
|
||||
command: ["--config=/etc/otel-collector-config.yaml"]
|
||||
# user: root # required for reading docker container logs
|
||||
volumes:
|
||||
@ -67,7 +67,7 @@ services:
|
||||
|
||||
otel-collector-metrics:
|
||||
container_name: otel-collector-metrics
|
||||
image: signoz/signoz-otel-collector:0.66.6
|
||||
image: signoz/signoz-otel-collector:0.66.7
|
||||
command: ["--config=/etc/otel-collector-metrics-config.yaml"]
|
||||
volumes:
|
||||
- ./otel-collector-metrics-config.yaml:/etc/otel-collector-metrics-config.yaml
|
||||
|
@ -153,7 +153,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:${DOCKER_TAG:-0.17.0}
|
||||
image: signoz/query-service:${DOCKER_TAG:-0.18.0}
|
||||
container_name: query-service
|
||||
command: ["-config=/root/config/prometheus.yml"]
|
||||
# ports:
|
||||
@ -181,7 +181,7 @@ services:
|
||||
<<: *clickhouse-depend
|
||||
|
||||
frontend:
|
||||
image: signoz/frontend:${DOCKER_TAG:-0.17.0}
|
||||
image: signoz/frontend:${DOCKER_TAG:-0.18.0}
|
||||
container_name: frontend
|
||||
restart: on-failure
|
||||
depends_on:
|
||||
@ -193,7 +193,7 @@ services:
|
||||
- ../common/nginx-config.conf:/etc/nginx/conf.d/default.conf
|
||||
|
||||
otel-collector:
|
||||
image: signoz/signoz-otel-collector:${OTELCOL_TAG:-0.66.6}
|
||||
image: signoz/signoz-otel-collector:${OTELCOL_TAG:-0.66.7}
|
||||
command: ["--config=/etc/otel-collector-config.yaml"]
|
||||
user: root # required for reading docker container logs
|
||||
volumes:
|
||||
@ -219,7 +219,7 @@ services:
|
||||
<<: *clickhouse-depend
|
||||
|
||||
otel-collector-metrics:
|
||||
image: signoz/signoz-otel-collector:${OTELCOL_TAG:-0.66.6}
|
||||
image: signoz/signoz-otel-collector:${OTELCOL_TAG:-0.66.7}
|
||||
command: ["--config=/etc/otel-collector-metrics-config.yaml"]
|
||||
volumes:
|
||||
- ./otel-collector-metrics-config.yaml:/etc/otel-collector-metrics-config.yaml
|
||||
|
@ -25,16 +25,18 @@ import (
|
||||
licensepkg "go.signoz.io/signoz/ee/query-service/license"
|
||||
"go.signoz.io/signoz/ee/query-service/usage"
|
||||
|
||||
"go.signoz.io/signoz/pkg/query-service/agentConf"
|
||||
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/explorer"
|
||||
baseexplorer "go.signoz.io/signoz/pkg/query-service/app/explorer"
|
||||
"go.signoz.io/signoz/pkg/query-service/app/opamp"
|
||||
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/constants"
|
||||
baseconst "go.signoz.io/signoz/pkg/query-service/constants"
|
||||
"go.signoz.io/signoz/pkg/query-service/healthcheck"
|
||||
basealm "go.signoz.io/signoz/pkg/query-service/integrations/alertManager"
|
||||
baseint "go.signoz.io/signoz/pkg/query-service/interfaces"
|
||||
"go.signoz.io/signoz/pkg/query-service/model"
|
||||
basemodel "go.signoz.io/signoz/pkg/query-service/model"
|
||||
pqle "go.signoz.io/signoz/pkg/query-service/pqlEngine"
|
||||
rules "go.signoz.io/signoz/pkg/query-service/rules"
|
||||
"go.signoz.io/signoz/pkg/query-service/telemetry"
|
||||
@ -42,6 +44,8 @@ import (
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
const AppDbEngine = "sqlite"
|
||||
|
||||
type ServerOptions struct {
|
||||
PromConfigPath string
|
||||
HTTPHostPort string
|
||||
@ -85,8 +89,9 @@ func NewServer(serverOptions *ServerOptions) (*Server, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
baseexplorer.InitWithDSN(baseconst.RELATIONAL_DATASOURCE_PATH)
|
||||
|
||||
localDB, err := dashboards.InitDB(baseconst.RELATIONAL_DATASOURCE_PATH)
|
||||
explorer.InitWithDSN(constants.RELATIONAL_DATASOURCE_PATH)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -127,6 +132,17 @@ func NewServer(serverOptions *ServerOptions) (*Server, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// initiate opamp
|
||||
_, err = opAmpModel.InitDB(baseconst.RELATIONAL_DATASOURCE_PATH)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// initiate agent config handler
|
||||
if err := agentConf.Initiate(localDB, AppDbEngine); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// start the usagemanager
|
||||
usageManager, err := usage.New("sqlite", localDB, lm.GetRepo(), reader.GetConn())
|
||||
if err != nil {
|
||||
@ -208,7 +224,7 @@ func (s *Server) createPublicServer(apiHandler *api.APIHandler) (*http.Server, e
|
||||
|
||||
r := mux.NewRouter()
|
||||
|
||||
getUserFromRequest := func(r *http.Request) (*model.UserPayload, error) {
|
||||
getUserFromRequest := func(r *http.Request) (*basemodel.UserPayload, error) {
|
||||
patToken := r.Header.Get("SIGNOZ-API-KEY")
|
||||
if len(patToken) > 0 {
|
||||
zap.S().Debugf("Received a non-zero length PAT token")
|
||||
@ -299,7 +315,7 @@ func extractDashboardMetaData(path string, r *http.Request) (map[string]interfac
|
||||
pathToExtractBodyFrom := "/api/v2/metrics/query_range"
|
||||
|
||||
data := map[string]interface{}{}
|
||||
var postData *model.QueryRangeParamsV2
|
||||
var postData *basemodel.QueryRangeParamsV2
|
||||
|
||||
if path == pathToExtractBodyFrom && (r.Method == "POST") {
|
||||
if r.Body != nil {
|
||||
@ -472,7 +488,7 @@ func (s *Server) Start() error {
|
||||
if port, err := utils.GetPort(s.privateConn.Addr()); err == nil {
|
||||
privatePort = port
|
||||
}
|
||||
fmt.Println("starting private http")
|
||||
|
||||
go func() {
|
||||
zap.S().Info("Starting Private HTTP server", zap.Int("port", privatePort), zap.String("addr", s.serverOptions.PrivateHostPort))
|
||||
|
||||
@ -488,6 +504,37 @@ func (s *Server) Start() error {
|
||||
|
||||
}()
|
||||
|
||||
go func() {
|
||||
zap.S().Info("Starting OpAmp Websocket server", zap.String("addr", baseconst.OpAmpWsEndpoint))
|
||||
err := opamp.InitalizeServer(baseconst.OpAmpWsEndpoint, &opAmpModel.AllAgents)
|
||||
if err != nil {
|
||||
zap.S().Info("opamp ws server failed to start", err)
|
||||
s.unavailableChannel <- healthcheck.Unavailable
|
||||
}
|
||||
}()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Server) Stop() error {
|
||||
if s.httpServer != nil {
|
||||
if err := s.httpServer.Shutdown(context.Background()); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if s.privateHTTP != nil {
|
||||
if err := s.privateHTTP.Shutdown(context.Background()); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
opamp.StopServer()
|
||||
|
||||
if s.ruleManager != nil {
|
||||
s.ruleManager.Stop()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -4,7 +4,9 @@ import Spinner from 'components/Spinner';
|
||||
import AppLayout from 'container/AppLayout';
|
||||
import { useThemeConfig } from 'hooks/useDarkMode';
|
||||
import { NotificationProvider } from 'hooks/useNotifications';
|
||||
import { ResourceProvider } from 'hooks/useResourceAttribute';
|
||||
import history from 'lib/history';
|
||||
import { QueryBuilderProvider } from 'providers/QueryBuilder';
|
||||
import React, { Suspense } from 'react';
|
||||
import { Route, Router, Switch } from 'react-router-dom';
|
||||
|
||||
@ -16,28 +18,32 @@ function App(): JSX.Element {
|
||||
|
||||
return (
|
||||
<ConfigProvider theme={themeConfig}>
|
||||
<NotificationProvider>
|
||||
<Router history={history}>
|
||||
<Router history={history}>
|
||||
<NotificationProvider>
|
||||
<PrivateRoute>
|
||||
<AppLayout>
|
||||
<Suspense fallback={<Spinner size="large" tip="Loading..." />}>
|
||||
<Switch>
|
||||
{routes.map(({ path, component, exact }) => (
|
||||
<Route
|
||||
key={`${path}`}
|
||||
exact={exact}
|
||||
path={path}
|
||||
component={component}
|
||||
/>
|
||||
))}
|
||||
<ResourceProvider>
|
||||
<QueryBuilderProvider>
|
||||
<AppLayout>
|
||||
<Suspense fallback={<Spinner size="large" tip="Loading..." />}>
|
||||
<Switch>
|
||||
{routes.map(({ path, component, exact }) => (
|
||||
<Route
|
||||
key={`${path}`}
|
||||
exact={exact}
|
||||
path={path}
|
||||
component={component}
|
||||
/>
|
||||
))}
|
||||
|
||||
<Route path="*" component={NotFound} />
|
||||
</Switch>
|
||||
</Suspense>
|
||||
</AppLayout>
|
||||
<Route path="*" component={NotFound} />
|
||||
</Switch>
|
||||
</Suspense>
|
||||
</AppLayout>
|
||||
</QueryBuilderProvider>
|
||||
</ResourceProvider>
|
||||
</PrivateRoute>
|
||||
</Router>
|
||||
</NotificationProvider>
|
||||
</NotificationProvider>
|
||||
</Router>
|
||||
</ConfigProvider>
|
||||
);
|
||||
}
|
||||
|
@ -1,7 +1,6 @@
|
||||
import axios from 'api';
|
||||
import { ErrorResponseHandler } from 'api/ErrorResponseHandler';
|
||||
import { AxiosError } from 'axios';
|
||||
import createQueryParams from 'lib/createQueryParams';
|
||||
import { ErrorResponse, SuccessResponse } from 'types/api';
|
||||
import { PayloadProps, Props } from 'types/api/errors/getAll';
|
||||
|
||||
@ -9,11 +8,17 @@ const getAll = async (
|
||||
props: Props,
|
||||
): Promise<SuccessResponse<PayloadProps> | ErrorResponse> => {
|
||||
try {
|
||||
const response = await axios.get(
|
||||
`/listErrors?${createQueryParams({
|
||||
...props,
|
||||
})}`,
|
||||
);
|
||||
const response = await axios.post(`/listErrors`, {
|
||||
start: `${props.start}`,
|
||||
end: `${props.end}`,
|
||||
order: props.order,
|
||||
orderParam: props.orderParam,
|
||||
limit: props.limit,
|
||||
offset: props.offset,
|
||||
exceptionType: props.exceptionType,
|
||||
serviceName: props.serviceName,
|
||||
tags: props.tags,
|
||||
});
|
||||
|
||||
return {
|
||||
statusCode: 200,
|
||||
|
@ -1,7 +1,6 @@
|
||||
import axios from 'api';
|
||||
import { ErrorResponseHandler } from 'api/ErrorResponseHandler';
|
||||
import { AxiosError } from 'axios';
|
||||
import createQueryParams from 'lib/createQueryParams';
|
||||
import { ErrorResponse, SuccessResponse } from 'types/api';
|
||||
import { PayloadProps, Props } from 'types/api/errors/getErrorCounts';
|
||||
|
||||
@ -9,11 +8,13 @@ const getErrorCounts = async (
|
||||
props: Props,
|
||||
): Promise<SuccessResponse<PayloadProps> | ErrorResponse> => {
|
||||
try {
|
||||
const response = await axios.get(
|
||||
`/countErrors?${createQueryParams({
|
||||
...props,
|
||||
})}`,
|
||||
);
|
||||
const response = await axios.post(`/countErrors`, {
|
||||
start: `${props.start}`,
|
||||
end: `${props.end}`,
|
||||
exceptionType: props.exceptionType,
|
||||
serviceName: props.serviceName,
|
||||
tags: props.tags,
|
||||
});
|
||||
|
||||
return {
|
||||
statusCode: 200,
|
||||
|
@ -10,7 +10,7 @@ const getSpans = async (
|
||||
): Promise<SuccessResponse<PayloadProps> | ErrorResponse> => {
|
||||
try {
|
||||
const updatedSelectedTags = props.selectedTags.map((e) => ({
|
||||
Key: e.Key,
|
||||
Key: `${e.Key}.(string)`,
|
||||
Operator: e.Operator,
|
||||
StringValues: e.StringValues,
|
||||
NumberValues: e.NumberValues,
|
||||
|
@ -28,7 +28,7 @@ const getSpanAggregate = async (
|
||||
});
|
||||
|
||||
const updatedSelectedTags = props.selectedTags.map((e) => ({
|
||||
Key: e.Key,
|
||||
Key: `${e.Key}.(string)`,
|
||||
Operator: e.Operator,
|
||||
StringValues: e.StringValues,
|
||||
NumberValues: e.NumberValues,
|
||||
|
@ -1,6 +1,6 @@
|
||||
import MEditor, { EditorProps } from '@monaco-editor/react';
|
||||
import { useIsDarkMode } from 'hooks/useDarkMode';
|
||||
import React from 'react';
|
||||
import React, { useMemo } from 'react';
|
||||
|
||||
function Editor({
|
||||
value,
|
||||
@ -11,16 +11,24 @@ function Editor({
|
||||
options,
|
||||
}: MEditorProps): JSX.Element {
|
||||
const isDarkMode = useIsDarkMode();
|
||||
|
||||
const onChangeHandler = (newValue?: string): void => {
|
||||
if (typeof newValue === 'string' && onChange) onChange(newValue);
|
||||
};
|
||||
|
||||
const editorOptions = useMemo(
|
||||
() => ({ fontSize: 16, automaticLayout: true, readOnly, ...options }),
|
||||
[options, readOnly],
|
||||
);
|
||||
|
||||
return (
|
||||
<MEditor
|
||||
theme={isDarkMode ? 'vs-dark' : 'vs-light'}
|
||||
language={language}
|
||||
value={value}
|
||||
options={{ fontSize: 16, automaticLayout: true, readOnly, ...options }}
|
||||
options={editorOptions}
|
||||
height={height}
|
||||
onChange={(newValue): void => {
|
||||
if (typeof newValue === 'string') onChange(newValue);
|
||||
}}
|
||||
onChange={onChangeHandler}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@ -28,7 +36,7 @@ function Editor({
|
||||
interface MEditorProps {
|
||||
value: string;
|
||||
language?: string;
|
||||
onChange: (value: string) => void;
|
||||
onChange?: (value: string) => void;
|
||||
readOnly?: boolean;
|
||||
height?: string;
|
||||
options?: EditorProps['options'];
|
||||
@ -39,6 +47,7 @@ Editor.defaultProps = {
|
||||
readOnly: false,
|
||||
height: '40vh',
|
||||
options: {},
|
||||
onChange: (): void => {},
|
||||
};
|
||||
|
||||
export default Editor;
|
||||
|
@ -2,8 +2,6 @@ import { Tabs, TabsProps } from 'antd';
|
||||
import history from 'lib/history';
|
||||
import React from 'react';
|
||||
|
||||
const { TabPane } = Tabs;
|
||||
|
||||
function RouteTab({
|
||||
routes,
|
||||
activeKey,
|
||||
@ -22,29 +20,23 @@ function RouteTab({
|
||||
}
|
||||
};
|
||||
|
||||
const items = routes.map(({ Component, name, route }) => ({
|
||||
label: name,
|
||||
key: name,
|
||||
tabKey: route,
|
||||
children: <Component />,
|
||||
}));
|
||||
|
||||
return (
|
||||
<Tabs
|
||||
onChange={onChange}
|
||||
destroyInactiveTabPane
|
||||
activeKey={activeKey}
|
||||
animated
|
||||
items={items}
|
||||
// eslint-disable-next-line react/jsx-props-no-spreading
|
||||
{...rest}
|
||||
>
|
||||
{routes.map(
|
||||
({ Component, name, route }): JSX.Element => (
|
||||
<TabPane
|
||||
tabKey={route}
|
||||
animated
|
||||
destroyInactiveTabPane
|
||||
tab={name}
|
||||
key={name}
|
||||
>
|
||||
<Component />
|
||||
</TabPane>
|
||||
),
|
||||
)}
|
||||
</Tabs>
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -1,23 +1,40 @@
|
||||
/* eslint-disable react/no-unstable-nested-components */
|
||||
import { grey } from '@ant-design/colors';
|
||||
import { QuestionCircleFilled } from '@ant-design/icons';
|
||||
import { Tooltip } from 'antd';
|
||||
import React from 'react';
|
||||
import { themeColors } from 'constants/theme';
|
||||
import { useIsDarkMode } from 'hooks/useDarkMode';
|
||||
import React, { useMemo } from 'react';
|
||||
|
||||
import { style } from './styles';
|
||||
|
||||
function TextToolTip({ text, url }: TextToolTipProps): JSX.Element {
|
||||
const isDarkMode = useIsDarkMode();
|
||||
|
||||
const overlay = useMemo(
|
||||
() => (
|
||||
<div>
|
||||
{`${text} `}
|
||||
{url && (
|
||||
<a href={url} rel="noopener noreferrer" target="_blank">
|
||||
here
|
||||
</a>
|
||||
)}
|
||||
</div>
|
||||
),
|
||||
[text, url],
|
||||
);
|
||||
|
||||
const iconStyle = useMemo(
|
||||
() => ({
|
||||
...style,
|
||||
color: isDarkMode ? themeColors.whiteCream : grey[0],
|
||||
}),
|
||||
[isDarkMode],
|
||||
);
|
||||
|
||||
return (
|
||||
<Tooltip
|
||||
overlay={(): JSX.Element => (
|
||||
<div>
|
||||
{`${text} `}
|
||||
{url && (
|
||||
<a href={url} rel="noopener noreferrer" target="_blank">
|
||||
here
|
||||
</a>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
>
|
||||
<QuestionCircleFilled style={{ fontSize: '1.3125rem' }} />
|
||||
<Tooltip overlay={overlay}>
|
||||
<QuestionCircleFilled style={iconStyle} />
|
||||
</Tooltip>
|
||||
);
|
||||
}
|
||||
|
1
frontend/src/components/TextToolTip/styles.ts
Normal file
1
frontend/src/components/TextToolTip/styles.ts
Normal file
@ -0,0 +1 @@
|
||||
export const style = { fontSize: '1.3125rem' };
|
@ -1,9 +1,9 @@
|
||||
import { Button, Dropdown, Menu } from 'antd';
|
||||
import { Button, Dropdown } from 'antd';
|
||||
import TimeItems, {
|
||||
timePreferance,
|
||||
timePreferenceType,
|
||||
} from 'container/NewWidget/RightContainer/timeItems';
|
||||
import React, { useCallback } from 'react';
|
||||
import React, { useCallback, useMemo } from 'react';
|
||||
|
||||
import { menuItems } from './config';
|
||||
import { TextContainer } from './styles';
|
||||
@ -22,11 +22,17 @@ function TimePreference({
|
||||
[setSelectedTime],
|
||||
);
|
||||
|
||||
const menu = useMemo(
|
||||
() => ({
|
||||
items: menuItems,
|
||||
onClick: timeMenuItemOnChangeHandler,
|
||||
}),
|
||||
[timeMenuItemOnChangeHandler],
|
||||
);
|
||||
|
||||
return (
|
||||
<TextContainer noButtonMargin>
|
||||
<Dropdown
|
||||
overlay={<Menu onClick={timeMenuItemOnChangeHandler} items={menuItems} />}
|
||||
>
|
||||
<Dropdown menu={menu}>
|
||||
<Button>{selectedTime.name}</Button>
|
||||
</Dropdown>
|
||||
</TextContainer>
|
||||
|
@ -18,6 +18,8 @@ import { ResizeTable } from 'components/ResizeTable';
|
||||
import ROUTES from 'constants/routes';
|
||||
import dayjs from 'dayjs';
|
||||
import { useNotifications } from 'hooks/useNotifications';
|
||||
import useResourceAttribute from 'hooks/useResourceAttribute';
|
||||
import { convertRawQueriesToTraceSelectedTags } from 'hooks/useResourceAttribute/utils';
|
||||
import useUrlQuery from 'hooks/useUrlQuery';
|
||||
import createQueryParams from 'lib/createQueryParams';
|
||||
import history from 'lib/history';
|
||||
@ -93,9 +95,11 @@ function AllErrors(): JSX.Element {
|
||||
],
|
||||
);
|
||||
|
||||
const { queries } = useResourceAttribute();
|
||||
|
||||
const [{ isLoading, data }, errorCountResponse] = useQueries([
|
||||
{
|
||||
queryKey: ['getAllErrors', updatedPath, maxTime, minTime],
|
||||
queryKey: ['getAllErrors', updatedPath, maxTime, minTime, queries],
|
||||
queryFn: (): Promise<SuccessResponse<PayloadProps> | ErrorResponse> =>
|
||||
getAll({
|
||||
end: maxTime,
|
||||
@ -106,6 +110,7 @@ function AllErrors(): JSX.Element {
|
||||
orderParam: getUpdatedParams,
|
||||
exceptionType: getUpdatedExceptionType,
|
||||
serviceName: getUpdatedServiceName,
|
||||
tags: convertRawQueriesToTraceSelectedTags(queries),
|
||||
}),
|
||||
enabled: !loading,
|
||||
},
|
||||
@ -116,6 +121,7 @@ function AllErrors(): JSX.Element {
|
||||
minTime,
|
||||
getUpdatedExceptionType,
|
||||
getUpdatedServiceName,
|
||||
queries,
|
||||
],
|
||||
queryFn: (): Promise<ErrorResponse | SuccessResponse<number>> =>
|
||||
getErrorCounts({
|
||||
@ -123,6 +129,7 @@ function AllErrors(): JSX.Element {
|
||||
start: minTime,
|
||||
exceptionType: getUpdatedExceptionType,
|
||||
serviceName: getUpdatedServiceName,
|
||||
tags: convertRawQueriesToTraceSelectedTags(queries),
|
||||
}),
|
||||
enabled: !loading,
|
||||
},
|
||||
|
@ -1,17 +0,0 @@
|
||||
import { Menu } from 'antd';
|
||||
import styled from 'styled-components';
|
||||
|
||||
export const MenuDropdown = styled(Menu)`
|
||||
&&& {
|
||||
.ant-dropdown,
|
||||
.ant-dropdown-menu,
|
||||
.ant-dropdown-menu-item {
|
||||
padding: 0px;
|
||||
}
|
||||
.ant-menu-item {
|
||||
height: 1.75rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
`;
|
@ -13,7 +13,6 @@ import { ConfigProps } from 'types/api/dynamicConfigs/getDynamicConfigs';
|
||||
import AppReducer from 'types/reducer/app';
|
||||
|
||||
import HelpToolTip from './Config';
|
||||
import { MenuDropdown } from './Config/styles';
|
||||
|
||||
function DynamicConfigDropdown({
|
||||
frontendId,
|
||||
@ -34,13 +33,15 @@ function DynamicConfigDropdown({
|
||||
setIsHelpDropDownOpen(!isHelpDropDownOpen);
|
||||
};
|
||||
|
||||
const menuItems = useMemo(
|
||||
() => [
|
||||
{
|
||||
key: '1',
|
||||
label: <HelpToolTip config={config as ConfigProps} />,
|
||||
},
|
||||
],
|
||||
const menu = useMemo(
|
||||
() => ({
|
||||
items: [
|
||||
{
|
||||
key: '1',
|
||||
label: <HelpToolTip config={config as ConfigProps} />,
|
||||
},
|
||||
],
|
||||
}),
|
||||
[config],
|
||||
);
|
||||
|
||||
@ -53,10 +54,10 @@ function DynamicConfigDropdown({
|
||||
|
||||
return (
|
||||
<Dropdown
|
||||
onVisibleChange={onToggleHandler}
|
||||
onOpenChange={onToggleHandler}
|
||||
trigger={['click']}
|
||||
overlay={<MenuDropdown items={menuItems} />}
|
||||
visible={isHelpDropDownOpen}
|
||||
menu={menu}
|
||||
open={isHelpDropDownOpen}
|
||||
>
|
||||
<Space align="center">
|
||||
<Icon
|
||||
|
@ -23,7 +23,6 @@ import PromqlSection from './PromqlSection';
|
||||
import { FormContainer, QueryButton, StepHeading } from './styles';
|
||||
import { toIMetricsBuilderQuery } from './utils';
|
||||
|
||||
const { TabPane } = Tabs;
|
||||
function QuerySection({
|
||||
queryCategory,
|
||||
setQueryCategory,
|
||||
@ -282,6 +281,24 @@ function QuerySection({
|
||||
runQuery();
|
||||
};
|
||||
|
||||
const tabs = [
|
||||
{
|
||||
label: t('tab_qb'),
|
||||
key: EQueryType.QUERY_BUILDER.toString(),
|
||||
disabled: true,
|
||||
},
|
||||
{
|
||||
label: t('tab_chquery'),
|
||||
key: EQueryType.CLICKHOUSE.toString(),
|
||||
},
|
||||
];
|
||||
|
||||
const items = [
|
||||
{ label: t('tab_qb'), key: EQueryType.QUERY_BUILDER.toString() },
|
||||
{ label: t('tab_chquery'), key: EQueryType.CLICKHOUSE.toString() },
|
||||
{ label: t('tab_promql'), key: EQueryType.PROM.toString() },
|
||||
];
|
||||
|
||||
const renderTabs = (typ: AlertTypes): JSX.Element | null => {
|
||||
switch (typ) {
|
||||
case AlertTypes.TRACES_BASED_ALERT:
|
||||
@ -303,14 +320,8 @@ function QuerySection({
|
||||
)}
|
||||
</span>
|
||||
}
|
||||
>
|
||||
<TabPane
|
||||
tab={t('tab_qb')}
|
||||
key={EQueryType.QUERY_BUILDER.toString()}
|
||||
disabled
|
||||
/>
|
||||
<TabPane tab={t('tab_chquery')} key={EQueryType.CLICKHOUSE.toString()} />
|
||||
</Tabs>
|
||||
items={tabs}
|
||||
/>
|
||||
);
|
||||
case AlertTypes.METRICS_BASED_ALERT:
|
||||
default:
|
||||
@ -330,11 +341,8 @@ function QuerySection({
|
||||
)}
|
||||
</span>
|
||||
}
|
||||
>
|
||||
<TabPane tab={t('tab_qb')} key={EQueryType.QUERY_BUILDER.toString()} />
|
||||
<TabPane tab={t('tab_chquery')} key={EQueryType.CLICKHOUSE.toString()} />
|
||||
<TabPane tab={t('tab_promql')} key={EQueryType.PROM.toString()} />
|
||||
</Tabs>
|
||||
items={items}
|
||||
/>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
@ -1,16 +1,21 @@
|
||||
import { Avatar, Typography } from 'antd';
|
||||
import ROUTES from 'constants/routes';
|
||||
import history from 'lib/history';
|
||||
import React from 'react';
|
||||
import React, { useCallback } from 'react';
|
||||
import { useSelector } from 'react-redux';
|
||||
import { AppState } from 'store/reducers';
|
||||
import AppReducer from 'types/reducer/app';
|
||||
|
||||
import { AvatarContainer, ManageAccountLink, Wrapper } from '../styles';
|
||||
|
||||
function SignedInAS(): JSX.Element {
|
||||
function SignedIn({ onToggle }: SignedInProps): JSX.Element {
|
||||
const { user } = useSelector<AppState, AppReducer>((state) => state.app);
|
||||
|
||||
const onManageAccountClick = useCallback(() => {
|
||||
onToggle();
|
||||
history.push(ROUTES.MY_SETTINGS);
|
||||
}, [onToggle]);
|
||||
|
||||
if (!user) {
|
||||
return <div />;
|
||||
}
|
||||
@ -30,11 +35,7 @@ function SignedInAS(): JSX.Element {
|
||||
<Typography>{email}</Typography>
|
||||
</div>
|
||||
</AvatarContainer>
|
||||
<ManageAccountLink
|
||||
onClick={(): void => {
|
||||
history.push(ROUTES.MY_SETTINGS);
|
||||
}}
|
||||
>
|
||||
<ManageAccountLink onClick={onManageAccountClick}>
|
||||
Manage Account
|
||||
</ManageAccountLink>
|
||||
</Wrapper>
|
||||
@ -42,4 +43,8 @@ function SignedInAS(): JSX.Element {
|
||||
);
|
||||
}
|
||||
|
||||
export default SignedInAS;
|
||||
interface SignedInProps {
|
||||
onToggle: VoidFunction;
|
||||
}
|
||||
|
||||
export default SignedIn;
|
@ -3,12 +3,19 @@ import {
|
||||
CaretUpFilled,
|
||||
LogoutOutlined,
|
||||
} from '@ant-design/icons';
|
||||
import { Divider, Dropdown, Menu, Space, Typography } from 'antd';
|
||||
import type { MenuProps } from 'antd';
|
||||
import { Divider, Dropdown, Space, Typography } from 'antd';
|
||||
import { Logout } from 'api/utils';
|
||||
import ROUTES from 'constants/routes';
|
||||
import Config from 'container/ConfigDropdown';
|
||||
import { useIsDarkMode, useThemeMode } from 'hooks/useDarkMode';
|
||||
import React, { Dispatch, SetStateAction, useCallback, useState } from 'react';
|
||||
import React, {
|
||||
Dispatch,
|
||||
SetStateAction,
|
||||
useCallback,
|
||||
useMemo,
|
||||
useState,
|
||||
} from 'react';
|
||||
import { useSelector } from 'react-redux';
|
||||
import { NavLink } from 'react-router-dom';
|
||||
import { AppState } from 'store/reducers';
|
||||
@ -16,7 +23,7 @@ import AppReducer from 'types/reducer/app';
|
||||
|
||||
import CurrentOrganization from './CurrentOrganization';
|
||||
import ManageLicense from './ManageLicense';
|
||||
import SignedInAS from './SignedInAs';
|
||||
import SignedIn from './SignedIn';
|
||||
import {
|
||||
AvatarWrapper,
|
||||
Container,
|
||||
@ -43,32 +50,45 @@ function HeaderContainer(): JSX.Element {
|
||||
[],
|
||||
);
|
||||
|
||||
const menu = (
|
||||
<Menu style={{ padding: '1rem' }}>
|
||||
<Menu.ItemGroup>
|
||||
<SignedInAS />
|
||||
<Divider />
|
||||
<CurrentOrganization onToggle={onToggleHandler(setIsUserDropDownOpen)} />
|
||||
<Divider />
|
||||
<ManageLicense onToggle={onToggleHandler(setIsUserDropDownOpen)} />
|
||||
<Divider />
|
||||
<LogoutContainer>
|
||||
<LogoutOutlined />
|
||||
<div
|
||||
tabIndex={0}
|
||||
onKeyDown={(e): void => {
|
||||
if (e.key === 'Enter' || e.key === 'Space') {
|
||||
Logout();
|
||||
}
|
||||
}}
|
||||
role="button"
|
||||
onClick={Logout}
|
||||
>
|
||||
<Typography.Link>Logout</Typography.Link>
|
||||
</div>
|
||||
</LogoutContainer>
|
||||
</Menu.ItemGroup>
|
||||
</Menu>
|
||||
const onLogoutKeyDown = useCallback(
|
||||
(e: React.KeyboardEvent<HTMLDivElement>) => {
|
||||
if (e.key === 'Enter' || e.key === 'Space') {
|
||||
Logout();
|
||||
}
|
||||
},
|
||||
[],
|
||||
);
|
||||
|
||||
const menu: MenuProps = useMemo(
|
||||
() => ({
|
||||
items: [
|
||||
{
|
||||
key: 'main-menu',
|
||||
label: (
|
||||
<div>
|
||||
<SignedIn onToggle={onToggleHandler(setIsUserDropDownOpen)} />
|
||||
<Divider />
|
||||
<CurrentOrganization onToggle={onToggleHandler(setIsUserDropDownOpen)} />
|
||||
<Divider />
|
||||
<ManageLicense onToggle={onToggleHandler(setIsUserDropDownOpen)} />
|
||||
<Divider />
|
||||
<LogoutContainer>
|
||||
<LogoutOutlined />
|
||||
<div
|
||||
tabIndex={0}
|
||||
onKeyDown={onLogoutKeyDown}
|
||||
role="button"
|
||||
onClick={Logout}
|
||||
>
|
||||
<Typography.Link>Logout</Typography.Link>
|
||||
</div>
|
||||
</LogoutContainer>
|
||||
</div>
|
||||
),
|
||||
},
|
||||
],
|
||||
}),
|
||||
[onToggleHandler, onLogoutKeyDown],
|
||||
);
|
||||
|
||||
return (
|
||||
@ -98,10 +118,10 @@ function HeaderContainer(): JSX.Element {
|
||||
/>
|
||||
|
||||
<Dropdown
|
||||
onVisibleChange={onToggleHandler(setIsUserDropDownOpen)}
|
||||
onOpenChange={onToggleHandler(setIsUserDropDownOpen)}
|
||||
trigger={['click']}
|
||||
overlay={menu}
|
||||
visible={isUserDropDownOpen}
|
||||
menu={menu}
|
||||
open={isUserDropDownOpen}
|
||||
>
|
||||
<Space>
|
||||
<AvatarWrapper shape="circle">{user?.name[0]}</AvatarWrapper>
|
||||
|
@ -8,8 +8,6 @@ import { useQuery } from 'react-query';
|
||||
import ApplyLicenseForm from './ApplyLicenseForm';
|
||||
import ListLicenses from './ListLicenses';
|
||||
|
||||
const { TabPane } = Tabs;
|
||||
|
||||
function Licenses(): JSX.Element {
|
||||
const { t } = useTranslation(['licenses']);
|
||||
const { data, isError, isLoading, refetch } = useQuery({
|
||||
@ -28,17 +26,21 @@ function Licenses(): JSX.Element {
|
||||
const allValidLicense =
|
||||
data?.payload?.filter((license) => license.isCurrent) || [];
|
||||
|
||||
return (
|
||||
<Tabs destroyInactiveTabPane defaultActiveKey="licenses">
|
||||
<TabPane tabKey="licenses" tab={t('tab_current_license')} key="licenses">
|
||||
<ApplyLicenseForm licenseRefetch={refetch} />
|
||||
<ListLicenses licenses={allValidLicense} />
|
||||
</TabPane>
|
||||
const tabs = [
|
||||
{
|
||||
label: t('tab_current_license'),
|
||||
key: 'licenses',
|
||||
children: <ApplyLicenseForm licenseRefetch={refetch} />,
|
||||
},
|
||||
{
|
||||
label: t('tab_license_history'),
|
||||
key: 'history',
|
||||
children: <ListLicenses licenses={allValidLicense} />,
|
||||
},
|
||||
];
|
||||
|
||||
<TabPane tabKey="history" tab={t('tab_license_history')} key="history">
|
||||
<ListLicenses licenses={allValidLicense} />
|
||||
</TabPane>
|
||||
</Tabs>
|
||||
return (
|
||||
<Tabs destroyInactiveTabPane defaultActiveKey="licenses" items={tabs} />
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,12 @@
|
||||
import { PlusOutlined } from '@ant-design/icons';
|
||||
import { Card, Dropdown, Menu, Row, TableColumnProps, Typography } from 'antd';
|
||||
import {
|
||||
Card,
|
||||
Dropdown,
|
||||
MenuProps,
|
||||
Row,
|
||||
TableColumnProps,
|
||||
Typography,
|
||||
} from 'antd';
|
||||
import { ItemType } from 'antd/es/menu/hooks/useItems';
|
||||
import createDashboard from 'api/dashboard/create';
|
||||
import { AxiosError } from 'axios';
|
||||
@ -47,10 +54,12 @@ function ListOfAllDashboard(): JSX.Element {
|
||||
);
|
||||
|
||||
const { t } = useTranslation('dashboard');
|
||||
|
||||
const [
|
||||
isImportJSONModalVisible,
|
||||
setIsImportJSONModalVisible,
|
||||
] = useState<boolean>(false);
|
||||
|
||||
const [uploadedGrafana, setUploadedGrafana] = useState<boolean>(false);
|
||||
|
||||
const [filteredDashboards, setFilteredDashboards] = useState<Dashboard[]>();
|
||||
@ -58,6 +67,7 @@ function ListOfAllDashboard(): JSX.Element {
|
||||
useEffect(() => {
|
||||
setFilteredDashboards(dashboards);
|
||||
}, [dashboards]);
|
||||
|
||||
const [newDashboardState, setNewDashboardState] = useState({
|
||||
loading: false,
|
||||
error: false,
|
||||
@ -215,7 +225,12 @@ function ListOfAllDashboard(): JSX.Element {
|
||||
return menuItems;
|
||||
}, [createNewDashboard, loading, onNewDashboardHandler, t]);
|
||||
|
||||
const menuItems = getMenuItems();
|
||||
const menu: MenuProps = useMemo(
|
||||
() => ({
|
||||
items: getMenuItems(),
|
||||
}),
|
||||
[getMenuItems],
|
||||
);
|
||||
|
||||
const GetHeader = useMemo(
|
||||
() => (
|
||||
@ -230,7 +245,7 @@ function ListOfAllDashboard(): JSX.Element {
|
||||
}}
|
||||
/>
|
||||
{newDashboard && (
|
||||
<Dropdown trigger={['click']} overlay={<Menu items={menuItems} />}>
|
||||
<Dropdown trigger={['click']} menu={menu}>
|
||||
<NewDashboardButton
|
||||
icon={<PlusOutlined />}
|
||||
type="primary"
|
||||
@ -249,7 +264,7 @@ function ListOfAllDashboard(): JSX.Element {
|
||||
newDashboard,
|
||||
newDashboardState.error,
|
||||
newDashboardState.loading,
|
||||
menuItems,
|
||||
menu,
|
||||
],
|
||||
);
|
||||
|
||||
|
@ -1,14 +1,18 @@
|
||||
import { blue, orange } from '@ant-design/colors';
|
||||
import { Input } from 'antd';
|
||||
import { ColumnsType } from 'antd/es/table';
|
||||
import Editor from 'components/Editor';
|
||||
import AddToQueryHOC from 'components/Logs/AddToQueryHOC';
|
||||
import CopyClipboardHOC from 'components/Logs/CopyClipboardHOC';
|
||||
import { ResizeTable } from 'components/ResizeTable';
|
||||
import flatten from 'flat';
|
||||
import { fieldSearchFilter } from 'lib/logs/fieldSearch';
|
||||
import { isEmpty } from 'lodash-es';
|
||||
import React, { useMemo, useState } from 'react';
|
||||
import { ILog } from 'types/api/logs/log';
|
||||
|
||||
import ActionItem from './ActionItem';
|
||||
import { recursiveParseJSON } from './utils';
|
||||
|
||||
// Fields which should be restricted from adding it to query
|
||||
const RESTRICTED_FIELDS = ['timestamp'];
|
||||
@ -41,10 +45,10 @@ function TableView({ logData }: TableViewProps): JSX.Element | null {
|
||||
return null;
|
||||
}
|
||||
|
||||
const columns = [
|
||||
const columns: ColumnsType<DataType> = [
|
||||
{
|
||||
title: 'Action',
|
||||
width: 100,
|
||||
width: 15,
|
||||
render: (fieldData: Record<string, string>): JSX.Element | null => {
|
||||
const fieldKey = fieldData.field.split('.').slice(-1);
|
||||
if (!RESTRICTED_FIELDS.includes(fieldKey[0])) {
|
||||
@ -57,7 +61,8 @@ function TableView({ logData }: TableViewProps): JSX.Element | null {
|
||||
title: 'Field',
|
||||
dataIndex: 'field',
|
||||
key: 'field',
|
||||
width: 100,
|
||||
width: 30,
|
||||
ellipsis: true,
|
||||
render: (field: string): JSX.Element => {
|
||||
const fieldKey = field.split('.').slice(-1);
|
||||
const renderedField = <span style={{ color: blue[4] }}>{field}</span>;
|
||||
@ -78,16 +83,36 @@ function TableView({ logData }: TableViewProps): JSX.Element | null {
|
||||
key: 'value',
|
||||
width: 80,
|
||||
ellipsis: false,
|
||||
render: (field: never): JSX.Element => (
|
||||
<CopyClipboardHOC textToCopy={field}>
|
||||
<span style={{ color: orange[6] }}>{field}</span>
|
||||
</CopyClipboardHOC>
|
||||
),
|
||||
render: (field, record): JSX.Element => {
|
||||
if (record.field === 'body') {
|
||||
const parsedBody = recursiveParseJSON(field);
|
||||
if (!isEmpty(parsedBody)) {
|
||||
return (
|
||||
<Editor
|
||||
value={JSON.stringify(parsedBody, null, 2)}
|
||||
readOnly
|
||||
height="70vh"
|
||||
options={{
|
||||
minimap: {
|
||||
enabled: false,
|
||||
},
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<CopyClipboardHOC textToCopy={field}>
|
||||
<span style={{ color: orange[6] }}>{field}</span>
|
||||
</CopyClipboardHOC>
|
||||
);
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<div style={{ position: 'relative' }}>
|
||||
<>
|
||||
<Input
|
||||
placeholder="Search field names"
|
||||
size="large"
|
||||
@ -95,13 +120,19 @@ function TableView({ logData }: TableViewProps): JSX.Element | null {
|
||||
onChange={(e): void => setFieldSearchInput(e.target.value)}
|
||||
/>
|
||||
<ResizeTable
|
||||
columns={columns as never}
|
||||
columns={columns}
|
||||
tableLayout="fixed"
|
||||
dataSource={dataSource}
|
||||
pagination={false}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
interface DataType {
|
||||
key: string;
|
||||
field: string;
|
||||
value: string;
|
||||
}
|
||||
|
||||
export default TableView;
|
||||
|
@ -24,6 +24,19 @@ function LogDetailedView(): JSX.Element {
|
||||
});
|
||||
};
|
||||
|
||||
const items = [
|
||||
{
|
||||
label: 'Table',
|
||||
key: '1',
|
||||
children: detailedLog && <TableView logData={detailedLog} />,
|
||||
},
|
||||
{
|
||||
label: 'JSON',
|
||||
key: '2',
|
||||
children: detailedLog && <JSONView logData={detailedLog} />,
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<Drawer
|
||||
width="60%"
|
||||
@ -35,14 +48,7 @@ function LogDetailedView(): JSX.Element {
|
||||
style={{ overscrollBehavior: 'contain' }}
|
||||
destroyOnClose
|
||||
>
|
||||
<Tabs defaultActiveKey="1">
|
||||
<Tabs.TabPane tab="Table" key="1">
|
||||
{detailedLog && <TableView logData={detailedLog} />}
|
||||
</Tabs.TabPane>
|
||||
<Tabs.TabPane tab="JSON" key="2">
|
||||
{detailedLog && <JSONView logData={detailedLog} />}
|
||||
</Tabs.TabPane>
|
||||
</Tabs>
|
||||
<Tabs defaultActiveKey="1" items={items} />
|
||||
</Drawer>
|
||||
);
|
||||
}
|
||||
|
47
frontend/src/container/LogDetailedView/util.test.ts
Normal file
47
frontend/src/container/LogDetailedView/util.test.ts
Normal file
@ -0,0 +1,47 @@
|
||||
import { recursiveParseJSON } from './utils';
|
||||
|
||||
describe('recursiveParseJSON', () => {
|
||||
it('should return an empty object if the input is not valid JSON', () => {
|
||||
const result = recursiveParseJSON('not valid JSON');
|
||||
expect(result).toEqual({});
|
||||
});
|
||||
|
||||
it('should return the parsed JSON object for valid JSON input', () => {
|
||||
const jsonString = '{"name": "John", "age": 30}';
|
||||
const result = recursiveParseJSON(jsonString);
|
||||
expect(result).toEqual({ name: 'John', age: 30 });
|
||||
});
|
||||
|
||||
it('should recursively parse nested JSON objects', () => {
|
||||
const jsonString =
|
||||
'{"name": "John", "age": 30, "address": {"street": "123 Main St", "city": "Anytown", "state": "CA"}}';
|
||||
const result = recursiveParseJSON(jsonString);
|
||||
expect(result).toEqual({
|
||||
name: 'John',
|
||||
age: 30,
|
||||
address: {
|
||||
street: '123 Main St',
|
||||
city: 'Anytown',
|
||||
state: 'CA',
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('should recursively parse nested JSON arrays', () => {
|
||||
const jsonString = '[1, 2, [3, 4], {"foo": "bar"}]';
|
||||
const result = recursiveParseJSON(jsonString);
|
||||
expect(result).toEqual([1, 2, [3, 4], { foo: 'bar' }]);
|
||||
});
|
||||
|
||||
it('should recursively parse deeply nested JSON objects', () => {
|
||||
const jsonString = '{"foo": {"bar": {"baz": {"qux": {"value": 42}}}}}';
|
||||
const result = recursiveParseJSON(jsonString);
|
||||
expect(result).toEqual({ foo: { bar: { baz: { qux: { value: 42 } } } } });
|
||||
});
|
||||
|
||||
it('should handle JSON input that contains escaped characters', () => {
|
||||
const jsonString = '{"name": "John\\", \\"Doe", "age": 30}';
|
||||
const result = recursiveParseJSON(jsonString);
|
||||
expect(result).toEqual({ name: 'John", "Doe', age: 30 });
|
||||
});
|
||||
});
|
11
frontend/src/container/LogDetailedView/utils.ts
Normal file
11
frontend/src/container/LogDetailedView/utils.ts
Normal file
@ -0,0 +1,11 @@
|
||||
export const recursiveParseJSON = (obj: string): Record<string, unknown> => {
|
||||
try {
|
||||
const value = JSON.parse(obj);
|
||||
if (typeof value === 'string') {
|
||||
return recursiveParseJSON(value);
|
||||
}
|
||||
return value;
|
||||
} catch (e) {
|
||||
return {};
|
||||
}
|
||||
};
|
@ -27,8 +27,9 @@ function QueryConditionField({
|
||||
return (
|
||||
<Select
|
||||
defaultValue={
|
||||
(query as any).value &&
|
||||
(((query as any)?.value as any) as string).toUpperCase()
|
||||
(query as QueryFields).value &&
|
||||
(((((query as QueryFields)
|
||||
?.value as unknown) as QueryFields) as unknown) as string).toUpperCase()
|
||||
}
|
||||
onChange={(e): void => {
|
||||
onUpdate({ ...query, value: e }, queryIndex);
|
||||
|
@ -173,6 +173,13 @@ function SearchFilter({
|
||||
globalTime.minTime,
|
||||
]);
|
||||
|
||||
const onPopOverChange = useCallback(
|
||||
(isVisible: boolean) => {
|
||||
onDropDownToggleHandler(isVisible)();
|
||||
},
|
||||
[onDropDownToggleHandler],
|
||||
);
|
||||
|
||||
return (
|
||||
<Container>
|
||||
<Popover
|
||||
@ -189,11 +196,9 @@ function SearchFilter({
|
||||
overlayInnerStyle={{
|
||||
width: `${searchRef?.current?.input?.offsetWidth || 0}px`,
|
||||
}}
|
||||
visible={showDropDown}
|
||||
open={showDropDown}
|
||||
destroyTooltipOnHide
|
||||
onVisibleChange={(value): void => {
|
||||
onDropDownToggleHandler(value)();
|
||||
}}
|
||||
onOpenChange={onPopOverChange}
|
||||
>
|
||||
<Input.Search
|
||||
ref={searchRef}
|
||||
|
@ -64,7 +64,7 @@ export function useSearchParser(): {
|
||||
},
|
||||
// need to hide this warning as we don't want to update the query string on every change
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
[dispatch, parsedQuery],
|
||||
[dispatch, parsedQuery, selectedTime],
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
|
@ -1,32 +0,0 @@
|
||||
import { convertMetricKeyToTrace } from 'lib/resourceAttributes';
|
||||
import React from 'react';
|
||||
|
||||
import { QueryChipContainer, QueryChipItem } from './styles';
|
||||
import { IResourceAttributeQuery } from './types';
|
||||
|
||||
interface IQueryChipProps {
|
||||
queryData: IResourceAttributeQuery;
|
||||
onClose: (id: string) => void;
|
||||
disabled: boolean;
|
||||
}
|
||||
|
||||
export default function QueryChip({
|
||||
queryData,
|
||||
onClose,
|
||||
disabled,
|
||||
}: IQueryChipProps): JSX.Element {
|
||||
return (
|
||||
<QueryChipContainer>
|
||||
<QueryChipItem>{convertMetricKeyToTrace(queryData.tagKey)}</QueryChipItem>
|
||||
<QueryChipItem>{queryData.operator}</QueryChipItem>
|
||||
<QueryChipItem
|
||||
closable={!disabled}
|
||||
onClose={(): void => {
|
||||
if (!disabled) onClose(queryData.id);
|
||||
}}
|
||||
>
|
||||
{queryData.tagValue.join(', ')}
|
||||
</QueryChipItem>
|
||||
</QueryChipContainer>
|
||||
);
|
||||
}
|
@ -1,61 +0,0 @@
|
||||
import { createMachine } from 'xstate';
|
||||
|
||||
export const ResourceAttributesFilterMachine =
|
||||
/** @xstate-layout N4IgpgJg5mDOIC5QBECGsAWAjA9qgThAAQDKYBAxhkQIIB2xAYgJYA2ALmPgHQAqqUANJgAngGIAcgFEAGr0SgADjljN2zHHQUgAHogAcAFgAM3AOz6ATAEYAzJdsA2Y4cOWAnABoQIxAFpDR2tuQ319AFYTcKdbFycAX3jvNExcAmIySmp6JjZOHn4hUTFNACFWAFd8bWVVdU1tPQQzY1MXY2tDdzNHM3dHd0NvXwR7biMTa313S0i+63DE5PRsPEJScnwqWgYiFg4uPgFhcQAlKRIpeSQQWrUNLRumx3Czbg8TR0sbS31jfUcw38fW47gBHmm4XCVms3SWIBSq3SGyyO1yBx4AHlFFxUOwcPhJLJrkoVPcGk9ENYFuF3i5YR0wtEHECEAEgiEmV8zH1DLYzHZ4Yi0utMltsrt9vluNjcfjCWVKtUbnd6o9QE1rMYBtxbGFvsZ3NrZj1WdYOfotUZLX0XEFHEKViKMpttjk9nlDrL8HiCWJzpcSbcyWrGoh3NCQj0zK53P1ph1WeFLLqnJZ2s5vmZLA6kginWsXaj3VLDoUAGqoSpgEp0cpVGohh5hhDWDy0sz8zruakzamWVm-Qyg362V5-AZOayO1KFlHitEejFHKCV6v+i5XRt1ZuU1s52zjNOOaZfdOWIY+RDZ0Hc6ZmKEXqyLPPCudit2Sz08ACSEFYNbSHI27kuquiIOEjiONwjJgrM3RWJYZisgEIJgnYPTmuEdi2OaiR5nQOAQHA2hvsiH4Sui0qFCcIGhnuLSmP0YJuJ2xjJsmKELG8XZTK0tjdHG06vgW5GupRS7St6vrKqSO4UhqVL8TBWp8o4eqdl0A5Xmy3G6gK56-B4uERDOSKiuJi6lgUAhrhUYB0buimtrEKZBDYrxaS0OZca8+ltheybOI4hivGZzrzp+VGHH+AGOQp4EIHy+ghNYnawtG4TsbYvk8QKfHGAJfQ9uF76WSW37xWBTSGJ0qXpd0vRZdEKGPqC2YeO2-zfO4+HxEAA */
|
||||
createMachine({
|
||||
tsTypes: {} as import('./ResourceAttributesFilter.Machine.typegen').Typegen0,
|
||||
initial: 'Idle',
|
||||
states: {
|
||||
TagKey: {
|
||||
on: {
|
||||
NEXT: {
|
||||
actions: 'onSelectOperator',
|
||||
target: 'Operator',
|
||||
},
|
||||
onBlur: {
|
||||
actions: 'onBlurPurge',
|
||||
target: 'Idle',
|
||||
},
|
||||
RESET: {
|
||||
target: 'Idle',
|
||||
},
|
||||
},
|
||||
},
|
||||
Operator: {
|
||||
on: {
|
||||
NEXT: {
|
||||
actions: 'onSelectTagValue',
|
||||
target: 'TagValue',
|
||||
},
|
||||
onBlur: {
|
||||
actions: 'onBlurPurge',
|
||||
target: 'Idle',
|
||||
},
|
||||
RESET: {
|
||||
target: 'Idle',
|
||||
},
|
||||
},
|
||||
},
|
||||
TagValue: {
|
||||
on: {
|
||||
onBlur: {
|
||||
actions: ['onValidateQuery', 'onBlurPurge'],
|
||||
target: 'Idle',
|
||||
},
|
||||
RESET: {
|
||||
target: 'Idle',
|
||||
},
|
||||
},
|
||||
},
|
||||
Idle: {
|
||||
on: {
|
||||
NEXT: {
|
||||
actions: 'onSelectTagKey',
|
||||
description: 'Select Category',
|
||||
target: 'TagKey',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
id: 'Dashboard Search And Filter',
|
||||
});
|
@ -1,219 +0,0 @@
|
||||
import { CloseCircleFilled } from '@ant-design/icons';
|
||||
import { useMachine } from '@xstate/react';
|
||||
import { Button, Select, Spin } from 'antd';
|
||||
import ROUTES from 'constants/routes';
|
||||
import history from 'lib/history';
|
||||
import { convertMetricKeyToTrace } from 'lib/resourceAttributes';
|
||||
import { map } from 'lodash-es';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import { ResetInitialData } from 'store/actions/metrics/resetInitialData';
|
||||
import { SetResourceAttributeQueries } from 'store/actions/metrics/setResourceAttributeQueries';
|
||||
import { AppState } from 'store/reducers';
|
||||
import MetricReducer from 'types/reducer/metrics';
|
||||
import { v4 as uuid } from 'uuid';
|
||||
|
||||
import QueryChip from './QueryChip';
|
||||
import { ResourceAttributesFilterMachine } from './ResourceAttributesFilter.Machine';
|
||||
import { QueryChipItem, SearchContainer } from './styles';
|
||||
import { IOption, IResourceAttributeQuery } from './types';
|
||||
import { createQuery, GetTagKeys, GetTagValues, OperatorSchema } from './utils';
|
||||
|
||||
function ResourceAttributesFilter(): JSX.Element | null {
|
||||
const dispatch = useDispatch();
|
||||
const [disabled, setDisabled] = useState(
|
||||
!(history.location.pathname === ROUTES.APPLICATION),
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
const unListen = history.listen(({ pathname }) => {
|
||||
setDisabled(!(pathname === ROUTES.APPLICATION));
|
||||
});
|
||||
return (): void => {
|
||||
if (!history.location.pathname.startsWith(`${ROUTES.APPLICATION}/`)) {
|
||||
dispatch(ResetInitialData());
|
||||
}
|
||||
unListen();
|
||||
};
|
||||
}, [dispatch]);
|
||||
|
||||
const { resourceAttributeQueries } = useSelector<AppState, MetricReducer>(
|
||||
(state) => state.metrics,
|
||||
);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [selectedValues, setSelectedValues] = useState<string[]>([]);
|
||||
const [staging, setStaging] = useState<string[]>([]);
|
||||
const [queries, setQueries] = useState<IResourceAttributeQuery[]>([]);
|
||||
const [optionsData, setOptionsData] = useState<{
|
||||
mode: undefined | 'tags' | 'multiple';
|
||||
options: IOption[];
|
||||
}>({
|
||||
mode: undefined,
|
||||
options: [],
|
||||
});
|
||||
|
||||
const dispatchQueries = (updatedQueries: IResourceAttributeQuery[]): void => {
|
||||
dispatch(SetResourceAttributeQueries(updatedQueries));
|
||||
};
|
||||
const handleLoading = (isLoading: boolean): void => {
|
||||
setLoading(isLoading);
|
||||
if (isLoading) {
|
||||
setOptionsData({ mode: undefined, options: [] });
|
||||
}
|
||||
};
|
||||
const [state, send] = useMachine(ResourceAttributesFilterMachine, {
|
||||
actions: {
|
||||
onSelectTagKey: () => {
|
||||
handleLoading(true);
|
||||
GetTagKeys()
|
||||
.then((tagKeys) => setOptionsData({ options: tagKeys, mode: undefined }))
|
||||
.finally(() => {
|
||||
handleLoading(false);
|
||||
});
|
||||
},
|
||||
onSelectOperator: () => {
|
||||
setOptionsData({ options: OperatorSchema, mode: undefined });
|
||||
},
|
||||
onSelectTagValue: () => {
|
||||
handleLoading(true);
|
||||
|
||||
GetTagValues(staging[0])
|
||||
.then((tagValuesOptions) =>
|
||||
setOptionsData({ options: tagValuesOptions, mode: 'multiple' }),
|
||||
)
|
||||
.finally(() => {
|
||||
handleLoading(false);
|
||||
});
|
||||
},
|
||||
onBlurPurge: () => {
|
||||
setSelectedValues([]);
|
||||
setStaging([]);
|
||||
},
|
||||
onValidateQuery: (): void => {
|
||||
if (staging.length < 2 || selectedValues.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const generatedQuery = createQuery([...staging, selectedValues]);
|
||||
if (generatedQuery) {
|
||||
dispatchQueries([...queries, generatedQuery]);
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
setQueries(resourceAttributeQueries);
|
||||
}, [resourceAttributeQueries]);
|
||||
|
||||
const handleFocus = (): void => {
|
||||
if (state.value === 'Idle') {
|
||||
send('NEXT');
|
||||
}
|
||||
};
|
||||
|
||||
const handleBlur = (): void => {
|
||||
send('onBlur');
|
||||
};
|
||||
const handleChange = (value: never): void => {
|
||||
if (!optionsData.mode) {
|
||||
setStaging((prevStaging) => [...prevStaging, value]);
|
||||
setSelectedValues([]);
|
||||
send('NEXT');
|
||||
return;
|
||||
}
|
||||
|
||||
setSelectedValues([...value]);
|
||||
};
|
||||
|
||||
const handleClose = (id: string): void => {
|
||||
dispatchQueries(queries.filter((queryData) => queryData.id !== id));
|
||||
};
|
||||
|
||||
const handleClearAll = (): void => {
|
||||
send('RESET');
|
||||
dispatchQueries([]);
|
||||
setStaging([]);
|
||||
setSelectedValues([]);
|
||||
};
|
||||
const disabledAndEmpty = !!(
|
||||
!queries.length &&
|
||||
!staging.length &&
|
||||
!selectedValues.length &&
|
||||
disabled
|
||||
);
|
||||
const disabledOrEmpty = !!(
|
||||
queries.length ||
|
||||
staging.length ||
|
||||
selectedValues.length ||
|
||||
disabled
|
||||
);
|
||||
|
||||
if (disabledAndEmpty) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<SearchContainer disabled={disabled}>
|
||||
<div
|
||||
style={{
|
||||
maxWidth: disabled ? '100%' : '70%',
|
||||
display: 'flex',
|
||||
overflowX: 'auto',
|
||||
}}
|
||||
>
|
||||
{map(
|
||||
queries,
|
||||
(query): JSX.Element => (
|
||||
<QueryChip
|
||||
disabled={disabled}
|
||||
key={query.id}
|
||||
queryData={query}
|
||||
onClose={handleClose}
|
||||
/>
|
||||
),
|
||||
)}
|
||||
{map(staging, (item, idx) => (
|
||||
<QueryChipItem key={uuid()}>
|
||||
{idx === 0 ? convertMetricKeyToTrace(item) : item}
|
||||
</QueryChipItem>
|
||||
))}
|
||||
</div>
|
||||
{!disabled && (
|
||||
<Select
|
||||
placeholder={
|
||||
disabledOrEmpty ? '' : 'Search and Filter based on resource attributes.'
|
||||
}
|
||||
disabled={disabled}
|
||||
onChange={handleChange}
|
||||
bordered={false}
|
||||
value={selectedValues as never}
|
||||
style={{ flex: 1 }}
|
||||
options={optionsData.options}
|
||||
mode={optionsData?.mode}
|
||||
showArrow={false}
|
||||
onFocus={handleFocus}
|
||||
onBlur={handleBlur}
|
||||
notFoundContent={
|
||||
loading ? (
|
||||
<span>
|
||||
<Spin size="small" /> Loading...{' '}
|
||||
</span>
|
||||
) : (
|
||||
<span>
|
||||
No resource attributes available to filter. Please refer docs to send
|
||||
attributes.
|
||||
</span>
|
||||
)
|
||||
}
|
||||
/>
|
||||
)}
|
||||
|
||||
{(queries.length || staging.length || selectedValues.length) && !disabled ? (
|
||||
<Button onClick={handleClearAll} icon={<CloseCircleFilled />} type="text" />
|
||||
) : null}
|
||||
</SearchContainer>
|
||||
);
|
||||
}
|
||||
|
||||
export default ResourceAttributesFilter;
|
@ -1,11 +0,0 @@
|
||||
export interface IOption {
|
||||
label: string;
|
||||
value: string;
|
||||
}
|
||||
|
||||
export interface IResourceAttributeQuery {
|
||||
id: string;
|
||||
tagKey: string;
|
||||
operator: string;
|
||||
tagValue: string[];
|
||||
}
|
@ -1,64 +0,0 @@
|
||||
import {
|
||||
getResourceAttributesTagKeys,
|
||||
getResourceAttributesTagValues,
|
||||
} from 'api/metrics/getResourceAttributes';
|
||||
import { OperatorConversions } from 'constants/resourceAttributes';
|
||||
import { convertMetricKeyToTrace } from 'lib/resourceAttributes';
|
||||
import { v4 as uuid } from 'uuid';
|
||||
|
||||
import { IOption, IResourceAttributeQuery } from './types';
|
||||
|
||||
export const OperatorSchema: IOption[] = OperatorConversions.map(
|
||||
(operator) => ({
|
||||
label: operator.label,
|
||||
value: operator.label,
|
||||
}),
|
||||
);
|
||||
|
||||
export const GetTagKeys = async (): Promise<IOption[]> => {
|
||||
// if (TagKeysCache) {
|
||||
// return new Promise((resolve) => {
|
||||
// resolve(TagKeysCache);
|
||||
// });
|
||||
// }
|
||||
const { payload } = await getResourceAttributesTagKeys({
|
||||
metricName: 'signoz_calls_total',
|
||||
match: 'resource_',
|
||||
});
|
||||
if (!payload || !payload?.data) {
|
||||
return [];
|
||||
}
|
||||
return payload.data.map((tagKey: string) => ({
|
||||
label: convertMetricKeyToTrace(tagKey),
|
||||
value: tagKey,
|
||||
}));
|
||||
};
|
||||
|
||||
export const GetTagValues = async (tagKey: string): Promise<IOption[]> => {
|
||||
const { payload } = await getResourceAttributesTagValues({
|
||||
tagKey,
|
||||
metricName: 'signoz_calls_total',
|
||||
});
|
||||
|
||||
if (!payload || !payload?.data) {
|
||||
return [];
|
||||
}
|
||||
return payload.data.map((tagValue: string) => ({
|
||||
label: tagValue,
|
||||
value: tagValue,
|
||||
}));
|
||||
};
|
||||
|
||||
export const createQuery = (
|
||||
selectedItems: Array<string | string[]> = [],
|
||||
): IResourceAttributeQuery | null => {
|
||||
if (selectedItems.length === 3) {
|
||||
return {
|
||||
id: uuid().slice(0, 8),
|
||||
tagKey: selectedItems[0] as string,
|
||||
operator: selectedItems[1] as string,
|
||||
tagValue: selectedItems[2] as string[],
|
||||
};
|
||||
}
|
||||
return null;
|
||||
};
|
@ -4,21 +4,20 @@ import {
|
||||
databaseCallsAvgDuration,
|
||||
databaseCallsRPS,
|
||||
} from 'container/MetricsApplication/MetricsPageQueries/DBCallQueries';
|
||||
import useResourceAttribute from 'hooks/useResourceAttribute';
|
||||
import {
|
||||
convertRawQueriesToTraceSelectedTags,
|
||||
resourceAttributesToTagFilterItems,
|
||||
} from 'lib/resourceAttributes';
|
||||
} from 'hooks/useResourceAttribute/utils';
|
||||
import React, { useMemo, useState } from 'react';
|
||||
import { useSelector } from 'react-redux';
|
||||
import { useParams } from 'react-router-dom';
|
||||
import { AppState } from 'store/reducers';
|
||||
import { Widgets } from 'types/api/dashboard/getAll';
|
||||
import MetricReducer from 'types/reducer/metrics';
|
||||
|
||||
import { Card, GraphContainer, GraphTitle, Row } from '../styles';
|
||||
import { Button } from './styles';
|
||||
import {
|
||||
dbSystemTags,
|
||||
handleNonInQueryRange,
|
||||
onGraphClickHandler,
|
||||
onViewTracePopupClick,
|
||||
} from './util';
|
||||
@ -26,22 +25,22 @@ import {
|
||||
function DBCall({ getWidgetQueryBuilder }: DBCallProps): JSX.Element {
|
||||
const { servicename } = useParams<{ servicename?: string }>();
|
||||
const [selectedTimeStamp, setSelectedTimeStamp] = useState<number>(0);
|
||||
const { resourceAttributeQueries } = useSelector<AppState, MetricReducer>(
|
||||
(state) => state.metrics,
|
||||
);
|
||||
const { queries } = useResourceAttribute();
|
||||
|
||||
const tagFilterItems = useMemo(
|
||||
() => resourceAttributesToTagFilterItems(resourceAttributeQueries) || [],
|
||||
[resourceAttributeQueries],
|
||||
() =>
|
||||
handleNonInQueryRange(resourceAttributesToTagFilterItems(queries)) || [],
|
||||
[queries],
|
||||
);
|
||||
|
||||
const selectedTraceTags: string = useMemo(
|
||||
() =>
|
||||
JSON.stringify(
|
||||
convertRawQueriesToTraceSelectedTags(resourceAttributeQueries).concat(
|
||||
...dbSystemTags,
|
||||
) || [],
|
||||
convertRawQueriesToTraceSelectedTags(queries).concat(...dbSystemTags) || [],
|
||||
),
|
||||
[resourceAttributeQueries],
|
||||
[queries],
|
||||
);
|
||||
|
||||
const legend = '{{db_system}}';
|
||||
|
||||
const databaseCallsRPSWidget = useMemo(
|
||||
|
@ -6,33 +6,34 @@ import {
|
||||
externalCallErrorPercent,
|
||||
externalCallRpsByAddress,
|
||||
} from 'container/MetricsApplication/MetricsPageQueries/ExternalQueries';
|
||||
import useResourceAttribute from 'hooks/useResourceAttribute';
|
||||
import {
|
||||
convertRawQueriesToTraceSelectedTags,
|
||||
resourceAttributesToTagFilterItems,
|
||||
} from 'lib/resourceAttributes';
|
||||
} from 'hooks/useResourceAttribute/utils';
|
||||
import React, { useMemo, useState } from 'react';
|
||||
import { useSelector } from 'react-redux';
|
||||
import { useParams } from 'react-router-dom';
|
||||
import { AppState } from 'store/reducers';
|
||||
import { Widgets } from 'types/api/dashboard/getAll';
|
||||
import MetricReducer from 'types/reducer/metrics';
|
||||
|
||||
import { Card, GraphContainer, GraphTitle, Row } from '../styles';
|
||||
import { legend } from './constant';
|
||||
import { Button } from './styles';
|
||||
import { onGraphClickHandler, onViewTracePopupClick } from './util';
|
||||
import {
|
||||
handleNonInQueryRange,
|
||||
onGraphClickHandler,
|
||||
onViewTracePopupClick,
|
||||
} from './util';
|
||||
|
||||
function External({ getWidgetQueryBuilder }: ExternalProps): JSX.Element {
|
||||
const [selectedTimeStamp, setSelectedTimeStamp] = useState<number>(0);
|
||||
|
||||
const { servicename } = useParams<{ servicename?: string }>();
|
||||
const { resourceAttributeQueries } = useSelector<AppState, MetricReducer>(
|
||||
(state) => state.metrics,
|
||||
);
|
||||
const { queries } = useResourceAttribute();
|
||||
|
||||
const tagFilterItems = useMemo(
|
||||
() => resourceAttributesToTagFilterItems(resourceAttributeQueries) || [],
|
||||
[resourceAttributeQueries],
|
||||
() =>
|
||||
handleNonInQueryRange(resourceAttributesToTagFilterItems(queries)) || [],
|
||||
[queries],
|
||||
);
|
||||
|
||||
const externalCallErrorWidget = useMemo(
|
||||
@ -51,11 +52,8 @@ function External({ getWidgetQueryBuilder }: ExternalProps): JSX.Element {
|
||||
);
|
||||
|
||||
const selectedTraceTags = useMemo(
|
||||
() =>
|
||||
JSON.stringify(
|
||||
convertRawQueriesToTraceSelectedTags(resourceAttributeQueries) || [],
|
||||
),
|
||||
[resourceAttributeQueries],
|
||||
() => JSON.stringify(convertRawQueriesToTraceSelectedTags(queries) || []),
|
||||
[queries],
|
||||
);
|
||||
|
||||
const externalCallDurationWidget = useMemo(
|
||||
|
@ -3,13 +3,14 @@ import Graph from 'components/Graph';
|
||||
import { METRICS_PAGE_QUERY_PARAM } from 'constants/query';
|
||||
import ROUTES from 'constants/routes';
|
||||
import FullView from 'container/GridGraphLayout/Graph/FullView/index.metricsBuilder';
|
||||
import convertToNanoSecondsToSecond from 'lib/convertToNanoSecondsToSecond';
|
||||
import { colors } from 'lib/getRandomColor';
|
||||
import history from 'lib/history';
|
||||
import useResourceAttribute from 'hooks/useResourceAttribute';
|
||||
import {
|
||||
convertRawQueriesToTraceSelectedTags,
|
||||
resourceAttributesToTagFilterItems,
|
||||
} from 'lib/resourceAttributes';
|
||||
} from 'hooks/useResourceAttribute/utils';
|
||||
import convertToNanoSecondsToSecond from 'lib/convertToNanoSecondsToSecond';
|
||||
import { colors } from 'lib/getRandomColor';
|
||||
import history from 'lib/history';
|
||||
import React, { useCallback, useMemo, useState } from 'react';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import { useParams } from 'react-router-dom';
|
||||
@ -25,7 +26,11 @@ import {
|
||||
import { Card, Col, GraphContainer, GraphTitle, Row } from '../styles';
|
||||
import TopOperationsTable from '../TopOperationsTable';
|
||||
import { Button } from './styles';
|
||||
import { onGraphClickHandler, onViewTracePopupClick } from './util';
|
||||
import {
|
||||
handleNonInQueryRange,
|
||||
onGraphClickHandler,
|
||||
onViewTracePopupClick,
|
||||
} from './util';
|
||||
|
||||
function Application({ getWidgetQueryBuilder }: DashboardProps): JSX.Element {
|
||||
const { servicename } = useParams<{ servicename?: string }>();
|
||||
@ -54,20 +59,21 @@ function Application({ getWidgetQueryBuilder }: DashboardProps): JSX.Element {
|
||||
[handleSetTimeStamp],
|
||||
);
|
||||
|
||||
const {
|
||||
topOperations,
|
||||
serviceOverview,
|
||||
resourceAttributeQueries,
|
||||
topLevelOperations,
|
||||
} = useSelector<AppState, MetricReducer>((state) => state.metrics);
|
||||
const { topOperations, serviceOverview, topLevelOperations } = useSelector<
|
||||
AppState,
|
||||
MetricReducer
|
||||
>((state) => state.metrics);
|
||||
|
||||
const { queries } = useResourceAttribute();
|
||||
|
||||
const selectedTraceTags: string = JSON.stringify(
|
||||
convertRawQueriesToTraceSelectedTags(resourceAttributeQueries) || [],
|
||||
convertRawQueriesToTraceSelectedTags(queries) || [],
|
||||
);
|
||||
|
||||
const tagFilterItems = useMemo(
|
||||
() => resourceAttributesToTagFilterItems(resourceAttributeQueries) || [],
|
||||
[resourceAttributeQueries],
|
||||
() =>
|
||||
handleNonInQueryRange(resourceAttributesToTagFilterItems(queries)) || [],
|
||||
[queries],
|
||||
);
|
||||
|
||||
const operationPerSecWidget = useMemo(
|
||||
|
@ -2,6 +2,7 @@ import { ActiveElement, Chart, ChartData, ChartEvent } from 'chart.js';
|
||||
import { METRICS_PAGE_QUERY_PARAM } from 'constants/query';
|
||||
import ROUTES from 'constants/routes';
|
||||
import history from 'lib/history';
|
||||
import { IQueryBuilderTagFilterItems } from 'types/api/dashboard/getAll';
|
||||
import { Tags } from 'types/reducer/trace';
|
||||
|
||||
export const dbSystemTags: Tags[] = [
|
||||
@ -60,7 +61,7 @@ export function onGraphClickHandler(
|
||||
const points = chart.getElementsAtEventForMode(
|
||||
event.native,
|
||||
'nearest',
|
||||
{ intersect: false },
|
||||
{ intersect: true },
|
||||
true,
|
||||
);
|
||||
const id = `${from}_button`;
|
||||
@ -84,3 +85,16 @@ export function onGraphClickHandler(
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export const handleNonInQueryRange = (
|
||||
tags: IQueryBuilderTagFilterItems[],
|
||||
): IQueryBuilderTagFilterItems[] =>
|
||||
tags.map((tag) => {
|
||||
if (tag.op === 'Not IN') {
|
||||
return {
|
||||
...tag,
|
||||
op: 'NIN',
|
||||
};
|
||||
}
|
||||
return tag;
|
||||
});
|
||||
|
@ -3,25 +3,23 @@ import { ColumnsType } from 'antd/lib/table';
|
||||
import { ResizeTable } from 'components/ResizeTable';
|
||||
import { METRICS_PAGE_QUERY_PARAM } from 'constants/query';
|
||||
import ROUTES from 'constants/routes';
|
||||
import useResourceAttribute from 'hooks/useResourceAttribute';
|
||||
import { convertRawQueriesToTraceSelectedTags } from 'hooks/useResourceAttribute/utils';
|
||||
import history from 'lib/history';
|
||||
import { convertRawQueriesToTraceSelectedTags } from 'lib/resourceAttributes';
|
||||
import React from 'react';
|
||||
import { useSelector } from 'react-redux';
|
||||
import { useParams } from 'react-router-dom';
|
||||
import { AppState } from 'store/reducers';
|
||||
import { GlobalReducer } from 'types/reducer/globalTime';
|
||||
import MetricReducer from 'types/reducer/metrics';
|
||||
|
||||
function TopOperationsTable(props: TopOperationsTableProps): JSX.Element {
|
||||
const { minTime, maxTime } = useSelector<AppState, GlobalReducer>(
|
||||
(state) => state.globalTime,
|
||||
);
|
||||
const { resourceAttributeQueries } = useSelector<AppState, MetricReducer>(
|
||||
(state) => state.metrics,
|
||||
);
|
||||
const { queries } = useResourceAttribute();
|
||||
|
||||
const selectedTraceTags: string = JSON.stringify(
|
||||
convertRawQueriesToTraceSelectedTags(resourceAttributeQueries) || [],
|
||||
convertRawQueriesToTraceSelectedTags(queries) || [],
|
||||
);
|
||||
|
||||
const { data } = props;
|
||||
|
@ -1,11 +1,11 @@
|
||||
import RouteTab from 'components/RouteTab';
|
||||
import ROUTES from 'constants/routes';
|
||||
import ResourceAttributesFilter from 'container/ResourceAttributesFilter';
|
||||
import React, { memo } from 'react';
|
||||
import { generatePath, useParams } from 'react-router-dom';
|
||||
import { useLocation } from 'react-use';
|
||||
|
||||
import { getWidgetQueryBuilder } from './MetricsApplication.factory';
|
||||
import ResourceAttributesFilter from './ResourceAttributesFilter';
|
||||
import DBCall from './Tabs/DBCall';
|
||||
import External from './Tabs/External';
|
||||
import Overview from './Tabs/Overview';
|
||||
|
@ -4,19 +4,13 @@ import React from 'react';
|
||||
import GeneralDashboardSettings from './General';
|
||||
import VariablesSetting from './Variables';
|
||||
|
||||
const { TabPane } = Tabs;
|
||||
|
||||
function DashboardSettingsContent(): JSX.Element {
|
||||
return (
|
||||
<Tabs>
|
||||
<TabPane tab="General" key="general">
|
||||
<GeneralDashboardSettings />
|
||||
</TabPane>
|
||||
<TabPane tab="Variables" key="variables">
|
||||
<VariablesSetting />
|
||||
</TabPane>
|
||||
</Tabs>
|
||||
);
|
||||
const items = [
|
||||
{ label: 'General', key: 'general', children: <GeneralDashboardSettings /> },
|
||||
{ label: 'Variables', key: 'variables', children: <VariablesSetting /> },
|
||||
];
|
||||
|
||||
return <Tabs items={items} />;
|
||||
}
|
||||
|
||||
export default DashboardSettingsContent;
|
||||
|
@ -2,31 +2,31 @@
|
||||
|
||||
export interface Typegen0 {
|
||||
'@@xstate/typegen': true;
|
||||
eventsCausingActions: {
|
||||
onSelectOperator: 'NEXT';
|
||||
onBlurPurge: 'onBlur';
|
||||
onSelectTagValue: 'NEXT';
|
||||
onValidateQuery: 'onBlur';
|
||||
onSelectTagKey: 'NEXT';
|
||||
};
|
||||
internalEvents: {
|
||||
'xstate.init': { type: 'xstate.init' };
|
||||
};
|
||||
invokeSrcNameMap: {};
|
||||
missingImplementations: {
|
||||
actions:
|
||||
| 'onSelectOperator'
|
||||
| 'onBlurPurge'
|
||||
| 'onSelectOperator'
|
||||
| 'onSelectTagKey'
|
||||
| 'onSelectTagValue'
|
||||
| 'onValidateQuery'
|
||||
| 'onSelectTagKey';
|
||||
services: never;
|
||||
guards: never;
|
||||
| 'onValidateQuery';
|
||||
delays: never;
|
||||
guards: never;
|
||||
services: never;
|
||||
};
|
||||
eventsCausingActions: {
|
||||
onBlurPurge: 'onBlur';
|
||||
onSelectOperator: 'NEXT';
|
||||
onSelectTagKey: 'NEXT';
|
||||
onSelectTagValue: 'NEXT';
|
||||
onValidateQuery: 'onBlur';
|
||||
};
|
||||
eventsCausingServices: {};
|
||||
eventsCausingGuards: {};
|
||||
eventsCausingDelays: {};
|
||||
matchesStates: 'TagKey' | 'Operator' | 'TagValue' | 'Idle';
|
||||
eventsCausingGuards: {};
|
||||
eventsCausingServices: {};
|
||||
matchesStates: 'Idle' | 'Operator' | 'TagKey' | 'TagValue';
|
||||
tags: never;
|
||||
}
|
||||
|
@ -68,6 +68,8 @@ function MetricsBuilder({
|
||||
});
|
||||
}, [metricName]);
|
||||
|
||||
// TODO: rewrite to Form component from antd
|
||||
|
||||
return (
|
||||
<QueryHeader
|
||||
name={queryData.name}
|
||||
|
@ -34,7 +34,6 @@ import TabHeader from './TabHeader';
|
||||
import { getQueryKey } from './utils/getQueryKey';
|
||||
import { showUnstagedStashConfirmBox } from './utils/userSettings';
|
||||
|
||||
const { TabPane } = Tabs;
|
||||
function QuerySection({
|
||||
handleUnstagedChanges,
|
||||
updateQuery,
|
||||
@ -144,6 +143,80 @@ function QuerySection({
|
||||
setLocalQueryChanges(cloneDeep(updatedQuery));
|
||||
};
|
||||
|
||||
const items = [
|
||||
{
|
||||
key: EQueryType.QUERY_BUILDER.toString(),
|
||||
label: 'Query Builder',
|
||||
tab: (
|
||||
<TabHeader
|
||||
tabName="Query Builder"
|
||||
hasUnstagedChanges={queryDiff(
|
||||
query,
|
||||
localQueryChanges,
|
||||
EQueryType.QUERY_BUILDER,
|
||||
)}
|
||||
/>
|
||||
),
|
||||
children: (
|
||||
<QueryBuilderQueryContainer
|
||||
key={rctTabKey.QUERY_BUILDER}
|
||||
queryData={localQueryChanges}
|
||||
updateQueryData={({ updatedQuery }: IHandleUpdatedQuery): void => {
|
||||
handleLocalQueryUpdate({ updatedQuery });
|
||||
}}
|
||||
metricsBuilderQueries={
|
||||
localQueryChanges[WIDGET_QUERY_BUILDER_QUERY_KEY_NAME]
|
||||
}
|
||||
selectedGraph={selectedGraph}
|
||||
/>
|
||||
),
|
||||
},
|
||||
{
|
||||
key: EQueryType.CLICKHOUSE.toString(),
|
||||
label: 'ClickHouse Query',
|
||||
tab: (
|
||||
<TabHeader
|
||||
tabName="ClickHouse Query"
|
||||
hasUnstagedChanges={queryDiff(
|
||||
query,
|
||||
localQueryChanges,
|
||||
EQueryType.CLICKHOUSE,
|
||||
)}
|
||||
/>
|
||||
),
|
||||
children: (
|
||||
<ClickHouseQueryContainer
|
||||
key={rctTabKey.CLICKHOUSE}
|
||||
queryData={localQueryChanges}
|
||||
updateQueryData={({ updatedQuery }: IHandleUpdatedQuery): void => {
|
||||
handleLocalQueryUpdate({ updatedQuery });
|
||||
}}
|
||||
clickHouseQueries={localQueryChanges[WIDGET_CLICKHOUSE_QUERY_KEY_NAME]}
|
||||
/>
|
||||
),
|
||||
},
|
||||
{
|
||||
key: EQueryType.PROM.toString(),
|
||||
label: 'PromQL',
|
||||
tab: (
|
||||
<TabHeader
|
||||
tabName="PromQL"
|
||||
hasUnstagedChanges={queryDiff(query, localQueryChanges, EQueryType.PROM)}
|
||||
/>
|
||||
),
|
||||
children: (
|
||||
<PromQLQueryContainer
|
||||
key={rctTabKey.PROM}
|
||||
queryData={localQueryChanges}
|
||||
updateQueryData={({ updatedQuery }: IHandleUpdatedQuery): void => {
|
||||
handleLocalQueryUpdate({ updatedQuery });
|
||||
}}
|
||||
promQLQueries={localQueryChanges[WIDGET_PROMQL_QUERY_KEY_NAME]}
|
||||
/>
|
||||
),
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<>
|
||||
<div style={{ display: 'flex' }}>
|
||||
@ -165,77 +238,8 @@ function QuerySection({
|
||||
</Button>
|
||||
</span>
|
||||
}
|
||||
>
|
||||
<TabPane
|
||||
tab={
|
||||
<TabHeader
|
||||
tabName="Query Builder"
|
||||
hasUnstagedChanges={queryDiff(
|
||||
query,
|
||||
localQueryChanges,
|
||||
EQueryType.QUERY_BUILDER,
|
||||
)}
|
||||
/>
|
||||
}
|
||||
key={EQueryType.QUERY_BUILDER.toString()}
|
||||
>
|
||||
<QueryBuilderQueryContainer
|
||||
key={rctTabKey.QUERY_BUILDER}
|
||||
queryData={localQueryChanges}
|
||||
updateQueryData={({ updatedQuery }: IHandleUpdatedQuery): void => {
|
||||
handleLocalQueryUpdate({ updatedQuery });
|
||||
}}
|
||||
metricsBuilderQueries={
|
||||
localQueryChanges[WIDGET_QUERY_BUILDER_QUERY_KEY_NAME]
|
||||
}
|
||||
selectedGraph={selectedGraph}
|
||||
/>
|
||||
</TabPane>
|
||||
<TabPane
|
||||
tab={
|
||||
<TabHeader
|
||||
tabName="ClickHouse Query"
|
||||
hasUnstagedChanges={queryDiff(
|
||||
query,
|
||||
localQueryChanges,
|
||||
EQueryType.CLICKHOUSE,
|
||||
)}
|
||||
/>
|
||||
}
|
||||
key={EQueryType.CLICKHOUSE.toString()}
|
||||
>
|
||||
<ClickHouseQueryContainer
|
||||
key={rctTabKey.CLICKHOUSE}
|
||||
queryData={localQueryChanges}
|
||||
updateQueryData={({ updatedQuery }: IHandleUpdatedQuery): void => {
|
||||
handleLocalQueryUpdate({ updatedQuery });
|
||||
}}
|
||||
clickHouseQueries={localQueryChanges[WIDGET_CLICKHOUSE_QUERY_KEY_NAME]}
|
||||
/>
|
||||
</TabPane>
|
||||
<TabPane
|
||||
tab={
|
||||
<TabHeader
|
||||
tabName="PromQL"
|
||||
hasUnstagedChanges={queryDiff(
|
||||
query,
|
||||
localQueryChanges,
|
||||
EQueryType.PROM,
|
||||
)}
|
||||
/>
|
||||
}
|
||||
key={EQueryType.PROM.toString()}
|
||||
>
|
||||
<PromQLQueryContainer
|
||||
key={rctTabKey.PROM}
|
||||
queryData={localQueryChanges}
|
||||
updateQueryData={({ updatedQuery }: IHandleUpdatedQuery): void => {
|
||||
handleLocalQueryUpdate({ updatedQuery });
|
||||
}}
|
||||
promQLQueries={localQueryChanges[WIDGET_PROMQL_QUERY_KEY_NAME]}
|
||||
/>
|
||||
</TabPane>
|
||||
</Tabs>
|
||||
items={items}
|
||||
/>
|
||||
</div>
|
||||
{/* {localQueryChanges.map((e, index) => (
|
||||
// <Query
|
||||
|
@ -0,0 +1,9 @@
|
||||
import {
|
||||
IBuilderFormula,
|
||||
IBuilderQuery,
|
||||
} from 'types/api/queryBuilder/queryBuilderData';
|
||||
|
||||
export type QueryBuilderProps = {
|
||||
queryData: IBuilderQuery[];
|
||||
queryFormula: IBuilderFormula[];
|
||||
};
|
23
frontend/src/container/QueryBuilder/QueryBuilder.tsx
Normal file
23
frontend/src/container/QueryBuilder/QueryBuilder.tsx
Normal file
@ -0,0 +1,23 @@
|
||||
// ** Hooks
|
||||
import { useQueryBuilder } from 'hooks/useQueryBuilder';
|
||||
import React from 'react';
|
||||
|
||||
// ** Types
|
||||
import { QueryBuilderProps } from './QueryBuilder.interfaces';
|
||||
|
||||
// TODO: temporary eslint disable while variable isn't used
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
export function QueryBuilder(props: QueryBuilderProps): JSX.Element {
|
||||
// TODO: temporary doesn't use
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
const { queryBuilderData } = useQueryBuilder();
|
||||
|
||||
// Here we can use Form from antd library and fill context data or edit
|
||||
// Connect form with adding or removing items from the list
|
||||
|
||||
// Here will be map of query queryBuilderData.queryData and queryBuilderData.queryFormulas components
|
||||
// Each component can be part of antd Form list where we can add or remove items
|
||||
// Also need decide to make a copy of queryData for working with form or not and after it set the full new list with formulas or queries to the context
|
||||
// With button to add him
|
||||
return <div>null</div>;
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
export type ListMarkerProps = {
|
||||
isDisabled: boolean;
|
||||
labelName: string;
|
||||
index: number;
|
||||
className?: string;
|
||||
isAvailableToDisable: boolean;
|
||||
toggleDisabled: (index: number) => void;
|
||||
};
|
@ -0,0 +1,9 @@
|
||||
import { Button } from 'antd';
|
||||
import styled from 'styled-components';
|
||||
|
||||
export const StyledButton = styled(Button)`
|
||||
min-width: 2rem;
|
||||
height: 2.25rem;
|
||||
padding: 0.125rem;
|
||||
border-radius: 0.375rem;
|
||||
`;
|
@ -0,0 +1,36 @@
|
||||
import { EyeFilled, EyeInvisibleFilled } from '@ant-design/icons';
|
||||
import { ButtonProps } from 'antd';
|
||||
import React from 'react';
|
||||
|
||||
// ** Types
|
||||
import { ListMarkerProps } from './ListMarker.interfaces';
|
||||
// ** Styles
|
||||
import { StyledButton } from './ListMarker.styled';
|
||||
|
||||
export function ListMarker({
|
||||
isDisabled,
|
||||
labelName,
|
||||
index,
|
||||
isAvailableToDisable,
|
||||
className,
|
||||
toggleDisabled,
|
||||
}: ListMarkerProps): JSX.Element {
|
||||
const buttonProps: Partial<ButtonProps> = isAvailableToDisable
|
||||
? {
|
||||
type: isDisabled ? 'default' : 'primary',
|
||||
icon: isDisabled ? <EyeInvisibleFilled /> : <EyeFilled />,
|
||||
onClick: (): void => toggleDisabled(index),
|
||||
}
|
||||
: { type: 'primary' };
|
||||
|
||||
return (
|
||||
<StyledButton
|
||||
type={buttonProps.type}
|
||||
icon={buttonProps.icon}
|
||||
onClick={buttonProps.onClick}
|
||||
className={className}
|
||||
>
|
||||
{labelName}
|
||||
</StyledButton>
|
||||
);
|
||||
}
|
@ -0,0 +1 @@
|
||||
export { ListMarker } from './ListMarker';
|
@ -0,0 +1,17 @@
|
||||
import { SelectProps } from 'antd';
|
||||
import { DataSource } from 'types/common/queryBuilder';
|
||||
|
||||
type StaticLabel = { variant: 'static'; dataSource: DataSource };
|
||||
|
||||
export type DropdownLabel = {
|
||||
variant: 'dropdown';
|
||||
onChange: (value: DataSource) => void;
|
||||
} & Omit<SelectProps, 'onChange'>;
|
||||
|
||||
export type QueryLabelProps = StaticLabel | DropdownLabel;
|
||||
|
||||
export function isLabelDropdown(
|
||||
label: QueryLabelProps,
|
||||
): label is DropdownLabel {
|
||||
return label.variant === 'dropdown';
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
import { Select } from 'antd';
|
||||
import styled, { css } from 'styled-components';
|
||||
|
||||
// ** Types
|
||||
import { DropdownLabel } from './QueryLabel.interfaces';
|
||||
|
||||
const LabelStyle = css`
|
||||
width: fit-content;
|
||||
min-width: 5.75rem;
|
||||
`;
|
||||
|
||||
export const StyledSingleLabel = styled(Select)`
|
||||
pointer-events: none;
|
||||
${LabelStyle}
|
||||
`;
|
||||
|
||||
export const StyledDropdownLabel = styled(Select)<DropdownLabel>`
|
||||
${LabelStyle}
|
||||
`;
|
@ -0,0 +1,49 @@
|
||||
import { Select } from 'antd';
|
||||
import React from 'react';
|
||||
import { DataSource } from 'types/common/queryBuilder';
|
||||
import { SelectOption } from 'types/common/select';
|
||||
|
||||
// ** Types
|
||||
import { isLabelDropdown, QueryLabelProps } from './QueryLabel.interfaces';
|
||||
// ** Styles
|
||||
import { StyledSingleLabel } from './QueryLabel.styled';
|
||||
|
||||
const { Option } = Select;
|
||||
|
||||
const dataSourceMap = [DataSource.LOGS, DataSource.METRICS, DataSource.TRACES];
|
||||
|
||||
export function QueryLabel(props: QueryLabelProps): JSX.Element {
|
||||
const isDropdown = isLabelDropdown(props);
|
||||
|
||||
if (!isDropdown) {
|
||||
const { dataSource } = props;
|
||||
|
||||
return (
|
||||
<StyledSingleLabel
|
||||
defaultValue={dataSource}
|
||||
showArrow={false}
|
||||
dropdownStyle={{ display: 'none' }}
|
||||
>
|
||||
<Option value={dataSource}>{dataSource}</Option>
|
||||
</StyledSingleLabel>
|
||||
);
|
||||
}
|
||||
|
||||
const { onChange } = props;
|
||||
|
||||
const dataSourceOptions: SelectOption<
|
||||
DataSource,
|
||||
string
|
||||
>[] = dataSourceMap.map((source) => ({
|
||||
label: source.charAt(0).toUpperCase() + source.slice(1),
|
||||
value: source,
|
||||
}));
|
||||
|
||||
return (
|
||||
<Select
|
||||
defaultValue={dataSourceOptions[0].value}
|
||||
options={dataSourceOptions}
|
||||
onChange={onChange}
|
||||
/>
|
||||
);
|
||||
}
|
@ -0,0 +1 @@
|
||||
export { QueryLabel } from './QueryLabel';
|
2
frontend/src/container/QueryBuilder/components/index.ts
Normal file
2
frontend/src/container/QueryBuilder/components/index.ts
Normal file
@ -0,0 +1,2 @@
|
||||
export { ListMarker } from './ListMarker';
|
||||
export { QueryLabel } from './QueryLabel';
|
1
frontend/src/container/QueryBuilder/index.ts
Normal file
1
frontend/src/container/QueryBuilder/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export { QueryBuilder } from './QueryBuilder';
|
@ -0,0 +1,88 @@
|
||||
import { CloseCircleFilled } from '@ant-design/icons';
|
||||
import { Button, Select, Spin } from 'antd';
|
||||
import useResourceAttribute, {
|
||||
isResourceEmpty,
|
||||
} from 'hooks/useResourceAttribute';
|
||||
import { convertMetricKeyToTrace } from 'hooks/useResourceAttribute/utils';
|
||||
import React, { useMemo } from 'react';
|
||||
import { v4 as uuid } from 'uuid';
|
||||
|
||||
import QueryChip from './components/QueryChip';
|
||||
import { QueryChipItem, SearchContainer } from './styles';
|
||||
|
||||
function ResourceAttributesFilter({
|
||||
suffixIcon,
|
||||
}: ResourceAttributesFilterProps): JSX.Element | null {
|
||||
const {
|
||||
queries,
|
||||
staging,
|
||||
handleClose,
|
||||
handleBlur,
|
||||
handleClearAll,
|
||||
handleFocus,
|
||||
handleChange,
|
||||
selectedQuery,
|
||||
optionsData,
|
||||
loading,
|
||||
} = useResourceAttribute();
|
||||
|
||||
const isEmpty = useMemo(
|
||||
() => isResourceEmpty(queries, staging, selectedQuery),
|
||||
[queries, selectedQuery, staging],
|
||||
);
|
||||
|
||||
return (
|
||||
<SearchContainer>
|
||||
<div>
|
||||
{queries.map((query) => (
|
||||
<QueryChip key={query.id} queryData={query} onClose={handleClose} />
|
||||
))}
|
||||
{staging.map((query, idx) => (
|
||||
<QueryChipItem key={uuid()}>
|
||||
{idx === 0 ? convertMetricKeyToTrace(query) : query}
|
||||
</QueryChipItem>
|
||||
))}
|
||||
</div>
|
||||
<Select
|
||||
placeholder={!isEmpty && 'Search and Filter based on resource attributes.'}
|
||||
onChange={handleChange}
|
||||
bordered={false}
|
||||
value={selectedQuery as never}
|
||||
style={{ flex: 1 }}
|
||||
options={optionsData.options}
|
||||
mode={optionsData?.mode}
|
||||
showArrow={!!suffixIcon}
|
||||
onClick={handleFocus}
|
||||
onBlur={handleBlur}
|
||||
onClear={handleClearAll}
|
||||
suffixIcon={suffixIcon}
|
||||
notFoundContent={
|
||||
loading ? (
|
||||
<span>
|
||||
<Spin size="small" /> Loading...
|
||||
</span>
|
||||
) : (
|
||||
<span>
|
||||
No resource attributes available to filter. Please refer docs to send
|
||||
attributes.
|
||||
</span>
|
||||
)
|
||||
}
|
||||
/>
|
||||
|
||||
{queries.length || staging.length || selectedQuery.length ? (
|
||||
<Button onClick={handleClearAll} icon={<CloseCircleFilled />} type="text" />
|
||||
) : null}
|
||||
</SearchContainer>
|
||||
);
|
||||
}
|
||||
|
||||
interface ResourceAttributesFilterProps {
|
||||
suffixIcon?: React.ReactNode;
|
||||
}
|
||||
|
||||
ResourceAttributesFilter.defaultProps = {
|
||||
suffixIcon: undefined,
|
||||
};
|
||||
|
||||
export default ResourceAttributesFilter;
|
@ -0,0 +1,23 @@
|
||||
import { convertMetricKeyToTrace } from 'hooks/useResourceAttribute/utils';
|
||||
import React from 'react';
|
||||
|
||||
import { QueryChipContainer, QueryChipItem } from '../../styles';
|
||||
import { IQueryChipProps } from './types';
|
||||
|
||||
function QueryChip({ queryData, onClose }: IQueryChipProps): JSX.Element {
|
||||
const onCloseHandler = (): void => {
|
||||
onClose(queryData.id);
|
||||
};
|
||||
|
||||
return (
|
||||
<QueryChipContainer>
|
||||
<QueryChipItem>{convertMetricKeyToTrace(queryData.tagKey)}</QueryChipItem>
|
||||
<QueryChipItem>{queryData.operator}</QueryChipItem>
|
||||
<QueryChipItem closable onClose={onCloseHandler}>
|
||||
{queryData.tagValue.join(', ')}
|
||||
</QueryChipItem>
|
||||
</QueryChipContainer>
|
||||
);
|
||||
}
|
||||
|
||||
export default QueryChip;
|
@ -0,0 +1,3 @@
|
||||
import QueryChip from './QueryChip';
|
||||
|
||||
export default QueryChip;
|
@ -0,0 +1,6 @@
|
||||
import { IResourceAttribute } from 'hooks/useResourceAttribute/types';
|
||||
|
||||
export interface IQueryChipProps {
|
||||
queryData: IResourceAttribute;
|
||||
onClose: (id: string) => void;
|
||||
}
|
3
frontend/src/container/ResourceAttributesFilter/index.ts
Normal file
3
frontend/src/container/ResourceAttributesFilter/index.ts
Normal file
@ -0,0 +1,3 @@
|
||||
import ResourceAttributesFilter from './ResourceAttributesFilter';
|
||||
|
||||
export default ResourceAttributesFilter;
|
@ -2,9 +2,7 @@ import { grey } from '@ant-design/colors';
|
||||
import { Tag } from 'antd';
|
||||
import styled from 'styled-components';
|
||||
|
||||
export const SearchContainer = styled.div<{
|
||||
disabled: boolean;
|
||||
}>`
|
||||
export const SearchContainer = styled.div`
|
||||
width: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@ -12,8 +10,8 @@ export const SearchContainer = styled.div<{
|
||||
padding: 0.2rem;
|
||||
margin: 1rem 0;
|
||||
border: 1px solid #ccc5;
|
||||
${({ disabled }): string => (disabled ? `cursor: not-allowed;` : '')}
|
||||
`;
|
||||
|
||||
export const QueryChipContainer = styled.span`
|
||||
display: flex;
|
||||
align-items: center;
|
@ -29,6 +29,7 @@ function SideNav(): JSX.Element {
|
||||
const [collapsed, setCollapsed] = useState<boolean>(
|
||||
getLocalStorageKey(IS_SIDEBAR_COLLAPSED) === 'true',
|
||||
);
|
||||
const { search } = useLocation();
|
||||
const { currentVersion, latestVersion, isCurrentVersionError } = useSelector<
|
||||
AppState,
|
||||
AppReducer
|
||||
@ -47,11 +48,15 @@ function SideNav(): JSX.Element {
|
||||
|
||||
const onClickHandler = useCallback(
|
||||
(to: string) => {
|
||||
const queryParams = new URLSearchParams(search);
|
||||
|
||||
const url = queryParams.toString();
|
||||
|
||||
if (pathname !== to) {
|
||||
history.push(to);
|
||||
history.push(`${to}?${url}`);
|
||||
}
|
||||
},
|
||||
[pathname],
|
||||
[pathname, search],
|
||||
);
|
||||
|
||||
const onClickSlackHandler = (): void => {
|
||||
@ -98,7 +103,7 @@ function SideNav(): JSX.Element {
|
||||
);
|
||||
|
||||
const items = [
|
||||
...menus.map(({ to, Icon, name, tags }) => ({
|
||||
...menus.map(({ to, Icon, name, tags, children }) => ({
|
||||
key: to,
|
||||
icon: <Icon />,
|
||||
onClick: (): void => onClickHandler(to),
|
||||
@ -113,6 +118,7 @@ function SideNav(): JSX.Element {
|
||||
))}
|
||||
</Space>
|
||||
),
|
||||
children,
|
||||
})),
|
||||
];
|
||||
|
||||
@ -129,7 +135,7 @@ function SideNav(): JSX.Element {
|
||||
theme="dark"
|
||||
defaultSelectedKeys={[ROUTES.APPLICATION]}
|
||||
selectedKeys={currentMenu ? [currentMenu?.to] : []}
|
||||
mode="inline"
|
||||
mode="vertical"
|
||||
style={styles}
|
||||
items={items}
|
||||
/>
|
||||
|
@ -10,6 +10,7 @@ import {
|
||||
MenuOutlined,
|
||||
SettingOutlined,
|
||||
} from '@ant-design/icons';
|
||||
import type { MenuProps } from 'antd';
|
||||
import ROUTES from 'constants/routes';
|
||||
|
||||
const menus: SidebarMenu[] = [
|
||||
@ -28,6 +29,12 @@ const menus: SidebarMenu[] = [
|
||||
to: ROUTES.LOGS,
|
||||
name: 'Logs',
|
||||
// tags: ['Beta'],
|
||||
// children: [
|
||||
// {
|
||||
// key: ROUTES.LOGS,
|
||||
// label: 'Search',
|
||||
// },
|
||||
// ],
|
||||
},
|
||||
{
|
||||
Icon: DashboardFilled,
|
||||
@ -71,6 +78,7 @@ interface SidebarMenu {
|
||||
name: string;
|
||||
Icon: typeof ApiOutlined;
|
||||
tags?: string[];
|
||||
children?: Required<MenuProps>['items'][number][];
|
||||
}
|
||||
|
||||
export default menus;
|
||||
|
@ -210,7 +210,7 @@ function Duration(): JSX.Element {
|
||||
min={Number(getMs(String(preLocalMinDuration.current || 0)))}
|
||||
max={Number(getMs(String(preLocalMaxDuration.current || 0)))}
|
||||
range
|
||||
tipFormatter={TipComponent}
|
||||
tooltip={{ formatter: TipComponent }}
|
||||
onChange={([min, max]): void => {
|
||||
onRangeSliderHandler([String(min), String(max)]);
|
||||
}}
|
||||
|
@ -15,8 +15,6 @@ import {
|
||||
} from './styles';
|
||||
import Tags from './Tags';
|
||||
|
||||
const { TabPane } = Tabs;
|
||||
|
||||
function SelectedSpanDetails(props: SelectedSpanDetailsProps): JSX.Element {
|
||||
const { tree, firstSpanStartTime } = props;
|
||||
|
||||
@ -44,6 +42,33 @@ function SelectedSpanDetails(props: SelectedSpanDetailsProps): JSX.Element {
|
||||
|
||||
const { tags, nonChildReferences } = tree;
|
||||
|
||||
const items = [
|
||||
{
|
||||
label: 'Tags',
|
||||
key: '1',
|
||||
children: (
|
||||
<Tags
|
||||
onToggleHandler={onToggleHandler}
|
||||
setText={setText}
|
||||
tags={tags}
|
||||
linkedSpans={nonChildReferences}
|
||||
/>
|
||||
),
|
||||
},
|
||||
{
|
||||
label: 'Events',
|
||||
key: '2',
|
||||
children: (
|
||||
<Events
|
||||
events={tree.event}
|
||||
onToggleHandler={onToggleHandler}
|
||||
setText={setText}
|
||||
firstSpanStartTime={firstSpanStartTime}
|
||||
/>
|
||||
),
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<CardContainer>
|
||||
<StyledSpace
|
||||
@ -81,24 +106,7 @@ function SelectedSpanDetails(props: SelectedSpanDetailsProps): JSX.Element {
|
||||
)}
|
||||
</Modal>
|
||||
|
||||
<Tabs defaultActiveKey="1">
|
||||
<TabPane tab="Tags" key="1">
|
||||
<Tags
|
||||
onToggleHandler={onToggleHandler}
|
||||
setText={setText}
|
||||
tags={tags}
|
||||
linkedSpans={nonChildReferences}
|
||||
/>
|
||||
</TabPane>
|
||||
<TabPane tab="Events" key="2">
|
||||
<Events
|
||||
events={tree.event}
|
||||
onToggleHandler={onToggleHandler}
|
||||
setText={setText}
|
||||
firstSpanStartTime={firstSpanStartTime}
|
||||
/>
|
||||
</TabPane>
|
||||
</Tabs>
|
||||
<Tabs defaultActiveKey="1" items={items} />
|
||||
</CardContainer>
|
||||
);
|
||||
}
|
||||
|
9
frontend/src/hooks/useQueryBuilder.ts
Normal file
9
frontend/src/hooks/useQueryBuilder.ts
Normal file
@ -0,0 +1,9 @@
|
||||
import {
|
||||
QueryBuilderContext,
|
||||
QueryBuilderContextType,
|
||||
} from 'providers/QueryBuilder';
|
||||
import { useContext } from 'react';
|
||||
|
||||
export function useQueryBuilder(): QueryBuilderContextType {
|
||||
return useContext(QueryBuilderContext);
|
||||
}
|
188
frontend/src/hooks/useResourceAttribute/ResourceProvider.tsx
Normal file
188
frontend/src/hooks/useResourceAttribute/ResourceProvider.tsx
Normal file
@ -0,0 +1,188 @@
|
||||
import { useMachine } from '@xstate/react';
|
||||
import ROUTES from 'constants/routes';
|
||||
import { encode } from 'js-base64';
|
||||
import history from 'lib/history';
|
||||
import React, { useCallback, useMemo, useState } from 'react';
|
||||
import { useLocation } from 'react-router-dom';
|
||||
|
||||
import { whilelistedKeys } from './config';
|
||||
import { ResourceContext } from './context';
|
||||
import { ResourceAttributesFilterMachine } from './machine';
|
||||
import {
|
||||
IResourceAttribute,
|
||||
IResourceAttributeProps,
|
||||
OptionsData,
|
||||
} from './types';
|
||||
import {
|
||||
createQuery,
|
||||
getResourceAttributeQueriesFromURL,
|
||||
GetTagKeys,
|
||||
GetTagValues,
|
||||
mappingWithRoutesAndKeys,
|
||||
OperatorSchema,
|
||||
} from './utils';
|
||||
|
||||
function ResourceProvider({ children }: Props): JSX.Element {
|
||||
const { pathname } = useLocation();
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [selectedQuery, setSelectedQueries] = useState<string[]>([]);
|
||||
const [staging, setStaging] = useState<string[]>([]);
|
||||
const [queries, setQueries] = useState<IResourceAttribute[]>(
|
||||
getResourceAttributeQueriesFromURL(),
|
||||
);
|
||||
|
||||
const [optionsData, setOptionsData] = useState<OptionsData>({
|
||||
mode: undefined,
|
||||
options: [],
|
||||
});
|
||||
|
||||
const handleLoading = (isLoading: boolean): void => {
|
||||
setLoading(isLoading);
|
||||
if (isLoading) {
|
||||
setOptionsData({ mode: undefined, options: [] });
|
||||
}
|
||||
};
|
||||
|
||||
const dispatchQueries = useCallback(
|
||||
(queries: IResourceAttribute[]): void => {
|
||||
history.replace({
|
||||
pathname,
|
||||
search:
|
||||
queries && queries.length
|
||||
? `?resourceAttribute=${encode(JSON.stringify(queries))}`
|
||||
: '',
|
||||
});
|
||||
setQueries(queries);
|
||||
},
|
||||
[pathname],
|
||||
);
|
||||
|
||||
const [state, send] = useMachine(ResourceAttributesFilterMachine, {
|
||||
actions: {
|
||||
onSelectTagKey: () => {
|
||||
handleLoading(true);
|
||||
GetTagKeys()
|
||||
.then((tagKeys) =>
|
||||
setOptionsData({
|
||||
options: mappingWithRoutesAndKeys(pathname, tagKeys),
|
||||
mode: undefined,
|
||||
}),
|
||||
)
|
||||
.finally(() => {
|
||||
handleLoading(false);
|
||||
});
|
||||
},
|
||||
onSelectOperator: () => {
|
||||
setOptionsData({ options: OperatorSchema, mode: undefined });
|
||||
},
|
||||
onSelectTagValue: () => {
|
||||
handleLoading(true);
|
||||
|
||||
GetTagValues(staging[0])
|
||||
.then((tagValuesOptions) =>
|
||||
setOptionsData({ options: tagValuesOptions, mode: 'multiple' }),
|
||||
)
|
||||
.finally(() => {
|
||||
handleLoading(false);
|
||||
});
|
||||
},
|
||||
onBlurPurge: () => {
|
||||
setSelectedQueries([]);
|
||||
setStaging([]);
|
||||
},
|
||||
onValidateQuery: (): void => {
|
||||
if (staging.length < 2 || selectedQuery.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const generatedQuery = createQuery([...staging, selectedQuery]);
|
||||
if (generatedQuery) {
|
||||
dispatchQueries([...queries, generatedQuery]);
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const handleFocus = useCallback((): void => {
|
||||
if (state.value === 'Idle') {
|
||||
send('NEXT');
|
||||
}
|
||||
}, [send, state.value]);
|
||||
|
||||
const handleBlur = useCallback((): void => {
|
||||
send('onBlur');
|
||||
}, [send]);
|
||||
|
||||
const handleChange = useCallback(
|
||||
(value: string): void => {
|
||||
if (!optionsData.mode) {
|
||||
setStaging((prevStaging) => [...prevStaging, value]);
|
||||
setSelectedQueries([]);
|
||||
send('NEXT');
|
||||
return;
|
||||
}
|
||||
|
||||
setSelectedQueries([...value]);
|
||||
},
|
||||
[optionsData.mode, send],
|
||||
);
|
||||
|
||||
const handleClose = useCallback(
|
||||
(id: string): void => {
|
||||
dispatchQueries(queries.filter((queryData) => queryData.id !== id));
|
||||
},
|
||||
[dispatchQueries, queries],
|
||||
);
|
||||
|
||||
const handleClearAll = useCallback(() => {
|
||||
send('RESET');
|
||||
dispatchQueries([]);
|
||||
setStaging([]);
|
||||
setQueries([]);
|
||||
setOptionsData({ mode: undefined, options: [] });
|
||||
}, [dispatchQueries, send]);
|
||||
|
||||
const getVisibleQueries = useMemo(() => {
|
||||
if (pathname === ROUTES.SERVICE_MAP) {
|
||||
return queries.filter((query) => whilelistedKeys.includes(query.tagKey));
|
||||
}
|
||||
return queries;
|
||||
}, [queries, pathname]);
|
||||
|
||||
const value: IResourceAttributeProps = useMemo(
|
||||
() => ({
|
||||
queries: getVisibleQueries,
|
||||
staging,
|
||||
handleClearAll,
|
||||
handleClose,
|
||||
handleBlur,
|
||||
handleFocus,
|
||||
loading,
|
||||
handleChange,
|
||||
selectedQuery,
|
||||
optionsData,
|
||||
}),
|
||||
[
|
||||
handleBlur,
|
||||
handleChange,
|
||||
handleClearAll,
|
||||
handleClose,
|
||||
handleFocus,
|
||||
loading,
|
||||
staging,
|
||||
selectedQuery,
|
||||
optionsData,
|
||||
getVisibleQueries,
|
||||
],
|
||||
);
|
||||
|
||||
return (
|
||||
<ResourceContext.Provider value={value}>{children}</ResourceContext.Provider>
|
||||
);
|
||||
}
|
||||
|
||||
interface Props {
|
||||
children: React.ReactNode;
|
||||
}
|
||||
|
||||
export default ResourceProvider;
|
5
frontend/src/hooks/useResourceAttribute/config.ts
Normal file
5
frontend/src/hooks/useResourceAttribute/config.ts
Normal file
@ -0,0 +1,5 @@
|
||||
export const whilelistedKeys = [
|
||||
'resource_deployment_environment',
|
||||
'resource_k8s_cluster_name',
|
||||
'resource_k8s_cluster_namespace',
|
||||
];
|
7
frontend/src/hooks/useResourceAttribute/context.ts
Normal file
7
frontend/src/hooks/useResourceAttribute/context.ts
Normal file
@ -0,0 +1,7 @@
|
||||
import { createContext } from 'react';
|
||||
|
||||
import { IResourceAttributeProps } from './types';
|
||||
|
||||
export const ResourceContext = createContext<IResourceAttributeProps>(
|
||||
{} as IResourceAttributeProps,
|
||||
);
|
7
frontend/src/hooks/useResourceAttribute/index.ts
Normal file
7
frontend/src/hooks/useResourceAttribute/index.ts
Normal file
@ -0,0 +1,7 @@
|
||||
import ResourceProvider from './ResourceProvider';
|
||||
import useResourceAttribute from './useResourceAttribute';
|
||||
import { convertMetricKeyToTrace, isResourceEmpty } from './utils';
|
||||
|
||||
export default useResourceAttribute;
|
||||
|
||||
export { convertMetricKeyToTrace, isResourceEmpty, ResourceProvider };
|
61
frontend/src/hooks/useResourceAttribute/machine.ts
Normal file
61
frontend/src/hooks/useResourceAttribute/machine.ts
Normal file
@ -0,0 +1,61 @@
|
||||
import { createMachine } from 'xstate';
|
||||
|
||||
export const ResourceAttributesFilterMachine =
|
||||
/** @xstate-layout N4IgpgJg5mDOIC5QBECGsAWAjA9qgThAAQDKYBAxhkQIIB2xAYgJYA2ALmPgHQAqqUANJgAngGIAcgFEAGrwDaABgC6iUAAccsZu2Y46akAA9EATkUB2bgEYAbBYsBWWwA5HAFkW3F7gDQgRRABaU3duFwsXAGZbWwAmF3co01jTAF80-zRMXAJiMkpqeiY2Th5+IVExfQAhVgBXfCVVJBBNbV19QxMEcys7B2c3T28-AOC4xUduKItrSbiEuNMo6zcMrPRsPEJScnwqWgYiFg4uPgFhcQAlKRIpBRVDdp09A1aevpt7J1cPLx8-kCCCCcUcURmcwWSxWa0cGxA2W2eT2hSOJTOPAA8uouKh2Dh8JJZI8WhotK8uh9EPM4tYZl4IrZHNY1rZrEDgqFwpEoi43HEnMt3NYEUjcrsCgcisdTmVuDi8QSibUGk0nq0Xp13qAerT6VFGRZmayXOzOSDJtNZrT3I44t5bHaLGKthL8vtDsUTqVzor8PjCWJbvdSc8KdrujTFgajSa2RzxpbwZDbfbHc7XTkdh60d65ecKgA1VANMDVOh1RrNcMdN6GYFBayOKw2xZ2h1eZ3+PX2+mxFzWEWmFymBxRLPIyWemUY+XF0v1cshh41zUR+vUhDNuncAdD6wjscWKIW0FTVPt9NdluT92o6Xon2Y7gASQgrHL0jka-JdapuqIPEcTcIoihxHyTh2Pa-JntyETRO4ngig6yTuBkmQgHQOAQHAhjijmD5erKvr4LWlI6sYiDJIo3Aiieh7Gk4UynkmQRRJ44TARYijJC4AJRBOmEESiUrEXOhaXKI5GRluPG0SkI7uIKhr2vaZ7Nq2cxrGByQWKYpiisJbqEWJs7PvK-qBmR67-pReq6aB1g+DEkEcaYcQaS2l7gTCqzrMZ2aiTOT4FuUAglmWMmboB258hCESmNeLgQR4jheVp8y+SlsIBZsQXTnmJEvu+n7RQBVEIEkLh0dYDFjvYjgsRlqY6bxY4GUZGRAA */
|
||||
createMachine({
|
||||
tsTypes: {} as import('./machine.typegen').Typegen0,
|
||||
initial: 'Idle',
|
||||
states: {
|
||||
TagKey: {
|
||||
on: {
|
||||
NEXT: {
|
||||
actions: 'onSelectOperator',
|
||||
target: 'Operator',
|
||||
},
|
||||
onBlur: {
|
||||
actions: 'onBlurPurge',
|
||||
target: 'Idle',
|
||||
},
|
||||
RESET: {
|
||||
target: 'Idle',
|
||||
},
|
||||
},
|
||||
},
|
||||
Operator: {
|
||||
on: {
|
||||
NEXT: {
|
||||
actions: 'onSelectTagValue',
|
||||
target: 'TagValue',
|
||||
},
|
||||
onBlur: {
|
||||
actions: 'onBlurPurge',
|
||||
target: 'Idle',
|
||||
},
|
||||
RESET: {
|
||||
target: 'Idle',
|
||||
},
|
||||
},
|
||||
},
|
||||
TagValue: {
|
||||
on: {
|
||||
onBlur: {
|
||||
actions: ['onValidateQuery', 'onBlurPurge'],
|
||||
target: 'Idle',
|
||||
},
|
||||
RESET: {
|
||||
target: 'Idle',
|
||||
},
|
||||
},
|
||||
},
|
||||
Idle: {
|
||||
on: {
|
||||
NEXT: {
|
||||
actions: 'onSelectTagKey',
|
||||
description: 'Select Category',
|
||||
target: 'TagKey',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
id: 'ResourceAttributesFilterMachine',
|
||||
});
|
@ -2,31 +2,31 @@
|
||||
|
||||
export interface Typegen0 {
|
||||
'@@xstate/typegen': true;
|
||||
eventsCausingActions: {
|
||||
onSelectOperator: 'NEXT';
|
||||
onBlurPurge: 'onBlur';
|
||||
onSelectTagValue: 'NEXT';
|
||||
onValidateQuery: 'onBlur';
|
||||
onSelectTagKey: 'NEXT';
|
||||
};
|
||||
internalEvents: {
|
||||
'xstate.init': { type: 'xstate.init' };
|
||||
};
|
||||
invokeSrcNameMap: {};
|
||||
missingImplementations: {
|
||||
actions:
|
||||
| 'onSelectOperator'
|
||||
| 'onBlurPurge'
|
||||
| 'onSelectOperator'
|
||||
| 'onSelectTagKey'
|
||||
| 'onSelectTagValue'
|
||||
| 'onValidateQuery'
|
||||
| 'onSelectTagKey';
|
||||
services: never;
|
||||
guards: never;
|
||||
| 'onValidateQuery';
|
||||
delays: never;
|
||||
guards: never;
|
||||
services: never;
|
||||
};
|
||||
eventsCausingActions: {
|
||||
onBlurPurge: 'onBlur';
|
||||
onSelectOperator: 'NEXT';
|
||||
onSelectTagKey: 'NEXT';
|
||||
onSelectTagValue: 'NEXT';
|
||||
onValidateQuery: 'onBlur';
|
||||
};
|
||||
eventsCausingServices: {};
|
||||
eventsCausingGuards: {};
|
||||
eventsCausingDelays: {};
|
||||
matchesStates: 'TagKey' | 'Operator' | 'TagValue' | 'Idle';
|
||||
eventsCausingGuards: {};
|
||||
eventsCausingServices: {};
|
||||
matchesStates: 'Idle' | 'Operator' | 'TagKey' | 'TagValue';
|
||||
tags: never;
|
||||
}
|
31
frontend/src/hooks/useResourceAttribute/types.ts
Normal file
31
frontend/src/hooks/useResourceAttribute/types.ts
Normal file
@ -0,0 +1,31 @@
|
||||
export interface IResourceAttribute {
|
||||
id: string;
|
||||
tagKey: string;
|
||||
operator: string;
|
||||
tagValue: string[];
|
||||
}
|
||||
|
||||
export interface IOption {
|
||||
label: string;
|
||||
value: string;
|
||||
}
|
||||
|
||||
type Modes = 'tags' | 'multiple';
|
||||
|
||||
export interface OptionsData {
|
||||
mode?: Modes;
|
||||
options: IOption[];
|
||||
}
|
||||
|
||||
export interface IResourceAttributeProps {
|
||||
queries: IResourceAttribute[];
|
||||
staging: string[];
|
||||
handleClearAll: VoidFunction;
|
||||
handleClose: (id: string) => void;
|
||||
handleBlur: VoidFunction;
|
||||
handleFocus: VoidFunction;
|
||||
loading: boolean;
|
||||
handleChange: (value: string) => void;
|
||||
selectedQuery: string[];
|
||||
optionsData: OptionsData;
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
import { useContext } from 'react';
|
||||
|
||||
import { ResourceContext } from './context';
|
||||
import { IResourceAttributeProps } from './types';
|
||||
|
||||
const useResourceAttribute = (): IResourceAttributeProps =>
|
||||
useContext(ResourceContext);
|
||||
|
||||
export default useResourceAttribute;
|
154
frontend/src/hooks/useResourceAttribute/utils.ts
Normal file
154
frontend/src/hooks/useResourceAttribute/utils.ts
Normal file
@ -0,0 +1,154 @@
|
||||
import {
|
||||
getResourceAttributesTagKeys,
|
||||
getResourceAttributesTagValues,
|
||||
} from 'api/metrics/getResourceAttributes';
|
||||
import { OperatorConversions } from 'constants/resourceAttributes';
|
||||
import ROUTES from 'constants/routes';
|
||||
import {
|
||||
IOption,
|
||||
IResourceAttribute,
|
||||
IResourceAttributeProps,
|
||||
} from 'hooks/useResourceAttribute/types';
|
||||
import { decode } from 'js-base64';
|
||||
import history from 'lib/history';
|
||||
import { IQueryBuilderTagFilterItems } from 'types/api/dashboard/getAll';
|
||||
import { OperatorValues, Tags } from 'types/reducer/trace';
|
||||
import { v4 as uuid } from 'uuid';
|
||||
|
||||
import { whilelistedKeys } from './config';
|
||||
|
||||
/**
|
||||
* resource_x_y -> x.y
|
||||
*/
|
||||
export const convertMetricKeyToTrace = (key: string): string => {
|
||||
const splittedKey = key.split('_');
|
||||
|
||||
if (splittedKey.length <= 1) {
|
||||
return '';
|
||||
}
|
||||
return splittedKey.splice(1).join('.');
|
||||
};
|
||||
|
||||
/**
|
||||
* x.y -> resource_x_y
|
||||
*/
|
||||
export const convertTraceKeyToMetric = (key: string): string => {
|
||||
const splittedKey = key.split('.');
|
||||
return `resource_${splittedKey.join('_')}`;
|
||||
};
|
||||
|
||||
export const convertOperatorLabelToMetricOperator = (label: string): string =>
|
||||
OperatorConversions.find((operator) => operator.label === label)
|
||||
?.metricValue || '';
|
||||
|
||||
export const convertOperatorLabelToTraceOperator = (
|
||||
label: string,
|
||||
): OperatorValues =>
|
||||
OperatorConversions.find((operator) => operator.label === label)
|
||||
?.traceValue as OperatorValues;
|
||||
|
||||
export const convertRawQueriesToTraceSelectedTags = (
|
||||
queries: IResourceAttribute[],
|
||||
tagType = 'ResourceAttribute',
|
||||
): Tags[] =>
|
||||
queries.map((query) => ({
|
||||
Key: convertMetricKeyToTrace(query.tagKey),
|
||||
Operator: convertOperatorLabelToTraceOperator(query.operator),
|
||||
StringValues: query.tagValue,
|
||||
NumberValues: [],
|
||||
BoolValues: [],
|
||||
TagType: tagType,
|
||||
}));
|
||||
|
||||
/* Convert resource attributes to tagFilter items for queryBuilder */
|
||||
export const resourceAttributesToTagFilterItems = (
|
||||
queries: IResourceAttribute[],
|
||||
): IQueryBuilderTagFilterItems[] =>
|
||||
queries.map((res) => ({
|
||||
id: `${res.id}`,
|
||||
key: `${res.tagKey}`,
|
||||
op: `${res.operator}`,
|
||||
value: `${res.tagValue}`.split(','),
|
||||
}));
|
||||
|
||||
export const OperatorSchema: IOption[] = OperatorConversions.map(
|
||||
(operator) => ({
|
||||
label: operator.label,
|
||||
value: operator.label,
|
||||
}),
|
||||
);
|
||||
|
||||
export const GetTagKeys = async (): Promise<IOption[]> => {
|
||||
const { payload } = await getResourceAttributesTagKeys({
|
||||
metricName: 'signoz_calls_total',
|
||||
match: 'resource_',
|
||||
});
|
||||
if (!payload || !payload?.data) {
|
||||
return [];
|
||||
}
|
||||
return payload.data.map((tagKey: string) => ({
|
||||
label: convertMetricKeyToTrace(tagKey),
|
||||
value: tagKey,
|
||||
}));
|
||||
};
|
||||
|
||||
export const GetTagValues = async (tagKey: string): Promise<IOption[]> => {
|
||||
const { payload } = await getResourceAttributesTagValues({
|
||||
tagKey,
|
||||
metricName: 'signoz_calls_total',
|
||||
});
|
||||
|
||||
if (!payload || !payload?.data) {
|
||||
return [];
|
||||
}
|
||||
return payload.data.map((tagValue: string) => ({
|
||||
label: tagValue,
|
||||
value: tagValue,
|
||||
}));
|
||||
};
|
||||
|
||||
export const createQuery = (
|
||||
selectedItems: Array<string | string[]> = [],
|
||||
): IResourceAttribute | null => {
|
||||
if (selectedItems.length === 3) {
|
||||
return {
|
||||
id: uuid().slice(0, 8),
|
||||
tagKey: selectedItems[0] as string,
|
||||
operator: selectedItems[1] as string,
|
||||
tagValue: selectedItems[2] as string[],
|
||||
};
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
export function getResourceAttributeQueriesFromURL(): IResourceAttribute[] {
|
||||
const resourceAttributeQuery = new URLSearchParams(
|
||||
history.location.search,
|
||||
).get('resourceAttribute');
|
||||
|
||||
try {
|
||||
if (resourceAttributeQuery) {
|
||||
return JSON.parse(decode(resourceAttributeQuery)) as IResourceAttribute[];
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
export const isResourceEmpty = (
|
||||
queries: IResourceAttributeProps['queries'],
|
||||
staging: IResourceAttributeProps['staging'],
|
||||
selectedQuery: IResourceAttributeProps['selectedQuery'],
|
||||
): boolean => !!(queries.length || staging.length || selectedQuery.length);
|
||||
|
||||
export const mappingWithRoutesAndKeys = (
|
||||
pathname: string,
|
||||
filters: IOption[],
|
||||
): IOption[] => {
|
||||
if (ROUTES.SERVICE_MAP === pathname) {
|
||||
return filters.filter((filter) => whilelistedKeys.includes(filter.value));
|
||||
}
|
||||
return filters;
|
||||
};
|
@ -1,76 +0,0 @@
|
||||
import { OperatorConversions } from 'constants/resourceAttributes';
|
||||
import { IResourceAttributeQuery } from 'container/MetricsApplication/ResourceAttributesFilter/types';
|
||||
import { IQueryBuilderTagFilterItems } from 'types/api/dashboard/getAll';
|
||||
import { OperatorValues, Tags } from 'types/reducer/trace';
|
||||
|
||||
/**
|
||||
* resource_x_y -> x.y
|
||||
*/
|
||||
export const convertMetricKeyToTrace = (key: string): string => {
|
||||
const splittedKey = key.split('_');
|
||||
|
||||
if (splittedKey.length <= 1) {
|
||||
return '';
|
||||
}
|
||||
return splittedKey.splice(1).join('.');
|
||||
};
|
||||
|
||||
/**
|
||||
* x.y -> resource_x_y
|
||||
*/
|
||||
export const convertTraceKeyToMetric = (key: string): string => {
|
||||
const splittedKey = key.split('.');
|
||||
return `resource_${splittedKey.join('_')}`;
|
||||
};
|
||||
|
||||
export const convertOperatorLabelToMetricOperator = (label: string): string =>
|
||||
OperatorConversions.find((operator) => operator.label === label)
|
||||
?.metricValue || '';
|
||||
|
||||
export const convertOperatorLabelToTraceOperator = (
|
||||
label: string,
|
||||
): OperatorValues =>
|
||||
OperatorConversions.find((operator) => operator.label === label)
|
||||
?.traceValue as OperatorValues;
|
||||
|
||||
export const convertRawQueriesToTraceSelectedTags = (
|
||||
queries: IResourceAttributeQuery[],
|
||||
): Tags[] =>
|
||||
queries.map((query) => ({
|
||||
Key: convertMetricKeyToTrace(query.tagKey),
|
||||
Operator: convertOperatorLabelToTraceOperator(query.operator),
|
||||
StringValues: query.tagValue,
|
||||
NumberValues: [],
|
||||
BoolValues: [],
|
||||
}));
|
||||
|
||||
/**
|
||||
* Converts Resource Attribute Queries to PromQL query string
|
||||
*/
|
||||
export const resourceAttributesQueryToPromQL = (
|
||||
queries: IResourceAttributeQuery[],
|
||||
): string => {
|
||||
let parsedQueryString = '';
|
||||
|
||||
if (Array.isArray(queries))
|
||||
queries.forEach((query) => {
|
||||
parsedQueryString += `, ${
|
||||
query.tagKey
|
||||
}${convertOperatorLabelToMetricOperator(
|
||||
query.operator,
|
||||
)}"${query.tagValue.join('|')}"`;
|
||||
});
|
||||
|
||||
return parsedQueryString;
|
||||
};
|
||||
|
||||
/* Convert resource attributes to tagFilter items for queryBuilder */
|
||||
export const resourceAttributesToTagFilterItems = (
|
||||
queries: IResourceAttributeQuery[],
|
||||
): IQueryBuilderTagFilterItems[] =>
|
||||
queries.map((res) => ({
|
||||
id: `${res.id}`,
|
||||
key: `${res.tagKey}`,
|
||||
op: `${res.operator}`,
|
||||
value: `${res.tagValue}`.split(','),
|
||||
}));
|
56
frontend/src/modules/Servicemap/Map.tsx
Normal file
56
frontend/src/modules/Servicemap/Map.tsx
Normal file
@ -0,0 +1,56 @@
|
||||
/* eslint-disable */
|
||||
//@ts-nocheck
|
||||
import { useIsDarkMode } from 'hooks/useDarkMode';
|
||||
import React, { memo } from 'react';
|
||||
import { ForceGraph2D } from 'react-force-graph';
|
||||
|
||||
import { getGraphData, getTooltip, transformLabel } from './utils';
|
||||
|
||||
function ServiceMap({ fgRef, serviceMap }: any): JSX.Element {
|
||||
const isDarkMode = useIsDarkMode();
|
||||
|
||||
const { nodes, links } = getGraphData(serviceMap, isDarkMode);
|
||||
|
||||
const graphData = { nodes, links };
|
||||
|
||||
return (
|
||||
<ForceGraph2D
|
||||
ref={fgRef}
|
||||
cooldownTicks={100}
|
||||
graphData={graphData}
|
||||
linkLabel={getTooltip}
|
||||
linkAutoColorBy={(d) => d.target}
|
||||
linkDirectionalParticles="value"
|
||||
linkDirectionalParticleSpeed={(d) => d.value}
|
||||
nodeCanvasObject={(node, ctx) => {
|
||||
const label = transformLabel(node.id);
|
||||
const { fontSize } = node;
|
||||
ctx.font = `${fontSize}px Roboto`;
|
||||
const { width } = node;
|
||||
|
||||
ctx.fillStyle = node.color;
|
||||
ctx.beginPath();
|
||||
ctx.arc(node.x, node.y, width, 0, 2 * Math.PI, false);
|
||||
ctx.fill();
|
||||
ctx.textAlign = 'center';
|
||||
ctx.textBaseline = 'middle';
|
||||
ctx.fillStyle = isDarkMode ? '#ffffff' : '#000000';
|
||||
ctx.fillText(label, node.x, node.y);
|
||||
}}
|
||||
onLinkHover={(node) => {
|
||||
const tooltip = document.querySelector('.graph-tooltip');
|
||||
if (tooltip && node) {
|
||||
tooltip.innerHTML = getTooltip(node);
|
||||
}
|
||||
}}
|
||||
nodePointerAreaPaint={(node, color, ctx) => {
|
||||
ctx.fillStyle = color;
|
||||
ctx.beginPath();
|
||||
ctx.arc(node.x, node.y, 5, 0, 2 * Math.PI, false);
|
||||
ctx.fill();
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
export default memo(ServiceMap);
|
@ -3,9 +3,12 @@
|
||||
|
||||
import { Card } from 'antd';
|
||||
import Spinner from 'components/Spinner';
|
||||
import { useIsDarkMode } from 'hooks/useDarkMode';
|
||||
import TextToolTip from 'components/TextToolTip';
|
||||
import ResourceAttributesFilter from 'container/ResourceAttributesFilter';
|
||||
import useResourceAttribute from 'hooks/useResourceAttribute';
|
||||
import { whilelistedKeys } from 'hooks/useResourceAttribute/config';
|
||||
import { IResourceAttribute } from 'hooks/useResourceAttribute/types';
|
||||
import React, { useEffect, useRef } from 'react';
|
||||
import { ForceGraph2D } from 'react-force-graph';
|
||||
import { connect } from 'react-redux';
|
||||
import { RouteComponentProps, withRouter } from 'react-router-dom';
|
||||
import { getDetailedServiceMapItems, ServiceMapStore } from 'store/actions';
|
||||
@ -13,7 +16,7 @@ import { AppState } from 'store/reducers';
|
||||
import styled from 'styled-components';
|
||||
import { GlobalTime } from 'types/actions/globalTime';
|
||||
|
||||
import { getGraphData, getTooltip, getZoomPx, transformLabel } from './utils';
|
||||
import Map from './Map';
|
||||
|
||||
const Container = styled.div`
|
||||
.force-graph-container {
|
||||
@ -38,7 +41,10 @@ const Container = styled.div`
|
||||
interface ServiceMapProps extends RouteComponentProps<any> {
|
||||
serviceMap: ServiceMapStore;
|
||||
globalTime: GlobalTime;
|
||||
getDetailedServiceMapItems: (time: GlobalTime) => void;
|
||||
getDetailedServiceMapItems: (
|
||||
time: GlobalTime,
|
||||
queries: IResourceAttribute[],
|
||||
) => void;
|
||||
}
|
||||
interface graphNode {
|
||||
id: string;
|
||||
@ -60,17 +66,17 @@ export interface graphDataType {
|
||||
function ServiceMap(props: ServiceMapProps): JSX.Element {
|
||||
const fgRef = useRef();
|
||||
|
||||
const isDarkMode = useIsDarkMode();
|
||||
|
||||
const { getDetailedServiceMapItems, globalTime, serviceMap } = props;
|
||||
|
||||
const { queries } = useResourceAttribute();
|
||||
|
||||
useEffect(() => {
|
||||
/*
|
||||
Call the apis only when the route is loaded.
|
||||
Check this issue: https://github.com/SigNoz/signoz/issues/110
|
||||
*/
|
||||
getDetailedServiceMapItems(globalTime);
|
||||
}, [globalTime, getDetailedServiceMapItems]);
|
||||
getDetailedServiceMapItems(globalTime, queries);
|
||||
}, [globalTime, getDetailedServiceMapItems, queries]);
|
||||
|
||||
useEffect(() => {
|
||||
fgRef.current && fgRef.current.d3Force('charge').strength(-400);
|
||||
@ -83,51 +89,26 @@ function ServiceMap(props: ServiceMapProps): JSX.Element {
|
||||
if (!serviceMap.loading && serviceMap.items.length === 0) {
|
||||
return (
|
||||
<Container>
|
||||
<ResourceAttributesFilter />
|
||||
<Card>No Service Found</Card>
|
||||
</Container>
|
||||
);
|
||||
}
|
||||
|
||||
const { nodes, links } = getGraphData(serviceMap, isDarkMode);
|
||||
const graphData = { nodes, links };
|
||||
return (
|
||||
<Container>
|
||||
<ForceGraph2D
|
||||
ref={fgRef}
|
||||
cooldownTicks={100}
|
||||
graphData={graphData}
|
||||
linkLabel={getTooltip}
|
||||
linkAutoColorBy={(d) => d.target}
|
||||
linkDirectionalParticles="value"
|
||||
linkDirectionalParticleSpeed={(d) => d.value}
|
||||
nodeCanvasObject={(node, ctx) => {
|
||||
const label = transformLabel(node.id);
|
||||
const { fontSize } = node;
|
||||
ctx.font = `${fontSize}px Roboto`;
|
||||
const { width } = node;
|
||||
|
||||
ctx.fillStyle = node.color;
|
||||
ctx.beginPath();
|
||||
ctx.arc(node.x, node.y, width, 0, 2 * Math.PI, false);
|
||||
ctx.fill();
|
||||
ctx.textAlign = 'center';
|
||||
ctx.textBaseline = 'middle';
|
||||
ctx.fillStyle = isDarkMode ? '#ffffff' : '#000000';
|
||||
ctx.fillText(label, node.x, node.y);
|
||||
}}
|
||||
onLinkHover={(node) => {
|
||||
const tooltip = document.querySelector('.graph-tooltip');
|
||||
if (tooltip && node) {
|
||||
tooltip.innerHTML = getTooltip(node);
|
||||
}
|
||||
}}
|
||||
nodePointerAreaPaint={(node, color, ctx) => {
|
||||
ctx.fillStyle = color;
|
||||
ctx.beginPath();
|
||||
ctx.arc(node.x, node.y, 5, 0, 2 * Math.PI, false);
|
||||
ctx.fill();
|
||||
}}
|
||||
<ResourceAttributesFilter
|
||||
suffixIcon={
|
||||
<TextToolTip
|
||||
{...{
|
||||
text: `Currently, service map supports filtering of ${whilelistedKeys.join(
|
||||
', ',
|
||||
)} only, in resource attributes`,
|
||||
}}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
<Map fgRef={fgRef} serviceMap={serviceMap} />
|
||||
</Container>
|
||||
);
|
||||
}
|
||||
|
@ -4,31 +4,23 @@ import AllAlertRules from 'container/ListAlertRules';
|
||||
import TriggeredAlerts from 'container/TriggeredAlerts';
|
||||
import React from 'react';
|
||||
|
||||
const { TabPane } = Tabs;
|
||||
|
||||
function AllAlertList(): JSX.Element {
|
||||
const items = [
|
||||
{ label: 'Alert Rules', key: 'Alert Rules', children: <AllAlertRules /> },
|
||||
{
|
||||
label: 'Triggered Alerts',
|
||||
key: 'Triggered Alerts',
|
||||
children: <TriggeredAlerts />,
|
||||
},
|
||||
// {
|
||||
// label: 'Map Alert Channels',
|
||||
// key = 'Map Alert Channels',
|
||||
// children: <MapAlertChannels />,
|
||||
// },
|
||||
];
|
||||
|
||||
return (
|
||||
<Tabs destroyInactiveTabPane defaultActiveKey="Alert Rules">
|
||||
<TabPane tabKey="Alert Rules" tab="Alert Rules" key="Alert Rules">
|
||||
<AllAlertRules />
|
||||
</TabPane>
|
||||
|
||||
<TabPane
|
||||
tabKey="Triggered Alerts"
|
||||
key="Triggered Alerts"
|
||||
tab="Triggered Alerts"
|
||||
>
|
||||
<TriggeredAlerts />
|
||||
</TabPane>
|
||||
|
||||
{/* <TabPane
|
||||
tabKey="Map Alert Channels"
|
||||
key="Map Alert Channels"
|
||||
tab="Map Alert Channels"
|
||||
>
|
||||
<MapAlertChannels />
|
||||
</TabPane> */}
|
||||
</Tabs>
|
||||
<Tabs destroyInactiveTabPane defaultActiveKey="Alert Rules" items={items} />
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
import RouteTab from 'components/RouteTab';
|
||||
import ROUTES from 'constants/routes';
|
||||
import AllErrorsContainer from 'container/AllError';
|
||||
import ResourceAttributesFilter from 'container/ResourceAttributesFilter';
|
||||
import React from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
@ -8,18 +9,21 @@ function AllErrors(): JSX.Element {
|
||||
const { t } = useTranslation();
|
||||
|
||||
return (
|
||||
<RouteTab
|
||||
{...{
|
||||
routes: [
|
||||
{
|
||||
Component: AllErrorsContainer,
|
||||
name: t('routes.all_errors'),
|
||||
route: ROUTES.ALL_ERROR,
|
||||
},
|
||||
],
|
||||
activeKey: t('routes.all_errors'),
|
||||
}}
|
||||
/>
|
||||
<>
|
||||
<ResourceAttributesFilter />
|
||||
<RouteTab
|
||||
{...{
|
||||
routes: [
|
||||
{
|
||||
Component: AllErrorsContainer,
|
||||
name: t('routes.all_errors'),
|
||||
route: ROUTES.ALL_ERROR,
|
||||
},
|
||||
],
|
||||
activeKey: t('routes.all_errors'),
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,8 @@
|
||||
import { Typography } from 'antd';
|
||||
import Spinner from 'components/Spinner';
|
||||
import MetricsApplicationContainer from 'container/MetricsApplication';
|
||||
import { convertRawQueriesToTraceSelectedTags } from 'lib/resourceAttributes';
|
||||
import useResourceAttribute from 'hooks/useResourceAttribute';
|
||||
import { convertRawQueriesToTraceSelectedTags } from 'hooks/useResourceAttribute/utils';
|
||||
import React, { useEffect, useMemo } from 'react';
|
||||
import { connect, useSelector } from 'react-redux';
|
||||
import { useParams } from 'react-router-dom';
|
||||
@ -27,16 +28,11 @@ function MetricsApplication({ getInitialData }: MetricsProps): JSX.Element {
|
||||
>((state) => state.metrics);
|
||||
|
||||
const { servicename } = useParams<ServiceProps>();
|
||||
|
||||
const { resourceAttributeQueries } = useSelector<AppState, MetricReducer>(
|
||||
(state) => state.metrics,
|
||||
);
|
||||
const { queries } = useResourceAttribute();
|
||||
|
||||
const selectedTags = useMemo(
|
||||
() =>
|
||||
(convertRawQueriesToTraceSelectedTags(resourceAttributeQueries) as Tags[]) ||
|
||||
[],
|
||||
[resourceAttributeQueries],
|
||||
() => (convertRawQueriesToTraceSelectedTags(queries) as Tags[]) || [],
|
||||
[queries],
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
|
@ -3,10 +3,11 @@ import getLocalStorageKey from 'api/browser/localstorage/get';
|
||||
import ReleaseNote from 'components/ReleaseNote';
|
||||
import Spinner from 'components/Spinner';
|
||||
import { SKIP_ONBOARDING } from 'constants/onboarding';
|
||||
import ResourceAttributesFilter from 'container/MetricsApplication/ResourceAttributesFilter';
|
||||
import MetricTable from 'container/MetricsTable';
|
||||
import ResourceAttributesFilter from 'container/ResourceAttributesFilter';
|
||||
import { useNotifications } from 'hooks/useNotifications';
|
||||
import { convertRawQueriesToTraceSelectedTags } from 'lib/resourceAttributes';
|
||||
import useResourceAttribute from 'hooks/useResourceAttribute';
|
||||
import { convertRawQueriesToTraceSelectedTags } from 'hooks/useResourceAttribute/utils';
|
||||
import React, { useEffect, useMemo } from 'react';
|
||||
import { connect, useSelector } from 'react-redux';
|
||||
import { useLocation } from 'react-router-dom';
|
||||
@ -25,12 +26,9 @@ function Metrics({ getService }: MetricsProps): JSX.Element {
|
||||
GlobalReducer
|
||||
>((state) => state.globalTime);
|
||||
const location = useLocation();
|
||||
const {
|
||||
services,
|
||||
resourceAttributeQueries,
|
||||
error,
|
||||
errorMessage,
|
||||
} = useSelector<AppState, MetricReducer>((state) => state.metrics);
|
||||
const { services, error, errorMessage } = useSelector<AppState, MetricReducer>(
|
||||
(state) => state.metrics,
|
||||
);
|
||||
const { notifications } = useNotifications();
|
||||
|
||||
useEffect(() => {
|
||||
@ -41,12 +39,13 @@ function Metrics({ getService }: MetricsProps): JSX.Element {
|
||||
}
|
||||
}, [error, errorMessage, notifications]);
|
||||
|
||||
const { queries } = useResourceAttribute();
|
||||
|
||||
const selectedTags = useMemo(
|
||||
() =>
|
||||
(convertRawQueriesToTraceSelectedTags(resourceAttributeQueries) as Tags[]) ||
|
||||
[],
|
||||
[resourceAttributeQueries],
|
||||
() => (convertRawQueriesToTraceSelectedTags(queries, '') as Tags[]) || [],
|
||||
[queries],
|
||||
);
|
||||
|
||||
const isSkipped = getLocalStorageKey(SKIP_ONBOARDING) === 'true';
|
||||
|
||||
useEffect(() => {
|
||||
|
93
frontend/src/providers/QueryBuilder.tsx
Normal file
93
frontend/src/providers/QueryBuilder.tsx
Normal file
@ -0,0 +1,93 @@
|
||||
import React, {
|
||||
createContext,
|
||||
PropsWithChildren,
|
||||
useCallback,
|
||||
useMemo,
|
||||
useState,
|
||||
} from 'react';
|
||||
// ** Types
|
||||
// TODO: Rename Types on the Reusable type for any source
|
||||
import {
|
||||
IBuilderFormula,
|
||||
IBuilderQuery,
|
||||
} from 'types/api/queryBuilder/queryBuilderData';
|
||||
|
||||
export type QueryBuilderData = {
|
||||
queryData: IBuilderQuery[];
|
||||
queryFormulas: IBuilderFormula[];
|
||||
};
|
||||
|
||||
// ** TODO: temporary types for context, fix it during development
|
||||
export type QueryBuilderContextType = {
|
||||
queryBuilderData: QueryBuilderData;
|
||||
resetQueryBuilderData: () => void;
|
||||
handleSetQueryData: (index: number, queryData: IBuilderQuery) => void;
|
||||
handleSetFormulaData: (index: number, formulaData: IBuilderFormula) => void;
|
||||
};
|
||||
|
||||
export const QueryBuilderContext = createContext<QueryBuilderContextType>({
|
||||
queryBuilderData: { queryData: [], queryFormulas: [] },
|
||||
resetQueryBuilderData: () => {},
|
||||
handleSetQueryData: () => {},
|
||||
handleSetFormulaData: () => {},
|
||||
});
|
||||
|
||||
const initialQueryBuilderData: QueryBuilderData = {
|
||||
queryData: [],
|
||||
queryFormulas: [],
|
||||
};
|
||||
|
||||
export function QueryBuilderProvider({
|
||||
children,
|
||||
}: PropsWithChildren): JSX.Element {
|
||||
// ** TODO: get queryId from url for getting data for query builder
|
||||
// ** TODO: type the params which will be used for request of the data for query builder
|
||||
|
||||
const [queryBuilderData, setQueryBuilderData] = useState<QueryBuilderData>({
|
||||
queryData: [],
|
||||
queryFormulas: [],
|
||||
});
|
||||
|
||||
// ** TODO: Also in the future need to add AddFormula and AddQuery and remove them.
|
||||
|
||||
const resetQueryBuilderData = useCallback((): void => {
|
||||
setQueryBuilderData(initialQueryBuilderData);
|
||||
}, []);
|
||||
|
||||
const handleSetQueryData = useCallback(
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
(index: number, queryData: IBuilderQuery): void => {},
|
||||
[],
|
||||
);
|
||||
const handleSetFormulaData = useCallback(
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
(index: number, formulaData: IBuilderFormula): void => {},
|
||||
[],
|
||||
);
|
||||
|
||||
// ** TODO: Discuss with Palash how the state of the queryBuilder and queryFormulas
|
||||
// ** TODO: should be filled from url
|
||||
|
||||
// ** TODO: put these values and setter to the context value
|
||||
|
||||
const contextValues: QueryBuilderContextType = useMemo(
|
||||
() => ({
|
||||
queryBuilderData,
|
||||
resetQueryBuilderData,
|
||||
handleSetQueryData,
|
||||
handleSetFormulaData,
|
||||
}),
|
||||
[
|
||||
queryBuilderData,
|
||||
resetQueryBuilderData,
|
||||
handleSetQueryData,
|
||||
handleSetFormulaData,
|
||||
],
|
||||
);
|
||||
|
||||
return (
|
||||
<QueryBuilderContext.Provider value={contextValues}>
|
||||
{children}
|
||||
</QueryBuilderContext.Provider>
|
||||
);
|
||||
}
|
@ -1,55 +0,0 @@
|
||||
import { IResourceAttributeQuery } from 'container/MetricsApplication/ResourceAttributesFilter/types';
|
||||
import { decode, encode } from 'js-base64';
|
||||
import history from 'lib/history';
|
||||
import { resourceAttributesQueryToPromQL } from 'lib/resourceAttributes';
|
||||
import { SET_RESOURCE_ATTRIBUTE_QUERIES } from 'types/actions/metrics';
|
||||
|
||||
export function GetResourceAttributeQueriesFromURL():
|
||||
| IResourceAttributeQuery[]
|
||||
| null {
|
||||
const resourceAttributeQuery = new URLSearchParams(
|
||||
history.location.search,
|
||||
).get('resourceAttribute');
|
||||
|
||||
try {
|
||||
if (resourceAttributeQuery) {
|
||||
return JSON.parse(
|
||||
decode(resourceAttributeQuery),
|
||||
) as IResourceAttributeQuery[];
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
export const SetResourceAttributeQueriesFromURL = (
|
||||
queries: IResourceAttributeQuery[],
|
||||
): void => {
|
||||
history.push({
|
||||
pathname: history.location.pathname,
|
||||
search:
|
||||
queries && queries.length
|
||||
? `?resourceAttribute=${encode(JSON.stringify(queries))}`
|
||||
: '',
|
||||
});
|
||||
};
|
||||
export const SetResourceAttributeQueries = (
|
||||
queries: IResourceAttributeQuery[],
|
||||
): {
|
||||
type: typeof SET_RESOURCE_ATTRIBUTE_QUERIES;
|
||||
payload: {
|
||||
queries: IResourceAttributeQuery[];
|
||||
promQLQuery: string;
|
||||
};
|
||||
} => {
|
||||
SetResourceAttributeQueriesFromURL(queries);
|
||||
return {
|
||||
type: SET_RESOURCE_ATTRIBUTE_QUERIES,
|
||||
payload: {
|
||||
queries,
|
||||
promQLQuery: resourceAttributesQueryToPromQL(queries),
|
||||
},
|
||||
};
|
||||
};
|
@ -1,4 +1,6 @@
|
||||
import api from 'api';
|
||||
import { IResourceAttribute } from 'hooks/useResourceAttribute/types';
|
||||
import { convertRawQueriesToTraceSelectedTags } from 'hooks/useResourceAttribute/utils';
|
||||
import { Dispatch } from 'redux';
|
||||
import { GlobalTime } from 'types/actions/globalTime';
|
||||
|
||||
@ -30,16 +32,17 @@ export interface ServiceMapLoading {
|
||||
};
|
||||
}
|
||||
|
||||
export const getDetailedServiceMapItems = (globalTime: GlobalTime) => async (
|
||||
dispatch: Dispatch,
|
||||
): Promise<void> => {
|
||||
export const getDetailedServiceMapItems = (
|
||||
globalTime: GlobalTime,
|
||||
queries: IResourceAttribute[],
|
||||
) => async (dispatch: Dispatch): Promise<void> => {
|
||||
const start = `${globalTime.minTime}`;
|
||||
const end = `${globalTime.maxTime}`;
|
||||
|
||||
const serviceMapPayload = {
|
||||
start,
|
||||
end,
|
||||
tags: [],
|
||||
tags: convertRawQueriesToTraceSelectedTags(queries),
|
||||
};
|
||||
const [dependencyGraphResponse] = await Promise.all([
|
||||
api.post<ServicesMapItem[]>(`/dependency_graph`, serviceMapPayload),
|
||||
|
@ -1,5 +1,3 @@
|
||||
import { resourceAttributesQueryToPromQL } from 'lib/resourceAttributes';
|
||||
import { GetResourceAttributeQueriesFromURL } from 'store/actions/metrics/setResourceAttributeQueries';
|
||||
import {
|
||||
GET_INITIAL_APPLICATION_ERROR,
|
||||
GET_INITIAL_APPLICATION_LOADING,
|
||||
@ -9,7 +7,6 @@ import {
|
||||
GET_SERVICE_LIST_SUCCESS,
|
||||
MetricsActions,
|
||||
RESET_INITIAL_APPLICATION_DATA,
|
||||
SET_RESOURCE_ATTRIBUTE_QUERIES,
|
||||
} from 'types/actions/metrics';
|
||||
import InitialValueTypes from 'types/reducer/metrics';
|
||||
|
||||
@ -25,10 +22,6 @@ const InitialValue: InitialValueTypes = {
|
||||
externalAverageDuration: [],
|
||||
externalError: [],
|
||||
serviceOverview: [],
|
||||
resourceAttributeQueries: GetResourceAttributeQueriesFromURL() || [],
|
||||
resourceAttributePromQLQuery: resourceAttributesQueryToPromQL(
|
||||
GetResourceAttributeQueriesFromURL() || [],
|
||||
),
|
||||
topLevelOperations: [],
|
||||
};
|
||||
|
||||
@ -110,15 +103,6 @@ const metrics = (
|
||||
};
|
||||
}
|
||||
|
||||
case SET_RESOURCE_ATTRIBUTE_QUERIES: {
|
||||
const { queries, promQLQuery } = action.payload;
|
||||
return {
|
||||
...state,
|
||||
resourceAttributeQueries: queries,
|
||||
resourceAttributePromQLQuery: promQLQuery,
|
||||
};
|
||||
}
|
||||
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
|
@ -1,8 +1,3 @@
|
||||
// import { DBOverView } from 'types/api/metrics/getDBOverview';
|
||||
// import { ExternalAverageDuration } from 'types/api/metrics/getExternalAverageDuration';
|
||||
// import { ExternalError } from 'types/api/metrics/getExternalError';
|
||||
// import { ExternalService } from 'types/api/metrics/getExternalService';
|
||||
import { IResourceAttributeQuery } from 'container/MetricsApplication/ResourceAttributesFilter/types';
|
||||
import { ServicesList } from 'types/api/metrics/getService';
|
||||
import { ServiceOverview } from 'types/api/metrics/getServiceOverview';
|
||||
import { TopOperations } from 'types/api/metrics/getTopOperations';
|
||||
@ -15,7 +10,6 @@ export const GET_INITIAL_APPLICATION_LOADING =
|
||||
export const GET_INITIAL_APPLICATION_ERROR = 'GET_INITIAL_APPLICATION_ERROR';
|
||||
export const GET_INTIAL_APPLICATION_DATA = 'GET_INTIAL_APPLICATION_DATA';
|
||||
export const RESET_INITIAL_APPLICATION_DATA = 'RESET_INITIAL_APPLICATION_DATA';
|
||||
export const SET_RESOURCE_ATTRIBUTE_QUERIES = 'SET_RESOURCE_ATTRIBUTE_QUERIES';
|
||||
|
||||
export interface GetServiceList {
|
||||
type: typeof GET_SERVICE_LIST_SUCCESS;
|
||||
@ -52,18 +46,9 @@ export interface ResetInitialApplicationData {
|
||||
type: typeof RESET_INITIAL_APPLICATION_DATA;
|
||||
}
|
||||
|
||||
export interface SetResourceAttributeQueries {
|
||||
type: typeof SET_RESOURCE_ATTRIBUTE_QUERIES;
|
||||
payload: {
|
||||
queries: IResourceAttributeQuery[];
|
||||
promQLQuery: string;
|
||||
};
|
||||
}
|
||||
|
||||
export type MetricsActions =
|
||||
| GetServiceListError
|
||||
| GetServiceListLoading
|
||||
| GetServiceList
|
||||
| GetInitialApplicationData
|
||||
| ResetInitialApplicationData
|
||||
| SetResourceAttributeQueries;
|
||||
| ResetInitialApplicationData;
|
||||
|
@ -1,4 +1,5 @@
|
||||
import { GlobalTime } from 'types/actions/globalTime';
|
||||
import { Tags } from 'types/reducer/trace';
|
||||
|
||||
export type Order = 'ascending' | 'descending';
|
||||
export type OrderBy =
|
||||
@ -17,6 +18,7 @@ export interface Props {
|
||||
offset?: number;
|
||||
exceptionType?: string;
|
||||
serviceName?: string;
|
||||
tags?: Tags[];
|
||||
}
|
||||
|
||||
export interface Exception {
|
||||
|
@ -1,10 +1,12 @@
|
||||
import { GlobalTime } from 'types/actions/globalTime';
|
||||
import { Tags } from 'types/reducer/trace';
|
||||
|
||||
export type Props = {
|
||||
start: GlobalTime['minTime'];
|
||||
end: GlobalTime['minTime'];
|
||||
exceptionType: string;
|
||||
serviceName: string;
|
||||
tags: Tags[];
|
||||
};
|
||||
|
||||
export type PayloadProps = number;
|
||||
|
22
frontend/src/types/api/queryBuilder/queryBuilderData.ts
Normal file
22
frontend/src/types/api/queryBuilder/queryBuilderData.ts
Normal file
@ -0,0 +1,22 @@
|
||||
import { EAggregateOperator, EReduceOperator } from 'types/common/dashboard';
|
||||
|
||||
import { IQueryBuilderTagFilters } from '../dashboard/getAll';
|
||||
|
||||
export interface IBuilderQuery {
|
||||
// TODO: add another list of operator depended from data source
|
||||
aggregateOperator: EAggregateOperator;
|
||||
disabled: boolean;
|
||||
label: string;
|
||||
legend: string;
|
||||
attribute: string;
|
||||
groupBy: string[];
|
||||
tagFilters: IQueryBuilderTagFilters;
|
||||
reduceTo?: EReduceOperator;
|
||||
}
|
||||
|
||||
export interface IBuilderFormula {
|
||||
expression: string;
|
||||
disabled: boolean;
|
||||
label: string;
|
||||
legend: string;
|
||||
}
|
5
frontend/src/types/common/queryBuilder.ts
Normal file
5
frontend/src/types/common/queryBuilder.ts
Normal file
@ -0,0 +1,5 @@
|
||||
export enum DataSource {
|
||||
METRICS = 'metrics',
|
||||
TRACES = 'traces',
|
||||
LOGS = 'logs',
|
||||
}
|
4
frontend/src/types/common/select.ts
Normal file
4
frontend/src/types/common/select.ts
Normal file
@ -0,0 +1,4 @@
|
||||
export type SelectOption<Value, Label extends unknown = string> = {
|
||||
value: Value;
|
||||
label: Label;
|
||||
};
|
@ -1,4 +1,3 @@
|
||||
import { IResourceAttributeQuery } from 'container/MetricsApplication/ResourceAttributesFilter/types';
|
||||
import { DBOverView } from 'types/api/metrics/getDBOverview';
|
||||
import { ExternalAverageDuration } from 'types/api/metrics/getExternalAverageDuration';
|
||||
import { ExternalError } from 'types/api/metrics/getExternalError';
|
||||
@ -19,8 +18,6 @@ interface MetricReducer {
|
||||
externalAverageDuration: ExternalAverageDuration[];
|
||||
externalError: ExternalError[];
|
||||
serviceOverview: ServiceOverview[];
|
||||
resourceAttributeQueries: IResourceAttributeQuery[];
|
||||
resourceAttributePromQLQuery: string;
|
||||
topLevelOperations: string[];
|
||||
}
|
||||
|
||||
|
13
go.mod
13
go.mod
@ -13,11 +13,13 @@ require (
|
||||
github.com/gosimple/slug v1.10.0
|
||||
github.com/jmoiron/sqlx v1.3.4
|
||||
github.com/json-iterator/go v1.1.12
|
||||
github.com/knadh/koanf v1.5.0
|
||||
github.com/mailru/easyjson v0.7.7
|
||||
github.com/mattn/go-sqlite3 v2.0.3+incompatible
|
||||
github.com/minio/minio-go/v6 v6.0.57
|
||||
github.com/mitchellh/mapstructure v1.5.0
|
||||
github.com/oklog/oklog v0.3.2
|
||||
github.com/open-telemetry/opamp-go v0.5.0
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/posthog/posthog-go v0.0.0-20220817142604-0b0bbf0f9c0f
|
||||
github.com/prometheus/common v0.39.0
|
||||
@ -28,8 +30,10 @@ require (
|
||||
github.com/sethvargo/go-password v0.2.0
|
||||
github.com/smartystreets/goconvey v1.6.4
|
||||
github.com/soheilhy/cmux v0.1.5
|
||||
go.opentelemetry.io/collector/confmap v0.70.0
|
||||
go.uber.org/zap v1.24.0
|
||||
gopkg.in/segmentio/analytics-go.v3 v3.1.0
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
k8s.io/apimachinery v0.26.0
|
||||
)
|
||||
|
||||
@ -66,17 +70,20 @@ require (
|
||||
github.com/beevik/etree v1.1.0 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.2.0 // indirect
|
||||
github.com/form3tech-oss/jwt-go v3.2.5+incompatible // indirect
|
||||
github.com/gorilla/websocket v1.5.0 // indirect
|
||||
github.com/jonboulle/clockwork v0.2.2 // indirect
|
||||
github.com/josharian/intern v1.0.0 // indirect
|
||||
github.com/klauspost/cpuid v1.2.3 // indirect
|
||||
github.com/mattermost/xml-roundtrip-validator v0.1.0 // indirect
|
||||
github.com/minio/md5-simd v1.1.0 // indirect
|
||||
github.com/minio/sha256-simd v0.1.1 // indirect
|
||||
github.com/mitchellh/copystructure v1.2.0 // indirect
|
||||
github.com/mitchellh/reflectwalk v1.0.2 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/prometheus/client_golang v1.14.0 // indirect
|
||||
go.opentelemetry.io/collector/featuregate v0.70.0 // indirect
|
||||
gopkg.in/ini.v1 v1.67.0 // indirect
|
||||
gopkg.in/square/go-jose.v2 v2.6.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
)
|
||||
|
||||
require (
|
||||
@ -116,7 +123,7 @@ require (
|
||||
github.com/sirupsen/logrus v1.9.0 // indirect
|
||||
github.com/smartystreets/assertions v1.1.0
|
||||
github.com/spaolacci/murmur3 v1.1.0 // indirect
|
||||
github.com/stretchr/testify v1.8.1
|
||||
github.com/stretchr/testify v1.8.2
|
||||
github.com/xtgo/uuid v0.0.0-20140804021211-a0b114877d4c // indirect
|
||||
go.opentelemetry.io/otel v1.11.2 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.11.2 // indirect
|
||||
@ -131,7 +138,7 @@ require (
|
||||
golang.org/x/time v0.3.0 // indirect
|
||||
google.golang.org/appengine v1.6.7 // indirect
|
||||
google.golang.org/grpc v1.51.0
|
||||
google.golang.org/protobuf v1.28.1 // indirect
|
||||
google.golang.org/protobuf v1.28.1
|
||||
gopkg.in/yaml.v2 v2.4.0
|
||||
)
|
||||
|
||||
|
141
go.sum
141
go.sum
@ -89,13 +89,27 @@ github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137/go.mod h1:OMCwj8V
|
||||
github.com/andybalholm/brotli v1.0.4 h1:V7DdXeJtZscaqfNuAdSRuRFzuiKlHSC/Zh3zl9qY3JY=
|
||||
github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
|
||||
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
|
||||
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
|
||||
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
|
||||
github.com/armon/go-metrics v0.4.0 h1:yCQqn7dwca4ITXb+CbubHmedzaQYHhNhrEXLYUeEe8Q=
|
||||
github.com/armon/go-metrics v0.4.0/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4=
|
||||
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
|
||||
github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
|
||||
github.com/auth0/go-jwt-middleware v1.0.1 h1:/fsQ4vRr4zod1wKReUH+0A3ySRjGiT9G34kypO/EKwI=
|
||||
github.com/auth0/go-jwt-middleware v1.0.1/go.mod h1:YSeUX3z6+TF2H+7padiEqNJ73Zy9vXW72U//IgN0BIM=
|
||||
github.com/aws/aws-sdk-go v1.38.35/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro=
|
||||
github.com/aws/aws-sdk-go v1.44.159 h1:9odtuHAYQE9tQKyuX6ny1U1MHeH5/yzeCJi96g9H4DU=
|
||||
github.com/aws/aws-sdk-go v1.44.159/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI=
|
||||
github.com/aws/aws-sdk-go-v2 v1.9.2/go.mod h1:cK/D0BBs0b/oWPIcX/Z/obahJK1TT7IPVjy53i/mX/4=
|
||||
github.com/aws/aws-sdk-go-v2/config v1.8.3/go.mod h1:4AEiLtAb8kLs7vgw2ZV3p2VZ1+hBavOc84hqxVNpCyw=
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.4.3/go.mod h1:FNNC6nQZQUuyhq5aE5c7ata8o9e4ECGmS4lAXC7o1mQ=
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.6.0/go.mod h1:gqlclDEZp4aqJOancXK6TN24aKhT0W0Ae9MHk3wzTMM=
|
||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.2.4/go.mod h1:ZcBrrI3zBKlhGFNYWvju0I3TR93I7YIgAfy82Fh4lcQ=
|
||||
github.com/aws/aws-sdk-go-v2/service/appconfig v1.4.2/go.mod h1:FZ3HkCe+b10uFZZkFdvf98LHW21k49W8o8J366lqVKY=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.3.2/go.mod h1:72HRZDLMtmVQiLG2tLfQcaWLCssELvGl+Zf2WVxMmR8=
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.4.2/go.mod h1:NBvT9R1MEF+Ud6ApJKM0G+IkPchKS7p7c2YPKwHmBOk=
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.7.2/go.mod h1:8EzeIqfWt2wWT4rJVu3f21TfrhJ8AEMzVybRNSb/b4g=
|
||||
github.com/aws/smithy-go v1.8.0/go.mod h1:SObp3lf9smib00L/v3U2eAKG8FyQ7iLrJnQiAmR5n+E=
|
||||
github.com/beevik/etree v1.1.0 h1:T0xke/WvNtMoCqgzPhkX2r4rjY3GDZFi+FjpRZY2Jbs=
|
||||
github.com/beevik/etree v1.1.0/go.mod h1:r8Aw8JqVegEf0w2fDnATrX9VpkMcyFeM0FhwO62wh+A=
|
||||
github.com/benbjohnson/clock v1.3.0 h1:ip6w0uFQkncKQ979AypyG0ER7mqUSBdKLOgAle/AT8A=
|
||||
@ -104,6 +118,7 @@ github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24
|
||||
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
||||
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
|
||||
github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 h1:DDGfHa7BWjL4YnC6+E63dPcxHo2sUxDIu8g3QgEJdRY=
|
||||
github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4=
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
@ -130,6 +145,8 @@ github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWH
|
||||
github.com/cncf/xds/go v0.0.0-20220314180256-7f1daf1720fc h1:PYXxkRUBGUMa5xgMVMDl62vEklZvKpVaxQeN9ie7Hfk=
|
||||
github.com/coreos/go-oidc/v3 v3.4.0 h1:xz7elHb/LDwm/ERpwHd+5nb7wFHL32rsr6bBOgaeu6g=
|
||||
github.com/coreos/go-oidc/v3 v3.4.0/go.mod h1:eHUXhZtXPQLgEaDrOVTgwbgmz1xGOkJNye6h3zkD2Pw=
|
||||
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
||||
github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
@ -159,12 +176,16 @@ github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.
|
||||
github.com/envoyproxy/go-control-plane v0.10.3 h1:xdCVXxEe0Y3FQith+0cj2irwZudqGYvecuLB1HtdexY=
|
||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||
github.com/envoyproxy/protoc-gen-validate v0.9.1 h1:PS7VIOgmSVhWUEeZwTe7z7zouA22Cr590PzXKbZHOVY=
|
||||
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
||||
github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU=
|
||||
github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
|
||||
github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
|
||||
github.com/felixge/httpsnoop v1.0.3 h1:s/nj+GCswXYzN5v2DpNMuMQYe+0DDwt5WVCU6CWBdXk=
|
||||
github.com/felixge/httpsnoop v1.0.3/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
|
||||
github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k=
|
||||
github.com/form3tech-oss/jwt-go v3.2.5+incompatible h1:/l4kBbb4/vGSsdtB5nUe8L7B9mImVMaBPw9L/0TBHU8=
|
||||
github.com/form3tech-oss/jwt-go v3.2.5+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k=
|
||||
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
||||
github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
|
||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
github.com/go-faster/city v1.0.1 h1:4WAxSZ3V2Ws4QRDrscLEDcibJY8uf41H6AhXDrNDcGw=
|
||||
@ -181,6 +202,7 @@ github.com/go-kit/kit v0.12.0/go.mod h1:lHd+EkCZPIwYItmGDDRdhinkzX2A1sj+M9biaEai
|
||||
github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY=
|
||||
github.com/go-kit/log v0.2.1 h1:MRVx0/zhvdseW+Gza6N9rVzU/IVzaeE1SFI4raAhmBU=
|
||||
github.com/go-kit/log v0.2.1/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0=
|
||||
github.com/go-ldap/ldap v3.0.2+incompatible/go.mod h1:qfd9rJvER9Q0/D/Sqn1DfHRoBp40uXYvFoEVrNEPqRc=
|
||||
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
||||
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
||||
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
|
||||
@ -201,7 +223,9 @@ github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LB
|
||||
github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE=
|
||||
github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
|
||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||
github.com/go-test/deep v1.0.2-0.20181118220953-042da051cf31/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA=
|
||||
github.com/go-zookeeper/zk v1.0.3 h1:7M2kwOsc//9VeeFiPtf+uSJlVpU66x9Ba5+8XK7/TDg=
|
||||
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
||||
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||
@ -239,6 +263,7 @@ github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaS
|
||||
github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM=
|
||||
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
|
||||
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
|
||||
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
@ -304,30 +329,63 @@ github.com/gorilla/mux v1.7.4/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB7
|
||||
github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
|
||||
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
|
||||
github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
|
||||
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/gosimple/slug v1.10.0 h1:3XbiQua1IpCdrvuntWvGBxVm+K99wCSxJjlxkP49GGQ=
|
||||
github.com/gosimple/slug v1.10.0/go.mod h1:MICb3w495l9KNdZm+Xn5b6T2Hn831f9DMxiJ1r+bAjw=
|
||||
github.com/gosimple/unidecode v1.0.0 h1:kPdvM+qy0tnk4/BrnkrbdJ82xe88xn7c9hcaipDz4dQ=
|
||||
github.com/gosimple/unidecode v1.0.0/go.mod h1:CP0Cr1Y1kogOtx0bJblKzsVWrqYaqfNOnHzpgWw4Awc=
|
||||
github.com/grafana/regexp v0.0.0-20221122212121-6b5c0a4cb7fd h1:PpuIBO5P3e9hpqBD0O/HjhShYuM6XE0i/lbE6J94kww=
|
||||
github.com/grafana/regexp v0.0.0-20221122212121-6b5c0a4cb7fd/go.mod h1:M5qHK+eWfAv8VR/265dIuEpL3fNfeC21tXXp9itM24A=
|
||||
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
|
||||
github.com/hashicorp/consul v1.1.1-0.20180615161029-bed22a81e9fd h1:u6o+bd6FHxDKoCSa8PJ5vrHhAYSKgJtAHQtLO1EYgos=
|
||||
github.com/hashicorp/consul v1.1.1-0.20180615161029-bed22a81e9fd/go.mod h1:mFrjN1mfidgJfYP1xrJCF+AfRhr6Eaqhb2+sfyn/OOI=
|
||||
github.com/hashicorp/consul/api v1.13.0/go.mod h1:ZlVrynguJKcYr54zGaDbaL3fOvKC9m72FhPvA8T35KQ=
|
||||
github.com/hashicorp/consul/sdk v0.8.0/go.mod h1:GBvyrGALthsZObzUGsfgHZQDXjg4lOjagTIwIR1vPms=
|
||||
github.com/hashicorp/cronexpr v1.1.1 h1:NJZDd87hGXjoZBdvyCF9mX4DCq5Wy7+A/w+A7q0wn6c=
|
||||
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
||||
github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
|
||||
github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
|
||||
github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ=
|
||||
github.com/hashicorp/go-hclog v0.0.0-20180709165350-ff2cf002a8dd/go.mod h1:9bjs9uLqI8l75knNv3lV1kA55veR+WUPSiKIWcQHudI=
|
||||
github.com/hashicorp/go-hclog v0.8.0/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ=
|
||||
github.com/hashicorp/go-hclog v0.12.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ=
|
||||
github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
|
||||
github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc=
|
||||
github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
|
||||
github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
|
||||
github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA=
|
||||
github.com/hashicorp/go-plugin v1.0.1/go.mod h1:++UyYGoz3o5w9ZzAdZxtQKrWWP+iqPBn3cQptSMzBuY=
|
||||
github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs=
|
||||
github.com/hashicorp/go-retryablehttp v0.5.4/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs=
|
||||
github.com/hashicorp/go-retryablehttp v0.7.1 h1:sUiuQAnLlbvmExtFQs72iFW/HXeUn8Z1aJLQ4LJJbTQ=
|
||||
github.com/hashicorp/go-rootcerts v1.0.1/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8=
|
||||
github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc=
|
||||
github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8=
|
||||
github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=
|
||||
github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A=
|
||||
github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
|
||||
github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||
github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||
github.com/hashicorp/go-version v1.1.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
|
||||
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc=
|
||||
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
|
||||
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
||||
github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
|
||||
github.com/hashicorp/mdns v1.0.4/go.mod h1:mtBihi+LeNXGtG8L9dX59gAEa12BDtBQSp4v/YAJqrc=
|
||||
github.com/hashicorp/memberlist v0.3.0/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE=
|
||||
github.com/hashicorp/nomad/api v0.0.0-20221214074818-7dbbf6bc584d h1:kEWrUx7mld3c6HRcO2KhfD1MYBkofuZfEfDwCRQ9aMU=
|
||||
github.com/hashicorp/serf v0.9.6/go.mod h1:TXZNMjZQijwlDvp+r0b63xZ45H7JmCmgg4gpTwn9UV4=
|
||||
github.com/hashicorp/serf v0.10.1 h1:Z1H2J60yRKvfDYAOZLd2MU0ND4AH/WDz7xYHDWQsIPY=
|
||||
github.com/hashicorp/vault/api v1.0.4/go.mod h1:gDcqh3WGcR1cpF5AJz/B1UFheUEneMoIospckxBxk6Q=
|
||||
github.com/hashicorp/vault/sdk v0.1.13/go.mod h1:B+hVj7TpuQY1Y/GPbCpffmgd+tSEwvhkWnjtSYCaS2M=
|
||||
github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM=
|
||||
github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM=
|
||||
github.com/hetznercloud/hcloud-go v1.38.0 h1:K6Pd/mMdcLfBhvwG39qyAaacp4pCS3dKa8gChmLKxLg=
|
||||
github.com/hjson/hjson-go/v4 v4.0.0 h1:wlm6IYYqHjOdXH1gHev4VoXCaW20HdQAGCxdOEEg2cs=
|
||||
github.com/hjson/hjson-go/v4 v4.0.0/go.mod h1:KaYt3bTw3zhBjYqnXkYywcYctk0A2nxeEFTse3rH13E=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU=
|
||||
@ -338,6 +396,8 @@ github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGw
|
||||
github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
|
||||
github.com/jmoiron/sqlx v1.3.4 h1:wv+0IJZfL5z0uZoUjlpKgHkgaFSYD+r9CfrXjEXsO7w=
|
||||
github.com/jmoiron/sqlx v1.3.4/go.mod h1:2BljVx/86SuTyjE+aPYlHCTNvZrnJXghYGpNiXLBMCQ=
|
||||
github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc=
|
||||
github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=
|
||||
github.com/jonboulle/clockwork v0.2.2 h1:UOGuzwb1PwsrDAObMuhUnj0p5ULPj8V/xJ7Kx9qUBdQ=
|
||||
github.com/jonboulle/clockwork v0.2.2/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8=
|
||||
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
|
||||
@ -362,11 +422,14 @@ github.com/klauspost/compress v1.15.13 h1:NFn1Wr8cfnenSJSA46lLq4wHCcBzKTSjnBIexD
|
||||
github.com/klauspost/compress v1.15.13/go.mod h1:QPwzmACJjUTFsnSHH934V6woptycfrDDJnH7hvFVbGM=
|
||||
github.com/klauspost/cpuid v1.2.3 h1:CCtW0xUnWGVINKvE/WWOYKdsPV6mawAtvQuSl8guwQs=
|
||||
github.com/klauspost/cpuid v1.2.3/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
|
||||
github.com/knadh/koanf v1.5.0 h1:q2TSd/3Pyc/5yP9ldIrSdIz26MCcyNQzW0pEAugLPNs=
|
||||
github.com/knadh/koanf v1.5.0/go.mod h1:Hgyjp4y8v44hpZtPzs7JZfRAW5AhN7KfZcwv1RYggDs=
|
||||
github.com/kolo/xmlrpc v0.0.0-20220921171641-a4b6fa1dd06b h1:udzkj9S/zlT5X367kqJis0QP7YMxobob6zhzq6Yre00=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
|
||||
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
|
||||
@ -382,12 +445,22 @@ github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0
|
||||
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
|
||||
github.com/mattermost/xml-roundtrip-validator v0.1.0 h1:RXbVD2UAl7A7nOTR4u7E3ILa4IbtvKBHw64LDsmu9hU=
|
||||
github.com/mattermost/xml-roundtrip-validator v0.1.0/go.mod h1:qccnGMcpgwcNaBnxqpJpWWUiPNr5H3O8eDgGV9gT5To=
|
||||
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
||||
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
||||
github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
||||
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||
github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84=
|
||||
github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE=
|
||||
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||
github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
|
||||
github.com/mattn/go-sqlite3 v2.0.3+incompatible h1:gXHsfypPkaMZrKbD5209QV9jbUTJKjyR5WD3HYQSd+U=
|
||||
github.com/mattn/go-sqlite3 v2.0.3+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
|
||||
github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso=
|
||||
github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI=
|
||||
github.com/miekg/dns v1.1.50 h1:DQUfb9uc6smULcREF09Uc+/Gd46YWqJd5DbpPE9xkcA=
|
||||
github.com/minio/md5-simd v1.1.0 h1:QPfiOqlZH+Cj9teu0t9b1nTBfPbyTl16Of5MeuShdK4=
|
||||
github.com/minio/md5-simd v1.1.0/go.mod h1:XpBqgZULrMYD3R+M28PcmP0CkI7PEMzB3U77ZrKZ0Gw=
|
||||
@ -395,10 +468,23 @@ github.com/minio/minio-go/v6 v6.0.57 h1:ixPkbKkyD7IhnluRgQpGSpHdpvNVaW6OD5R9IAO/
|
||||
github.com/minio/minio-go/v6 v6.0.57/go.mod h1:5+R/nM9Pwrh0vqF+HbYYDQ84wdUFPyXHkrdT4AIkifM=
|
||||
github.com/minio/sha256-simd v0.1.1 h1:5QHSlgo3nt5yKOJrC7W8w7X+NFl8cMPZm96iu8kKUJU=
|
||||
github.com/minio/sha256-simd v0.1.1/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM=
|
||||
github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
|
||||
github.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI=
|
||||
github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw=
|
||||
github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw=
|
||||
github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s=
|
||||
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
|
||||
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||
github.com/mitchellh/go-testing-interface v0.0.0-20171004221916-a61a99592b77/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
|
||||
github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
|
||||
github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo=
|
||||
github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
|
||||
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||
github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
|
||||
github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ=
|
||||
github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
@ -410,21 +496,29 @@ github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq
|
||||
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f h1:KUppIJq7/+SVif2QVs3tOP0zanoHgBEVAwHxUSIzRqU=
|
||||
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||
github.com/npillmayer/nestext v0.1.3/go.mod h1:h2lrijH8jpicr25dFY+oAJLyzlya6jhnuG+zWp9L0Uk=
|
||||
github.com/oklog/oklog v0.3.2 h1:wVfs8F+in6nTBMkA7CbRw+zZMIB7nNM825cM1wuzoTk=
|
||||
github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtbWGs=
|
||||
github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA=
|
||||
github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA=
|
||||
github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU=
|
||||
github.com/oklog/ulid v1.3.1 h1:EGfNDEx6MqHz8B3uNV6QAib1UR2Lm97sHi3ocA6ESJ4=
|
||||
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
|
||||
github.com/open-telemetry/opamp-go v0.5.0 h1:2YFbb6G4qBkq3yTRdVb5Nfz9hKHW/ldUyex352e1J7g=
|
||||
github.com/open-telemetry/opamp-go v0.5.0/go.mod h1:IMdeuHGVc5CjKSu5/oNV0o+UmiXuahoHvoZ4GOmAI9M=
|
||||
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
|
||||
github.com/opencontainers/image-spec v1.0.3-0.20211202183452-c5a74bcca799 h1:rc3tiVYb5z54aKaDfakKn0dDjIyPpTtszkjuMzyt7ec=
|
||||
github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs=
|
||||
github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc=
|
||||
github.com/ovh/go-ovh v1.3.0 h1:mvZaddk4E4kLcXhzb+cxBsMPYp2pHqiQpWYkInsuZPQ=
|
||||
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
|
||||
github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
|
||||
github.com/paulmach/orb v0.8.0 h1:W5XAt5yNPNnhaMNEf0xNSkBMJ1LzOzdk2MRlB6EN0Vs=
|
||||
github.com/paulmach/orb v0.8.0/go.mod h1:FWRlTgl88VI1RBx/MkrwWDRhQ96ctqMCh8boXhmqB/A=
|
||||
github.com/paulmach/protoscan v0.2.1/go.mod h1:SpcSwydNLrxUGSDvXvO0P7g7AuhJ7lcKfDlhJCDw2gY=
|
||||
github.com/pelletier/go-toml v1.7.0 h1:7utD74fnzVc/cpcyy8sjrlFr5vYpypUixARcHIMIGuI=
|
||||
github.com/pelletier/go-toml v1.7.0/go.mod h1:vwGMzjaWMwyfHwgIBhI2YUM4fB6nL6lVAvS1LBMMhTE=
|
||||
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
|
||||
github.com/pierrec/lz4/v4 v4.1.17 h1:kV4Ip+/hUBC+8T6+2EgburRtkE9ef4nbY3f4dFhGjMc=
|
||||
github.com/pierrec/lz4/v4 v4.1.17/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
|
||||
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
|
||||
@ -434,6 +528,8 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
|
||||
github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s=
|
||||
github.com/posthog/posthog-go v0.0.0-20220817142604-0b0bbf0f9c0f h1:h0p1aZ9F5d6IXOygysob3g4B07b+HuVUQC0VJKD8wA4=
|
||||
github.com/posthog/posthog-go v0.0.0-20220817142604-0b0bbf0f9c0f/go.mod h1:oa2sAs9tGai3VldabTV0eWejt/O4/OOD7azP8GaikqU=
|
||||
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
||||
@ -441,6 +537,7 @@ github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5Fsn
|
||||
github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU=
|
||||
github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=
|
||||
github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0=
|
||||
github.com/prometheus/client_golang v1.11.1/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0=
|
||||
github.com/prometheus/client_golang v1.14.0 h1:nJdhIvne2eSX/XRAFV9PcvFFRbrjbcTUj0VP62TMhnw=
|
||||
github.com/prometheus/client_golang v1.14.0/go.mod h1:8vpkKitgIVNcqrRBWh1C4TIUQgYNtG/XQE4E/Zae36Y=
|
||||
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||
@ -465,6 +562,7 @@ github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4O
|
||||
github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
|
||||
github.com/prometheus/procfs v0.8.0 h1:ODq8ZFEaYeCaZOJlZZdJA2AbQR98dSHSM1KW/You5mo=
|
||||
github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0uaxHdg830/4=
|
||||
github.com/rhnvrm/simples3 v0.6.1/go.mod h1:Y+3vYm2V7Y4VijFoJHHTrja6OgPrJ2cBti8dPGkC3sA=
|
||||
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
|
||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
|
||||
@ -477,7 +575,11 @@ github.com/russellhaering/gosaml2 v0.8.0/go.mod h1:byViER/1YPUa0Puj9ROZblpoq2jsE
|
||||
github.com/russellhaering/goxmldsig v1.2.0 h1:Y6GTTc9Un5hCxSzVz4UIWQ/zuVwDvzJk80guqzwx6Vg=
|
||||
github.com/russellhaering/goxmldsig v1.2.0/go.mod h1:gM4MDENBQf7M+V824SGfyIUVFWydB7n0KkEubVJl+Tw=
|
||||
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
|
||||
github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
|
||||
github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc=
|
||||
github.com/scaleway/scaleway-sdk-go v1.0.0-beta.10 h1:wsfMs0iv+MJiViM37qh5VEKISi3/ZUq2nNKNdqmumAs=
|
||||
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
|
||||
github.com/segmentio/asm v1.2.0 h1:9BQrFxC+YOHJlTlHGkTrFWf59nbL3XnCoFLTwDCI7ys=
|
||||
github.com/segmentio/asm v1.2.0/go.mod h1:BqMnlJP91P8d+4ibuonYZw9mfnzI9HfxselHZr5aAcs=
|
||||
github.com/segmentio/backo-go v1.0.0 h1:kbOAtGJY2DqOR0jfRkYEorx/b18RgtepGtY3+Cpe6qA=
|
||||
@ -506,6 +608,7 @@ github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasO
|
||||
github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI=
|
||||
github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
||||
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
||||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
@ -518,8 +621,8 @@ github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
|
||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8=
|
||||
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM=
|
||||
github.com/urfave/cli v1.22.5/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
|
||||
github.com/urfave/negroni v1.0.0 h1:kIimOitoypq34K7TG7DUaJ9kq/N4Ofuwi1sjz0KipXc=
|
||||
@ -533,6 +636,9 @@ github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
go.etcd.io/etcd/api/v3 v3.5.4/go.mod h1:5GB2vv4A4AOn3yk7MftYGHkUfGtDHnEraIjym4dYz5A=
|
||||
go.etcd.io/etcd/client/pkg/v3 v3.5.4/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g=
|
||||
go.etcd.io/etcd/client/v3 v3.5.4/go.mod h1:ZaRkVgBZC+L+dLCjTcF1hRXpgZXQPOvnA/Ak/gq3kiY=
|
||||
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
||||
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
|
||||
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
@ -540,6 +646,10 @@ go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk=
|
||||
go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E=
|
||||
go.opentelemetry.io/collector/confmap v0.70.0 h1:GJDaM7c3yFyT7Zv6l2/5ahwaqPCvtC92Ii8Bg2AVdjU=
|
||||
go.opentelemetry.io/collector/confmap v0.70.0/go.mod h1:8//JWR2TMChLH35Az0mGFrCskEIP6POgZJK6iRRhzeM=
|
||||
go.opentelemetry.io/collector/featuregate v0.70.0 h1:Xr6hrMT/++SjTm06nreex8WlpgFhYJ7S0yRVn1OvVf8=
|
||||
go.opentelemetry.io/collector/featuregate v0.70.0/go.mod h1:ih+oCwrHW3bLac/qnPUzes28yDCDmh8WzsAKKauwCYI=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.37.0 h1:yt2NKzK7Vyo6h0+X8BA4FpreZQTlVEIarnsBP/H5mzs=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.37.0/go.mod h1:+ARmXlUlc51J7sZeCBkBJNdHGySrdOzgzxp6VWRWM1U=
|
||||
go.opentelemetry.io/otel v1.11.2 h1:YBZcQlsVekzFsFbjygXMOXSs6pialIZxcjfO/mBDmR0=
|
||||
@ -549,12 +659,15 @@ go.opentelemetry.io/otel/metric v0.34.0/go.mod h1:ZFuI4yQGNCupurTXCwkeD/zHBt+C2b
|
||||
go.opentelemetry.io/otel/trace v1.11.2 h1:Xf7hWSF2Glv0DE3MH7fBHvtpSBsjcBUe5MYAmZM/+y0=
|
||||
go.opentelemetry.io/otel/trace v1.11.2/go.mod h1:4N+yC7QEz7TTsG9BSRLNAa63eg5E06ObSbKPmxQ/pKA=
|
||||
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
|
||||
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
||||
go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ=
|
||||
go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
|
||||
go.uber.org/goleak v1.2.0 h1:xqgm/S+aQvhWFTtR0XK3Jvg7z8kGV8P4X14IzwN3Eqk=
|
||||
go.uber.org/goleak v1.2.0/go.mod h1:XJYK+MuIchqpmGmUSAzotztawfKvYLUIgg7guXrwVUo=
|
||||
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
|
||||
go.uber.org/multierr v1.9.0 h1:7fIwc/ZtS0q++VgcfqFDxSBZVv/Xo49/SYnDFupUwlI=
|
||||
go.uber.org/multierr v1.9.0/go.mod h1:X2jQV1h+kxSjClGpnseKVIxpmcjrj7MNnI0bnlfKTVQ=
|
||||
go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo=
|
||||
go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60=
|
||||
go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg=
|
||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
@ -562,6 +675,7 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk
|
||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190513172903-22d7a77e9e5f/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
@ -622,6 +736,7 @@ golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLL
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
@ -645,6 +760,7 @@ golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc=
|
||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||
golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8=
|
||||
golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
@ -697,11 +813,15 @@ golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJ
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
|
||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190129075346-302c3dd5f1cc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
@ -709,12 +829,19 @@ golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
@ -736,10 +863,12 @@ golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
@ -776,6 +905,7 @@ golang.org/x/term v0.3.0 h1:qoo4akIqOcDME5bhc/NgxUdovd6BSS2uMsVjB56q1xI=
|
||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1-0.20181227161524-e6919f6577db/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
@ -804,6 +934,7 @@ golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgw
|
||||
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
@ -902,6 +1033,7 @@ google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6
|
||||
google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190404172233-64821d5d2107/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
@ -979,9 +1111,11 @@ google.golang.org/genproto v0.0.0-20220523171625-347a074981d8/go.mod h1:RAyBrSAP
|
||||
google.golang.org/genproto v0.0.0-20220608133413-ed9918b62aac/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA=
|
||||
google.golang.org/genproto v0.0.0-20220616135557-88e70c0c3a90/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA=
|
||||
google.golang.org/genproto v0.0.0-20221207170731-23e4bf6bdc37 h1:jmIfw8+gSvXcZSgaFAGyInDXeWzUhvYH57G/5GKMn70=
|
||||
google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
||||
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
||||
google.golang.org/grpc v1.22.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
|
||||
google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||
@ -1030,6 +1164,7 @@ google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqw
|
||||
google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w=
|
||||
google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||
gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d/go.mod h1:cuepJuh7vyXfUyUwEgHQXw849cJrilpS5NeIjOWESAw=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
@ -1042,6 +1177,7 @@ gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
|
||||
gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||
gopkg.in/segmentio/analytics-go.v3 v3.1.0 h1:UzxH1uaGZRpMKDhJyBz0pexz6yUoBU3x8bJsRk/HV6U=
|
||||
gopkg.in/segmentio/analytics-go.v3 v3.1.0/go.mod h1:4QqqlTlSSpVlWA9/9nDcPw+FkM2yv1NQoYjUbL9/JAw=
|
||||
gopkg.in/square/go-jose.v2 v2.3.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
|
||||
gopkg.in/square/go-jose.v2 v2.6.0 h1:NGk74WTnPKBNUhNzQX7PYcTLUjoq7mzKk2OKbvwk2iI=
|
||||
gopkg.in/square/go-jose.v2 v2.6.0/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
|
||||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
@ -1078,4 +1214,5 @@ rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
|
||||
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
|
||||
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo=
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.2.3 h1:PRbqxJClWWYMNV1dhaG4NsibJbArud9kFxnAMREiWFE=
|
||||
sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc=
|
||||
sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo=
|
||||
|
241
pkg/query-service/agentConf/db.go
Normal file
241
pkg/query-service/agentConf/db.go
Normal file
@ -0,0 +1,241 @@
|
||||
package agentConf
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/jmoiron/sqlx"
|
||||
"go.signoz.io/signoz/pkg/query-service/agentConf/sqlite"
|
||||
"go.signoz.io/signoz/pkg/query-service/model"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
func init() {
|
||||
rand.Seed(2000)
|
||||
}
|
||||
|
||||
// Repo handles DDL and DML ops on ingestion rules
|
||||
type Repo struct {
|
||||
db *sqlx.DB
|
||||
}
|
||||
|
||||
func (r *Repo) initDB(engine string) error {
|
||||
switch engine {
|
||||
case "sqlite3", "sqlite":
|
||||
return sqlite.InitDB(r.db)
|
||||
default:
|
||||
return fmt.Errorf("unsupported db")
|
||||
}
|
||||
}
|
||||
|
||||
func (r *Repo) GetConfigHistory(ctx context.Context, typ ElementTypeDef, limit int) ([]ConfigVersion, error) {
|
||||
var c []ConfigVersion
|
||||
err := r.db.SelectContext(ctx, &c, fmt.Sprintf(`SELECT
|
||||
version,
|
||||
id,
|
||||
element_type,
|
||||
COALESCE(created_by, -1) as created_by,
|
||||
created_at,
|
||||
COALESCE((SELECT NAME FROM users
|
||||
WHERE id = v.created_by), "unknown") created_by_name,
|
||||
active,
|
||||
is_valid,
|
||||
disabled,
|
||||
deploy_status,
|
||||
deploy_result,
|
||||
last_hash,
|
||||
last_config
|
||||
FROM agent_config_versions AS v
|
||||
WHERE element_type = $1
|
||||
ORDER BY created_at desc, version desc
|
||||
limit %v`, limit),
|
||||
typ)
|
||||
|
||||
return c, err
|
||||
}
|
||||
|
||||
func (r *Repo) GetConfigVersion(ctx context.Context, typ ElementTypeDef, v int) (*ConfigVersion, error) {
|
||||
var c ConfigVersion
|
||||
err := r.db.GetContext(ctx, &c, `SELECT
|
||||
id,
|
||||
version,
|
||||
element_type,
|
||||
COALESCE(created_by, -1) as created_by,
|
||||
created_at,
|
||||
COALESCE((SELECT NAME FROM users
|
||||
WHERE id = v.created_by), "unknown") created_by_name,
|
||||
active,
|
||||
is_valid,
|
||||
disabled,
|
||||
deploy_status,
|
||||
deploy_result,
|
||||
last_hash,
|
||||
last_config
|
||||
FROM agent_config_versions v
|
||||
WHERE element_type = $1
|
||||
AND version = $2`, typ, v)
|
||||
|
||||
return &c, err
|
||||
|
||||
}
|
||||
|
||||
func (r *Repo) GetLatestVersion(ctx context.Context, typ ElementTypeDef) (*ConfigVersion, error) {
|
||||
var c ConfigVersion
|
||||
err := r.db.GetContext(ctx, &c, `SELECT
|
||||
id,
|
||||
version,
|
||||
element_type,
|
||||
COALESCE(created_by, -1) as created_by,
|
||||
created_at,
|
||||
COALESCE((SELECT NAME FROM users
|
||||
WHERE id = v.created_by), "unknown") created_by_name,
|
||||
active,
|
||||
is_valid,
|
||||
disabled,
|
||||
deploy_status,
|
||||
deploy_result
|
||||
FROM agent_config_versions AS v
|
||||
WHERE element_type = $1
|
||||
AND version = (
|
||||
SELECT MAX(version)
|
||||
FROM agent_config_versions
|
||||
WHERE element_type=$2)`, typ, typ)
|
||||
if err != nil {
|
||||
zap.S().Error("failed get latest config version for element:", typ, err)
|
||||
}
|
||||
return &c, err
|
||||
}
|
||||
|
||||
func (r *Repo) insertConfig(ctx context.Context, userId string, c *ConfigVersion, elements []string) (fnerr error) {
|
||||
|
||||
if string(c.ElementType) == "" {
|
||||
return fmt.Errorf("element type is required for creating agent config version")
|
||||
}
|
||||
|
||||
if len(elements) == 0 {
|
||||
zap.S().Error("insert config called with no elements", c.ElementType)
|
||||
return fmt.Errorf("config must have atleast one element")
|
||||
}
|
||||
|
||||
if c.Version != 0 {
|
||||
// the version can not be set by the user, we want to auto-assign the versions
|
||||
// in a monotonically increasing order starting with 1. hence, we reject insert
|
||||
// requests with version anything other than 0. here, 0 indicates un-assigned
|
||||
zap.S().Error("invalid version assignment while inserting agent config", c.Version, c.ElementType)
|
||||
return fmt.Errorf("user defined versions are not supported in the agent config")
|
||||
}
|
||||
|
||||
configVersion, err := r.GetLatestVersion(ctx, c.ElementType)
|
||||
if err != nil {
|
||||
if err != sql.ErrNoRows {
|
||||
zap.S().Error("failed to fetch latest config version", err)
|
||||
return fmt.Errorf("failed to fetch latest config version")
|
||||
}
|
||||
}
|
||||
|
||||
c.Version = updateVersion(configVersion.Version)
|
||||
|
||||
defer func() {
|
||||
if fnerr != nil {
|
||||
// remove all the damage (invalid rows from db)
|
||||
r.db.Exec("DELETE FROM agent_config_versions WHERE id = $1", c.ID)
|
||||
r.db.Exec("DELETE FROM agent_config_elements WHERE version_id=$1", c.ID)
|
||||
}
|
||||
}()
|
||||
|
||||
// insert config
|
||||
configQuery := `INSERT INTO agent_config_versions(
|
||||
id,
|
||||
version,
|
||||
created_by,
|
||||
element_type,
|
||||
active,
|
||||
is_valid,
|
||||
disabled,
|
||||
deploy_status,
|
||||
deploy_result)
|
||||
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)`
|
||||
|
||||
_, err = r.db.ExecContext(ctx,
|
||||
configQuery,
|
||||
c.ID,
|
||||
c.Version,
|
||||
userId,
|
||||
c.ElementType,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
c.DeployStatus,
|
||||
c.DeployResult)
|
||||
|
||||
if err != nil {
|
||||
zap.S().Error("error in inserting config version: ", zap.Error(err))
|
||||
return fmt.Errorf("failed to insert ingestion rule")
|
||||
}
|
||||
|
||||
elementsQuery := `INSERT INTO agent_config_elements(
|
||||
id,
|
||||
version_id,
|
||||
element_type,
|
||||
element_id)
|
||||
VALUES ($1, $2, $3, $4)`
|
||||
|
||||
for _, e := range elements {
|
||||
|
||||
_, err = r.db.ExecContext(ctx,
|
||||
elementsQuery,
|
||||
uuid.NewString(),
|
||||
c.ID,
|
||||
c.ElementType,
|
||||
e)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *Repo) updateDeployStatus(ctx context.Context,
|
||||
elementType ElementTypeDef,
|
||||
version int,
|
||||
status string,
|
||||
result string,
|
||||
lastHash string,
|
||||
lastconf string) error {
|
||||
|
||||
updateQuery := `UPDATE agent_config_versions
|
||||
set deploy_status = $1,
|
||||
deploy_result = $2,
|
||||
last_hash = COALESCE($3, last_hash),
|
||||
last_config = $4
|
||||
WHERE version=$5
|
||||
AND element_type = $6`
|
||||
|
||||
_, err := r.db.ExecContext(ctx, updateQuery, status, result, lastHash, lastconf, version, string(elementType))
|
||||
if err != nil {
|
||||
zap.S().Error("failed to update deploy status", err)
|
||||
return model.BadRequestStr("failed to update deploy status")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *Repo) updateDeployStatusByHash(ctx context.Context, confighash string, status string, result string) error {
|
||||
|
||||
updateQuery := `UPDATE agent_config_versions
|
||||
set deploy_status = $1,
|
||||
deploy_result = $2
|
||||
WHERE last_hash=$4`
|
||||
|
||||
_, err := r.db.ExecContext(ctx, updateQuery, status, result, confighash)
|
||||
if err != nil {
|
||||
zap.S().Error("failed to update deploy status", err)
|
||||
return model.BadRequestStr("failed to update deploy status")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user