Logs.tsx 6.5 KB

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