mirror of
https://github.com/grafana/grafana.git
synced 2025-02-10 23:55:47 -06:00
Tests for label stats calculation
This commit is contained in:
parent
5916cb3e7c
commit
9f0b1e533f
@ -45,6 +45,13 @@ export interface LogRow {
|
||||
uniqueLabels?: LogsStreamLabels;
|
||||
}
|
||||
|
||||
export interface LogsLabelStat {
|
||||
active?: boolean;
|
||||
count: number;
|
||||
proportion: number;
|
||||
value: string;
|
||||
}
|
||||
|
||||
export enum LogsMetaKind {
|
||||
Number,
|
||||
String,
|
||||
@ -88,6 +95,22 @@ export enum LogsDedupStrategy {
|
||||
signature = 'signature',
|
||||
}
|
||||
|
||||
export function calculateLogsLabelStats(rows: LogRow[], label: string): LogsLabelStat[] {
|
||||
// Consider only rows that have the given label
|
||||
const rowsWithLabel = rows.filter(row => row.labels[label] !== undefined);
|
||||
const rowCount = rowsWithLabel.length;
|
||||
|
||||
// Get label value counts for eligible rows
|
||||
const countsByValue = _.countBy(rowsWithLabel, row => (row as LogRow).labels[label]);
|
||||
const sortedCounts = _.chain(countsByValue)
|
||||
.map((count, value) => ({ count, value, proportion: count / rowCount }))
|
||||
.sortBy('count')
|
||||
.reverse()
|
||||
.value();
|
||||
|
||||
return sortedCounts;
|
||||
}
|
||||
|
||||
const isoDateRegexp = /\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-6]\d[,\.]\d+([+-][0-2]\d:[0-5]\d|Z)/g;
|
||||
function isDuplicateRow(row: LogRow, other: LogRow, strategy: LogsDedupStrategy): boolean {
|
||||
switch (strategy) {
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { dedupLogRows, LogsDedupStrategy, LogsModel } from '../logs_model';
|
||||
import { calculateLogsLabelStats, dedupLogRows, LogsDedupStrategy, LogsModel } from '../logs_model';
|
||||
|
||||
describe('dedupLogRows()', () => {
|
||||
test('should return rows as is when dedup is set to none', () => {
|
||||
@ -106,3 +106,56 @@ describe('dedupLogRows()', () => {
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('calculateLogsLabelStats()', () => {
|
||||
test('should return no stats for empty rows', () => {
|
||||
expect(calculateLogsLabelStats([], '')).toEqual([]);
|
||||
});
|
||||
|
||||
test('should return no stats of label is not found', () => {
|
||||
const rows = [
|
||||
{
|
||||
entry: 'foo 1',
|
||||
labels: {
|
||||
foo: 'bar',
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
expect(calculateLogsLabelStats(rows as any, 'baz')).toEqual([]);
|
||||
});
|
||||
|
||||
test('should return stats for found labels', () => {
|
||||
const rows = [
|
||||
{
|
||||
entry: 'foo 1',
|
||||
labels: {
|
||||
foo: 'bar',
|
||||
},
|
||||
},
|
||||
{
|
||||
entry: 'foo 0',
|
||||
labels: {
|
||||
foo: 'xxx',
|
||||
},
|
||||
},
|
||||
{
|
||||
entry: 'foo 2',
|
||||
labels: {
|
||||
foo: 'bar',
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
expect(calculateLogsLabelStats(rows as any, 'foo')).toMatchObject([
|
||||
{
|
||||
value: 'bar',
|
||||
count: 2,
|
||||
},
|
||||
{
|
||||
value: 'xxx',
|
||||
count: 1,
|
||||
},
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
@ -2,32 +2,9 @@ import _ from 'lodash';
|
||||
import React, { PureComponent } from 'react';
|
||||
import classnames from 'classnames';
|
||||
|
||||
import { LogsStreamLabels, LogRow } from 'app/core/logs_model';
|
||||
import { calculateLogsLabelStats, LogsLabelStat, LogsStreamLabels, LogRow } from 'app/core/logs_model';
|
||||
|
||||
interface FieldStat {
|
||||
active?: boolean;
|
||||
value: string;
|
||||
count: number;
|
||||
proportion: number;
|
||||
}
|
||||
|
||||
function calculateStats(rows: LogRow[], label: string): FieldStat[] {
|
||||
// Consider only rows that have the given label
|
||||
const rowsWithLabel = rows.filter(row => row.labels[label] !== undefined);
|
||||
const rowCount = rowsWithLabel.length;
|
||||
|
||||
// Get label value counts for eligible rows
|
||||
const countsByValue = _.countBy(rowsWithLabel, row => (row as LogRow).labels[label]);
|
||||
const sortedCounts = _.chain(countsByValue)
|
||||
.map((count, value) => ({ count, value, proportion: count / rowCount }))
|
||||
.sortBy('count')
|
||||
.reverse()
|
||||
.value();
|
||||
|
||||
return sortedCounts;
|
||||
}
|
||||
|
||||
function StatsRow({ active, count, proportion, value }: FieldStat) {
|
||||
function StatsRow({ active, count, proportion, value }: LogsLabelStat) {
|
||||
const percent = `${Math.round(proportion * 100)}%`;
|
||||
const barStyle = { width: percent };
|
||||
const className = classnames('logs-stats-row', { 'logs-stats-row--active': active });
|
||||
@ -48,7 +25,7 @@ function StatsRow({ active, count, proportion, value }: FieldStat) {
|
||||
|
||||
const STATS_ROW_LIMIT = 5;
|
||||
class Stats extends PureComponent<{
|
||||
stats: FieldStat[];
|
||||
stats: LogsLabelStat[];
|
||||
label: string;
|
||||
value: string;
|
||||
rowCount: number;
|
||||
@ -92,7 +69,7 @@ class Label extends PureComponent<
|
||||
value: string;
|
||||
onClickLabel?: (label: string, value: string) => void;
|
||||
},
|
||||
{ showStats: boolean; stats: FieldStat[] }
|
||||
{ showStats: boolean; stats: LogsLabelStat[] }
|
||||
> {
|
||||
state = {
|
||||
stats: null,
|
||||
@ -115,7 +92,7 @@ class Label extends PureComponent<
|
||||
if (state.showStats) {
|
||||
return { showStats: false, stats: null };
|
||||
}
|
||||
const stats = calculateStats(this.props.allRows, this.props.label);
|
||||
const stats = calculateLogsLabelStats(this.props.allRows, this.props.label);
|
||||
return { showStats: true, stats };
|
||||
});
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user