| 
									
										
										
										
											2022-09-19 16:51:46 +08:00
										 |  |  | import { css, cx } from '@emotion/css'; | 
					
						
							|  |  |  | import memoizeOne from 'memoize-one'; | 
					
						
							|  |  |  | import React, { PureComponent } from 'react'; | 
					
						
							|  |  |  | import Highlighter from 'react-highlight-words'; | 
					
						
							|  |  |  | import tinycolor from 'tinycolor2'; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-27 22:12:01 +08:00
										 |  |  | import { | 
					
						
							|  |  |  |   LogRowModel, | 
					
						
							|  |  |  |   findHighlightChunksInText, | 
					
						
							|  |  |  |   GrafanaTheme2, | 
					
						
							|  |  |  |   LogsSortOrder, | 
					
						
							|  |  |  |   CoreApp, | 
					
						
							|  |  |  |   DataSourceWithLogsContextSupport, | 
					
						
							|  |  |  | } from '@grafana/data'; | 
					
						
							| 
									
										
										
										
											2022-09-19 16:51:46 +08:00
										 |  |  | import { withTheme2, Themeable2, IconButton, Tooltip } from '@grafana/ui'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import { LogMessageAnsi } from './LogMessageAnsi'; | 
					
						
							|  |  |  | import { LogRowContext } from './LogRowContext'; | 
					
						
							|  |  |  | import { LogRowContextQueryErrors, HasMoreContextRows, LogRowContextRows } from './LogRowContextProvider'; | 
					
						
							|  |  |  | import { getLogRowStyles } from './getLogRowStyles'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | export const MAX_CHARACTERS = 100000; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | interface Props extends Themeable2 { | 
					
						
							|  |  |  |   row: LogRowModel; | 
					
						
							|  |  |  |   hasMoreContextRows?: HasMoreContextRows; | 
					
						
							|  |  |  |   contextIsOpen: boolean; | 
					
						
							|  |  |  |   wrapLogMessage: boolean; | 
					
						
							|  |  |  |   prettifyLogMessage: boolean; | 
					
						
							|  |  |  |   errors?: LogRowContextQueryErrors; | 
					
						
							|  |  |  |   context?: LogRowContextRows; | 
					
						
							| 
									
										
										
										
											2022-09-29 16:00:01 +08:00
										 |  |  |   showRowMenu?: boolean; | 
					
						
							|  |  |  |   app?: CoreApp; | 
					
						
							| 
									
										
										
										
											2022-09-29 20:51:20 +08:00
										 |  |  |   scrollElement?: HTMLDivElement; | 
					
						
							| 
									
										
										
										
											2022-09-19 16:51:46 +08:00
										 |  |  |   showContextToggle?: (row?: LogRowModel) => boolean; | 
					
						
							| 
									
										
										
										
											2023-01-27 22:12:01 +08:00
										 |  |  |   getLogRowContextUi?: DataSourceWithLogsContextSupport['getLogRowContextUi']; | 
					
						
							| 
									
										
										
										
											2022-09-19 16:51:46 +08:00
										 |  |  |   getRows: () => LogRowModel[]; | 
					
						
							| 
									
										
										
										
											2022-10-19 17:01:45 +08:00
										 |  |  |   onToggleContext: (method: string) => void; | 
					
						
							| 
									
										
										
										
											2022-09-19 16:51:46 +08:00
										 |  |  |   updateLimit?: () => void; | 
					
						
							| 
									
										
										
										
											2023-01-27 22:12:01 +08:00
										 |  |  |   runContextQuery?: () => void; | 
					
						
							| 
									
										
										
										
											2022-09-28 19:37:49 +08:00
										 |  |  |   logsSortOrder?: LogsSortOrder | null; | 
					
						
							| 
									
										
										
										
											2022-09-19 16:51:46 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-25 02:10:27 +08:00
										 |  |  | const getStyles = (theme: GrafanaTheme2, showContextButton: boolean, isInExplore: boolean) => { | 
					
						
							| 
									
										
										
										
											2022-09-19 16:51:46 +08:00
										 |  |  |   const outlineColor = tinycolor(theme.components.dashboard.background).setAlpha(0.7).toRgbString(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return { | 
					
						
							|  |  |  |     positionRelative: css`
 | 
					
						
							|  |  |  |       label: positionRelative; | 
					
						
							|  |  |  |       position: relative; | 
					
						
							|  |  |  |     `,
 | 
					
						
							|  |  |  |     rowWithContext: css`
 | 
					
						
							|  |  |  |       label: rowWithContext; | 
					
						
							|  |  |  |       z-index: 1; | 
					
						
							|  |  |  |       outline: 9999px solid ${outlineColor}; | 
					
						
							| 
									
										
										
										
											2022-10-13 17:42:40 +08:00
										 |  |  |       display: inherit; | 
					
						
							| 
									
										
										
										
											2022-09-19 16:51:46 +08:00
										 |  |  |     `,
 | 
					
						
							|  |  |  |     horizontalScroll: css`
 | 
					
						
							| 
									
										
										
										
											2022-11-24 20:21:55 +08:00
										 |  |  |       label: horizontalScroll; | 
					
						
							| 
									
										
										
										
											2022-09-19 16:51:46 +08:00
										 |  |  |       white-space: pre; | 
					
						
							|  |  |  |     `,
 | 
					
						
							|  |  |  |     contextNewline: css`
 | 
					
						
							|  |  |  |       display: block; | 
					
						
							|  |  |  |       margin-left: 0px; | 
					
						
							|  |  |  |     `,
 | 
					
						
							| 
									
										
										
										
											2022-09-29 16:00:01 +08:00
										 |  |  |     rowMenu: css`
 | 
					
						
							| 
									
										
										
										
											2022-09-19 16:51:46 +08:00
										 |  |  |       display: flex; | 
					
						
							|  |  |  |       flex-wrap: nowrap; | 
					
						
							|  |  |  |       flex-direction: row; | 
					
						
							|  |  |  |       align-content: flex-end; | 
					
						
							|  |  |  |       justify-content: space-evenly; | 
					
						
							|  |  |  |       align-items: center; | 
					
						
							|  |  |  |       position: absolute; | 
					
						
							|  |  |  |       top: 0; | 
					
						
							|  |  |  |       bottom: auto; | 
					
						
							| 
									
										
										
										
											2022-11-04 23:18:55 +08:00
										 |  |  |       height: ${theme.spacing(4.5)}; | 
					
						
							| 
									
										
										
										
											2022-09-19 16:51:46 +08:00
										 |  |  |       background: ${theme.colors.background.primary}; | 
					
						
							|  |  |  |       box-shadow: ${theme.shadows.z3}; | 
					
						
							|  |  |  |       padding: ${theme.spacing(0, 0, 0, 0.5)}; | 
					
						
							|  |  |  |       z-index: 100; | 
					
						
							| 
									
										
										
										
											2022-09-29 16:00:01 +08:00
										 |  |  |       visibility: hidden; | 
					
						
							| 
									
										
										
										
											2022-11-04 23:18:55 +08:00
										 |  |  |       width: ${showContextButton ? theme.spacing(10) : theme.spacing(5)}; | 
					
						
							| 
									
										
										
										
											2022-09-19 16:51:46 +08:00
										 |  |  |     `,
 | 
					
						
							| 
									
										
										
										
											2022-10-05 22:11:08 +08:00
										 |  |  |     logRowMenuCell: css`
 | 
					
						
							|  |  |  |       position: absolute; | 
					
						
							| 
									
										
										
										
											2023-01-25 02:10:27 +08:00
										 |  |  |       right: ${!isInExplore ? '40px' : `calc(75px + ${theme.spacing()} + ${showContextButton ? '80px' : '40px'})`}; | 
					
						
							| 
									
										
										
										
											2022-11-04 23:18:55 +08:00
										 |  |  |       margin-top: -${theme.spacing(0.125)}; | 
					
						
							| 
									
										
										
										
											2022-10-05 22:11:08 +08:00
										 |  |  |     `,
 | 
					
						
							| 
									
										
										
										
											2022-12-21 21:45:47 +08:00
										 |  |  |     logLine: css`
 | 
					
						
							|  |  |  |       background-color: transparent; | 
					
						
							|  |  |  |       border: none; | 
					
						
							|  |  |  |       diplay: inline; | 
					
						
							|  |  |  |       font-family: ${theme.typography.fontFamilyMonospace}; | 
					
						
							|  |  |  |       font-size: ${theme.typography.bodySmall.fontSize}; | 
					
						
							|  |  |  |       letter-spacing: ${theme.typography.bodySmall.letterSpacing}; | 
					
						
							|  |  |  |       text-align: left; | 
					
						
							|  |  |  |       padding: 0; | 
					
						
							| 
									
										
										
										
											2023-01-06 18:15:12 +08:00
										 |  |  |       user-select: text; | 
					
						
							| 
									
										
										
										
											2022-12-21 21:45:47 +08:00
										 |  |  |     `,
 | 
					
						
							| 
									
										
										
										
											2022-09-19 16:51:46 +08:00
										 |  |  |   }; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | function renderLogMessage( | 
					
						
							|  |  |  |   hasAnsi: boolean, | 
					
						
							|  |  |  |   entry: string, | 
					
						
							|  |  |  |   highlights: string[] | undefined, | 
					
						
							|  |  |  |   highlightClassName: string | 
					
						
							|  |  |  | ) { | 
					
						
							|  |  |  |   const needsHighlighter = | 
					
						
							|  |  |  |     highlights && highlights.length > 0 && highlights[0] && highlights[0].length > 0 && entry.length < MAX_CHARACTERS; | 
					
						
							|  |  |  |   const searchWords = highlights ?? []; | 
					
						
							|  |  |  |   if (hasAnsi) { | 
					
						
							|  |  |  |     const highlight = needsHighlighter ? { searchWords, highlightClassName } : undefined; | 
					
						
							|  |  |  |     return <LogMessageAnsi value={entry} highlight={highlight} />; | 
					
						
							|  |  |  |   } else if (needsHighlighter) { | 
					
						
							|  |  |  |     return ( | 
					
						
							|  |  |  |       <Highlighter | 
					
						
							|  |  |  |         textToHighlight={entry} | 
					
						
							|  |  |  |         searchWords={searchWords} | 
					
						
							|  |  |  |         findChunks={findHighlightChunksInText} | 
					
						
							|  |  |  |         highlightClassName={highlightClassName} | 
					
						
							|  |  |  |       /> | 
					
						
							|  |  |  |     ); | 
					
						
							|  |  |  |   } else { | 
					
						
							|  |  |  |     return entry; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const restructureLog = memoizeOne((line: string, prettifyLogMessage: boolean): string => { | 
					
						
							|  |  |  |   if (prettifyLogMessage) { | 
					
						
							|  |  |  |     try { | 
					
						
							|  |  |  |       return JSON.stringify(JSON.parse(line), undefined, 2); | 
					
						
							|  |  |  |     } catch (error) { | 
					
						
							|  |  |  |       return line; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   return line; | 
					
						
							|  |  |  | }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class UnThemedLogRowMessage extends PureComponent<Props> { | 
					
						
							| 
									
										
										
										
											2022-09-29 20:51:20 +08:00
										 |  |  |   logRowRef: React.RefObject<HTMLTableCellElement> = React.createRef(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-19 16:51:46 +08:00
										 |  |  |   onContextToggle = (e: React.SyntheticEvent<HTMLElement>) => { | 
					
						
							|  |  |  |     e.stopPropagation(); | 
					
						
							| 
									
										
										
										
											2022-10-19 17:01:45 +08:00
										 |  |  |     this.props.onToggleContext('open'); | 
					
						
							| 
									
										
										
										
											2022-09-19 16:51:46 +08:00
										 |  |  |   }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-29 20:51:20 +08:00
										 |  |  |   onShowContextClick = (e: React.SyntheticEvent<HTMLElement, Event>) => { | 
					
						
							|  |  |  |     const { scrollElement } = this.props; | 
					
						
							|  |  |  |     this.onContextToggle(e); | 
					
						
							|  |  |  |     if (scrollElement && this.logRowRef.current) { | 
					
						
							|  |  |  |       scrollElement.scroll({ | 
					
						
							|  |  |  |         behavior: 'smooth', | 
					
						
							|  |  |  |         top: scrollElement.scrollTop + this.logRowRef.current.getBoundingClientRect().top - window.innerHeight / 2, | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-19 16:51:46 +08:00
										 |  |  |   render() { | 
					
						
							|  |  |  |     const { | 
					
						
							|  |  |  |       row, | 
					
						
							|  |  |  |       theme, | 
					
						
							|  |  |  |       errors, | 
					
						
							|  |  |  |       hasMoreContextRows, | 
					
						
							|  |  |  |       updateLimit, | 
					
						
							| 
									
										
										
										
											2023-01-27 22:12:01 +08:00
										 |  |  |       runContextQuery, | 
					
						
							| 
									
										
										
										
											2022-09-19 16:51:46 +08:00
										 |  |  |       context, | 
					
						
							|  |  |  |       contextIsOpen, | 
					
						
							| 
									
										
										
										
											2022-09-29 16:00:01 +08:00
										 |  |  |       showRowMenu, | 
					
						
							| 
									
										
										
										
											2022-09-19 16:51:46 +08:00
										 |  |  |       wrapLogMessage, | 
					
						
							|  |  |  |       prettifyLogMessage, | 
					
						
							|  |  |  |       onToggleContext, | 
					
						
							| 
									
										
										
										
											2022-09-29 16:00:01 +08:00
										 |  |  |       app, | 
					
						
							| 
									
										
										
										
											2022-09-28 19:37:49 +08:00
										 |  |  |       logsSortOrder, | 
					
						
							| 
									
										
										
										
											2022-09-29 16:00:01 +08:00
										 |  |  |       showContextToggle, | 
					
						
							| 
									
										
										
										
											2023-01-27 22:12:01 +08:00
										 |  |  |       getLogRowContextUi, | 
					
						
							| 
									
										
										
										
											2022-09-19 16:51:46 +08:00
										 |  |  |     } = this.props; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const style = getLogRowStyles(theme, row.logLevel); | 
					
						
							|  |  |  |     const { hasAnsi, raw } = row; | 
					
						
							|  |  |  |     const restructuredEntry = restructureLog(raw, prettifyLogMessage); | 
					
						
							| 
									
										
										
										
											2022-09-29 16:00:01 +08:00
										 |  |  |     const shouldShowContextToggle = showContextToggle ? showContextToggle(row) : false; | 
					
						
							| 
									
										
										
										
											2023-01-25 02:10:27 +08:00
										 |  |  |     const styles = getStyles(theme, shouldShowContextToggle, app === CoreApp.Explore); | 
					
						
							| 
									
										
										
										
											2022-09-19 16:51:46 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     return ( | 
					
						
							| 
									
										
										
										
											2022-10-05 22:11:08 +08:00
										 |  |  |       <> | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |           // When context is open, the position has to be NOT relative. // Setting the postion as inline-style to
 | 
					
						
							|  |  |  |           // overwrite the more sepecific style definition from `style.logsRowMessage`.
 | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         <td | 
					
						
							|  |  |  |           ref={this.logRowRef} | 
					
						
							|  |  |  |           style={contextIsOpen ? { position: 'unset' } : undefined} | 
					
						
							|  |  |  |           className={style.logsRowMessage} | 
					
						
							| 
									
										
										
										
											2022-09-19 16:51:46 +08:00
										 |  |  |         > | 
					
						
							| 
									
										
										
										
											2022-10-05 22:11:08 +08:00
										 |  |  |           <div | 
					
						
							|  |  |  |             className={cx( | 
					
						
							|  |  |  |               { [styles.positionRelative]: wrapLogMessage }, | 
					
						
							|  |  |  |               { [styles.horizontalScroll]: !wrapLogMessage } | 
					
						
							|  |  |  |             )} | 
					
						
							|  |  |  |           > | 
					
						
							|  |  |  |             {contextIsOpen && context && ( | 
					
						
							|  |  |  |               <LogRowContext | 
					
						
							|  |  |  |                 row={row} | 
					
						
							| 
									
										
										
										
											2023-01-27 22:12:01 +08:00
										 |  |  |                 getLogRowContextUi={getLogRowContextUi} | 
					
						
							|  |  |  |                 runContextQuery={runContextQuery} | 
					
						
							| 
									
										
										
										
											2022-10-05 22:11:08 +08:00
										 |  |  |                 context={context} | 
					
						
							|  |  |  |                 errors={errors} | 
					
						
							|  |  |  |                 wrapLogMessage={wrapLogMessage} | 
					
						
							|  |  |  |                 hasMoreContextRows={hasMoreContextRows} | 
					
						
							|  |  |  |                 onOutsideClick={onToggleContext} | 
					
						
							|  |  |  |                 logsSortOrder={logsSortOrder} | 
					
						
							|  |  |  |                 onLoadMoreContext={() => { | 
					
						
							|  |  |  |                   if (updateLimit) { | 
					
						
							|  |  |  |                     updateLimit(); | 
					
						
							|  |  |  |                   } | 
					
						
							|  |  |  |                 }} | 
					
						
							|  |  |  |               /> | 
					
						
							|  |  |  |             )} | 
					
						
							| 
									
										
										
										
											2022-12-21 21:45:47 +08:00
										 |  |  |             <button className={cx(styles.logLine, styles.positionRelative, { [styles.rowWithContext]: contextIsOpen })}> | 
					
						
							| 
									
										
										
										
											2022-10-05 22:11:08 +08:00
										 |  |  |               {renderLogMessage(hasAnsi, restructuredEntry, row.searchWords, style.logsRowMatchHighLight)} | 
					
						
							| 
									
										
										
										
											2022-12-21 21:45:47 +08:00
										 |  |  |             </button> | 
					
						
							| 
									
										
										
										
											2022-10-05 22:11:08 +08:00
										 |  |  |           </div> | 
					
						
							|  |  |  |         </td> | 
					
						
							|  |  |  |         {showRowMenu && ( | 
					
						
							|  |  |  |           <td className={cx('log-row-menu-cell', styles.logRowMenuCell)}> | 
					
						
							| 
									
										
										
										
											2022-09-29 16:00:01 +08:00
										 |  |  |             <span className={cx('log-row-menu', styles.rowMenu)} onClick={(e) => e.stopPropagation()}> | 
					
						
							|  |  |  |               {shouldShowContextToggle && ( | 
					
						
							|  |  |  |                 <Tooltip placement="top" content={'Show context'}> | 
					
						
							| 
									
										
										
										
											2022-09-29 20:51:20 +08:00
										 |  |  |                   <IconButton size="md" name="gf-show-context" onClick={this.onShowContextClick} /> | 
					
						
							| 
									
										
										
										
											2022-09-29 16:00:01 +08:00
										 |  |  |                 </Tooltip> | 
					
						
							|  |  |  |               )} | 
					
						
							| 
									
										
										
										
											2022-09-19 16:51:46 +08:00
										 |  |  |               <Tooltip placement="top" content={'Copy'}> | 
					
						
							| 
									
										
										
										
											2022-10-19 17:58:16 +08:00
										 |  |  |                 <IconButton size="md" name="copy" onClick={() => navigator.clipboard.writeText(restructuredEntry)} /> | 
					
						
							| 
									
										
										
										
											2022-09-19 16:51:46 +08:00
										 |  |  |               </Tooltip> | 
					
						
							|  |  |  |             </span> | 
					
						
							| 
									
										
										
										
											2022-10-05 22:11:08 +08:00
										 |  |  |           </td> | 
					
						
							|  |  |  |         )} | 
					
						
							|  |  |  |       </> | 
					
						
							| 
									
										
										
										
											2022-09-19 16:51:46 +08:00
										 |  |  |     ); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | export const LogRowMessage = withTheme2(UnThemedLogRowMessage); | 
					
						
							|  |  |  | LogRowMessage.displayName = 'LogRowMessage'; |