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
c3692794
Commit
c3692794
authored
Jan 22, 2019
by
Hugo Häggmark
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Splitted up LogLabels into LogLabelStats and LogLabel
parent
23202ab1
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
165 additions
and
145 deletions
+165
-145
public/app/core/logs_model.ts
+3
-3
public/app/features/explore/LogLabel.tsx
+74
-0
public/app/features/explore/LogLabelStats.tsx
+72
-0
public/app/features/explore/LogLabels.tsx
+7
-134
public/app/features/explore/LogRow.tsx
+8
-7
public/app/features/explore/Logs.tsx
+1
-1
No files found.
public/app/core/logs_model.ts
View file @
c3692794
...
...
@@ -56,7 +56,7 @@ export interface LogRowModel {
uniqueLabels
?:
LogsStreamLabels
;
}
export
interface
Log
sLabelStat
{
export
interface
Log
LabelStatsModel
{
active
?:
boolean
;
count
:
number
;
proportion
:
number
;
...
...
@@ -188,7 +188,7 @@ export const LogsParsers: { [name: string]: LogsParser } = {
},
};
export
function
calculateFieldStats
(
rows
:
LogRowModel
[],
extractor
:
RegExp
):
Log
sLabelStat
[]
{
export
function
calculateFieldStats
(
rows
:
LogRowModel
[],
extractor
:
RegExp
):
Log
LabelStatsModel
[]
{
// Consider only rows that satisfy the matcher
const
rowsWithField
=
rows
.
filter
(
row
=>
extractor
.
test
(
row
.
entry
));
const
rowCount
=
rowsWithField
.
length
;
...
...
@@ -204,7 +204,7 @@ export function calculateFieldStats(rows: LogRowModel[], extractor: RegExp): Log
return
sortedCounts
;
}
export
function
calculateLogsLabelStats
(
rows
:
LogRowModel
[],
label
:
string
):
Log
sLabelStat
[]
{
export
function
calculateLogsLabelStats
(
rows
:
LogRowModel
[],
label
:
string
):
Log
LabelStatsModel
[]
{
// Consider only rows that have the given label
const
rowsWithLabel
=
rows
.
filter
(
row
=>
row
.
labels
[
label
]
!==
undefined
);
const
rowCount
=
rowsWithLabel
.
length
;
...
...
public/app/features/explore/LogLabel.tsx
0 → 100644
View file @
c3692794
import
React
,
{
PureComponent
}
from
'react'
;
import
{
calculateLogsLabelStats
,
LogLabelStatsModel
,
LogRowModel
}
from
'app/core/logs_model'
;
import
{
LogLabelStats
}
from
'./LogLabelStats'
;
interface
Props
{
getRows
?:
()
=>
LogRowModel
[];
label
:
string
;
plain
?:
boolean
;
value
:
string
;
onClickLabel
?:
(
label
:
string
,
value
:
string
)
=>
void
;
}
interface
State
{
showStats
:
boolean
;
stats
:
LogLabelStatsModel
[];
}
export
class
LogLabel
extends
PureComponent
<
Props
,
State
>
{
state
=
{
stats
:
null
,
showStats
:
false
,
};
onClickClose
=
()
=>
{
this
.
setState
({
showStats
:
false
});
};
onClickLabel
=
()
=>
{
const
{
onClickLabel
,
label
,
value
}
=
this
.
props
;
if
(
onClickLabel
)
{
onClickLabel
(
label
,
value
);
}
};
onClickStats
=
()
=>
{
this
.
setState
(
state
=>
{
if
(
state
.
showStats
)
{
return
{
showStats
:
false
,
stats
:
null
};
}
const
allRows
=
this
.
props
.
getRows
();
const
stats
=
calculateLogsLabelStats
(
allRows
,
this
.
props
.
label
);
return
{
showStats
:
true
,
stats
};
});
};
render
()
{
const
{
getRows
,
label
,
plain
,
value
}
=
this
.
props
;
const
{
showStats
,
stats
}
=
this
.
state
;
const
tooltip
=
`
${
label
}
:
${
value
}
`
;
return
(
<
span
className=
"logs-label"
>
<
span
className=
"logs-label__value"
title=
{
tooltip
}
>
{
value
}
</
span
>
{
!
plain
&&
(
<
span
title=
"Filter for label"
onClick=
{
this
.
onClickLabel
}
className=
"logs-label__icon fa fa-search-plus"
/>
)
}
{
!
plain
&&
getRows
&&
<
span
onClick=
{
this
.
onClickStats
}
className=
"logs-label__icon fa fa-signal"
/>
}
{
showStats
&&
(
<
span
className=
"logs-label__stats"
>
<
LogLabelStats
stats=
{
stats
}
rowCount=
{
getRows
().
length
}
label=
{
label
}
value=
{
value
}
onClickClose=
{
this
.
onClickClose
}
/>
</
span
>
)
}
</
span
>
);
}
}
public/app/features/explore/LogLabelStats.tsx
0 → 100644
View file @
c3692794
import
React
,
{
PureComponent
}
from
'react'
;
import
classnames
from
'classnames'
;
import
{
LogLabelStatsModel
}
from
'app/core/logs_model'
;
function
LogLabelStatsRow
(
logLabelStatsModel
:
LogLabelStatsModel
)
{
const
{
active
,
count
,
proportion
,
value
}
=
logLabelStatsModel
;
const
percent
=
`
${
Math
.
round
(
proportion
*
100
)}
%`
;
const
barStyle
=
{
width
:
percent
};
const
className
=
classnames
(
'logs-stats-row'
,
{
'logs-stats-row--active'
:
active
});
return
(
<
div
className=
{
className
}
>
<
div
className=
"logs-stats-row__label"
>
<
div
className=
"logs-stats-row__value"
>
{
value
}
</
div
>
<
div
className=
"logs-stats-row__count"
>
{
count
}
</
div
>
<
div
className=
"logs-stats-row__percent"
>
{
percent
}
</
div
>
</
div
>
<
div
className=
"logs-stats-row__bar"
>
<
div
className=
"logs-stats-row__innerbar"
style=
{
barStyle
}
/>
</
div
>
</
div
>
);
}
const
STATS_ROW_LIMIT
=
5
;
interface
Props
{
stats
:
LogLabelStatsModel
[];
label
:
string
;
value
:
string
;
rowCount
:
number
;
onClickClose
:
()
=>
void
;
}
export
class
LogLabelStats
extends
PureComponent
<
Props
>
{
render
()
{
const
{
label
,
rowCount
,
stats
,
value
,
onClickClose
}
=
this
.
props
;
const
topRows
=
stats
.
slice
(
0
,
STATS_ROW_LIMIT
);
let
activeRow
=
topRows
.
find
(
row
=>
row
.
value
===
value
);
let
otherRows
=
stats
.
slice
(
STATS_ROW_LIMIT
);
const
insertActiveRow
=
!
activeRow
;
// Remove active row from other to show extra
if
(
insertActiveRow
)
{
activeRow
=
otherRows
.
find
(
row
=>
row
.
value
===
value
);
otherRows
=
otherRows
.
filter
(
row
=>
row
.
value
!==
value
);
}
const
otherCount
=
otherRows
.
reduce
((
sum
,
row
)
=>
sum
+
row
.
count
,
0
);
const
topCount
=
topRows
.
reduce
((
sum
,
row
)
=>
sum
+
row
.
count
,
0
);
const
total
=
topCount
+
otherCount
;
const
otherProportion
=
otherCount
/
total
;
return
(
<
div
className=
"logs-stats"
>
<
div
className=
"logs-stats__header"
>
<
span
className=
"logs-stats__title"
>
{
label
}
:
{
total
}
of
{
rowCount
}
rows have that label
</
span
>
<
span
className=
"logs-stats__close fa fa-remove"
onClick=
{
onClickClose
}
/>
</
div
>
<
div
className=
"logs-stats__body"
>
{
topRows
.
map
(
stat
=>
<
LogLabelStatsRow
key=
{
stat
.
value
}
{
...
stat
}
active=
{
stat
.
value
===
value
}
/>)
}
{
insertActiveRow
&&
activeRow
&&
<
LogLabelStatsRow
key=
{
activeRow
.
value
}
{
...
activeRow
}
active
/>
}
{
otherCount
>
0
&&
(
<
LogLabelStatsRow
key=
"__OTHERS__"
count=
{
otherCount
}
value=
"Other"
proportion=
{
otherProportion
}
/>
)
}
</
div
>
</
div
>
);
}
}
public/app/features/explore/LogLabels.tsx
View file @
c3692794
import
React
,
{
PureComponent
}
from
'react'
;
import
classnames
from
'classnames'
;
import
{
calculateLogsLabelStats
,
LogsLabelStat
,
LogsStreamLabels
,
LogRowModel
}
from
'app/core/logs_model'
;
import
{
LogsStreamLabels
,
LogRowModel
}
from
'app/core/logs_model'
;
import
{
LogLabel
}
from
'./LogLabel'
;
function
StatsRow
({
active
,
count
,
proportion
,
value
}:
LogsLabelStat
)
{
const
percent
=
`
${
Math
.
round
(
proportion
*
100
)}
%`
;
const
barStyle
=
{
width
:
percent
};
const
className
=
classnames
(
'logs-stats-row'
,
{
'logs-stats-row--active'
:
active
});
return
(
<
div
className=
{
className
}
>
<
div
className=
"logs-stats-row__label"
>
<
div
className=
"logs-stats-row__value"
>
{
value
}
</
div
>
<
div
className=
"logs-stats-row__count"
>
{
count
}
</
div
>
<
div
className=
"logs-stats-row__percent"
>
{
percent
}
</
div
>
</
div
>
<
div
className=
"logs-stats-row__bar"
>
<
div
className=
"logs-stats-row__innerbar"
style=
{
barStyle
}
/>
</
div
>
</
div
>
);
}
const
STATS_ROW_LIMIT
=
5
;
export
class
Stats
extends
PureComponent
<
{
stats
:
LogsLabelStat
[];
label
:
string
;
value
:
string
;
rowCount
:
number
;
onClickClose
:
()
=>
void
;
}
>
{
render
()
{
const
{
label
,
rowCount
,
stats
,
value
,
onClickClose
}
=
this
.
props
;
const
topRows
=
stats
.
slice
(
0
,
STATS_ROW_LIMIT
);
let
activeRow
=
topRows
.
find
(
row
=>
row
.
value
===
value
);
let
otherRows
=
stats
.
slice
(
STATS_ROW_LIMIT
);
const
insertActiveRow
=
!
activeRow
;
// Remove active row from other to show extra
if
(
insertActiveRow
)
{
activeRow
=
otherRows
.
find
(
row
=>
row
.
value
===
value
);
otherRows
=
otherRows
.
filter
(
row
=>
row
.
value
!==
value
);
}
const
otherCount
=
otherRows
.
reduce
((
sum
,
row
)
=>
sum
+
row
.
count
,
0
);
const
topCount
=
topRows
.
reduce
((
sum
,
row
)
=>
sum
+
row
.
count
,
0
);
const
total
=
topCount
+
otherCount
;
const
otherProportion
=
otherCount
/
total
;
return
(
<
div
className=
"logs-stats"
>
<
div
className=
"logs-stats__header"
>
<
span
className=
"logs-stats__title"
>
{
label
}
:
{
total
}
of
{
rowCount
}
rows have that label
</
span
>
<
span
className=
"logs-stats__close fa fa-remove"
onClick=
{
onClickClose
}
/>
</
div
>
<
div
className=
"logs-stats__body"
>
{
topRows
.
map
(
stat
=>
<
StatsRow
key=
{
stat
.
value
}
{
...
stat
}
active=
{
stat
.
value
===
value
}
/>)
}
{
insertActiveRow
&&
activeRow
&&
<
StatsRow
key=
{
activeRow
.
value
}
{
...
activeRow
}
active
/>
}
{
otherCount
>
0
&&
(
<
StatsRow
key=
"__OTHERS__"
count=
{
otherCount
}
value=
"Other"
proportion=
{
otherProportion
}
/>
)
}
</
div
>
</
div
>
);
}
}
class
Label
extends
PureComponent
<
{
getRows
?:
()
=>
LogRowModel
[];
label
:
string
;
plain
?:
boolean
;
value
:
string
;
onClickLabel
?:
(
label
:
string
,
value
:
string
)
=>
void
;
},
{
showStats
:
boolean
;
stats
:
LogsLabelStat
[]
}
>
{
state
=
{
stats
:
null
,
showStats
:
false
,
};
onClickClose
=
()
=>
{
this
.
setState
({
showStats
:
false
});
};
onClickLabel
=
()
=>
{
const
{
onClickLabel
,
label
,
value
}
=
this
.
props
;
if
(
onClickLabel
)
{
onClickLabel
(
label
,
value
);
}
};
onClickStats
=
()
=>
{
this
.
setState
(
state
=>
{
if
(
state
.
showStats
)
{
return
{
showStats
:
false
,
stats
:
null
};
}
const
allRows
=
this
.
props
.
getRows
();
const
stats
=
calculateLogsLabelStats
(
allRows
,
this
.
props
.
label
);
return
{
showStats
:
true
,
stats
};
});
};
render
()
{
const
{
getRows
,
label
,
plain
,
value
}
=
this
.
props
;
const
{
showStats
,
stats
}
=
this
.
state
;
const
tooltip
=
`
${
label
}
:
${
value
}
`
;
return
(
<
span
className=
"logs-label"
>
<
span
className=
"logs-label__value"
title=
{
tooltip
}
>
{
value
}
</
span
>
{
!
plain
&&
(
<
span
title=
"Filter for label"
onClick=
{
this
.
onClickLabel
}
className=
"logs-label__icon fa fa-search-plus"
/>
)
}
{
!
plain
&&
getRows
&&
<
span
onClick=
{
this
.
onClickStats
}
className=
"logs-label__icon fa fa-signal"
/>
}
{
showStats
&&
(
<
span
className=
"logs-label__stats"
>
<
Stats
stats=
{
stats
}
rowCount=
{
getRows
().
length
}
label=
{
label
}
value=
{
value
}
onClickClose=
{
this
.
onClickClose
}
/>
</
span
>
)
}
</
span
>
);
}
}
export
default
class
LogLabels
extends
PureComponent
<
{
interface
Props
{
getRows
?:
()
=>
LogRowModel
[];
labels
:
LogsStreamLabels
;
plain
?:
boolean
;
onClickLabel
?:
(
label
:
string
,
value
:
string
)
=>
void
;
}
>
{
}
export
class
LogLabels
extends
PureComponent
<
Props
>
{
render
()
{
const
{
getRows
,
labels
,
onClickLabel
,
plain
}
=
this
.
props
;
return
Object
.
keys
(
labels
).
map
(
key
=>
(
<
Label
key=
{
key
}
getRows=
{
getRows
}
label=
{
key
}
value=
{
labels
[
key
]
}
plain=
{
plain
}
onClickLabel=
{
onClickLabel
}
/>
<
L
ogL
abel
key=
{
key
}
getRows=
{
getRows
}
label=
{
key
}
value=
{
labels
[
key
]
}
plain=
{
plain
}
onClickLabel=
{
onClickLabel
}
/>
));
}
}
public/app/features/explore/LogRow.tsx
View file @
c3692794
...
...
@@ -3,11 +3,12 @@ import _ from 'lodash';
import
Highlighter
from
'react-highlight-words'
;
import
classnames
from
'classnames'
;
import
{
LogRowModel
,
Log
sLabelStat
,
LogsParser
,
calculateFieldStats
,
getParser
}
from
'app/core/logs_model'
;
import
LogLabels
,
{
Stat
s
}
from
'./LogLabels'
;
import
{
LogRowModel
,
Log
LabelStatsModel
,
LogsParser
,
calculateFieldStats
,
getParser
}
from
'app/core/logs_model'
;
import
{
LogLabel
s
}
from
'./LogLabels'
;
import
{
findHighlightChunksInText
}
from
'app/core/utils/text'
;
import
{
LogLabelStats
}
from
'./LogLabelStats'
;
interface
Row
Props
{
interface
Props
{
highlighterExpressions
?:
string
[];
row
:
LogRowModel
;
showDuplicates
:
boolean
;
...
...
@@ -18,10 +19,10 @@ interface RowProps {
onClickLabel
?:
(
label
:
string
,
value
:
string
)
=>
void
;
}
interface
Row
State
{
interface
State
{
fieldCount
:
number
;
fieldLabel
:
string
;
fieldStats
:
Log
sLabelStat
[];
fieldStats
:
Log
LabelStatsModel
[];
fieldValue
:
string
;
parsed
:
boolean
;
parser
?:
LogsParser
;
...
...
@@ -49,7 +50,7 @@ const FieldHighlight = onClick => props => {
* Once a parser is found, it will determine fields, that will be highlighted.
* When the user requests stats for a field, they will be calculated and rendered below the row.
*/
export
class
LogRow
extends
PureComponent
<
RowProps
,
Row
State
>
{
export
class
LogRow
extends
PureComponent
<
Props
,
State
>
{
mouseMessageTimer
:
NodeJS
.
Timer
;
state
=
{
...
...
@@ -177,7 +178,7 @@ export class LogRow extends PureComponent<RowProps, RowState> {
{
!
parsed
&&
!
needsHighlighter
&&
row
.
entry
}
{
showFieldStats
&&
(
<
div
className=
"logs-row__stats"
>
<
Stats
<
LogLabel
Stats
stats=
{
fieldStats
}
label=
{
fieldLabel
}
value=
{
fieldValue
}
...
...
public/app/features/explore/Logs.tsx
View file @
c3692794
...
...
@@ -17,7 +17,7 @@ import { Switch } from 'app/core/components/Switch/Switch';
import
ToggleButtonGroup
,
{
ToggleButton
}
from
'app/core/components/ToggleButtonGroup/ToggleButtonGroup'
;
import
Graph
from
'./Graph'
;
import
LogLabels
from
'./LogLabels'
;
import
{
LogLabels
}
from
'./LogLabels'
;
import
{
LogRow
}
from
'./LogRow'
;
const
PREVIEW_LIMIT
=
100
;
...
...
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