From c3b67f3a13f1ecb24bfc65c3377cb7a3329120ba Mon Sep 17 00:00:00 2001 From: David Kaltschmidt Date: Wed, 28 Nov 2018 10:46:35 +0100 Subject: [PATCH] Explore: Logging label filtering - adds a custom label renderer to Logs viewer in Explore - labels are no longer treated as strings, they are passed as parsed objects to the log row - label renderer supports onClick handler for an action - renamed Explore's `onClickTableCell` to `onClickLabel` and wired up log label renderers - reuse Prometheus `addLabelToSelector` to modify Logging queries via click on label - added tests to `addLabelToSelector`, changed to include the surrounding `{}` - use label render also for common labels in the controls panel - logging meta data section has now a custom renderer that can render numbers, strings, and labels - style adjustments --- public/app/core/logs_model.ts | 15 +++- public/app/features/explore/Explore.tsx | 7 +- public/app/features/explore/Logs.tsx | 84 +++++++++++++++++-- .../plugins/datasource/logging/datasource.ts | 31 +++---- ...datasource.test.ts => query_utils.test.ts} | 2 +- .../plugins/datasource/logging/query_utils.ts | 17 ++++ .../logging/result_transformer.test.ts | 30 +++---- .../datasource/logging/result_transformer.ts | 25 ++++-- .../prometheus/add_label_to_query.ts | 8 +- .../specs/add_label_to_query.test.ts | 15 +++- public/sass/pages/_explore.scss | 31 ++++++- 11 files changed, 206 insertions(+), 59 deletions(-) rename public/app/plugins/datasource/logging/{datasource.test.ts => query_utils.test.ts} (95%) create mode 100644 public/app/plugins/datasource/logging/query_utils.ts diff --git a/public/app/core/logs_model.ts b/public/app/core/logs_model.ts index 2485dbda40a..a65669c088d 100644 --- a/public/app/core/logs_model.ts +++ b/public/app/core/logs_model.ts @@ -35,19 +35,26 @@ export interface LogRow { duplicates?: number; entry: string; key: string; // timestamp + labels - labels: string; + labels: LogsStreamLabels; logLevel: LogLevel; searchWords?: string[]; timestamp: string; // ISO with nanosec precision timeFromNow: string; timeEpochMs: number; timeLocal: string; - uniqueLabels?: string; + uniqueLabels?: LogsStreamLabels; +} + +export enum LogsMetaKind { + Number, + String, + LabelsMap, } export interface LogsMetaItem { label: string; - value: string; + value: string | number | LogsStreamLabels; + kind: LogsMetaKind; } export interface LogsModel { @@ -61,7 +68,7 @@ export interface LogsStream { entries: LogsStreamEntry[]; search?: string; parsedLabels?: LogsStreamLabels; - uniqueLabels?: string; + uniqueLabels?: LogsStreamLabels; } export interface LogsStreamEntry { diff --git a/public/app/features/explore/Explore.tsx b/public/app/features/explore/Explore.tsx index 44380877c34..317017ae072 100644 --- a/public/app/features/explore/Explore.tsx +++ b/public/app/features/explore/Explore.tsx @@ -429,8 +429,8 @@ export class Explore extends React.PureComponent { ); }; - onClickTableCell = (columnKey: string, rowValue: string) => { - this.onModifyQueries({ type: 'ADD_FILTER', key: columnKey, value: rowValue }); + onClickLabel = (key: string, value: string) => { + this.onModifyQueries({ type: 'ADD_FILTER', key, value }); }; onModifyQueries = (action, index?: number) => { @@ -931,7 +931,7 @@ export class Explore extends React.PureComponent { isOpen={showingTable} onToggle={this.onClickTableButton} > - +
)} {supportsLogs && ( @@ -941,6 +941,7 @@ export class Explore extends React.PureComponent { loading={logsLoading} position={position} onChangeTime={this.onChangeTime} + onClickLabel={this.onClickLabel} onStartScanning={this.onStartScanning} onStopScanning={this.onStopScanning} range={range} diff --git a/public/app/features/explore/Logs.tsx b/public/app/features/explore/Logs.tsx index 58965df4514..2c78d9782b9 100644 --- a/public/app/features/explore/Logs.tsx +++ b/public/app/features/explore/Logs.tsx @@ -1,9 +1,18 @@ +import _ from 'lodash'; import React, { Fragment, PureComponent } from 'react'; import Highlighter from 'react-highlight-words'; import * as rangeUtil from 'app/core/utils/rangeutil'; import { RawTimeRange } from 'app/types/series'; -import { LogsDedupStrategy, LogsModel, dedupLogRows, filterLogLevels, LogLevel } from 'app/core/logs_model'; +import { + LogsDedupStrategy, + LogsModel, + dedupLogRows, + filterLogLevels, + LogLevel, + LogsStreamLabels, + LogsMetaKind, +} from 'app/core/logs_model'; import { findHighlightChunksInText } from 'app/core/utils/text'; import { Switch } from 'app/core/components/Switch/Switch'; @@ -23,6 +32,51 @@ const graphOptions = { }, }; +function renderMetaItem(value: any, kind: LogsMetaKind) { + if (kind === LogsMetaKind.LabelsMap) { + return ( + + + + ); + } + return value; +} + +class Label extends PureComponent<{ + label: string; + value: string; + onClickLabel?: (label: string, value: string) => void; +}> { + onClickLabel = () => { + const { onClickLabel, label, value } = this.props; + if (onClickLabel) { + onClickLabel(label, value); + } + }; + + render() { + const { label, value } = this.props; + const tooltip = `${label}: ${value}`; + return ( + + {value} + + ); + } +} +class Labels extends PureComponent<{ + labels: LogsStreamLabels; + onClickLabel?: (label: string, value: string) => void; +}> { + render() { + const { labels, onClickLabel } = this.props; + return Object.keys(labels).map(key => ( +