LogsContainer.tsx 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  1. import { css } from '@emotion/css';
  2. import React, { PureComponent } from 'react';
  3. import { connect, ConnectedProps } from 'react-redux';
  4. import {
  5. AbsoluteTimeRange,
  6. Field,
  7. hasLogsContextSupport,
  8. LoadingState,
  9. LogRowModel,
  10. RawTimeRange,
  11. } from '@grafana/data';
  12. import { Collapse } from '@grafana/ui';
  13. import { StoreState } from 'app/types';
  14. import { ExploreId, ExploreItemState } from 'app/types/explore';
  15. import { getTimeZone } from '../profile/state/selectors';
  16. import { LiveLogsWithTheme } from './LiveLogs';
  17. import { Logs } from './Logs';
  18. import { splitOpen } from './state/main';
  19. import { addResultsToCache, clearCache } from './state/query';
  20. import { updateTimeRange } from './state/time';
  21. import { LiveTailControls } from './useLiveTailControls';
  22. import { LogsCrossFadeTransition } from './utils/LogsCrossFadeTransition';
  23. import { getFieldLinksForExplore } from './utils/links';
  24. interface LogsContainerProps extends PropsFromRedux {
  25. width: number;
  26. exploreId: ExploreId;
  27. scanRange?: RawTimeRange;
  28. syncedTimes: boolean;
  29. loadingState: LoadingState;
  30. onClickFilterLabel?: (key: string, value: string) => void;
  31. onClickFilterOutLabel?: (key: string, value: string) => void;
  32. onStartScanning: () => void;
  33. onStopScanning: () => void;
  34. }
  35. class LogsContainer extends PureComponent<LogsContainerProps> {
  36. onChangeTime = (absoluteRange: AbsoluteTimeRange) => {
  37. const { exploreId, updateTimeRange } = this.props;
  38. updateTimeRange({ exploreId, absoluteRange });
  39. };
  40. getLogRowContext = async (row: LogRowModel, options?: any): Promise<any> => {
  41. const { datasourceInstance, logsQueries } = this.props;
  42. if (hasLogsContextSupport(datasourceInstance)) {
  43. // we need to find the query, and we need to be very sure that
  44. // it's a query from this datasource
  45. const query = (logsQueries ?? []).find(
  46. (q) => q.refId === row.dataFrame.refId && q.datasource != null && q.datasource.type === datasourceInstance.type
  47. );
  48. return datasourceInstance.getLogRowContext(row, options, query);
  49. }
  50. return [];
  51. };
  52. showContextToggle = (row?: LogRowModel): boolean => {
  53. const { datasourceInstance } = this.props;
  54. if (hasLogsContextSupport(datasourceInstance)) {
  55. return datasourceInstance.showContextToggle(row);
  56. }
  57. return false;
  58. };
  59. getFieldLinks = (field: Field, rowIndex: number) => {
  60. const { splitOpen: splitOpenFn, range } = this.props;
  61. return getFieldLinksForExplore({ field, rowIndex, splitOpenFn, range });
  62. };
  63. render() {
  64. const {
  65. loading,
  66. loadingState,
  67. logRows,
  68. logsMeta,
  69. logsSeries,
  70. logsQueries,
  71. onClickFilterLabel,
  72. onClickFilterOutLabel,
  73. onStartScanning,
  74. onStopScanning,
  75. absoluteRange,
  76. timeZone,
  77. visibleRange,
  78. scanning,
  79. range,
  80. width,
  81. isLive,
  82. exploreId,
  83. addResultsToCache,
  84. clearCache,
  85. } = this.props;
  86. if (!logRows) {
  87. return null;
  88. }
  89. // We need to override css overflow of divs in Collapse element to enable sticky Logs navigation
  90. const styleOverridesForStickyNavigation = css`
  91. & > div {
  92. overflow: visible;
  93. & > div {
  94. overflow: visible;
  95. }
  96. }
  97. `;
  98. return (
  99. <>
  100. <LogsCrossFadeTransition visible={isLive}>
  101. <Collapse label="Logs" loading={false} isOpen>
  102. <LiveTailControls exploreId={exploreId}>
  103. {(controls) => (
  104. <LiveLogsWithTheme
  105. logRows={logRows}
  106. timeZone={timeZone}
  107. stopLive={controls.stop}
  108. isPaused={this.props.isPaused}
  109. onPause={controls.pause}
  110. onResume={controls.resume}
  111. />
  112. )}
  113. </LiveTailControls>
  114. </Collapse>
  115. </LogsCrossFadeTransition>
  116. <LogsCrossFadeTransition visible={!isLive}>
  117. <Collapse label="Logs" loading={loading} isOpen className={styleOverridesForStickyNavigation}>
  118. <Logs
  119. exploreId={exploreId}
  120. datasourceType={this.props.datasourceInstance?.type}
  121. logRows={logRows}
  122. logsMeta={logsMeta}
  123. logsSeries={logsSeries}
  124. logsQueries={logsQueries}
  125. width={width}
  126. loading={loading}
  127. loadingState={loadingState}
  128. onChangeTime={this.onChangeTime}
  129. onClickFilterLabel={onClickFilterLabel}
  130. onClickFilterOutLabel={onClickFilterOutLabel}
  131. onStartScanning={onStartScanning}
  132. onStopScanning={onStopScanning}
  133. absoluteRange={absoluteRange}
  134. visibleRange={visibleRange}
  135. timeZone={timeZone}
  136. scanning={scanning}
  137. scanRange={range.raw}
  138. showContextToggle={this.showContextToggle}
  139. getRowContext={this.getLogRowContext}
  140. getFieldLinks={this.getFieldLinks}
  141. addResultsToCache={() => addResultsToCache(exploreId)}
  142. clearCache={() => clearCache(exploreId)}
  143. />
  144. </Collapse>
  145. </LogsCrossFadeTransition>
  146. </>
  147. );
  148. }
  149. }
  150. function mapStateToProps(state: StoreState, { exploreId }: { exploreId: string }) {
  151. const explore = state.explore;
  152. // @ts-ignore
  153. const item: ExploreItemState = explore[exploreId];
  154. const {
  155. logsResult,
  156. loading,
  157. scanning,
  158. datasourceInstance,
  159. isLive,
  160. isPaused,
  161. range,
  162. absoluteRange,
  163. logsVolumeDataProvider,
  164. logsVolumeData,
  165. } = item;
  166. const timeZone = getTimeZone(state.user);
  167. return {
  168. loading,
  169. logRows: logsResult?.rows,
  170. logsMeta: logsResult?.meta,
  171. logsSeries: logsResult?.series,
  172. logsQueries: logsResult?.queries,
  173. visibleRange: logsResult?.visibleRange,
  174. scanning,
  175. timeZone,
  176. datasourceInstance,
  177. isLive,
  178. isPaused,
  179. range,
  180. absoluteRange,
  181. logsVolumeDataProvider,
  182. logsVolumeData,
  183. };
  184. }
  185. const mapDispatchToProps = {
  186. updateTimeRange,
  187. splitOpen,
  188. addResultsToCache,
  189. clearCache,
  190. };
  191. const connector = connect(mapStateToProps, mapDispatchToProps);
  192. type PropsFromRedux = ConnectedProps<typeof connector>;
  193. export default connector(LogsContainer);