Logs.tsx 6.4 KB

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