1import React from 'react'; 2import { LogsDedupStrategy, LogsMetaItem, LogsMetaKind, LogRowModel } from '@grafana/data'; 3import { Button, Tooltip, Icon, LogLabels } from '@grafana/ui'; 4import { MAX_CHARACTERS } from '@grafana/ui/src/components/Logs/LogRowMessage'; 5import { MetaInfoText, MetaItemProps } from './MetaInfoText'; 6 7export type Props = { 8 meta: LogsMetaItem[]; 9 dedupStrategy: LogsDedupStrategy; 10 dedupCount: number; 11 showDetectedFields: string[]; 12 hasUnescapedContent: boolean; 13 forceEscape: boolean; 14 logRows: LogRowModel[]; 15 onEscapeNewlines: () => void; 16 clearDetectedFields: () => void; 17}; 18 19export const LogsMetaRow: React.FC<Props> = React.memo( 20 ({ 21 meta, 22 dedupStrategy, 23 dedupCount, 24 showDetectedFields, 25 clearDetectedFields, 26 hasUnescapedContent, 27 forceEscape, 28 onEscapeNewlines, 29 logRows, 30 }) => { 31 const logsMetaItem: Array<LogsMetaItem | MetaItemProps> = [...meta]; 32 33 // Add deduplication info 34 if (dedupStrategy !== LogsDedupStrategy.none) { 35 logsMetaItem.push({ 36 label: 'Dedup count', 37 value: dedupCount, 38 kind: LogsMetaKind.Number, 39 }); 40 } 41 // Add info about limit for highlighting 42 if (logRows.some((r) => r.entry.length > MAX_CHARACTERS)) { 43 logsMetaItem.push({ 44 label: 'Info', 45 value: 'Logs with more than 100,000 characters could not be parsed and highlighted', 46 kind: LogsMetaKind.String, 47 }); 48 } 49 50 // Add detected fields info 51 if (showDetectedFields?.length > 0) { 52 logsMetaItem.push( 53 { 54 label: 'Showing only detected fields', 55 value: renderMetaItem(showDetectedFields, LogsMetaKind.LabelsMap), 56 }, 57 { 58 label: '', 59 value: ( 60 <Button variant="secondary" size="sm" onClick={clearDetectedFields}> 61 Show all detected fields 62 </Button> 63 ), 64 } 65 ); 66 } 67 68 // Add unescaped content info 69 if (hasUnescapedContent) { 70 logsMetaItem.push({ 71 label: 'Your logs might have incorrectly escaped content', 72 value: ( 73 <Tooltip 74 content="We suggest to try to fix the escaping of your log lines first. This is an experimental feature, your logs might not be correctly escaped." 75 placement="right" 76 > 77 <Button variant="secondary" size="sm" onClick={onEscapeNewlines}> 78 <span>{forceEscape ? 'Remove escaping' : 'Escape newlines'} </span> 79 <Icon name="exclamation-triangle" className="muted" size="sm" /> 80 </Button> 81 </Tooltip> 82 ), 83 }); 84 } 85 86 return ( 87 <> 88 {logsMetaItem && ( 89 <MetaInfoText 90 metaItems={logsMetaItem.map((item) => { 91 return { 92 label: item.label, 93 value: 'kind' in item ? renderMetaItem(item.value, item.kind) : item.value, 94 }; 95 })} 96 /> 97 )} 98 </> 99 ); 100 } 101); 102 103LogsMetaRow.displayName = 'LogsMetaRow'; 104 105function renderMetaItem(value: any, kind: LogsMetaKind) { 106 if (kind === LogsMetaKind.LabelsMap) { 107 return ( 108 <span className="logs-meta-item__labels"> 109 <LogLabels labels={value} /> 110 </span> 111 ); 112 } else if (kind === LogsMetaKind.Error) { 113 return <span className="logs-meta-item__error">{value}</span>; 114 } 115 return value; 116} 117