| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200 |
- import _ from 'lodash';
- import { TimeSeries } from 'app/core/core';
- import colors from 'app/core/utils/colors';
- export enum LogLevel {
- crit = 'critical',
- critical = 'critical',
- warn = 'warning',
- warning = 'warning',
- err = 'error',
- error = 'error',
- info = 'info',
- debug = 'debug',
- trace = 'trace',
- unkown = 'unkown',
- }
- export const LogLevelColor = {
- [LogLevel.critical]: colors[7],
- [LogLevel.warning]: colors[1],
- [LogLevel.error]: colors[4],
- [LogLevel.info]: colors[0],
- [LogLevel.debug]: colors[5],
- [LogLevel.trace]: colors[2],
- [LogLevel.unkown]: '#ddd',
- };
- export interface LogSearchMatch {
- start: number;
- length: number;
- text: string;
- }
- export interface LogRow {
- duplicates?: number;
- entry: string;
- key: string; // timestamp + labels
- labels: LogsStreamLabels;
- logLevel: LogLevel;
- searchWords?: string[];
- timestamp: string; // ISO with nanosec precision
- timeFromNow: string;
- timeEpochMs: number;
- timeLocal: string;
- uniqueLabels?: LogsStreamLabels;
- }
- export interface LogsLabelStat {
- active?: boolean;
- count: number;
- proportion: number;
- value: string;
- }
- export enum LogsMetaKind {
- Number,
- String,
- LabelsMap,
- }
- export interface LogsMetaItem {
- label: string;
- value: string | number | LogsStreamLabels;
- kind: LogsMetaKind;
- }
- export interface LogsModel {
- id: string; // Identify one logs result from another
- meta?: LogsMetaItem[];
- rows: LogRow[];
- series?: TimeSeries[];
- }
- export interface LogsStream {
- labels: string;
- entries: LogsStreamEntry[];
- search?: string;
- parsedLabels?: LogsStreamLabels;
- uniqueLabels?: LogsStreamLabels;
- }
- export interface LogsStreamEntry {
- line: string;
- timestamp: string;
- }
- export interface LogsStreamLabels {
- [key: string]: string;
- }
- export enum LogsDedupStrategy {
- none = 'none',
- exact = 'exact',
- numbers = 'numbers',
- 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) {
- case LogsDedupStrategy.exact:
- // Exact still strips dates
- return row.entry.replace(isoDateRegexp, '') === other.entry.replace(isoDateRegexp, '');
- case LogsDedupStrategy.numbers:
- return row.entry.replace(/\d/g, '') === other.entry.replace(/\d/g, '');
- case LogsDedupStrategy.signature:
- return row.entry.replace(/\w/g, '') === other.entry.replace(/\w/g, '');
- default:
- return false;
- }
- }
- export function dedupLogRows(logs: LogsModel, strategy: LogsDedupStrategy): LogsModel {
- if (strategy === LogsDedupStrategy.none) {
- return logs;
- }
- const dedupedRows = logs.rows.reduce((result: LogRow[], row: LogRow, index, list) => {
- const previous = result[result.length - 1];
- if (index > 0 && isDuplicateRow(row, previous, strategy)) {
- previous.duplicates++;
- } else {
- row.duplicates = 0;
- result.push(row);
- }
- return result;
- }, []);
- return {
- ...logs,
- rows: dedupedRows,
- };
- }
- export function filterLogLevels(logs: LogsModel, hiddenLogLevels: Set<LogLevel>): LogsModel {
- if (hiddenLogLevels.size === 0) {
- return logs;
- }
- const filteredRows = logs.rows.reduce((result: LogRow[], row: LogRow, index, list) => {
- if (!hiddenLogLevels.has(row.logLevel)) {
- result.push(row);
- }
- return result;
- }, []);
- return {
- ...logs,
- rows: filteredRows,
- };
- }
- export function makeSeriesForLogs(rows: LogRow[], intervalMs: number): TimeSeries[] {
- // Graph time series by log level
- const seriesByLevel = {};
- rows.forEach(row => {
- if (!seriesByLevel[row.logLevel]) {
- seriesByLevel[row.logLevel] = { lastTs: null, datapoints: [], alias: row.logLevel };
- }
- const levelSeries = seriesByLevel[row.logLevel];
- // Bucket to nearest minute
- const time = Math.round(row.timeEpochMs / intervalMs / 10) * intervalMs * 10;
- // Entry for time
- if (time === levelSeries.lastTs) {
- levelSeries.datapoints[levelSeries.datapoints.length - 1][0]++;
- } else {
- levelSeries.datapoints.push([1, time]);
- levelSeries.lastTs = time;
- }
- });
- return Object.keys(seriesByLevel).reduce((acc, level) => {
- if (seriesByLevel[level]) {
- const gs = new TimeSeries(seriesByLevel[level]);
- gs.setColor(LogLevelColor[level]);
- acc.push(gs);
- }
- return acc;
- }, []);
- }
|