Compare commits

...

14 Commits

Author SHA1 Message Date
SagarRajput-7
e0e3ab2ef4 feat: refactored code and addressed feedbacks 2026-04-02 00:21:50 +05:30
SagarRajput-7
407409fc00 feat: refactored code and addressed feedbacks 2026-04-01 23:53:53 +05:30
SagarRajput-7
b795085189 Merge branch 'main' into user-v2-updates 2026-04-01 22:25:10 +05:30
SagarRajput-7
e1f6943e1a feat: code refactor 2026-04-01 22:23:22 +05:30
swapnil-signoz
4f273b296e refactor: removing dashboard overview images (#10801)
Some checks failed
build-staging / prepare (push) Has been cancelled
build-staging / js-build (push) Has been cancelled
build-staging / go-build (push) Has been cancelled
build-staging / staging (push) Has been cancelled
Release Drafter / update_release_draft (push) Has been cancelled
2026-04-01 16:25:55 +00:00
SagarRajput-7
1d20af668c Merge branch 'main' into user-v2-updates 2026-04-01 20:20:47 +05:30
SagarRajput-7
bb2babdbb4 feat: updated test cases 2026-04-01 20:17:53 +05:30
swapnil-signoz
3dc0a7c8ce feat: adding aws service definitions in types (#10798)
* feat: adding aws service definitions in types

* refactor: moving definitions to module fs
2026-04-01 14:08:46 +00:00
SagarRajput-7
f11c73bbe6 Merge branch 'main' into user-v2-updates 2026-04-01 18:59:49 +05:30
SagarRajput-7
c8c6a52e36 feat: updated members page to use new role management and v2 user api 2026-04-01 18:58:33 +05:30
Liapis Nikolaos
1080553905 feat(logs): pretty-print JSON attribute values when copying to clipboard (#10778)
When copying log attribute values that contain valid JSON objects or
arrays, the value is now pretty-printed with 2-space indentation.
This makes it easy to paste into JSON tools or editors.

Non-JSON values (strings, numbers, booleans) are unaffected.

Closes #8208
2026-04-01 13:01:09 +00:00
SagarRajput-7
820d26617b feat: updated user api to v2 and accordingly update members page and role management 2026-04-01 16:40:48 +05:30
Nikhil Soni
23e3c75d24 feat: return all spans for flamegraph under a limit (#10757)
* feat: return all spans for flamegraph under a limit

* feat: increase fg limits and add timestamp boundaries

* fix: set default value for ts boundary

* fix: use correct value for boundary end ts

* chore: change info log of flamegraph to debug
2026-04-01 10:18:36 +00:00
Pandey
42415e0873 feat(audit): handler-level AuditDef, audit middleware, and response capture (#10791)
* feat(audit): handler-level AuditDef and response-capturing wrapper

Add declarative audit instrumentation to the handler package. Routes
declare an AuditDef alongside OpenAPIDef; the handler automatically
captures the response status/body and emits an audit event via
auditor.Audit() after every request.

* refactor(audit): move audit logic to middleware, merge with logging

Move audit event emission from handler to middleware layer. The handler
package keeps only the AuditDef struct and AuditDefProvider interface.
The logging middleware now handles both request logging and audit event
emission using a single response capture, avoiding double-wrapping.

Rename badResponseLoggingWriter to responseCapture with body capture
on all 4xx/5xx responses (previously only 400 and 5xx).

* refactor(audit): rename Logging middleware to Audit, merge into single file

Delete logging.go and merge its contents into audit.go. Rename
Logging/NewLogging to Audit/NewAudit. The response.go file with
responseCapture is unchanged.

* refactor(audit): extract NewAuditEventFromHTTPRequest factory into audittypes

Move event construction to audittypes.NewAuditEventFromHTTPRequest with
an AuditEventContext struct for caller-provided fields. The audittypes
layer reads only transport fields from *http.Request and has no mux,
authtypes, or context dependencies. The middleware pre-extracts
principal, trace, error, and route fields before calling the factory.

* refactor(audit): move error parsing to render.ErrorFromBody and render.ErrorTypeFromStatusCode

Add render.ErrorFromBody to extract errors.JSON from a JSON-encoded
ErrorResponse body, and render.ErrorTypeFromStatusCode to reverse-map
HTTP status codes to error type strings. The middleware now uses these
instead of local duplicates.

* refactor(audit): move AuditDef onto Handler interface, consolidate files

Move AuditDef() onto the Handler interface directly. All Handler
implementations now carry it: handler returns the configured def,
healthOpenAPIHandler returns nil. Delete the separate AuditDefProvider
interface and audit.go handler file. Move excludedRoutes check before
audit emission so excluded routes skip both logging and audit.

* feat(audit): add option.go with AuditDef, Option, and WithAuditDef

* refactor(audit): decompose AuditEvent into attribute sub-structs, add tests

Decompose flat AuditEvent fields into typed sub-structs
(AuditEventAuditAttributes, PrincipalAttributes, ResourceAttributes,
ErrorAttributes, TransportAttributes) each with a constructor and
Put(pcommon.Map) method. Simplify NewAuditEventFromHTTPRequest to
accept authtypes.Claims and oteltrace IDs directly. Simplify the
middleware caller accordingly.

Add unit tests for the factory, outcome boundary, and principal type
derivation.

* refactor(audit): shorten attribute struct names, drop error message

Rename AuditEventAuditAttributes to AuditAttributes,
AuditEventPrincipalAttributes to PrincipalAttributes, and likewise
for Resource, Error, and Transport. The package prefix already
disambiguates.

Remove ErrorMessage from ErrorAttributes to avoid leaking sensitive
or PII data into audit logs. Error type and code are sufficient for
filtering; investigators can correlate via trace ID.

* fix(audit): update auditorserver test and otlphttp provider for new struct layout

Update newTestEvent in server_test.go to use nested AuditAttributes
and ResourceAttributes. Update otlphttpauditor provider to access
PrincipalOrgID via PrincipalAttributes. Fix godot lint on attribute
section comments.

* fix(audit): fix gjson path in ErrorCodeFromBody, add tests

Fix ErrorCodeFromBody gjson path from "errors.code" to "error.code"
to match the ErrorResponse JSON structure. Add unit tests for valid
error response and invalid JSON cases.

* fix(audit): add CodeUnset, use ErrorCodeFromBody in middleware

Add errors.CodeUnset for responses missing an error code. Update the
audit middleware to use render.ErrorCodeFromBody instead of the removed
render.ErrorFromBody.

* test(audit): add unit tests for responseCapture

Test the four meaningful behaviors: success responses don't capture
body, error responses capture body, large error bodies truncate at
4096 bytes, and 204 No Content suppresses writes entirely.

* fix(audit): check rw.Write return values in response_test.go

* style(audit): rename want prefix to expected in test fields

* refactor(audit): replace Sprintf with strings.Builder in newBody

Handle edge cases where principal email, ID, or resource ID may be
empty. The builder conditionally includes each segment, avoiding
empty parentheses or leading spaces in the audit body.

Add test cases covering all meaningful combinations: success/failure
with full/partial/empty principal, resource ID, and error details.

* chore: fix formatting

* chore: remove json tags

* fix: rebase with main
2026-04-01 10:10:52 +00:00
119 changed files with 65294 additions and 839 deletions

View File

@@ -76,12 +76,12 @@ func (provider *provider) Start(ctx context.Context) error {
}
func (provider *provider) Audit(ctx context.Context, event audittypes.AuditEvent) {
if event.PrincipalOrgID.IsZero() {
if event.PrincipalAttributes.PrincipalOrgID.IsZero() {
provider.settings.Logger().WarnContext(ctx, "audit event dropped as org_id is zero")
return
}
if _, err := provider.licensing.GetActive(ctx, event.PrincipalOrgID); err != nil {
if _, err := provider.licensing.GetActive(ctx, event.PrincipalAttributes.PrincipalOrgID); err != nil {
return
}

View File

@@ -229,7 +229,7 @@ func (s *Server) createPublicServer(apiHandler *api.APIHandler, web web.Web) (*h
s.config.APIServer.Timeout.Default,
s.config.APIServer.Timeout.Max,
).Wrap)
r.Use(middleware.NewLogging(s.signoz.Instrumentation.Logger(), s.config.APIServer.Logging.ExcludedRoutes).Wrap)
r.Use(middleware.NewAudit(s.signoz.Instrumentation.Logger(), s.config.APIServer.Logging.ExcludedRoutes, nil).Wrap)
r.Use(middleware.NewComment().Wrap)
apiHandler.RegisterRoutes(r, am)

View File

@@ -1,9 +1,8 @@
import { ReactChild, useCallback, useEffect, useMemo, useState } from 'react';
import { useQuery } from 'react-query';
import { matchPath, Redirect, useLocation } from 'react-router-dom';
import getLocalStorageApi from 'api/browser/localstorage/get';
import setLocalStorageApi from 'api/browser/localstorage/set';
import getAll from 'api/v1/user/get';
import { useListUsers } from 'api/generated/services/users';
import { FeatureKeys } from 'constants/features';
import { LOCALSTORAGE } from 'constants/localStorage';
import { ORG_PREFERENCES } from 'constants/orgPreferences';
@@ -12,12 +11,9 @@ import { useGetTenantLicense } from 'hooks/useGetTenantLicense';
import history from 'lib/history';
import { isEmpty } from 'lodash-es';
import { useAppContext } from 'providers/App/App';
import { SuccessResponseV2 } from 'types/api';
import APIError from 'types/api/error';
import { LicensePlatform, LicenseState } from 'types/api/licensesV3/getActive';
import { OrgPreference } from 'types/api/preferences/preference';
import { Organization } from 'types/api/user/getOrganization';
import { UserResponse } from 'types/api/user/getUser';
import { USER_ROLES } from 'types/roles';
import { routePermission } from 'utils/permission';
@@ -63,18 +59,10 @@ function PrivateRoute({ children }: PrivateRouteProps): JSX.Element {
const [orgData, setOrgData] = useState<Organization | undefined>(undefined);
const { data: usersData, isFetching: isFetchingUsers } = useQuery<
SuccessResponseV2<UserResponse[]> | undefined,
APIError
>({
queryFn: () => {
if (orgData && orgData.id !== undefined) {
return getAll();
}
return undefined;
const { data: usersData, isFetching: isFetchingUsers } = useListUsers({
query: {
enabled: !isEmpty(orgData) && user.role === 'ADMIN',
},
queryKey: ['getOrgUser'],
enabled: !isEmpty(orgData) && user.role === 'ADMIN',
});
const checkFirstTimeUser = useCallback((): boolean => {

View File

@@ -67,9 +67,12 @@ jest.mock('hooks/useGetTenantLicense', () => ({
// Mock react-query for users fetch
let mockUsersData: { email: string }[] = [];
jest.mock('api/v1/user/get', () => ({
__esModule: true,
default: jest.fn(() => Promise.resolve({ data: mockUsersData })),
jest.mock('api/generated/services/users', () => ({
...jest.requireActual('api/generated/services/users'),
useListUsers: jest.fn(() => ({
data: { data: mockUsersData },
isFetching: false,
})),
}));
const queryClient = new QueryClient({

View File

@@ -1,26 +0,0 @@
import { ApiV2Instance as axios } from 'api';
import { ErrorResponseHandler } from 'api/ErrorResponseHandler';
import { AxiosError } from 'axios';
import { ErrorResponse, SuccessResponse } from 'types/api';
import { PayloadProps, Props } from 'types/api/user/editOrg';
const editOrg = async (
props: Props,
): Promise<SuccessResponse<PayloadProps> | ErrorResponse> => {
try {
const response = await axios.put(`/orgs/me`, {
displayName: props.displayName,
});
return {
statusCode: 204,
error: null,
message: response.data.status,
payload: response.data,
};
} catch (error) {
return ErrorResponseHandler(error as AxiosError);
}
};
export default editOrg;

View File

@@ -1,28 +0,0 @@
import axios from 'api';
import { ErrorResponseHandler } from 'api/ErrorResponseHandler';
import { AxiosError } from 'axios';
import { ErrorResponse, SuccessResponse } from 'types/api';
import { PayloadProps } from 'types/api/user/getOrganization';
const getOrganization = async (
token?: string,
): Promise<SuccessResponse<PayloadProps> | ErrorResponse> => {
try {
const response = await axios.get(`/org`, {
headers: {
Authorization: `bearer ${token}`,
},
});
return {
statusCode: 200,
error: null,
message: response.data.status,
payload: response.data,
};
} catch (error) {
return ErrorResponseHandler(error as AxiosError);
}
};
export default getOrganization;

View File

@@ -1,21 +0,0 @@
import axios from 'api';
import { ErrorResponseHandlerV2 } from 'api/ErrorResponseHandlerV2';
import { AxiosError } from 'axios';
import { ErrorV2Resp, SuccessResponseV2 } from 'types/api';
import { UserResponse } from 'types/api/user/getUser';
import { PayloadProps } from 'types/api/user/getUsers';
const getAll = async (): Promise<SuccessResponseV2<UserResponse[]>> => {
try {
const response = await axios.get<PayloadProps>(`/user`);
return {
httpStatusCode: response.status,
data: response.data.data,
};
} catch (error) {
ErrorResponseHandlerV2(error as AxiosError<ErrorV2Resp>);
}
};
export default getAll;

View File

@@ -1,22 +0,0 @@
import axios from 'api';
import { ErrorResponseHandlerV2 } from 'api/ErrorResponseHandlerV2';
import { AxiosError } from 'axios';
import { ErrorV2Resp, SuccessResponseV2 } from 'types/api';
import { PayloadProps, Props, UserResponse } from 'types/api/user/getUser';
const getUser = async (
props: Props,
): Promise<SuccessResponseV2<UserResponse>> => {
try {
const response = await axios.get<PayloadProps>(`/user/${props.userId}`);
return {
httpStatusCode: response.status,
data: response.data.data,
};
} catch (error) {
ErrorResponseHandlerV2(error as AxiosError<ErrorV2Resp>);
}
};
export default getUser;

View File

@@ -1,23 +0,0 @@
import axios from 'api';
import { ErrorResponseHandlerV2 } from 'api/ErrorResponseHandlerV2';
import { AxiosError } from 'axios';
import { ErrorV2Resp, SuccessResponseV2 } from 'types/api';
import { Props } from 'types/api/user/editUser';
const update = async (props: Props): Promise<SuccessResponseV2<null>> => {
try {
const response = await axios.put(`/user/${props.userId}`, {
displayName: props.displayName,
role: props.role,
});
return {
httpStatusCode: response.status,
data: null,
};
} catch (error) {
ErrorResponseHandlerV2(error as AxiosError<ErrorV2Resp>);
}
};
export default update;

View File

@@ -1,20 +0,0 @@
import axios from 'api';
import { ErrorResponseHandlerV2 } from 'api/ErrorResponseHandlerV2';
import { AxiosError } from 'axios';
import { ErrorV2Resp, SuccessResponseV2 } from 'types/api';
import { PayloadProps, UserResponse } from 'types/api/user/getUser';
const get = async (): Promise<SuccessResponseV2<UserResponse>> => {
try {
const response = await axios.get<PayloadProps>(`/user/me`);
return {
httpStatusCode: response.status,
data: response.data.data,
};
} catch (error) {
ErrorResponseHandlerV2(error as AxiosError<ErrorV2Resp>);
}
};
export default get;

View File

@@ -0,0 +1,75 @@
import { Button } from '@signozhq/button';
import { DialogFooter, DialogWrapper } from '@signozhq/dialog';
import { Trash2, X } from '@signozhq/icons';
import { MemberRow } from 'components/MembersTable/MembersTable';
interface DeleteMemberDialogProps {
open: boolean;
isInvited: boolean;
member: MemberRow | null;
isDeleting: boolean;
onClose: () => void;
onConfirm: () => void;
}
function DeleteMemberDialog({
open,
isInvited,
member,
isDeleting,
onClose,
onConfirm,
}: DeleteMemberDialogProps): JSX.Element {
const title = isInvited ? 'Revoke Invite' : 'Delete Member';
const body = isInvited ? (
<>
Are you sure you want to revoke the invite for{' '}
<strong>{member?.email}</strong>? They will no longer be able to join the
workspace using this invite.
</>
) : (
<>
Are you sure you want to delete{' '}
<strong>{member?.name || member?.email}</strong>? This will remove their
access to the workspace.
</>
);
return (
<DialogWrapper
open={open}
onOpenChange={(isOpen): void => {
if (!isOpen) {
onClose();
}
}}
title={title}
width="narrow"
className="alert-dialog delete-dialog"
showCloseButton={false}
disableOutsideClick={false}
>
<p className="delete-dialog__body">{body}</p>
<DialogFooter className="delete-dialog__footer">
<Button variant="solid" color="secondary" size="sm" onClick={onClose}>
<X size={12} />
Cancel
</Button>
<Button
variant="solid"
color="destructive"
size="sm"
disabled={isDeleting}
onClick={onConfirm}
>
<Trash2 size={12} />
{isDeleting ? 'Processing...' : title}
</Button>
</DialogFooter>
</DialogWrapper>
);
}
export default DeleteMemberDialog;

View File

@@ -45,8 +45,8 @@
display: flex;
align-items: center;
justify-content: space-between;
height: 32px;
padding: 0 var(--padding-2);
min-height: 32px;
padding: var(--padding-1) var(--padding-2);
border-radius: 2px;
background: var(--l2-background);
border: 1px solid var(--border);
@@ -57,6 +57,13 @@
}
}
&__disabled-roles {
display: flex;
flex-wrap: wrap;
gap: var(--spacing-2);
flex: 1;
}
&__email-text {
font-size: var(--font-size-sm);
font-weight: var(--font-weight-normal);
@@ -78,21 +85,23 @@
&__role-select {
width: 100%;
height: 32px;
.ant-select-selector {
background-color: var(--l2-background) !important;
border-color: var(--border) !important;
border-radius: 2px;
padding: 0 var(--padding-2) !important;
padding: var(--padding-1) var(--padding-2) !important;
display: flex;
align-items: center;
flex-wrap: wrap;
min-height: 32px;
height: auto !important;
}
.ant-select-selection-item {
font-size: var(--font-size-sm);
color: var(--l1-foreground);
line-height: 32px;
line-height: 22px;
letter-spacing: -0.07px;
}

View File

@@ -2,38 +2,52 @@ import { useCallback, useEffect, useState } from 'react';
import { useCopyToClipboard } from 'react-use';
import { Badge } from '@signozhq/badge';
import { Button } from '@signozhq/button';
import { DialogFooter, DialogWrapper } from '@signozhq/dialog';
import { DrawerWrapper } from '@signozhq/drawer';
import {
Check,
ChevronDown,
Copy,
LockKeyhole,
RefreshCw,
Trash2,
X,
} from '@signozhq/icons';
import { LockKeyhole, RefreshCw, Trash2, X } from '@signozhq/icons';
import { Input } from '@signozhq/input';
import { toast } from '@signozhq/sonner';
import { Select } from 'antd';
import { Skeleton } from 'antd';
import { convertToApiError } from 'api/ErrorResponseHandlerForGeneratedAPIs';
import { RenderErrorResponseDTO } from 'api/generated/services/sigNoz.schemas';
import type { RenderErrorResponseDTO } from 'api/generated/services/sigNoz.schemas';
import {
getResetPasswordToken,
useDeleteUser,
useUpdateUserDeprecated,
useGetUser,
useUpdateMyUserV2,
useUpdateUser,
} from 'api/generated/services/users';
import { AxiosError } from 'axios';
import { MemberRow } from 'components/MembersTable/MembersTable';
import RolesSelect, { useRoles } from 'components/RolesSelect';
import SaveErrorItem from 'components/ServiceAccountDrawer/SaveErrorItem';
import type { SaveError } from 'components/ServiceAccountDrawer/utils';
import { DATE_TIME_FORMATS } from 'constants/dateTimeFormats';
import { MemberStatus } from 'container/MembersSettings/utils';
import { capitalize } from 'lodash-es';
import {
MemberRoleUpdateFailure,
useMemberRoleManager,
} from 'hooks/member/useMemberRoleManager';
import { useAppContext } from 'providers/App/App';
import { useTimezone } from 'providers/Timezone';
import { ROLES } from 'types/roles';
import { popupContainer } from 'utils/selectPopupContainer';
import APIError from 'types/api/error';
import { toAPIError } from 'utils/errorUtils';
import DeleteMemberDialog from './DeleteMemberDialog';
import ResetLinkDialog from './ResetLinkDialog';
import './EditMemberDrawer.styles.scss';
function toSaveApiError(err: unknown): APIError {
return (
convertToApiError(err as AxiosError<RenderErrorResponseDTO>) ??
toAPIError(err as AxiosError<RenderErrorResponseDTO>)
);
}
function areSortedArraysEqual(a: string[], b: string[]): boolean {
return JSON.stringify([...a].sort()) === JSON.stringify([...b].sort());
}
export interface EditMemberDrawerProps {
member: MemberRow | null;
open: boolean;
@@ -49,9 +63,12 @@ function EditMemberDrawer({
onComplete,
}: EditMemberDrawerProps): JSX.Element {
const { formatTimezoneAdjustedTimestamp } = useTimezone();
const { user: currentUser } = useAppContext();
const [displayName, setDisplayName] = useState('');
const [selectedRole, setSelectedRole] = useState<ROLES>('VIEWER');
const [localDisplayName, setLocalDisplayName] = useState('');
const [localRoles, setLocalRoles] = useState<string[]>([]);
const [isSaving, setIsSaving] = useState(false);
const [saveErrors, setSaveErrors] = useState<SaveError[]>([]);
const [isGeneratingLink, setIsGeneratingLink] = useState(false);
const [showDeleteConfirm, setShowDeleteConfirm] = useState(false);
const [resetLink, setResetLink] = useState<string | null>(null);
@@ -60,25 +77,54 @@ function EditMemberDrawer({
const [linkType, setLinkType] = useState<'invite' | 'reset' | null>(null);
const isInvited = member?.status === MemberStatus.Invited;
const isSelf = !!member?.id && member.id === currentUser?.id;
const { mutate: updateUser, isLoading: isSaving } = useUpdateUserDeprecated({
mutation: {
onSuccess: (): void => {
toast.success('Member details updated successfully', { richColors: true });
onComplete();
onClose();
},
onError: (err): void => {
const errMessage =
convertToApiError(
err as AxiosError<RenderErrorResponseDTO, unknown> | null,
)?.getErrorMessage() || 'An error occurred';
toast.error(`Failed to update member details: ${errMessage}`, {
richColors: true,
});
},
},
});
const {
data: fetchedUser,
isLoading: isFetchingUser,
refetch: refetchUser,
} = useGetUser(
{ id: member?.id ?? '' },
{ query: { enabled: open && !!member?.id } },
);
const {
roles: availableRoles,
isLoading: rolesLoading,
isError: rolesError,
error: rolesErrorObj,
refetch: refetchRoles,
} = useRoles();
const { fetchedRoleIds, applyDiff } = useMemberRoleManager(
member?.id ?? '',
open && !!member?.id,
);
const fetchedDisplayName =
fetchedUser?.data?.displayName ?? member?.name ?? '';
const fetchedUserId = fetchedUser?.data?.id;
const fetchedUserDisplayName = fetchedUser?.data?.displayName;
useEffect(() => {
if (fetchedUserId) {
setLocalDisplayName(fetchedUserDisplayName ?? member?.name ?? '');
}
setSaveErrors([]);
}, [fetchedUserId, fetchedUserDisplayName, member?.name]);
useEffect(() => {
setLocalRoles(fetchedRoleIds);
}, [fetchedRoleIds]);
const isDirty =
member !== null &&
fetchedUser != null &&
(localDisplayName !== fetchedDisplayName ||
!areSortedArraysEqual(localRoles, fetchedRoleIds));
const { mutateAsync: updateMyUser } = useUpdateMyUserV2();
const { mutateAsync: updateUser } = useUpdateUser();
const { mutate: deleteUser, isLoading: isDeleting } = useDeleteUser({
mutation: {
@@ -104,48 +150,152 @@ function EditMemberDrawer({
},
});
useEffect(() => {
if (member) {
setDisplayName(member.name ?? '');
setSelectedRole(member.role);
}
}, [member]);
const isDirty =
member !== null &&
(displayName !== (member.name ?? '') || selectedRole !== member.role);
const formatTimestamp = useCallback(
(ts: string | null | undefined): string => {
if (!ts) {
return '—';
const makeRoleRetry = useCallback(
(
context: string,
rawRetry: () => Promise<void>,
) => async (): Promise<void> => {
try {
await rawRetry();
setSaveErrors((prev) => prev.filter((e) => e.context !== context));
refetchUser();
} catch (err) {
setSaveErrors((prev) =>
prev.map((e) =>
e.context === context ? { ...e, apiError: toSaveApiError(err) } : e,
),
);
}
const d = new Date(ts);
if (Number.isNaN(d.getTime())) {
return '—';
}
return formatTimezoneAdjustedTimestamp(ts, DATE_TIME_FORMATS.DASH_DATETIME);
},
[formatTimezoneAdjustedTimestamp],
[refetchUser],
);
const handleSave = useCallback((): void => {
const retryNameUpdate = useCallback(async (): Promise<void> => {
if (!member) {
return;
}
try {
if (isSelf) {
await updateMyUser({ data: { displayName: localDisplayName } });
} else {
await updateUser({
pathParams: { id: member.id },
data: { displayName: localDisplayName },
});
}
setSaveErrors((prev) => prev.filter((e) => e.context !== 'Name update'));
refetchUser();
} catch (err) {
setSaveErrors((prev) =>
prev.map((e) =>
e.context === 'Name update' ? { ...e, apiError: toSaveApiError(err) } : e,
),
);
}
}, [member, isSelf, localDisplayName, updateMyUser, updateUser, refetchUser]);
const handleSave = useCallback(async (): Promise<void> => {
if (!member || !isDirty) {
return;
}
updateUser({
pathParams: { id: member.id },
data: { id: member.id, displayName, role: selectedRole },
});
}, [member, isDirty, displayName, selectedRole, updateUser]);
setSaveErrors([]);
setIsSaving(true);
try {
const nameChanged = localDisplayName !== fetchedDisplayName;
const rolesChanged = !areSortedArraysEqual(localRoles, fetchedRoleIds);
const namePromise = nameChanged
? isSelf
? updateMyUser({ data: { displayName: localDisplayName } })
: updateUser({
pathParams: { id: member.id },
data: { displayName: localDisplayName },
})
: Promise.resolve();
const [nameResult, rolesResult] = await Promise.allSettled([
namePromise,
rolesChanged ? applyDiff(localRoles, availableRoles) : Promise.resolve([]),
]);
const errors: SaveError[] = [];
if (nameResult.status === 'rejected') {
errors.push({
context: 'Name update',
apiError: toSaveApiError(nameResult.reason),
onRetry: retryNameUpdate,
});
}
if (rolesResult.status === 'rejected') {
errors.push({
context: 'Roles update',
apiError: toSaveApiError(rolesResult.reason),
onRetry: async (): Promise<void> => {
const failures = await applyDiff(localRoles, availableRoles);
setSaveErrors((prev) => {
const rest = prev.filter((e) => e.context !== 'Roles update');
return [
...rest,
...failures.map((f: MemberRoleUpdateFailure) => {
const ctx = `Role '${f.roleName}'`;
return {
context: ctx,
apiError: toSaveApiError(f.error),
onRetry: makeRoleRetry(ctx, f.onRetry),
};
}),
];
});
refetchUser();
},
});
} else {
for (const failure of rolesResult.value ?? []) {
const context = `Role '${failure.roleName}'`;
errors.push({
context,
apiError: toSaveApiError(failure.error),
onRetry: makeRoleRetry(context, failure.onRetry),
});
}
}
if (errors.length > 0) {
setSaveErrors(errors);
} else {
toast.success('Member details updated successfully', { richColors: true });
onComplete();
}
refetchUser();
} finally {
setIsSaving(false);
}
}, [
member,
isDirty,
isSelf,
localDisplayName,
localRoles,
fetchedDisplayName,
fetchedRoleIds,
updateMyUser,
updateUser,
applyDiff,
availableRoles,
refetchUser,
retryNameUpdate,
makeRoleRetry,
onComplete,
]);
const handleDelete = useCallback((): void => {
if (!member) {
return;
}
deleteUser({
pathParams: { id: member.id },
});
deleteUser({ pathParams: { id: member.id } });
}, [member, deleteUser]);
const handleGenerateResetLink = useCallback(async (): Promise<void> => {
@@ -176,30 +326,26 @@ function EditMemberDrawer({
} finally {
setIsGeneratingLink(false);
}
}, [member, isInvited, setLinkType, onClose]);
}, [member, isInvited, onClose]);
const [copyState, copyToClipboard] = useCopyToClipboard();
const handleCopyResetLink = useCallback(async (): Promise<void> => {
const handleCopyResetLink = useCallback((): void => {
if (!resetLink) {
return;
}
copyToClipboard(resetLink);
setHasCopiedResetLink(true);
setTimeout(() => setHasCopiedResetLink(false), 2000);
toast.success(
const message =
linkType === 'invite'
? 'Invite link copied to clipboard'
: 'Reset link copied to clipboard',
{ richColors: true },
);
: 'Reset link copied to clipboard';
toast.success(message, { richColors: true });
}, [resetLink, copyToClipboard, linkType]);
useEffect(() => {
if (copyState.error) {
toast.error('Failed to copy link', {
richColors: true,
});
toast.error('Failed to copy link', { richColors: true });
}
}, [copyState.error]);
@@ -210,79 +356,146 @@ function EditMemberDrawer({
const joinedOnLabel = isInvited ? 'Invited On' : 'Joined On';
const drawerContent = (
<div className="edit-member-drawer__layout">
<div className="edit-member-drawer__body">
<div className="edit-member-drawer__field">
<label className="edit-member-drawer__label" htmlFor="member-name">
Name
</label>
<Input
id="member-name"
value={displayName}
onChange={(e): void => setDisplayName(e.target.value)}
className="edit-member-drawer__input"
placeholder="Enter name"
/>
</div>
const formatTimestamp = useCallback(
(ts: string | null | undefined): string => {
if (!ts) {
return '—';
}
const d = new Date(ts);
if (Number.isNaN(d.getTime())) {
return '—';
}
return formatTimezoneAdjustedTimestamp(ts, DATE_TIME_FORMATS.DASH_DATETIME);
},
[formatTimezoneAdjustedTimestamp],
);
<div className="edit-member-drawer__field">
<label className="edit-member-drawer__label" htmlFor="member-email">
Email Address
</label>
<div className="edit-member-drawer__input-wrapper edit-member-drawer__input-wrapper--disabled">
<span className="edit-member-drawer__email-text">
{member?.email || '—'}
</span>
<LockKeyhole size={16} className="edit-member-drawer__lock-icon" />
</div>
</div>
const drawerBody = isFetchingUser ? (
<Skeleton active paragraph={{ rows: 6 }} />
) : (
<>
<div className="edit-member-drawer__field">
<label className="edit-member-drawer__label" htmlFor="member-name">
Name
</label>
<Input
id="member-name"
value={localDisplayName}
onChange={(e): void => {
setLocalDisplayName(e.target.value);
setSaveErrors((prev) =>
prev.filter((err) => err.context !== 'Name update'),
);
}}
className="edit-member-drawer__input"
placeholder="Enter name"
/>
</div>
<div className="edit-member-drawer__field">
<label className="edit-member-drawer__label" htmlFor="member-role">
Roles
</label>
<Select
id="member-role"
value={selectedRole}
onChange={(role): void => setSelectedRole(role as ROLES)}
className="edit-member-drawer__role-select"
suffixIcon={<ChevronDown size={14} />}
getPopupContainer={popupContainer}
>
<Select.Option value="ADMIN">{capitalize('ADMIN')}</Select.Option>
<Select.Option value="EDITOR">{capitalize('EDITOR')}</Select.Option>
<Select.Option value="VIEWER">{capitalize('VIEWER')}</Select.Option>
</Select>
</div>
<div className="edit-member-drawer__meta">
<div className="edit-member-drawer__meta-item">
<span className="edit-member-drawer__meta-label">Status</span>
{member?.status === MemberStatus.Active ? (
<Badge color="forest" variant="outline">
ACTIVE
</Badge>
) : (
<Badge color="amber" variant="outline">
INVITED
</Badge>
)}
</div>
<div className="edit-member-drawer__meta-item">
<span className="edit-member-drawer__meta-label">{joinedOnLabel}</span>
<Badge color="vanilla">{formatTimestamp(member?.joinedOn)}</Badge>
</div>
{!isInvited && (
<div className="edit-member-drawer__meta-item">
<span className="edit-member-drawer__meta-label">Last Modified</span>
<Badge color="vanilla">{formatTimestamp(member?.updatedAt)}</Badge>
</div>
)}
<div className="edit-member-drawer__field">
<label className="edit-member-drawer__label" htmlFor="member-email">
Email Address
</label>
<div className="edit-member-drawer__input-wrapper edit-member-drawer__input-wrapper--disabled">
<span className="edit-member-drawer__email-text">
{member?.email || '—'}
</span>
<LockKeyhole size={16} className="edit-member-drawer__lock-icon" />
</div>
</div>
<div className="edit-member-drawer__field">
<label className="edit-member-drawer__label" htmlFor="member-role">
Roles
</label>
{isSelf ? (
<div className="edit-member-drawer__input-wrapper edit-member-drawer__input-wrapper--disabled">
<div className="edit-member-drawer__disabled-roles">
{localRoles.length > 0 ? (
localRoles.map((roleId) => {
const role = availableRoles.find((r) => r.id === roleId);
return (
<Badge key={roleId} color="vanilla">
{role?.name ?? roleId}
</Badge>
);
})
) : (
<span className="edit-member-drawer__email-text"></span>
)}
</div>
<LockKeyhole size={16} className="edit-member-drawer__lock-icon" />
</div>
) : (
<RolesSelect
id="member-role"
mode="multiple"
roles={availableRoles}
loading={rolesLoading}
isError={rolesError}
error={rolesErrorObj}
onRefetch={refetchRoles}
value={localRoles}
onChange={(roles): void => {
setLocalRoles(roles);
setSaveErrors((prev) =>
prev.filter(
(err) =>
err.context !== 'Roles update' && !err.context.startsWith("Role '"),
),
);
}}
className="edit-member-drawer__role-select"
placeholder="Select roles"
/>
)}
</div>
<div className="edit-member-drawer__meta">
<div className="edit-member-drawer__meta-item">
<span className="edit-member-drawer__meta-label">Status</span>
{member?.status === MemberStatus.Active ? (
<Badge color="forest" variant="outline">
ACTIVE
</Badge>
) : (
<Badge color="amber" variant="outline">
INVITED
</Badge>
)}
</div>
<div className="edit-member-drawer__meta-item">
<span className="edit-member-drawer__meta-label">{joinedOnLabel}</span>
<Badge color="vanilla">{formatTimestamp(member?.joinedOn)}</Badge>
</div>
{!isInvited && (
<div className="edit-member-drawer__meta-item">
<span className="edit-member-drawer__meta-label">Last Modified</span>
<Badge color="vanilla">{formatTimestamp(member?.updatedAt)}</Badge>
</div>
)}
</div>
{saveErrors.length > 0 && (
<div className="edit-member-drawer__save-errors">
{saveErrors.map((e) => (
<SaveErrorItem
key={e.context}
context={e.context}
apiError={e.apiError}
onRetry={e.onRetry}
/>
))}
</div>
)}
</>
);
const drawerContent = (
<div className="edit-member-drawer__layout">
<div className="edit-member-drawer__body">{drawerBody}</div>
<div className="edit-member-drawer__footer">
<div className="edit-member-drawer__footer-left">
<Button
@@ -300,11 +513,9 @@ function EditMemberDrawer({
disabled={isGeneratingLink}
>
<RefreshCw size={12} />
{isGeneratingLink
? 'Generating...'
: isInvited
? 'Copy Invite Link'
: 'Generate Password Reset Link'}
{isGeneratingLink && 'Generating...'}
{!isGeneratingLink && isInvited && 'Copy Invite Link'}
{!isGeneratingLink && !isInvited && 'Generate Password Reset Link'}
</Button>
</div>
@@ -328,22 +539,6 @@ function EditMemberDrawer({
</div>
);
const deleteDialogTitle = isInvited ? 'Revoke Invite' : 'Delete Member';
const deleteDialogBody = isInvited ? (
<>
Are you sure you want to revoke the invite for{' '}
<strong>{member?.email}</strong>? They will no longer be able to join the
workspace using this invite.
</>
) : (
<>
Are you sure you want to delete{' '}
<strong>{member?.name || member?.email}</strong>? This will remove their
access to the workspace.
</>
);
const deleteConfirmLabel = isInvited ? 'Revoke Invite' : 'Delete Member';
return (
<>
<DrawerWrapper
@@ -363,82 +558,26 @@ function EditMemberDrawer({
className="edit-member-drawer"
/>
<DialogWrapper
<ResetLinkDialog
open={showResetLinkDialog}
onOpenChange={(isOpen): void => {
if (!isOpen) {
setShowResetLinkDialog(false);
setLinkType(null);
}
linkType={linkType}
resetLink={resetLink}
hasCopied={hasCopiedResetLink}
onClose={(): void => {
setShowResetLinkDialog(false);
setLinkType(null);
}}
title={linkType === 'invite' ? 'Invite Link' : 'Password Reset Link'}
showCloseButton
width="base"
className="reset-link-dialog"
>
<div className="reset-link-dialog__content">
<p className="reset-link-dialog__description">
{linkType === 'invite'
? 'Share this one-time link with the team member to complete their account setup.'
: 'This creates a one-time link the team member can use to set a new password for their SigNoz account.'}
</p>
<div className="reset-link-dialog__link-row">
<div className="reset-link-dialog__link-text-wrap">
<span className="reset-link-dialog__link-text">{resetLink}</span>
</div>
<Button
variant="outlined"
color="secondary"
size="sm"
onClick={handleCopyResetLink}
prefixIcon={
hasCopiedResetLink ? <Check size={12} /> : <Copy size={12} />
}
className="reset-link-dialog__copy-btn"
>
{hasCopiedResetLink ? 'Copied!' : 'Copy'}
</Button>
</div>
</div>
</DialogWrapper>
onCopy={handleCopyResetLink}
/>
<DialogWrapper
<DeleteMemberDialog
open={showDeleteConfirm}
onOpenChange={(isOpen): void => {
if (!isOpen) {
setShowDeleteConfirm(false);
}
}}
title={deleteDialogTitle}
width="narrow"
className="alert-dialog delete-dialog"
showCloseButton={false}
disableOutsideClick={false}
>
<p className="delete-dialog__body">{deleteDialogBody}</p>
<DialogFooter className="delete-dialog__footer">
<Button
variant="solid"
color="secondary"
size="sm"
onClick={(): void => setShowDeleteConfirm(false)}
>
<X size={12} />
Cancel
</Button>
<Button
variant="solid"
color="destructive"
size="sm"
disabled={isDeleting}
onClick={handleDelete}
>
<Trash2 size={12} />
{isDeleting ? 'Processing...' : deleteConfirmLabel}
</Button>
</DialogFooter>
</DialogWrapper>
isInvited={isInvited}
member={member}
isDeleting={isDeleting}
onClose={(): void => setShowDeleteConfirm(false)}
onConfirm={handleDelete}
/>
</>
);
}

View File

@@ -0,0 +1,61 @@
import { Button } from '@signozhq/button';
import { DialogWrapper } from '@signozhq/dialog';
import { Check, Copy } from '@signozhq/icons';
interface ResetLinkDialogProps {
open: boolean;
linkType: 'invite' | 'reset' | null;
resetLink: string | null;
hasCopied: boolean;
onClose: () => void;
onCopy: () => void;
}
function ResetLinkDialog({
open,
linkType,
resetLink,
hasCopied,
onClose,
onCopy,
}: ResetLinkDialogProps): JSX.Element {
return (
<DialogWrapper
open={open}
onOpenChange={(isOpen): void => {
if (!isOpen) {
onClose();
}
}}
title={linkType === 'invite' ? 'Invite Link' : 'Password Reset Link'}
showCloseButton
width="base"
className="reset-link-dialog"
>
<div className="reset-link-dialog__content">
<p className="reset-link-dialog__description">
{linkType === 'invite'
? 'Share this one-time link with the team member to complete their account setup.'
: 'This creates a one-time link the team member can use to set a new password for their SigNoz account.'}
</p>
<div className="reset-link-dialog__link-row">
<div className="reset-link-dialog__link-text-wrap">
<span className="reset-link-dialog__link-text">{resetLink}</span>
</div>
<Button
variant="outlined"
color="secondary"
size="sm"
onClick={onCopy}
prefixIcon={hasCopied ? <Check size={12} /> : <Copy size={12} />}
className="reset-link-dialog__copy-btn"
>
{hasCopied ? 'Copied!' : 'Copy'}
</Button>
</div>
</div>
</DialogWrapper>
);
}
export default ResetLinkDialog;

View File

@@ -4,11 +4,19 @@ import { convertToApiError } from 'api/ErrorResponseHandlerForGeneratedAPIs';
import {
getResetPasswordToken,
useDeleteUser,
useUpdateUserDeprecated,
useGetUser,
useRemoveUserRoleByUserIDAndRoleID,
useSetRoleByUserID,
useUpdateMyUserV2,
useUpdateUser,
} from 'api/generated/services/users';
import { MemberStatus } from 'container/MembersSettings/utils';
import {
listRolesSuccessResponse,
managedRoles,
} from 'mocks-server/__mockdata__/roles';
import { rest, server } from 'mocks-server/server';
import { render, screen, userEvent, waitFor } from 'tests/test-utils';
import { ROLES } from 'types/roles';
import EditMemberDrawer, { EditMemberDrawerProps } from '../EditMemberDrawer';
@@ -44,7 +52,11 @@ jest.mock('@signozhq/dialog', () => ({
jest.mock('api/generated/services/users', () => ({
useDeleteUser: jest.fn(),
useUpdateUserDeprecated: jest.fn(),
useGetUser: jest.fn(),
useUpdateUser: jest.fn(),
useUpdateMyUserV2: jest.fn(),
useSetRoleByUserID: jest.fn(),
useRemoveUserRoleByUserIDAndRoleID: jest.fn(),
getResetPasswordToken: jest.fn(),
}));
@@ -69,15 +81,31 @@ jest.mock('react-use', () => ({
],
}));
const mockUpdateMutate = jest.fn();
const ROLES_ENDPOINT = '*/api/v1/roles';
const mockDeleteMutate = jest.fn();
const mockGetResetPasswordToken = jest.mocked(getResetPasswordToken);
const mockFetchedUser = {
data: {
id: 'user-1',
displayName: 'Alice Smith',
email: 'alice@signoz.io',
status: 'active',
userRoles: [
{
id: 'ur-1',
roleId: managedRoles[0].id,
role: managedRoles[0], // signoz-admin
},
],
},
};
const activeMember = {
id: 'user-1',
name: 'Alice Smith',
email: 'alice@signoz.io',
role: 'ADMIN' as ROLES,
status: MemberStatus.Active,
joinedOn: '1700000000000',
updatedAt: '1710000000000',
@@ -87,7 +115,6 @@ const invitedMember = {
id: 'abc123',
name: '',
email: 'bob@signoz.io',
role: 'VIEWER' as ROLES,
status: MemberStatus.Invited,
joinedOn: '1700000000000',
};
@@ -109,8 +136,30 @@ function renderDrawer(
describe('EditMemberDrawer', () => {
beforeEach(() => {
jest.clearAllMocks();
(useUpdateUserDeprecated as jest.Mock).mockReturnValue({
mutate: mockUpdateMutate,
server.use(
rest.get(ROLES_ENDPOINT, (_, res, ctx) =>
res(ctx.status(200), ctx.json(listRolesSuccessResponse)),
),
);
(useGetUser as jest.Mock).mockReturnValue({
data: mockFetchedUser,
isLoading: false,
refetch: jest.fn(),
});
(useUpdateUser as jest.Mock).mockReturnValue({
mutateAsync: jest.fn().mockResolvedValue({}),
isLoading: false,
});
(useUpdateMyUserV2 as jest.Mock).mockReturnValue({
mutateAsync: jest.fn().mockResolvedValue({}),
isLoading: false,
});
(useSetRoleByUserID as jest.Mock).mockReturnValue({
mutateAsync: jest.fn().mockResolvedValue({}),
isLoading: false,
});
(useRemoveUserRoleByUserIDAndRoleID as jest.Mock).mockReturnValue({
mutateAsync: jest.fn().mockResolvedValue({}),
isLoading: false,
});
(useDeleteUser as jest.Mock).mockReturnValue({
@@ -119,6 +168,10 @@ describe('EditMemberDrawer', () => {
});
});
afterEach(() => {
server.resetHandlers();
});
it('renders active member details and disables Save when form is not dirty', () => {
renderDrawer();
@@ -130,16 +183,15 @@ describe('EditMemberDrawer', () => {
).toBeDisabled();
});
it('enables Save after editing name and calls update API on confirm', async () => {
it('enables Save after editing name and calls updateUser on confirm', async () => {
const onComplete = jest.fn();
const user = userEvent.setup({ pointerEventsCheck: 0 });
const mockMutateAsync = jest.fn().mockResolvedValue({});
(useUpdateUserDeprecated as jest.Mock).mockImplementation((options) => ({
mutate: mockUpdateMutate.mockImplementation(() => {
options?.mutation?.onSuccess?.();
}),
(useUpdateUser as jest.Mock).mockReturnValue({
mutateAsync: mockMutateAsync,
isLoading: false,
}));
});
renderDrawer({ onComplete });
@@ -153,12 +205,92 @@ describe('EditMemberDrawer', () => {
await user.click(saveBtn);
await waitFor(() => {
expect(mockUpdateMutate).toHaveBeenCalledWith(
expect.objectContaining({
pathParams: { id: 'user-1' },
data: expect.objectContaining({ displayName: 'Alice Updated' }),
}),
);
expect(mockMutateAsync).toHaveBeenCalledWith({
pathParams: { id: 'user-1' },
data: { displayName: 'Alice Updated' },
});
expect(onComplete).toHaveBeenCalled();
});
});
it('does not close the drawer after a successful save', async () => {
const onClose = jest.fn();
const user = userEvent.setup({ pointerEventsCheck: 0 });
renderDrawer({ onClose });
const nameInput = screen.getByDisplayValue('Alice Smith');
await user.clear(nameInput);
await user.type(nameInput, 'Alice Updated');
const saveBtn = screen.getByRole('button', { name: /save member details/i });
await waitFor(() => expect(saveBtn).not.toBeDisabled());
await user.click(saveBtn);
await waitFor(() => {
expect(
screen.getByRole('button', { name: /save member details/i }),
).toBeInTheDocument();
});
expect(onClose).not.toHaveBeenCalled();
});
it('calls setRole when a new role is added', async () => {
const onComplete = jest.fn();
const user = userEvent.setup({ pointerEventsCheck: 0 });
const mockSet = jest.fn().mockResolvedValue({});
(useSetRoleByUserID as jest.Mock).mockReturnValue({
mutateAsync: mockSet,
isLoading: false,
});
renderDrawer({ onComplete });
// Open the roles dropdown and select signoz-editor
await user.click(screen.getByLabelText('Roles'));
await user.click(await screen.findByTitle('signoz-editor'));
const saveBtn = screen.getByRole('button', { name: /save member details/i });
await waitFor(() => expect(saveBtn).not.toBeDisabled());
await user.click(saveBtn);
await waitFor(() => {
expect(mockSet).toHaveBeenCalledWith({
pathParams: { id: 'user-1' },
data: { name: 'signoz-editor' },
});
expect(onComplete).toHaveBeenCalled();
});
});
it('calls removeRole when an existing role is removed', async () => {
const onComplete = jest.fn();
const user = userEvent.setup({ pointerEventsCheck: 0 });
const mockRemove = jest.fn().mockResolvedValue({});
(useRemoveUserRoleByUserIDAndRoleID as jest.Mock).mockReturnValue({
mutateAsync: mockRemove,
isLoading: false,
});
renderDrawer({ onComplete });
// Wait for the signoz-admin tag to appear, then click its remove button
const adminTag = await screen.findByTitle('signoz-admin');
const removeBtn = adminTag.querySelector(
'.ant-select-selection-item-remove',
) as Element;
await user.click(removeBtn);
const saveBtn = screen.getByRole('button', { name: /save member details/i });
await waitFor(() => expect(saveBtn).not.toBeDisabled());
await user.click(saveBtn);
await waitFor(() => {
expect(mockRemove).toHaveBeenCalledWith({
pathParams: { id: 'user-1', roleId: managedRoles[0].id },
});
expect(onComplete).toHaveBeenCalled();
});
});
@@ -239,16 +371,33 @@ describe('EditMemberDrawer', () => {
});
});
it('calls update API when saving changes for an invited member', async () => {
it('calls updateUser when saving name change for an invited member', async () => {
const onComplete = jest.fn();
const user = userEvent.setup({ pointerEventsCheck: 0 });
const mockMutateAsync = jest.fn().mockResolvedValue({});
(useUpdateUserDeprecated as jest.Mock).mockImplementation((options) => ({
mutate: mockUpdateMutate.mockImplementation(() => {
options?.mutation?.onSuccess?.();
}),
(useGetUser as jest.Mock).mockReturnValue({
data: {
data: {
...mockFetchedUser.data,
id: 'abc123',
displayName: 'Bob',
userRoles: [
{
id: 'ur-2',
roleId: managedRoles[2].id,
role: managedRoles[2], // signoz-viewer
},
],
},
},
isLoading: false,
}));
refetch: jest.fn(),
});
(useUpdateUser as jest.Mock).mockReturnValue({
mutateAsync: mockMutateAsync,
isLoading: false,
});
renderDrawer({ member: { ...invitedMember, name: 'Bob' }, onComplete });
@@ -261,12 +410,10 @@ describe('EditMemberDrawer', () => {
await user.click(saveBtn);
await waitFor(() => {
expect(mockUpdateMutate).toHaveBeenCalledWith(
expect.objectContaining({
pathParams: { id: 'abc123' },
data: expect.objectContaining({ displayName: 'Bob Updated' }),
}),
);
expect(mockMutateAsync).toHaveBeenCalledWith({
pathParams: { id: 'abc123' },
data: { displayName: 'Bob Updated' },
});
expect(onComplete).toHaveBeenCalled();
});
});
@@ -280,16 +427,13 @@ describe('EditMemberDrawer', () => {
} as ReturnType<typeof convertToApiError>);
});
it('shows API error message when updateUser fails', async () => {
it('shows SaveErrorItem when updateUser fails for name change', async () => {
const user = userEvent.setup({ pointerEventsCheck: 0 });
const mockToast = jest.mocked(toast);
(useUpdateUserDeprecated as jest.Mock).mockImplementation((options) => ({
mutate: mockUpdateMutate.mockImplementation(() => {
options?.mutation?.onError?.({});
}),
(useUpdateUser as jest.Mock).mockReturnValue({
mutateAsync: jest.fn().mockRejectedValue(new Error('server error')),
isLoading: false,
}));
});
renderDrawer();
@@ -302,10 +446,9 @@ describe('EditMemberDrawer', () => {
await user.click(saveBtn);
await waitFor(() => {
expect(mockToast.error).toHaveBeenCalledWith(
'Failed to update member details: Something went wrong on server',
expect.anything(),
);
expect(
screen.getByText('Name update: Something went wrong on server'),
).toBeInTheDocument();
});
});

View File

@@ -4,9 +4,7 @@ import { Table, Tooltip } from 'antd';
import type { ColumnsType, SorterResult } from 'antd/es/table/interface';
import { DATE_TIME_FORMATS } from 'constants/dateTimeFormats';
import { MemberStatus } from 'container/MembersSettings/utils';
import { capitalize } from 'lodash-es';
import { useTimezone } from 'providers/Timezone';
import { ROLES } from 'types/roles';
import './MembersTable.styles.scss';
@@ -14,7 +12,6 @@ export interface MemberRow {
id: string;
name?: string;
email: string;
role: ROLES;
status: MemberStatus;
joinedOn: string | null;
updatedAt?: string | null;
@@ -141,17 +138,6 @@ function MembersTable({
<NameEmailCell name={record.name} email={record.email} />
),
},
{
title: 'Roles',
dataIndex: 'role',
key: 'role',
width: 180,
sorter: (a, b): number => a.role.localeCompare(b.role),
render: (role: ROLES): JSX.Element => (
<Badge color="vanilla">{capitalize(role)}</Badge>
),
},
{
title: 'Status',
dataIndex: 'status',

View File

@@ -1,6 +1,5 @@
import { MemberStatus } from 'container/MembersSettings/utils';
import { render, screen, userEvent } from 'tests/test-utils';
import { ROLES } from 'types/roles';
import MembersTable, { MemberRow } from '../MembersTable';
@@ -9,7 +8,6 @@ const mockActiveMembers: MemberRow[] = [
id: 'user-1',
name: 'Alice Smith',
email: 'alice@signoz.io',
role: 'ADMIN' as ROLES,
status: MemberStatus.Active,
joinedOn: '1700000000000',
},
@@ -17,7 +15,6 @@ const mockActiveMembers: MemberRow[] = [
id: 'user-2',
name: 'Bob Jones',
email: 'bob@signoz.io',
role: 'VIEWER' as ROLES,
status: MemberStatus.Active,
joinedOn: null,
},
@@ -27,7 +24,6 @@ const mockInvitedMember: MemberRow = {
id: 'inv-abc',
name: '',
email: 'charlie@signoz.io',
role: 'EDITOR' as ROLES,
status: MemberStatus.Invited,
joinedOn: null,
};
@@ -47,12 +43,11 @@ describe('MembersTable', () => {
jest.clearAllMocks();
});
it('renders member rows with name, email, role badge, and ACTIVE status', () => {
it('renders member rows with name, email, and ACTIVE status', () => {
render(<MembersTable {...defaultProps} data={mockActiveMembers} />);
expect(screen.getByText('Alice Smith')).toBeInTheDocument();
expect(screen.getByText('alice@signoz.io')).toBeInTheDocument();
expect(screen.getByText('Admin')).toBeInTheDocument();
expect(screen.getAllByText('ACTIVE')).toHaveLength(2);
});
@@ -67,7 +62,6 @@ describe('MembersTable', () => {
expect(screen.getByText('INVITED')).toBeInTheDocument();
expect(screen.getByText('charlie@signoz.io')).toBeInTheDocument();
expect(screen.getByText('Editor')).toBeInTheDocument();
});
it('calls onRowClick with the member data when a row is clicked', async () => {
@@ -99,7 +93,6 @@ describe('MembersTable', () => {
id: 'user-del',
name: 'Dave Deleted',
email: 'dave@signoz.io',
role: 'VIEWER' as ROLES,
status: MemberStatus.Deleted,
joinedOn: null,
};

View File

@@ -284,6 +284,15 @@ export default function TableViewActions(
error,
);
}
// If the value is valid JSON (object or array), pretty-print it for copying
try {
const parsed = JSON.parse(text);
if (typeof parsed === 'object' && parsed !== null) {
return JSON.stringify(parsed, null, 2);
}
} catch {
// not JSON, return as-is
}
return text;
}, [fieldData.value]);

View File

@@ -1,17 +1,15 @@
import { useCallback, useEffect, useMemo, useState } from 'react';
import { useQuery } from 'react-query';
import { useHistory } from 'react-router-dom';
import { Button } from '@signozhq/button';
import { Check, ChevronDown, Plus } from '@signozhq/icons';
import { Input } from '@signozhq/input';
import type { MenuProps } from 'antd';
import { Dropdown } from 'antd';
import getAll from 'api/v1/user/get';
import { useListUsers } from 'api/generated/services/users';
import EditMemberDrawer from 'components/EditMemberDrawer/EditMemberDrawer';
import InviteMembersModal from 'components/InviteMembersModal/InviteMembersModal';
import MembersTable, { MemberRow } from 'components/MembersTable/MembersTable';
import useUrlQuery from 'hooks/useUrlQuery';
import { useAppContext } from 'providers/App/App';
import { toISOString } from 'utils/app';
import { FilterMode, MemberStatus, toMemberStatus } from './utils';
@@ -21,7 +19,6 @@ import './MembersSettings.styles.scss';
const PAGE_SIZE = 20;
function MembersSettings(): JSX.Element {
const { org } = useAppContext();
const history = useHistory();
const urlQuery = useUrlQuery();
@@ -34,18 +31,14 @@ function MembersSettings(): JSX.Element {
const [isInviteModalOpen, setIsInviteModalOpen] = useState(false);
const [selectedMember, setSelectedMember] = useState<MemberRow | null>(null);
const { data: usersData, isLoading, refetch: refetchUsers } = useQuery({
queryFn: getAll,
queryKey: ['getOrgUser', org?.[0]?.id],
});
const { data: usersData, isLoading, refetch: refetchUsers } = useListUsers();
const allMembers = useMemo(
(): MemberRow[] =>
(usersData?.data ?? []).map((user) => ({
id: user.id,
name: user.displayName,
email: user.email,
role: user.role,
email: user.email ?? '',
status: toMemberStatus(user.status ?? ''),
joinedOn: toISOString(user.createdAt),
updatedAt: toISOString(user?.updatedAt),
@@ -64,9 +57,7 @@ function MembersSettings(): JSX.Element {
const q = searchQuery.toLowerCase();
result = result.filter(
(m) =>
m?.name?.toLowerCase().includes(q) ||
m.email.toLowerCase().includes(q) ||
m.role.toLowerCase().includes(q),
m?.name?.toLowerCase().includes(q) || m.email.toLowerCase().includes(q),
);
}
@@ -148,7 +139,6 @@ function MembersSettings(): JSX.Element {
const handleMemberEditComplete = useCallback((): void => {
refetchUsers();
setSelectedMember(null);
}, [refetchUsers]);
return (
@@ -181,7 +171,7 @@ function MembersSettings(): JSX.Element {
<div className="members-settings__search">
<Input
type="search"
placeholder="Search by name, email, or role..."
placeholder="Search by name or email..."
value={searchQuery}
onChange={(e): void => {
setSearchQuery(e.target.value);

View File

@@ -1,6 +1,6 @@
import type { TypesUserDTO } from 'api/generated/services/sigNoz.schemas';
import { rest, server } from 'mocks-server/server';
import { render, screen, userEvent } from 'tests/test-utils';
import { UserResponse } from 'types/api/user/getUser';
import MembersSettings from '../MembersSettings';
@@ -11,47 +11,39 @@ jest.mock('@signozhq/sonner', () => ({
},
}));
const USERS_ENDPOINT = '*/api/v1/user';
const USERS_ENDPOINT = '*/api/v2/users';
const mockUsers: UserResponse[] = [
const mockUsers: TypesUserDTO[] = [
{
id: 'user-1',
displayName: 'Alice Smith',
email: 'alice@signoz.io',
role: 'ADMIN',
status: 'active',
createdAt: '2024-01-01T00:00:00.000Z',
organization: 'TestOrg',
createdAt: new Date('2024-01-01T00:00:00.000Z'),
orgId: 'org-1',
},
{
id: 'user-2',
displayName: 'Bob Jones',
email: 'bob@signoz.io',
role: 'VIEWER',
status: 'active',
createdAt: '2024-01-02T00:00:00.000Z',
organization: 'TestOrg',
createdAt: new Date('2024-01-02T00:00:00.000Z'),
orgId: 'org-1',
},
{
id: 'inv-1',
displayName: '',
email: 'charlie@signoz.io',
role: 'EDITOR',
status: 'pending_invite',
createdAt: '2024-01-03T00:00:00.000Z',
organization: 'TestOrg',
createdAt: new Date('2024-01-03T00:00:00.000Z'),
orgId: 'org-1',
},
{
id: 'user-3',
displayName: 'Dave Deleted',
email: 'dave@signoz.io',
role: 'VIEWER',
status: 'deleted',
createdAt: '2024-01-04T00:00:00.000Z',
organization: 'TestOrg',
createdAt: new Date('2024-01-04T00:00:00.000Z'),
orgId: 'org-1',
},
];
@@ -106,7 +98,7 @@ describe('MembersSettings (integration)', () => {
await screen.findByText('Alice Smith');
await user.type(
screen.getByPlaceholderText(/Search by name, email, or role/i),
screen.getByPlaceholderText(/Search by name or email/i),
'bob',
);

View File

@@ -2,8 +2,8 @@ import { useState } from 'react';
import { useTranslation } from 'react-i18next';
import { Button, Input, Modal, Typography } from 'antd';
import logEvent from 'api/common/logEvent';
import { useUpdateMyUserV2 } from 'api/generated/services/users';
import changeMyPassword from 'api/v1/factor_password/changeMyPassword';
import editUser from 'api/v1/user/id/update';
import { useNotifications } from 'hooks/useNotifications';
import { Check, FileTerminal, MailIcon, UserIcon } from 'lucide-react';
import { useAppContext } from 'providers/App/App';
@@ -17,6 +17,7 @@ function UserInfo(): JSX.Element {
const { t } = useTranslation(['routes', 'settings', 'common']);
const { notifications } = useNotifications();
const { mutateAsync: updateMyUser } = useUpdateMyUserV2();
const [currentPassword, setCurrentPassword] = useState<string>('');
const [updatePassword, setUpdatePassword] = useState<string>('');
@@ -92,10 +93,7 @@ function UserInfo(): JSX.Element {
);
try {
setIsLoading(true);
await editUser({
displayName: changedName,
userId: user.id,
});
await updateMyUser({ data: { displayName: changedName } });
notifications.success({
message: t('success', {

View File

@@ -22,9 +22,12 @@ jest.mock('react-use', () => ({
],
}));
jest.mock('api/v1/user/id/update', () => ({
__esModule: true,
default: (...args: unknown[]): Promise<unknown> => editUserFn(...args),
jest.mock('api/generated/services/users', () => ({
...jest.requireActual('api/generated/services/users'),
useUpdateMyUserV2: jest.fn(() => ({
mutateAsync: (...args: unknown[]): Promise<unknown> => editUserFn(...args),
isLoading: false,
})),
}));
jest.mock('hooks/useDarkMode', () => ({

View File

@@ -1,8 +1,10 @@
import { useState } from 'react';
import { useTranslation } from 'react-i18next';
import { toast } from '@signozhq/sonner';
import { Button, Form, Input } from 'antd';
import editOrg from 'api/organization/editOrg';
import { useNotifications } from 'hooks/useNotifications';
import { convertToApiError } from 'api/ErrorResponseHandlerForGeneratedAPIs';
import { useUpdateMyOrganization } from 'api/generated/services/orgs';
import type { RenderErrorResponseDTO } from 'api/generated/services/sigNoz.schemas';
import { AxiosError } from 'axios';
import { useAppContext } from 'providers/App/App';
import { IUser } from 'providers/App/types';
import { requireErrorMessage } from 'utils/form/requireErrorMessage';
@@ -14,42 +16,34 @@ function DisplayName({ index, id: orgId }: DisplayNameProps): JSX.Element {
const { t } = useTranslation(['organizationsettings', 'common']);
const { org, updateOrg } = useAppContext();
const { displayName } = (org || [])[index];
const [isLoading, setIsLoading] = useState<boolean>(false);
const { notifications } = useNotifications();
const {
mutateAsync: updateMyOrganization,
isLoading,
} = useUpdateMyOrganization({
mutation: {
onSuccess: (_, { data }) => {
toast.success(t('success', { ns: 'common' }), {
richColors: true,
position: 'top-right',
});
updateOrg(orgId, data.displayName ?? '');
},
onError: (error) => {
const apiError = convertToApiError(
error as AxiosError<RenderErrorResponseDTO>,
);
toast.error(
apiError?.getErrorMessage() ?? t('something_went_wrong', { ns: 'common' }),
{ richColors: true, position: 'top-right' },
);
},
},
});
const onSubmit = async (values: FormValues): Promise<void> => {
try {
setIsLoading(true);
const { displayName } = values;
const { statusCode, error } = await editOrg({
displayName,
orgId,
});
if (statusCode === 204) {
notifications.success({
message: t('success', {
ns: 'common',
}),
});
updateOrg(orgId, displayName);
} else {
notifications.error({
message:
error ||
t('something_went_wrong', {
ns: 'common',
}),
});
}
setIsLoading(false);
} catch (error) {
setIsLoading(false);
notifications.error({
message: t('something_went_wrong', {
ns: 'common',
}),
});
}
const { displayName } = values;
await updateMyOrganization({ data: { id: orgId, displayName } });
};
if (!org) {

View File

@@ -0,0 +1,101 @@
import { useCallback, useMemo } from 'react';
import type { AuthtypesRoleDTO } from 'api/generated/services/sigNoz.schemas';
import {
useGetUser,
useRemoveUserRoleByUserIDAndRoleID,
useSetRoleByUserID,
} from 'api/generated/services/users';
export interface MemberRoleUpdateFailure {
roleName: string;
error: unknown;
onRetry: () => Promise<void>;
}
interface UseMemberRoleManagerResult {
fetchedRoleIds: string[];
isLoading: boolean;
applyDiff: (
localRoleIds: string[],
availableRoles: AuthtypesRoleDTO[],
) => Promise<MemberRoleUpdateFailure[]>;
}
export function useMemberRoleManager(
userId: string,
enabled: boolean,
): UseMemberRoleManagerResult {
const { data: fetchedUser, isLoading } = useGetUser(
{ id: userId },
{ query: { enabled: !!userId && enabled } },
);
const currentUserRoles = useMemo(() => fetchedUser?.data?.userRoles ?? [], [
fetchedUser,
]);
const fetchedRoleIds = useMemo(
() =>
currentUserRoles
.map((ur) => ur.role?.id ?? ur.roleId)
.filter((id): id is string => Boolean(id)),
[currentUserRoles],
);
const { mutateAsync: setRole } = useSetRoleByUserID();
const { mutateAsync: removeRole } = useRemoveUserRoleByUserIDAndRoleID();
const applyDiff = useCallback(
async (
localRoleIds: string[],
availableRoles: AuthtypesRoleDTO[],
): Promise<MemberRoleUpdateFailure[]> => {
const currentRoleIdSet = new Set(fetchedRoleIds);
const desiredRoleIdSet = new Set(localRoleIds.filter(Boolean));
const toRemove = currentUserRoles.filter((ur) => {
const id = ur.role?.id ?? ur.roleId;
return id && !desiredRoleIdSet.has(id);
});
const toAdd = availableRoles.filter(
(r) => r.id && desiredRoleIdSet.has(r.id) && !currentRoleIdSet.has(r.id),
);
const allOps = [
...toRemove.map((ur) => ({
roleName: ur.role?.name ?? 'unknown',
run: (): ReturnType<typeof removeRole> =>
removeRole({
pathParams: {
id: userId,
roleId: ur.role?.id ?? ur.roleId ?? '',
},
}),
})),
...toAdd.map((role) => ({
roleName: role.name ?? 'unknown',
run: (): ReturnType<typeof setRole> =>
setRole({
pathParams: { id: userId },
data: { name: role.name ?? '' },
}),
})),
];
const results = await Promise.allSettled(allOps.map((op) => op.run()));
const failures: MemberRoleUpdateFailure[] = [];
results.forEach((result, i) => {
if (result.status === 'rejected') {
const { roleName, run } = allOps[i];
failures.push({ roleName, error: result.reason, onRetry: run });
}
});
return failures;
},
[userId, fetchedRoleIds, currentUserRoles, setRole, removeRole],
);
return { fetchedRoleIds, isLoading, applyDiff };
}

View File

@@ -1,15 +0,0 @@
import { useQuery, UseQueryResult } from 'react-query';
import getUser from 'api/v1/user/id/get';
import { SuccessResponseV2 } from 'types/api';
import { UserResponse } from 'types/api/user/getUser';
const useGetUser = (userId: string, isLoggedIn: boolean): UseGetUser =>
useQuery({
queryFn: () => getUser({ userId }),
queryKey: [userId],
enabled: !!userId && !!isLoggedIn,
});
type UseGetUser = UseQueryResult<SuccessResponseV2<UserResponse>, unknown>;
export default useGetUser;

View File

@@ -12,8 +12,9 @@ import {
import { useQuery } from 'react-query';
import getLocalStorageApi from 'api/browser/localstorage/get';
import setLocalStorageApi from 'api/browser/localstorage/set';
import { useGetMyOrganization } from 'api/generated/services/orgs';
import { useGetMyUser } from 'api/generated/services/users';
import listOrgPreferences from 'api/v1/org/preferences/list';
import get from 'api/v1/user/me/get';
import listUserPreferences from 'api/v1/user/preferences/list';
import getUserVersion from 'api/v1/version/get';
import { LOCALSTORAGE } from 'constants/localStorage';
@@ -40,7 +41,9 @@ import {
UserPreference,
} from 'types/api/preferences/preference';
import { Organization } from 'types/api/user/getOrganization';
import { UserResponse } from 'types/api/user/getUser';
import { ROLES, USER_ROLES } from 'types/roles';
import { toISOString } from 'utils/app';
import { IAppContext, IUser } from './types';
import { getUserDefaults } from './utils';
@@ -71,17 +74,23 @@ export function AppProvider({ children }: PropsWithChildren): JSX.Element {
const [showChangelogModal, setShowChangelogModal] = useState<boolean>(false);
// fetcher for user
// fetcher for current user
// user will only be fetched if the user id and token is present
// if logged out and trying to hit any route none of these calls will trigger
const {
data: userData,
isFetching: isFetchingUserData,
error: userFetchDataError,
} = useQuery({
queryFn: get,
queryKey: ['/api/v1/user/me'],
enabled: isLoggedIn,
} = useGetMyUser({
query: { enabled: isLoggedIn },
});
const {
data: orgData,
isFetching: isFetchingOrgData,
error: orgFetchDataError,
} = useGetMyOrganization({
query: { enabled: isLoggedIn },
});
const {
@@ -93,8 +102,10 @@ export function AppProvider({ children }: PropsWithChildren): JSX.Element {
enabled: isLoggedIn,
});
const isFetchingUser = isFetchingUserData || isFetchingPermissions;
const userFetchError = userFetchDataError || errorOnPermissions;
const isFetchingUser =
isFetchingUserData || isFetchingOrgData || isFetchingPermissions;
const userFetchError =
userFetchDataError || orgFetchDataError || errorOnPermissions;
const userRole = useMemo(() => {
if (permissionsResult?.[IsAdminPermission]?.isGranted) {
@@ -118,38 +129,55 @@ export function AppProvider({ children }: PropsWithChildren): JSX.Element {
}, [defaultUser, userRole]);
useEffect(() => {
if (!isFetchingUser && userData && userData.data) {
setLocalStorageApi(LOCALSTORAGE.LOGGED_IN_USER_EMAIL, userData.data.email);
if (!isFetchingUserData && userData?.data) {
setLocalStorageApi(
LOCALSTORAGE.LOGGED_IN_USER_EMAIL,
userData.data.email ?? '',
);
setDefaultUser((prev) => ({
...prev,
...userData.data,
id: userData.data.id,
displayName: userData.data.displayName ?? prev.displayName,
email: userData.data.email ?? prev.email,
orgId: userData.data.orgId ?? prev.orgId,
isRoot: userData.data.isRoot,
status: userData.data.status as UserResponse['status'],
createdAt: toISOString(userData.data.createdAt) ?? prev.createdAt,
updatedAt: toISOString(userData.data.updatedAt) ?? prev.updatedAt,
}));
}
}, [userData, isFetchingUserData]);
useEffect(() => {
if (!isFetchingOrgData && orgData?.data) {
const { id: orgId, displayName: orgDisplayName } = orgData.data;
setOrg((prev) => {
if (!prev) {
// if no org is present enter a new entry
return [{ createdAt: 0, id: orgId, displayName: orgDisplayName ?? '' }];
}
const orgIndex = prev.findIndex((e) => e.id === orgId);
if (orgIndex === -1) {
return [
{
createdAt: 0,
id: userData.data.orgId,
displayName: userData.data.organization,
},
...prev,
{ createdAt: 0, id: orgId, displayName: orgDisplayName ?? '' },
];
}
// else mutate the existing entry
const orgIndex = prev.findIndex((e) => e.id === userData.data.orgId);
const updatedOrg: Organization[] = [
...prev.slice(0, orgIndex),
{
createdAt: 0,
id: userData.data.orgId,
displayName: userData.data.organization,
},
...prev.slice(orgIndex + 1, prev.length),
{ createdAt: 0, id: orgId, displayName: orgDisplayName ?? '' },
...prev.slice(orgIndex + 1),
];
return updatedOrg;
});
setDefaultUser((prev) => ({
...prev,
organization: orgDisplayName ?? prev.organization,
}));
}
}, [userData, isFetchingUser]);
}, [orgData, isFetchingOrgData]);
// fetcher for licenses v3
const {
@@ -273,6 +301,9 @@ export function AppProvider({ children }: PropsWithChildren): JSX.Element {
(orgId: string, updatedOrgName: string): void => {
if (org && org.length > 0) {
const orgIndex = org.findIndex((e) => e.id === orgId);
if (orgIndex === -1) {
return;
}
const updatedOrg: Organization[] = [
...org.slice(0, orgIndex),
{
@@ -280,7 +311,7 @@ export function AppProvider({ children }: PropsWithChildren): JSX.Element {
id: orgId,
displayName: updatedOrgName,
},
...org.slice(orgIndex + 1, org.length),
...org.slice(orgIndex + 1),
];
setOrg(updatedOrg);
setDefaultUser((prev) => {

View File

@@ -2,7 +2,7 @@ import { ReactElement } from 'react';
import { QueryClient, QueryClientProvider } from 'react-query';
import { renderHook, waitFor } from '@testing-library/react';
import setLocalStorageApi from 'api/browser/localstorage/set';
import {
import type {
AuthtypesGettableTransactionDTO,
AuthtypesTransactionDTO,
} from 'api/generated/services/sigNoz.schemas';
@@ -15,6 +15,8 @@ import { USER_ROLES } from 'types/roles';
import { AppProvider, useAppContext } from '../App';
const AUTHZ_CHECK_URL = 'http://localhost/api/v1/authz/check';
const MY_USER_URL = 'http://localhost/api/v2/users/me';
const MY_ORG_URL = 'http://localhost/api/v2/orgs/me';
jest.mock('constants/env', () => ({
ENVIRONMENT: { baseURL: 'http://localhost', wsURL: '' },
@@ -227,6 +229,132 @@ describe('AppProvider user.role from permissions', () => {
});
});
describe('AppProvider user and org data from v2 APIs', () => {
beforeEach(() => {
queryClient.clear();
setLocalStorageApi(LOCALSTORAGE.IS_LOGGED_IN, 'true');
});
it('populates user fields from GET /api/v2/users/me', async () => {
server.use(
rest.get(MY_USER_URL, (_, res, ctx) =>
res(
ctx.status(200),
ctx.json({
data: {
id: 'u-123',
displayName: 'Test User',
email: 'test@signoz.io',
orgId: 'org-abc',
isRoot: false,
status: 'active',
},
}),
),
),
rest.get(MY_ORG_URL, (_, res, ctx) =>
res(
ctx.status(200),
ctx.json({ data: { id: 'org-abc', displayName: 'My Org' } }),
),
),
rest.post(AUTHZ_CHECK_URL, async (req, res, ctx) => {
const payload = await req.json();
return res(
ctx.status(200),
ctx.json(authzMockResponse(payload, [false, false, false])),
);
}),
);
const wrapper = createWrapper();
const { result } = renderHook(() => useAppContext(), { wrapper });
await waitFor(
() => {
expect(result.current.user.id).toBe('u-123');
expect(result.current.user.displayName).toBe('Test User');
expect(result.current.user.email).toBe('test@signoz.io');
expect(result.current.user.orgId).toBe('org-abc');
},
{ timeout: 2000 },
);
});
it('populates org state from GET /api/v2/orgs/me', async () => {
server.use(
rest.get(MY_ORG_URL, (_, res, ctx) =>
res(
ctx.status(200),
ctx.json({
data: {
id: 'org-abc',
displayName: 'My Org',
},
}),
),
),
rest.get(MY_USER_URL, (_, res, ctx) =>
res(
ctx.status(200),
ctx.json({ data: { id: 'u-default', email: 'default@signoz.io' } }),
),
),
rest.post(AUTHZ_CHECK_URL, async (req, res, ctx) => {
const payload = await req.json();
return res(
ctx.status(200),
ctx.json(authzMockResponse(payload, [false, false, false])),
);
}),
);
const wrapper = createWrapper();
const { result } = renderHook(() => useAppContext(), { wrapper });
await waitFor(
() => {
expect(result.current.org).not.toBeNull();
const org = result.current.org?.[0];
expect(org?.id).toBe('org-abc');
expect(org?.displayName).toBe('My Org');
},
{ timeout: 2000 },
);
});
it('sets isFetchingUser false once both user and org calls complete', async () => {
server.use(
rest.get(MY_USER_URL, (_, res, ctx) =>
res(ctx.status(200), ctx.json({ data: { id: 'u-1', email: 'a@b.com' } })),
),
rest.get(MY_ORG_URL, (_, res, ctx) =>
res(
ctx.status(200),
ctx.json({ data: { id: 'org-1', displayName: 'Org' } }),
),
),
rest.post(AUTHZ_CHECK_URL, async (req, res, ctx) => {
const payload = await req.json();
return res(
ctx.status(200),
ctx.json(authzMockResponse(payload, [false, false, false])),
);
}),
);
const wrapper = createWrapper();
const { result } = renderHook(() => useAppContext(), { wrapper });
await waitFor(
() => {
expect(result.current.isFetchingUser).toBe(false);
},
{ timeout: 2000 },
);
});
});
describe('AppProvider when authz/check fails', () => {
beforeEach(() => {
queryClient.clear();

View File

@@ -50,6 +50,11 @@ func (handler *healthOpenAPIHandler) ServeOpenAPI(opCtx openapi.OperationContext
)
}
func (handler *healthOpenAPIHandler) AuditDef() *pkghandler.AuditDef {
// Health endpoints are not audited since they don't represent user actions and are called frequently by monitoring systems, which would create noise in the audit logs.
return nil
}
func (provider *provider) addRegistryRoutes(router *mux.Router) error {
if err := router.Handle("/api/v2/healthz", newHealthOpenAPIHandler(
provider.authZ.OpenAccess(provider.factoryHandler.Healthz),

View File

@@ -21,11 +21,15 @@ func newTestSettings() factory.ScopedProviderSettings {
func newTestEvent(resource string, action audittypes.Action) audittypes.AuditEvent {
return audittypes.AuditEvent{
Timestamp: time.Now(),
EventName: audittypes.NewEventName(resource, action),
ResourceName: resource,
Action: action,
Outcome: audittypes.OutcomeSuccess,
Timestamp: time.Now(),
EventName: audittypes.NewEventName(resource, action),
AuditAttributes: audittypes.AuditAttributes{
Action: action,
Outcome: audittypes.OutcomeSuccess,
},
ResourceAttributes: audittypes.ResourceAttributes{
ResourceName: resource,
},
}
}

View File

@@ -20,6 +20,12 @@ var (
CodeLicenseUnavailable = Code{"license_unavailable"}
)
var (
// Used when reverse engineering an error from a response that doesn't have a code.
// This should never be used in the codebase, and if it is, it's a bug that should be fixed by using proper error handling and including error codes in responses.
CodeUnset = Code{"unset"}
)
var (
codeRegex = regexp.MustCompile(`^[a-z_]+$`)
)

View File

@@ -15,14 +15,16 @@ type ServeOpenAPIFunc func(openapi.OperationContext)
type Handler interface {
http.Handler
ServeOpenAPI(openapi.OperationContext)
AuditDef() *AuditDef
}
type handler struct {
handlerFunc http.HandlerFunc
openAPIDef OpenAPIDef
auditDef *AuditDef
}
func New(handlerFunc http.HandlerFunc, openAPIDef OpenAPIDef) Handler {
func New(handlerFunc http.HandlerFunc, openAPIDef OpenAPIDef, opts ...Option) Handler {
// Remove duplicate error status codes
openAPIDef.ErrorStatusCodes = slices.DeleteFunc(openAPIDef.ErrorStatusCodes, func(statusCode int) bool {
return statusCode == http.StatusUnauthorized || statusCode == http.StatusForbidden || statusCode == http.StatusInternalServerError
@@ -36,10 +38,16 @@ func New(handlerFunc http.HandlerFunc, openAPIDef OpenAPIDef) Handler {
openAPIDef.ErrorStatusCodes = append(openAPIDef.ErrorStatusCodes, http.StatusUnauthorized, http.StatusForbidden)
}
return &handler{
handler := &handler{
handlerFunc: handlerFunc,
openAPIDef: openAPIDef,
}
for _, opt := range opts {
opt(handler)
}
return handler
}
func (handler *handler) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
@@ -120,5 +128,8 @@ func (handler *handler) ServeOpenAPI(opCtx openapi.OperationContext) {
openapi.WithHTTPStatus(statusCode),
)
}
}
func (handler *handler) AuditDef() *AuditDef {
return handler.auditDef
}

View File

@@ -0,0 +1,24 @@
package handler
import (
"github.com/SigNoz/signoz/pkg/types/audittypes"
)
// Option configures optional behaviour on a handler created by New.
type Option func(*handler)
type AuditDef struct {
ResourceName string // AuthZ Typeable.Name() value, e.g. "dashboard", "user".
Action audittypes.Action // create, update, delete, login, etc.
Category audittypes.ActionCategory // access_control, configuration_change, etc.
ResourceIDParam string // Gorilla mux path param name for the resource ID.
}
// WithAudit attaches an AuditDef to the handler. The actual audit event
// emission is handled by the middleware layer, which reads the AuditDef
// from the matched route's handler.
func WithAuditDef(def AuditDef) Option {
return func(h *handler) {
h.auditDef = &def
}
}

View File

@@ -0,0 +1,169 @@
package middleware
import (
"log/slog"
"net"
"net/http"
"time"
"github.com/gorilla/mux"
semconv "go.opentelemetry.io/otel/semconv/v1.26.0"
"go.opentelemetry.io/otel/trace"
"github.com/SigNoz/signoz/pkg/auditor"
"github.com/SigNoz/signoz/pkg/errors"
"github.com/SigNoz/signoz/pkg/http/handler"
"github.com/SigNoz/signoz/pkg/http/render"
"github.com/SigNoz/signoz/pkg/types/audittypes"
"github.com/SigNoz/signoz/pkg/types/authtypes"
)
const (
logMessage = "::RECEIVED-REQUEST::"
)
type Audit struct {
logger *slog.Logger
excludedRoutes map[string]struct{}
auditor auditor.Auditor
}
func NewAudit(logger *slog.Logger, excludedRoutes []string, auditor auditor.Auditor) *Audit {
excludedRoutesMap := make(map[string]struct{})
for _, route := range excludedRoutes {
excludedRoutesMap[route] = struct{}{}
}
return &Audit{
logger: logger.With(slog.String("pkg", pkgname)),
excludedRoutes: excludedRoutesMap,
auditor: auditor,
}
}
func (middleware *Audit) Wrap(next http.Handler) http.Handler {
return http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
start := time.Now()
host, port, _ := net.SplitHostPort(req.Host)
path, err := mux.CurrentRoute(req).GetPathTemplate()
if err != nil {
path = req.URL.Path
}
fields := []any{
string(semconv.ClientAddressKey), req.RemoteAddr,
string(semconv.UserAgentOriginalKey), req.UserAgent(),
string(semconv.ServerAddressKey), host,
string(semconv.ServerPortKey), port,
string(semconv.HTTPRequestSizeKey), req.ContentLength,
string(semconv.HTTPRouteKey), path,
}
responseBuffer := &byteBuffer{}
writer := newResponseCapture(rw, responseBuffer)
next.ServeHTTP(writer, req)
statusCode, writeErr := writer.StatusCode(), writer.WriteError()
// Logging or Audit: skip if the matched route is in the excluded list. This allows us to exclude noisy routes (e.g. health checks) from both logging and audit.
if _, ok := middleware.excludedRoutes[path]; ok {
return
}
middleware.emitAuditEvent(req, writer, path)
fields = append(fields,
string(semconv.HTTPResponseStatusCodeKey), statusCode,
string(semconv.HTTPServerRequestDurationName), time.Since(start),
)
if writeErr != nil {
fields = append(fields, errors.Attr(writeErr))
middleware.logger.ErrorContext(req.Context(), logMessage, fields...)
} else {
if responseBuffer.Len() != 0 {
fields = append(fields, "response.body", responseBuffer.String())
}
middleware.logger.InfoContext(req.Context(), logMessage, fields...)
}
})
}
func (middleware *Audit) emitAuditEvent(req *http.Request, writer responseCapture, routeTemplate string) {
if middleware.auditor == nil {
return
}
def := auditDefFromRequest(req)
if def == nil {
return
}
// extract claims
claims, _ := authtypes.ClaimsFromContext(req.Context())
// extract status code
statusCode := writer.StatusCode()
// extract traces.
span := trace.SpanFromContext(req.Context())
// extract error details.
var errorType, errorCode string
if statusCode >= 400 {
errorType = render.ErrorTypeFromStatusCode(statusCode)
errorCode = render.ErrorCodeFromBody(writer.BodyBytes())
}
event := audittypes.NewAuditEventFromHTTPRequest(
req,
routeTemplate,
statusCode,
span.SpanContext().TraceID(),
span.SpanContext().SpanID(),
def.Action,
def.Category,
claims,
resourceIDFromRequest(req, def.ResourceIDParam),
def.ResourceName,
errorType,
errorCode,
)
middleware.auditor.Audit(req.Context(), event)
}
func auditDefFromRequest(req *http.Request) *handler.AuditDef {
route := mux.CurrentRoute(req)
if route == nil {
return nil
}
actualHandler := route.GetHandler()
if actualHandler == nil {
return nil
}
// The type assertion is necessary because route.GetHandler() returns
// http.Handler, and not every http.Handler on the mux is a handler.Handler
// (e.g. middleware wrappers, raw http.HandlerFunc registrations).
provider, ok := actualHandler.(handler.Handler)
if !ok {
return nil
}
return provider.AuditDef()
}
func resourceIDFromRequest(req *http.Request, param string) string {
if param == "" {
return ""
}
vars := mux.Vars(req)
if vars == nil {
return ""
}
return vars[param]
}

View File

@@ -1,81 +0,0 @@
package middleware
import (
"bytes"
"log/slog"
"net"
"net/http"
"time"
"github.com/gorilla/mux"
semconv "go.opentelemetry.io/otel/semconv/v1.26.0"
"github.com/SigNoz/signoz/pkg/errors"
)
const (
logMessage string = "::RECEIVED-REQUEST::"
)
type Logging struct {
logger *slog.Logger
excludedRoutes map[string]struct{}
}
func NewLogging(logger *slog.Logger, excludedRoutes []string) *Logging {
excludedRoutesMap := make(map[string]struct{})
for _, route := range excludedRoutes {
excludedRoutesMap[route] = struct{}{}
}
return &Logging{
logger: logger.With(slog.String("pkg", pkgname)),
excludedRoutes: excludedRoutesMap,
}
}
func (middleware *Logging) Wrap(next http.Handler) http.Handler {
return http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
start := time.Now()
host, port, _ := net.SplitHostPort(req.Host)
path, err := mux.CurrentRoute(req).GetPathTemplate()
if err != nil {
path = req.URL.Path
}
fields := []any{
string(semconv.ClientAddressKey), req.RemoteAddr,
string(semconv.UserAgentOriginalKey), req.UserAgent(),
string(semconv.ServerAddressKey), host,
string(semconv.ServerPortKey), port,
string(semconv.HTTPRequestSizeKey), req.ContentLength,
string(semconv.HTTPRouteKey), path,
}
badResponseBuffer := new(bytes.Buffer)
writer := newBadResponseLoggingWriter(rw, badResponseBuffer)
next.ServeHTTP(writer, req)
// if the path is in the excludedRoutes map, don't log
if _, ok := middleware.excludedRoutes[path]; ok {
return
}
statusCode, err := writer.StatusCode(), writer.WriteError()
fields = append(fields,
string(semconv.HTTPResponseStatusCodeKey), statusCode,
string(semconv.HTTPServerRequestDurationName), time.Since(start),
)
if err != nil {
fields = append(fields, errors.Attr(err))
middleware.logger.ErrorContext(req.Context(), logMessage, fields...)
} else {
// when the status code is 400 or >=500, and the response body is not empty.
if badResponseBuffer.Len() != 0 {
fields = append(fields, "response.body", badResponseBuffer.String())
}
middleware.logger.InfoContext(req.Context(), logMessage, fields...)
}
})
}

View File

@@ -2,7 +2,6 @@ package middleware
import (
"bufio"
"io"
"net"
"net/http"
@@ -10,118 +9,156 @@ import (
)
const (
maxResponseBodyInLogs = 4096 // At most 4k bytes from response bodies in our logs.
maxResponseBodyCapture int = 4096 // At most 4k bytes from response bodies.
)
type badResponseLoggingWriter interface {
// Wraps an http.ResponseWriter to capture the status code,
// write errors, and (for error responses) a bounded slice of the body.
type responseCapture interface {
http.ResponseWriter
// Get the status code.
// StatusCode returns the HTTP status code written to the response.
StatusCode() int
// Get the error while writing.
// WriteError returns the error (if any) from the downstream Write call.
WriteError() error
// BodyBytes returns the captured response body bytes. Only populated
// for error responses (status >= 400).
BodyBytes() []byte
}
func newBadResponseLoggingWriter(rw http.ResponseWriter, buffer io.Writer) badResponseLoggingWriter {
b := nonFlushingBadResponseLoggingWriter{
func newResponseCapture(rw http.ResponseWriter, buffer *byteBuffer) responseCapture {
b := nonFlushingResponseCapture{
rw: rw,
buffer: buffer,
logBody: false,
bodyBytesLeft: maxResponseBodyInLogs,
captureBody: false,
bodyBytesLeft: maxResponseBodyCapture,
statusCode: http.StatusOK,
}
if f, ok := rw.(http.Flusher); ok {
return &flushingBadResponseLoggingWriter{b, f}
return &flushingResponseCapture{nonFlushingResponseCapture: b, f: f}
}
return &b
}
type nonFlushingBadResponseLoggingWriter struct {
rw http.ResponseWriter
buffer io.Writer
logBody bool
bodyBytesLeft int
statusCode int
writeError error // The error returned when downstream Write() fails.
// byteBuffer is a minimal write-only buffer used to capture response bodies.
type byteBuffer struct {
buf []byte
}
// Extends nonFlushingBadResponseLoggingWriter that implements http.Flusher.
type flushingBadResponseLoggingWriter struct {
nonFlushingBadResponseLoggingWriter
func (b *byteBuffer) Write(p []byte) (int, error) {
b.buf = append(b.buf, p...)
return len(p), nil
}
func (b *byteBuffer) WriteString(s string) (int, error) {
b.buf = append(b.buf, s...)
return len(s), nil
}
func (b *byteBuffer) Bytes() []byte {
return b.buf
}
func (b *byteBuffer) Len() int {
return len(b.buf)
}
func (b *byteBuffer) String() string {
return string(b.buf)
}
type nonFlushingResponseCapture struct {
rw http.ResponseWriter
buffer *byteBuffer
captureBody bool
bodyBytesLeft int
statusCode int
writeError error
}
type flushingResponseCapture struct {
nonFlushingResponseCapture
f http.Flusher
}
// Unwrap method is used by http.ResponseController to get access to original http.ResponseWriter.
func (writer *nonFlushingBadResponseLoggingWriter) Unwrap() http.ResponseWriter {
// Unwrap is used by http.ResponseController to get access to original http.ResponseWriter.
func (writer *nonFlushingResponseCapture) Unwrap() http.ResponseWriter {
return writer.rw
}
// Header returns the header map that will be sent by WriteHeader.
// Implements ResponseWriter.
func (writer *nonFlushingBadResponseLoggingWriter) Header() http.Header {
func (writer *nonFlushingResponseCapture) Header() http.Header {
return writer.rw.Header()
}
// WriteHeader writes the HTTP response header.
func (writer *nonFlushingBadResponseLoggingWriter) WriteHeader(statusCode int) {
func (writer *nonFlushingResponseCapture) WriteHeader(statusCode int) {
writer.statusCode = statusCode
if statusCode >= 500 || statusCode == 400 {
writer.logBody = true
if statusCode >= 400 {
writer.captureBody = true
}
writer.rw.WriteHeader(statusCode)
}
// Writes HTTP response data.
func (writer *nonFlushingBadResponseLoggingWriter) Write(data []byte) (int, error) {
// Write writes HTTP response data.
func (writer *nonFlushingResponseCapture) Write(data []byte) (int, error) {
if writer.statusCode == 0 {
// WriteHeader has (probably) not been called, so we need to call it with StatusOK to fulfill the interface contract.
// https://godoc.org/net/http#ResponseWriter
writer.WriteHeader(http.StatusOK)
}
// 204 No Content is a success response that indicates that the request has been successfully processed and that the response body is intentionally empty.
if writer.statusCode == 204 {
return 0, nil
}
n, err := writer.rw.Write(data)
if writer.logBody {
if writer.captureBody {
writer.captureResponseBody(data)
}
if err != nil {
writer.writeError = err
}
return n, err
}
// Hijack hijacks the first response writer that is a Hijacker.
func (writer *nonFlushingBadResponseLoggingWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) {
func (writer *nonFlushingResponseCapture) Hijack() (net.Conn, *bufio.ReadWriter, error) {
hj, ok := writer.rw.(http.Hijacker)
if ok {
return hj.Hijack()
}
return nil, nil, errors.NewInternalf(errors.CodeInternal, "cannot cast underlying response writer to Hijacker")
}
func (writer *nonFlushingBadResponseLoggingWriter) StatusCode() int {
func (writer *nonFlushingResponseCapture) StatusCode() int {
return writer.statusCode
}
func (writer *nonFlushingBadResponseLoggingWriter) WriteError() error {
func (writer *nonFlushingResponseCapture) WriteError() error {
return writer.writeError
}
func (writer *flushingBadResponseLoggingWriter) Flush() {
func (writer *nonFlushingResponseCapture) BodyBytes() []byte {
return writer.buffer.Bytes()
}
func (writer *flushingResponseCapture) Flush() {
writer.f.Flush()
}
func (writer *nonFlushingBadResponseLoggingWriter) captureResponseBody(data []byte) {
func (writer *nonFlushingResponseCapture) captureResponseBody(data []byte) {
if len(data) > writer.bodyBytesLeft {
_, _ = writer.buffer.Write(data[:writer.bodyBytesLeft])
_, _ = io.WriteString(writer.buffer, "...")
_, _ = writer.buffer.WriteString("...")
writer.bodyBytesLeft = 0
writer.logBody = false
writer.captureBody = false
} else {
_, _ = writer.buffer.Write(data)
writer.bodyBytesLeft -= len(data)

View File

@@ -0,0 +1,88 @@
package middleware
import (
"io"
"net/http"
"net/http/httptest"
"strings"
"testing"
"github.com/stretchr/testify/assert"
)
func TestResponseCapture(t *testing.T) {
t.Parallel()
testCases := []struct {
name string
handler http.HandlerFunc
expectedStatus int
expectedBodyBytes string
expectedClientBody string
}{
{
name: "Success_DoesNotCaptureBody",
handler: func(rw http.ResponseWriter, req *http.Request) {
rw.WriteHeader(http.StatusOK)
_, _ = rw.Write([]byte(`{"status":"success","data":{"id":"123"}}`))
},
expectedStatus: http.StatusOK,
expectedBodyBytes: "",
expectedClientBody: `{"status":"success","data":{"id":"123"}}`,
},
{
name: "Error_CapturesBody",
handler: func(rw http.ResponseWriter, req *http.Request) {
rw.WriteHeader(http.StatusForbidden)
_, _ = rw.Write([]byte(`{"status":"error","error":{"code":"authz_forbidden","message":"forbidden"}}`))
},
expectedStatus: http.StatusForbidden,
expectedBodyBytes: `{"status":"error","error":{"code":"authz_forbidden","message":"forbidden"}}`,
expectedClientBody: `{"status":"error","error":{"code":"authz_forbidden","message":"forbidden"}}`,
},
{
name: "Error_TruncatesAtMaxCapture",
handler: func(rw http.ResponseWriter, req *http.Request) {
rw.WriteHeader(http.StatusInternalServerError)
_, _ = rw.Write([]byte(strings.Repeat("x", maxResponseBodyCapture+100)))
},
expectedStatus: http.StatusInternalServerError,
expectedBodyBytes: strings.Repeat("x", maxResponseBodyCapture) + "...",
expectedClientBody: strings.Repeat("x", maxResponseBodyCapture+100),
},
{
name: "NoContent_SuppressesWrite",
handler: func(rw http.ResponseWriter, req *http.Request) {
rw.WriteHeader(http.StatusNoContent)
_, _ = rw.Write([]byte("should be suppressed"))
},
expectedStatus: http.StatusNoContent,
expectedBodyBytes: "",
expectedClientBody: "",
},
}
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
t.Parallel()
var captured responseCapture
server := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
buf := &byteBuffer{}
captured = newResponseCapture(rw, buf)
testCase.handler(captured, req)
}))
defer server.Close()
resp, err := http.Get(server.URL)
assert.NoError(t, err)
defer resp.Body.Close()
clientBody, _ := io.ReadAll(resp.Body)
assert.Equal(t, testCase.expectedStatus, captured.StatusCode())
assert.Equal(t, testCase.expectedBodyBytes, string(captured.BodyBytes()))
assert.Equal(t, testCase.expectedClientBody, string(clientBody))
})
}
}

View File

@@ -5,6 +5,7 @@ import (
"github.com/SigNoz/signoz/pkg/errors"
jsoniter "github.com/json-iterator/go"
"github.com/tidwall/gjson"
)
const (
@@ -42,6 +43,45 @@ func Success(rw http.ResponseWriter, httpCode int, data interface{}) {
_, _ = rw.Write(body)
}
func ErrorCodeFromBody(body []byte) string {
code := gjson.GetBytes(body, "error.code").String()
// This should never return empty since we only call this function on responses that were generated by us.
// If it does return empty, the codebase has failed to use render package for error responses somewhere, and we should fix that instead of trying to handle it here.
if code == "" {
return errors.CodeUnset.String()
}
return code
}
func ErrorTypeFromStatusCode(statusCode int) string {
// We are losing the exact type information here, but we can at least capture the error code and message for better observability.
// To get the exact type, we would need some changes in the render package to include the error type in the response, which we can consider in the future if there is a need for it.
switch statusCode {
case http.StatusBadRequest:
return errors.TypeInvalidInput.String()
case http.StatusNotFound:
return errors.TypeNotFound.String()
case http.StatusConflict:
return errors.TypeAlreadyExists.String()
case http.StatusUnauthorized:
return errors.TypeUnauthenticated.String()
case http.StatusNotImplemented:
return errors.TypeUnsupported.String()
case http.StatusForbidden:
return errors.TypeForbidden.String()
case statusClientClosedConnection:
return errors.TypeCanceled.String()
case http.StatusGatewayTimeout:
return errors.TypeTimeout.String()
case http.StatusUnavailableForLegalReasons:
return errors.TypeLicenseUnavailable.String()
default:
return errors.TypeInternal.String()
}
}
func Error(rw http.ResponseWriter, cause error) {
// Derive the http code from the error type
t, _, _, _, _, _ := errors.Unwrapb(cause)

View File

@@ -58,6 +58,31 @@ func TestSuccess(t *testing.T) {
assert.Equal(t, expected, actual)
}
func TestErrorCodeFromBody(t *testing.T) {
testCases := []struct {
name string
body []byte
wantCode string
}{
{
name: "ValidErrorResponse",
body: []byte(`{"status":"error","error":{"code":"authz_forbidden","message":"only admins can access this resource"}}`),
wantCode: "authz_forbidden",
},
{
name: "InvalidJSON",
body: []byte(`not json`),
wantCode: "unset",
},
}
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
assert.Equal(t, testCase.wantCode, ErrorCodeFromBody(testCase.body))
})
}
}
func TestError(t *testing.T) {
listener, err := net.Listen("tcp", "localhost:0")
require.NoError(t, err)

View File

@@ -0,0 +1,21 @@
package implcloudintegration
import (
"context"
citypes "github.com/SigNoz/signoz/pkg/types/cloudintegrationtypes"
)
type definitionStore struct{}
func NewDefinitionStore() citypes.ServiceDefinitionStore {
return &definitionStore{}
}
func (d *definitionStore) Get(ctx context.Context, provider citypes.CloudProviderType, serviceID citypes.ServiceID) (*citypes.ServiceDefinition, error) {
panic("unimplemented")
}
func (d *definitionStore) List(ctx context.Context, provider citypes.CloudProviderType) ([]*citypes.ServiceDefinition, error) {
panic("unimplemented")
}

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 85 85" fill="#fff" fill-rule="evenodd" stroke="#000" stroke-linecap="round" stroke-linejoin="round"><use xlink:href="#A" x="2.5" y="2.5"/><symbol id="A" overflow="visible"><g stroke="none"><path d="M0 41.579C0 20.293 17.84 3.157 40 3.157s40 17.136 40 38.422S62.16 80 40 80 0 62.864 0 41.579z" fill="#9d5025"/><path d="M0 38.422C0 17.136 17.84 0 40 0s40 17.136 40 38.422-17.84 38.422-40 38.422S0 59.707 0 38.422z" fill="#f58536"/><path d="M51.672 7.387v13.952H28.327V7.387zm18.061 40.378v11.364h-11.83V47.765zm-14.958 0v11.364h-11.83V47.765zm-18.206 0v11.364h-11.83V47.765zm-14.959 0v11.364H9.78V47.765z"/><path d="M14.63 37.929h2.13v11.149h-2.13z"/><path d="M14.63 37.929h17.088v2.045H14.63z"/><path d="M29.589 37.929h2.13v11.149H29.59zm18.206 0h2.13v11.149h-2.13z"/><path d="M47.795 37.929h17.088v2.045H47.795z"/><path d="M62.754 37.929h2.13v11.149h-2.129zm-40.631-7.954h2.13v8.977h-2.13zM38.935 19.28h2.13v10.859h-2.129z"/><path d="M22.123 29.116h35.32v2.045h-35.32z"/><path d="M55.314 29.975h2.13v8.977h-2.129z"/></g></symbol></svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -0,0 +1,468 @@
{
"id": "alb",
"title": "ALB",
"icon": "file://icon.svg",
"overview": "file://overview.md",
"supportedSignals": {
"metrics": true,
"logs": false
},
"dataCollected": {
"metrics": [
{
"name": "aws_ApplicationELB_ActiveConnectionCount_count",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ApplicationELB_ActiveConnectionCount_max",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ApplicationELB_ActiveConnectionCount_min",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ApplicationELB_ActiveConnectionCount_sum",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ApplicationELB_AnomalousHostCount_count",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ApplicationELB_AnomalousHostCount_max",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ApplicationELB_AnomalousHostCount_min",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ApplicationELB_AnomalousHostCount_sum",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ApplicationELB_ConsumedLCUs_count",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ApplicationELB_ConsumedLCUs_max",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ApplicationELB_ConsumedLCUs_min",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ApplicationELB_ConsumedLCUs_sum",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ApplicationELB_HTTPCode_Target_2XX_Count_count",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ApplicationELB_HTTPCode_Target_2XX_Count_max",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ApplicationELB_HTTPCode_Target_2XX_Count_min",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ApplicationELB_HTTPCode_Target_2XX_Count_sum",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ApplicationELB_HTTPCode_Target_4XX_Count_count",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ApplicationELB_HTTPCode_Target_4XX_Count_max",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ApplicationELB_HTTPCode_Target_4XX_Count_min",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ApplicationELB_HTTPCode_Target_4XX_Count_sum",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ApplicationELB_HealthyHostCount_count",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ApplicationELB_HealthyHostCount_max",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ApplicationELB_HealthyHostCount_min",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ApplicationELB_HealthyHostCount_sum",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ApplicationELB_HealthyStateDNS_count",
"unit": "None",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ApplicationELB_HealthyStateDNS_max",
"unit": "None",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ApplicationELB_HealthyStateDNS_min",
"unit": "None",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ApplicationELB_HealthyStateDNS_sum",
"unit": "None",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ApplicationELB_HealthyStateRouting_count",
"unit": "None",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ApplicationELB_HealthyStateRouting_max",
"unit": "None",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ApplicationELB_HealthyStateRouting_min",
"unit": "None",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ApplicationELB_HealthyStateRouting_sum",
"unit": "None",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ApplicationELB_MitigatedHostCount_count",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ApplicationELB_MitigatedHostCount_max",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ApplicationELB_MitigatedHostCount_min",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ApplicationELB_MitigatedHostCount_sum",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ApplicationELB_NewConnectionCount_count",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ApplicationELB_NewConnectionCount_max",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ApplicationELB_NewConnectionCount_min",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ApplicationELB_NewConnectionCount_sum",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ApplicationELB_PeakLCUs_count",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ApplicationELB_PeakLCUs_max",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ApplicationELB_PeakLCUs_min",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ApplicationELB_PeakLCUs_sum",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ApplicationELB_ProcessedBytes_count",
"unit": "Bytes",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ApplicationELB_ProcessedBytes_max",
"unit": "Bytes",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ApplicationELB_ProcessedBytes_min",
"unit": "Bytes",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ApplicationELB_ProcessedBytes_sum",
"unit": "Bytes",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ApplicationELB_RequestCountPerTarget_count",
"unit": "None",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ApplicationELB_RequestCountPerTarget_max",
"unit": "None",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ApplicationELB_RequestCountPerTarget_min",
"unit": "None",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ApplicationELB_RequestCountPerTarget_sum",
"unit": "None",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ApplicationELB_RequestCount_count",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ApplicationELB_RequestCount_max",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ApplicationELB_RequestCount_min",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ApplicationELB_RequestCount_sum",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ApplicationELB_TargetResponseTime_count",
"unit": "Seconds",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ApplicationELB_TargetResponseTime_max",
"unit": "Seconds",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ApplicationELB_TargetResponseTime_min",
"unit": "Seconds",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ApplicationELB_TargetResponseTime_sum",
"unit": "Seconds",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ApplicationELB_UnHealthyHostCount_count",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ApplicationELB_UnHealthyHostCount_max",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ApplicationELB_UnHealthyHostCount_min",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ApplicationELB_UnHealthyHostCount_sum",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ApplicationELB_UnhealthyStateDNS_count",
"unit": "None",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ApplicationELB_UnhealthyStateDNS_max",
"unit": "None",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ApplicationELB_UnhealthyStateDNS_min",
"unit": "None",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ApplicationELB_UnhealthyStateDNS_sum",
"unit": "None",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ApplicationELB_UnhealthyStateRouting_count",
"unit": "None",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ApplicationELB_UnhealthyStateRouting_max",
"unit": "None",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ApplicationELB_UnhealthyStateRouting_min",
"unit": "None",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ApplicationELB_UnhealthyStateRouting_sum",
"unit": "None",
"type": "Gauge",
"description": ""
}
],
"logs": []
},
"telemetryCollectionStrategy": {
"aws": {
"metrics": {
"cloudwatchMetricStreamFilters": [
{
"Namespace": "AWS/ApplicationELB"
}
]
}
}
},
"assets": {
"dashboards": [
{
"id": "overview",
"title": "ALB Overview",
"description": "Overview of Application Load Balancer",
"definition": "file://assets/dashboards/overview.json"
}
]
}
}

View File

@@ -0,0 +1,3 @@
### Monitor Application Load Balancers with SigNoz
Collect key ALB metrics and view them with an out of the box dashboard.

View File

@@ -0,0 +1,14 @@
<svg width="24px" height="24px" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<linearGradient x1="0%" y1="100%" x2="100%" y2="0%" id="linearGradient-1">
<stop stop-color="#4D27A8" offset="0%"></stop>
<stop stop-color="#A166FF" offset="100%"></stop>
</linearGradient>
</defs>
<g stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g fill="url(#linearGradient-1)">
<rect id="Rectangle" x="0" y="0" width="24" height="24"></rect>
</g>
<path d="M6,6.76751613 L8,5.43446738 L8,18.5659476 L6,17.2328988 L6,6.76751613 Z M5,6.49950633 L5,17.4999086 C5,17.6669147 5.084,17.8239204 5.223,17.9159238 L8.223,19.9159969 C8.307,19.971999 8.403,20 8.5,20 C8.581,20 8.662,19.9809993 8.736,19.9409978 C8.898,19.8539947 9,19.6849885 9,19.4999817 L9,16.9998903 L10,16.9998903 L10,15.9998537 L9,15.9998537 L9,7.99956118 L10,7.99956118 L10,6.99952461 L9,6.99952461 L9,4.49943319 C9,4.31542646 8.898,4.14542025 8.736,4.0594171 C8.574,3.97241392 8.377,3.98141425 8.223,4.08341798 L5.223,6.08349112 C5.084,6.17649452 5,6.33250022 5,6.49950633 L5,6.49950633 Z M19,17.2328988 L17,18.5659476 L17,5.43446738 L19,6.76751613 L19,17.2328988 Z M19.777,6.08349112 L16.777,4.08341798 C16.623,3.98141425 16.426,3.97241392 16.264,4.0594171 C16.102,4.14542025 16,4.31542646 16,4.49943319 L16,6.99952461 L15,6.99952461 L15,7.99956118 L16,7.99956118 L16,15.9998537 L15,15.9998537 L15,16.9998903 L16,16.9998903 L16,19.4999817 C16,19.6849885 16.102,19.8539947 16.264,19.9409978 C16.338,19.9809993 16.419,20 16.5,20 C16.597,20 16.693,19.971999 16.777,19.9159969 L19.777,17.9159238 C19.916,17.8239204 20,17.6669147 20,17.4999086 L20,6.49950633 C20,6.33250022 19.916,6.17649452 19.777,6.08349112 L19.777,6.08349112 Z M13,7.99956118 L14,7.99956118 L14,6.99952461 L13,6.99952461 L13,7.99956118 Z M11,7.99956118 L12,7.99956118 L12,6.99952461 L11,6.99952461 L11,7.99956118 Z M13,16.9998903 L14,16.9998903 L14,15.9998537 L13,15.9998537 L13,16.9998903 Z M11,16.9998903 L12,16.9998903 L12,15.9998537 L11,15.9998537 L11,16.9998903 Z M13.18,14.884813 L10.18,12.3847215 C10.065,12.288718 10,12.1487129 10,11.9997075 C10,11.851702 10.065,11.7106969 10.18,11.6156934 L13.18,9.11560199 L13.82,9.88463011 L11.281,11.9997075 L13.82,14.1157848 L13.18,14.884813 Z" id="Amazon-API-Gateway_Icon_16_Squid" fill="#FFFFFF"></path>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.4 KiB

View File

@@ -0,0 +1,200 @@
{
"id": "api-gateway",
"title": "API Gateway",
"icon": "file://icon.svg",
"overview": "file://overview.md",
"supportedSignals": {
"metrics": true,
"logs": true
},
"dataCollected": {
"metrics": [
{
"name": "aws_ApiGateway_4XXError_count",
"unit": "Count",
"type": "Gauge"
},
{
"name": "aws_ApiGateway_4XXError_max",
"unit": "Count",
"type": "Gauge"
},
{
"name": "aws_ApiGateway_4XXError_min",
"unit": "Count",
"type": "Gauge"
},
{
"name": "aws_ApiGateway_4XXError_sum",
"unit": "Count",
"type": "Gauge"
},
{
"name": "aws_ApiGateway_5XXError_count",
"unit": "Count",
"type": "Gauge"
},
{
"name": "aws_ApiGateway_5XXError_max",
"unit": "Count",
"type": "Gauge"
},
{
"name": "aws_ApiGateway_5XXError_min",
"unit": "Count",
"type": "Gauge"
},
{
"name": "aws_ApiGateway_5XXError_sum",
"unit": "Count",
"type": "Gauge"
},
{
"name": "aws_ApiGateway_CacheHitCount_count",
"unit": "Count",
"type": "Gauge"
},
{
"name": "aws_ApiGateway_CacheHitCount_max",
"unit": "Count",
"type": "Gauge"
},
{
"name": "aws_ApiGateway_CacheHitCount_min",
"unit": "Count",
"type": "Gauge"
},
{
"name": "aws_ApiGateway_CacheHitCount_sum",
"unit": "Count",
"type": "Gauge"
},
{
"name": "aws_ApiGateway_CacheMissCount_count",
"unit": "Count",
"type": "Gauge"
},
{
"name": "aws_ApiGateway_CacheMissCount_max",
"unit": "Count",
"type": "Gauge"
},
{
"name": "aws_ApiGateway_CacheMissCount_min",
"unit": "Count",
"type": "Gauge"
},
{
"name": "aws_ApiGateway_CacheMissCount_sum",
"unit": "Count",
"type": "Gauge"
},
{
"name": "aws_ApiGateway_Count_count",
"unit": "Count",
"type": "Gauge"
},
{
"name": "aws_ApiGateway_Count_max",
"unit": "Count",
"type": "Gauge"
},
{
"name": "aws_ApiGateway_Count_min",
"unit": "Count",
"type": "Gauge"
},
{
"name": "aws_ApiGateway_Count_sum",
"unit": "Count",
"type": "Gauge"
},
{
"name": "aws_ApiGateway_IntegrationLatency_count",
"unit": "Milliseconds",
"type": "Gauge"
},
{
"name": "aws_ApiGateway_IntegrationLatency_max",
"unit": "Milliseconds",
"type": "Gauge"
},
{
"name": "aws_ApiGateway_IntegrationLatency_min",
"unit": "Milliseconds",
"type": "Gauge"
},
{
"name": "aws_ApiGateway_IntegrationLatency_sum",
"unit": "Milliseconds",
"type": "Gauge"
},
{
"name": "aws_ApiGateway_Latency_count",
"unit": "Milliseconds",
"type": "Gauge"
},
{
"name": "aws_ApiGateway_Latency_max",
"unit": "Milliseconds",
"type": "Gauge"
},
{
"name": "aws_ApiGateway_Latency_min",
"unit": "Milliseconds",
"type": "Gauge"
},
{
"name": "aws_ApiGateway_Latency_sum",
"unit": "Milliseconds",
"type": "Gauge"
}
],
"logs": [
{
"name": "Account Id",
"path": "resources.cloud.account.id",
"type": "string"
},
{
"name": "Log Group Name",
"path": "resources.aws.cloudwatch.log_group_name",
"type": "string"
},
{
"name": "Log Stream Name",
"path": "resources.aws.cloudwatch.log_stream_name",
"type": "string"
}
]
},
"telemetryCollectionStrategy": {
"aws": {
"metrics": {
"cloudwatchMetricStreamFilters": [
{
"Namespace": "AWS/ApiGateway"
}
]
},
"logs": {
"cloudwatchLogsSubscriptions": [
{
"logGroupNamePrefix": "API-Gateway",
"filterPattern": ""
}
]
}
}
},
"assets": {
"dashboards": [
{
"id": "overview",
"title": "API Gateway Overview",
"description": "Overview of API Gateway",
"definition": "file://assets/dashboards/overview.json"
}
]
}
}

View File

@@ -0,0 +1,3 @@
### Monitor API Gateway with SigNoz
Collect key API Gateway metrics and view them with an out of the box dashboard.

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 6.2 KiB

View File

@@ -0,0 +1,395 @@
{
"id": "dynamodb",
"title": "DynamoDB",
"icon": "file://icon.svg",
"overview": "file://overview.md",
"supportedSignals": {
"metrics": true,
"logs": false
},
"dataCollected": {
"metrics": [
{
"name": "aws_DynamoDB_AccountMaxReads_count",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_DynamoDB_AccountMaxReads_max",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_DynamoDB_AccountMaxReads_min",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_DynamoDB_AccountMaxReads_sum",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_DynamoDB_AccountMaxTableLevelReads_count",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_DynamoDB_AccountMaxTableLevelReads_max",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_DynamoDB_AccountMaxTableLevelReads_min",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_DynamoDB_AccountMaxTableLevelReads_sum",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_DynamoDB_AccountMaxTableLevelWrites_count",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_DynamoDB_AccountMaxTableLevelWrites_max",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_DynamoDB_AccountMaxTableLevelWrites_min",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_DynamoDB_AccountMaxTableLevelWrites_sum",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_DynamoDB_AccountMaxWrites_count",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_DynamoDB_AccountMaxWrites_max",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_DynamoDB_AccountMaxWrites_min",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_DynamoDB_AccountMaxWrites_sum",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_DynamoDB_AccountProvisionedReadCapacityUtilization_count",
"unit": "Percent",
"type": "Gauge",
"description": ""
},
{
"name": "aws_DynamoDB_AccountProvisionedReadCapacityUtilization_max",
"unit": "Percent",
"type": "Gauge",
"description": ""
},
{
"name": "aws_DynamoDB_AccountProvisionedReadCapacityUtilization_min",
"unit": "Percent",
"type": "Gauge",
"description": ""
},
{
"name": "aws_DynamoDB_AccountProvisionedReadCapacityUtilization_sum",
"unit": "Percent",
"type": "Gauge",
"description": ""
},
{
"name": "aws_DynamoDB_AccountProvisionedWriteCapacityUtilization_count",
"unit": "Percent",
"type": "Gauge",
"description": ""
},
{
"name": "aws_DynamoDB_AccountProvisionedWriteCapacityUtilization_max",
"unit": "Percent",
"type": "Gauge",
"description": ""
},
{
"name": "aws_DynamoDB_AccountProvisionedWriteCapacityUtilization_min",
"unit": "Percent",
"type": "Gauge",
"description": ""
},
{
"name": "aws_DynamoDB_AccountProvisionedWriteCapacityUtilization_sum",
"unit": "Percent",
"type": "Gauge",
"description": ""
},
{
"name": "aws_DynamoDB_ConsumedReadCapacityUnits_count",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_DynamoDB_ConsumedReadCapacityUnits_max",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_DynamoDB_ConsumedReadCapacityUnits_min",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_DynamoDB_ConsumedReadCapacityUnits_sum",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_DynamoDB_ConsumedWriteCapacityUnits_count",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_DynamoDB_ConsumedWriteCapacityUnits_max",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_DynamoDB_ConsumedWriteCapacityUnits_min",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_DynamoDB_ConsumedWriteCapacityUnits_sum",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_DynamoDB_MaxProvisionedTableReadCapacityUtilization_count",
"unit": "Percent",
"type": "Gauge",
"description": ""
},
{
"name": "aws_DynamoDB_MaxProvisionedTableReadCapacityUtilization_max",
"unit": "Percent",
"type": "Gauge",
"description": ""
},
{
"name": "aws_DynamoDB_MaxProvisionedTableReadCapacityUtilization_min",
"unit": "Percent",
"type": "Gauge",
"description": ""
},
{
"name": "aws_DynamoDB_MaxProvisionedTableReadCapacityUtilization_sum",
"unit": "Percent",
"type": "Gauge",
"description": ""
},
{
"name": "aws_DynamoDB_MaxProvisionedTableWriteCapacityUtilization_count",
"unit": "Percent",
"type": "Gauge",
"description": ""
},
{
"name": "aws_DynamoDB_MaxProvisionedTableWriteCapacityUtilization_max",
"unit": "Percent",
"type": "Gauge",
"description": ""
},
{
"name": "aws_DynamoDB_MaxProvisionedTableWriteCapacityUtilization_min",
"unit": "Percent",
"type": "Gauge",
"description": ""
},
{
"name": "aws_DynamoDB_MaxProvisionedTableWriteCapacityUtilization_sum",
"unit": "Percent",
"type": "Gauge",
"description": ""
},
{
"name": "aws_DynamoDB_ReturnedItemCount_count",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_DynamoDB_ReturnedItemCount_max",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_DynamoDB_ReturnedItemCount_min",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_DynamoDB_ReturnedItemCount_sum",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_DynamoDB_SuccessfulRequestLatency_count",
"unit": "Milliseconds",
"type": "Gauge",
"description": ""
},
{
"name": "aws_DynamoDB_SuccessfulRequestLatency_max",
"unit": "Milliseconds",
"type": "Gauge",
"description": ""
},
{
"name": "aws_DynamoDB_SuccessfulRequestLatency_min",
"unit": "Milliseconds",
"type": "Gauge",
"description": ""
},
{
"name": "aws_DynamoDB_SuccessfulRequestLatency_sum",
"unit": "Milliseconds",
"type": "Gauge",
"description": ""
},
{
"name": "aws_DynamoDB_ThrottledRequests_count",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_DynamoDB_ThrottledRequests_max",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_DynamoDB_ThrottledRequests_min",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_DynamoDB_ThrottledRequests_sum",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_DynamoDB_UserErrors_count",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_DynamoDB_UserErrors_max",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_DynamoDB_UserErrors_min",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_DynamoDB_UserErrors_sum",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_DynamoDB_WriteThrottleEvents_count",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_DynamoDB_WriteThrottleEvents_max",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_DynamoDB_WriteThrottleEvents_min",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_DynamoDB_WriteThrottleEvents_sum",
"unit": "Count",
"type": "Gauge",
"description": ""
}
]
},
"telemetryCollectionStrategy": {
"aws": {
"metrics": {
"cloudwatchMetricStreamFilters": [
{
"Namespace": "AWS/DynamoDB"
}
]
}
}
},
"assets": {
"dashboards": [
{
"id": "overview",
"title": "DynamoDB Overview",
"description": "Overview of DynamoDB",
"definition": "file://assets/dashboards/overview.json"
}
]
}
}

View File

@@ -0,0 +1,3 @@
### Monitor DynamoDB with SigNoz
Collect DynamoDB Key Metrics and view them with an out of the box dashboard.

View File

@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<svg width="800px" height="800px" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" fill="none">
<path fill="#9D5025" d="M1.702 2.98L1 3.312v9.376l.702.332 2.842-4.777L1.702 2.98z" />
<path fill="#F58536" d="M3.339 12.657l-1.637.363V2.98l1.637.353v9.324z" />
<path fill="#9D5025" d="M2.476 2.612l.863-.406 4.096 6.216-4.096 5.372-.863-.406V2.612z" />
<path fill="#F58536" d="M5.38 13.248l-2.041.546V2.206l2.04.548v10.494z" />
<path fill="#9D5025" d="M4.3 1.75l1.08-.512 6.043 7.864-6.043 5.66-1.08-.511V1.749z" />
<path fill="#F58536" d="M7.998 13.856l-2.618.906V1.238l2.618.908v11.71z" />
<path fill="#9D5025" d="M6.602.66L7.998 0l6.538 8.453L7.998 16l-1.396-.66V.66z" />
<path fill="#F58536" d="M15 12.686L7.998 16V0L15 3.314v9.372z" />
</svg>

After

Width:  |  Height:  |  Size: 805 B

View File

@@ -0,0 +1,519 @@
{
"id": "ec2",
"title": "EC2",
"icon": "file://icon.svg",
"overview": "file://overview.md",
"supportedSignals": {
"metrics": true,
"logs": false
},
"dataCollected": {
"metrics": [
{
"name": "aws_EC2_CPUCreditBalance_count",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_EC2_CPUCreditBalance_max",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_EC2_CPUCreditBalance_min",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_EC2_CPUCreditBalance_sum",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_EC2_CPUCreditUsage_count",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_EC2_CPUCreditUsage_max",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_EC2_CPUCreditUsage_min",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_EC2_CPUCreditUsage_sum",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_EC2_CPUSurplusCreditBalance_count",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_EC2_CPUSurplusCreditBalance_max",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_EC2_CPUSurplusCreditBalance_min",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_EC2_CPUSurplusCreditBalance_sum",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_EC2_CPUSurplusCreditsCharged_count",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_EC2_CPUSurplusCreditsCharged_max",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_EC2_CPUSurplusCreditsCharged_min",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_EC2_CPUSurplusCreditsCharged_sum",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_EC2_CPUUtilization_count",
"unit": "Percent",
"type": "Gauge",
"description": ""
},
{
"name": "aws_EC2_CPUUtilization_max",
"unit": "Percent",
"type": "Gauge",
"description": ""
},
{
"name": "aws_EC2_CPUUtilization_min",
"unit": "Percent",
"type": "Gauge",
"description": ""
},
{
"name": "aws_EC2_CPUUtilization_sum",
"unit": "Percent",
"type": "Gauge",
"description": ""
},
{
"name": "aws_EC2_EBSByteBalance__count",
"unit": "Percent",
"type": "Gauge",
"description": ""
},
{
"name": "aws_EC2_EBSByteBalance__max",
"unit": "Percent",
"type": "Gauge",
"description": ""
},
{
"name": "aws_EC2_EBSByteBalance__min",
"unit": "Percent",
"type": "Gauge",
"description": ""
},
{
"name": "aws_EC2_EBSByteBalance__sum",
"unit": "Percent",
"type": "Gauge",
"description": ""
},
{
"name": "aws_EC2_EBSIOBalance__count",
"unit": "Percent",
"type": "Gauge",
"description": ""
},
{
"name": "aws_EC2_EBSIOBalance__max",
"unit": "Percent",
"type": "Gauge",
"description": ""
},
{
"name": "aws_EC2_EBSIOBalance__min",
"unit": "Percent",
"type": "Gauge",
"description": ""
},
{
"name": "aws_EC2_EBSIOBalance__sum",
"unit": "Percent",
"type": "Gauge",
"description": ""
},
{
"name": "aws_EC2_EBSReadBytes_count",
"unit": "Bytes",
"type": "Gauge",
"description": ""
},
{
"name": "aws_EC2_EBSReadBytes_max",
"unit": "Bytes",
"type": "Gauge",
"description": ""
},
{
"name": "aws_EC2_EBSReadBytes_min",
"unit": "Bytes",
"type": "Gauge",
"description": ""
},
{
"name": "aws_EC2_EBSReadBytes_sum",
"unit": "Bytes",
"type": "Gauge",
"description": ""
},
{
"name": "aws_EC2_EBSReadOps_count",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_EC2_EBSReadOps_max",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_EC2_EBSReadOps_min",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_EC2_EBSReadOps_sum",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_EC2_EBSWriteBytes_count",
"unit": "Bytes",
"type": "Gauge",
"description": ""
},
{
"name": "aws_EC2_EBSWriteBytes_max",
"unit": "Bytes",
"type": "Gauge",
"description": ""
},
{
"name": "aws_EC2_EBSWriteBytes_min",
"unit": "Bytes",
"type": "Gauge",
"description": ""
},
{
"name": "aws_EC2_EBSWriteBytes_sum",
"unit": "Bytes",
"type": "Gauge",
"description": ""
},
{
"name": "aws_EC2_EBSWriteOps_count",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_EC2_EBSWriteOps_max",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_EC2_EBSWriteOps_min",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_EC2_EBSWriteOps_sum",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_EC2_MetadataNoToken_count",
"unit": "None",
"type": "Gauge",
"description": ""
},
{
"name": "aws_EC2_MetadataNoToken_max",
"unit": "None",
"type": "Gauge",
"description": ""
},
{
"name": "aws_EC2_MetadataNoToken_min",
"unit": "None",
"type": "Gauge",
"description": ""
},
{
"name": "aws_EC2_MetadataNoToken_sum",
"unit": "None",
"type": "Gauge",
"description": ""
},
{
"name": "aws_EC2_NetworkIn_count",
"unit": "Bytes",
"type": "Gauge",
"description": ""
},
{
"name": "aws_EC2_NetworkIn_max",
"unit": "Bytes",
"type": "Gauge",
"description": ""
},
{
"name": "aws_EC2_NetworkIn_min",
"unit": "Bytes",
"type": "Gauge",
"description": ""
},
{
"name": "aws_EC2_NetworkIn_sum",
"unit": "Bytes",
"type": "Gauge",
"description": ""
},
{
"name": "aws_EC2_NetworkOut_count",
"unit": "Bytes",
"type": "Gauge",
"description": ""
},
{
"name": "aws_EC2_NetworkOut_max",
"unit": "Bytes",
"type": "Gauge",
"description": ""
},
{
"name": "aws_EC2_NetworkOut_min",
"unit": "Bytes",
"type": "Gauge",
"description": ""
},
{
"name": "aws_EC2_NetworkOut_sum",
"unit": "Bytes",
"type": "Gauge",
"description": ""
},
{
"name": "aws_EC2_NetworkPacketsIn_count",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_EC2_NetworkPacketsIn_max",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_EC2_NetworkPacketsIn_min",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_EC2_NetworkPacketsIn_sum",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_EC2_NetworkPacketsOut_count",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_EC2_NetworkPacketsOut_max",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_EC2_NetworkPacketsOut_min",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_EC2_NetworkPacketsOut_sum",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_EC2_StatusCheckFailed_AttachedEBS_count",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_EC2_StatusCheckFailed_AttachedEBS_max",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_EC2_StatusCheckFailed_AttachedEBS_min",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_EC2_StatusCheckFailed_AttachedEBS_sum",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_EC2_StatusCheckFailed_Instance_count",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_EC2_StatusCheckFailed_Instance_max",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_EC2_StatusCheckFailed_Instance_min",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_EC2_StatusCheckFailed_Instance_sum",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_EC2_StatusCheckFailed_System_count",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_EC2_StatusCheckFailed_System_max",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_EC2_StatusCheckFailed_System_min",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_EC2_StatusCheckFailed_System_sum",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_EC2_StatusCheckFailed_count",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_EC2_StatusCheckFailed_max",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_EC2_StatusCheckFailed_min",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_EC2_StatusCheckFailed_sum",
"unit": "Count",
"type": "Gauge",
"description": ""
}
],
"logs": []
},
"telemetryCollectionStrategy": {
"aws": {
"metrics": {
"cloudwatchMetricStreamFilters": [
{
"Namespace": "AWS/EC2"
},
{
"Namespace": "CWAgent"
}
]
}
}
},
"assets": {
"dashboards": [
{
"id": "overview",
"title": "EC2 Overview",
"description": "Overview of EC2",
"definition": "file://assets/dashboards/overview.json"
}
]
}
}

View File

@@ -0,0 +1,3 @@
### Monitor EC2 with SigNoz
Collect key EC2 metrics and view them with an out of the box dashboard.

View File

@@ -0,0 +1,851 @@
{
"description": "View key AWS ECS metrics with an out of the box dashboard.\n",
"image":"data:image/svg+xml,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22UTF-8%22%3F%3E%3Csvg%20width%3D%2280px%22%20height%3D%2280px%22%20viewBox%3D%220%200%2080%2080%22%20version%3D%221.1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%3E%3C!--%20Generator%3A%20Sketch%2064%20(93537)%20-%20https%3A%2F%2Fsketch.com%20--%3E%3Ctitle%3EIcon-Architecture%2F64%2FArch_Amazon-Elastic-Container-Service_64%3C%2Ftitle%3E%3Cdesc%3ECreated%20with%20Sketch.%3C%2Fdesc%3E%3Cdefs%3E%3ClinearGradient%20x1%3D%220%25%22%20y1%3D%22100%25%22%20x2%3D%22100%25%22%20y2%3D%220%25%22%20id%3D%22linearGradient-1%22%3E%3Cstop%20stop-color%3D%22%23C8511B%22%20offset%3D%220%25%22%3E%3C%2Fstop%3E%3Cstop%20stop-color%3D%22%23FF9900%22%20offset%3D%22100%25%22%3E%3C%2Fstop%3E%3C%2FlinearGradient%3E%3C%2Fdefs%3E%3Cg%20id%3D%22Icon-Architecture%2F64%2FArch_Amazon-Elastic-Container-Service_64%22%20stroke%3D%22none%22%20stroke-width%3D%221%22%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%3Cg%20id%3D%22Icon-Architecture-BG%2F64%2FContainers%22%20fill%3D%22url(%23linearGradient-1)%22%3E%3Crect%20id%3D%22Rectangle%22%20x%3D%220%22%20y%3D%220%22%20width%3D%2280%22%20height%3D%2280%22%3E%3C%2Frect%3E%3C%2Fg%3E%3Cpath%20d%3D%22M64%2C48.2340095%20L56%2C43.4330117%20L56%2C32.0000169%20C56%2C31.6440171%2055.812%2C31.3150172%2055.504%2C31.1360173%20L44%2C24.4260204%20L44%2C14.7520248%20L64%2C26.5710194%20L64%2C48.2340095%20Z%20M65.509%2C25.13902%20L43.509%2C12.139026%20C43.199%2C11.9560261%2042.818%2C11.9540261%2042.504%2C12.131026%20C42.193%2C12.3090259%2042%2C12.6410257%2042%2C13.0000256%20L42%2C25.0000201%20C42%2C25.3550199%2042.189%2C25.6840198%2042.496%2C25.8640197%20L54%2C32.5740166%20L54%2C44.0000114%20C54%2C44.3510113%2054.185%2C44.6770111%2054.486%2C44.857011%20L64.486%2C50.8570083%20C64.644%2C50.9520082%2064.822%2C51%2065%2C51%20C65.17%2C51%2065.34%2C50.9570082%2065.493%2C50.8700083%20C65.807%2C50.6930084%2066%2C50.3600085%2066%2C50%20L66%2C26.0000196%20C66%2C25.6460198%2065.814%2C25.31902%2065.509%2C25.13902%20L65.509%2C25.13902%20Z%20M40.445%2C66.863001%20L17%2C54.3990067%20L17%2C26.5710194%20L37%2C14.7520248%20L37%2C24.4510204%20L26.463%2C31.1560173%20C26.175%2C31.3400172%2026%2C31.6580171%2026%2C32.0000169%20L26%2C49.0000091%20C26%2C49.373009%2026.208%2C49.7150088%2026.538%2C49.8870087%20L39.991%2C56.8870055%20C40.28%2C57.0370055%2040.624%2C57.0380055%2040.912%2C56.8880055%20L53.964%2C50.1440086%20L61.996%2C54.9640064%20L40.445%2C66.863001%20Z%20M64.515%2C54.1420068%20L54.515%2C48.1420095%20C54.217%2C47.9640096%2053.849%2C47.9520096%2053.541%2C48.1120095%20L40.455%2C54.8730065%20L28%2C48.3930094%20L28%2C32.5490167%20L38.537%2C25.8440197%20C38.825%2C25.6600198%2039%2C25.3420199%2039%2C25.0000201%20L39%2C13.0000256%20C39%2C12.6410257%2038.808%2C12.3090259%2038.496%2C12.131026%20C38.184%2C11.9540261%2037.802%2C11.9560261%2037.491%2C12.139026%20L15.491%2C25.13902%20C15.187%2C25.31902%2015%2C25.6460198%2015%2C26.0000196%20L15%2C55%20C15%2C55.3690062%2015.204%2C55.7090061%2015.53%2C55.883006%20L39.984%2C68.8830001%20C40.131%2C68.961%2040.292%2C69%2040.453%2C69%20C40.62%2C69%2040.786%2C68.958%2040.937%2C68.8750001%20L64.484%2C55.875006%20C64.797%2C55.7020061%2064.993%2C55.3750062%2065.0001416%2C55.0180064%20C65.006%2C54.6600066%2064.821%2C54.3260067%2064.515%2C54.1420068%20L64.515%2C54.1420068%20Z%22%20id%3D%22Amazon-Elastic-Container-Service_Icon_64_Squid%22%20fill%3D%22%23FFFFFF%22%3E%3C%2Fpath%3E%3C%2Fg%3E%3C%2Fsvg%3E",
"layout": [
{
"h": 6,
"i": "f78becf8-0328-48b4-84b6-ff4dac325940",
"moved": false,
"static": false,
"w": 6,
"x": 0,
"y": 0
},
{
"h": 6,
"i": "2b4eac06-b426-4f78-b874-2e1734c4104b",
"moved": false,
"static": false,
"w": 6,
"x": 6,
"y": 0
},
{
"h": 6,
"i": "5bea2bc0-13a2-4937-bccb-60ffe8a43ad5",
"moved": false,
"static": false,
"w": 6,
"x": 0,
"y": 6
},
{
"h": 6,
"i": "6fac67b0-50ec-4b43-ac4b-320a303d0369",
"moved": false,
"static": false,
"w": 6,
"x": 6,
"y": 6
}
],
"panelMap": {},
"tags": [],
"title": "AWS ECS Overview",
"uploadedGrafana": false,
"variables": {
"51f4fa2b-89c7-47c2-9795-f32cffaab985": {
"allSelected": false,
"customValue": "",
"description": "AWS Account ID",
"id": "51f4fa2b-89c7-47c2-9795-f32cffaab985",
"key": "51f4fa2b-89c7-47c2-9795-f32cffaab985",
"modificationUUID": "7b814d17-8fff-4ed6-a4ea-90e3b1a97584",
"multiSelect": false,
"name": "Account",
"order": 0,
"queryValue": "SELECT DISTINCT JSONExtractString(labels, 'cloud_account_id') AS cloud_account_id\nFROM signoz_metrics.distributed_time_series_v4_1day\nWHERE metric_name = 'aws_ECS_MemoryUtilization_max' GROUP BY cloud_account_id",
"showALLOption": false,
"sort": "DISABLED",
"textboxValue": "",
"type": "QUERY"
},
"9faf0f4b-b245-4b3c-83a3-60cfa76dfeb0": {
"allSelected": false,
"customValue": "",
"description": "Account Region",
"id": "9faf0f4b-b245-4b3c-83a3-60cfa76dfeb0",
"key": "9faf0f4b-b245-4b3c-83a3-60cfa76dfeb0",
"modificationUUID": "3b5f499b-22a3-4c8a-847c-8d3811c9e6b2",
"multiSelect": false,
"name": "Region",
"order": 1,
"queryValue": "SELECT DISTINCT JSONExtractString(labels, 'cloud_region') AS region\nFROM signoz_metrics.distributed_time_series_v4_1day\nWHERE metric_name = 'aws_ECS_MemoryUtilization_max' AND JSONExtractString(labels, 'cloud_account_id') IN {{.Account}} GROUP BY region",
"showALLOption": false,
"sort": "ASC",
"textboxValue": "",
"type": "QUERY"
},
"bfbdbcbe-a168-4d81-b108-36339e249116": {
"allSelected": true,
"customValue": "",
"description": "ECS Cluster Name",
"id": "bfbdbcbe-a168-4d81-b108-36339e249116",
"key": "bfbdbcbe-a168-4d81-b108-36339e249116",
"modificationUUID": "9fb0d63c-ac6c-497d-82b3-17d95944e245",
"multiSelect": true,
"name": "Cluster",
"order": 2,
"queryValue": "SELECT DISTINCT JSONExtractString(labels, 'ClusterName') AS cluster\nFROM signoz_metrics.distributed_time_series_v4_1day\nWHERE metric_name = 'aws_ECS_MemoryUtilization_max' AND JSONExtractString(labels, 'cloud_account_id') IN {{.Account}} AND JSONExtractString(labels, 'cloud_region') IN {{.Region}}\nGROUP BY cluster",
"showALLOption": true,
"sort": "ASC",
"textboxValue": "",
"type": "QUERY"
}
},
"version": "v4",
"widgets": [
{
"bucketCount": 30,
"bucketWidth": 0,
"columnUnits": {},
"description": "",
"fillSpans": false,
"id": "f78becf8-0328-48b4-84b6-ff4dac325940",
"isLogScale": false,
"isStacked": false,
"mergeAllActiveQueries": false,
"nullZeroValues": "zero",
"opacity": "1",
"panelTypes": "graph",
"query": {
"builder": {
"queryData": [
{
"aggregateAttribute": {
"dataType": "float64",
"id": "aws_ECS_MemoryUtilization_max--float64--Gauge--true",
"isColumn": true,
"isJSON": false,
"key": "aws_ECS_MemoryUtilization_max",
"type": "Gauge"
},
"aggregateOperator": "max",
"dataSource": "metrics",
"disabled": false,
"expression": "A",
"filters": {
"items": [
{
"id": "26ac617d",
"key": {
"dataType": "string",
"id": "cloud_region--string--tag--false",
"isColumn": false,
"isJSON": false,
"key": "cloud_region",
"type": "tag"
},
"op": "=",
"value": "$Region"
},
{
"id": "57172ed9",
"key": {
"dataType": "string",
"id": "cloud_account_id--string--tag--false",
"isColumn": false,
"isJSON": false,
"key": "cloud_account_id",
"type": "tag"
},
"op": "=",
"value": "$Account"
},
{
"id": "49b9f85e",
"key": {
"dataType": "string",
"id": "ClusterName--string--tag--false",
"isColumn": false,
"isJSON": false,
"key": "ClusterName",
"type": "tag"
},
"op": "in",
"value": [
"$Cluster"
]
}
],
"op": "AND"
},
"functions": [],
"groupBy": [
{
"dataType": "string",
"id": "ServiceName--string--tag--false",
"isColumn": false,
"isJSON": false,
"key": "ServiceName",
"type": "tag"
},
{
"dataType": "string",
"id": "ClusterName--string--tag--false",
"isColumn": false,
"isJSON": false,
"key": "ClusterName",
"type": "tag"
}
],
"having": [],
"legend": "{{ServiceName}} ({{ClusterName}})",
"limit": null,
"orderBy": [],
"queryName": "A",
"reduceTo": "avg",
"spaceAggregation": "max",
"stepInterval": 60,
"timeAggregation": "max"
}
],
"queryFormulas": []
},
"clickhouse_sql": [
{
"disabled": false,
"legend": "",
"name": "A",
"query": ""
}
],
"id": "56068fdd-d523-4117-92fa-87c6518ad07c",
"promql": [
{
"disabled": false,
"legend": "",
"name": "A",
"query": ""
}
],
"queryType": "builder"
},
"selectedLogFields": [
{
"dataType": "string",
"name": "body",
"type": ""
},
{
"dataType": "string",
"name": "timestamp",
"type": ""
}
],
"selectedTracesFields": [
{
"dataType": "string",
"id": "serviceName--string--tag--true",
"isColumn": true,
"isJSON": false,
"key": "serviceName",
"type": "tag"
},
{
"dataType": "string",
"id": "name--string--tag--true",
"isColumn": true,
"isJSON": false,
"key": "name",
"type": "tag"
},
{
"dataType": "float64",
"id": "durationNano--float64--tag--true",
"isColumn": true,
"isJSON": false,
"key": "durationNano",
"type": "tag"
},
{
"dataType": "string",
"id": "httpMethod--string--tag--true",
"isColumn": true,
"isJSON": false,
"key": "httpMethod",
"type": "tag"
},
{
"dataType": "string",
"id": "responseStatusCode--string--tag--true",
"isColumn": true,
"isJSON": false,
"key": "responseStatusCode",
"type": "tag"
}
],
"softMax": 0,
"softMin": 0,
"stackedBarChart": false,
"thresholds": [],
"timePreferance": "GLOBAL_TIME",
"title": "Maximum Memory Utilization",
"yAxisUnit": "none"
},
{
"bucketCount": 30,
"bucketWidth": 0,
"columnUnits": {},
"description": "",
"fillSpans": false,
"id": "2b4eac06-b426-4f78-b874-2e1734c4104b",
"isLogScale": false,
"isStacked": false,
"mergeAllActiveQueries": false,
"nullZeroValues": "zero",
"opacity": "1",
"panelTypes": "graph",
"query": {
"builder": {
"queryData": [
{
"aggregateAttribute": {
"dataType": "float64",
"id": "aws_ECS_MemoryUtilization_min--float64--Gauge--true",
"isColumn": true,
"isJSON": false,
"key": "aws_ECS_MemoryUtilization_min",
"type": "Gauge"
},
"aggregateOperator": "min",
"dataSource": "metrics",
"disabled": false,
"expression": "A",
"filters": {
"items": [
{
"id": "cd4b8848",
"key": {
"dataType": "string",
"id": "cloud_region--string--tag--false",
"isColumn": false,
"isJSON": false,
"key": "cloud_region",
"type": "tag"
},
"op": "=",
"value": "$Region"
},
{
"id": "aa5115c6",
"key": {
"dataType": "string",
"id": "cloud_account_id--string--tag--false",
"isColumn": false,
"isJSON": false,
"key": "cloud_account_id",
"type": "tag"
},
"op": "=",
"value": "$Account"
},
{
"id": "f60677b6",
"key": {
"dataType": "string",
"id": "ClusterName--string--tag--false",
"isColumn": false,
"isJSON": false,
"key": "ClusterName",
"type": "tag"
},
"op": "in",
"value": [
"$Cluster"
]
}
],
"op": "AND"
},
"functions": [],
"groupBy": [
{
"dataType": "string",
"id": "ServiceName--string--tag--false",
"isColumn": false,
"isJSON": false,
"key": "ServiceName",
"type": "tag"
},
{
"dataType": "string",
"id": "ClusterName--string--tag--false",
"isColumn": false,
"isJSON": false,
"key": "ClusterName",
"type": "tag"
}
],
"having": [],
"legend": "{{ServiceName}} ({{ClusterName}})",
"limit": null,
"orderBy": [],
"queryName": "A",
"reduceTo": "avg",
"spaceAggregation": "min",
"stepInterval": 60,
"timeAggregation": "min"
}
],
"queryFormulas": []
},
"clickhouse_sql": [
{
"disabled": false,
"legend": "",
"name": "A",
"query": ""
}
],
"id": "fb19342e-cbde-40d8-b12f-ad108698356b",
"promql": [
{
"disabled": false,
"legend": "",
"name": "A",
"query": ""
}
],
"queryType": "builder"
},
"selectedLogFields": [
{
"dataType": "string",
"name": "body",
"type": ""
},
{
"dataType": "string",
"name": "timestamp",
"type": ""
}
],
"selectedTracesFields": [
{
"dataType": "string",
"id": "serviceName--string--tag--true",
"isColumn": true,
"isJSON": false,
"key": "serviceName",
"type": "tag"
},
{
"dataType": "string",
"id": "name--string--tag--true",
"isColumn": true,
"isJSON": false,
"key": "name",
"type": "tag"
},
{
"dataType": "float64",
"id": "durationNano--float64--tag--true",
"isColumn": true,
"isJSON": false,
"key": "durationNano",
"type": "tag"
},
{
"dataType": "string",
"id": "httpMethod--string--tag--true",
"isColumn": true,
"isJSON": false,
"key": "httpMethod",
"type": "tag"
},
{
"dataType": "string",
"id": "responseStatusCode--string--tag--true",
"isColumn": true,
"isJSON": false,
"key": "responseStatusCode",
"type": "tag"
}
],
"softMax": 0,
"softMin": 0,
"stackedBarChart": false,
"thresholds": [],
"timePreferance": "GLOBAL_TIME",
"title": "Minimum Memory Utilization",
"yAxisUnit": "none"
},
{
"bucketCount": 30,
"bucketWidth": 0,
"columnUnits": {},
"description": "",
"fillSpans": false,
"id": "5bea2bc0-13a2-4937-bccb-60ffe8a43ad5",
"isLogScale": false,
"isStacked": false,
"mergeAllActiveQueries": false,
"nullZeroValues": "zero",
"opacity": "1",
"panelTypes": "graph",
"query": {
"builder": {
"queryData": [
{
"aggregateAttribute": {
"dataType": "float64",
"id": "aws_ECS_CPUUtilization_max--float64--Gauge--true",
"isColumn": true,
"isJSON": false,
"key": "aws_ECS_CPUUtilization_max",
"type": "Gauge"
},
"aggregateOperator": "max",
"dataSource": "metrics",
"disabled": false,
"expression": "A",
"filters": {
"items": [
{
"id": "2c13c8ee",
"key": {
"dataType": "string",
"id": "cloud_region--string--tag--false",
"isColumn": false,
"isJSON": false,
"key": "cloud_region",
"type": "tag"
},
"op": "=",
"value": "$Region"
},
{
"id": "f489f6a8",
"key": {
"dataType": "string",
"id": "cloud_account_id--string--tag--false",
"isColumn": false,
"isJSON": false,
"key": "cloud_account_id",
"type": "tag"
},
"op": "=",
"value": "$Account"
},
{
"id": "94012320",
"key": {
"dataType": "string",
"id": "ClusterName--string--tag--false",
"isColumn": false,
"isJSON": false,
"key": "ClusterName",
"type": "tag"
},
"op": "in",
"value": [
"$Cluster"
]
}
],
"op": "AND"
},
"functions": [],
"groupBy": [
{
"dataType": "string",
"id": "ServiceName--string--tag--false",
"isColumn": false,
"isJSON": false,
"key": "ServiceName",
"type": "tag"
},
{
"dataType": "string",
"id": "ClusterName--string--tag--false",
"isColumn": false,
"isJSON": false,
"key": "ClusterName",
"type": "tag"
}
],
"having": [],
"legend": "{{ServiceName}} ({{ClusterName}})",
"limit": null,
"orderBy": [],
"queryName": "A",
"reduceTo": "avg",
"spaceAggregation": "max",
"stepInterval": 60,
"timeAggregation": "max"
}
],
"queryFormulas": []
},
"clickhouse_sql": [
{
"disabled": false,
"legend": "",
"name": "A",
"query": ""
}
],
"id": "273e0a76-c780-4b9a-9b03-2649d4227173",
"promql": [
{
"disabled": false,
"legend": "",
"name": "A",
"query": ""
}
],
"queryType": "builder"
},
"selectedLogFields": [
{
"dataType": "string",
"name": "body",
"type": ""
},
{
"dataType": "string",
"name": "timestamp",
"type": ""
}
],
"selectedTracesFields": [
{
"dataType": "string",
"id": "serviceName--string--tag--true",
"isColumn": true,
"isJSON": false,
"key": "serviceName",
"type": "tag"
},
{
"dataType": "string",
"id": "name--string--tag--true",
"isColumn": true,
"isJSON": false,
"key": "name",
"type": "tag"
},
{
"dataType": "float64",
"id": "durationNano--float64--tag--true",
"isColumn": true,
"isJSON": false,
"key": "durationNano",
"type": "tag"
},
{
"dataType": "string",
"id": "httpMethod--string--tag--true",
"isColumn": true,
"isJSON": false,
"key": "httpMethod",
"type": "tag"
},
{
"dataType": "string",
"id": "responseStatusCode--string--tag--true",
"isColumn": true,
"isJSON": false,
"key": "responseStatusCode",
"type": "tag"
}
],
"softMax": 0,
"softMin": 0,
"stackedBarChart": false,
"thresholds": [],
"timePreferance": "GLOBAL_TIME",
"title": "Maximum CPU Utilization",
"yAxisUnit": "none"
},
{
"bucketCount": 30,
"bucketWidth": 0,
"columnUnits": {},
"description": "",
"fillSpans": false,
"id": "6fac67b0-50ec-4b43-ac4b-320a303d0369",
"isLogScale": false,
"isStacked": false,
"mergeAllActiveQueries": false,
"nullZeroValues": "zero",
"opacity": "1",
"panelTypes": "graph",
"query": {
"builder": {
"queryData": [
{
"aggregateAttribute": {
"dataType": "float64",
"id": "aws_ECS_CPUUtilization_min--float64--Gauge--true",
"isColumn": true,
"isJSON": false,
"key": "aws_ECS_CPUUtilization_min",
"type": "Gauge"
},
"aggregateOperator": "min",
"dataSource": "metrics",
"disabled": false,
"expression": "A",
"filters": {
"items": [
{
"id": "758ba906",
"key": {
"dataType": "string",
"id": "cloud_region--string--tag--false",
"isColumn": false,
"isJSON": false,
"key": "cloud_region",
"type": "tag"
},
"op": "=",
"value": "$Region"
},
{
"id": "4ffe6bf7",
"key": {
"dataType": "string",
"id": "cloud_account_id--string--tag--false",
"isColumn": false,
"isJSON": false,
"key": "cloud_account_id",
"type": "tag"
},
"op": "=",
"value": "$Account"
},
{
"id": "53d98059",
"key": {
"dataType": "string",
"id": "ClusterName--string--tag--false",
"isColumn": false,
"isJSON": false,
"key": "ClusterName",
"type": "tag"
},
"op": "in",
"value": [
"$Cluster"
]
}
],
"op": "AND"
},
"functions": [],
"groupBy": [
{
"dataType": "string",
"id": "ServiceName--string--tag--false",
"isColumn": false,
"isJSON": false,
"key": "ServiceName",
"type": "tag"
},
{
"dataType": "string",
"id": "ClusterName--string--tag--false",
"isColumn": false,
"isJSON": false,
"key": "ClusterName",
"type": "tag"
}
],
"having": [],
"legend": "{{ServiceName}} ({{ClusterName}})",
"limit": null,
"orderBy": [],
"queryName": "A",
"reduceTo": "avg",
"spaceAggregation": "min",
"stepInterval": 60,
"timeAggregation": "min"
}
],
"queryFormulas": []
},
"clickhouse_sql": [
{
"disabled": false,
"legend": "",
"name": "A",
"query": ""
}
],
"id": "c89482b3-5a98-4e2c-be0d-ef036d7dac05",
"promql": [
{
"disabled": false,
"legend": "",
"name": "A",
"query": ""
}
],
"queryType": "builder"
},
"selectedLogFields": [
{
"dataType": "string",
"name": "body",
"type": ""
},
{
"dataType": "string",
"name": "timestamp",
"type": ""
}
],
"selectedTracesFields": [
{
"dataType": "string",
"id": "serviceName--string--tag--true",
"isColumn": true,
"isJSON": false,
"key": "serviceName",
"type": "tag"
},
{
"dataType": "string",
"id": "name--string--tag--true",
"isColumn": true,
"isJSON": false,
"key": "name",
"type": "tag"
},
{
"dataType": "float64",
"id": "durationNano--float64--tag--true",
"isColumn": true,
"isJSON": false,
"key": "durationNano",
"type": "tag"
},
{
"dataType": "string",
"id": "httpMethod--string--tag--true",
"isColumn": true,
"isJSON": false,
"key": "httpMethod",
"type": "tag"
},
{
"dataType": "string",
"id": "responseStatusCode--string--tag--true",
"isColumn": true,
"isJSON": false,
"key": "responseStatusCode",
"type": "tag"
}
],
"softMax": 0,
"softMin": 0,
"stackedBarChart": false,
"thresholds": [],
"timePreferance": "GLOBAL_TIME",
"title": "Minimum CPU Utilization",
"yAxisUnit": "none"
}
]
}

View File

@@ -0,0 +1,851 @@
{
"description": "View key AWS ECS metrics with an out of the box dashboard.\n",
"image":"data:image/svg+xml,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22UTF-8%22%3F%3E%3Csvg%20width%3D%2280px%22%20height%3D%2280px%22%20viewBox%3D%220%200%2080%2080%22%20version%3D%221.1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%3E%3C!--%20Generator%3A%20Sketch%2064%20(93537)%20-%20https%3A%2F%2Fsketch.com%20--%3E%3Ctitle%3EIcon-Architecture%2F64%2FArch_Amazon-Elastic-Container-Service_64%3C%2Ftitle%3E%3Cdesc%3ECreated%20with%20Sketch.%3C%2Fdesc%3E%3Cdefs%3E%3ClinearGradient%20x1%3D%220%25%22%20y1%3D%22100%25%22%20x2%3D%22100%25%22%20y2%3D%220%25%22%20id%3D%22linearGradient-1%22%3E%3Cstop%20stop-color%3D%22%23C8511B%22%20offset%3D%220%25%22%3E%3C%2Fstop%3E%3Cstop%20stop-color%3D%22%23FF9900%22%20offset%3D%22100%25%22%3E%3C%2Fstop%3E%3C%2FlinearGradient%3E%3C%2Fdefs%3E%3Cg%20id%3D%22Icon-Architecture%2F64%2FArch_Amazon-Elastic-Container-Service_64%22%20stroke%3D%22none%22%20stroke-width%3D%221%22%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%3Cg%20id%3D%22Icon-Architecture-BG%2F64%2FContainers%22%20fill%3D%22url(%23linearGradient-1)%22%3E%3Crect%20id%3D%22Rectangle%22%20x%3D%220%22%20y%3D%220%22%20width%3D%2280%22%20height%3D%2280%22%3E%3C%2Frect%3E%3C%2Fg%3E%3Cpath%20d%3D%22M64%2C48.2340095%20L56%2C43.4330117%20L56%2C32.0000169%20C56%2C31.6440171%2055.812%2C31.3150172%2055.504%2C31.1360173%20L44%2C24.4260204%20L44%2C14.7520248%20L64%2C26.5710194%20L64%2C48.2340095%20Z%20M65.509%2C25.13902%20L43.509%2C12.139026%20C43.199%2C11.9560261%2042.818%2C11.9540261%2042.504%2C12.131026%20C42.193%2C12.3090259%2042%2C12.6410257%2042%2C13.0000256%20L42%2C25.0000201%20C42%2C25.3550199%2042.189%2C25.6840198%2042.496%2C25.8640197%20L54%2C32.5740166%20L54%2C44.0000114%20C54%2C44.3510113%2054.185%2C44.6770111%2054.486%2C44.857011%20L64.486%2C50.8570083%20C64.644%2C50.9520082%2064.822%2C51%2065%2C51%20C65.17%2C51%2065.34%2C50.9570082%2065.493%2C50.8700083%20C65.807%2C50.6930084%2066%2C50.3600085%2066%2C50%20L66%2C26.0000196%20C66%2C25.6460198%2065.814%2C25.31902%2065.509%2C25.13902%20L65.509%2C25.13902%20Z%20M40.445%2C66.863001%20L17%2C54.3990067%20L17%2C26.5710194%20L37%2C14.7520248%20L37%2C24.4510204%20L26.463%2C31.1560173%20C26.175%2C31.3400172%2026%2C31.6580171%2026%2C32.0000169%20L26%2C49.0000091%20C26%2C49.373009%2026.208%2C49.7150088%2026.538%2C49.8870087%20L39.991%2C56.8870055%20C40.28%2C57.0370055%2040.624%2C57.0380055%2040.912%2C56.8880055%20L53.964%2C50.1440086%20L61.996%2C54.9640064%20L40.445%2C66.863001%20Z%20M64.515%2C54.1420068%20L54.515%2C48.1420095%20C54.217%2C47.9640096%2053.849%2C47.9520096%2053.541%2C48.1120095%20L40.455%2C54.8730065%20L28%2C48.3930094%20L28%2C32.5490167%20L38.537%2C25.8440197%20C38.825%2C25.6600198%2039%2C25.3420199%2039%2C25.0000201%20L39%2C13.0000256%20C39%2C12.6410257%2038.808%2C12.3090259%2038.496%2C12.131026%20C38.184%2C11.9540261%2037.802%2C11.9560261%2037.491%2C12.139026%20L15.491%2C25.13902%20C15.187%2C25.31902%2015%2C25.6460198%2015%2C26.0000196%20L15%2C55%20C15%2C55.3690062%2015.204%2C55.7090061%2015.53%2C55.883006%20L39.984%2C68.8830001%20C40.131%2C68.961%2040.292%2C69%2040.453%2C69%20C40.62%2C69%2040.786%2C68.958%2040.937%2C68.8750001%20L64.484%2C55.875006%20C64.797%2C55.7020061%2064.993%2C55.3750062%2065.0001416%2C55.0180064%20C65.006%2C54.6600066%2064.821%2C54.3260067%2064.515%2C54.1420068%20L64.515%2C54.1420068%20Z%22%20id%3D%22Amazon-Elastic-Container-Service_Icon_64_Squid%22%20fill%3D%22%23FFFFFF%22%3E%3C%2Fpath%3E%3C%2Fg%3E%3C%2Fsvg%3E",
"layout": [
{
"h": 6,
"i": "f78becf8-0328-48b4-84b6-ff4dac325940",
"moved": false,
"static": false,
"w": 6,
"x": 0,
"y": 0
},
{
"h": 6,
"i": "2b4eac06-b426-4f78-b874-2e1734c4104b",
"moved": false,
"static": false,
"w": 6,
"x": 6,
"y": 0
},
{
"h": 6,
"i": "5bea2bc0-13a2-4937-bccb-60ffe8a43ad5",
"moved": false,
"static": false,
"w": 6,
"x": 0,
"y": 6
},
{
"h": 6,
"i": "6fac67b0-50ec-4b43-ac4b-320a303d0369",
"moved": false,
"static": false,
"w": 6,
"x": 6,
"y": 6
}
],
"panelMap": {},
"tags": [],
"title": "AWS ECS Overview",
"uploadedGrafana": false,
"variables": {
"51f4fa2b-89c7-47c2-9795-f32cffaab985": {
"allSelected": false,
"customValue": "",
"description": "AWS Account ID",
"id": "51f4fa2b-89c7-47c2-9795-f32cffaab985",
"key": "51f4fa2b-89c7-47c2-9795-f32cffaab985",
"modificationUUID": "7b814d17-8fff-4ed6-a4ea-90e3b1a97584",
"multiSelect": false,
"name": "Account",
"order": 0,
"queryValue": "SELECT DISTINCT JSONExtractString(labels, 'cloud.account.id') AS `cloud.account.id`\nFROM signoz_metrics.distributed_time_series_v4_1day\nWHERE metric_name = 'aws_ECS_MemoryUtilization_max' GROUP BY `cloud.account.id`",
"showALLOption": false,
"sort": "DISABLED",
"textboxValue": "",
"type": "QUERY"
},
"9faf0f4b-b245-4b3c-83a3-60cfa76dfeb0": {
"allSelected": false,
"customValue": "",
"description": "Account Region",
"id": "9faf0f4b-b245-4b3c-83a3-60cfa76dfeb0",
"key": "9faf0f4b-b245-4b3c-83a3-60cfa76dfeb0",
"modificationUUID": "3b5f499b-22a3-4c8a-847c-8d3811c9e6b2",
"multiSelect": false,
"name": "Region",
"order": 1,
"queryValue": "SELECT DISTINCT JSONExtractString(labels, 'cloud.region') AS region\nFROM signoz_metrics.distributed_time_series_v4_1day\nWHERE metric_name = 'aws_ECS_MemoryUtilization_max' AND JSONExtractString(labels, 'cloud.account.id') IN {{.Account}} GROUP BY region",
"showALLOption": false,
"sort": "ASC",
"textboxValue": "",
"type": "QUERY"
},
"bfbdbcbe-a168-4d81-b108-36339e249116": {
"allSelected": true,
"customValue": "",
"description": "ECS Cluster Name",
"id": "bfbdbcbe-a168-4d81-b108-36339e249116",
"key": "bfbdbcbe-a168-4d81-b108-36339e249116",
"modificationUUID": "9fb0d63c-ac6c-497d-82b3-17d95944e245",
"multiSelect": true,
"name": "Cluster",
"order": 2,
"queryValue": "SELECT DISTINCT JSONExtractString(labels, 'ClusterName') AS cluster\nFROM signoz_metrics.distributed_time_series_v4_1day\nWHERE metric_name = 'aws_ECS_MemoryUtilization_max' AND JSONExtractString(labels, 'cloud.account.id') IN {{.Account}} AND JSONExtractString(labels, 'cloud.region') IN {{.Region}}\nGROUP BY cluster",
"showALLOption": true,
"sort": "ASC",
"textboxValue": "",
"type": "QUERY"
}
},
"version": "v4",
"widgets": [
{
"bucketCount": 30,
"bucketWidth": 0,
"columnUnits": {},
"description": "",
"fillSpans": false,
"id": "f78becf8-0328-48b4-84b6-ff4dac325940",
"isLogScale": false,
"isStacked": false,
"mergeAllActiveQueries": false,
"nullZeroValues": "zero",
"opacity": "1",
"panelTypes": "graph",
"query": {
"builder": {
"queryData": [
{
"aggregateAttribute": {
"dataType": "float64",
"id": "aws_ECS_MemoryUtilization_max--float64--Gauge--true",
"isColumn": true,
"isJSON": false,
"key": "aws_ECS_MemoryUtilization_max",
"type": "Gauge"
},
"aggregateOperator": "max",
"dataSource": "metrics",
"disabled": false,
"expression": "A",
"filters": {
"items": [
{
"id": "26ac617d",
"key": {
"dataType": "string",
"id": "cloud.region--string--tag--false",
"isColumn": false,
"isJSON": false,
"key": "cloud.region",
"type": "tag"
},
"op": "=",
"value": "$Region"
},
{
"id": "57172ed9",
"key": {
"dataType": "string",
"id": "cloud.account.id--string--tag--false",
"isColumn": false,
"isJSON": false,
"key": "cloud.account.id",
"type": "tag"
},
"op": "=",
"value": "$Account"
},
{
"id": "49b9f85e",
"key": {
"dataType": "string",
"id": "ClusterName--string--tag--false",
"isColumn": false,
"isJSON": false,
"key": "ClusterName",
"type": "tag"
},
"op": "in",
"value": [
"$Cluster"
]
}
],
"op": "AND"
},
"functions": [],
"groupBy": [
{
"dataType": "string",
"id": "ServiceName--string--tag--false",
"isColumn": false,
"isJSON": false,
"key": "ServiceName",
"type": "tag"
},
{
"dataType": "string",
"id": "ClusterName--string--tag--false",
"isColumn": false,
"isJSON": false,
"key": "ClusterName",
"type": "tag"
}
],
"having": [],
"legend": "{{ServiceName}} ({{ClusterName}})",
"limit": null,
"orderBy": [],
"queryName": "A",
"reduceTo": "avg",
"spaceAggregation": "max",
"stepInterval": 60,
"timeAggregation": "max"
}
],
"queryFormulas": []
},
"clickhouse_sql": [
{
"disabled": false,
"legend": "",
"name": "A",
"query": ""
}
],
"id": "56068fdd-d523-4117-92fa-87c6518ad07c",
"promql": [
{
"disabled": false,
"legend": "",
"name": "A",
"query": ""
}
],
"queryType": "builder"
},
"selectedLogFields": [
{
"dataType": "string",
"name": "body",
"type": ""
},
{
"dataType": "string",
"name": "timestamp",
"type": ""
}
],
"selectedTracesFields": [
{
"dataType": "string",
"id": "serviceName--string--tag--true",
"isColumn": true,
"isJSON": false,
"key": "serviceName",
"type": "tag"
},
{
"dataType": "string",
"id": "name--string--tag--true",
"isColumn": true,
"isJSON": false,
"key": "name",
"type": "tag"
},
{
"dataType": "float64",
"id": "durationNano--float64--tag--true",
"isColumn": true,
"isJSON": false,
"key": "durationNano",
"type": "tag"
},
{
"dataType": "string",
"id": "httpMethod--string--tag--true",
"isColumn": true,
"isJSON": false,
"key": "httpMethod",
"type": "tag"
},
{
"dataType": "string",
"id": "responseStatusCode--string--tag--true",
"isColumn": true,
"isJSON": false,
"key": "responseStatusCode",
"type": "tag"
}
],
"softMax": 0,
"softMin": 0,
"stackedBarChart": false,
"thresholds": [],
"timePreferance": "GLOBAL_TIME",
"title": "Maximum Memory Utilization",
"yAxisUnit": "none"
},
{
"bucketCount": 30,
"bucketWidth": 0,
"columnUnits": {},
"description": "",
"fillSpans": false,
"id": "2b4eac06-b426-4f78-b874-2e1734c4104b",
"isLogScale": false,
"isStacked": false,
"mergeAllActiveQueries": false,
"nullZeroValues": "zero",
"opacity": "1",
"panelTypes": "graph",
"query": {
"builder": {
"queryData": [
{
"aggregateAttribute": {
"dataType": "float64",
"id": "aws_ECS_MemoryUtilization_min--float64--Gauge--true",
"isColumn": true,
"isJSON": false,
"key": "aws_ECS_MemoryUtilization_min",
"type": "Gauge"
},
"aggregateOperator": "min",
"dataSource": "metrics",
"disabled": false,
"expression": "A",
"filters": {
"items": [
{
"id": "cd4b8848",
"key": {
"dataType": "string",
"id": "cloud.region--string--tag--false",
"isColumn": false,
"isJSON": false,
"key": "cloud.region",
"type": "tag"
},
"op": "=",
"value": "$Region"
},
{
"id": "aa5115c6",
"key": {
"dataType": "string",
"id": "cloud.account.id--string--tag--false",
"isColumn": false,
"isJSON": false,
"key": "cloud.account.id",
"type": "tag"
},
"op": "=",
"value": "$Account"
},
{
"id": "f60677b6",
"key": {
"dataType": "string",
"id": "ClusterName--string--tag--false",
"isColumn": false,
"isJSON": false,
"key": "ClusterName",
"type": "tag"
},
"op": "in",
"value": [
"$Cluster"
]
}
],
"op": "AND"
},
"functions": [],
"groupBy": [
{
"dataType": "string",
"id": "ServiceName--string--tag--false",
"isColumn": false,
"isJSON": false,
"key": "ServiceName",
"type": "tag"
},
{
"dataType": "string",
"id": "ClusterName--string--tag--false",
"isColumn": false,
"isJSON": false,
"key": "ClusterName",
"type": "tag"
}
],
"having": [],
"legend": "{{ServiceName}} ({{ClusterName}})",
"limit": null,
"orderBy": [],
"queryName": "A",
"reduceTo": "avg",
"spaceAggregation": "min",
"stepInterval": 60,
"timeAggregation": "min"
}
],
"queryFormulas": []
},
"clickhouse_sql": [
{
"disabled": false,
"legend": "",
"name": "A",
"query": ""
}
],
"id": "fb19342e-cbde-40d8-b12f-ad108698356b",
"promql": [
{
"disabled": false,
"legend": "",
"name": "A",
"query": ""
}
],
"queryType": "builder"
},
"selectedLogFields": [
{
"dataType": "string",
"name": "body",
"type": ""
},
{
"dataType": "string",
"name": "timestamp",
"type": ""
}
],
"selectedTracesFields": [
{
"dataType": "string",
"id": "serviceName--string--tag--true",
"isColumn": true,
"isJSON": false,
"key": "serviceName",
"type": "tag"
},
{
"dataType": "string",
"id": "name--string--tag--true",
"isColumn": true,
"isJSON": false,
"key": "name",
"type": "tag"
},
{
"dataType": "float64",
"id": "durationNano--float64--tag--true",
"isColumn": true,
"isJSON": false,
"key": "durationNano",
"type": "tag"
},
{
"dataType": "string",
"id": "httpMethod--string--tag--true",
"isColumn": true,
"isJSON": false,
"key": "httpMethod",
"type": "tag"
},
{
"dataType": "string",
"id": "responseStatusCode--string--tag--true",
"isColumn": true,
"isJSON": false,
"key": "responseStatusCode",
"type": "tag"
}
],
"softMax": 0,
"softMin": 0,
"stackedBarChart": false,
"thresholds": [],
"timePreferance": "GLOBAL_TIME",
"title": "Minimum Memory Utilization",
"yAxisUnit": "none"
},
{
"bucketCount": 30,
"bucketWidth": 0,
"columnUnits": {},
"description": "",
"fillSpans": false,
"id": "5bea2bc0-13a2-4937-bccb-60ffe8a43ad5",
"isLogScale": false,
"isStacked": false,
"mergeAllActiveQueries": false,
"nullZeroValues": "zero",
"opacity": "1",
"panelTypes": "graph",
"query": {
"builder": {
"queryData": [
{
"aggregateAttribute": {
"dataType": "float64",
"id": "aws_ECS_CPUUtilization_max--float64--Gauge--true",
"isColumn": true,
"isJSON": false,
"key": "aws_ECS_CPUUtilization_max",
"type": "Gauge"
},
"aggregateOperator": "max",
"dataSource": "metrics",
"disabled": false,
"expression": "A",
"filters": {
"items": [
{
"id": "2c13c8ee",
"key": {
"dataType": "string",
"id": "cloud.region--string--tag--false",
"isColumn": false,
"isJSON": false,
"key": "cloud.region",
"type": "tag"
},
"op": "=",
"value": "$Region"
},
{
"id": "f489f6a8",
"key": {
"dataType": "string",
"id": "cloud.account.id--string--tag--false",
"isColumn": false,
"isJSON": false,
"key": "cloud.account.id",
"type": "tag"
},
"op": "=",
"value": "$Account"
},
{
"id": "94012320",
"key": {
"dataType": "string",
"id": "ClusterName--string--tag--false",
"isColumn": false,
"isJSON": false,
"key": "ClusterName",
"type": "tag"
},
"op": "in",
"value": [
"$Cluster"
]
}
],
"op": "AND"
},
"functions": [],
"groupBy": [
{
"dataType": "string",
"id": "ServiceName--string--tag--false",
"isColumn": false,
"isJSON": false,
"key": "ServiceName",
"type": "tag"
},
{
"dataType": "string",
"id": "ClusterName--string--tag--false",
"isColumn": false,
"isJSON": false,
"key": "ClusterName",
"type": "tag"
}
],
"having": [],
"legend": "{{ServiceName}} ({{ClusterName}})",
"limit": null,
"orderBy": [],
"queryName": "A",
"reduceTo": "avg",
"spaceAggregation": "max",
"stepInterval": 60,
"timeAggregation": "max"
}
],
"queryFormulas": []
},
"clickhouse_sql": [
{
"disabled": false,
"legend": "",
"name": "A",
"query": ""
}
],
"id": "273e0a76-c780-4b9a-9b03-2649d4227173",
"promql": [
{
"disabled": false,
"legend": "",
"name": "A",
"query": ""
}
],
"queryType": "builder"
},
"selectedLogFields": [
{
"dataType": "string",
"name": "body",
"type": ""
},
{
"dataType": "string",
"name": "timestamp",
"type": ""
}
],
"selectedTracesFields": [
{
"dataType": "string",
"id": "serviceName--string--tag--true",
"isColumn": true,
"isJSON": false,
"key": "serviceName",
"type": "tag"
},
{
"dataType": "string",
"id": "name--string--tag--true",
"isColumn": true,
"isJSON": false,
"key": "name",
"type": "tag"
},
{
"dataType": "float64",
"id": "durationNano--float64--tag--true",
"isColumn": true,
"isJSON": false,
"key": "durationNano",
"type": "tag"
},
{
"dataType": "string",
"id": "httpMethod--string--tag--true",
"isColumn": true,
"isJSON": false,
"key": "httpMethod",
"type": "tag"
},
{
"dataType": "string",
"id": "responseStatusCode--string--tag--true",
"isColumn": true,
"isJSON": false,
"key": "responseStatusCode",
"type": "tag"
}
],
"softMax": 0,
"softMin": 0,
"stackedBarChart": false,
"thresholds": [],
"timePreferance": "GLOBAL_TIME",
"title": "Maximum CPU Utilization",
"yAxisUnit": "none"
},
{
"bucketCount": 30,
"bucketWidth": 0,
"columnUnits": {},
"description": "",
"fillSpans": false,
"id": "6fac67b0-50ec-4b43-ac4b-320a303d0369",
"isLogScale": false,
"isStacked": false,
"mergeAllActiveQueries": false,
"nullZeroValues": "zero",
"opacity": "1",
"panelTypes": "graph",
"query": {
"builder": {
"queryData": [
{
"aggregateAttribute": {
"dataType": "float64",
"id": "aws_ECS_CPUUtilization_min--float64--Gauge--true",
"isColumn": true,
"isJSON": false,
"key": "aws_ECS_CPUUtilization_min",
"type": "Gauge"
},
"aggregateOperator": "min",
"dataSource": "metrics",
"disabled": false,
"expression": "A",
"filters": {
"items": [
{
"id": "758ba906",
"key": {
"dataType": "string",
"id": "cloud.region--string--tag--false",
"isColumn": false,
"isJSON": false,
"key": "cloud.region",
"type": "tag"
},
"op": "=",
"value": "$Region"
},
{
"id": "4ffe6bf7",
"key": {
"dataType": "string",
"id": "cloud.account.id--string--tag--false",
"isColumn": false,
"isJSON": false,
"key": "cloud.account.id",
"type": "tag"
},
"op": "=",
"value": "$Account"
},
{
"id": "53d98059",
"key": {
"dataType": "string",
"id": "ClusterName--string--tag--false",
"isColumn": false,
"isJSON": false,
"key": "ClusterName",
"type": "tag"
},
"op": "in",
"value": [
"$Cluster"
]
}
],
"op": "AND"
},
"functions": [],
"groupBy": [
{
"dataType": "string",
"id": "ServiceName--string--tag--false",
"isColumn": false,
"isJSON": false,
"key": "ServiceName",
"type": "tag"
},
{
"dataType": "string",
"id": "ClusterName--string--tag--false",
"isColumn": false,
"isJSON": false,
"key": "ClusterName",
"type": "tag"
}
],
"having": [],
"legend": "{{ServiceName}} ({{ClusterName}})",
"limit": null,
"orderBy": [],
"queryName": "A",
"reduceTo": "avg",
"spaceAggregation": "min",
"stepInterval": 60,
"timeAggregation": "min"
}
],
"queryFormulas": []
},
"clickhouse_sql": [
{
"disabled": false,
"legend": "",
"name": "A",
"query": ""
}
],
"id": "c89482b3-5a98-4e2c-be0d-ef036d7dac05",
"promql": [
{
"disabled": false,
"legend": "",
"name": "A",
"query": ""
}
],
"queryType": "builder"
},
"selectedLogFields": [
{
"dataType": "string",
"name": "body",
"type": ""
},
{
"dataType": "string",
"name": "timestamp",
"type": ""
}
],
"selectedTracesFields": [
{
"dataType": "string",
"id": "serviceName--string--tag--true",
"isColumn": true,
"isJSON": false,
"key": "serviceName",
"type": "tag"
},
{
"dataType": "string",
"id": "name--string--tag--true",
"isColumn": true,
"isJSON": false,
"key": "name",
"type": "tag"
},
{
"dataType": "float64",
"id": "durationNano--float64--tag--true",
"isColumn": true,
"isJSON": false,
"key": "durationNano",
"type": "tag"
},
{
"dataType": "string",
"id": "httpMethod--string--tag--true",
"isColumn": true,
"isJSON": false,
"key": "httpMethod",
"type": "tag"
},
{
"dataType": "string",
"id": "responseStatusCode--string--tag--true",
"isColumn": true,
"isJSON": false,
"key": "responseStatusCode",
"type": "tag"
}
],
"softMax": 0,
"softMin": 0,
"stackedBarChart": false,
"thresholds": [],
"timePreferance": "GLOBAL_TIME",
"title": "Minimum CPU Utilization",
"yAxisUnit": "none"
}
]
}

View File

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

After

Width:  |  Height:  |  Size: 2.7 KiB

View File

@@ -0,0 +1,871 @@
{
"id": "ecs",
"title": "ECS",
"icon": "file://icon.svg",
"overview": "file://overview.md",
"supportedSignals": {
"metrics": true,
"logs": true
},
"dataCollected": {
"metrics": [
{
"name": "aws_ECS_CPUUtilization_count",
"unit": "Percent",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ECS_CPUUtilization_max",
"unit": "Percent",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ECS_CPUUtilization_min",
"unit": "Percent",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ECS_CPUUtilization_sum",
"unit": "Percent",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ECS_ContainerInsights_ContainerCpuReserved_count",
"unit": "None",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ECS_ContainerInsights_ContainerCpuReserved_max",
"unit": "None",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ECS_ContainerInsights_ContainerCpuReserved_min",
"unit": "None",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ECS_ContainerInsights_ContainerCpuReserved_sum",
"unit": "None",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ECS_ContainerInsights_ContainerCpuUtilization_count",
"unit": "Percent",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ECS_ContainerInsights_ContainerCpuUtilization_max",
"unit": "Percent",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ECS_ContainerInsights_ContainerCpuUtilization_min",
"unit": "Percent",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ECS_ContainerInsights_ContainerCpuUtilization_sum",
"unit": "Percent",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ECS_ContainerInsights_ContainerCpuUtilized_count",
"unit": "None",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ECS_ContainerInsights_ContainerCpuUtilized_max",
"unit": "None",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ECS_ContainerInsights_ContainerCpuUtilized_min",
"unit": "None",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ECS_ContainerInsights_ContainerCpuUtilized_sum",
"unit": "None",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ECS_ContainerInsights_ContainerInstanceCount_count",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ECS_ContainerInsights_ContainerInstanceCount_max",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ECS_ContainerInsights_ContainerInstanceCount_min",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ECS_ContainerInsights_ContainerInstanceCount_sum",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ECS_ContainerInsights_ContainerMemoryReserved_count",
"unit": "Megabytes",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ECS_ContainerInsights_ContainerMemoryReserved_max",
"unit": "Megabytes",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ECS_ContainerInsights_ContainerMemoryReserved_min",
"unit": "Megabytes",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ECS_ContainerInsights_ContainerMemoryReserved_sum",
"unit": "Megabytes",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ECS_ContainerInsights_ContainerMemoryUtilization_count",
"unit": "Percent",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ECS_ContainerInsights_ContainerMemoryUtilization_max",
"unit": "Percent",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ECS_ContainerInsights_ContainerMemoryUtilization_min",
"unit": "Percent",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ECS_ContainerInsights_ContainerMemoryUtilization_sum",
"unit": "Percent",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ECS_ContainerInsights_ContainerMemoryUtilized_count",
"unit": "Megabytes",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ECS_ContainerInsights_ContainerMemoryUtilized_max",
"unit": "Megabytes",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ECS_ContainerInsights_ContainerMemoryUtilized_min",
"unit": "Megabytes",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ECS_ContainerInsights_ContainerMemoryUtilized_sum",
"unit": "Megabytes",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ECS_ContainerInsights_ContainerNetworkRxBytes_count",
"unit": "Bytes/Second",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ECS_ContainerInsights_ContainerNetworkRxBytes_max",
"unit": "Bytes/Second",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ECS_ContainerInsights_ContainerNetworkRxBytes_min",
"unit": "Bytes/Second",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ECS_ContainerInsights_ContainerNetworkRxBytes_sum",
"unit": "Bytes/Second",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ECS_ContainerInsights_ContainerNetworkTxBytes_count",
"unit": "Bytes/Second",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ECS_ContainerInsights_ContainerNetworkTxBytes_max",
"unit": "Bytes/Second",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ECS_ContainerInsights_ContainerNetworkTxBytes_min",
"unit": "Bytes/Second",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ECS_ContainerInsights_ContainerNetworkTxBytes_sum",
"unit": "Bytes/Second",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ECS_ContainerInsights_ContainerStorageReadBytes_count",
"unit": "Bytes/Second",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ECS_ContainerInsights_ContainerStorageReadBytes_max",
"unit": "Bytes/Second",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ECS_ContainerInsights_ContainerStorageReadBytes_min",
"unit": "Bytes/Second",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ECS_ContainerInsights_ContainerStorageReadBytes_sum",
"unit": "Bytes/Second",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ECS_ContainerInsights_ContainerStorageWriteBytes_count",
"unit": "Bytes/Second",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ECS_ContainerInsights_ContainerStorageWriteBytes_max",
"unit": "Bytes/Second",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ECS_ContainerInsights_ContainerStorageWriteBytes_min",
"unit": "Bytes/Second",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ECS_ContainerInsights_ContainerStorageWriteBytes_sum",
"unit": "Bytes/Second",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ECS_ContainerInsights_CpuReserved_count",
"unit": "None",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ECS_ContainerInsights_CpuReserved_max",
"unit": "None",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ECS_ContainerInsights_CpuReserved_min",
"unit": "None",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ECS_ContainerInsights_CpuReserved_sum",
"unit": "None",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ECS_ContainerInsights_CpuUtilized_count",
"unit": "None",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ECS_ContainerInsights_CpuUtilized_max",
"unit": "None",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ECS_ContainerInsights_CpuUtilized_min",
"unit": "None",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ECS_ContainerInsights_CpuUtilized_sum",
"unit": "None",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ECS_ContainerInsights_DeploymentCount_count",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ECS_ContainerInsights_DeploymentCount_max",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ECS_ContainerInsights_DeploymentCount_min",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ECS_ContainerInsights_DeploymentCount_sum",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ECS_ContainerInsights_DesiredTaskCount_count",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ECS_ContainerInsights_DesiredTaskCount_max",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ECS_ContainerInsights_DesiredTaskCount_min",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ECS_ContainerInsights_DesiredTaskCount_sum",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ECS_ContainerInsights_EphemeralStorageReserved_count",
"unit": "Gigabytes",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ECS_ContainerInsights_EphemeralStorageReserved_max",
"unit": "Gigabytes",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ECS_ContainerInsights_EphemeralStorageReserved_min",
"unit": "Gigabytes",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ECS_ContainerInsights_EphemeralStorageReserved_sum",
"unit": "Gigabytes",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ECS_ContainerInsights_EphemeralStorageUtilized_count",
"unit": "Gigabytes",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ECS_ContainerInsights_EphemeralStorageUtilized_max",
"unit": "Gigabytes",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ECS_ContainerInsights_EphemeralStorageUtilized_min",
"unit": "Gigabytes",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ECS_ContainerInsights_EphemeralStorageUtilized_sum",
"unit": "Gigabytes",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ECS_ContainerInsights_MemoryReserved_count",
"unit": "Megabytes",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ECS_ContainerInsights_MemoryReserved_max",
"unit": "Megabytes",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ECS_ContainerInsights_MemoryReserved_min",
"unit": "Megabytes",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ECS_ContainerInsights_MemoryReserved_sum",
"unit": "Megabytes",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ECS_ContainerInsights_MemoryUtilized_count",
"unit": "Megabytes",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ECS_ContainerInsights_MemoryUtilized_max",
"unit": "Megabytes",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ECS_ContainerInsights_MemoryUtilized_min",
"unit": "Megabytes",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ECS_ContainerInsights_MemoryUtilized_sum",
"unit": "Megabytes",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ECS_ContainerInsights_NetworkRxBytes_count",
"unit": "Bytes/Second",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ECS_ContainerInsights_NetworkRxBytes_max",
"unit": "Bytes/Second",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ECS_ContainerInsights_NetworkRxBytes_min",
"unit": "Bytes/Second",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ECS_ContainerInsights_NetworkRxBytes_sum",
"unit": "Bytes/Second",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ECS_ContainerInsights_NetworkTxBytes_count",
"unit": "Bytes/Second",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ECS_ContainerInsights_NetworkTxBytes_max",
"unit": "Bytes/Second",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ECS_ContainerInsights_NetworkTxBytes_min",
"unit": "Bytes/Second",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ECS_ContainerInsights_NetworkTxBytes_sum",
"unit": "Bytes/Second",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ECS_ContainerInsights_PendingTaskCount_count",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ECS_ContainerInsights_PendingTaskCount_max",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ECS_ContainerInsights_PendingTaskCount_min",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ECS_ContainerInsights_PendingTaskCount_sum",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ECS_ContainerInsights_RunningTaskCount_count",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ECS_ContainerInsights_RunningTaskCount_max",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ECS_ContainerInsights_RunningTaskCount_min",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ECS_ContainerInsights_RunningTaskCount_sum",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ECS_ContainerInsights_ServiceCount_count",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ECS_ContainerInsights_ServiceCount_max",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ECS_ContainerInsights_ServiceCount_min",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ECS_ContainerInsights_ServiceCount_sum",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ECS_ContainerInsights_StorageReadBytes_count",
"unit": "Bytes/Second",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ECS_ContainerInsights_StorageReadBytes_max",
"unit": "Bytes/Second",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ECS_ContainerInsights_StorageReadBytes_min",
"unit": "Bytes/Second",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ECS_ContainerInsights_StorageReadBytes_sum",
"unit": "Bytes/Second",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ECS_ContainerInsights_StorageWriteBytes_count",
"unit": "Bytes/Second",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ECS_ContainerInsights_StorageWriteBytes_max",
"unit": "Bytes/Second",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ECS_ContainerInsights_StorageWriteBytes_min",
"unit": "Bytes/Second",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ECS_ContainerInsights_StorageWriteBytes_sum",
"unit": "Bytes/Second",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ECS_ContainerInsights_TaskCount_count",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ECS_ContainerInsights_TaskCount_max",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ECS_ContainerInsights_TaskCount_min",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ECS_ContainerInsights_TaskCount_sum",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ECS_ContainerInsights_TaskCpuUtilization_count",
"unit": "Percent",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ECS_ContainerInsights_TaskCpuUtilization_max",
"unit": "Percent",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ECS_ContainerInsights_TaskCpuUtilization_min",
"unit": "Percent",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ECS_ContainerInsights_TaskCpuUtilization_sum",
"unit": "Percent",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ECS_ContainerInsights_TaskEphemeralStorageUtilization_count",
"unit": "Percent",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ECS_ContainerInsights_TaskEphemeralStorageUtilization_max",
"unit": "Percent",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ECS_ContainerInsights_TaskEphemeralStorageUtilization_min",
"unit": "Percent",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ECS_ContainerInsights_TaskEphemeralStorageUtilization_sum",
"unit": "Percent",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ECS_ContainerInsights_TaskMemoryUtilization_count",
"unit": "Percent",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ECS_ContainerInsights_TaskMemoryUtilization_max",
"unit": "Percent",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ECS_ContainerInsights_TaskMemoryUtilization_min",
"unit": "Percent",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ECS_ContainerInsights_TaskMemoryUtilization_sum",
"unit": "Percent",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ECS_ContainerInsights_TaskSetCount_count",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ECS_ContainerInsights_TaskSetCount_max",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ECS_ContainerInsights_TaskSetCount_min",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ECS_ContainerInsights_TaskSetCount_sum",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ECS_MemoryUtilization_count",
"unit": "Percent",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ECS_MemoryUtilization_max",
"unit": "Percent",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ECS_MemoryUtilization_min",
"unit": "Percent",
"type": "Gauge",
"description": ""
},
{
"name": "aws_ECS_MemoryUtilization_sum",
"unit": "Percent",
"type": "Gauge",
"description": ""
}
],
"logs": [
{
"name": "Account ID",
"path": "resources.cloud.account.id",
"type": "string"
},
{
"name": "Log Group Name",
"path": "resources.aws.cloudwatch.log_group_name",
"type": "string"
},
{
"name": "Log Stream Name",
"path": "resources.aws.cloudwatch.log_stream_name",
"type": "string"
}
]
},
"telemetryCollectionStrategy": {
"aws": {
"metrics": {
"cloudwatchMetricStreamFilters": [
{
"Namespace": "AWS/ECS"
},
{
"Namespace": "ECS/ContainerInsights"
}
]
},
"logs": {
"cloudwatchLogsSubscriptions": [
{
"logGroupNamePrefix": "/ecs",
"filterPattern": ""
},
{
"logGroupNamePrefix": "/aws/ecs/containerinsights",
"filterPattern": ""
}
]
}
}
},
"assets": {
"dashboards": [
{
"id": "overview",
"title": "AWS ECS Overview",
"description": "Overview of ECS",
"definition": "file://assets/dashboards/overview.json"
},
{
"id": "containerinsights",
"title": "ECS ContainerInsights",
"description": "Overview of ECS ContainerInsights",
"definition": "file://assets/dashboards/containerinsights.json"
},
{
"id": "enhanced_containerinsights",
"title": "ECS Enhanced ContainerInsights",
"description": "Enhanced ECS ContainerInsights",
"definition": "file://assets/dashboards/enhanced_containerinsights.json"
}
]
}
}

View File

@@ -0,0 +1,3 @@
### Monitor Elastic Container Service with SigNoz
Collect ECS Logs and key Metrics and view them with an out of the box dashboard.

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="80px" height="80px" viewBox="0 0 80 80" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>Icon-Architecture/64/Arch_Amazon-EKS-Cloud_64</title>
<defs>
<linearGradient x1="0%" y1="100%" x2="100%" y2="0%" id="linearGradient-1">
<stop stop-color="#C8511B" offset="0%"></stop>
<stop stop-color="#FF9900" offset="100%"></stop>
</linearGradient>
</defs>
<g id="Icon-Architecture/64/Arch_Amazon-EKS-Cloud_64" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="Rectangle" fill="url(#linearGradient-1)">
<rect x="0" y="0" width="80" height="80"></rect>
</g>
<g id="Icon-Service/64/Amazon-EKS-Cloud_64" transform="translate(8.000000, 8.000000)" fill="#FFFFFF">
<path d="M53.239,53.377026 L31.737,53.355026 C29.133,53.352026 26.906,51.416026 26.667,48.949026 C26.647,48.743026 26.636,48.528026 26.636,48.305026 C26.636,44.929026 28.968,43.798026 30.391,43.422026 C30.849,43.328026 31.189,42.922026 31.189,42.441026 C31.189,42.394026 31.186,42.347026 31.179,42.300026 C31.145,42.004026 31.128,41.702026 31.128,41.396026 C31.128,38.613026 33.046,35.621026 35.494,34.584026 C39.745,32.786026 42.754,35.151026 43.852,36.253026 C44.751,37.154026 45.453,38.309026 45.938,39.684026 C46.062,40.033026 46.368,40.286026 46.734,40.340026 C47.097,40.394026 47.467,40.243026 47.686,39.945026 C48.322,39.085026 49.352,38.708026 50.307,38.988026 C51.477,39.330026 52.253,40.541026 52.393,42.238026 C52.342,42.756026 52.7,43.231026 53.218,43.320026 C54.587,43.556026 57.769,44.517026 57.769,48.356026 C57.769,52.839026 53.626,53.338026 53.239,53.377026 L53.239,53.377026 Z M29.444,57.862026 L6,45.398026 L6,18.570026 L26,6.75202604 L26,16.451026 L15.463,23.156026 C15.175,23.339026 15,23.658026 15,24.000026 L15,40.000026 C15,40.373026 15.208,40.714026 15.538,40.887026 L24.901,45.758026 L25.04,45.835026 C24.784,46.592026 24.636,47.415026 24.636,48.305026 C24.636,48.594026 24.651,48.872026 24.677,49.140026 C25.012,52.621026 28.113,55.351026 31.735,55.355026 L33.982,55.356026 L29.444,57.862026 Z M44.504,23.136026 L33,16.425026 L33,6.75202604 L53,18.570026 L53,38.467026 C52.431,37.803026 51.716,37.316026 50.868,37.068026 C49.616,36.703026 48.308,36.926026 47.245,37.637026 C46.718,36.567026 46.056,35.631026 45.268,34.841026 C45.182,34.755026 45.088,34.689026 45,34.606026 L45,24.000026 C45,23.644026 44.811,23.315026 44.504,23.136026 L44.504,23.136026 Z M55,41.726026 L55,18.000026 C55,17.646026 54.813,17.318026 54.509,17.139026 L32.509,4.13902604 C32.199,3.95602604 31.817,3.95402604 31.504,4.13102604 C31.192,4.30902604 31,4.64102604 31,5.00002604 L31,17.000026 C31,17.355026 31.188,17.684026 31.496,17.863026 L43,24.574026 L43,33.118026 C40.483,31.714026 37.537,31.548026 34.715,32.742026 C33.725,33.161026 32.827,33.828026 32.037,34.629026 L29.011,31.120026 L35.842,23.199026 L33.18,23.199026 L27,30.000026 L27,23.000026 L25,23.000026 L25,40.000026 L27,40.000026 L27,32.000026 L30.682,36.311026 C29.714,37.841026 29.128,39.633026 29.128,41.396026 C29.128,41.505026 29.13,41.614026 29.133,41.723026 C27.785,42.216026 26.712,43.027026 25.946,44.073026 L17,39.393026 L17,24.548026 L27.537,17.843026 C27.825,17.660026 28,17.341026 28,17.000026 L28,5.00002604 C28,4.64102604 27.807,4.30902604 27.496,4.13102604 C27.183,3.95402604 26.802,3.95602604 26.491,4.13902604 L4.491,17.139026 C4.186,17.318026 4,17.646026 4,18.000026 L4,46.000026 C4,46.369026 4.204,46.709026 4.53,46.882026 L28.983,59.882026 C29.131,59.960026 29.292,60.000026 29.453,60.000026 C29.62,60.000026 29.786,59.958026 29.936,59.875026 L38.114,55.360026 L53.319,55.374026 C55.551,55.192026 59.769,53.492026 59.769,48.356026 C59.769,44.678026 57.505,42.603026 55,41.726026 L55,41.726026 Z" id="Fill-1"></path>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.8 KiB

View File

@@ -0,0 +1,3 @@
### Monitor EKS with SigNoz
Collect EKS key Metrics and ContainerInsights Metrics(if enabled in EKS) and view them with an out of the box dashboard.

View File

@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="80px" height="80px" viewBox="0 0 80 80" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 64 (93537) - https://sketch.com -->
<title>Icon-Architecture/64/Arch_Amazon-ElastiCache_64</title>
<desc>Created with Sketch.</desc>
<defs>
<linearGradient x1="0%" y1="100%" x2="100%" y2="0%" id="linearGradient-1">
<stop stop-color="#2E27AD" offset="0%"></stop>
<stop stop-color="#527FFF" offset="100%"></stop>
</linearGradient>
</defs>
<g id="Icon-Architecture/64/Arch_Amazon-ElastiCache_64" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="Icon-Architecture-BG/64/Database" fill="url(#linearGradient-1)">
<rect id="Rectangle" x="0" y="0" width="80" height="80"></rect>
</g>
<path d="M51,61.5554864 L51,55.7029342 C48.466,57.3400887 43.904,58.1131616 39.556,58.1131616 C34.816,58.1131616 31.121,57.2860836 29,55.8679498 L29,61.5554864 C29,63.2486461 32.948,64.9998113 39.556,64.9998113 C46.3,64.9998113 51,63.1846401 51,61.5554864 L51,61.5554864 Z M39.556,49.2203227 C34.816,49.2203227 31.121,48.3942447 29,46.976111 L29,52.6866497 C29.031,54.3738088 32.973,56.1129729 39.556,56.1129729 C46.279,56.1129729 50.969,54.3088027 51,52.6826493 L51,46.8100953 C48.466,48.4482498 43.904,49.2203227 39.556,49.2203227 L39.556,49.2203227 Z M51,43.7908105 L51,37.0291726 C48.466,38.666327 43.904,39.4393999 39.556,39.4393999 C34.816,39.4393999 31.121,38.613322 29,37.1951882 L29,43.7948108 C29.031,45.48197 32.973,47.220134 39.556,47.220134 C46.279,47.220134 50.969,45.4159638 51,43.7908105 L51,43.7908105 Z M28.997,33.9928861 C28.997,33.9958864 28.998,33.9988867 28.998,34.001887 L29,34.001887 L29,34.012888 C29.031,35.7000472 32.973,37.4392112 39.556,37.4392112 C46.898,37.4392112 50.969,35.4170205 51,34.0098877 L51,34.001887 L51.002,34.001887 C51.002,33.9988867 51.003,33.9958864 51.003,33.9928861 C51.003,32.5847533 46.927,30.546561 39.556,30.546561 C32.946,30.546561 28.997,32.2987263 28.997,33.9928861 L28.997,33.9928861 Z M53,34.0178885 L53,43.7738088 L53.003,43.7738088 C53.003,43.7828097 53,43.7898104 53,43.7988112 L53,52.6666478 L53.003,52.6666478 C53.003,52.6756486 53,52.6826493 53,52.6916502 L53,61.5554864 C53,65.2968393 46.031,67 39.556,67 C31.929,67 27,64.8627984 27,61.5554864 L27,52.6976507 C27,52.6866497 26.997,52.6776488 26.997,52.6666478 L27,52.6666478 L27,43.8048118 C27,43.7948108 26.997,43.7848099 26.997,43.7738088 L27,43.7738088 L27,34.023889 C27,34.012888 26.997,34.0038872 26.997,33.9928861 C26.997,30.684574 31.927,28.5463723 39.556,28.5463723 C46.032,28.5463723 53.003,30.2505331 53.003,33.9928861 C53.003,34.001887 53,34.0088876 53,34.0178885 L53,34.0178885 Z M67,21.1206718 C67.553,21.1206718 68,20.6726295 68,20.1205774 L68,15.0000943 C68,14.4470422 67.553,14 67,14 L13,14 C12.447,14 12,14.4470422 12,15.0000943 L12,20.1205774 C12,20.6726295 12.447,21.1206718 13,21.1206718 C14.221,21.1206718 15.214,22.1077649 15.214,23.3208793 C15.214,24.5339938 14.221,25.5210869 13,25.5210869 C12.447,25.5210869 12,25.9691292 12,26.5211812 L12,47.0031135 C12,47.5551656 12.447,48.0032078 13,48.0032078 L23,48.0032078 L23,46.0030192 L18,46.0030192 L18,43.0027361 L23,43.0027361 L23,41.0025474 L17,41.0025474 C16.447,41.0025474 16,41.4495896 16,42.0026418 L16,46.0030192 L14,46.0030192 L14,27.4012643 C15.843,26.9522219 17.214,25.2930654 17.214,23.3208793 C17.214,21.3476932 15.843,19.6885367 14,19.2394943 L14,16.0001887 L66,16.0001887 L66,19.2394943 C64.157,19.6885367 62.786,21.3476932 62.786,23.3208793 C62.786,25.2930654 64.157,26.9522219 66,27.4012643 L66,46.0030192 L64,46.0030192 L64,42.0026418 C64,41.4495896 63.553,41.0025474 63,41.0025474 L57,41.0025474 L57,43.0027361 L62,43.0027361 L62,46.0030192 L57,46.0030192 L57,48.0032078 L67,48.0032078 C67.553,48.0032078 68,47.5551656 68,47.0031135 L68,26.5211812 C68,25.9691292 67.553,25.5210869 67,25.5210869 C65.779,25.5210869 64.786,24.5339938 64.786,23.3208793 C64.786,22.1077649 65.779,21.1206718 67,21.1206718 L67,21.1206718 Z M28,28.0013209 L28,20.0005661 C28,19.4475139 27.553,19.0004717 27,19.0004717 L21,19.0004717 C20.447,19.0004717 20,19.4475139 20,20.0005661 L20,37.00217 C20,37.5542221 20.447,38.0022644 21,38.0022644 L24,38.0022644 L24,36.0020757 L22,36.0020757 L22,21.0006604 L26,21.0006604 L26,28.0013209 L28,28.0013209 Z M58,36.0020757 L57,36.0020757 L57,38.0022644 L59,38.0022644 C59.553,38.0022644 60,37.5542221 60,37.00217 L60,20.0005661 C60,19.4475139 59.553,19.0004717 59,19.0004717 L53,19.0004717 C52.447,19.0004717 52,19.4475139 52,20.0005661 L52,28.0013209 L54,28.0013209 L54,21.0006604 L58,21.0006604 L58,36.0020757 Z M50,27.0012265 L50,20.0005661 C50,19.4475139 49.553,19.0004717 49,19.0004717 L42,19.0004717 C41.447,19.0004717 41,19.4475139 41,20.0005661 L41,26.0011322 L43,26.0011322 L43,21.0006604 L48,21.0006604 L48,27.0012265 L50,27.0012265 Z M37,26.0011322 L37,21.0006604 L32,21.0006604 L32,27.0012265 L30,27.0012265 L30,20.0005661 C30,19.4475139 30.447,19.0004717 31,19.0004717 L38,19.0004717 C38.553,19.0004717 39,19.4475139 39,20.0005661 L39,26.0011322 L37,26.0011322 Z" id="Amazon-ElastiCache_Icon_64_Squid" fill="#FFFFFF"></path>
</g>
</svg>

After

Width:  |  Height:  |  Size: 5.2 KiB

View File

@@ -0,0 +1,3 @@
### Monitor ElastiCache with SigNoz
Collect ElastiCache key Metrics and view them with an out of the box dashboard.

View File

@@ -0,0 +1 @@
<svg width="800px" height="800px" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" fill="none"><path fill="#FA7E14" d="M7.983 8.37c-.053.073-.098.133-.141.194L5.775 11.5c-.64.91-1.282 1.82-1.924 2.73a.128.128 0 01-.092.051c-.906-.007-1.813-.017-2.719-.028-.01 0-.02-.003-.04-.006a.455.455 0 01.025-.053 13977.496 13977.496 0 015.446-8.146c.092-.138.188-.273.275-.413a.165.165 0 00.018-.124c-.167-.515-.338-1.03-.508-1.543-.073-.22-.15-.44-.218-.66-.022-.072-.059-.094-.134-.093-.57.002-1.136.001-1.704.001-.108 0-.108 0-.108-.103 0-.674 0-1.347-.002-2.021 0-.075.026-.092.099-.092 1.143.002 2.286.002 3.43 0a.113.113 0 01.076.017.107.107 0 01.045.061 18266.184 18266.184 0 003.92 9.51c.218.53.438 1.059.654 1.59.026.064.053.076.12.056.6-.178 1.2-.352 1.8-.531.075-.023.102-.008.126.064.204.62.412 1.239.62 1.858l.02.073c-.043.015-.083.032-.124.043l-4.085 1.25c-.065.02-.085 0-.106-.054l-1.25-3.048-1.226-2.984-.183-.449c-.01-.026-.023-.048-.043-.087z"/></svg>

After

Width:  |  Height:  |  Size: 965 B

View File

@@ -0,0 +1,300 @@
{
"id": "lambda",
"title": "Lambda",
"icon": "file://icon.svg",
"overview": "file://overview.md",
"supportedSignals": {
"metrics": true,
"logs": true
},
"dataCollected": {
"metrics": [
{
"name": "aws_Lambda_AsyncEventAge_count",
"unit": "Milliseconds",
"type": "Gauge",
"description": ""
},
{
"name": "aws_Lambda_AsyncEventAge_max",
"unit": "Milliseconds",
"type": "Gauge",
"description": ""
},
{
"name": "aws_Lambda_AsyncEventAge_min",
"unit": "Milliseconds",
"type": "Gauge",
"description": ""
},
{
"name": "aws_Lambda_AsyncEventAge_sum",
"unit": "Milliseconds",
"type": "Gauge",
"description": ""
},
{
"name": "aws_Lambda_AsyncEventsDropped_count",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_Lambda_AsyncEventsDropped_max",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_Lambda_AsyncEventsDropped_min",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_Lambda_AsyncEventsDropped_sum",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_Lambda_AsyncEventsReceived_count",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_Lambda_AsyncEventsReceived_max",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_Lambda_AsyncEventsReceived_min",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_Lambda_AsyncEventsReceived_sum",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_Lambda_ClaimedAccountConcurrency_count",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_Lambda_ClaimedAccountConcurrency_max",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_Lambda_ClaimedAccountConcurrency_min",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_Lambda_ClaimedAccountConcurrency_sum",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_Lambda_ConcurrentExecutions_count",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_Lambda_ConcurrentExecutions_max",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_Lambda_ConcurrentExecutions_min",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_Lambda_ConcurrentExecutions_sum",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_Lambda_Duration_count",
"unit": "Milliseconds",
"type": "Gauge",
"description": ""
},
{
"name": "aws_Lambda_Duration_max",
"unit": "Milliseconds",
"type": "Gauge",
"description": ""
},
{
"name": "aws_Lambda_Duration_min",
"unit": "Milliseconds",
"type": "Gauge",
"description": ""
},
{
"name": "aws_Lambda_Duration_sum",
"unit": "Milliseconds",
"type": "Gauge",
"description": ""
},
{
"name": "aws_Lambda_Errors_count",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_Lambda_Errors_max",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_Lambda_Errors_min",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_Lambda_Errors_sum",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_Lambda_Invocations_count",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_Lambda_Invocations_max",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_Lambda_Invocations_min",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_Lambda_Invocations_sum",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_Lambda_Throttles_count",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_Lambda_Throttles_max",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_Lambda_Throttles_min",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_Lambda_Throttles_sum",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_Lambda_UnreservedConcurrentExecutions_count",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_Lambda_UnreservedConcurrentExecutions_max",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_Lambda_UnreservedConcurrentExecutions_min",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_Lambda_UnreservedConcurrentExecutions_sum",
"unit": "Count",
"type": "Gauge",
"description": ""
}
],
"logs": [
{
"name": "Account Id",
"path": "resources.cloud.account.id",
"type": "string"
},
{
"name": "Log Group Name",
"path": "resources.aws.cloudwatch.log_group_name",
"type": "string"
},
{
"name": "Log Stream Name",
"path": "resources.aws.cloudwatch.log_stream_name",
"type": "string"
}
]
},
"telemetryCollectionStrategy": {
"aws": {
"metrics": {
"cloudwatchMetricStreamFilters": [
{
"Namespace": "AWS/Lambda"
}
]
},
"logs": {
"cloudwatchLogsSubscriptions": [
{
"logGroupNamePrefix": "/aws/lambda",
"filterPattern": ""
}
]
}
}
},
"assets": {
"dashboards": [
{
"id": "overview",
"title": "AWS Lambda Overview",
"description": "Overview of AWS Lambda",
"definition": "file://assets/dashboards/overview.json"
}
]
}
}

View File

@@ -0,0 +1,3 @@
### Monitor AWS Lambda with SigNoz
Collect key AWS Lambda metrics and view them with an out of the box dashboard.

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 6.0 KiB

View File

@@ -0,0 +1,3 @@
### Monitor Managed Streaming Kafka with SigNoz
Collect key MSK metrics and view them with an out of the box dashboard.

View File

@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="80px" height="80px" viewBox="0 0 80 80" version="1.1" xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink">
<title>Icon-Architecture/64/Arch_Amazon-RDS_64</title>
<desc>Created with Sketch.</desc>
<defs>
<linearGradient x1="0%" y1="100%" x2="100%" y2="0%" id="linearGradient-1">
<stop stop-color="#2E27AD" offset="0%"></stop>
<stop stop-color="#527FFF" offset="100%"></stop>
</linearGradient>
</defs>
<g id="Icon-Architecture/64/Arch_Amazon-RDS_64" stroke="none" stroke-width="1" fill="none"
fill-rule="evenodd">
<g id="Icon-Architecture-BG/64/Database" fill="url(#linearGradient-1)">
<rect id="Rectangle" x="0" y="0" width="80" height="80"></rect>
</g>
<path
d="M15.414,14 L24.707,23.293 L23.293,24.707 L14,15.414 L14,23 L12,23 L12,13 C12,12.448 12.447,12 13,12 L23,12 L23,14 L15.414,14 Z M68,13 L68,23 L66,23 L66,15.414 L56.707,24.707 L55.293,23.293 L64.586,14 L57,14 L57,12 L67,12 C67.553,12 68,12.448 68,13 L68,13 Z M66,57 L68,57 L68,67 C68,67.552 67.553,68 67,68 L57,68 L57,66 L64.586,66 L55.293,56.707 L56.707,55.293 L66,64.586 L66,57 Z M65.5,39.213 C65.5,35.894 61.668,32.615 55.25,30.442 L55.891,28.548 C63.268,31.045 67.5,34.932 67.5,39.213 C67.5,43.495 63.268,47.383 55.89,49.879 L55.249,47.984 C61.668,45.812 65.5,42.534 65.5,39.213 L65.5,39.213 Z M14.556,39.213 C14.556,42.393 18.143,45.585 24.152,47.753 L23.473,49.634 C16.535,47.131 12.556,43.333 12.556,39.213 C12.556,35.094 16.535,31.296 23.473,28.792 L24.152,30.673 C18.143,32.842 14.556,36.034 14.556,39.213 L14.556,39.213 Z M24.707,56.707 L15.414,66 L23,66 L23,68 L13,68 C12.447,68 12,67.552 12,67 L12,57 L14,57 L14,64.586 L23.293,55.293 L24.707,56.707 Z M40,31.286 C32.854,31.286 29,29.44 29,28.686 C29,27.931 32.854,26.086 40,26.086 C47.145,26.086 51,27.931 51,28.686 C51,29.44 47.145,31.286 40,31.286 L40,31.286 Z M40.029,39.031 C33.187,39.031 29,37.162 29,36.145 L29,31.284 C31.463,32.643 35.832,33.286 40,33.286 C44.168,33.286 48.537,32.643 51,31.284 L51,36.145 C51,37.163 46.835,39.031 40.029,39.031 L40.029,39.031 Z M40.029,46.667 C33.187,46.667 29,44.798 29,43.781 L29,38.862 C31.431,40.291 35.742,41.031 40.029,41.031 C44.292,41.031 48.578,40.292 51,38.867 L51,43.781 C51,44.799 46.835,46.667 40.029,46.667 L40.029,46.667 Z M40,53.518 C32.883,53.518 29,51.605 29,50.622 L29,46.498 C31.431,47.927 35.742,48.667 40.029,48.667 C44.292,48.667 48.578,47.929 51,46.503 L51,50.622 C51,51.605 47.117,53.518 40,53.518 L40,53.518 Z M40,24.086 C33.739,24.086 27,25.525 27,28.686 L27,50.622 C27,53.836 33.54,55.518 40,55.518 C46.46,55.518 53,53.836 53,50.622 L53,28.686 C53,25.525 46.261,24.086 40,24.086 L40,24.086 Z"
id="Amazon-RDS_Icon_64_Squid" fill="#FFFFFF"></path>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.7 KiB

View File

@@ -0,0 +1,804 @@
{
"id": "rds",
"title": "RDS",
"icon": "file://icon.svg",
"overview": "file://overview.md",
"supportedSignals": {
"metrics": true,
"logs": true
},
"dataCollected": {
"metrics": [
{
"name": "aws_RDS_BurstBalance_count",
"unit": "Percent",
"type": "Gauge",
"description": ""
},
{
"name": "aws_RDS_BurstBalance_max",
"unit": "Percent",
"type": "Gauge",
"description": ""
},
{
"name": "aws_RDS_BurstBalance_min",
"unit": "Percent",
"type": "Gauge",
"description": ""
},
{
"name": "aws_RDS_BurstBalance_sum",
"unit": "Percent",
"type": "Gauge",
"description": ""
},
{
"name": "aws_RDS_CPUCreditBalance_count",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_RDS_CPUCreditBalance_max",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_RDS_CPUCreditBalance_min",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_RDS_CPUCreditBalance_sum",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_RDS_CPUCreditUsage_count",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_RDS_CPUCreditUsage_max",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_RDS_CPUCreditUsage_min",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_RDS_CPUCreditUsage_sum",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_RDS_CPUSurplusCreditBalance_count",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_RDS_CPUSurplusCreditBalance_max",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_RDS_CPUSurplusCreditBalance_min",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_RDS_CPUSurplusCreditBalance_sum",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_RDS_CPUSurplusCreditsCharged_count",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_RDS_CPUSurplusCreditsCharged_max",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_RDS_CPUSurplusCreditsCharged_min",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_RDS_CPUSurplusCreditsCharged_sum",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_RDS_CPUUtilization_count",
"unit": "Percent",
"type": "Gauge",
"description": ""
},
{
"name": "aws_RDS_CPUUtilization_max",
"unit": "Percent",
"type": "Gauge",
"description": ""
},
{
"name": "aws_RDS_CPUUtilization_min",
"unit": "Percent",
"type": "Gauge",
"description": ""
},
{
"name": "aws_RDS_CPUUtilization_sum",
"unit": "Percent",
"type": "Gauge",
"description": ""
},
{
"name": "aws_RDS_CheckpointLag_count",
"unit": "Seconds",
"type": "Gauge",
"description": ""
},
{
"name": "aws_RDS_CheckpointLag_max",
"unit": "Seconds",
"type": "Gauge",
"description": ""
},
{
"name": "aws_RDS_CheckpointLag_min",
"unit": "Seconds",
"type": "Gauge",
"description": ""
},
{
"name": "aws_RDS_CheckpointLag_sum",
"unit": "Seconds",
"type": "Gauge",
"description": ""
},
{
"name": "aws_RDS_DBLoadCPU_count",
"unit": "None",
"type": "Gauge",
"description": ""
},
{
"name": "aws_RDS_DBLoadCPU_max",
"unit": "None",
"type": "Gauge",
"description": ""
},
{
"name": "aws_RDS_DBLoadCPU_min",
"unit": "None",
"type": "Gauge",
"description": ""
},
{
"name": "aws_RDS_DBLoadCPU_sum",
"unit": "None",
"type": "Gauge",
"description": ""
},
{
"name": "aws_RDS_DBLoadNonCPU_count",
"unit": "None",
"type": "Gauge",
"description": ""
},
{
"name": "aws_RDS_DBLoadNonCPU_max",
"unit": "None",
"type": "Gauge",
"description": ""
},
{
"name": "aws_RDS_DBLoadNonCPU_min",
"unit": "None",
"type": "Gauge",
"description": ""
},
{
"name": "aws_RDS_DBLoadNonCPU_sum",
"unit": "None",
"type": "Gauge",
"description": ""
},
{
"name": "aws_RDS_DBLoadRelativeToNumVCPUs_count",
"unit": "None",
"type": "Gauge",
"description": ""
},
{
"name": "aws_RDS_DBLoadRelativeToNumVCPUs_max",
"unit": "None",
"type": "Gauge",
"description": ""
},
{
"name": "aws_RDS_DBLoadRelativeToNumVCPUs_min",
"unit": "None",
"type": "Gauge",
"description": ""
},
{
"name": "aws_RDS_DBLoadRelativeToNumVCPUs_sum",
"unit": "None",
"type": "Gauge",
"description": ""
},
{
"name": "aws_RDS_DBLoad_count",
"unit": "None",
"type": "Gauge",
"description": ""
},
{
"name": "aws_RDS_DBLoad_max",
"unit": "None",
"type": "Gauge",
"description": ""
},
{
"name": "aws_RDS_DBLoad_min",
"unit": "None",
"type": "Gauge",
"description": ""
},
{
"name": "aws_RDS_DBLoad_sum",
"unit": "None",
"type": "Gauge",
"description": ""
},
{
"name": "aws_RDS_DatabaseConnections_count",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_RDS_DatabaseConnections_max",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_RDS_DatabaseConnections_min",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_RDS_DatabaseConnections_sum",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_RDS_DiskQueueDepth_count",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_RDS_DiskQueueDepth_max",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_RDS_DiskQueueDepth_min",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_RDS_DiskQueueDepth_sum",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_RDS_EBSByteBalance__count",
"unit": "Percent",
"type": "Gauge",
"description": ""
},
{
"name": "aws_RDS_EBSByteBalance__max",
"unit": "Percent",
"type": "Gauge",
"description": ""
},
{
"name": "aws_RDS_EBSByteBalance__min",
"unit": "Percent",
"type": "Gauge",
"description": ""
},
{
"name": "aws_RDS_EBSByteBalance__sum",
"unit": "Percent",
"type": "Gauge",
"description": ""
},
{
"name": "aws_RDS_EBSIOBalance__count",
"unit": "Percent",
"type": "Gauge",
"description": ""
},
{
"name": "aws_RDS_EBSIOBalance__max",
"unit": "Percent",
"type": "Gauge",
"description": ""
},
{
"name": "aws_RDS_EBSIOBalance__min",
"unit": "Percent",
"type": "Gauge",
"description": ""
},
{
"name": "aws_RDS_EBSIOBalance__sum",
"unit": "Percent",
"type": "Gauge",
"description": ""
},
{
"name": "aws_RDS_FreeStorageSpace_count",
"unit": "Bytes",
"type": "Gauge",
"description": ""
},
{
"name": "aws_RDS_FreeStorageSpace_max",
"unit": "Bytes",
"type": "Gauge",
"description": ""
},
{
"name": "aws_RDS_FreeStorageSpace_min",
"unit": "Bytes",
"type": "Gauge",
"description": ""
},
{
"name": "aws_RDS_FreeStorageSpace_sum",
"unit": "Bytes",
"type": "Gauge",
"description": ""
},
{
"name": "aws_RDS_FreeableMemory_count",
"unit": "Bytes",
"type": "Gauge",
"description": ""
},
{
"name": "aws_RDS_FreeableMemory_max",
"unit": "Bytes",
"type": "Gauge",
"description": ""
},
{
"name": "aws_RDS_FreeableMemory_min",
"unit": "Bytes",
"type": "Gauge",
"description": ""
},
{
"name": "aws_RDS_FreeableMemory_sum",
"unit": "Bytes",
"type": "Gauge",
"description": ""
},
{
"name": "aws_RDS_MaximumUsedTransactionIDs_count",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_RDS_MaximumUsedTransactionIDs_max",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_RDS_MaximumUsedTransactionIDs_min",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_RDS_MaximumUsedTransactionIDs_sum",
"unit": "Count",
"type": "Gauge",
"description": ""
},
{
"name": "aws_RDS_NetworkReceiveThroughput_count",
"unit": "Bytes/Second",
"type": "Gauge",
"description": ""
},
{
"name": "aws_RDS_NetworkReceiveThroughput_max",
"unit": "Bytes/Second",
"type": "Gauge",
"description": ""
},
{
"name": "aws_RDS_NetworkReceiveThroughput_min",
"unit": "Bytes/Second",
"type": "Gauge",
"description": ""
},
{
"name": "aws_RDS_NetworkReceiveThroughput_sum",
"unit": "Bytes/Second",
"type": "Gauge",
"description": ""
},
{
"name": "aws_RDS_NetworkTransmitThroughput_count",
"unit": "Bytes/Second",
"type": "Gauge",
"description": ""
},
{
"name": "aws_RDS_NetworkTransmitThroughput_max",
"unit": "Bytes/Second",
"type": "Gauge",
"description": ""
},
{
"name": "aws_RDS_NetworkTransmitThroughput_min",
"unit": "Bytes/Second",
"type": "Gauge",
"description": ""
},
{
"name": "aws_RDS_NetworkTransmitThroughput_sum",
"unit": "Bytes/Second",
"type": "Gauge",
"description": ""
},
{
"name": "aws_RDS_OldestReplicationSlotLag_count",
"unit": "Bytes",
"type": "Gauge",
"description": ""
},
{
"name": "aws_RDS_OldestReplicationSlotLag_max",
"unit": "Bytes",
"type": "Gauge",
"description": ""
},
{
"name": "aws_RDS_OldestReplicationSlotLag_min",
"unit": "Bytes",
"type": "Gauge",
"description": ""
},
{
"name": "aws_RDS_OldestReplicationSlotLag_sum",
"unit": "Bytes",
"type": "Gauge",
"description": ""
},
{
"name": "aws_RDS_ReadIOPS_count",
"unit": "Count/Second",
"type": "Gauge",
"description": ""
},
{
"name": "aws_RDS_ReadIOPS_max",
"unit": "Count/Second",
"type": "Gauge",
"description": ""
},
{
"name": "aws_RDS_ReadIOPS_min",
"unit": "Count/Second",
"type": "Gauge",
"description": ""
},
{
"name": "aws_RDS_ReadIOPS_sum",
"unit": "Count/Second",
"type": "Gauge",
"description": ""
},
{
"name": "aws_RDS_ReadLatency_count",
"unit": "Seconds",
"type": "Gauge",
"description": ""
},
{
"name": "aws_RDS_ReadLatency_max",
"unit": "Seconds",
"type": "Gauge",
"description": ""
},
{
"name": "aws_RDS_ReadLatency_min",
"unit": "Seconds",
"type": "Gauge",
"description": ""
},
{
"name": "aws_RDS_ReadLatency_sum",
"unit": "Seconds",
"type": "Gauge",
"description": ""
},
{
"name": "aws_RDS_ReadThroughput_count",
"unit": "Bytes/Second",
"type": "Gauge",
"description": ""
},
{
"name": "aws_RDS_ReadThroughput_max",
"unit": "Bytes/Second",
"type": "Gauge",
"description": ""
},
{
"name": "aws_RDS_ReadThroughput_min",
"unit": "Bytes/Second",
"type": "Gauge",
"description": ""
},
{
"name": "aws_RDS_ReadThroughput_sum",
"unit": "Bytes/Second",
"type": "Gauge",
"description": ""
},
{
"name": "aws_RDS_ReplicationSlotDiskUsage_count",
"unit": "Bytes",
"type": "Gauge",
"description": ""
},
{
"name": "aws_RDS_ReplicationSlotDiskUsage_max",
"unit": "Bytes",
"type": "Gauge",
"description": ""
},
{
"name": "aws_RDS_ReplicationSlotDiskUsage_min",
"unit": "Bytes",
"type": "Gauge",
"description": ""
},
{
"name": "aws_RDS_ReplicationSlotDiskUsage_sum",
"unit": "Bytes",
"type": "Gauge",
"description": ""
},
{
"name": "aws_RDS_SwapUsage_count",
"unit": "Bytes",
"type": "Gauge",
"description": ""
},
{
"name": "aws_RDS_SwapUsage_max",
"unit": "Bytes",
"type": "Gauge",
"description": ""
},
{
"name": "aws_RDS_SwapUsage_min",
"unit": "Bytes",
"type": "Gauge",
"description": ""
},
{
"name": "aws_RDS_SwapUsage_sum",
"unit": "Bytes",
"type": "Gauge",
"description": ""
},
{
"name": "aws_RDS_TransactionLogsDiskUsage_count",
"unit": "Bytes",
"type": "Gauge",
"description": ""
},
{
"name": "aws_RDS_TransactionLogsDiskUsage_max",
"unit": "Bytes",
"type": "Gauge",
"description": ""
},
{
"name": "aws_RDS_TransactionLogsDiskUsage_min",
"unit": "Bytes",
"type": "Gauge",
"description": ""
},
{
"name": "aws_RDS_TransactionLogsDiskUsage_sum",
"unit": "Bytes",
"type": "Gauge",
"description": ""
},
{
"name": "aws_RDS_TransactionLogsGeneration_count",
"unit": "Bytes/Second",
"type": "Gauge",
"description": ""
},
{
"name": "aws_RDS_TransactionLogsGeneration_max",
"unit": "Bytes/Second",
"type": "Gauge",
"description": ""
},
{
"name": "aws_RDS_TransactionLogsGeneration_min",
"unit": "Bytes/Second",
"type": "Gauge",
"description": ""
},
{
"name": "aws_RDS_TransactionLogsGeneration_sum",
"unit": "Bytes/Second",
"type": "Gauge",
"description": ""
},
{
"name": "aws_RDS_WriteIOPS_count",
"unit": "Count/Second",
"type": "Gauge",
"description": ""
},
{
"name": "aws_RDS_WriteIOPS_max",
"unit": "Count/Second",
"type": "Gauge",
"description": ""
},
{
"name": "aws_RDS_WriteIOPS_min",
"unit": "Count/Second",
"type": "Gauge",
"description": ""
},
{
"name": "aws_RDS_WriteIOPS_sum",
"unit": "Count/Second",
"type": "Gauge",
"description": ""
},
{
"name": "aws_RDS_WriteLatency_count",
"unit": "Seconds",
"type": "Gauge",
"description": ""
},
{
"name": "aws_RDS_WriteLatency_max",
"unit": "Seconds",
"type": "Gauge",
"description": ""
},
{
"name": "aws_RDS_WriteLatency_min",
"unit": "Seconds",
"type": "Gauge",
"description": ""
},
{
"name": "aws_RDS_WriteLatency_sum",
"unit": "Seconds",
"type": "Gauge",
"description": ""
},
{
"name": "aws_RDS_WriteThroughput_count",
"unit": "Bytes/Second",
"type": "Gauge",
"description": ""
},
{
"name": "aws_RDS_WriteThroughput_max",
"unit": "Bytes/Second",
"type": "Gauge",
"description": ""
},
{
"name": "aws_RDS_WriteThroughput_min",
"unit": "Bytes/Second",
"type": "Gauge",
"description": ""
},
{
"name": "aws_RDS_WriteThroughput_sum",
"unit": "Bytes/Second",
"type": "Gauge",
"description": ""
}
],
"logs": [
{
"name": "Account Id",
"path": "resources.cloud.account.id",
"type": "string"
},
{
"name": "Log Group Name",
"path": "resources.aws.cloudwatch.log_group_name",
"type": "string"
},
{
"name": "Log Stream Name",
"path": "resources.aws.cloudwatch.log_stream_name",
"type": "string"
}
]
},
"telemetryCollectionStrategy": {
"aws": {
"metrics": {
"cloudwatchMetricStreamFilters": [
{
"Namespace": "AWS/RDS"
}
]
},
"logs": {
"cloudwatchLogsSubscriptions": [
{
"logGroupNamePrefix": "/aws/rds",
"filterPattern": ""
}
]
}
}
},
"assets": {
"dashboards": [
{
"id": "overview",
"title": "RDS Overview",
"description": "Overview of RDS",
"definition": "file://assets/dashboards/overview.json"
}
]
}
}

View File

@@ -0,0 +1,3 @@
### Monitor RDS with SigNoz
Collect key RDS metrics and view them with an out of the box dashboard.

View File

@@ -0,0 +1 @@
<svg width="256" height="256" viewBox="0 0 256 256" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" preserveAspectRatio="xMidYMid"><title>AWS Simple Storage Service (S3)</title><defs><linearGradient x1="0%" y1="100%" x2="100%" y2="0%" id="a"><stop stop-color="#1B660F" offset="0%"/><stop stop-color="#6CAE3E" offset="100%"/></linearGradient></defs><g><rect fill="url(#a)" width="256" height="256"/><path d="M194.67488,137.25632 L195.90368,128.60352 C207.23488,135.39072 207.38208,138.19392 207.378964,138.27072 C207.35968,138.28672 205.42688,139.89952 194.67488,137.25632 L194.67488,137.25632 Z M188.45728,135.52832 C168.87328,129.60192 141.59968,117.08992 130.56288,111.87392 C130.56288,111.82912 130.57568,111.78752 130.57568,111.74272 C130.57568,107.50272 127.12608,104.05312 122.88288,104.05312 C118.64608,104.05312 115.19648,107.50272 115.19648,111.74272 C115.19648,115.98272 118.64608,119.43232 122.88288,119.43232 C124.74528,119.43232 126.43488,118.73792 127.76928,117.63392 C140.75488,123.78112 167.81728,136.11072 187.54528,141.93472 L179.74368,196.99392 C179.72128,197.14432 179.71168,197.29472 179.71168,197.44512 C179.71168,202.29312 158.24928,211.19872 123.18048,211.19872 C87.74048,211.19872 66.05088,202.29312 66.05088,197.44512 C66.05088,197.29792 66.04128,197.15392 66.02208,197.00992 L49.72128,77.94752 C63.83008,87.65952 94.17568,92.79872 123.19968,92.79872 C152.17888,92.79872 182.47328,87.67872 196.61088,77.99552 L188.45728,135.52832 Z M47.99968,65.52832 C48.23008,61.31712 72.42848,44.79872 123.19968,44.79872 C173.96448,44.79872 198.16608,61.31392 198.39968,65.52832 L198.39968,66.96512 C195.61568,76.40832 164.25568,86.39872 123.19968,86.39872 C82.07328,86.39872 50.69728,76.37632 47.99968,66.92032 L47.99968,65.52832 Z M204.79968,65.59872 C204.79968,54.51072 173.01088,38.39872 123.19968,38.39872 C73.38848,38.39872 41.59968,54.51072 41.59968,65.59872 L41.90048,68.01152 L59.65408,197.68832 C60.07968,212.19072 98.75488,217.59872 123.18048,217.59872 C153.49088,217.59872 185.69248,210.62912 186.10848,197.69792 L193.77568,143.62752 C198.04128,144.64832 201.55168,145.16992 204.37088,145.16992 C208.15648,145.16992 210.71648,144.24512 212.26848,142.39552 C213.54208,140.87872 214.02848,139.04192 213.66368,137.08672 C212.83488,132.65792 207.57728,127.88352 196.87008,121.77472 L204.47328,68.13632 L204.79968,65.59872 Z" fill="#FFFFFF"/></g></svg>

After

Width:  |  Height:  |  Size: 2.3 KiB

View File

@@ -0,0 +1,54 @@
{
"id": "s3sync",
"title": "S3 Sync",
"icon": "file://icon.svg",
"overview": "file://overview.md",
"supportedSignals": {
"metrics": false,
"logs": true
},
"dataCollected": {
"logs": [
{
"name": "Account ID",
"path": "resources.cloud.account.id",
"type": "string"
},
{
"name": "Account Region",
"path": "resources.cloud.account.region",
"type": "string"
},
{
"name": "Bucket Name",
"path": "resources.cloud.bucket.name",
"type": "string"
},
{
"name": "Object Key",
"path": "attributes.object.key",
"type": "string"
},
{
"name": "Object S3 Event Time",
"path": "attributes.object.event_time",
"type": "string"
}
]
},
"telemetryCollectionStrategy": {
"aws": {
"logs": {
"cloudwatchLogsSubscriptions": [
{
"logGroupNamePrefix": "x/signoz/forwarder",
"filterPattern": ""
}
]
}
}
},
"assets": {
"dashboards": []
}
}

View File

@@ -0,0 +1,3 @@
### Sync logs stored in S3 Object Store with SigNoz
Collect logs stored by AWS Services in S3 Object Store and explore them in SigNoz.

View File

@@ -0,0 +1,818 @@
{
"description": "View key AWS SNS metrics with an out of the box dashboard.",
"image": "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHN2ZyB3aWR0aD0iODBweCIgaGVpZ2h0PSI4MHB4IiB2aWV3Qm94PSIwIDAgODAgODAiIHZlcnNpb249IjEuMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayI+CiAgICA8IS0tIEdlbmVyYXRvcjogU2tldGNoIDY0ICg5MzUzNykgLSBodHRwczovL3NrZXRjaC5jb20gLS0+CiAgICA8dGl0bGU+SWNvbi1BcmNoaXRlY3R1cmUvNjQvQXJjaF9BV1MtU2ltcGxlLU5vdGlmaWNhdGlvbi1TZXJ2aWNlXzY0PC90aXRsZT4KICAgIDxkZXNjPkNyZWF0ZWQgd2l0aCBTa2V0Y2guPC9kZXNjPgogICAgPGRlZnM+CiAgICAgICAgPGxpbmVhckdyYWRpZW50IHgxPSIwJSIgeTE9IjEwMCUiIHgyPSIxMDAlIiB5Mj0iMCUiIGlkPSJsaW5lYXJHcmFkaWVudC0xIj4KICAgICAgICAgICAgPHN0b3Agc3RvcC1jb2xvcj0iI0IwMDg0RCIgb2Zmc2V0PSIwJSI+PC9zdG9wPgogICAgICAgICAgICA8c3RvcCBzdG9wLWNvbG9yPSIjRkY0RjhCIiBvZmZzZXQ9IjEwMCUiPjwvc3RvcD4KICAgICAgICA8L2xpbmVhckdyYWRpZW50PgogICAgPC9kZWZzPgogICAgPGcgaWQ9Ikljb24tQXJjaGl0ZWN0dXJlLzY0L0FyY2hfQVdTLVNpbXBsZS1Ob3RpZmljYXRpb24tU2VydmljZV82NCIgc3Ryb2tlPSJub25lIiBzdHJva2Utd2lkdGg9IjEiIGZpbGw9Im5vbmUiIGZpbGwtcnVsZT0iZXZlbm9kZCI+CiAgICAgICAgPGcgaWQ9Ikljb24tQXJjaGl0ZWN0dXJlLUJHLzY0L0FwcGxpY2F0aW9uLUludGVncmF0aW9uIiBmaWxsPSJ1cmwoI2xpbmVhckdyYWRpZW50LTEpIj4KICAgICAgICAgICAgPHJlY3QgaWQ9IlJlY3RhbmdsZSIgeD0iMCIgeT0iMCIgd2lkdGg9IjgwIiBoZWlnaHQ9IjgwIj48L3JlY3Q+CiAgICAgICAgPC9nPgogICAgICAgIDxwYXRoIGQ9Ik0xNywzOCBDMTguMTAzLDM4IDE5LDM4Ljg5NyAxOSw0MCBDMTksNDEuMTAzIDE4LjEwMyw0MiAxNyw0MiBDMTUuODk3LDQyIDE1LDQxLjEwMyAxNSw0MCBDMTUsMzguODk3IDE1Ljg5NywzOCAxNywzOCBMMTcsMzggWiBNNDEsNjQgQzI5LjMxNCw2NCAxOS4yODksNTUuNDY2IDE3LjE5NCw0My45OCBDMTguOTY1LDQzLjg5NCAyMC40MjcsNDIuNjU5IDIwLjg1Nyw0MSBMMjcsNDEgTDI3LDM5IEwyMC44NTcsMzkgQzIwLjQyNywzNy4zNDIgMTguOTY2LDM2LjEwNyAxNy4xOTUsMzYuMDIgQzE5LjI4NSwyNC43MSAyOS41MTEsMTYgNDEsMTYgQzQ1LjMxMywxNiA0OS44MzIsMTcuNjIyIDU0LjQyOSwyMC44MjEgTDU1LjU3MSwxOS4xNzkgQzUwLjYzMywxNS43NDMgNDUuNzMsMTQgNDEsMTQgQzI4LjI3LDE0IDE2Ljk0OSwyMy44NjUgMTUuMDYzLDM2LjUyMSBDMTMuODM5LDM3LjIwNyAxMywzOC41IDEzLDQwIEMxMyw0MS41IDEzLjgzOSw0Mi43OTMgMTUuMDYzLDQzLjQ3OCBDMTYuOTcsNTYuMzQxIDI4LjA1Niw2NiA0MSw2NiBDNDYuNDA3LDY2IDUxLjk0Miw2NC4xNTcgNTYuNTg1LDYwLjgxMSBMNTUuNDE1LDU5LjE4OSBDNTEuMTEsNjIuMjkyIDQ1Ljk5MSw2NCA0MSw2NCBMNDEsNjQgWiBNMzAuMTAxLDM2LjQ0MiBDMzEuOTU1LDM2Ljg5NSAzNC4yNzUsMzcgMzYsMzcgQzM3LjY0MiwzNyAzOS44MjMsMzYuOTA1IDQxLjYyOSwzNi41MDYgTDM3LjEwNSw0NS41NTMgQzM3LjAzNiw0NS42OTEgMzcsNDUuODQ1IDM3LDQ2IEwzNyw1MC40NTMgQzM2LjE5OSw1MC45NjQgMzQuODMzLDUxLjgxMiAzNCw1MS45ODYgTDM0LDQ2IEMzNCw0NS44NjggMzMuOTc0LDQ1LjczNyAzMy45MjMsNDUuNjE1IEwzMC4xMDEsMzYuNDQyIFogTTM2LDMzIEM0MC4wMjUsMzMgNDIuMTc0LDMzLjYwNCA0Mi44NDEsMzQgQzQyLjE3NCwzNC4zOTYgNDAuMDI1LDM1IDM2LDM1IEMzMS45NzUsMzUgMjkuODI2LDM0LjM5NiAyOS4xNTksMzQgQzI5LjgyNiwzMy42MDQgMzEuOTc1LDMzIDM2LDMzIEwzNiwzMyBaIE0zMyw1NCBMMzQsNTQgQzM0LjA0Myw1NCAzNC4wODYsNTMuOTk3IDM0LjEyOCw1My45OTIgQzM1LjM1Miw1My44MzMgMzYuOTA5LDUyLjg4NyAzOC4yNzIsNTIuMDEzIEwzOC41MzUsNTEuODQ1IEMzOC44MjQsNTEuNjYxIDM5LDUxLjM0MiAzOSw1MSBMMzksNDYuMjM2IEw0NC41NTksMzUuMTIgQzQ0LjgzMywzNC44MDEgNDUsMzQuNDM0IDQ1LDM0IEM0NSwzMS4zOSAzOS4zNjEsMzEgMzYsMzEgQzMyLjYzOSwzMSAyNywzMS4zOSAyNywzNCBDMjcsMzQuMzY2IDI3LjEyLDM0LjY4NCAyNy4zMiwzNC45NjcgTDMyLDQ2LjIgTDMyLDUzIEMzMiw1My41NTIgMzIuNDQ3LDU0IDMzLDU0IEwzMyw1NCBaIE02Miw1MyBDNjMuMTAzLDUzIDY0LDUzLjg5NyA2NCw1NSBDNjQsNTYuMTAzIDYzLjEwMyw1NyA2Miw1NyBDNjAuODk3LDU3IDYwLDU2LjEwMyA2MCw1NSBDNjAsNTMuODk3IDYwLjg5Nyw1MyA2Miw1MyBMNjIsNTMgWiBNNjIsMjMgQzYzLjEwMywyMyA2NCwyMy44OTcgNjQsMjUgQzY0LDI2LjEwMyA2My4xMDMsMjcgNjIsMjcgQzYwLjg5NywyNyA2MCwyNi4xMDMgNjAsMjUgQzYwLDIzLjg5NyA2MC44OTcsMjMgNjIsMjMgTDYyLDIzIFogTTY0LDM4IEM2NS4xMDMsMzggNjYsMzguODk3IDY2LDQwIEM2Niw0MS4xMDMgNjUuMTAzLDQyIDY0LDQyIEM2Mi44OTcsNDIgNjIsNDEuMTAzIDYyLDQwIEM2MiwzOC44OTcgNjIuODk3LDM4IDY0LDM4IEw2NCwzOCBaIE01NCw0MSBMNjAuMTQzLDQxIEM2MC41ODksNDIuNzIgNjIuMTQyLDQ0IDY0LDQ0IEM2Ni4yMDYsNDQgNjgsNDIuMjA2IDY4LDQwIEM2OCwzNy43OTQgNjYuMjA2LDM2IDY0LDM2IEM2Mi4xNDIsMzYgNjAuNTg5LDM3LjI4IDYwLjE0MywzOSBMNTQsMzkgTDU0LDI2IEw1OC4xNDMsMjYgQzU4LjU4OSwyNy43MiA2MC4xNDIsMjkgNjIsMjkgQzY0LjIwNiwyOSA2NiwyNy4yMDYgNjYsMjUgQzY2LDIyLjc5NCA2NC4yMDYsMjEgNjIsMjEgQzYwLjE0MiwyMSA1OC41ODksMjIuMjggNTguMTQzLDI0IEw1MywyNCBDNTIuNDQ3LDI0IDUyLDI0LjQ0OCA1MiwyNSBMNTIsMzkgTDQ1LDM5IEw0NSw0MSBMNTIsNDEgTDUyLDU1IEM1Miw1NS41NTIgNTIuNDQ3LDU2IDUzLDU2IEw1OC4xNDMsNTYgQzU4LjU4OSw1Ny43MiA2MC4xNDIsNTkgNjIsNTkgQzY0LjIwNiw1OSA2Niw1Ny4yMDYgNjYsNTUgQzY2LDUyLjc5NCA2NC4yMDYsNTEgNjIsNTEgQzYwLjE0Miw1MSA1OC41ODksNTIuMjggNTguMTQzLDU0IEw1NCw1NCBMNTQsNDEgWiIgaWQ9IkFXUy1TaW1wbGUtTm90aWZpY2F0aW9uLVNlcnZpY2VfSWNvbl82NF9TcXVpZCIgZmlsbD0iI0ZGRkZGRiI+PC9wYXRoPgogICAgPC9nPgo8L3N2Zz4=",
"layout": [
{
"h": 6,
"i": "4eb87f89-0213-4773-9b06-6aecc6701898",
"moved": false,
"static": false,
"w": 6,
"x": 0,
"y": 0
},
{
"h": 6,
"i": "7a010b4e-ea7c-4a45-a9eb-93af650c45b4",
"moved": false,
"static": false,
"w": 6,
"x": 6,
"y": 0
},
{
"h": 6,
"i": "2299d4e3-6c40-4bf2-a550-c7bb8a7acd38",
"moved": false,
"static": false,
"w": 6,
"x": 0,
"y": 6
},
{
"h": 6,
"i": "16eec8b7-de1a-4039-b180-24c7a6704b6e",
"moved": false,
"static": false,
"w": 6,
"x": 6,
"y": 6
}
],
"panelMap": {},
"tags": [],
"title": "SNS Overview",
"uploadedGrafana": false,
"variables": {
"51f4fa2b-89c7-47c2-9795-f32cffaab985": {
"allSelected": false,
"customValue": "",
"description": "AWS Account ID",
"id": "51f4fa2b-89c7-47c2-9795-f32cffaab985",
"key": "51f4fa2b-89c7-47c2-9795-f32cffaab985",
"modificationUUID": "b7a6b06b-fa1f-4fb8-b70e-6bd9b350f29e",
"multiSelect": false,
"name": "Account",
"order": 0,
"queryValue": "SELECT DISTINCT JSONExtractString(labels, 'cloud_account_id') AS cloud_account_id\nFROM signoz_metrics.distributed_time_series_v4_1day\nWHERE metric_name = 'aws_SNS_PublishSize_count' GROUP BY cloud_account_id",
"showALLOption": false,
"sort": "DISABLED",
"textboxValue": "",
"type": "QUERY"
},
"9faf0f4b-b245-4b3c-83a3-60cfa76dfeb0": {
"allSelected": false,
"customValue": "",
"description": "Account Region",
"id": "9faf0f4b-b245-4b3c-83a3-60cfa76dfeb0",
"key": "9faf0f4b-b245-4b3c-83a3-60cfa76dfeb0",
"modificationUUID": "8428a5de-bfd1-4a69-9601-63e3041cd556",
"multiSelect": false,
"name": "Region",
"order": 1,
"queryValue": "SELECT DISTINCT JSONExtractString(labels, 'cloud_region') AS region\nFROM signoz_metrics.distributed_time_series_v4_1day\nWHERE metric_name = 'aws_SNS_PublishSize_count' AND JSONExtractString(labels, 'cloud_account_id') IN {{.Account}} GROUP BY region",
"showALLOption": false,
"sort": "ASC",
"textboxValue": "",
"type": "QUERY"
},
"bfbdbcbe-a168-4d81-b108-36339e249116": {
"allSelected": true,
"customValue": "",
"description": "SNS Topic Name",
"id": "bfbdbcbe-a168-4d81-b108-36339e249116",
"modificationUUID": "dfed7272-16dc-4eb6-99bf-7c82fc8e04f0",
"multiSelect": true,
"name": "Topic",
"order": 2,
"queryValue": "SELECT DISTINCT JSONExtractString(labels, 'TopicName') AS topic\nFROM signoz_metrics.distributed_time_series_v4_1day\nWHERE metric_name = 'aws_SNS_PublishSize_count' AND JSONExtractString(labels, 'cloud_account_id') IN {{.Account}} AND JSONExtractString(labels, 'cloud_region') IN {{.Region}}\nGROUP BY topic",
"showALLOption": true,
"sort": "ASC",
"textboxValue": "",
"type": "QUERY"
}
},
"version": "v4",
"widgets": [
{
"bucketCount": 30,
"bucketWidth": 0,
"columnUnits": {},
"description": "",
"fillSpans": false,
"id": "4eb87f89-0213-4773-9b06-6aecc6701898",
"isLogScale": false,
"isStacked": false,
"mergeAllActiveQueries": false,
"nullZeroValues": "zero",
"opacity": "1",
"panelTypes": "graph",
"query": {
"builder": {
"queryData": [
{
"aggregateAttribute": {
"dataType": "float64",
"id": "aws_SNS_NumberOfMessagesPublished_max--float64--Gauge--true",
"isColumn": true,
"isJSON": false,
"key": "aws_SNS_NumberOfMessagesPublished_max",
"type": "Gauge"
},
"aggregateOperator": "max",
"dataSource": "metrics",
"disabled": false,
"expression": "A",
"filters": {
"items": [
{
"id": "8fd51b53",
"key": {
"dataType": "string",
"id": "TopicName--string--tag--false",
"isColumn": false,
"isJSON": false,
"key": "TopicName",
"type": "tag"
},
"op": "in",
"value": [
"$Topic"
]
},
{
"id": "b18187c3",
"key": {
"dataType": "string",
"id": "cloud_region--string--tag--false",
"isColumn": false,
"isJSON": false,
"key": "cloud_region",
"type": "tag"
},
"op": "=",
"value": "$Region"
},
{
"id": "eebe4578",
"key": {
"dataType": "string",
"id": "cloud_account_id--string--tag--false",
"isColumn": false,
"isJSON": false,
"key": "cloud_account_id",
"type": "tag"
},
"op": "=",
"value": "$Account"
}
],
"op": "AND"
},
"functions": [],
"groupBy": [
{
"dataType": "string",
"id": "TopicName--string--tag--false",
"isColumn": false,
"isJSON": false,
"key": "TopicName",
"type": "tag"
}
],
"having": [],
"legend": "{{TopicName}}",
"limit": null,
"orderBy": [],
"queryName": "A",
"reduceTo": "avg",
"spaceAggregation": "max",
"stepInterval": 60,
"timeAggregation": "max"
}
],
"queryFormulas": []
},
"clickhouse_sql": [
{
"disabled": false,
"legend": "",
"name": "A",
"query": ""
}
],
"id": "9c67615a-55f7-42da-835c-86922f2ff8bb",
"promql": [
{
"disabled": false,
"legend": "",
"name": "A",
"query": ""
}
],
"queryType": "builder"
},
"selectedLogFields": [
{
"dataType": "string",
"name": "body",
"type": ""
},
{
"dataType": "string",
"name": "timestamp",
"type": ""
}
],
"selectedTracesFields": [
{
"dataType": "string",
"id": "serviceName--string--tag--true",
"isColumn": true,
"isJSON": false,
"key": "serviceName",
"type": "tag"
},
{
"dataType": "string",
"id": "name--string--tag--true",
"isColumn": true,
"isJSON": false,
"key": "name",
"type": "tag"
},
{
"dataType": "float64",
"id": "durationNano--float64--tag--true",
"isColumn": true,
"isJSON": false,
"key": "durationNano",
"type": "tag"
},
{
"dataType": "string",
"id": "httpMethod--string--tag--true",
"isColumn": true,
"isJSON": false,
"key": "httpMethod",
"type": "tag"
},
{
"dataType": "string",
"id": "responseStatusCode--string--tag--true",
"isColumn": true,
"isJSON": false,
"key": "responseStatusCode",
"type": "tag"
}
],
"softMax": 0,
"softMin": 0,
"stackedBarChart": false,
"thresholds": [],
"timePreferance": "GLOBAL_TIME",
"title": "Number of Messages Published",
"yAxisUnit": "none"
},
{
"bucketCount": 30,
"bucketWidth": 0,
"columnUnits": {},
"description": "",
"fillSpans": false,
"id": "7a010b4e-ea7c-4a45-a9eb-93af650c45b4",
"isLogScale": false,
"isStacked": false,
"mergeAllActiveQueries": false,
"nullZeroValues": "zero",
"opacity": "1",
"panelTypes": "graph",
"query": {
"builder": {
"queryData": [
{
"aggregateAttribute": {
"dataType": "float64",
"id": "aws_SNS_PublishSize_max--float64--Gauge--true",
"isColumn": true,
"isJSON": false,
"key": "aws_SNS_PublishSize_max",
"type": "Gauge"
},
"aggregateOperator": "max",
"dataSource": "metrics",
"disabled": false,
"expression": "A",
"filters": {
"items": [
{
"id": "1aa0d1a9",
"key": {
"dataType": "string",
"id": "TopicName--string--tag--false",
"isColumn": false,
"isJSON": false,
"key": "TopicName",
"type": "tag"
},
"op": "in",
"value": [
"$Topic"
]
},
{
"id": "62255cff",
"key": {
"dataType": "string",
"id": "cloud_region--string--tag--false",
"isColumn": false,
"isJSON": false,
"key": "cloud_region",
"type": "tag"
},
"op": "=",
"value": "$Region"
},
{
"id": "17c7153e",
"key": {
"dataType": "string",
"id": "cloud_account_id--string--tag--false",
"isColumn": false,
"isJSON": false,
"key": "cloud_account_id",
"type": "tag"
},
"op": "=",
"value": "$Account"
}
],
"op": "AND"
},
"functions": [],
"groupBy": [
{
"dataType": "string",
"id": "TopicName--string--tag--false",
"isColumn": false,
"isJSON": false,
"key": "TopicName",
"type": "tag"
}
],
"having": [],
"legend": "{{TopicName}}",
"limit": null,
"orderBy": [],
"queryName": "A",
"reduceTo": "avg",
"spaceAggregation": "max",
"stepInterval": 60,
"timeAggregation": "max"
}
],
"queryFormulas": []
},
"clickhouse_sql": [
{
"disabled": false,
"legend": "",
"name": "A",
"query": ""
}
],
"id": "a635a15b-dfe6-4617-a82e-29d93e27deaf",
"promql": [
{
"disabled": false,
"legend": "",
"name": "A",
"query": ""
}
],
"queryType": "builder"
},
"selectedLogFields": [
{
"dataType": "string",
"name": "body",
"type": ""
},
{
"dataType": "string",
"name": "timestamp",
"type": ""
}
],
"selectedTracesFields": [
{
"dataType": "string",
"id": "serviceName--string--tag--true",
"isColumn": true,
"isJSON": false,
"key": "serviceName",
"type": "tag"
},
{
"dataType": "string",
"id": "name--string--tag--true",
"isColumn": true,
"isJSON": false,
"key": "name",
"type": "tag"
},
{
"dataType": "float64",
"id": "durationNano--float64--tag--true",
"isColumn": true,
"isJSON": false,
"key": "durationNano",
"type": "tag"
},
{
"dataType": "string",
"id": "httpMethod--string--tag--true",
"isColumn": true,
"isJSON": false,
"key": "httpMethod",
"type": "tag"
},
{
"dataType": "string",
"id": "responseStatusCode--string--tag--true",
"isColumn": true,
"isJSON": false,
"key": "responseStatusCode",
"type": "tag"
}
],
"softMax": 0,
"softMin": 0,
"stackedBarChart": false,
"thresholds": [],
"timePreferance": "GLOBAL_TIME",
"title": "Published Message Size",
"yAxisUnit": "decbytes"
},
{
"bucketCount": 30,
"bucketWidth": 0,
"columnUnits": {},
"description": "",
"fillSpans": false,
"id": "2299d4e3-6c40-4bf2-a550-c7bb8a7acd38",
"isLogScale": false,
"isStacked": false,
"mergeAllActiveQueries": false,
"nullZeroValues": "zero",
"opacity": "1",
"panelTypes": "graph",
"query": {
"builder": {
"queryData": [
{
"aggregateAttribute": {
"dataType": "float64",
"id": "aws_SNS_NumberOfNotificationsDelivered_max--float64--Gauge--true",
"isColumn": true,
"isJSON": false,
"key": "aws_SNS_NumberOfNotificationsDelivered_max",
"type": "Gauge"
},
"aggregateOperator": "max",
"dataSource": "metrics",
"disabled": false,
"expression": "A",
"filters": {
"items": [
{
"id": "c96a4ac0",
"key": {
"dataType": "string",
"id": "TopicName--string--tag--false",
"isColumn": false,
"isJSON": false,
"key": "TopicName",
"type": "tag"
},
"op": "in",
"value": [
"$Topic"
]
},
{
"id": "8ca86829",
"key": {
"dataType": "string",
"id": "cloud_region--string--tag--false",
"isColumn": false,
"isJSON": false,
"key": "cloud_region",
"type": "tag"
},
"op": "=",
"value": "$Region"
},
{
"id": "8a444f66",
"key": {
"dataType": "string",
"id": "cloud_account_id--string--tag--false",
"isColumn": false,
"isJSON": false,
"key": "cloud_account_id",
"type": "tag"
},
"op": "=",
"value": "$Account"
}
],
"op": "AND"
},
"functions": [],
"groupBy": [
{
"dataType": "string",
"id": "TopicName--string--tag--false",
"isColumn": false,
"isJSON": false,
"key": "TopicName",
"type": "tag"
}
],
"having": [],
"legend": "{{TopicName}}",
"limit": null,
"orderBy": [],
"queryName": "A",
"reduceTo": "avg",
"spaceAggregation": "max",
"stepInterval": 60,
"timeAggregation": "max"
}
],
"queryFormulas": []
},
"clickhouse_sql": [
{
"disabled": false,
"legend": "",
"name": "A",
"query": ""
}
],
"id": "0d2fc26c-9b21-4dfc-b631-64b7c8d3bd71",
"promql": [
{
"disabled": false,
"legend": "",
"name": "A",
"query": ""
}
],
"queryType": "builder"
},
"selectedLogFields": [
{
"dataType": "string",
"name": "body",
"type": ""
},
{
"dataType": "string",
"name": "timestamp",
"type": ""
}
],
"selectedTracesFields": [
{
"dataType": "string",
"id": "serviceName--string--tag--true",
"isColumn": true,
"isJSON": false,
"key": "serviceName",
"type": "tag"
},
{
"dataType": "string",
"id": "name--string--tag--true",
"isColumn": true,
"isJSON": false,
"key": "name",
"type": "tag"
},
{
"dataType": "float64",
"id": "durationNano--float64--tag--true",
"isColumn": true,
"isJSON": false,
"key": "durationNano",
"type": "tag"
},
{
"dataType": "string",
"id": "httpMethod--string--tag--true",
"isColumn": true,
"isJSON": false,
"key": "httpMethod",
"type": "tag"
},
{
"dataType": "string",
"id": "responseStatusCode--string--tag--true",
"isColumn": true,
"isJSON": false,
"key": "responseStatusCode",
"type": "tag"
}
],
"softMax": 0,
"softMin": 0,
"stackedBarChart": false,
"thresholds": [],
"timePreferance": "GLOBAL_TIME",
"title": "Number of Notifications Delivered",
"yAxisUnit": "none"
},
{
"bucketCount": 30,
"bucketWidth": 0,
"columnUnits": {},
"description": "",
"fillSpans": false,
"id": "16eec8b7-de1a-4039-b180-24c7a6704b6e",
"isLogScale": false,
"isStacked": false,
"mergeAllActiveQueries": false,
"nullZeroValues": "zero",
"opacity": "1",
"panelTypes": "graph",
"query": {
"builder": {
"queryData": [
{
"aggregateAttribute": {
"dataType": "float64",
"id": "aws_SNS_NumberOfNotificationsFailed_max--float64--Gauge--true",
"isColumn": true,
"isJSON": false,
"key": "aws_SNS_NumberOfNotificationsFailed_max",
"type": "Gauge"
},
"aggregateOperator": "max",
"dataSource": "metrics",
"disabled": false,
"expression": "A",
"filters": {
"items": [
{
"id": "6175f3d5",
"key": {
"dataType": "string",
"id": "TopicName--string--tag--false",
"isColumn": false,
"isJSON": false,
"key": "TopicName",
"type": "tag"
},
"op": "in",
"value": [
"$Topic"
]
},
{
"id": "e2084931",
"key": {
"dataType": "string",
"id": "cloud_region--string--tag--false",
"isColumn": false,
"isJSON": false,
"key": "cloud_region",
"type": "tag"
},
"op": "=",
"value": "$Region"
},
{
"id": "0b05209a",
"key": {
"dataType": "string",
"id": "cloud_account_id--string--tag--false",
"isColumn": false,
"isJSON": false,
"key": "cloud_account_id",
"type": "tag"
},
"op": "=",
"value": "$Account"
}
],
"op": "AND"
},
"functions": [],
"groupBy": [
{
"dataType": "string",
"id": "TopicName--string--tag--false",
"isColumn": false,
"isJSON": false,
"key": "TopicName",
"type": "tag"
}
],
"having": [],
"legend": "{{TopicName}}",
"limit": null,
"orderBy": [],
"queryName": "A",
"reduceTo": "avg",
"spaceAggregation": "max",
"stepInterval": 60,
"timeAggregation": "max"
}
],
"queryFormulas": []
},
"clickhouse_sql": [
{
"disabled": false,
"legend": "",
"name": "A",
"query": ""
}
],
"id": "526247af-6ac9-42ff-83e9-cce0e32a9e63",
"promql": [
{
"disabled": false,
"legend": "",
"name": "A",
"query": ""
}
],
"queryType": "builder"
},
"selectedLogFields": [
{
"dataType": "string",
"name": "body",
"type": ""
},
{
"dataType": "string",
"name": "timestamp",
"type": ""
}
],
"selectedTracesFields": [
{
"dataType": "string",
"id": "serviceName--string--tag--true",
"isColumn": true,
"isJSON": false,
"key": "serviceName",
"type": "tag"
},
{
"dataType": "string",
"id": "name--string--tag--true",
"isColumn": true,
"isJSON": false,
"key": "name",
"type": "tag"
},
{
"dataType": "float64",
"id": "durationNano--float64--tag--true",
"isColumn": true,
"isJSON": false,
"key": "durationNano",
"type": "tag"
},
{
"dataType": "string",
"id": "httpMethod--string--tag--true",
"isColumn": true,
"isJSON": false,
"key": "httpMethod",
"type": "tag"
},
{
"dataType": "string",
"id": "responseStatusCode--string--tag--true",
"isColumn": true,
"isJSON": false,
"key": "responseStatusCode",
"type": "tag"
}
],
"softMax": 0,
"softMin": 0,
"stackedBarChart": false,
"thresholds": [],
"timePreferance": "GLOBAL_TIME",
"title": "Number of Notifications Failed",
"yAxisUnit": "none"
}
]
}

View File

@@ -0,0 +1,818 @@
{
"description": "View key AWS SNS metrics with an out of the box dashboard.",
"image": "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHN2ZyB3aWR0aD0iODBweCIgaGVpZ2h0PSI4MHB4IiB2aWV3Qm94PSIwIDAgODAgODAiIHZlcnNpb249IjEuMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayI+CiAgICA8IS0tIEdlbmVyYXRvcjogU2tldGNoIDY0ICg5MzUzNykgLSBodHRwczovL3NrZXRjaC5jb20gLS0+CiAgICA8dGl0bGU+SWNvbi1BcmNoaXRlY3R1cmUvNjQvQXJjaF9BV1MtU2ltcGxlLU5vdGlmaWNhdGlvbi1TZXJ2aWNlXzY0PC90aXRsZT4KICAgIDxkZXNjPkNyZWF0ZWQgd2l0aCBTa2V0Y2guPC9kZXNjPgogICAgPGRlZnM+CiAgICAgICAgPGxpbmVhckdyYWRpZW50IHgxPSIwJSIgeTE9IjEwMCUiIHgyPSIxMDAlIiB5Mj0iMCUiIGlkPSJsaW5lYXJHcmFkaWVudC0xIj4KICAgICAgICAgICAgPHN0b3Agc3RvcC1jb2xvcj0iI0IwMDg0RCIgb2Zmc2V0PSIwJSI+PC9zdG9wPgogICAgICAgICAgICA8c3RvcCBzdG9wLWNvbG9yPSIjRkY0RjhCIiBvZmZzZXQ9IjEwMCUiPjwvc3RvcD4KICAgICAgICA8L2xpbmVhckdyYWRpZW50PgogICAgPC9kZWZzPgogICAgPGcgaWQ9Ikljb24tQXJjaGl0ZWN0dXJlLzY0L0FyY2hfQVdTLVNpbXBsZS1Ob3RpZmljYXRpb24tU2VydmljZV82NCIgc3Ryb2tlPSJub25lIiBzdHJva2Utd2lkdGg9IjEiIGZpbGw9Im5vbmUiIGZpbGwtcnVsZT0iZXZlbm9kZCI+CiAgICAgICAgPGcgaWQ9Ikljb24tQXJjaGl0ZWN0dXJlLUJHLzY0L0FwcGxpY2F0aW9uLUludGVncmF0aW9uIiBmaWxsPSJ1cmwoI2xpbmVhckdyYWRpZW50LTEpIj4KICAgICAgICAgICAgPHJlY3QgaWQ9IlJlY3RhbmdsZSIgeD0iMCIgeT0iMCIgd2lkdGg9IjgwIiBoZWlnaHQ9IjgwIj48L3JlY3Q+CiAgICAgICAgPC9nPgogICAgICAgIDxwYXRoIGQ9Ik0xNywzOCBDMTguMTAzLDM4IDE5LDM4Ljg5NyAxOSw0MCBDMTksNDEuMTAzIDE4LjEwMyw0MiAxNyw0MiBDMTUuODk3LDQyIDE1LDQxLjEwMyAxNSw0MCBDMTUsMzguODk3IDE1Ljg5NywzOCAxNywzOCBMMTcsMzggWiBNNDEsNjQgQzI5LjMxNCw2NCAxOS4yODksNTUuNDY2IDE3LjE5NCw0My45OCBDMTguOTY1LDQzLjg5NCAyMC40MjcsNDIuNjU5IDIwLjg1Nyw0MSBMMjcsNDEgTDI3LDM5IEwyMC44NTcsMzkgQzIwLjQyNywzNy4zNDIgMTguOTY2LDM2LjEwNyAxNy4xOTUsMzYuMDIgQzE5LjI4NSwyNC43MSAyOS41MTEsMTYgNDEsMTYgQzQ1LjMxMywxNiA0OS44MzIsMTcuNjIyIDU0LjQyOSwyMC44MjEgTDU1LjU3MSwxOS4xNzkgQzUwLjYzMywxNS43NDMgNDUuNzMsMTQgNDEsMTQgQzI4LjI3LDE0IDE2Ljk0OSwyMy44NjUgMTUuMDYzLDM2LjUyMSBDMTMuODM5LDM3LjIwNyAxMywzOC41IDEzLDQwIEMxMyw0MS41IDEzLjgzOSw0Mi43OTMgMTUuMDYzLDQzLjQ3OCBDMTYuOTcsNTYuMzQxIDI4LjA1Niw2NiA0MSw2NiBDNDYuNDA3LDY2IDUxLjk0Miw2NC4xNTcgNTYuNTg1LDYwLjgxMSBMNTUuNDE1LDU5LjE4OSBDNTEuMTEsNjIuMjkyIDQ1Ljk5MSw2NCA0MSw2NCBMNDEsNjQgWiBNMzAuMTAxLDM2LjQ0MiBDMzEuOTU1LDM2Ljg5NSAzNC4yNzUsMzcgMzYsMzcgQzM3LjY0MiwzNyAzOS44MjMsMzYuOTA1IDQxLjYyOSwzNi41MDYgTDM3LjEwNSw0NS41NTMgQzM3LjAzNiw0NS42OTEgMzcsNDUuODQ1IDM3LDQ2IEwzNyw1MC40NTMgQzM2LjE5OSw1MC45NjQgMzQuODMzLDUxLjgxMiAzNCw1MS45ODYgTDM0LDQ2IEMzNCw0NS44NjggMzMuOTc0LDQ1LjczNyAzMy45MjMsNDUuNjE1IEwzMC4xMDEsMzYuNDQyIFogTTM2LDMzIEM0MC4wMjUsMzMgNDIuMTc0LDMzLjYwNCA0Mi44NDEsMzQgQzQyLjE3NCwzNC4zOTYgNDAuMDI1LDM1IDM2LDM1IEMzMS45NzUsMzUgMjkuODI2LDM0LjM5NiAyOS4xNTksMzQgQzI5LjgyNiwzMy42MDQgMzEuOTc1LDMzIDM2LDMzIEwzNiwzMyBaIE0zMyw1NCBMMzQsNTQgQzM0LjA0Myw1NCAzNC4wODYsNTMuOTk3IDM0LjEyOCw1My45OTIgQzM1LjM1Miw1My44MzMgMzYuOTA5LDUyLjg4NyAzOC4yNzIsNTIuMDEzIEwzOC41MzUsNTEuODQ1IEMzOC44MjQsNTEuNjYxIDM5LDUxLjM0MiAzOSw1MSBMMzksNDYuMjM2IEw0NC41NTksMzUuMTIgQzQ0LjgzMywzNC44MDEgNDUsMzQuNDM0IDQ1LDM0IEM0NSwzMS4zOSAzOS4zNjEsMzEgMzYsMzEgQzMyLjYzOSwzMSAyNywzMS4zOSAyNywzNCBDMjcsMzQuMzY2IDI3LjEyLDM0LjY4NCAyNy4zMiwzNC45NjcgTDMyLDQ2LjIgTDMyLDUzIEMzMiw1My41NTIgMzIuNDQ3LDU0IDMzLDU0IEwzMyw1NCBaIE02Miw1MyBDNjMuMTAzLDUzIDY0LDUzLjg5NyA2NCw1NSBDNjQsNTYuMTAzIDYzLjEwMyw1NyA2Miw1NyBDNjAuODk3LDU3IDYwLDU2LjEwMyA2MCw1NSBDNjAsNTMuODk3IDYwLjg5Nyw1MyA2Miw1MyBMNjIsNTMgWiBNNjIsMjMgQzYzLjEwMywyMyA2NCwyMy44OTcgNjQsMjUgQzY0LDI2LjEwMyA2My4xMDMsMjcgNjIsMjcgQzYwLjg5NywyNyA2MCwyNi4xMDMgNjAsMjUgQzYwLDIzLjg5NyA2MC44OTcsMjMgNjIsMjMgTDYyLDIzIFogTTY0LDM4IEM2NS4xMDMsMzggNjYsMzguODk3IDY2LDQwIEM2Niw0MS4xMDMgNjUuMTAzLDQyIDY0LDQyIEM2Mi44OTcsNDIgNjIsNDEuMTAzIDYyLDQwIEM2MiwzOC44OTcgNjIuODk3LDM4IDY0LDM4IEw2NCwzOCBaIE01NCw0MSBMNjAuMTQzLDQxIEM2MC41ODksNDIuNzIgNjIuMTQyLDQ0IDY0LDQ0IEM2Ni4yMDYsNDQgNjgsNDIuMjA2IDY4LDQwIEM2OCwzNy43OTQgNjYuMjA2LDM2IDY0LDM2IEM2Mi4xNDIsMzYgNjAuNTg5LDM3LjI4IDYwLjE0MywzOSBMNTQsMzkgTDU0LDI2IEw1OC4xNDMsMjYgQzU4LjU4OSwyNy43MiA2MC4xNDIsMjkgNjIsMjkgQzY0LjIwNiwyOSA2NiwyNy4yMDYgNjYsMjUgQzY2LDIyLjc5NCA2NC4yMDYsMjEgNjIsMjEgQzYwLjE0MiwyMSA1OC41ODksMjIuMjggNTguMTQzLDI0IEw1MywyNCBDNTIuNDQ3LDI0IDUyLDI0LjQ0OCA1MiwyNSBMNTIsMzkgTDQ1LDM5IEw0NSw0MSBMNTIsNDEgTDUyLDU1IEM1Miw1NS41NTIgNTIuNDQ3LDU2IDUzLDU2IEw1OC4xNDMsNTYgQzU4LjU4OSw1Ny43MiA2MC4xNDIsNTkgNjIsNTkgQzY0LjIwNiw1OSA2Niw1Ny4yMDYgNjYsNTUgQzY2LDUyLjc5NCA2NC4yMDYsNTEgNjIsNTEgQzYwLjE0Miw1MSA1OC41ODksNTIuMjggNTguMTQzLDU0IEw1NCw1NCBMNTQsNDEgWiIgaWQ9IkFXUy1TaW1wbGUtTm90aWZpY2F0aW9uLVNlcnZpY2VfSWNvbl82NF9TcXVpZCIgZmlsbD0iI0ZGRkZGRiI+PC9wYXRoPgogICAgPC9nPgo8L3N2Zz4=",
"layout": [
{
"h": 6,
"i": "4eb87f89-0213-4773-9b06-6aecc6701898",
"moved": false,
"static": false,
"w": 6,
"x": 0,
"y": 0
},
{
"h": 6,
"i": "7a010b4e-ea7c-4a45-a9eb-93af650c45b4",
"moved": false,
"static": false,
"w": 6,
"x": 6,
"y": 0
},
{
"h": 6,
"i": "2299d4e3-6c40-4bf2-a550-c7bb8a7acd38",
"moved": false,
"static": false,
"w": 6,
"x": 0,
"y": 6
},
{
"h": 6,
"i": "16eec8b7-de1a-4039-b180-24c7a6704b6e",
"moved": false,
"static": false,
"w": 6,
"x": 6,
"y": 6
}
],
"panelMap": {},
"tags": [],
"title": "SNS Overview",
"uploadedGrafana": false,
"variables": {
"51f4fa2b-89c7-47c2-9795-f32cffaab985": {
"allSelected": false,
"customValue": "",
"description": "AWS Account ID",
"id": "51f4fa2b-89c7-47c2-9795-f32cffaab985",
"key": "51f4fa2b-89c7-47c2-9795-f32cffaab985",
"modificationUUID": "b7a6b06b-fa1f-4fb8-b70e-6bd9b350f29e",
"multiSelect": false,
"name": "Account",
"order": 0,
"queryValue": "SELECT DISTINCT JSONExtractString(labels, 'cloud.account.id') AS `cloud.account.id`\nFROM signoz_metrics.distributed_time_series_v4_1day\nWHERE metric_name = 'aws_SNS_PublishSize_count' GROUP BY `cloud.account.id`",
"showALLOption": false,
"sort": "DISABLED",
"textboxValue": "",
"type": "QUERY"
},
"9faf0f4b-b245-4b3c-83a3-60cfa76dfeb0": {
"allSelected": false,
"customValue": "",
"description": "Account Region",
"id": "9faf0f4b-b245-4b3c-83a3-60cfa76dfeb0",
"key": "9faf0f4b-b245-4b3c-83a3-60cfa76dfeb0",
"modificationUUID": "8428a5de-bfd1-4a69-9601-63e3041cd556",
"multiSelect": false,
"name": "Region",
"order": 1,
"queryValue": "SELECT DISTINCT JSONExtractString(labels, 'cloud.region') AS region\nFROM signoz_metrics.distributed_time_series_v4_1day\nWHERE metric_name = 'aws_SNS_PublishSize_count' AND JSONExtractString(labels, 'cloud.account.id') IN {{.Account}} GROUP BY region",
"showALLOption": false,
"sort": "ASC",
"textboxValue": "",
"type": "QUERY"
},
"bfbdbcbe-a168-4d81-b108-36339e249116": {
"allSelected": true,
"customValue": "",
"description": "SNS Topic Name",
"id": "bfbdbcbe-a168-4d81-b108-36339e249116",
"modificationUUID": "dfed7272-16dc-4eb6-99bf-7c82fc8e04f0",
"multiSelect": true,
"name": "Topic",
"order": 2,
"queryValue": "SELECT DISTINCT JSONExtractString(labels, 'TopicName') AS topic\nFROM signoz_metrics.distributed_time_series_v4_1day\nWHERE metric_name = 'aws_SNS_PublishSize_count' AND JSONExtractString(labels, 'cloud.account.id') IN {{.Account}} AND JSONExtractString(labels, 'cloud.region') IN {{.Region}}\nGROUP BY topic",
"showALLOption": true,
"sort": "ASC",
"textboxValue": "",
"type": "QUERY"
}
},
"version": "v4",
"widgets": [
{
"bucketCount": 30,
"bucketWidth": 0,
"columnUnits": {},
"description": "",
"fillSpans": false,
"id": "4eb87f89-0213-4773-9b06-6aecc6701898",
"isLogScale": false,
"isStacked": false,
"mergeAllActiveQueries": false,
"nullZeroValues": "zero",
"opacity": "1",
"panelTypes": "graph",
"query": {
"builder": {
"queryData": [
{
"aggregateAttribute": {
"dataType": "float64",
"id": "aws_SNS_NumberOfMessagesPublished_max--float64--Gauge--true",
"isColumn": true,
"isJSON": false,
"key": "aws_SNS_NumberOfMessagesPublished_max",
"type": "Gauge"
},
"aggregateOperator": "max",
"dataSource": "metrics",
"disabled": false,
"expression": "A",
"filters": {
"items": [
{
"id": "8fd51b53",
"key": {
"dataType": "string",
"id": "TopicName--string--tag--false",
"isColumn": false,
"isJSON": false,
"key": "TopicName",
"type": "tag"
},
"op": "in",
"value": [
"$Topic"
]
},
{
"id": "b18187c3",
"key": {
"dataType": "string",
"id": "cloud.region--string--tag--false",
"isColumn": false,
"isJSON": false,
"key": "cloud.region",
"type": "tag"
},
"op": "=",
"value": "$Region"
},
{
"id": "eebe4578",
"key": {
"dataType": "string",
"id": "cloud.account.id--string--tag--false",
"isColumn": false,
"isJSON": false,
"key": "cloud.account.id",
"type": "tag"
},
"op": "=",
"value": "$Account"
}
],
"op": "AND"
},
"functions": [],
"groupBy": [
{
"dataType": "string",
"id": "TopicName--string--tag--false",
"isColumn": false,
"isJSON": false,
"key": "TopicName",
"type": "tag"
}
],
"having": [],
"legend": "{{TopicName}}",
"limit": null,
"orderBy": [],
"queryName": "A",
"reduceTo": "avg",
"spaceAggregation": "max",
"stepInterval": 60,
"timeAggregation": "max"
}
],
"queryFormulas": []
},
"clickhouse_sql": [
{
"disabled": false,
"legend": "",
"name": "A",
"query": ""
}
],
"id": "9c67615a-55f7-42da-835c-86922f2ff8bb",
"promql": [
{
"disabled": false,
"legend": "",
"name": "A",
"query": ""
}
],
"queryType": "builder"
},
"selectedLogFields": [
{
"dataType": "string",
"name": "body",
"type": ""
},
{
"dataType": "string",
"name": "timestamp",
"type": ""
}
],
"selectedTracesFields": [
{
"dataType": "string",
"id": "serviceName--string--tag--true",
"isColumn": true,
"isJSON": false,
"key": "serviceName",
"type": "tag"
},
{
"dataType": "string",
"id": "name--string--tag--true",
"isColumn": true,
"isJSON": false,
"key": "name",
"type": "tag"
},
{
"dataType": "float64",
"id": "durationNano--float64--tag--true",
"isColumn": true,
"isJSON": false,
"key": "durationNano",
"type": "tag"
},
{
"dataType": "string",
"id": "httpMethod--string--tag--true",
"isColumn": true,
"isJSON": false,
"key": "httpMethod",
"type": "tag"
},
{
"dataType": "string",
"id": "responseStatusCode--string--tag--true",
"isColumn": true,
"isJSON": false,
"key": "responseStatusCode",
"type": "tag"
}
],
"softMax": 0,
"softMin": 0,
"stackedBarChart": false,
"thresholds": [],
"timePreferance": "GLOBAL_TIME",
"title": "Number of Messages Published",
"yAxisUnit": "none"
},
{
"bucketCount": 30,
"bucketWidth": 0,
"columnUnits": {},
"description": "",
"fillSpans": false,
"id": "7a010b4e-ea7c-4a45-a9eb-93af650c45b4",
"isLogScale": false,
"isStacked": false,
"mergeAllActiveQueries": false,
"nullZeroValues": "zero",
"opacity": "1",
"panelTypes": "graph",
"query": {
"builder": {
"queryData": [
{
"aggregateAttribute": {
"dataType": "float64",
"id": "aws_SNS_PublishSize_max--float64--Gauge--true",
"isColumn": true,
"isJSON": false,
"key": "aws_SNS_PublishSize_max",
"type": "Gauge"
},
"aggregateOperator": "max",
"dataSource": "metrics",
"disabled": false,
"expression": "A",
"filters": {
"items": [
{
"id": "1aa0d1a9",
"key": {
"dataType": "string",
"id": "TopicName--string--tag--false",
"isColumn": false,
"isJSON": false,
"key": "TopicName",
"type": "tag"
},
"op": "in",
"value": [
"$Topic"
]
},
{
"id": "62255cff",
"key": {
"dataType": "string",
"id": "cloud.region--string--tag--false",
"isColumn": false,
"isJSON": false,
"key": "cloud.region",
"type": "tag"
},
"op": "=",
"value": "$Region"
},
{
"id": "17c7153e",
"key": {
"dataType": "string",
"id": "cloud.account.id--string--tag--false",
"isColumn": false,
"isJSON": false,
"key": "cloud.account.id",
"type": "tag"
},
"op": "=",
"value": "$Account"
}
],
"op": "AND"
},
"functions": [],
"groupBy": [
{
"dataType": "string",
"id": "TopicName--string--tag--false",
"isColumn": false,
"isJSON": false,
"key": "TopicName",
"type": "tag"
}
],
"having": [],
"legend": "{{TopicName}}",
"limit": null,
"orderBy": [],
"queryName": "A",
"reduceTo": "avg",
"spaceAggregation": "max",
"stepInterval": 60,
"timeAggregation": "max"
}
],
"queryFormulas": []
},
"clickhouse_sql": [
{
"disabled": false,
"legend": "",
"name": "A",
"query": ""
}
],
"id": "a635a15b-dfe6-4617-a82e-29d93e27deaf",
"promql": [
{
"disabled": false,
"legend": "",
"name": "A",
"query": ""
}
],
"queryType": "builder"
},
"selectedLogFields": [
{
"dataType": "string",
"name": "body",
"type": ""
},
{
"dataType": "string",
"name": "timestamp",
"type": ""
}
],
"selectedTracesFields": [
{
"dataType": "string",
"id": "serviceName--string--tag--true",
"isColumn": true,
"isJSON": false,
"key": "serviceName",
"type": "tag"
},
{
"dataType": "string",
"id": "name--string--tag--true",
"isColumn": true,
"isJSON": false,
"key": "name",
"type": "tag"
},
{
"dataType": "float64",
"id": "durationNano--float64--tag--true",
"isColumn": true,
"isJSON": false,
"key": "durationNano",
"type": "tag"
},
{
"dataType": "string",
"id": "httpMethod--string--tag--true",
"isColumn": true,
"isJSON": false,
"key": "httpMethod",
"type": "tag"
},
{
"dataType": "string",
"id": "responseStatusCode--string--tag--true",
"isColumn": true,
"isJSON": false,
"key": "responseStatusCode",
"type": "tag"
}
],
"softMax": 0,
"softMin": 0,
"stackedBarChart": false,
"thresholds": [],
"timePreferance": "GLOBAL_TIME",
"title": "Published Message Size",
"yAxisUnit": "decbytes"
},
{
"bucketCount": 30,
"bucketWidth": 0,
"columnUnits": {},
"description": "",
"fillSpans": false,
"id": "2299d4e3-6c40-4bf2-a550-c7bb8a7acd38",
"isLogScale": false,
"isStacked": false,
"mergeAllActiveQueries": false,
"nullZeroValues": "zero",
"opacity": "1",
"panelTypes": "graph",
"query": {
"builder": {
"queryData": [
{
"aggregateAttribute": {
"dataType": "float64",
"id": "aws_SNS_NumberOfNotificationsDelivered_max--float64--Gauge--true",
"isColumn": true,
"isJSON": false,
"key": "aws_SNS_NumberOfNotificationsDelivered_max",
"type": "Gauge"
},
"aggregateOperator": "max",
"dataSource": "metrics",
"disabled": false,
"expression": "A",
"filters": {
"items": [
{
"id": "c96a4ac0",
"key": {
"dataType": "string",
"id": "TopicName--string--tag--false",
"isColumn": false,
"isJSON": false,
"key": "TopicName",
"type": "tag"
},
"op": "in",
"value": [
"$Topic"
]
},
{
"id": "8ca86829",
"key": {
"dataType": "string",
"id": "cloud.region--string--tag--false",
"isColumn": false,
"isJSON": false,
"key": "cloud.region",
"type": "tag"
},
"op": "=",
"value": "$Region"
},
{
"id": "8a444f66",
"key": {
"dataType": "string",
"id": "cloud.account.id--string--tag--false",
"isColumn": false,
"isJSON": false,
"key": "cloud.account.id",
"type": "tag"
},
"op": "=",
"value": "$Account"
}
],
"op": "AND"
},
"functions": [],
"groupBy": [
{
"dataType": "string",
"id": "TopicName--string--tag--false",
"isColumn": false,
"isJSON": false,
"key": "TopicName",
"type": "tag"
}
],
"having": [],
"legend": "{{TopicName}}",
"limit": null,
"orderBy": [],
"queryName": "A",
"reduceTo": "avg",
"spaceAggregation": "max",
"stepInterval": 60,
"timeAggregation": "max"
}
],
"queryFormulas": []
},
"clickhouse_sql": [
{
"disabled": false,
"legend": "",
"name": "A",
"query": ""
}
],
"id": "0d2fc26c-9b21-4dfc-b631-64b7c8d3bd71",
"promql": [
{
"disabled": false,
"legend": "",
"name": "A",
"query": ""
}
],
"queryType": "builder"
},
"selectedLogFields": [
{
"dataType": "string",
"name": "body",
"type": ""
},
{
"dataType": "string",
"name": "timestamp",
"type": ""
}
],
"selectedTracesFields": [
{
"dataType": "string",
"id": "serviceName--string--tag--true",
"isColumn": true,
"isJSON": false,
"key": "serviceName",
"type": "tag"
},
{
"dataType": "string",
"id": "name--string--tag--true",
"isColumn": true,
"isJSON": false,
"key": "name",
"type": "tag"
},
{
"dataType": "float64",
"id": "durationNano--float64--tag--true",
"isColumn": true,
"isJSON": false,
"key": "durationNano",
"type": "tag"
},
{
"dataType": "string",
"id": "httpMethod--string--tag--true",
"isColumn": true,
"isJSON": false,
"key": "httpMethod",
"type": "tag"
},
{
"dataType": "string",
"id": "responseStatusCode--string--tag--true",
"isColumn": true,
"isJSON": false,
"key": "responseStatusCode",
"type": "tag"
}
],
"softMax": 0,
"softMin": 0,
"stackedBarChart": false,
"thresholds": [],
"timePreferance": "GLOBAL_TIME",
"title": "Number of Notifications Delivered",
"yAxisUnit": "none"
},
{
"bucketCount": 30,
"bucketWidth": 0,
"columnUnits": {},
"description": "",
"fillSpans": false,
"id": "16eec8b7-de1a-4039-b180-24c7a6704b6e",
"isLogScale": false,
"isStacked": false,
"mergeAllActiveQueries": false,
"nullZeroValues": "zero",
"opacity": "1",
"panelTypes": "graph",
"query": {
"builder": {
"queryData": [
{
"aggregateAttribute": {
"dataType": "float64",
"id": "aws_SNS_NumberOfNotificationsFailed_max--float64--Gauge--true",
"isColumn": true,
"isJSON": false,
"key": "aws_SNS_NumberOfNotificationsFailed_max",
"type": "Gauge"
},
"aggregateOperator": "max",
"dataSource": "metrics",
"disabled": false,
"expression": "A",
"filters": {
"items": [
{
"id": "6175f3d5",
"key": {
"dataType": "string",
"id": "TopicName--string--tag--false",
"isColumn": false,
"isJSON": false,
"key": "TopicName",
"type": "tag"
},
"op": "in",
"value": [
"$Topic"
]
},
{
"id": "e2084931",
"key": {
"dataType": "string",
"id": "cloud.region--string--tag--false",
"isColumn": false,
"isJSON": false,
"key": "cloud.region",
"type": "tag"
},
"op": "=",
"value": "$Region"
},
{
"id": "0b05209a",
"key": {
"dataType": "string",
"id": "cloud.account.id--string--tag--false",
"isColumn": false,
"isJSON": false,
"key": "cloud.account.id",
"type": "tag"
},
"op": "=",
"value": "$Account"
}
],
"op": "AND"
},
"functions": [],
"groupBy": [
{
"dataType": "string",
"id": "TopicName--string--tag--false",
"isColumn": false,
"isJSON": false,
"key": "TopicName",
"type": "tag"
}
],
"having": [],
"legend": "{{TopicName}}",
"limit": null,
"orderBy": [],
"queryName": "A",
"reduceTo": "avg",
"spaceAggregation": "max",
"stepInterval": 60,
"timeAggregation": "max"
}
],
"queryFormulas": []
},
"clickhouse_sql": [
{
"disabled": false,
"legend": "",
"name": "A",
"query": ""
}
],
"id": "526247af-6ac9-42ff-83e9-cce0e32a9e63",
"promql": [
{
"disabled": false,
"legend": "",
"name": "A",
"query": ""
}
],
"queryType": "builder"
},
"selectedLogFields": [
{
"dataType": "string",
"name": "body",
"type": ""
},
{
"dataType": "string",
"name": "timestamp",
"type": ""
}
],
"selectedTracesFields": [
{
"dataType": "string",
"id": "serviceName--string--tag--true",
"isColumn": true,
"isJSON": false,
"key": "serviceName",
"type": "tag"
},
{
"dataType": "string",
"id": "name--string--tag--true",
"isColumn": true,
"isJSON": false,
"key": "name",
"type": "tag"
},
{
"dataType": "float64",
"id": "durationNano--float64--tag--true",
"isColumn": true,
"isJSON": false,
"key": "durationNano",
"type": "tag"
},
{
"dataType": "string",
"id": "httpMethod--string--tag--true",
"isColumn": true,
"isJSON": false,
"key": "httpMethod",
"type": "tag"
},
{
"dataType": "string",
"id": "responseStatusCode--string--tag--true",
"isColumn": true,
"isJSON": false,
"key": "responseStatusCode",
"type": "tag"
}
],
"softMax": 0,
"softMin": 0,
"stackedBarChart": false,
"thresholds": [],
"timePreferance": "GLOBAL_TIME",
"title": "Number of Notifications Failed",
"yAxisUnit": "none"
}
]
}

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