Logs: Add possibility to download logs in JSON format (#61394)

* add implementation of `logRowsToReadableJson`

* add test for logRowsToReadableJson

* add json, txt download buttons

* changed downloadmenu to `Menu`

* set closed state when menu closes

* removed unused css

* removed unused imports

* remove isOpen state

* remove unused import

* add tests

* remove untouched file
This commit is contained in:
Sven Grossmann
2023-01-16 17:20:19 +01:00
committed by GitHub
parent 0eeeeef08b
commit 82d8b2036f
5 changed files with 300 additions and 9 deletions
@@ -27,7 +27,7 @@ export const getAllFields = memoizeOne(
/**
* creates fields from the dataframe-fields, adding data-links, when field.config.links exists
*/
const getDataframeFields = memoizeOne(
export const getDataframeFields = memoizeOne(
(
row: LogRowModel,
getFieldLinks?: (field: Field, rowIndex: number, dataFrame: DataFrame) => Array<LinkModel<Field>>
+56
View File
@@ -7,6 +7,7 @@ import {
getLogLevelFromKey,
sortLogsResult,
checkLogsError,
logRowsToReadableJson,
} from './utils';
describe('getLoglevel()', () => {
@@ -205,3 +206,58 @@ describe('checkLogsError()', () => {
expect(checkLogsError(log)).toStrictEqual({ hasError: true, errorMessage: 'Error Message' });
});
});
describe('logRowsToReadableJson', () => {
const testRow: LogRowModel = {
rowIndex: 1,
entryFieldIndex: 0,
dataFrame: new MutableDataFrame(),
entry: 'test entry',
hasAnsi: false,
hasUnescapedContent: false,
labels: {
foo: 'bar',
},
logLevel: LogLevel.info,
raw: '',
timeEpochMs: 10,
timeEpochNs: '123456789',
timeFromNow: '',
timeLocal: '',
timeUtc: '',
uid: '2',
};
const testDf = new MutableDataFrame();
testDf.addField({ name: 'foo2', values: ['bar2'] });
const testRow2: LogRowModel = {
rowIndex: 0,
entryFieldIndex: -1,
dataFrame: testDf,
entry: 'test entry',
hasAnsi: false,
hasUnescapedContent: false,
labels: {
foo: 'bar',
},
logLevel: LogLevel.info,
raw: '',
timeEpochMs: 10,
timeEpochNs: '123456789',
timeFromNow: '',
timeLocal: '',
timeUtc: '',
uid: '2',
};
it('should format a single row', () => {
const result = logRowsToReadableJson([testRow]);
expect(result).toEqual([{ line: 'test entry', timestamp: '123456789', fields: { foo: 'bar' } }]);
});
it('should format a df field row', () => {
const result = logRowsToReadableJson([testRow2]);
expect(result).toEqual([{ line: 'test entry', timestamp: '123456789', fields: { foo: 'bar', foo2: 'bar2' } }]);
});
});
+20
View File
@@ -2,6 +2,8 @@ import { countBy, chain } from 'lodash';
import { LogLevel, LogRowModel, LogLabelStatsModel, LogsModel, LogsSortOrder } from '@grafana/data';
import { getDataframeFields } from './components/logParser';
/**
* Returns the log level of a log line.
* Parse the line for level words. If no level is found, it returns `LogLevel.unknown`.
@@ -129,3 +131,21 @@ export const checkLogsError = (logRow: LogRowModel): { hasError: boolean; errorM
export const escapeUnescapedString = (string: string) =>
string.replace(/\\r\\n|\\n|\\t|\\r/g, (match: string) => (match.slice(1) === 't' ? '\t' : '\n'));
export function logRowsToReadableJson(logs: LogRowModel[]) {
return logs.map((log) => {
const fields = getDataframeFields(log).reduce<Record<string, string>>((acc, field) => {
acc[field.key] = field.value;
return acc;
}, {});
return {
line: log.entry,
timestamp: log.timeEpochNs,
fields: {
...fields,
...log.labels,
},
};
});
}