fix: logs explorer chart severity text bugfixes (#8731)

* fix: fixed severity color getting incorrectly assigned due to the response changed in v5 API

* fix: implement consistent severity variant colors across logs chart and indicator component

* chore: fix the failing tests

* chore: fix the failing check

---------

Co-authored-by: ahmadshaheer <ashaheerki@gmail.com>
Co-authored-by: Nityananda Gohain <nityanandagohain@gmail.com>
This commit is contained in:
SagarRajput-7 2025-09-10 10:51:06 +05:30 committed by GitHub
parent f91115948a
commit f82e9b55f8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 299 additions and 38 deletions

View File

@ -208,7 +208,11 @@ function ListLogView({
fontSize={fontSize}
>
<div className="log-line">
<LogStateIndicator type={logType} fontSize={fontSize} />
<LogStateIndicator
fontSize={fontSize}
severityText={logData.severity_text}
severityNumber={logData.severity_number}
/>
<div>
<LogContainer fontSize={fontSize}>
{updatedSelecedFields.some((field) => field.name === 'body') && (

View File

@ -7,7 +7,6 @@
height: 100%;
width: 3px;
border-radius: 50px;
background-color: transparent;
&.small {
min-height: 16px;
@ -21,24 +20,107 @@
min-height: 24px;
}
&.INFO {
background-color: var(--bg-robin-500);
// Severity variant CSS classes using design tokens
// Trace variants -
&.severity-trace-0 {
background-color: var(--bg-forest-600);
}
&.WARNING,
&.WARN {
background-color: var(--bg-amber-500);
&.severity-trace-1 {
background-color: var(--bg-forest-500);
}
&.ERROR {
background-color: var(--bg-cherry-500);
}
&.TRACE {
&.severity-trace-2 {
background-color: var(--bg-forest-400);
}
&.DEBUG {
&.severity-trace-3 {
background-color: var(--bg-forest-300);
}
&.severity-trace-4 {
background-color: var(--bg-forest-200);
}
// Debug variants
&.severity-debug-0 {
background-color: var(--bg-aqua-600);
}
&.severity-debug-1 {
background-color: var(--bg-aqua-500);
}
&.FATAL {
&.severity-debug-2 {
background-color: var(--bg-aqua-400);
}
&.severity-debug-3 {
background-color: var(--bg-aqua-300);
}
&.severity-debug-4 {
background-color: var(--bg-aqua-200);
}
// Info variants
&.severity-info-0 {
background-color: var(--bg-robin-600);
}
&.severity-info-1 {
background-color: var(--bg-robin-500);
}
&.severity-info-2 {
background-color: var(--bg-robin-400);
}
&.severity-info-3 {
background-color: var(--bg-robin-300);
}
&.severity-info-4 {
background-color: var(--bg-robin-200);
}
// Warn variants
&.severity-warn-0 {
background-color: var(--bg-amber-600);
}
&.severity-warn-1 {
background-color: var(--bg-amber-500);
}
&.severity-warn-2 {
background-color: var(--bg-amber-400);
}
&.severity-warn-3 {
background-color: var(--bg-amber-300);
}
&.severity-warn-4 {
background-color: var(--bg-amber-200);
}
// Error variants
&.severity-error-0 {
background-color: var(--bg-cherry-600);
}
&.severity-error-1 {
background-color: var(--bg-cherry-500);
}
&.severity-error-2 {
background-color: var(--bg-cherry-400);
}
&.severity-error-3 {
background-color: var(--bg-cherry-300);
}
&.severity-error-4 {
background-color: var(--bg-cherry-200);
}
// Fatal variants
&.severity-fatal-0 {
background-color: var(--bg-sakura-600);
}
&.severity-fatal-1 {
background-color: var(--bg-sakura-500);
}
&.severity-fatal-2 {
background-color: var(--bg-sakura-400);
}
&.severity-fatal-3 {
background-color: var(--bg-sakura-300);
}
&.severity-fatal-4 {
background-color: var(--bg-sakura-200);
}
}
}

View File

@ -6,37 +6,41 @@ import LogStateIndicator from './LogStateIndicator';
describe('LogStateIndicator', () => {
it('renders correctly with default props', () => {
const { container } = render(
<LogStateIndicator type="INFO" fontSize={FontSize.MEDIUM} />,
<LogStateIndicator severityText="INFO" fontSize={FontSize.MEDIUM} />,
);
const indicator = container.firstChild as HTMLElement;
expect(indicator.classList.contains('log-state-indicator')).toBe(true);
expect(indicator.classList.contains('isActive')).toBe(false);
expect(container.querySelector('.line')).toBeTruthy();
expect(container.querySelector('.line')?.classList.contains('INFO')).toBe(
true,
);
expect(
container.querySelector('.line')?.classList.contains('severity-info-0'),
).toBe(true);
});
it('renders correctly with different types', () => {
const { container: containerInfo } = render(
<LogStateIndicator type="INFO" fontSize={FontSize.MEDIUM} />,
);
expect(containerInfo.querySelector('.line')?.classList.contains('INFO')).toBe(
true,
);
const { container: containerWarning } = render(
<LogStateIndicator type="WARNING" fontSize={FontSize.MEDIUM} />,
<LogStateIndicator severityText="INFO" fontSize={FontSize.MEDIUM} />,
);
expect(
containerWarning.querySelector('.line')?.classList.contains('WARNING'),
containerInfo.querySelector('.line')?.classList.contains('severity-info-0'),
).toBe(true);
const { container: containerWarning } = render(
<LogStateIndicator severityText="WARNING" fontSize={FontSize.MEDIUM} />,
);
expect(
containerWarning
.querySelector('.line')
?.classList.contains('severity-warn-0'),
).toBe(true);
const { container: containerError } = render(
<LogStateIndicator type="ERROR" fontSize={FontSize.MEDIUM} />,
<LogStateIndicator severityText="ERROR" fontSize={FontSize.MEDIUM} />,
);
expect(
containerError.querySelector('.line')?.classList.contains('ERROR'),
containerError
.querySelector('.line')
?.classList.contains('severity-error-0'),
).toBe(true);
});
});

View File

@ -3,6 +3,8 @@ import './LogStateIndicator.styles.scss';
import cx from 'classnames';
import { FontSize } from 'container/OptionsMenu/types';
import { getLogTypeBySeverityNumber } from './utils';
export const SEVERITY_TEXT_TYPE = {
TRACE: 'TRACE',
TRACE2: 'TRACE2',
@ -42,18 +44,112 @@ export const LogType = {
UNKNOWN: 'UNKNOWN',
} as const;
// Severity variant mapping to CSS classes
const SEVERITY_VARIANT_CLASSES: Record<string, string> = {
// Trace variants - forest-600 to forest-200
TRACE: 'severity-trace-0',
Trace: 'severity-trace-1',
trace: 'severity-trace-2',
trc: 'severity-trace-3',
Trc: 'severity-trace-4',
// Debug variants - aqua-600 to aqua-200
DEBUG: 'severity-debug-0',
Debug: 'severity-debug-1',
debug: 'severity-debug-2',
dbg: 'severity-debug-3',
Dbg: 'severity-debug-4',
// Info variants - robin-600 to robin-200
INFO: 'severity-info-0',
Info: 'severity-info-1',
info: 'severity-info-2',
Information: 'severity-info-3',
information: 'severity-info-4',
// Warn variants - amber-600 to amber-200
WARN: 'severity-warn-0',
WARNING: 'severity-warn-0',
Warn: 'severity-warn-1',
warn: 'severity-warn-2',
warning: 'severity-warn-3',
Warning: 'severity-warn-4',
wrn: 'severity-warn-3',
Wrn: 'severity-warn-4',
// Error variants - cherry-600 to cherry-200
// eslint-disable-next-line sonarjs/no-duplicate-string
ERROR: 'severity-error-0',
Error: 'severity-error-1',
error: 'severity-error-2',
err: 'severity-error-3',
Err: 'severity-error-4',
ERR: 'severity-error-0',
fail: 'severity-error-2',
Fail: 'severity-error-3',
FAIL: 'severity-error-0',
// Fatal variants - sakura-600 to sakura-200
// eslint-disable-next-line sonarjs/no-duplicate-string
FATAL: 'severity-fatal-0',
Fatal: 'severity-fatal-1',
fatal: 'severity-fatal-2',
// eslint-disable-next-line sonarjs/no-duplicate-string
critical: 'severity-fatal-3',
Critical: 'severity-fatal-4',
CRITICAL: 'severity-fatal-0',
crit: 'severity-fatal-3',
Crit: 'severity-fatal-4',
CRIT: 'severity-fatal-0',
panic: 'severity-fatal-2',
Panic: 'severity-fatal-3',
PANIC: 'severity-fatal-0',
};
function getSeverityClass(
severityText?: string,
severityNumber?: number,
): string {
// Priority 1: Use severityText for exact variant mapping
if (severityText) {
const variantClass = SEVERITY_VARIANT_CLASSES[severityText.trim()];
if (variantClass) {
return variantClass;
}
}
// Priority 2: Use severityNumber for base color (use middle shade as default)
if (severityNumber) {
const logType = getLogTypeBySeverityNumber(severityNumber);
if (logType !== LogType.UNKNOWN) {
return `severity-${logType.toLowerCase()}-0`; // Use middle shade (index 2)
}
}
return 'severity-info-0'; // Fallback to CSS classes based on type
}
function LogStateIndicator({
type,
fontSize,
severityText,
severityNumber,
}: {
type: string;
fontSize: FontSize;
severityText?: string;
severityNumber?: number;
}): JSX.Element {
const severityClass = getSeverityClass(severityText, severityNumber);
return (
<div className="log-state-indicator">
<div className={cx('line', type, fontSize)}> </div>
<div className={cx('line', fontSize, severityClass)} />
</div>
);
}
LogStateIndicator.defaultProps = {
severityText: '',
severityNumber: 0,
};
export default LogStateIndicator;

View File

@ -41,7 +41,7 @@ const getLogTypeBySeverityText = (severityText: string): string => {
};
// https://opentelemetry.io/docs/specs/otel/logs/data-model/#field-severitynumber
const getLogTypeBySeverityNumber = (severityNumber: number): string => {
export const getLogTypeBySeverityNumber = (severityNumber: number): string => {
if (severityNumber < 1) {
return LogType.UNKNOWN;
}

View File

@ -192,7 +192,11 @@ function RawLogView({
onMouseLeave={handleMouseLeave}
fontSize={fontSize}
>
<LogStateIndicator type={logType} fontSize={fontSize} />
<LogStateIndicator
fontSize={fontSize}
severityText={data.severity_text}
severityNumber={data.severity_number}
/>
<RawLogContent
className="raw-log-content"

View File

@ -11,7 +11,6 @@ import { useTimezone } from 'providers/Timezone';
import { useMemo } from 'react';
import LogStateIndicator from '../LogStateIndicator/LogStateIndicator';
import { getLogIndicatorTypeForTable } from '../LogStateIndicator/utils';
import {
defaultListViewPanelStyle,
defaultTableStyle,
@ -93,8 +92,9 @@ export const useTableView = (props: UseTableViewProps): UseTableViewResult => {
children: (
<div className={cx('state-indicator', fontSize)}>
<LogStateIndicator
type={getLogIndicatorTypeForTable(item)}
fontSize={fontSize}
severityText={item.severity_text as string}
severityNumber={item.severity_number as number}
/>
</div>
),

View File

@ -2,12 +2,80 @@ import { Color } from '@signozhq/design-tokens';
import { themeColors } from 'constants/theme';
import { colors } from 'lib/getRandomColor';
const SEVERITY_VARIANT_COLORS: Record<string, string> = {
TRACE: Color.BG_FOREST_600,
Trace: Color.BG_FOREST_500,
trace: Color.BG_FOREST_400,
trc: Color.BG_FOREST_300,
Trc: Color.BG_FOREST_200,
DEBUG: Color.BG_AQUA_600,
Debug: Color.BG_AQUA_500,
debug: Color.BG_AQUA_400,
dbg: Color.BG_AQUA_300,
Dbg: Color.BG_AQUA_200,
INFO: Color.BG_ROBIN_600,
Info: Color.BG_ROBIN_500,
info: Color.BG_ROBIN_400,
Information: Color.BG_ROBIN_300,
information: Color.BG_ROBIN_200,
WARN: Color.BG_AMBER_600,
Warn: Color.BG_AMBER_500,
warn: Color.BG_AMBER_400,
warning: Color.BG_AMBER_300,
Warning: Color.BG_AMBER_200,
wrn: Color.BG_AMBER_300,
Wrn: Color.BG_AMBER_200,
ERROR: Color.BG_CHERRY_600,
Error: Color.BG_CHERRY_500,
error: Color.BG_CHERRY_400,
err: Color.BG_CHERRY_300,
Err: Color.BG_CHERRY_200,
ERR: Color.BG_CHERRY_600,
fail: Color.BG_CHERRY_400,
Fail: Color.BG_CHERRY_300,
FAIL: Color.BG_CHERRY_600,
FATAL: Color.BG_SAKURA_600,
Fatal: Color.BG_SAKURA_500,
fatal: Color.BG_SAKURA_400,
critical: Color.BG_SAKURA_300,
Critical: Color.BG_SAKURA_200,
CRITICAL: Color.BG_SAKURA_600,
crit: Color.BG_SAKURA_300,
Crit: Color.BG_SAKURA_200,
CRIT: Color.BG_SAKURA_600,
panic: Color.BG_SAKURA_400,
Panic: Color.BG_SAKURA_300,
PANIC: Color.BG_SAKURA_600,
};
// Simple function to get severity color for any component
export function getSeverityColor(severityText: string): string {
const variantColor = SEVERITY_VARIANT_COLORS[severityText.trim()];
if (variantColor) {
return variantColor;
}
return Color.BG_ROBIN_500; // Default fallback
}
export function getColorsForSeverityLabels(
label: string,
index: number,
): string {
// Check if we have a direct mapping for this severity variant
const variantColor = SEVERITY_VARIANT_COLORS[label.trim()];
if (variantColor) {
return variantColor;
}
const lowerCaseLabel = label.toLowerCase();
// Fallback to old format for backward compatibility
if (lowerCaseLabel.includes(`{severity_text="trace"}`)) {
return Color.BG_FOREST_400;
}

View File

@ -4,7 +4,6 @@ import { ColumnDef, DataTable, Row } from '@signozhq/table';
import LogDetail from 'components/LogDetail';
import { VIEW_TYPES } from 'components/LogDetail/constants';
import LogStateIndicator from 'components/Logs/LogStateIndicator/LogStateIndicator';
import { getLogIndicatorTypeForTable } from 'components/Logs/LogStateIndicator/utils';
import { useTableView } from 'components/Logs/TableView/useTableView';
import { DATE_TIME_FORMATS } from 'constants/dateTimeFormats';
import { LOCALSTORAGE } from 'constants/localStorage';
@ -169,10 +168,14 @@ function ColumnView({
getValue: () => string | JSX.Element;
}): string | JSX.Element => {
if (field.key === 'state-indicator') {
const type = getLogIndicatorTypeForTable(row.original);
const fontSize = options.fontSize as FontSize;
return <LogStateIndicator type={type} fontSize={fontSize} />;
return (
<LogStateIndicator
severityText={row.original?.severity_text}
fontSize={fontSize}
/>
);
}
const isTimestamp = field.key === 'timestamp';