@@ -22,6 +22,8 @@ import {
2222} from '@zwave-js/core'
2323import { createDefaultTransportFormat } from '@zwave-js/core/bindings/log/node'
2424import { JSONTransport } from '@zwave-js/log-transport-json'
25+ import winston from 'winston'
26+ import DailyRotateFile from 'winston-daily-rotate-file'
2527import { isDocker } from './utils'
2628import {
2729 AssociationAddress ,
@@ -133,6 +135,7 @@ import { socketEvents } from './SocketEvents'
133135import { isUint8Array } from 'util/types'
134136import { PkgFsBindings } from './PkgFsBindings'
135137import { join } from 'path'
138+ import * as path from 'path'
136139
137140export const deviceConfigPriorityDir = join ( storeDir , 'config' )
138141
@@ -2318,14 +2321,8 @@ class ZwaveClient extends TypedEventEmitter<ZwaveClientEventCallbacks> {
23182321
23192322 utils . parseSecurityKeys ( this . cfg , zwaveOptions )
23202323
2321- const logTransport = new JSONTransport ( )
2322- logTransport . format = createDefaultTransportFormat ( true , false )
2323-
2324- zwaveOptions . logConfig . transports = [ logTransport ]
2325-
2326- logTransport . stream . on ( 'data' , ( data ) => {
2327- this . socket . emit ( socketEvents . debug , data . message . toString ( ) )
2328- } )
2324+ // Setup driver logging based on format setting
2325+ this . setupDriverLogging ( zwaveOptions )
23292326
23302327 try {
23312328 if ( shouldUpdateSettings ) {
@@ -6946,6 +6943,105 @@ class ZwaveClient extends TypedEventEmitter<ZwaveClientEventCallbacks> {
69466943 }
69476944 } , 1000 )
69486945 }
6946+
6947+
6948+ private setupDriverLogging ( zwaveOptions : PartialZWaveOptions ) {
6949+ const logFormat = this . getLogFormat ( )
6950+
6951+ if ( logFormat === 'json' ) {
6952+ this . setupJsonDriverLogging ( zwaveOptions )
6953+ } else {
6954+ this . setupTextDriverLogging ( zwaveOptions )
6955+ }
6956+ }
6957+
6958+ private getLogFormat ( ) : 'text' | 'json' {
6959+ const settings = jsonStore . get ( store . settings )
6960+ return settings ?. gateway ?. logFormat || 'text'
6961+ }
6962+
6963+ private setupJsonDriverLogging ( zwaveOptions : PartialZWaveOptions ) {
6964+ const transports = [ ]
6965+
6966+ const parseFormat = this . createParseDriverJsonFormat ( )
6967+ const jsonFormat = winston . format . combine (
6968+ parseFormat ( ) ,
6969+ winston . format . timestamp ( ) ,
6970+ winston . format . json ( ) ,
6971+ )
6972+
6973+ // Console transport
6974+ transports . push ( new winston . transports . Console ( {
6975+ format : jsonFormat ,
6976+ } ) )
6977+
6978+ // File transport (if enabled)
6979+ if ( this . cfg . logToFile ) {
6980+ transports . push ( new DailyRotateFile ( {
6981+ filename : ZWAVEJS_LOG_FILE ,
6982+ auditFile : utils . joinPath ( logsDir , 'zwavejs-logs.audit.json' ) ,
6983+ datePattern : 'YYYY-MM-DD' ,
6984+ createSymlink : true ,
6985+ symlinkName : path . basename ( ZWAVEJS_LOG_FILE ) . replace ( '_%DATE%' , '_current' ) ,
6986+ zippedArchive : true ,
6987+ maxFiles : process . env . ZUI_LOG_MAXFILES || '7d' ,
6988+ maxSize : process . env . ZUI_LOG_MAXSIZE || '50m' ,
6989+ format : jsonFormat ,
6990+ } ) )
6991+ }
6992+
6993+ // WebSocket transport with JSON format
6994+ const jsonTransport = new JSONTransport ( )
6995+ jsonTransport . format = jsonFormat
6996+ transports . push ( jsonTransport )
6997+
6998+ // Configure driver
6999+ zwaveOptions . logConfig = {
7000+ ...zwaveOptions . logConfig ,
7001+ enabled : false ,
7002+ raw : true ,
7003+ showLogo : false ,
7004+ transports : transports ,
7005+ }
7006+
7007+ // Stream JSON logs to WebSocket for debug view
7008+ jsonTransport . stream . on ( 'data' , ( data ) => {
7009+ this . socket . emit ( socketEvents . debug , data . message . toString ( ) )
7010+ } )
7011+ }
7012+
7013+ private setupTextDriverLogging ( zwaveOptions : PartialZWaveOptions ) {
7014+ const logTransport = new JSONTransport ( )
7015+ logTransport . format = createDefaultTransportFormat ( true , false )
7016+
7017+ zwaveOptions . logConfig . transports = [ logTransport ]
7018+
7019+ logTransport . stream . on ( 'data' , ( data ) => {
7020+ this . socket . emit ( socketEvents . debug , data . message . toString ( ) )
7021+ } )
7022+ }
7023+
7024+ private createParseDriverJsonFormat ( ) {
7025+ return winston . format ( ( info ) => {
7026+ if ( typeof info . message === 'string' && info . message . startsWith ( '{' ) ) {
7027+ try {
7028+ const parsed = JSON . parse ( info . message )
7029+ // Flatten the nested structure: merge tags and message fields
7030+ if ( parsed . tags && parsed . message ) {
7031+ info . message = {
7032+ ...parsed . message ,
7033+ tags : parsed . tags
7034+ }
7035+ } else {
7036+ info . message = parsed
7037+ }
7038+ } catch ( e ) {
7039+ // Keep as string if parsing fails
7040+ }
7041+ }
7042+ return info
7043+ } )
7044+ }
69497045}
69507046
69517047export default ZwaveClient
0 commit comments