Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
N
nexpie-grafana-theme
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Registry
Registry
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Kornkitt Poolsup
nexpie-grafana-theme
Commits
8024a6aa
Unverified
Commit
8024a6aa
authored
Nov 29, 2018
by
David
Committed by
GitHub
Nov 29, 2018
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #14214 from grafana/davkal/explore-logging-label-filter
Explore: Logging label filtering
parents
9b20c9c3
c3b67f3a
Hide whitespace changes
Inline
Side-by-side
Showing
11 changed files
with
206 additions
and
59 deletions
+206
-59
public/app/core/logs_model.ts
+11
-4
public/app/features/explore/Explore.tsx
+4
-3
public/app/features/explore/Logs.tsx
+75
-9
public/app/plugins/datasource/logging/datasource.ts
+17
-14
public/app/plugins/datasource/logging/query_utils.test.ts
+1
-1
public/app/plugins/datasource/logging/query_utils.ts
+17
-0
public/app/plugins/datasource/logging/result_transformer.test.ts
+15
-15
public/app/plugins/datasource/logging/result_transformer.ts
+18
-7
public/app/plugins/datasource/prometheus/add_label_to_query.ts
+5
-3
public/app/plugins/datasource/prometheus/specs/add_label_to_query.test.ts
+14
-1
public/sass/pages/_explore.scss
+29
-2
No files found.
public/app/core/logs_model.ts
View file @
8024a6aa
...
...
@@ -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
{
...
...
public/app/features/explore/Explore.tsx
View file @
8024a6aa
...
...
@@ -429,8 +429,8 @@ export class Explore extends React.PureComponent<ExploreProps, ExploreState> {
);
};
onClick
TableCell
=
(
columnKey
:
string
,
rowV
alue
:
string
)
=>
{
this
.
onModifyQueries
({
type
:
'ADD_FILTER'
,
key
:
columnKey
,
value
:
rowV
alue
});
onClick
Label
=
(
key
:
string
,
v
alue
:
string
)
=>
{
this
.
onModifyQueries
({
type
:
'ADD_FILTER'
,
key
,
v
alue
});
};
onModifyQueries
=
(
action
,
index
?:
number
)
=>
{
...
...
@@ -931,7 +931,7 @@ export class Explore extends React.PureComponent<ExploreProps, ExploreState> {
isOpen=
{
showingTable
}
onToggle=
{
this
.
onClickTableButton
}
>
<
Table
data=
{
tableResult
}
loading=
{
tableLoading
}
onClickCell=
{
this
.
onClick
TableCel
l
}
/>
<
Table
data=
{
tableResult
}
loading=
{
tableLoading
}
onClickCell=
{
this
.
onClick
Labe
l
}
/>
</
Panel
>
)
}
{
supportsLogs
&&
(
...
...
@@ -941,6 +941,7 @@ export class Explore extends React.PureComponent<ExploreProps, ExploreState> {
loading=
{
logsLoading
}
position=
{
position
}
onChangeTime=
{
this
.
onChangeTime
}
onClickLabel=
{
this
.
onClickLabel
}
onStartScanning=
{
this
.
onStartScanning
}
onStopScanning=
{
this
.
onStopScanning
}
range=
{
range
}
...
...
public/app/features/explore/Logs.tsx
View file @
8024a6aa
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
(
<
span
className=
"logs-meta-item__value-labels"
>
<
Labels
labels=
{
value
}
/>
</
span
>
);
}
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
(
<
span
className=
"logs-label"
title=
{
tooltip
}
onClick=
{
this
.
onClickLabel
}
>
{
value
}
</
span
>
);
}
}
class
Labels
extends
PureComponent
<
{
labels
:
LogsStreamLabels
;
onClickLabel
?:
(
label
:
string
,
value
:
string
)
=>
void
;
}
>
{
render
()
{
const
{
labels
,
onClickLabel
}
=
this
.
props
;
return
Object
.
keys
(
labels
).
map
(
key
=>
(
<
Label
key=
{
key
}
label=
{
key
}
value=
{
labels
[
key
]
}
onClickLabel=
{
onClickLabel
}
/>
));
}
}
interface
LogsProps
{
className
?:
string
;
data
:
LogsModel
;
...
...
@@ -32,6 +86,7 @@ interface LogsProps {
scanning
?:
boolean
;
scanRange
?:
RawTimeRange
;
onChangeTime
?:
(
range
:
RawTimeRange
)
=>
void
;
onClickLabel
?:
(
label
:
string
,
value
:
string
)
=>
void
;
onStartScanning
?:
()
=>
void
;
onStopScanning
?:
()
=>
void
;
}
...
...
@@ -39,7 +94,7 @@ interface LogsProps {
interface
LogsState
{
dedup
:
LogsDedupStrategy
;
hiddenLogLevels
:
Set
<
LogLevel
>
;
showLabels
:
boolean
;
showLabels
:
boolean
|
null
;
// Tristate: null means auto
showLocalTime
:
boolean
;
showUtc
:
boolean
;
}
...
...
@@ -48,7 +103,7 @@ export default class Logs extends PureComponent<LogsProps, LogsState> {
state
=
{
dedup
:
LogsDedupStrategy
.
none
,
hiddenLogLevels
:
new
Set
(),
showLabels
:
true
,
showLabels
:
null
,
showLocalTime
:
true
,
showUtc
:
false
,
};
...
...
@@ -99,9 +154,12 @@ export default class Logs extends PureComponent<LogsProps, LogsState> {
};
render
()
{
const
{
className
=
''
,
data
,
loading
=
false
,
position
,
range
,
scanning
,
scanRange
}
=
this
.
props
;
const
{
dedup
,
hiddenLogLevels
,
showLabels
,
showLocalTime
,
showUtc
}
=
this
.
state
;
const
{
className
=
''
,
data
,
loading
=
false
,
onClickLabel
,
position
,
range
,
scanning
,
scanRange
}
=
this
.
props
;
const
{
dedup
,
hiddenLogLevels
,
showLocalTime
,
showUtc
}
=
this
.
state
;
let
{
showLabels
}
=
this
.
state
;
const
hasData
=
data
&&
data
.
rows
&&
data
.
rows
.
length
>
0
;
// Filtering
const
filteredData
=
filterLogLevels
(
data
,
hiddenLogLevels
);
const
dedupedData
=
dedupLogRows
(
filteredData
,
dedup
);
const
dedupCount
=
dedupedData
.
rows
.
reduce
((
sum
,
row
)
=>
sum
+
row
.
duplicates
,
0
);
...
...
@@ -109,9 +167,17 @@ export default class Logs extends PureComponent<LogsProps, LogsState> {
if
(
dedup
!==
LogsDedupStrategy
.
none
)
{
meta
.
push
({
label
:
'Dedup count'
,
value
:
String
(
dedupCount
),
value
:
dedupCount
,
kind
:
LogsMetaKind
.
Number
,
});
}
// Check for labels
if
(
showLabels
===
null
&&
hasData
)
{
showLabels
=
data
.
rows
.
some
(
row
=>
_
.
size
(
row
.
uniqueLabels
)
>
0
);
}
// Grid options
const
cssColumnSizes
=
[
'3px'
];
// Log-level indicator line
if
(
showUtc
)
{
cssColumnSizes
.
push
(
'minmax(100px, max-content)'
);
...
...
@@ -177,7 +243,7 @@ export default class Logs extends PureComponent<LogsProps, LogsState> {
{
meta
.
map
(
item
=>
(
<
div
className=
"logs-meta-item"
key=
{
item
.
label
}
>
<
span
className=
"logs-meta-item__label"
>
{
item
.
label
}
:
</
span
>
<
span
className=
"logs-meta-item__value"
>
{
item
.
value
}
</
span
>
<
span
className=
"logs-meta-item__value"
>
{
renderMetaItem
(
item
.
value
,
item
.
kind
)
}
</
span
>
</
div
>
))
}
</
div
>
...
...
@@ -201,8 +267,8 @@ export default class Logs extends PureComponent<LogsProps, LogsState> {
{
showUtc
&&
<
div
title=
{
`Local: ${row.timeLocal} (${row.timeFromNow})`
}
>
{
row
.
timestamp
}
</
div
>
}
{
showLocalTime
&&
<
div
title=
{
`${row.timestamp} (${row.timeFromNow})`
}
>
{
row
.
timeLocal
}
</
div
>
}
{
showLabels
&&
(
<
div
className=
"
max-width"
title=
{
row
.
labels
}
>
{
row
.
labels
}
<
div
className=
"
logs-row-labels"
>
<
Labels
labels=
{
row
.
uniqueLabels
}
onClickLabel=
{
onClickLabel
}
/>
</
div
>
)
}
<
div
>
...
...
public/app/plugins/datasource/logging/datasource.ts
View file @
8024a6aa
...
...
@@ -3,9 +3,11 @@ import _ from 'lodash';
import
*
as
dateMath
from
'app/core/utils/datemath'
;
import
{
LogsStream
,
LogsModel
,
makeSeriesForLogs
}
from
'app/core/logs_model'
;
import
{
PluginMeta
,
DataQuery
}
from
'app/types'
;
import
{
addLabelToSelector
}
from
'app/plugins/datasource/prometheus/add_label_to_query'
;
import
LanguageProvider
from
'./language_provider'
;
import
{
mergeStreamsToLogs
}
from
'./result_transformer'
;
import
{
formatQuery
,
parseQuery
}
from
'./query_utils'
;
export
const
DEFAULT_LIMIT
=
1000
;
...
...
@@ -16,20 +18,6 @@ const DEFAULT_QUERY_PARAMS = {
query
:
''
,
};
const
selectorRegexp
=
/{
[^
{
]
*}/g
;
export
function
parseQuery
(
input
:
string
)
{
const
match
=
input
.
match
(
selectorRegexp
);
let
query
=
''
;
let
regexp
=
input
;
if
(
match
)
{
query
=
match
[
0
];
regexp
=
input
.
replace
(
selectorRegexp
,
''
).
trim
();
}
return
{
query
,
regexp
};
}
function
serializeParams
(
data
:
any
)
{
return
Object
.
keys
(
data
)
.
map
(
k
=>
{
...
...
@@ -114,6 +102,21 @@ export default class LoggingDatasource {
});
}
modifyQuery
(
query
:
DataQuery
,
action
:
any
):
DataQuery
{
const
parsed
=
parseQuery
(
query
.
expr
||
''
);
let
selector
=
parsed
.
query
;
switch
(
action
.
type
)
{
case
'ADD_FILTER'
:
{
selector
=
addLabelToSelector
(
selector
,
action
.
key
,
action
.
value
);
break
;
}
default
:
break
;
}
const
expression
=
formatQuery
(
selector
,
parsed
.
regexp
);
return
{
...
query
,
expr
:
expression
};
}
getTime
(
date
,
roundUp
)
{
if
(
_
.
isString
(
date
))
{
date
=
dateMath
.
parse
(
date
,
roundUp
);
...
...
public/app/plugins/datasource/logging/
datasource
.test.ts
→
public/app/plugins/datasource/logging/
query_utils
.test.ts
View file @
8024a6aa
import
{
parseQuery
}
from
'./
datasource
'
;
import
{
parseQuery
}
from
'./
query_utils
'
;
describe
(
'parseQuery'
,
()
=>
{
it
(
'returns empty for empty string'
,
()
=>
{
...
...
public/app/plugins/datasource/logging/query_utils.ts
0 → 100644
View file @
8024a6aa
const
selectorRegexp
=
/{
[^
{
]
*}/g
;
export
function
parseQuery
(
input
:
string
)
{
const
match
=
input
.
match
(
selectorRegexp
);
let
query
=
''
;
let
regexp
=
input
;
if
(
match
)
{
query
=
match
[
0
];
regexp
=
input
.
replace
(
selectorRegexp
,
''
).
trim
();
}
return
{
query
,
regexp
};
}
export
function
formatQuery
(
selector
:
string
,
search
:
string
):
string
{
return
`
${
selector
||
''
}
${
search
||
''
}
`
.
trim
();
}
public/app/plugins/datasource/logging/result_transformer.test.ts
View file @
8024a6aa
...
...
@@ -41,7 +41,7 @@ describe('parseLabels()', () => {
});
it
(
'returns labels on labels string'
,
()
=>
{
expect
(
parseLabels
(
'{foo="bar", baz="42"}'
)).
toEqual
({
foo
:
'
"bar"'
,
baz
:
'"42"
'
});
expect
(
parseLabels
(
'{foo="bar", baz="42"}'
)).
toEqual
({
foo
:
'
bar'
,
baz
:
'42
'
});
});
});
...
...
@@ -52,7 +52,7 @@ describe('formatLabels()', () => {
});
it
(
'returns label string on label set'
,
()
=>
{
expect
(
formatLabels
({
foo
:
'
"bar"'
,
baz
:
'"42"
'
})).
toEqual
(
'{baz="42", foo="bar"}'
);
expect
(
formatLabels
({
foo
:
'
bar'
,
baz
:
'42
'
})).
toEqual
(
'{baz="42", foo="bar"}'
);
});
});
...
...
@@ -63,14 +63,14 @@ describe('findCommonLabels()', () => {
});
it
(
'returns no common labels on differing sets'
,
()
=>
{
expect
(
findCommonLabels
([{
foo
:
'
"bar"
'
},
{}])).
toEqual
({});
expect
(
findCommonLabels
([{},
{
foo
:
'
"bar"
'
}])).
toEqual
({});
expect
(
findCommonLabels
([{
baz
:
'42'
},
{
foo
:
'
"bar"
'
}])).
toEqual
({});
expect
(
findCommonLabels
([{
foo
:
'42'
,
baz
:
'
"bar"'
},
{
foo
:
'"bar"
'
}])).
toEqual
({});
expect
(
findCommonLabels
([{
foo
:
'
bar
'
},
{}])).
toEqual
({});
expect
(
findCommonLabels
([{},
{
foo
:
'
bar
'
}])).
toEqual
({});
expect
(
findCommonLabels
([{
baz
:
'42'
},
{
foo
:
'
bar
'
}])).
toEqual
({});
expect
(
findCommonLabels
([{
foo
:
'42'
,
baz
:
'
bar'
},
{
foo
:
'bar
'
}])).
toEqual
({});
});
it
(
'returns the single labels set as common labels'
,
()
=>
{
expect
(
findCommonLabels
([{
foo
:
'
"bar"'
}])).
toEqual
({
foo
:
'"bar"
'
});
expect
(
findCommonLabels
([{
foo
:
'
bar'
}])).
toEqual
({
foo
:
'bar
'
});
});
});
...
...
@@ -106,10 +106,10 @@ describe('mergeStreamsToLogs()', () => {
expect
(
mergeStreamsToLogs
([
stream1
]).
rows
).
toMatchObject
([
{
entry
:
'WARN boooo'
,
labels
:
'{foo="bar"}'
,
labels
:
{
foo
:
'bar'
}
,
key
:
'EK1970-01-01T00:00:00Z{foo="bar"}'
,
logLevel
:
'warning'
,
uniqueLabels
:
''
,
uniqueLabels
:
{}
,
},
]);
});
...
...
@@ -140,21 +140,21 @@ describe('mergeStreamsToLogs()', () => {
expect
(
mergeStreamsToLogs
([
stream1
,
stream2
]).
rows
).
toMatchObject
([
{
entry
:
'INFO 2'
,
labels
:
'{foo="bar", baz="2"}'
,
labels
:
{
foo
:
'bar'
,
baz
:
'2'
}
,
logLevel
:
'info'
,
uniqueLabels
:
'{baz="2"}'
,
uniqueLabels
:
{
baz
:
'2'
}
,
},
{
entry
:
'WARN boooo'
,
labels
:
'{foo="bar", baz="1"}'
,
labels
:
{
foo
:
'bar'
,
baz
:
'1'
}
,
logLevel
:
'warning'
,
uniqueLabels
:
'{baz="1"}'
,
uniqueLabels
:
{
baz
:
'1'
}
,
},
{
entry
:
'INFO 1'
,
labels
:
'{foo="bar", baz="2"}'
,
labels
:
{
foo
:
'bar'
,
baz
:
'2'
}
,
logLevel
:
'info'
,
uniqueLabels
:
'{baz="2"}'
,
uniqueLabels
:
{
baz
:
'2'
}
,
},
]);
});
...
...
public/app/plugins/datasource/logging/result_transformer.ts
View file @
8024a6aa
...
...
@@ -9,6 +9,7 @@ import {
LogsStream
,
LogsStreamEntry
,
LogsStreamLabels
,
LogsMetaKind
,
}
from
'app/core/logs_model'
;
import
{
DEFAULT_LIMIT
}
from
'./datasource'
;
...
...
@@ -40,7 +41,7 @@ export function getLogLevel(line: string): LogLevel {
/**
* Regexp to extract Prometheus-style labels
*/
const
labelRegexp
=
/
\b(\w
+
)(
!
?
=~
?)
(
"
[^
"
\n]
*
?
"
)
/g
;
const
labelRegexp
=
/
\b(\w
+
)(
!
?
=~
?)
"
([^
"
\n]
*
?)
"
/g
;
/**
* Returns a map of label keys to value from an input selector string.
...
...
@@ -104,11 +105,17 @@ export function formatLabels(labels: LogsStreamLabels, defaultValue = ''): strin
return
defaultValue
;
}
const
labelKeys
=
Object
.
keys
(
labels
).
sort
();
const
cleanSelector
=
labelKeys
.
map
(
key
=>
`
${
key
}
=
${
labels
[
key
]}
`
).
join
(
', '
);
const
cleanSelector
=
labelKeys
.
map
(
key
=>
`
${
key
}
=
"
${
labels
[
key
]}
"
`
).
join
(
', '
);
return
[
'{'
,
cleanSelector
,
'}'
].
join
(
''
);
}
export
function
processEntry
(
entry
:
LogsStreamEntry
,
labels
:
string
,
uniqueLabels
:
string
,
search
:
string
):
LogRow
{
export
function
processEntry
(
entry
:
LogsStreamEntry
,
labels
:
string
,
parsedLabels
:
LogsStreamLabels
,
uniqueLabels
:
LogsStreamLabels
,
search
:
string
):
LogRow
{
const
{
line
,
timestamp
}
=
entry
;
// Assumes unique-ness, needs nanosec precision for timestamp
const
key
=
`EK
${
timestamp
}${
labels
}
`
;
...
...
@@ -120,13 +127,13 @@ export function processEntry(entry: LogsStreamEntry, labels: string, uniqueLabel
return
{
key
,
labels
,
logLevel
,
timeFromNow
,
timeEpochMs
,
timeLocal
,
uniqueLabels
,
entry
:
line
,
labels
:
parsedLabels
,
searchWords
:
search
?
[
search
]
:
[],
timestamp
:
timestamp
,
};
...
...
@@ -141,7 +148,7 @@ export function mergeStreamsToLogs(streams: LogsStream[], limit = DEFAULT_LIMIT)
const
commonLabels
=
findCommonLabels
(
streams
.
map
(
model
=>
model
.
parsedLabels
));
streams
=
streams
.
map
(
stream
=>
({
...
stream
,
uniqueLabels
:
f
ormatLabels
(
findUniqueLabels
(
stream
.
parsedLabels
,
commonLabels
)
),
uniqueLabels
:
f
indUniqueLabels
(
stream
.
parsedLabels
,
commonLabels
),
}));
// Merge stream entries into single list of log rows
...
...
@@ -149,7 +156,9 @@ export function mergeStreamsToLogs(streams: LogsStream[], limit = DEFAULT_LIMIT)
.
reduce
(
(
acc
:
LogRow
[],
stream
:
LogsStream
)
=>
[
...
acc
,
...
stream
.
entries
.
map
(
entry
=>
processEntry
(
entry
,
stream
.
labels
,
stream
.
uniqueLabels
,
stream
.
search
)),
...
stream
.
entries
.
map
(
entry
=>
processEntry
(
entry
,
stream
.
labels
,
stream
.
parsedLabels
,
stream
.
uniqueLabels
,
stream
.
search
)
),
],
[]
)
...
...
@@ -162,13 +171,15 @@ export function mergeStreamsToLogs(streams: LogsStream[], limit = DEFAULT_LIMIT)
if
(
_
.
size
(
commonLabels
)
>
0
)
{
meta
.
push
({
label
:
'Common labels'
,
value
:
formatLabels
(
commonLabels
),
value
:
commonLabels
,
kind
:
LogsMetaKind
.
LabelsMap
,
});
}
if
(
limit
)
{
meta
.
push
({
label
:
'Limit'
,
value
:
`
${
limit
}
(
${
sortedRows
.
length
}
returned)`
,
kind
:
LogsMetaKind
.
String
,
});
}
...
...
public/app/plugins/datasource/prometheus/add_label_to_query.ts
View file @
8024a6aa
...
...
@@ -49,7 +49,7 @@ export function addLabelToQuery(query: string, key: string, value: string, opera
const
selectorWithLabel
=
addLabelToSelector
(
selector
,
key
,
value
,
operator
);
lastIndex
=
match
.
index
+
match
[
1
].
length
+
2
;
suffix
=
query
.
slice
(
match
.
index
+
match
[
0
].
length
);
parts
.
push
(
prefix
,
'{'
,
selectorWithLabel
,
'}'
);
parts
.
push
(
prefix
,
selectorWithLabel
);
match
=
selectorRegexp
.
exec
(
query
);
}
...
...
@@ -59,7 +59,7 @@ export function addLabelToQuery(query: string, key: string, value: string, opera
const
labelRegexp
=
/
(\w
+
)\s
*
(
=|!=|=~|!~
)\s
*
(
"
[^
"
]
*"
)
/g
;
function
addLabelToSelector
(
selector
:
string
,
labelKey
:
string
,
labelValue
:
string
,
labelOperator
?:
string
)
{
export
function
addLabelToSelector
(
selector
:
string
,
labelKey
:
string
,
labelValue
:
string
,
labelOperator
?:
string
)
{
const
parsedLabels
=
[];
// Split selector into labels
...
...
@@ -76,13 +76,15 @@ function addLabelToSelector(selector: string, labelKey: string, labelValue: stri
parsedLabels
.
push
({
key
:
labelKey
,
operator
:
operatorForLabelKey
,
value
:
`"
${
labelValue
}
"`
});
// Sort labels by key and put them together
return
_
.
chain
(
parsedLabels
)
const
formatted
=
_
.
chain
(
parsedLabels
)
.
uniqWith
(
_
.
isEqual
)
.
compact
()
.
sortBy
(
'key'
)
.
map
(({
key
,
operator
,
value
})
=>
`
${
key
}${
operator
}${
value
}
`
)
.
value
()
.
join
(
','
);
return
`{
${
formatted
}
}`
;
}
function
isPositionInsideChars
(
text
:
string
,
position
:
number
,
openChar
:
string
,
closeChar
:
string
)
{
...
...
public/app/plugins/datasource/prometheus/specs/add_label_to_query.test.ts
View file @
8024a6aa
import
addLabelToQuery
from
'../add_label_to_query'
;
import
{
addLabelToQuery
,
addLabelToSelector
}
from
'../add_label_to_query'
;
describe
(
'addLabelToQuery()'
,
()
=>
{
it
(
'should add label to simple query'
,
()
=>
{
...
...
@@ -56,3 +56,16 @@ describe('addLabelToQuery()', () => {
);
});
});
describe
(
'addLabelToSelector()'
,
()
=>
{
test
(
'should add a label to an empty selector'
,
()
=>
{
expect
(
addLabelToSelector
(
'{}'
,
'foo'
,
'bar'
)).
toBe
(
'{foo="bar"}'
);
expect
(
addLabelToSelector
(
''
,
'foo'
,
'bar'
)).
toBe
(
'{foo="bar"}'
);
});
test
(
'should add a label to a selector'
,
()
=>
{
expect
(
addLabelToSelector
(
'{foo="bar"}'
,
'baz'
,
'42'
)).
toBe
(
'{baz="42",foo="bar"}'
);
});
test
(
'should add a label to a selector with custom operator'
,
()
=>
{
expect
(
addLabelToSelector
(
'{}'
,
'baz'
,
'42'
,
'!='
)).
toBe
(
'{baz!="42"}'
);
});
});
public/sass/pages/_explore.scss
View file @
8024a6aa
...
...
@@ -261,6 +261,8 @@
border-radius
:
$border-radius
;
margin
:
2
*
$panel-margin
0
;
border
:
$panel-border
;
justify-items
:
flex-start
;
align-items
:
flex-start
;
>
*
{
margin-right
:
1em
;
...
...
@@ -276,11 +278,11 @@
.logs-meta
{
flex
:
1
;
color
:
$text-color-weak
;
padding
:
2px
0
;
// Align first line with controls labels
margin-top
:
-2px
;
}
.logs-meta-item
{
display
:
inline-block
;
margin-right
:
1em
;
}
...
...
@@ -294,6 +296,12 @@
font-family
:
$font-family-monospace
;
}
.logs-meta-item__value-labels
{
// compensate for the labels padding
position
:
relative
;
top
:
4px
;
}
.logs-row-match-highlight
{
// Undoing mark styling
background
:
inherit
;
...
...
@@ -356,6 +364,25 @@
background-color
:
#1f78c1
;
margin
:
0
1px
1px
0
;
}
.logs-label
{
display
:
inline-block
;
padding
:
0
2px
;
background-color
:
$btn-inverse-bg
;
border-radius
:
$border-radius
;
margin-right
:
4px
;
overflow
:
hidden
;
text-overflow
:
ellipsis
;
white-space
:
nowrap
;
}
.logs-row-labels
{
line-height
:
1
.2
;
.logs-label
{
cursor
:
pointer
;
}
}
}
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment