| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118 |
- import React, { PureComponent } from 'react';
- import { css, cx } from 'emotion';
- import { Themeable, withTheme, GrafanaTheme, selectThemeVariant, LinkButton } from '@grafana/ui';
- import { LogsModel, LogRowModel } from 'app/core/logs_model';
- import ElapsedTime from './ElapsedTime';
- import { ButtonSize, ButtonVariant } from '@grafana/ui/src/components/Button/AbstractButton';
- const getStyles = (theme: GrafanaTheme) => ({
- logsRowsLive: css`
- label: logs-rows-live;
- display: flex;
- flex-flow: column nowrap;
- height: 65vh;
- overflow-y: auto;
- :first-child {
- margin-top: auto !important;
- }
- `,
- logsRowFresh: css`
- label: logs-row-fresh;
- color: ${theme.colors.text};
- background-color: ${selectThemeVariant({ light: theme.colors.gray6, dark: theme.colors.gray1 }, theme.type)};
- `,
- logsRowOld: css`
- label: logs-row-old;
- opacity: 0.8;
- `,
- logsRowsIndicator: css`
- font-size: ${theme.typography.size.md};
- padding: ${theme.spacing.sm} 0;
- display: flex;
- align-items: center;
- `,
- });
- export interface Props extends Themeable {
- logsResult?: LogsModel;
- stopLive: () => void;
- }
- export interface State {
- renderCount: number;
- }
- class LiveLogs extends PureComponent<Props, State> {
- private liveEndDiv: HTMLDivElement = null;
- constructor(props: Props) {
- super(props);
- this.state = { renderCount: 0 };
- }
- componentDidUpdate(prevProps: Props) {
- const prevRows: LogRowModel[] = prevProps.logsResult ? prevProps.logsResult.rows : [];
- const rows: LogRowModel[] = this.props.logsResult ? this.props.logsResult.rows : [];
- if (prevRows !== rows) {
- this.setState({
- renderCount: this.state.renderCount + 1,
- });
- }
- if (this.liveEndDiv) {
- this.liveEndDiv.scrollIntoView(false);
- }
- }
- render() {
- const { theme } = this.props;
- const { renderCount } = this.state;
- const styles = getStyles(theme);
- const rowsToRender: LogRowModel[] = this.props.logsResult ? this.props.logsResult.rows : [];
- return (
- <>
- <div className={cx(['logs-rows', styles.logsRowsLive])}>
- {rowsToRender.map((row: any, index) => {
- return (
- <div
- className={row.fresh ? cx(['logs-row', styles.logsRowFresh]) : cx(['logs-row', styles.logsRowOld])}
- key={`${row.timeEpochMs}-${index}`}
- >
- <div className="logs-row__localtime" title={`${row.timestamp} (${row.timeFromNow})`}>
- {row.timeLocal}
- </div>
- <div className="logs-row__message">{row.entry}</div>
- </div>
- );
- })}
- <div
- ref={element => {
- this.liveEndDiv = element;
- if (this.liveEndDiv) {
- this.liveEndDiv.scrollIntoView(false);
- }
- }}
- />
- </div>
- <div className={cx([styles.logsRowsIndicator])}>
- <span>
- Last line received: <ElapsedTime renderCount={renderCount} humanize={true} /> ago
- </span>
- <LinkButton
- onClick={this.props.stopLive}
- size={ButtonSize.Medium}
- variant={ButtonVariant.Transparent}
- style={{ color: theme.colors.orange }}
- >
- Stop Live
- </LinkButton>
- </div>
- </>
- );
- }
- }
- export const LiveLogsWithTheme = withTheme(LiveLogs);
|