Logs.tsx 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  1. import React, { PureComponent } from 'react';
  2. import {
  3. rangeUtil,
  4. RawTimeRange,
  5. LogLevel,
  6. TimeZone,
  7. AbsoluteTimeRange,
  8. LogsMetaKind,
  9. LogsModel,
  10. LogsDedupStrategy,
  11. LogRowModel,
  12. LogsDedupDescription,
  13. } from '@grafana/data';
  14. import { Switch, LogLabels, ToggleButtonGroup, ToggleButton, LogRows } from '@grafana/ui';
  15. import { ExploreGraphPanel } from './ExploreGraphPanel';
  16. function renderMetaItem(value: any, kind: LogsMetaKind) {
  17. if (kind === LogsMetaKind.LabelsMap) {
  18. return (
  19. <span className="logs-meta-item__labels">
  20. <LogLabels labels={value} plain getRows={() => []} />
  21. </span>
  22. );
  23. }
  24. return value;
  25. }
  26. interface Props {
  27. data?: LogsModel;
  28. dedupedData?: LogsModel;
  29. width: number;
  30. highlighterExpressions: string[];
  31. loading: boolean;
  32. absoluteRange: AbsoluteTimeRange;
  33. timeZone: TimeZone;
  34. scanning?: boolean;
  35. scanRange?: RawTimeRange;
  36. dedupStrategy: LogsDedupStrategy;
  37. onChangeTime: (range: AbsoluteTimeRange) => void;
  38. onClickLabel?: (label: string, value: string) => void;
  39. onStartScanning?: () => void;
  40. onStopScanning?: () => void;
  41. onDedupStrategyChange: (dedupStrategy: LogsDedupStrategy) => void;
  42. onToggleLogLevel: (hiddenLogLevels: LogLevel[]) => void;
  43. getRowContext?: (row: LogRowModel, options?: any) => Promise<any>;
  44. }
  45. interface State {
  46. showLabels: boolean;
  47. showTime: boolean;
  48. }
  49. export class Logs extends PureComponent<Props, State> {
  50. state = {
  51. showLabels: false,
  52. showTime: true,
  53. };
  54. onChangeDedup = (dedup: LogsDedupStrategy) => {
  55. const { onDedupStrategyChange } = this.props;
  56. if (this.props.dedupStrategy === dedup) {
  57. return onDedupStrategyChange(LogsDedupStrategy.none);
  58. }
  59. return onDedupStrategyChange(dedup);
  60. };
  61. onChangeLabels = (event?: React.SyntheticEvent) => {
  62. const target = event && (event.target as HTMLInputElement);
  63. if (target) {
  64. this.setState({
  65. showLabels: target.checked,
  66. });
  67. }
  68. };
  69. onChangeTime = (event?: React.SyntheticEvent) => {
  70. const target = event && (event.target as HTMLInputElement);
  71. if (target) {
  72. this.setState({
  73. showTime: target.checked,
  74. });
  75. }
  76. };
  77. onToggleLogLevel = (hiddenRawLevels: string[]) => {
  78. const hiddenLogLevels: LogLevel[] = hiddenRawLevels.map(level => LogLevel[level as LogLevel]);
  79. this.props.onToggleLogLevel(hiddenLogLevels);
  80. };
  81. onClickScan = (event: React.SyntheticEvent) => {
  82. event.preventDefault();
  83. if (this.props.onStartScanning) {
  84. this.props.onStartScanning();
  85. }
  86. };
  87. onClickStopScan = (event: React.SyntheticEvent) => {
  88. event.preventDefault();
  89. if (this.props.onStopScanning) {
  90. this.props.onStopScanning();
  91. }
  92. };
  93. render() {
  94. const {
  95. data,
  96. highlighterExpressions,
  97. loading = false,
  98. onClickLabel,
  99. timeZone,
  100. scanning,
  101. scanRange,
  102. width,
  103. dedupedData,
  104. absoluteRange,
  105. onChangeTime,
  106. } = this.props;
  107. if (!data) {
  108. return null;
  109. }
  110. const { showLabels, showTime } = this.state;
  111. const { dedupStrategy } = this.props;
  112. const hasData = data && data.rows && data.rows.length > 0;
  113. const dedupCount = dedupedData
  114. ? dedupedData.rows.reduce((sum, row) => (row.duplicates ? sum + row.duplicates : sum), 0)
  115. : 0;
  116. const meta = data && data.meta ? [...data.meta] : [];
  117. if (dedupStrategy !== LogsDedupStrategy.none) {
  118. meta.push({
  119. label: 'Dedup count',
  120. value: dedupCount,
  121. kind: LogsMetaKind.Number,
  122. });
  123. }
  124. const scanText = scanRange ? `Scanning ${rangeUtil.describeTimeRange(scanRange)}` : 'Scanning...';
  125. const series = data && data.series ? data.series : [];
  126. return (
  127. <div className="logs-panel">
  128. <div className="logs-panel-graph">
  129. <ExploreGraphPanel
  130. series={series}
  131. width={width}
  132. onHiddenSeriesChanged={this.onToggleLogLevel}
  133. loading={loading}
  134. absoluteRange={absoluteRange}
  135. isStacked={true}
  136. showPanel={false}
  137. showingGraph={true}
  138. showingTable={true}
  139. timeZone={timeZone}
  140. showBars={true}
  141. showLines={false}
  142. onUpdateTimeRange={onChangeTime}
  143. />
  144. </div>
  145. <div className="logs-panel-options">
  146. <div className="logs-panel-controls">
  147. <Switch label="Time" checked={showTime} onChange={this.onChangeTime} transparent />
  148. <Switch label="Labels" checked={showLabels} onChange={this.onChangeLabels} transparent />
  149. <ToggleButtonGroup label="Dedup" transparent={true}>
  150. {Object.keys(LogsDedupStrategy).map((dedupType: string, i) => (
  151. <ToggleButton
  152. key={i}
  153. value={dedupType}
  154. onChange={this.onChangeDedup}
  155. selected={dedupStrategy === dedupType}
  156. // @ts-ignore
  157. tooltip={LogsDedupDescription[dedupType]}
  158. >
  159. {dedupType}
  160. </ToggleButton>
  161. ))}
  162. </ToggleButtonGroup>
  163. </div>
  164. </div>
  165. {hasData && meta && (
  166. <div className="logs-panel-meta">
  167. {meta.map(item => (
  168. <div className="logs-panel-meta__item" key={item.label}>
  169. <span className="logs-panel-meta__label">{item.label}:</span>
  170. <span className="logs-panel-meta__value">{renderMetaItem(item.value, item.kind)}</span>
  171. </div>
  172. ))}
  173. </div>
  174. )}
  175. <LogRows
  176. data={data}
  177. deduplicatedData={dedupedData}
  178. dedupStrategy={dedupStrategy}
  179. getRowContext={this.props.getRowContext}
  180. highlighterExpressions={highlighterExpressions}
  181. onClickLabel={onClickLabel}
  182. rowLimit={data ? data.rows.length : undefined}
  183. showLabels={showLabels}
  184. showTime={showTime}
  185. timeZone={timeZone}
  186. />
  187. {!loading && !hasData && !scanning && (
  188. <div className="logs-panel-nodata">
  189. No logs found.
  190. <a className="link" onClick={this.onClickScan}>
  191. Scan for older logs
  192. </a>
  193. </div>
  194. )}
  195. {scanning && (
  196. <div className="logs-panel-nodata">
  197. <span>{scanText}</span>
  198. <a className="link" onClick={this.onClickStopScan}>
  199. Stop scan
  200. </a>
  201. </div>
  202. )}
  203. </div>
  204. );
  205. }
  206. }