mirror of
https://github.com/grafana/grafana.git
synced 2026-07-29 15:59:50 -05:00
Graph log entries by log level
This commit is contained in:
@@ -1,5 +1,6 @@
|
|||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import { TimeSeries } from 'app/core/core';
|
import { TimeSeries } from 'app/core/core';
|
||||||
|
import colors from 'app/core/utils/colors';
|
||||||
|
|
||||||
export enum LogLevel {
|
export enum LogLevel {
|
||||||
crit = 'crit',
|
crit = 'crit',
|
||||||
@@ -9,8 +10,20 @@ export enum LogLevel {
|
|||||||
info = 'info',
|
info = 'info',
|
||||||
debug = 'debug',
|
debug = 'debug',
|
||||||
trace = 'trace',
|
trace = 'trace',
|
||||||
|
none = 'none',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const LogLevelColor = {
|
||||||
|
[LogLevel.crit]: colors[7],
|
||||||
|
[LogLevel.warn]: colors[1],
|
||||||
|
[LogLevel.err]: colors[4],
|
||||||
|
[LogLevel.error]: colors[4],
|
||||||
|
[LogLevel.info]: colors[0],
|
||||||
|
[LogLevel.debug]: colors[3],
|
||||||
|
[LogLevel.trace]: colors[3],
|
||||||
|
[LogLevel.none]: '#eee',
|
||||||
|
};
|
||||||
|
|
||||||
export interface LogSearchMatch {
|
export interface LogSearchMatch {
|
||||||
start: number;
|
start: number;
|
||||||
length: number;
|
length: number;
|
||||||
@@ -44,7 +57,7 @@ export interface LogsStream {
|
|||||||
labels: string;
|
labels: string;
|
||||||
entries: LogsStreamEntry[];
|
entries: LogsStreamEntry[];
|
||||||
parsedLabels: { [key: string]: string };
|
parsedLabels: { [key: string]: string };
|
||||||
graphSeries: TimeSeries;
|
intervalMs?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface LogsStreamEntry {
|
export interface LogsStreamEntry {
|
||||||
|
|||||||
@@ -10,16 +10,16 @@ export const NO_DATA_COLOR = 'rgba(150, 150, 150, 1)';
|
|||||||
export const REGION_FILL_ALPHA = 0.09;
|
export const REGION_FILL_ALPHA = 0.09;
|
||||||
|
|
||||||
const colors = [
|
const colors = [
|
||||||
'#7EB26D',
|
'#7EB26D', // 0: pale green
|
||||||
'#EAB839',
|
'#EAB839', // 1: mustard
|
||||||
'#6ED0E0',
|
'#6ED0E0', // 2: light blue
|
||||||
'#EF843C',
|
'#EF843C', // 3: orange
|
||||||
'#E24D42',
|
'#E24D42', // 4: red
|
||||||
'#1F78C1',
|
'#1F78C1', // 5: ocean
|
||||||
'#BA43A9',
|
'#BA43A9', // 6: purple
|
||||||
'#705DA0',
|
'#705DA0', // 7: violet
|
||||||
'#508642',
|
'#508642', // 8: dark green
|
||||||
'#CCA300',
|
'#CCA300', // 9: dark sand
|
||||||
'#447EBC',
|
'#447EBC',
|
||||||
'#C15C17',
|
'#C15C17',
|
||||||
'#890F02',
|
'#890F02',
|
||||||
|
|||||||
@@ -1,13 +1,12 @@
|
|||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
|
|
||||||
import { LogLevel, LogsMetaItem, LogsModel, LogRow, LogsStream } from 'app/core/logs_model';
|
import { LogLevel, LogLevelColor, LogsMetaItem, LogsModel, LogRow, LogsStream } from 'app/core/logs_model';
|
||||||
import { TimeSeries } from 'app/core/core';
|
import { TimeSeries } from 'app/core/core';
|
||||||
import colors from 'app/core/utils/colors';
|
|
||||||
|
|
||||||
export function getLogLevel(line: string): LogLevel {
|
export function getLogLevel(line: string): LogLevel {
|
||||||
if (!line) {
|
if (!line) {
|
||||||
return undefined;
|
return LogLevel.none;
|
||||||
}
|
}
|
||||||
let level: LogLevel;
|
let level: LogLevel;
|
||||||
Object.keys(LogLevel).forEach(key => {
|
Object.keys(LogLevel).forEach(key => {
|
||||||
@@ -18,6 +17,9 @@ export function getLogLevel(line: string): LogLevel {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
if (!level) {
|
||||||
|
level = LogLevel.none;
|
||||||
|
}
|
||||||
return level;
|
return level;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -107,8 +109,13 @@ export function mergeStreams(streams: LogsStream[], limit?: number): LogsModel {
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
let intervalMs;
|
||||||
|
|
||||||
// Flatten entries of streams
|
// Flatten entries of streams
|
||||||
const combinedEntries = streams.reduce((acc, stream) => {
|
const combinedEntries: LogRow[] = streams.reduce((acc, stream) => {
|
||||||
|
// Set interval for graphs
|
||||||
|
intervalMs = stream.intervalMs;
|
||||||
|
|
||||||
// Overwrite labels to be only the non-common ones
|
// Overwrite labels to be only the non-common ones
|
||||||
const labels = formatLabels(findUncommonLabels(stream.parsedLabels, commonLabels));
|
const labels = formatLabels(findUncommonLabels(stream.parsedLabels, commonLabels));
|
||||||
return [
|
return [
|
||||||
@@ -120,15 +127,34 @@ export function mergeStreams(streams: LogsStream[], limit?: number): LogsModel {
|
|||||||
];
|
];
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const commonLabelsAlias =
|
// Graph time series by log level
|
||||||
streams.length === 1 ? formatLabels(commonLabels) : `Stream with common labels ${formatLabels(commonLabels)}`;
|
const seriesByLevel = {};
|
||||||
const series = streams.map((stream, index) => {
|
combinedEntries.forEach(entry => {
|
||||||
const colorIndex = index % colors.length;
|
if (!seriesByLevel[entry.logLevel]) {
|
||||||
stream.graphSeries.setColor(colors[colorIndex]);
|
seriesByLevel[entry.logLevel] = { lastTs: null, datapoints: [], alias: entry.logLevel };
|
||||||
stream.graphSeries.alias = formatLabels(findUncommonLabels(stream.parsedLabels, commonLabels), commonLabelsAlias);
|
}
|
||||||
return stream.graphSeries;
|
const levelSeries = seriesByLevel[entry.logLevel];
|
||||||
|
|
||||||
|
// Bucket to nearest minute
|
||||||
|
const time = Math.round(entry.timeJs / 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;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const series = Object.keys(seriesByLevel).reduce((acc, level, index) => {
|
||||||
|
if (seriesByLevel[level]) {
|
||||||
|
const gs = new TimeSeries(seriesByLevel[level]);
|
||||||
|
gs.setColor(LogLevelColor[level]);
|
||||||
|
acc.push(gs);
|
||||||
|
}
|
||||||
|
return acc;
|
||||||
|
}, []);
|
||||||
|
|
||||||
const sortedEntries = _.chain(combinedEntries)
|
const sortedEntries = _.chain(combinedEntries)
|
||||||
.sortBy('timestamp')
|
.sortBy('timestamp')
|
||||||
.reverse()
|
.reverse()
|
||||||
@@ -151,25 +177,9 @@ export function processStream(stream: LogsStream, limit?: number, intervalMs?: n
|
|||||||
.slice(0, limit || stream.entries.length)
|
.slice(0, limit || stream.entries.length)
|
||||||
.value();
|
.value();
|
||||||
|
|
||||||
// Build graph data
|
|
||||||
let previousTime;
|
|
||||||
const datapoints = sortedEntries.reduce((acc, entry, index) => {
|
|
||||||
// Bucket to nearest minute
|
|
||||||
const time = Math.round(entry.timeJs / intervalMs / 10) * intervalMs * 10;
|
|
||||||
// Entry for time
|
|
||||||
if (time === previousTime) {
|
|
||||||
acc[acc.length - 1][0]++;
|
|
||||||
} else {
|
|
||||||
acc.push([1, time]);
|
|
||||||
previousTime = time;
|
|
||||||
}
|
|
||||||
return acc;
|
|
||||||
}, []);
|
|
||||||
const graphSeries = new TimeSeries({ datapoints, alias: stream.labels });
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...stream,
|
...stream,
|
||||||
graphSeries,
|
intervalMs,
|
||||||
entries: sortedEntries,
|
entries: sortedEntries,
|
||||||
parsedLabels: parseLabels(stream.labels),
|
parsedLabels: parseLabels(stream.labels),
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user