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
842dde3d
Unverified
Commit
842dde3d
authored
Dec 16, 2019
by
Ivana Huckova
Committed by
GitHub
Dec 16, 2019
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Explore: Refactor log rows (#21066)
parent
71382ae7
Hide whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
300 additions
and
227 deletions
+300
-227
packages/grafana-ui/src/components/Logs/LogDetails.test.tsx
+1
-0
packages/grafana-ui/src/components/Logs/LogDetails.tsx
+107
-58
packages/grafana-ui/src/components/Logs/LogDetailsRow.tsx
+5
-1
packages/grafana-ui/src/components/Logs/LogLabels.tsx
+1
-1
packages/grafana-ui/src/components/Logs/LogRow.tsx
+85
-57
packages/grafana-ui/src/components/Logs/LogRowMessage.tsx
+2
-2
packages/grafana-ui/src/components/Logs/LogRows.tsx
+49
-43
packages/grafana-ui/src/components/Logs/getLogRowStyles.ts
+14
-31
public/app/features/explore/LiveLogs.tsx
+36
-34
No files found.
packages/grafana-ui/src/components/Logs/LogDetails.test.tsx
View file @
842dde3d
...
@@ -7,6 +7,7 @@ import { LogDetailsRow } from './LogDetailsRow';
...
@@ -7,6 +7,7 @@ import { LogDetailsRow } from './LogDetailsRow';
const
setup
=
(
propOverrides
?:
Partial
<
Props
>
,
rowOverrides
?:
Partial
<
LogRowModel
>
)
=>
{
const
setup
=
(
propOverrides
?:
Partial
<
Props
>
,
rowOverrides
?:
Partial
<
LogRowModel
>
)
=>
{
const
props
:
Props
=
{
const
props
:
Props
=
{
theme
:
{}
as
GrafanaTheme
,
theme
:
{}
as
GrafanaTheme
,
showDuplicates
:
false
,
row
:
{
row
:
{
dataFrame
:
new
MutableDataFrame
(),
dataFrame
:
new
MutableDataFrame
(),
entryFieldIndex
:
0
,
entryFieldIndex
:
0
,
...
...
packages/grafana-ui/src/components/Logs/LogDetails.tsx
View file @
842dde3d
import
React
,
{
PureComponent
}
from
'react'
;
import
React
,
{
PureComponent
}
from
'react'
;
import
memoizeOne
from
'memoize-one'
;
import
memoizeOne
from
'memoize-one'
;
import
{
css
,
cx
}
from
'emotion'
;
import
{
import
{
calculateFieldStats
,
calculateFieldStats
,
calculateLogsLabelStats
,
calculateLogsLabelStats
,
...
@@ -8,11 +9,14 @@ import {
...
@@ -8,11 +9,14 @@ import {
getParser
,
getParser
,
LinkModel
,
LinkModel
,
LogRowModel
,
LogRowModel
,
GrafanaTheme
,
}
from
'@grafana/data'
;
}
from
'@grafana/data'
;
import
{
Themeable
}
from
'../../types/theme'
;
import
{
Themeable
}
from
'../../types/theme'
;
import
{
withTheme
}
from
'../../themes/index'
;
import
{
withTheme
}
from
'../../themes/index'
;
import
{
getLogRowStyles
}
from
'./getLogRowStyles'
;
import
{
getLogRowStyles
}
from
'./getLogRowStyles'
;
import
{
stylesFactory
}
from
'../../themes/stylesFactory'
;
import
{
selectThemeVariant
}
from
'../../themes/selectThemeVariant'
;
//Components
//Components
import
{
LogDetailsRow
}
from
'./LogDetailsRow'
;
import
{
LogDetailsRow
}
from
'./LogDetailsRow'
;
...
@@ -26,12 +30,36 @@ type FieldDef = {
...
@@ -26,12 +30,36 @@ type FieldDef = {
export
interface
Props
extends
Themeable
{
export
interface
Props
extends
Themeable
{
row
:
LogRowModel
;
row
:
LogRowModel
;
showDuplicates
:
boolean
;
getRows
:
()
=>
LogRowModel
[];
getRows
:
()
=>
LogRowModel
[];
className
?:
string
;
onMouseEnter
?:
()
=>
void
;
onMouseLeave
?:
()
=>
void
;
onClickFilterLabel
?:
(
key
:
string
,
value
:
string
)
=>
void
;
onClickFilterLabel
?:
(
key
:
string
,
value
:
string
)
=>
void
;
onClickFilterOutLabel
?:
(
key
:
string
,
value
:
string
)
=>
void
;
onClickFilterOutLabel
?:
(
key
:
string
,
value
:
string
)
=>
void
;
getFieldLinks
?:
(
field
:
Field
,
rowIndex
:
number
)
=>
Array
<
LinkModel
<
Field
>>
;
getFieldLinks
?:
(
field
:
Field
,
rowIndex
:
number
)
=>
Array
<
LinkModel
<
Field
>>
;
}
}
const
getStyles
=
stylesFactory
((
theme
:
GrafanaTheme
)
=>
{
const
bgColor
=
selectThemeVariant
({
light
:
theme
.
colors
.
gray7
,
dark
:
theme
.
colors
.
dark2
},
theme
.
type
);
return
{
hoverBackground
:
css
`
label: hoverBackground;
background-color:
${
bgColor
}
;
`
,
logsRowLevelDetails
:
css
`
label: logs-row__level_details;
&::after {
top: -3px;
}
`
,
logDetailsDefaultCursor
:
css
`
label: logDetailsDefaultCursor;
cursor: default;
`
,
};
});
class
UnThemedLogDetails
extends
PureComponent
<
Props
>
{
class
UnThemedLogDetails
extends
PureComponent
<
Props
>
{
getParser
=
memoizeOne
(
getParser
);
getParser
=
memoizeOne
(
getParser
);
...
@@ -102,72 +130,93 @@ class UnThemedLogDetails extends PureComponent<Props> {
...
@@ -102,72 +130,93 @@ class UnThemedLogDetails extends PureComponent<Props> {
};
};
render
()
{
render
()
{
const
{
row
,
theme
,
onClickFilterOutLabel
,
onClickFilterLabel
,
getRows
}
=
this
.
props
;
const
{
row
,
theme
,
onClickFilterOutLabel
,
onClickFilterLabel
,
getRows
,
showDuplicates
,
className
,
onMouseEnter
,
onMouseLeave
,
}
=
this
.
props
;
const
style
=
getLogRowStyles
(
theme
,
row
.
logLevel
);
const
style
=
getLogRowStyles
(
theme
,
row
.
logLevel
);
const
styles
=
getStyles
(
theme
);
const
labels
=
row
.
labels
?
row
.
labels
:
{};
const
labels
=
row
.
labels
?
row
.
labels
:
{};
const
labelsAvailable
=
Object
.
keys
(
labels
).
length
>
0
;
const
labelsAvailable
=
Object
.
keys
(
labels
).
length
>
0
;
const
fields
=
this
.
getAllFields
(
row
);
const
fields
=
this
.
getAllFields
(
row
);
const
parsedFieldsAvailable
=
fields
&&
fields
.
length
>
0
;
const
parsedFieldsAvailable
=
fields
&&
fields
.
length
>
0
;
return
(
return
(
<
div
className=
{
style
.
logDetailsContainer
}
>
<
tr
<
table
className=
{
style
.
logDetailsTable
}
>
className=
{
cx
(
className
,
styles
.
logDetailsDefaultCursor
)
}
<
tbody
>
onMouseEnter=
{
onMouseEnter
}
{
labelsAvailable
&&
(
onMouseLeave=
{
onMouseLeave
}
<
tr
>
>
<
td
colSpan=
{
5
}
className=
{
style
.
logDetailsHeading
}
aria
-
label=
"Log Labels"
>
{
showDuplicates
&&
<
td
/>
}
Log Labels:
<
td
className=
{
cx
(
style
.
logsRowLevel
,
styles
.
logsRowLevelDetails
)
}
/>
</
td
>
<
td
colSpan=
{
4
}
>
</
tr
>
<
div
className=
{
style
.
logDetailsContainer
}
>
)
}
<
table
className=
{
style
.
logDetailsTable
}
>
{
Object
.
keys
(
labels
).
map
(
key
=>
{
<
tbody
>
const
value
=
labels
[
key
];
{
labelsAvailable
&&
(
return
(
<
tr
>
<
LogDetailsRow
<
td
colSpan=
{
5
}
className=
{
style
.
logDetailsHeading
}
aria
-
label=
"Log Labels"
>
key=
{
`${key}=${value}`
}
Log Labels:
parsedKey=
{
key
}
</
td
>
parsedValue=
{
value
}
</
tr
>
isLabel=
{
true
}
)
}
getStats=
{
()
=>
calculateLogsLabelStats
(
getRows
(),
key
)
}
{
Object
.
keys
(
labels
).
map
(
key
=>
{
onClickFilterOutLabel=
{
onClickFilterOutLabel
}
const
value
=
labels
[
key
];
onClickFilterLabel=
{
onClickFilterLabel
}
return
(
/>
<
LogDetailsRow
);
key=
{
`${key}=${value}`
}
})
}
parsedKey=
{
key
}
parsedValue=
{
value
}
isLabel=
{
true
}
getStats=
{
()
=>
calculateLogsLabelStats
(
getRows
(),
key
)
}
onClickFilterOutLabel=
{
onClickFilterOutLabel
}
onClickFilterLabel=
{
onClickFilterLabel
}
/>
);
})
}
{
parsedFieldsAvailable
&&
(
{
parsedFieldsAvailable
&&
(
<
tr
>
<
tr
>
<
td
colSpan=
{
5
}
className=
{
style
.
logDetailsHeading
}
aria
-
label=
"Parsed Fields"
>
<
td
colSpan=
{
5
}
className=
{
style
.
logDetailsHeading
}
aria
-
label=
"Parsed Fields"
>
Parsed Fields:
Parsed Fields:
</
td
>
</
td
>
</
tr
>
</
tr
>
)
}
)
}
{
fields
.
map
(
field
=>
{
{
fields
.
map
(
field
=>
{
const
{
key
,
value
,
links
,
fieldIndex
}
=
field
;
const
{
key
,
value
,
links
,
fieldIndex
}
=
field
;
return
(
return
(
<
LogDetailsRow
<
LogDetailsRow
key=
{
`${key}=${value}`
}
key=
{
`${key}=${value}`
}
parsedKey=
{
key
}
parsedKey=
{
key
}
parsedValue=
{
value
}
parsedValue=
{
value
}
links=
{
links
}
links=
{
links
}
getStats=
{
()
=>
getStats=
{
()
=>
fieldIndex
===
undefined
fieldIndex
===
undefined
?
this
.
getStatsForParsedField
(
key
)
?
this
.
getStatsForParsedField
(
key
)
:
calculateStats
(
row
.
dataFrame
.
fields
[
fieldIndex
].
values
.
toArray
())
:
calculateStats
(
row
.
dataFrame
.
fields
[
fieldIndex
].
values
.
toArray
())
}
}
/>
/>
);
);
})
}
})
}
{
!
parsedFieldsAvailable
&&
!
labelsAvailable
&&
(
{
!
parsedFieldsAvailable
&&
!
labelsAvailable
&&
(
<
tr
>
<
tr
>
<
td
colSpan=
{
5
}
aria
-
label=
"No details"
>
<
td
colSpan=
{
5
}
aria
-
label=
"No details"
>
No details available
No details available
</
td
>
</
td
>
</
tr
>
</
tr
>
)
}
)
}
</
tbody
>
</
tbody
>
</
table
>
</
table
>
</
div
>
</
div
>
</
td
>
</
tr
>
);
);
}
}
}
}
...
...
packages/grafana-ui/src/components/Logs/LogDetailsRow.tsx
View file @
842dde3d
...
@@ -38,6 +38,10 @@ const getStyles = stylesFactory((theme: GrafanaTheme) => {
...
@@ -38,6 +38,10 @@ const getStyles = stylesFactory((theme: GrafanaTheme) => {
label: hoverCursor;
label: hoverCursor;
cursor: pointer;
cursor: pointer;
`
,
`
,
wordBreakAll
:
css
`
label: wordBreakAll;
word-break: break-all;
`
,
};
};
});
});
...
@@ -102,7 +106,7 @@ class UnThemedLogDetailsRow extends PureComponent<Props, State> {
...
@@ -102,7 +106,7 @@ class UnThemedLogDetailsRow extends PureComponent<Props, State> {
{
/* Key - value columns */
}
{
/* Key - value columns */
}
<
td
className=
{
style
.
logDetailsLabel
}
>
{
parsedKey
}
</
td
>
<
td
className=
{
style
.
logDetailsLabel
}
>
{
parsedKey
}
</
td
>
<
td
className=
{
style
.
logsRowCe
ll
}
>
<
td
className=
{
style
s
.
wordBreakA
ll
}
>
{
parsedValue
}
{
parsedValue
}
{
links
&&
{
links
&&
links
.
map
(
link
=>
{
links
.
map
(
link
=>
{
...
...
packages/grafana-ui/src/components/Logs/LogLabels.tsx
View file @
842dde3d
...
@@ -24,7 +24,7 @@ const getStyles = stylesFactory((theme: GrafanaTheme) => {
...
@@ -24,7 +24,7 @@ const getStyles = stylesFactory((theme: GrafanaTheme) => {
padding: 0 2px;
padding: 0 2px;
background-color:
${
selectThemeVariant
({
light
:
theme
.
colors
.
gray5
,
dark
:
theme
.
colors
.
dark6
},
theme
.
type
)}
;
background-color:
${
selectThemeVariant
({
light
:
theme
.
colors
.
gray5
,
dark
:
theme
.
colors
.
dark6
},
theme
.
type
)}
;
border-radius:
${
theme
.
border
.
radius
}
;
border-radius:
${
theme
.
border
.
radius
}
;
margin:
0 4px 2px
0;
margin:
1px 4px 0
0;
text-overflow: ellipsis;
text-overflow: ellipsis;
white-space: nowrap;
white-space: nowrap;
overflow: hidden;
overflow: hidden;
...
...
packages/grafana-ui/src/components/Logs/LogRow.tsx
View file @
842dde3d
...
@@ -12,6 +12,7 @@ import { Themeable } from '../../types/theme';
...
@@ -12,6 +12,7 @@ import { Themeable } from '../../types/theme';
import
{
withTheme
}
from
'../../themes/index'
;
import
{
withTheme
}
from
'../../themes/index'
;
import
{
getLogRowStyles
}
from
'./getLogRowStyles'
;
import
{
getLogRowStyles
}
from
'./getLogRowStyles'
;
import
{
stylesFactory
}
from
'../../themes/stylesFactory'
;
import
{
stylesFactory
}
from
'../../themes/stylesFactory'
;
import
{
selectThemeVariant
}
from
'../../themes/selectThemeVariant'
;
//Components
//Components
import
{
LogDetails
}
from
'./LogDetails'
;
import
{
LogDetails
}
from
'./LogDetails'
;
...
@@ -38,14 +39,20 @@ interface Props extends Themeable {
...
@@ -38,14 +39,20 @@ interface Props extends Themeable {
interface
State
{
interface
State
{
showContext
:
boolean
;
showContext
:
boolean
;
showDetails
:
boolean
;
showDetails
:
boolean
;
hasHoverBackground
:
boolean
;
}
}
const
getStyles
=
stylesFactory
((
theme
:
GrafanaTheme
)
=>
{
const
getStyles
=
stylesFactory
((
theme
:
GrafanaTheme
)
=>
{
const
bgColor
=
selectThemeVariant
({
light
:
theme
.
colors
.
gray7
,
dark
:
theme
.
colors
.
dark2
},
theme
.
type
);
return
{
return
{
topVerticalAlign
:
css
`
topVerticalAlign
:
css
`
label: topVerticalAlign;
label: topVerticalAlign;
vertical-align: top;
vertical-align: top;
`
,
`
,
hoverBackground
:
css
`
label: hoverBackground;
background-color:
${
bgColor
}
;
`
,
};
};
});
});
/**
/**
...
@@ -59,6 +66,7 @@ class UnThemedLogRow extends PureComponent<Props, State> {
...
@@ -59,6 +66,7 @@ class UnThemedLogRow extends PureComponent<Props, State> {
state
:
State
=
{
state
:
State
=
{
showContext
:
false
,
showContext
:
false
,
showDetails
:
false
,
showDetails
:
false
,
hasHoverBackground
:
false
,
};
};
toggleContext
=
()
=>
{
toggleContext
=
()
=>
{
...
@@ -69,6 +77,22 @@ class UnThemedLogRow extends PureComponent<Props, State> {
...
@@ -69,6 +77,22 @@ class UnThemedLogRow extends PureComponent<Props, State> {
});
});
};
};
/**
* We are using onMouse events to change background of Log Details Table to hover-state-background when
* hovered over Log Row and vice versa. This can't be done with css because we use 2 separate table rows without common parent element.
*/
addHoverBackground
=
()
=>
{
this
.
setState
({
hasHoverBackground
:
true
,
});
};
clearHoverBackground
=
()
=>
{
this
.
setState
({
hasHoverBackground
:
false
,
});
};
toggleDetails
=
()
=>
{
toggleDetails
=
()
=>
{
if
(
this
.
props
.
allowDetails
)
{
if
(
this
.
props
.
allowDetails
)
{
return
;
return
;
...
@@ -101,72 +125,76 @@ class UnThemedLogRow extends PureComponent<Props, State> {
...
@@ -101,72 +125,76 @@ class UnThemedLogRow extends PureComponent<Props, State> {
theme
,
theme
,
getFieldLinks
,
getFieldLinks
,
}
=
this
.
props
;
}
=
this
.
props
;
const
{
showDetails
,
showContext
}
=
this
.
state
;
const
{
showDetails
,
showContext
,
hasHoverBackground
}
=
this
.
state
;
const
style
=
getLogRowStyles
(
theme
,
row
.
logLevel
);
const
style
=
getLogRowStyles
(
theme
,
row
.
logLevel
);
const
styles
=
getStyles
(
theme
);
const
styles
=
getStyles
(
theme
);
const
showUtc
=
timeZone
===
'utc'
;
const
showUtc
=
timeZone
===
'utc'
;
const
showDetailsClassName
=
showDetails
const
showDetailsClassName
=
showDetails
?
cx
([
'fa fa-chevron-down'
,
styles
.
topVerticalAlign
])
?
cx
([
'fa fa-chevron-down'
,
styles
.
topVerticalAlign
])
:
cx
([
'fa fa-chevron-right'
,
styles
.
topVerticalAlign
]);
:
cx
([
'fa fa-chevron-right'
,
styles
.
topVerticalAlign
]);
const
hoverBackground
=
cx
(
style
.
logsRow
,
{
[
styles
.
hoverBackground
]:
hasHoverBackground
});
return
(
return
(
<
div
className=
{
style
.
logsRow
}
>
<>
{
showDuplicates
&&
(
<
tr
<
div
className=
{
style
.
logsRowDuplicates
}
>
className=
{
hoverBackground
}
{
row
.
duplicates
&&
row
.
duplicates
>
0
?
`${row.duplicates + 1}x`
:
null
}
onMouseEnter=
{
this
.
addHoverBackground
}
</
div
>
onMouseLeave=
{
this
.
clearHoverBackground
}
)
}
onClick=
{
this
.
toggleDetails
}
<
div
className=
{
style
.
logsRowLevel
}
/>
>
{
!
allowDetails
&&
(
{
showDuplicates
&&
(
<
div
<
td
className=
{
style
.
logsRowDuplicates
}
>
title=
{
showDetails
?
'Hide log details'
:
'See log details'
}
{
row
.
duplicates
&&
row
.
duplicates
>
0
?
`${row.duplicates + 1}x`
:
null
}
onClick=
{
this
.
toggleDetails
}
</
td
>
className=
{
style
.
logsRowToggleDetails
}
)
}
>
<
td
className=
{
style
.
logsRowLevel
}
/>
<
i
className=
{
showDetailsClassName
}
/>
{
!
allowDetails
&&
(
</
div
>
<
td
title=
{
showDetails
?
'Hide log details'
:
'See log details'
}
className=
{
style
.
logsRowToggleDetails
}
>
)
}
<
i
className=
{
showDetailsClassName
}
/>
<
div
>
</
td
>
<
div
onClick=
{
this
.
toggleDetails
}
>
)
}
{
showTime
&&
showUtc
&&
(
{
showTime
&&
showUtc
&&
(
<
div
className=
{
style
.
logsRowLocalTime
}
title=
{
`Local: ${row.timeLocal} (${row.timeFromNow})`
}
>
<
td
className=
{
style
.
logsRowLocalTime
}
title=
{
`Local: ${row.timeLocal} (${row.timeFromNow})`
}
>
{
row
.
timeUtc
}
{
row
.
timeUtc
}
</
div
>
</
td
>
)
}
{
showTime
&&
!
showUtc
&&
(
<
div
className=
{
style
.
logsRowLocalTime
}
title=
{
`${row.timeUtc} (${row.timeFromNow})`
}
>
{
row
.
timeLocal
}
</
div
>
)
}
{
showLabels
&&
row
.
uniqueLabels
&&
(
<
div
className=
{
style
.
logsRowLabels
}
>
<
LogLabels
labels=
{
row
.
uniqueLabels
}
/>
</
div
>
)
}
<
LogRowMessage
highlighterExpressions=
{
highlighterExpressions
}
row=
{
row
}
getRows=
{
getRows
}
errors=
{
errors
}
hasMoreContextRows=
{
hasMoreContextRows
}
updateLimit=
{
updateLimit
}
context=
{
context
}
showContext=
{
showContext
}
wrapLogMessage=
{
wrapLogMessage
}
onToggleContext=
{
this
.
toggleContext
}
/>
</
div
>
{
this
.
state
.
showDetails
&&
(
<
LogDetails
getFieldLinks=
{
getFieldLinks
}
onClickFilterLabel=
{
onClickFilterLabel
}
onClickFilterOutLabel=
{
onClickFilterOutLabel
}
getRows=
{
getRows
}
row=
{
row
}
/>
)
}
)
}
</
div
>
{
showTime
&&
!
showUtc
&&
(
</
div
>
<
td
className=
{
style
.
logsRowLocalTime
}
title=
{
`${row.timeUtc} (${row.timeFromNow})`
}
>
{
row
.
timeLocal
}
</
td
>
)
}
{
showLabels
&&
row
.
uniqueLabels
&&
(
<
td
className=
{
style
.
logsRowLabels
}
>
<
LogLabels
labels=
{
row
.
uniqueLabels
}
/>
</
td
>
)
}
<
LogRowMessage
highlighterExpressions=
{
highlighterExpressions
}
row=
{
row
}
getRows=
{
getRows
}
errors=
{
errors
}
hasMoreContextRows=
{
hasMoreContextRows
}
updateLimit=
{
updateLimit
}
context=
{
context
}
showContext=
{
showContext
}
wrapLogMessage=
{
wrapLogMessage
}
onToggleContext=
{
this
.
toggleContext
}
/>
</
tr
>
{
this
.
state
.
showDetails
&&
(
<
LogDetails
className=
{
hoverBackground
}
onMouseEnter=
{
this
.
addHoverBackground
}
onMouseLeave=
{
this
.
clearHoverBackground
}
showDuplicates=
{
showDuplicates
}
getFieldLinks=
{
getFieldLinks
}
onClickFilterLabel=
{
onClickFilterLabel
}
onClickFilterOutLabel=
{
onClickFilterOutLabel
}
getRows=
{
getRows
}
row=
{
row
}
/>
)
}
</>
);
);
}
}
...
...
packages/grafana-ui/src/components/Logs/LogRowMessage.tsx
View file @
842dde3d
...
@@ -96,7 +96,7 @@ class UnThemedLogRowMessage extends PureComponent<Props, State> {
...
@@ -96,7 +96,7 @@ class UnThemedLogRowMessage extends PureComponent<Props, State> {
:
cx
([
style
.
logsRowMatchHighLight
]);
:
cx
([
style
.
logsRowMatchHighLight
]);
const
styles
=
getStyles
(
theme
);
const
styles
=
getStyles
(
theme
);
return
(
return
(
<
div
className=
{
style
.
logsRowMessage
}
>
<
td
className=
{
style
.
logsRowMessage
}
>
<
div
className=
{
cx
(
styles
.
positionRelative
,
{
[
styles
.
horizontalScroll
]:
!
wrapLogMessage
})
}
>
<
div
className=
{
cx
(
styles
.
positionRelative
,
{
[
styles
.
horizontalScroll
]:
!
wrapLogMessage
})
}
>
{
showContext
&&
context
&&
(
{
showContext
&&
context
&&
(
<
LogRowContext
<
LogRowContext
...
@@ -133,7 +133,7 @@ class UnThemedLogRowMessage extends PureComponent<Props, State> {
...
@@ -133,7 +133,7 @@ class UnThemedLogRowMessage extends PureComponent<Props, State> {
</
span
>
</
span
>
)
}
)
}
</
div
>
</
div
>
</
div
>
</
td
>
);
);
}
}
}
}
...
...
packages/grafana-ui/src/components/Logs/LogRows.tsx
View file @
842dde3d
...
@@ -88,7 +88,7 @@ class UnThemedLogRows extends PureComponent<Props, State> {
...
@@ -88,7 +88,7 @@ class UnThemedLogRows extends PureComponent<Props, State> {
getFieldLinks
,
getFieldLinks
,
}
=
this
.
props
;
}
=
this
.
props
;
const
{
renderAll
}
=
this
.
state
;
const
{
renderAll
}
=
this
.
state
;
const
{
logsRows
,
logsRowsHorizontalScroll
}
=
getLogRowStyles
(
theme
);
const
{
logsRows
Table
,
logsRowsHorizontalScroll
}
=
getLogRowStyles
(
theme
);
const
dedupedRows
=
deduplicatedRows
?
deduplicatedRows
:
logRows
;
const
dedupedRows
=
deduplicatedRows
?
deduplicatedRows
:
logRows
;
const
hasData
=
logRows
&&
logRows
.
length
>
0
;
const
hasData
=
logRows
&&
logRows
.
length
>
0
;
const
dedupCount
=
dedupedRows
const
dedupCount
=
dedupedRows
...
@@ -108,48 +108,54 @@ class UnThemedLogRows extends PureComponent<Props, State> {
...
@@ -108,48 +108,54 @@ class UnThemedLogRows extends PureComponent<Props, State> {
const
getRowContext
=
this
.
props
.
getRowContext
?
this
.
props
.
getRowContext
:
()
=>
Promise
.
resolve
([]);
const
getRowContext
=
this
.
props
.
getRowContext
?
this
.
props
.
getRowContext
:
()
=>
Promise
.
resolve
([]);
return
(
return
(
<
div
className=
{
logsRows
}
>
<
div
className=
{
horizontalScrollWindow
}
>
<
div
className=
{
horizontalScrollWindow
}
>
<
table
className=
{
logsRowsTable
}
>
{
hasData
&&
<
tbody
>
firstRows
.
map
((
row
,
index
)
=>
(
{
hasData
&&
<
LogRow
firstRows
.
map
((
row
,
index
)
=>
(
key=
{
row
.
uid
}
<
LogRow
getRows=
{
getRows
}
key=
{
row
.
uid
}
getRowContext=
{
getRowContext
}
getRows=
{
getRows
}
highlighterExpressions=
{
highlighterExpressions
}
getRowContext=
{
getRowContext
}
row=
{
row
}
highlighterExpressions=
{
highlighterExpressions
}
showDuplicates=
{
showDuplicates
}
row=
{
row
}
showLabels=
{
showLabels
}
showDuplicates=
{
showDuplicates
}
showTime=
{
showTime
}
showLabels=
{
showLabels
}
wrapLogMessage=
{
wrapLogMessage
}
showTime=
{
showTime
}
timeZone=
{
timeZone
}
wrapLogMessage=
{
wrapLogMessage
}
allowDetails=
{
allowDetails
}
timeZone=
{
timeZone
}
onClickFilterLabel=
{
onClickFilterLabel
}
allowDetails=
{
allowDetails
}
onClickFilterOutLabel=
{
onClickFilterOutLabel
}
onClickFilterLabel=
{
onClickFilterLabel
}
getFieldLinks=
{
getFieldLinks
}
onClickFilterOutLabel=
{
onClickFilterOutLabel
}
/>
getFieldLinks=
{
getFieldLinks
}
))
}
/>
{
hasData
&&
))
}
renderAll
&&
{
hasData
&&
lastRows
.
map
((
row
,
index
)
=>
(
renderAll
&&
<
LogRow
lastRows
.
map
((
row
,
index
)
=>
(
key=
{
row
.
uid
}
<
LogRow
getRows=
{
getRows
}
key=
{
row
.
uid
}
getRowContext=
{
getRowContext
}
getRows=
{
getRows
}
row=
{
row
}
getRowContext=
{
getRowContext
}
showDuplicates=
{
showDuplicates
}
row=
{
row
}
showLabels=
{
showLabels
}
showDuplicates=
{
showDuplicates
}
showTime=
{
showTime
}
showLabels=
{
showLabels
}
wrapLogMessage=
{
wrapLogMessage
}
showTime=
{
showTime
}
timeZone=
{
timeZone
}
wrapLogMessage=
{
wrapLogMessage
}
allowDetails=
{
allowDetails
}
timeZone=
{
timeZone
}
onClickFilterLabel=
{
onClickFilterLabel
}
allowDetails=
{
allowDetails
}
onClickFilterOutLabel=
{
onClickFilterOutLabel
}
onClickFilterLabel=
{
onClickFilterLabel
}
getFieldLinks=
{
getFieldLinks
}
onClickFilterOutLabel=
{
onClickFilterOutLabel
}
/>
getFieldLinks=
{
getFieldLinks
}
))
}
/>
{
hasData
&&
!
renderAll
&&
<
span
>
Rendering
{
rowCount
-
previewLimit
!
}
rows...
</
span
>
}
))
}
</
div
>
{
hasData
&&
!
renderAll
&&
(
<
tr
>
<
td
colSpan=
{
5
}
>
Rendering
{
rowCount
-
previewLimit
!
}
rows...
</
td
>
</
tr
>
)
}
</
tbody
>
</
table
>
</
div
>
</
div
>
);
);
}
}
...
...
packages/grafana-ui/src/components/Logs/getLogRowStyles.ts
View file @
842dde3d
...
@@ -53,23 +53,22 @@ export const getLogRowStyles = stylesFactory((theme: GrafanaTheme, logLevel?: Lo
...
@@ -53,23 +53,22 @@ export const getLogRowStyles = stylesFactory((theme: GrafanaTheme, logLevel?: Lo
background-color: rgba(
${
theme
.
colors
.
yellow
}
, 0.2);
background-color: rgba(
${
theme
.
colors
.
yellow
}
, 0.2);
border-bottom-style: dotted;
border-bottom-style: dotted;
`
,
`
,
logsRows
:
css
`
logsRows
Table
:
css
`
label: logs-rows;
label: logs-rows;
font-family:
${
theme
.
typography
.
fontFamily
.
monospace
}
;
font-family:
${
theme
.
typography
.
fontFamily
.
monospace
}
;
font-size:
${
theme
.
typography
.
size
.
sm
}
;
font-size:
${
theme
.
typography
.
size
.
sm
}
;
display: table;
table-layout: fixed;
width: 100%;
width: 100%;
`
,
`
,
logsRowsHorizontalScroll
:
css
`
logsRowsHorizontalScroll
:
css
`
label: logs-rows__horizontal-scroll;
label: logs-rows__horizontal-scroll;
overflow
-y
: scroll;
overflow: scroll;
`
,
`
,
context
:
context
,
context
:
context
,
logsRow
:
css
`
logsRow
:
css
`
label: logs-row;
label: logs-row;
display: table-row
;
width: 100%
;
cursor: pointer;
cursor: pointer;
vertical-align: top;
&:hover {
&:hover {
.
${
context
}
{
.
${
context
}
{
visibility: visible;
visibility: visible;
...
@@ -82,8 +81,7 @@ export const getLogRowStyles = stylesFactory((theme: GrafanaTheme, logLevel?: Lo
...
@@ -82,8 +81,7 @@ export const getLogRowStyles = stylesFactory((theme: GrafanaTheme, logLevel?: Lo
}
}
}
}
> div {
> td {
display: table-cell;
padding-right:
${
theme
.
spacing
.
sm
}
;
padding-right:
${
theme
.
spacing
.
sm
}
;
border-top:
${
theme
.
border
.
width
.
sm
}
solid transparent;
border-top:
${
theme
.
border
.
width
.
sm
}
solid transparent;
border-bottom:
${
theme
.
border
.
width
.
sm
}
solid transparent;
border-bottom:
${
theme
.
border
.
width
.
sm
}
solid transparent;
...
@@ -103,9 +101,7 @@ export const getLogRowStyles = stylesFactory((theme: GrafanaTheme, logLevel?: Lo
...
@@ -103,9 +101,7 @@ export const getLogRowStyles = stylesFactory((theme: GrafanaTheme, logLevel?: Lo
logsRowLevel
:
css
`
logsRowLevel
:
css
`
label: logs-row__level;
label: logs-row__level;
position: relative;
position: relative;
width: 10px;
cursor: default;
cursor: default;
&::after {
&::after {
content: '';
content: '';
display: block;
display: block;
...
@@ -116,39 +112,24 @@ export const getLogRowStyles = stylesFactory((theme: GrafanaTheme, logLevel?: Lo
...
@@ -116,39 +112,24 @@ export const getLogRowStyles = stylesFactory((theme: GrafanaTheme, logLevel?: Lo
background-color:
${
logColor
}
;
background-color:
${
logColor
}
;
}
}
`
,
`
,
logsRowCell
:
css
`
label: logs-row-cell;
word-break: break-all;
padding-right:
${
theme
.
spacing
.
sm
}
;
`
,
logsRowToggleDetails
:
css
`
logsRowToggleDetails
:
css
`
label: logs-row-toggle-details__level;
label: logs-row-toggle-details__level;
position: relative;
position: relative;
width: 15px;
font-size: 9px;
font-size: 9px;
padding-top: 5px;
`
,
`
,
logsRowLocalTime
:
css
`
logsRowLocalTime
:
css
`
label: logs-row__localtime;
label: logs-row__localtime;
display: table-cell;
white-space: nowrap;
white-space: nowrap;
width: 12.5em;
padding-right: 1em;
`
,
`
,
logsRowLabels
:
css
`
logsRowLabels
:
css
`
label: logs-row__labels;
label: logs-row__labels;
display: table-cell;
white-space: nowrap;
white-space: nowrap;
width: 22em;
max-width: 22em;
padding-right: 1em;
`
,
`
,
logsRowMessage
:
css
`
logsRowMessage
:
css
`
label: logs-row__message;
label: logs-row__message;
word-break: break-all;
word-break: break-all;
display: table-cell;
`
,
logsRowStats
:
css
`
label: logs-row__stats;
margin: 5px 0;
`
,
`
,
//Log details sepcific CSS
//Log details sepcific CSS
logDetailsContainer
:
css
`
logDetailsContainer
:
css
`
...
@@ -156,23 +137,27 @@ export const getLogRowStyles = stylesFactory((theme: GrafanaTheme, logLevel?: Lo
...
@@ -156,23 +137,27 @@ export const getLogRowStyles = stylesFactory((theme: GrafanaTheme, logLevel?: Lo
border: 1px solid
${
borderColor
}
;
border: 1px solid
${
borderColor
}
;
padding: 0
${
theme
.
spacing
.
sm
}
${
theme
.
spacing
.
sm
}
;
padding: 0
${
theme
.
spacing
.
sm
}
${
theme
.
spacing
.
sm
}
;
border-radius: 3px;
border-radius: 3px;
margin: 20px
0
;
margin: 20px
8px 20px 16px
;
cursor: default;
cursor: default;
`
,
`
,
logDetailsTable
:
css
`
logDetailsTable
:
css
`
label: logs-row-details-table;
label: logs-row-details-table;
line-height: 2;
width: 100%;
width: 100%;
td:last-child {
width: 100%;
}
`
,
`
,
logsDetailsIcon
:
css
`
logsDetailsIcon
:
css
`
label: logs-row-details__icon;
label: logs-row-details__icon;
position: relative;
position: relative;
padding-right:
${
theme
.
spacing
.
sm
}
;
padding-right:
${
theme
.
spacing
.
md
}
;
color:
${
theme
.
colors
.
gray3
}
;
color:
${
theme
.
colors
.
gray3
}
;
`
,
`
,
logDetailsLabel
:
css
`
logDetailsLabel
:
css
`
label: logs-row-details__label;
label: logs-row-details__label;
max-width: 25em;
max-width: 25em;
min-width: 1
2
em;
min-width: 1
5
em;
padding: 0
${
theme
.
spacing
.
sm
}
;
padding: 0
${
theme
.
spacing
.
sm
}
;
word-break: break-all;
word-break: break-all;
`
,
`
,
...
@@ -183,8 +168,6 @@ export const getLogRowStyles = stylesFactory((theme: GrafanaTheme, logLevel?: Lo
...
@@ -183,8 +168,6 @@ export const getLogRowStyles = stylesFactory((theme: GrafanaTheme, logLevel?: Lo
`
,
`
,
logDetailsValue
:
css
`
logDetailsValue
:
css
`
label: logs-row-details__row;
label: logs-row-details__row;
line-height: 2;
padding:
${
theme
.
spacing
.
sm
}
;
position: relative;
position: relative;
vertical-align: top;
vertical-align: top;
cursor: default;
cursor: default;
...
...
public/app/features/explore/LiveLogs.tsx
View file @
842dde3d
...
@@ -64,7 +64,7 @@ interface State {
...
@@ -64,7 +64,7 @@ interface State {
class
LiveLogs
extends
PureComponent
<
Props
,
State
>
{
class
LiveLogs
extends
PureComponent
<
Props
,
State
>
{
private
liveEndDiv
:
HTMLDivElement
|
null
=
null
;
private
liveEndDiv
:
HTMLDivElement
|
null
=
null
;
private
scrollContainerRef
=
React
.
createRef
<
HTML
Div
Element
>
();
private
scrollContainerRef
=
React
.
createRef
<
HTML
TableSection
Element
>
();
private
lastScrollPos
:
number
|
null
=
null
;
private
lastScrollPos
:
number
|
null
=
null
;
constructor
(
props
:
Props
)
{
constructor
(
props
:
Props
)
{
...
@@ -139,39 +139,41 @@ class LiveLogs extends PureComponent<Props, State> {
...
@@ -139,39 +139,41 @@ class LiveLogs extends PureComponent<Props, State> {
return
(
return
(
<
div
>
<
div
>
<
div
<
table
>
onScroll=
{
isPaused
?
undefined
:
this
.
onScroll
}
<
tbody
className=
{
cx
([
'logs-rows'
,
styles
.
logsRowsLive
])
}
onScroll=
{
isPaused
?
undefined
:
this
.
onScroll
}
ref=
{
this
.
scrollContainerRef
}
className=
{
cx
([
'logs-rows'
,
styles
.
logsRowsLive
])
}
>
ref=
{
this
.
scrollContainerRef
}
{
this
.
rowsToRender
().
map
((
row
:
LogRowModel
)
=>
{
>
return
(
{
this
.
rowsToRender
().
map
((
row
:
LogRowModel
)
=>
{
<
div
className=
{
cx
(
logsRow
,
styles
.
logsRowFade
)
}
key=
{
row
.
uid
}
>
return
(
{
showUtc
&&
(
<
tr
className=
{
cx
(
logsRow
,
styles
.
logsRowFade
)
}
key=
{
row
.
uid
}
>
<
div
className=
{
cx
(
logsRowLocalTime
)
}
title=
{
`Local: ${row.timeLocal} (${row.timeFromNow})`
}
>
{
showUtc
&&
(
{
row
.
timeUtc
}
<
td
className=
{
cx
(
logsRowLocalTime
)
}
title=
{
`Local: ${row.timeLocal} (${row.timeFromNow})`
}
>
</
div
>
{
row
.
timeUtc
}
)
}
</
td
>
{
!
showUtc
&&
(
)
}
<
div
className=
{
cx
(
logsRowLocalTime
)
}
title=
{
`${row.timeUtc} (${row.timeFromNow})`
}
>
{
!
showUtc
&&
(
{
row
.
timeLocal
}
<
td
className=
{
cx
(
logsRowLocalTime
)
}
title=
{
`${row.timeUtc} (${row.timeFromNow})`
}
>
</
div
>
{
row
.
timeLocal
}
)
}
</
td
>
<
div
className=
{
cx
(
logsRowMessage
)
}
>
{
row
.
entry
}
</
div
>
)
}
</
div
>
<
td
className=
{
cx
(
logsRowMessage
)
}
>
{
row
.
entry
}
</
td
>
);
</
tr
>
})
}
);
<
div
})
}
ref=
{
element
=>
{
<
tr
this
.
liveEndDiv
=
element
;
ref=
{
element
=>
{
// This is triggered on every update so on every new row. It keeps the view scrolled at the bottom by
this
.
liveEndDiv
=
element
;
// default.
// This is triggered on every update so on every new row. It keeps the view scrolled at the bottom by
if
(
this
.
liveEndDiv
&&
!
isPaused
)
{
// default.
this
.
liveEndDiv
.
scrollIntoView
(
false
);
if
(
this
.
liveEndDiv
&&
!
isPaused
)
{
}
this
.
liveEndDiv
.
scrollIntoView
(
false
);
}
}
}
/>
}
}
</
div
>
/>
</
tbody
>
</
table
>
<
div
className=
{
cx
([
styles
.
logsRowsIndicator
])
}
>
<
div
className=
{
cx
([
styles
.
logsRowsIndicator
])
}
>
<
button
onClick=
{
isPaused
?
onResume
:
onPause
}
className=
{
cx
(
'btn btn-secondary'
,
styles
.
button
)
}
>
<
button
onClick=
{
isPaused
?
onResume
:
onPause
}
className=
{
cx
(
'btn btn-secondary'
,
styles
.
button
)
}
>
<
i
className=
{
cx
(
'fa'
,
isPaused
?
'fa-play'
:
'fa-pause'
)
}
/>
<
i
className=
{
cx
(
'fa'
,
isPaused
?
'fa-play'
:
'fa-pause'
)
}
/>
...
...
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