6565 <a-col :xs =" 24" :sm =" 8" >
6666 <tooltip-label :title =" 'Log Type'" :tooltip =" 'Log severity level'" />
6767 <a-select
68+ mode =" multiple"
6869 v-model:value =" selectedLogType"
6970 :placeholder =" 'Log Type'"
7071 style =" width : 100% " >
7172 <a-select-option
72- v-for =" level in ['CRITICAL', 'ERROR', 'WARN', 'INFO', 'DEBUG', 'TRACE'] "
73+ v-for =" level in logLevels "
7374 :key =" level"
7475 :value =" level" >
7576 {{ level }}
8990 :columns =" logTableColumns"
9091 :data-source =" filteredLogs"
9192 :rowKey =" record => record.id"
92- :pagination =" { pageSize: 50 }"
93+ :pagination =" false"
94+ :showHeader =" false"
95+ :bordered =" false"
9396 size =" small"
94- bordered
95- style =" margin : 16px "
96- />
97+ style =" margin : 16px " >
98+ <template #bodyCell =" { column , record } " >
99+ <template v-if =" column .key === ' message' " >
100+ <div
101+ style =" font-family : monospace ; white-space : pre-wrap ; font-size : 13px ;"
102+ v-html =" highlightLogLevels(record.message)"
103+ ></div >
104+ </template >
105+ </template >
106+ </a-table >
97107 </div >
98108 <div class =" footer" >
99109 <div class =" footer-left" v-if =" filtersAsString" >{{ $t('message.showing.logs').replace('%x', filtersAsString) }}</div >
109119 </template >
110120
111121<script >
112- import { h } from ' vue'
113122import { api } from ' @/api'
114123import TooltipLabel from ' @/components/widgets/TooltipLabel'
115124
@@ -140,50 +149,7 @@ export default {
140149 webSocketData: ' ' ,
141150 selectedLogType: undefined ,
142151 dataSource: [],
143- logLeves: [' CRITICAL' , ' ERROR' , ' WARN' , ' INFO' , ' DEBUG' , ' TRACE' ],
144- logTableColumns: [
145- {
146- title: ' Source' ,
147- dataIndex: ' sourceName' ,
148- key: ' sourceName' ,
149- width: 150
150- },
151- {
152- title: ' Timestamp' ,
153- dataIndex: ' timestamp' ,
154- key: ' timestamp' ,
155- width: 200
156- },
157- {
158- title: ' Level' ,
159- dataIndex: ' level' ,
160- key: ' level' ,
161- width: 100 ,
162- filters: ([' CRITICAL' , ' ERROR' , ' WARN' , ' INFO' , ' DEBUG' , ' TRACE' ]).map (level => ({ text: level, value: level })),
163- onFilter : (value , record ) => record .level === value,
164- customRender : ({ text }) => {
165- const levelColor = {
166- CRITICAL : ' red' ,
167- ERROR : ' red' ,
168- WARN : ' orange' ,
169- INFO : ' blue' ,
170- DEBUG : ' green' ,
171- TRACE : ' gray'
172- }
173- return h (' span' , {
174- style: {
175- color: levelColor[text] || ' black' ,
176- fontWeight: ' bold'
177- }
178- }, text || ' N/A' )
179- }
180- },
181- {
182- title: ' Message' ,
183- dataIndex: ' message' ,
184- key: ' message'
185- }
186- ]
152+ logLevels: [' CRITICAL' , ' ERROR' , ' WARN' , ' INFO' , ' DEBUG' , ' TRACE' ]
187153 }
188154 },
189155 watch: {
@@ -201,12 +167,35 @@ export default {
201167 showRawLogs () {
202168 return false
203169 },
170+ showSourceOnlyWhenMultiple () {
171+ return true
172+ },
204173 filtersAsString () {
205174 if (! this .filters ) {
206175 return null
207176 }
208177 return this .filters .join (' , ' )
209178 },
179+ logTableColumns () {
180+ const columns = []
181+
182+ if (! this .showSourceOnlyWhenMultiple || (this .selectedWebSockets && this .selectedWebSockets .length > 1 )) {
183+ columns .push ({
184+ title: ' Source' ,
185+ dataIndex: ' sourceName' ,
186+ key: ' sourceName' ,
187+ width: 150
188+ })
189+ }
190+
191+ columns .push ({
192+ title: ' Message' ,
193+ dataIndex: ' message' ,
194+ key: ' message'
195+ })
196+
197+ return columns
198+ },
210199 webSocketsValid () {
211200 return this .webSockets && this .webSockets .length > 0
212201 },
@@ -217,12 +206,12 @@ export default {
217206 return 0
218207 },
219208 filteredLogs () {
220- if (! this .dataSource || this .dataSource .length === 0 ) {
221- return []
222- }
209+ if (! this .dataSource || this .dataSource .length === 0 ) return []
210+
223211 return this .dataSource .filter (log => {
224212 const sourceMatch = ! this .selectedWebSockets || this .selectedWebSockets .length === 0 || this .selectedWebSockets .includes (log .sourceId )
225- return sourceMatch
213+ const levelMatch = ! this .selectedLogType || this .selectedLogType .length === 0 || this .selectedLogType .includes (log .level )
214+ return sourceMatch && levelMatch
226215 })
227216 }
228217 },
@@ -298,7 +287,6 @@ export default {
298287 opts .push (opt)
299288 }
300289 this .webSockets = opts .sort ((a , b ) => a .title .localeCompare (b .title ))
301- this .selectedWebSockets = this .webSockets .map (opt => opt .id )
302290 console .log (' WebSockets prepared:' , this .webSockets )
303291 this .openWebSockets ()
304292 },
@@ -340,18 +328,16 @@ export default {
340328
341329 var level = null
342330 var timestamp = new Date ().toISOString ()
343- var message = line
344331 if (match) {
345332 timestamp = match[1 ]
346333 level = match[2 ]
347- message = match[3 ]
348334 }
349335
350336 return {
351337 id: sourceId + ' -' + timestamp,
352338 timestamp: timestamp,
353339 level: level,
354- message: message ,
340+ message: line ,
355341 sourceId,
356342 sourceName
357343 }
@@ -381,6 +367,16 @@ export default {
381367 escaped = escaped .replace (/ (INFO)/ g , ' <span style="color: blue">$1</span>' )
382368 return escaped
383369 },
370+ highlightLogLevels (message ) {
371+ if (! message) return ' '
372+ return message
373+ .replace (/ CRITICAL/ g , ' <span style="color: red; font-weight: bold;">CRITICAL</span>' )
374+ .replace (/ ERROR/ g , ' <span style="color: red; font-weight: bold;">ERROR</span>' )
375+ .replace (/ WARN/ g , ' <span style="color: orange; font-weight: bold;">WARN</span>' )
376+ .replace (/ INFO/ g , ' <span style="color: blue; font-weight: bold;">INFO</span>' )
377+ .replace (/ DEBUG/ g , ' <span style="color: green; font-weight: bold;">DEBUG</span>' )
378+ .replace (/ TRACE/ g , ' <span style="color: gray; font-weight: bold;">TRACE</span>' )
379+ },
384380 onDownload () {
385381 let htmlString = this .webSocketData .replace (/ <br\s * \/ ? >/ gi , ' \n ' )
386382 // Optionally, handle closing </p> tags for paragraphs
0 commit comments