Merge branch 'develop' into feat/logs
@ -215,7 +215,7 @@ Please ping us in the [`#contributing`](https://signoz-community.slack.com/archi
|
|||||||
|
|
||||||
# 4. Contribute to Backend (Query-Service) 🌑
|
# 4. Contribute to Backend (Query-Service) 🌑
|
||||||
|
|
||||||
**Need to Update:** [**https://github.com/SigNoz/signoz/tree/develop/pkg/query-service**](https://github.com/SigNoz/signoz/tree/develop/pkg/query-service)
|
[**https://github.com/SigNoz/signoz/tree/develop/pkg/query-service**](https://github.com/SigNoz/signoz/tree/develop/pkg/query-service)
|
||||||
|
|
||||||
## 4.1 To run ClickHouse setup (recommended for local development)
|
## 4.1 To run ClickHouse setup (recommended for local development)
|
||||||
|
|
||||||
|
@ -204,9 +204,14 @@ start_docker() {
|
|||||||
echo "Starting docker service"
|
echo "Starting docker service"
|
||||||
$sudo_cmd systemctl start docker.service
|
$sudo_cmd systemctl start docker.service
|
||||||
fi
|
fi
|
||||||
|
# if [[ -z $sudo_cmd ]]; then
|
||||||
|
# docker ps > /dev/null && true
|
||||||
|
# if [[ $? -ne 0 ]]; then
|
||||||
|
# request_sudo
|
||||||
|
# fi
|
||||||
|
# fi
|
||||||
if [[ -z $sudo_cmd ]]; then
|
if [[ -z $sudo_cmd ]]; then
|
||||||
docker ps > /dev/null && true
|
if ! docker ps > /dev/null && true; then
|
||||||
if [[ $? -ne 0 ]]; then
|
|
||||||
request_sudo
|
request_sudo
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
@ -268,8 +273,12 @@ request_sudo() {
|
|||||||
if (( $EUID != 0 )); then
|
if (( $EUID != 0 )); then
|
||||||
sudo_cmd="sudo"
|
sudo_cmd="sudo"
|
||||||
echo -e "Please enter your sudo password, if prompt."
|
echo -e "Please enter your sudo password, if prompt."
|
||||||
$sudo_cmd -l | grep -e "NOPASSWD: ALL" > /dev/null
|
# $sudo_cmd -l | grep -e "NOPASSWD: ALL" > /dev/null
|
||||||
if [[ $? -ne 0 ]] && ! $sudo_cmd -v; then
|
# if [[ $? -ne 0 ]] && ! $sudo_cmd -v; then
|
||||||
|
# echo "Need sudo privileges to proceed with the installation."
|
||||||
|
# exit 1;
|
||||||
|
# fi
|
||||||
|
if ! $sudo_cmd -l | grep -e "NOPASSWD: ALL" > /dev/null && ! $sudo_cmd -v; then
|
||||||
echo "Need sudo privileges to proceed with the installation."
|
echo "Need sudo privileges to proceed with the installation."
|
||||||
exit 1;
|
exit 1;
|
||||||
fi
|
fi
|
||||||
@ -303,8 +312,13 @@ echo -e "🌏 Detecting your OS ...\n"
|
|||||||
check_os
|
check_os
|
||||||
|
|
||||||
# Obtain unique installation id
|
# Obtain unique installation id
|
||||||
sysinfo="$(uname -a)"
|
# sysinfo="$(uname -a)"
|
||||||
if [[ $? -ne 0 ]]; then
|
# if [[ $? -ne 0 ]]; then
|
||||||
|
# uuid="$(uuidgen)"
|
||||||
|
# uuid="${uuid:-$(cat /proc/sys/kernel/random/uuid)}"
|
||||||
|
# sysinfo="${uuid:-$(cat /proc/sys/kernel/random/uuid)}"
|
||||||
|
# fi
|
||||||
|
if ! sysinfo="$(uname -a)"; then
|
||||||
uuid="$(uuidgen)"
|
uuid="$(uuidgen)"
|
||||||
uuid="${uuid:-$(cat /proc/sys/kernel/random/uuid)}"
|
uuid="${uuid:-$(cat /proc/sys/kernel/random/uuid)}"
|
||||||
sysinfo="${uuid:-$(cat /proc/sys/kernel/random/uuid)}"
|
sysinfo="${uuid:-$(cat /proc/sys/kernel/random/uuid)}"
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
"playwright": "NODE_ENV=testing playwright test --config=./playwright.config.ts",
|
"playwright": "NODE_ENV=testing playwright test --config=./playwright.config.ts",
|
||||||
"playwright:local:debug": "PWDEBUG=console yarn playwright --headed --browser=chromium",
|
"playwright:local:debug": "PWDEBUG=console yarn playwright --headed --browser=chromium",
|
||||||
"playwright:codegen:local":"playwright codegen http://localhost:3301",
|
"playwright:codegen:local":"playwright codegen http://localhost:3301",
|
||||||
|
"playwright:codegen:local:auth":"yarn playwright:codegen:local --load-storage=tests/auth.json",
|
||||||
"husky:configure": "cd .. && husky install frontend/.husky && cd frontend && chmod ug+x .husky/*",
|
"husky:configure": "cd .. && husky install frontend/.husky && cd frontend && chmod ug+x .husky/*",
|
||||||
"commitlint": "commitlint --edit $1"
|
"commitlint": "commitlint --edit $1"
|
||||||
},
|
},
|
||||||
|
@ -14,8 +14,8 @@ const config: PlaywrightTestConfig = {
|
|||||||
baseURL: process.env.PLAYWRIGHT_TEST_BASE_URL || 'http://localhost:3301',
|
baseURL: process.env.PLAYWRIGHT_TEST_BASE_URL || 'http://localhost:3301',
|
||||||
},
|
},
|
||||||
updateSnapshots: 'all',
|
updateSnapshots: 'all',
|
||||||
fullyParallel: false,
|
fullyParallel: !!process.env.CI,
|
||||||
quiet: true,
|
quiet: false,
|
||||||
testMatch: ['**/*.spec.ts'],
|
testMatch: ['**/*.spec.ts'],
|
||||||
reporter: process.env.CI ? 'github' : 'list',
|
reporter: process.env.CI ? 'github' : 'list',
|
||||||
};
|
};
|
||||||
|
@ -66,8 +66,12 @@ function ChartPreview({
|
|||||||
}),
|
}),
|
||||||
enabled:
|
enabled:
|
||||||
query != null &&
|
query != null &&
|
||||||
(query.queryType !== EQueryType.PROM ||
|
((query.queryType === EQueryType.PROM &&
|
||||||
(query.promQL?.length > 0 && query.promQL[0].query !== '')),
|
query.promQL?.length > 0 &&
|
||||||
|
query.promQL[0].query !== '') ||
|
||||||
|
(query.queryType === EQueryType.QUERY_BUILDER &&
|
||||||
|
query.metricsBuilder?.queryBuilder?.length > 0 &&
|
||||||
|
query.metricsBuilder?.queryBuilder[0].metricName !== '')),
|
||||||
});
|
});
|
||||||
|
|
||||||
const chartDataSet = queryResponse.isError
|
const chartDataSet = queryResponse.isError
|
||||||
|
@ -83,7 +83,7 @@ function FormAlertRules({
|
|||||||
|
|
||||||
// staged query is used to display chart preview
|
// staged query is used to display chart preview
|
||||||
const [stagedQuery, setStagedQuery] = useState<StagedQuery>();
|
const [stagedQuery, setStagedQuery] = useState<StagedQuery>();
|
||||||
const debouncedStagedQuery = useDebounce(stagedQuery, 500);
|
const debouncedStagedQuery = useDebounce(stagedQuery, 1000);
|
||||||
|
|
||||||
// this use effect initiates staged query and
|
// this use effect initiates staged query and
|
||||||
// other queries based on server data.
|
// other queries based on server data.
|
||||||
@ -177,25 +177,26 @@ function FormAlertRules({
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Object.keys(metricQueries).forEach((key) => {
|
if (queryCategory === EQueryType.QUERY_BUILDER) {
|
||||||
if (metricQueries[key].metricName === '') {
|
Object.keys(metricQueries).forEach((key) => {
|
||||||
retval = false;
|
if (metricQueries[key].metricName === '') {
|
||||||
notification.error({
|
retval = false;
|
||||||
message: 'Error',
|
notification.error({
|
||||||
description: t('metricname_missing', { where: metricQueries[key].name }),
|
message: 'Error',
|
||||||
});
|
description: t('metricname_missing', { where: metricQueries[key].name }),
|
||||||
}
|
});
|
||||||
});
|
}
|
||||||
|
});
|
||||||
Object.keys(formulaQueries).forEach((key) => {
|
Object.keys(formulaQueries).forEach((key) => {
|
||||||
if (formulaQueries[key].expression === '') {
|
if (formulaQueries[key].expression === '') {
|
||||||
retval = false;
|
retval = false;
|
||||||
notification.error({
|
notification.error({
|
||||||
message: 'Error',
|
message: 'Error',
|
||||||
description: t('expression_missing', formulaQueries[key].name),
|
description: t('expression_missing', formulaQueries[key].name),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
return retval;
|
return retval;
|
||||||
}, [t, alertDef, queryCategory, metricQueries, formulaQueries, promQueries]);
|
}, [t, alertDef, queryCategory, metricQueries, formulaQueries, promQueries]);
|
||||||
@ -235,7 +236,7 @@ function FormAlertRules({
|
|||||||
description:
|
description:
|
||||||
!ruleId || ruleId === 0 ? t('rule_created') : t('rule_edited'),
|
!ruleId || ruleId === 0 ? t('rule_created') : t('rule_edited'),
|
||||||
});
|
});
|
||||||
console.log('invalidting cache');
|
|
||||||
// invalidate rule in cache
|
// invalidate rule in cache
|
||||||
ruleCache.invalidateQueries(['ruleId', ruleId]);
|
ruleCache.invalidateQueries(['ruleId', ruleId]);
|
||||||
|
|
||||||
|
@ -18,4 +18,8 @@ const store = createStore(
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (window !== undefined) {
|
||||||
|
window.store = store;
|
||||||
|
}
|
||||||
|
|
||||||
export default store;
|
export default store;
|
||||||
|
@ -10,7 +10,9 @@ const intitalState: GlobalReducer = {
|
|||||||
maxTime: Date.now() * 1000000,
|
maxTime: Date.now() * 1000000,
|
||||||
minTime: (Date.now() - 15 * 60 * 1000) * 1000000,
|
minTime: (Date.now() - 15 * 60 * 1000) * 1000000,
|
||||||
loading: true,
|
loading: true,
|
||||||
selectedTime: getDefaultOption(window.location.pathname),
|
selectedTime: getDefaultOption(
|
||||||
|
typeof window !== 'undefined' ? window?.location?.pathname : '',
|
||||||
|
),
|
||||||
};
|
};
|
||||||
|
|
||||||
const globalTimeReducer = (
|
const globalTimeReducer = (
|
||||||
|
101
frontend/tests/expectionDetails/index.spec.ts
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
import { expect, Page, test } from '@playwright/test';
|
||||||
|
import ROUTES from 'constants/routes';
|
||||||
|
|
||||||
|
import allErrorList from '../fixtures/api/allErrors/200.json';
|
||||||
|
import errorDetailSuccess from '../fixtures/api/errorDetails/200.json';
|
||||||
|
import errorDetailNotFound from '../fixtures/api/errorDetails/404.json';
|
||||||
|
import nextPreviousSuccess from '../fixtures/api/getNextPrev/200.json';
|
||||||
|
import { loginApi } from '../fixtures/common';
|
||||||
|
import { JsonApplicationType } from '../fixtures/constant';
|
||||||
|
|
||||||
|
let page: Page;
|
||||||
|
const timestamp = '1657794588955274000';
|
||||||
|
|
||||||
|
test.describe('Expections Details', async () => {
|
||||||
|
test.beforeEach(async ({ baseURL, browser }) => {
|
||||||
|
const context = await browser.newContext({ storageState: 'tests/auth.json' });
|
||||||
|
const newPage = await context.newPage();
|
||||||
|
|
||||||
|
await loginApi(newPage);
|
||||||
|
|
||||||
|
await newPage.goto(`${baseURL}${ROUTES.APPLICATION}`);
|
||||||
|
|
||||||
|
page = newPage;
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Should have not found when api return 404', async () => {
|
||||||
|
await Promise.all([
|
||||||
|
page.route('**/errorFromGroupID**', (route) =>
|
||||||
|
route.fulfill({
|
||||||
|
status: 404,
|
||||||
|
contentType: JsonApplicationType,
|
||||||
|
body: JSON.stringify(errorDetailNotFound),
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
page.route('**/nextPrevErrorIDs**', (route) =>
|
||||||
|
route.fulfill({
|
||||||
|
status: 404,
|
||||||
|
contentType: JsonApplicationType,
|
||||||
|
body: JSON.stringify([]),
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
]);
|
||||||
|
|
||||||
|
await page.goto(
|
||||||
|
`${ROUTES.ERROR_DETAIL}?groupId=${allErrorList[0].groupID}×tamp=${timestamp}`,
|
||||||
|
{
|
||||||
|
waitUntil: 'networkidle',
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
const NoDataLocator = page.locator('text=Not Found');
|
||||||
|
const isVisible = await NoDataLocator.isVisible();
|
||||||
|
const text = await NoDataLocator.textContent();
|
||||||
|
|
||||||
|
expect(isVisible).toBe(true);
|
||||||
|
expect(text).toBe('Not Found');
|
||||||
|
expect(await page.screenshot()).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Render Success Data when 200 from details page', async () => {
|
||||||
|
await Promise.all([
|
||||||
|
page.route('**/errorFromGroupID**', (route) =>
|
||||||
|
route.fulfill({
|
||||||
|
status: 200,
|
||||||
|
contentType: JsonApplicationType,
|
||||||
|
body: JSON.stringify(errorDetailSuccess),
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
page.route('**/nextPrevErrorIDs**', (route) =>
|
||||||
|
route.fulfill({
|
||||||
|
status: 200,
|
||||||
|
contentType: JsonApplicationType,
|
||||||
|
body: JSON.stringify(nextPreviousSuccess),
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
]);
|
||||||
|
|
||||||
|
await page.goto(
|
||||||
|
`${ROUTES.ERROR_DETAIL}?groupId=${allErrorList[0].groupID}×tamp=${timestamp}`,
|
||||||
|
{
|
||||||
|
waitUntil: 'networkidle',
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
const traceDetailButton = page.locator('text=See the error in trace graph');
|
||||||
|
const olderButton = page.locator('text=Older');
|
||||||
|
const newerButton = page.locator(`text=Newer`);
|
||||||
|
|
||||||
|
expect(await traceDetailButton.isVisible()).toBe(true);
|
||||||
|
expect(await olderButton.isVisible()).toBe(true);
|
||||||
|
expect(await newerButton.isVisible()).toBe(true);
|
||||||
|
|
||||||
|
expect(await traceDetailButton.textContent()).toBe(
|
||||||
|
'See the error in trace graph',
|
||||||
|
);
|
||||||
|
expect(await olderButton.textContent()).toBe('Older');
|
||||||
|
expect(await newerButton.textContent()).toBe('Newer');
|
||||||
|
|
||||||
|
expect(await page.screenshot()).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
});
|
After Width: | Height: | Size: 183 KiB |
After Width: | Height: | Size: 39 KiB |
148
frontend/tests/expections/index.spec.ts
Normal file
@ -0,0 +1,148 @@
|
|||||||
|
import { expect, Page, test } from '@playwright/test';
|
||||||
|
import ROUTES from 'constants/routes';
|
||||||
|
|
||||||
|
import successAllErrors from '../fixtures/api/allErrors/200.json';
|
||||||
|
import { loginApi } from '../fixtures/common';
|
||||||
|
import { JsonApplicationType } from '../fixtures/constant';
|
||||||
|
|
||||||
|
const noDataTableData = async (page: Page): Promise<void> => {
|
||||||
|
const text = page.locator('text=No Data');
|
||||||
|
|
||||||
|
expect(text).toBeVisible();
|
||||||
|
expect(text).toHaveText('No Data');
|
||||||
|
|
||||||
|
const textType = [
|
||||||
|
'Exception Type',
|
||||||
|
'Error Message',
|
||||||
|
'Last Seen',
|
||||||
|
'First Seen',
|
||||||
|
'Application',
|
||||||
|
];
|
||||||
|
|
||||||
|
textType.forEach(async (text) => {
|
||||||
|
const textLocator = page.locator(`text=${text}`);
|
||||||
|
|
||||||
|
const textContent = await textLocator.textContent();
|
||||||
|
|
||||||
|
expect(textContent).toBe(text);
|
||||||
|
expect(textLocator).not.toBeNull();
|
||||||
|
|
||||||
|
expect(textLocator).toBeVisible();
|
||||||
|
await expect(textLocator).toHaveText(`${text}`);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
let page: Page;
|
||||||
|
|
||||||
|
test.describe('Expections page', async () => {
|
||||||
|
test.beforeEach(async ({ baseURL, browser }) => {
|
||||||
|
const context = await browser.newContext({ storageState: 'tests/auth.json' });
|
||||||
|
const newPage = await context.newPage();
|
||||||
|
|
||||||
|
await loginApi(newPage);
|
||||||
|
|
||||||
|
await newPage.goto(`${baseURL}${ROUTES.APPLICATION}`);
|
||||||
|
|
||||||
|
page = newPage;
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Should have a valid route', async () => {
|
||||||
|
await page.goto(ROUTES.ALL_ERROR);
|
||||||
|
|
||||||
|
await expect(page).toHaveURL(ROUTES.ALL_ERROR);
|
||||||
|
expect(await page.screenshot()).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Should have a valid Breadcrumbs', async () => {
|
||||||
|
await page.goto(ROUTES.ALL_ERROR, {
|
||||||
|
waitUntil: 'networkidle',
|
||||||
|
});
|
||||||
|
|
||||||
|
const expectionsLocator = page.locator('a:has-text("Exceptions")');
|
||||||
|
|
||||||
|
await expect(expectionsLocator).toBeVisible();
|
||||||
|
await expect(expectionsLocator).toHaveText('Exceptions');
|
||||||
|
await expect(expectionsLocator).toHaveAttribute('href', ROUTES.ALL_ERROR);
|
||||||
|
expect(await page.screenshot()).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Should render the page with 404 status', async () => {
|
||||||
|
await page.route('**listErrors', (route) =>
|
||||||
|
route.fulfill({
|
||||||
|
status: 404,
|
||||||
|
contentType: JsonApplicationType,
|
||||||
|
body: JSON.stringify([]),
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
await page.goto(ROUTES.ALL_ERROR, {
|
||||||
|
waitUntil: 'networkidle',
|
||||||
|
});
|
||||||
|
|
||||||
|
await noDataTableData(page);
|
||||||
|
expect(await page.screenshot()).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Should render the page with 500 status in antd notification with no data antd table', async () => {
|
||||||
|
await page.route(`**/listErrors**`, (route) =>
|
||||||
|
route.fulfill({
|
||||||
|
status: 500,
|
||||||
|
contentType: JsonApplicationType,
|
||||||
|
body: JSON.stringify([]),
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
await page.goto(ROUTES.ALL_ERROR, {
|
||||||
|
waitUntil: 'networkidle',
|
||||||
|
});
|
||||||
|
|
||||||
|
const text = 'Something went wrong';
|
||||||
|
|
||||||
|
const el = page.locator(`text=${text}`);
|
||||||
|
|
||||||
|
expect(el).toBeVisible();
|
||||||
|
expect(el).toHaveText(`${text}`);
|
||||||
|
expect(await el.getAttribute('disabled')).toBe(null);
|
||||||
|
|
||||||
|
await noDataTableData(page);
|
||||||
|
expect(await page.screenshot()).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Should render data in antd table', async () => {
|
||||||
|
await Promise.all([
|
||||||
|
page.route(`**/listErrors**`, (route) =>
|
||||||
|
route.fulfill({
|
||||||
|
status: 200,
|
||||||
|
contentType: JsonApplicationType,
|
||||||
|
body: JSON.stringify(successAllErrors),
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
|
||||||
|
page.route('**/countErrors**', (route) =>
|
||||||
|
route.fulfill({
|
||||||
|
status: 200,
|
||||||
|
contentType: JsonApplicationType,
|
||||||
|
body: JSON.stringify(200),
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
]);
|
||||||
|
|
||||||
|
await page.goto(ROUTES.ALL_ERROR, {
|
||||||
|
waitUntil: 'networkidle',
|
||||||
|
});
|
||||||
|
|
||||||
|
await page.evaluate(() => window.scrollTo(0, document.body.scrollHeight));
|
||||||
|
|
||||||
|
const expectionType = page.locator(
|
||||||
|
`td:has-text("${successAllErrors[1].exceptionType}")`,
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(expectionType).toBeVisible();
|
||||||
|
|
||||||
|
const second = page.locator('li > a:has-text("2") >> nth=0');
|
||||||
|
const isVisisble = await second.isVisible();
|
||||||
|
|
||||||
|
expect(isVisisble).toBe(true);
|
||||||
|
expect(await page.screenshot()).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
});
|
After Width: | Height: | Size: 60 KiB |
After Width: | Height: | Size: 42 KiB |
After Width: | Height: | Size: 115 KiB |
After Width: | Height: | Size: 60 KiB |
After Width: | Height: | Size: 58 KiB |
92
frontend/tests/fixtures/api/allErrors/200.json
vendored
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"exceptionType": "ConnectionError",
|
||||||
|
"exceptionMessage": "HTTPSConnectionPool(host='run.mocekdy.io', port=443): Max retries exceeded with url: /v3/1cwb67153-a6ac-4aae-aca6-273ed68b5d9e (Caused by NewConnectionError('\u003curllib3.connection.HTTPSConnection object at 0x108ce9c10\u003e: Failed to establish a new connection: [Errno 8] nodename nor servname provided, or not known'))",
|
||||||
|
"exceptionCount": 2,
|
||||||
|
"lastSeen": "2022-07-14T10:29:48.955274Z",
|
||||||
|
"firstSeen": "2022-07-14T10:29:48.950721Z",
|
||||||
|
"serviceName": "1rfflaskAp",
|
||||||
|
"groupID": "e24d35bda98c5499a5c8df3ba61b0238"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"exceptionType": "NameError",
|
||||||
|
"exceptionMessage": "name 'listf' is not defined",
|
||||||
|
"exceptionCount": 8,
|
||||||
|
"lastSeen": "2022-07-14T10:30:42.411035Z",
|
||||||
|
"firstSeen": "2022-07-14T10:29:45.426784Z",
|
||||||
|
"serviceName": "1rfflaskAp",
|
||||||
|
"groupID": "efc46adcd5e87b65f8f244cba683b265"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"exceptionType": "ZeroDivisionError",
|
||||||
|
"exceptionMessage": "division by zero",
|
||||||
|
"exceptionCount": 1,
|
||||||
|
"lastSeen": "2022-07-14T10:29:54.195996Z",
|
||||||
|
"firstSeen": "2022-07-14T10:29:54.195996Z",
|
||||||
|
"serviceName": "1rfflaskAp",
|
||||||
|
"groupID": "a49058b540eef9aefe159d84f1a2b6df"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"exceptionType": "MaxRetryError",
|
||||||
|
"exceptionMessage": "HTTPSConnectionPool(host='rufn.fmoceky.io', port=443): Max retries exceeded with url: /v3/b851a5c6-ab54-495a-be04-69834ae0d2a7 (Caused by NewConnectionError('\u003curllib3.connection.HTTPSConnection object at 0x108ec2640\u003e: Failed to establish a new connection: [Errno 8] nodename nor servname provided, or not known'))",
|
||||||
|
"exceptionCount": 1,
|
||||||
|
"lastSeen": "2022-07-14T10:29:49.471402Z",
|
||||||
|
"firstSeen": "2022-07-14T10:29:49.471402Z",
|
||||||
|
"serviceName": "1rfflaskAp",
|
||||||
|
"groupID": "e59d39239f4d48842d83e3cc4cf53249"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"exceptionType": "MaxRetryError",
|
||||||
|
"exceptionMessage": "HTTPSConnectionPool(host='run.mocekdy.io', port=443): Max retries exceeded with url: /v3/1cwb67153-a6ac-4aae-aca6-273ed68b5d9e (Caused by NewConnectionError('\u003curllib3.connection.HTTPSConnection object at 0x108ce9c10\u003e: Failed to establish a new connection: [Errno 8] nodename nor servname provided, or not known'))",
|
||||||
|
"exceptionCount": 1,
|
||||||
|
"lastSeen": "2022-07-14T10:29:48.947579Z",
|
||||||
|
"firstSeen": "2022-07-14T10:29:48.947579Z",
|
||||||
|
"serviceName": "1rfflaskAp",
|
||||||
|
"groupID": "14d18a6fb1cd3f541de1566530e75486"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"exceptionType": "ConnectionError",
|
||||||
|
"exceptionMessage": "HTTPSConnectionPool(host='rufn.fmoceky.io', port=443): Max retries exceeded with url: /v3/b851a5c6-ab54-495a-be04-69834ae0d2a7 (Caused by NewConnectionError('\u003curllib3.connection.HTTPSConnection object at 0x108ec2640\u003e: Failed to establish a new connection: [Errno 8] nodename nor servname provided, or not known'))",
|
||||||
|
"exceptionCount": 2,
|
||||||
|
"lastSeen": "2022-07-14T10:29:49.476718Z",
|
||||||
|
"firstSeen": "2022-07-14T10:29:49.472271Z",
|
||||||
|
"serviceName": "1rfflaskAp",
|
||||||
|
"groupID": "bf6d88d10397ca3194b96a10f4719031"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"exceptionType": "github.com/gin-gonic/gin.Error",
|
||||||
|
"exceptionMessage": "Sample Error",
|
||||||
|
"exceptionCount": 6,
|
||||||
|
"lastSeen": "2022-07-15T18:55:32.3538096Z",
|
||||||
|
"firstSeen": "2022-07-14T14:47:19.874387Z",
|
||||||
|
"serviceName": "goApp",
|
||||||
|
"groupID": "b4fd099280072d45318e1523d82aa9c1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"exceptionType": "MaxRetryError",
|
||||||
|
"exceptionMessage": "HTTPSConnectionPool(host='rufn.fmoceky.io', port=443): Max retries exceeded with url: /v3/b851a5c6-ab54-495a-be04-69834ae0d2a7 (Caused by NewConnectionError('\u003curllib3.connection.HTTPSConnection object at 0x10801b490\u003e: Failed to establish a new connection: [Errno 8] nodename nor servname provided, or not known'))",
|
||||||
|
"exceptionCount": 1,
|
||||||
|
"lastSeen": "2022-07-14T11:07:06.560593Z",
|
||||||
|
"firstSeen": "2022-07-14T11:07:06.560593Z",
|
||||||
|
"serviceName": "samplFlaskApp",
|
||||||
|
"groupID": "1945671c945b10641e73b0fe28c4d486"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"exceptionType": "ConnectionError",
|
||||||
|
"exceptionMessage": "HTTPSConnectionPool(host='rufn.fmoceky.io', port=443): Max retries exceeded with url: /v3/b851a5c6-ab54-495a-be04-69834ae0d2a7 (Caused by NewConnectionError('\u003curllib3.connection.HTTPSConnection object at 0x10801b490\u003e: Failed to establish a new connection: [Errno 8] nodename nor servname provided, or not known'))",
|
||||||
|
"exceptionCount": 2,
|
||||||
|
"lastSeen": "2022-07-14T11:07:06.56493Z",
|
||||||
|
"firstSeen": "2022-07-14T11:07:06.561074Z",
|
||||||
|
"serviceName": "samplFlaskApp",
|
||||||
|
"groupID": "5bea5295cac187404005f9c96e71aa53"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"exceptionType": "ConnectionError",
|
||||||
|
"exceptionMessage": "HTTPSConnectionPool(host='rufn.fmoceky.io', port=443): Max retries exceeded with url: /v3/b851a5c6-ab54-495a-be04-69834ae0d2a7 (Caused by NewConnectionError('\u003curllib3.connection.HTTPSConnection object at 0x108031820\u003e: Failed to establish a new connection: [Errno 8] nodename nor servname provided, or not known'))",
|
||||||
|
"exceptionCount": 2,
|
||||||
|
"lastSeen": "2022-07-14T11:07:06.363977Z",
|
||||||
|
"firstSeen": "2022-07-14T11:07:06.361163Z",
|
||||||
|
"serviceName": "samplFlaskApp",
|
||||||
|
"groupID": "52a1fbe033453d806c0f24ba39168a78"
|
||||||
|
}
|
||||||
|
]
|
12
frontend/tests/fixtures/api/errorDetails/200.json
vendored
Normal file
5
frontend/tests/fixtures/api/errorDetails/404.json
vendored
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"error": "Error/Exception not found",
|
||||||
|
"errorType": "not_found",
|
||||||
|
"status": "error"
|
||||||
|
}
|
7
frontend/tests/fixtures/api/getNextPrev/200.json
vendored
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"nextErrorID": "",
|
||||||
|
"nextTimestamp": "0001-01-01T00:00:00Z",
|
||||||
|
"prevErrorID": "217133e5f7df429abd31b507859ea513",
|
||||||
|
"prevTimestamp": "2022-07-14T10:29:48.950721Z",
|
||||||
|
"groupID": "e24d35bda98c5499a5c8df3ba61b0238"
|
||||||
|
}
|
2
frontend/tests/fixtures/constant.ts
vendored
@ -6,3 +6,5 @@ export const validPassword = 'SamplePassword98@@';
|
|||||||
|
|
||||||
export const getStartedButtonSelector = 'button[data-attr="signup"]';
|
export const getStartedButtonSelector = 'button[data-attr="signup"]';
|
||||||
export const confirmPasswordSelector = '#password-confirm-error';
|
export const confirmPasswordSelector = '#password-confirm-error';
|
||||||
|
|
||||||
|
export const JsonApplicationType = 'application/json';
|
||||||
|
@ -24,5 +24,6 @@ test.describe('Version API fail while loading login page', async () => {
|
|||||||
expect(el).toBeVisible();
|
expect(el).toBeVisible();
|
||||||
expect(el).toHaveText(`${text}`);
|
expect(el).toHaveText(`${text}`);
|
||||||
expect(await el.getAttribute('disabled')).toBe(null);
|
expect(await el.getAttribute('disabled')).toBe(null);
|
||||||
|
expect(await page.screenshot()).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
After Width: | Height: | Size: 7.9 KiB |
@ -45,5 +45,6 @@ test.describe('Login Page', () => {
|
|||||||
element.isVisible();
|
element.isVisible();
|
||||||
const text = await element.innerText();
|
const text = await element.innerText();
|
||||||
expect(text).toBe(`SigNoz ${version}`);
|
expect(text).toBe(`SigNoz ${version}`);
|
||||||
|
expect(await page.screenshot()).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
After Width: | Height: | Size: 46 KiB |
@ -16,7 +16,17 @@ test.describe('Service Page', () => {
|
|||||||
|
|
||||||
page = newPage;
|
page = newPage;
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Serice Page is rendered', async ({ baseURL }) => {
|
test('Serice Page is rendered', async ({ baseURL }) => {
|
||||||
await expect(page).toHaveURL(`${baseURL}${ROUTES.APPLICATION}`);
|
await expect(page).toHaveURL(`${baseURL}${ROUTES.APPLICATION}`);
|
||||||
|
expect(await page.screenshot()).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Logged In must be true', async () => {
|
||||||
|
const { app } = await page.evaluate(() => window.store.getState());
|
||||||
|
|
||||||
|
const { isLoggedIn } = app;
|
||||||
|
|
||||||
|
expect(isLoggedIn).toBe(true);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
After Width: | Height: | Size: 40 KiB |
@ -77,6 +77,7 @@ test.describe('Sign Up Page', () => {
|
|||||||
await buttonSignupButton.click();
|
await buttonSignupButton.click();
|
||||||
|
|
||||||
expect(page).toHaveURL(`${baseURL}${ROUTES.SIGN_UP}`);
|
expect(page).toHaveURL(`${baseURL}${ROUTES.SIGN_UP}`);
|
||||||
|
expect(await page.screenshot()).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Invite link validation', async ({ baseURL, page }) => {
|
test('Invite link validation', async ({ baseURL, page }) => {
|
||||||
@ -87,6 +88,7 @@ test.describe('Sign Up Page', () => {
|
|||||||
const messageText = await page.locator(`text=${message}`).innerText();
|
const messageText = await page.locator(`text=${message}`).innerText();
|
||||||
|
|
||||||
expect(messageText).toBe(message);
|
expect(messageText).toBe(message);
|
||||||
|
expect(await page.screenshot()).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('User Sign up with valid details', async ({ baseURL, page, context }) => {
|
test('User Sign up with valid details', async ({ baseURL, page, context }) => {
|
||||||
@ -125,6 +127,7 @@ test.describe('Sign Up Page', () => {
|
|||||||
await context.storageState({
|
await context.storageState({
|
||||||
path: 'tests/auth.json',
|
path: 'tests/auth.json',
|
||||||
});
|
});
|
||||||
|
expect(await page.screenshot()).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Empty name with valid details', async ({ baseURL, page }) => {
|
test('Empty name with valid details', async ({ baseURL, page }) => {
|
||||||
@ -142,6 +145,7 @@ test.describe('Sign Up Page', () => {
|
|||||||
const gettingStartedButton = page.locator(getStartedButtonSelector);
|
const gettingStartedButton = page.locator(getStartedButtonSelector);
|
||||||
|
|
||||||
expect(await gettingStartedButton.isDisabled()).toBe(true);
|
expect(await gettingStartedButton.isDisabled()).toBe(true);
|
||||||
|
expect(await page.screenshot()).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Empty Company name with valid details', async ({ baseURL, page }) => {
|
test('Empty Company name with valid details', async ({ baseURL, page }) => {
|
||||||
@ -159,6 +163,7 @@ test.describe('Sign Up Page', () => {
|
|||||||
const gettingStartedButton = page.locator(getStartedButtonSelector);
|
const gettingStartedButton = page.locator(getStartedButtonSelector);
|
||||||
|
|
||||||
expect(await gettingStartedButton.isDisabled()).toBe(true);
|
expect(await gettingStartedButton.isDisabled()).toBe(true);
|
||||||
|
expect(await page.screenshot()).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Empty Email with valid details', async ({ baseURL, page }) => {
|
test('Empty Email with valid details', async ({ baseURL, page }) => {
|
||||||
@ -176,6 +181,7 @@ test.describe('Sign Up Page', () => {
|
|||||||
const gettingStartedButton = page.locator(getStartedButtonSelector);
|
const gettingStartedButton = page.locator(getStartedButtonSelector);
|
||||||
|
|
||||||
expect(await gettingStartedButton.isDisabled()).toBe(true);
|
expect(await gettingStartedButton.isDisabled()).toBe(true);
|
||||||
|
expect(await page.screenshot()).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Empty Password and confirm password with valid details', async ({
|
test('Empty Password and confirm password with valid details', async ({
|
||||||
@ -200,6 +206,7 @@ test.describe('Sign Up Page', () => {
|
|||||||
// password validation message is not present
|
// password validation message is not present
|
||||||
const locator = await page.locator(confirmPasswordSelector).isVisible();
|
const locator = await page.locator(confirmPasswordSelector).isVisible();
|
||||||
expect(locator).toBe(false);
|
expect(locator).toBe(false);
|
||||||
|
expect(await page.screenshot()).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Miss Match Password and confirm password with valid details', async ({
|
test('Miss Match Password and confirm password with valid details', async ({
|
||||||
@ -220,5 +227,6 @@ test.describe('Sign Up Page', () => {
|
|||||||
// password validation message is not present
|
// password validation message is not present
|
||||||
const locator = await page.locator(confirmPasswordSelector).isVisible();
|
const locator = await page.locator(confirmPasswordSelector).isVisible();
|
||||||
expect(locator).toBe(true);
|
expect(locator).toBe(true);
|
||||||
|
expect(await page.screenshot()).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
After Width: | Height: | Size: 70 KiB |
After Width: | Height: | Size: 70 KiB |
After Width: | Height: | Size: 69 KiB |
After Width: | Height: | Size: 70 KiB |
After Width: | Height: | Size: 66 KiB |
After Width: | Height: | Size: 72 KiB |
After Width: | Height: | Size: 54 KiB |
After Width: | Height: | Size: 70 KiB |
@ -6,8 +6,37 @@ Query service is the interface between frontend and databases. It is written in
|
|||||||
- parse response from databases and handle error if any
|
- parse response from databases and handle error if any
|
||||||
- clickhouse response in the format accepted by Frontend
|
- clickhouse response in the format accepted by Frontend
|
||||||
|
|
||||||
|
# Complete the clickhouse setup locally.
|
||||||
|
https://github.com/SigNoz/signoz/blob/main/CONTRIBUTING.md#to-run-clickhouse-setup-recommended-for-local-development
|
||||||
|
|
||||||
|
- Comment out the query-service and the frontend section in `signoz/deploy/docker/clickhouse-setup/docker-compose.yaml`
|
||||||
|
- Change the alertmanager section in `signoz/deploy/docker/clickhouse-setup/docker-compose.yaml` as follows:
|
||||||
|
```console
|
||||||
|
alertmanager:
|
||||||
|
image: signoz/alertmanager:0.23.0-0.1
|
||||||
|
volumes:
|
||||||
|
- ./data/alertmanager:/data
|
||||||
|
expose:
|
||||||
|
- "9093"
|
||||||
|
ports:
|
||||||
|
- "8080:9093"
|
||||||
|
# depends_on:
|
||||||
|
# query-service:
|
||||||
|
# condition: service_healthy
|
||||||
|
restart: on-failure
|
||||||
|
command:
|
||||||
|
- --queryService.url=http://172.17.0.1:8085
|
||||||
|
- --storage.path=/data
|
||||||
|
```
|
||||||
|
- Run the following:
|
||||||
|
```console
|
||||||
|
cd signoz/
|
||||||
|
If you are using x86_64 processors (All Intel/AMD processors) run sudo make run-x86
|
||||||
|
If you are on arm64 processors (Apple M1 Macs) run sudo make run-arm
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Backend Configuration
|
||||||
|
|
||||||
#### Configuration
|
|
||||||
- Open ./constants/constants.go
|
- Open ./constants/constants.go
|
||||||
- Replace ```const RELATIONAL_DATASOURCE_PATH = "/var/lib/signoz/signoz.db"``` \
|
- Replace ```const RELATIONAL_DATASOURCE_PATH = "/var/lib/signoz/signoz.db"``` \
|
||||||
with ```const RELATIONAL_DATASOURCE_PATH = "./signoz.db".```
|
with ```const RELATIONAL_DATASOURCE_PATH = "./signoz.db".```
|
||||||
@ -15,8 +44,9 @@ Query service is the interface between frontend and databases. It is written in
|
|||||||
- Query Service needs below `env` variables to run:
|
- Query Service needs below `env` variables to run:
|
||||||
|
|
||||||
```
|
```
|
||||||
ClickHouseUrl=tcp://localhost:9001
|
export ClickHouseUrl=tcp://localhost:9001
|
||||||
STORAGE=clickhouse
|
export STORAGE=clickhouse
|
||||||
|
export ALERTMANAGER_API_PREFIX=http://localhost:9093/api/
|
||||||
```
|
```
|
||||||
|
|
||||||
<!-- The above values are the default ones used by SigNoz and are kept at `deploy/kubernetes/platform/signoz-charts/query-service/values.yaml` -->
|
<!-- The above values are the default ones used by SigNoz and are kept at `deploy/kubernetes/platform/signoz-charts/query-service/values.yaml` -->
|
||||||
@ -28,5 +58,24 @@ go build -o build/query-service main.go
|
|||||||
ClickHouseUrl=tcp://localhost:9001 STORAGE=clickhouse build/query-service
|
ClickHouseUrl=tcp://localhost:9001 STORAGE=clickhouse build/query-service
|
||||||
```
|
```
|
||||||
|
|
||||||
|
# Frontend Configuration for local query-service.
|
||||||
|
|
||||||
|
- Set the following environment variables
|
||||||
|
```console
|
||||||
|
export FRONTEND_API_ENDPOINT=http://localhost:8080
|
||||||
|
```
|
||||||
|
|
||||||
|
- Run the following
|
||||||
|
```console
|
||||||
|
cd signoz\frontend\
|
||||||
|
yarn install
|
||||||
|
yarn dev
|
||||||
|
```
|
||||||
|
|
||||||
|
## Note:
|
||||||
|
If you use go version 1.18 for development and contributions, then please checkout the following issue.
|
||||||
|
https://github.com/SigNoz/signoz/issues/1371
|
||||||
|
|
||||||
|
|
||||||
#### Docker Images
|
#### Docker Images
|
||||||
The docker images of query-service is available at https://hub.docker.com/r/signoz/query-service
|
The docker images of query-service is available at https://hub.docker.com/r/signoz/query-service
|
||||||
|