@@ -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 ,
@@ -2318,14 +2320,8 @@ class ZwaveClient extends TypedEventEmitter<ZwaveClientEventCallbacks> {
23182320
23192321 utils . parseSecurityKeys ( this . cfg , zwaveOptions )
23202322
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- } )
2323+ // Setup driver logging based on format setting
2324+ this . setupDriverLogging ( zwaveOptions )
23292325
23302326 try {
23312327 if ( shouldUpdateSettings ) {
@@ -6946,6 +6942,111 @@ class ZwaveClient extends TypedEventEmitter<ZwaveClientEventCallbacks> {
69466942 }
69476943 } , 1000 )
69486944 }
6945+
6946+ /**
6947+ * Setup driver logging based on the configured format (text or JSON)
6948+ * Uses the same logFormat setting as the gateway for consistency
6949+ */
6950+ private setupDriverLogging ( zwaveOptions : PartialZWaveOptions ) {
6951+ // Get the log format from gateway settings - this applies to both app and driver logging
6952+ const settings = jsonStore . get ( store . settings )
6953+ const logFormat = settings ?. gateway ?. logFormat || 'text'
6954+
6955+ if ( logFormat === 'json' ) {
6956+ // JSON logging for driver - create custom transports for all outputs
6957+ const transports = [ ]
6958+
6959+ // Custom format to parse driver's JSON strings before Winston formatting
6960+ const parseDriverJsonFormat = winston . format ( ( info ) => {
6961+ if ( typeof info . message === 'string' && info . message . startsWith ( '{' ) ) {
6962+ try {
6963+ info . message = JSON . parse ( info . message )
6964+ } catch ( e ) {
6965+ // Keep as string if parsing fails
6966+ }
6967+ }
6968+ return info
6969+ } )
6970+
6971+ // Custom console transport for JSON output
6972+ const jsonConsoleTransport = new winston . transports . Console ( {
6973+ format : winston . format . combine (
6974+ parseDriverJsonFormat ( ) ,
6975+ winston . format . timestamp ( ) ,
6976+ winston . format . json ( ) ,
6977+ ) ,
6978+ } )
6979+ transports . push ( jsonConsoleTransport )
6980+
6981+ // Custom file transport for JSON output (if file logging is enabled)
6982+ // Use DailyRotateFile to maintain symlink functionality and proper date handling
6983+ if ( this . cfg . logToFile ) {
6984+ const fileTransport = new DailyRotateFile ( {
6985+ filename : ZWAVEJS_LOG_FILE ,
6986+ auditFile : ZWAVEJS_LOG_FILE . replace (
6987+ '_%DATE%' ,
6988+ '_logrotate' ,
6989+ ) . replace ( '.log' , '.json' ) ,
6990+ datePattern : 'YYYY-MM-DD' ,
6991+ createSymlink : true ,
6992+ symlinkName : 'zwavejs_current.log' ,
6993+ zippedArchive : true ,
6994+ maxFiles : `${ this . cfg . maxFiles || 7 } d` ,
6995+ maxSize : '50m' ,
6996+ format : winston . format . combine (
6997+ parseDriverJsonFormat ( ) ,
6998+ winston . format . timestamp ( ) ,
6999+ winston . format . json ( ) ,
7000+ ) ,
7001+ } )
7002+ transports . push ( fileTransport )
7003+ }
7004+
7005+ // Custom WebSocket transport for JSON output
7006+ const jsonTransport = new JSONTransport ( )
7007+ jsonTransport . format = winston . format . combine (
7008+ parseDriverJsonFormat ( ) ,
7009+ winston . format . timestamp ( ) ,
7010+ winston . format . json ( ) ,
7011+ )
7012+ transports . push ( jsonTransport )
7013+
7014+ // Configure driver to use ONLY our custom transports
7015+ // Disable internal transports and use only our custom ones
7016+ zwaveOptions . logConfig = {
7017+ ...zwaveOptions . logConfig ,
7018+ enabled : false , // This disables ALL internal transports
7019+ raw : true ,
7020+ showLogo : false ,
7021+ transports : transports , // Use ONLY our custom transports
7022+ }
7023+
7024+ // Stream JSON logs to WebSocket for debug view
7025+ jsonTransport . stream . on ( 'data' , ( data ) => {
7026+ this . socket . emit ( socketEvents . debug , data . message . toString ( ) )
7027+ } )
7028+ } else {
7029+ // Text logging for driver (preserve original behavior)
7030+ // Ensure console output by setting forceConsole: true when logToFile: true
7031+ // This matches the original behavior where console logs were visible
7032+ zwaveOptions . logConfig . forceConsole = true
7033+
7034+ // Add JSONTransport for WebSocket streaming alongside existing transports
7035+ const logTransport = new JSONTransport ( )
7036+ logTransport . format = createDefaultTransportFormat ( true , false )
7037+
7038+ // Add JSONTransport to existing transports instead of replacing them
7039+ if ( ! zwaveOptions . logConfig . transports ) {
7040+ zwaveOptions . logConfig . transports = [ ]
7041+ }
7042+ zwaveOptions . logConfig . transports . push ( logTransport )
7043+
7044+ // Stream logs to WebSocket for debug view
7045+ logTransport . stream . on ( 'data' , ( data ) => {
7046+ this . socket . emit ( socketEvents . debug , data . message . toString ( ) )
7047+ } )
7048+ }
7049+ }
69497050}
69507051
69517052export default ZwaveClient
0 commit comments