Custom logger in settings.js to write the logs to a filesystem?

Hi,
I am looking out for a solution on how to write nodered logs to filesystem. I tried using the logger in settings.js but couldnt find an appropriate way to do that. Please Help !!

Hi @Josh

You shouldn't need to resort to changing things in settings.js.
the function node exposes.

  • node.log()
  • node.warn()
  • node.error()

That should, under normal circumstances, output to the corresponding log file.

see below:

Or perhaps node-red-contrib-flogger will do what you want.

1 Like

I don't have exactly what you want. But I do have an example that writes to MQTT and that outputs trace logging but only for uibuilder (of course, you could change the filter to whatever you wanted).

Also included, but commented out is an example of logging to a Winston instance which might be of interest. I can't remember whether I stole it with pride from someone I'm afraid. Not even sure it actually works but anyway, might be a starting point.

    logging: {
        console: {
            /** Level of logging to be recorded. Options are:
             * fatal - only those errors which make the application unusable should be recorded
             * error - record errors which are deemed fatal for a particular request + fatal errors
             * warn - record problems which are non fatal + errors + fatal errors
             * info - record information about the general running of the application + warn + error + fatal errors
             * debug - record information which is more verbose than info + info + warn + error + fatal errors
             * trace - record very detailed logging + debug + info + warn + error + fatal errors
             * off - turn off all logging (doesn't affect metrics or audit)
             */
            level: 'info',
            /** Whether or not to include metric events in the log output */
            metrics: false,
            /** Whether or not to include audit events in the log output */
            audit: false,
        },
        /** Custom logging: https://nodered.org/docs/user-guide/runtime/logging */

        // winstonLog: {
        //     level: 'trace',
        //     metrics: false,
        //     audit: false,
        //     handler: function(settings) {
        //         // const winstond = require('winstond')

        //         // const server = winstond.nssocket.createServer({
        //         //     services: ['collect', 'query', 'stream'],
        //         //     port: 9003
        //         // });

        //         // server.add(winstond.transports.File, {
        //         //     filename: __dirname + '/foo.log'
        //         // })

        //         // server.listen()

        //         // const winston = require('winston')
        //         // require('winston-mqtt').MqttTransport

        //         const myCustomLevels = {
        //             levels: {
        //                 'FATAL':10, 
        //                 'ERROR':20, 
        //                 'WARN ':30, 
        //                 'INFO ':40, 
        //                 'DEBUG':50, 
        //                 'TRACE':60, 
        //                 'AUDIT':98, 
        //                 'MTRIC':99
        //             },
        //             colors: {
        //                 'FATAL':'redBG', 
        //                 'ERROR':'red', 
        //                 'WARN ':'orange', 
        //                 'INFO ':'yellow', 
        //                 'DEBUG':'green', 
        //                 'TRACE':'cyan', 
        //                 'AUDIT':'grey', 
        //                 'MTRIC':'grey'
        //             }
        //         }

        //         // winston.add(require('winston-nssocket').Nssocket, {
        //         //     host: 'localhost',
        //         //     port: 9003
        //         // })

        //         // const { combine, timestamp, label, printf, splat, prettyPrint, colorize } = winston.format

        //         // const myFormat = printf(({ level, message, label, timestamp }) => {
        //         //     //return `${timestamp} ${level}| [${label}] ${message}`
        //         //     return `${level}| ${message.replace('[uibuilder:','[')}`
        //         // })

        //         // var mylog = winston.createLogger({
        //         //     levels: myCustomLevels.levels, //winston.config.npm.levels, //
        //         //     level: 'TRACE',
        //         //     transports: [
        //         //         //new winston.transports.Console({ format: winston.format.simple() }),
        //         //         new winston.transports.File({ filename: 'uibuilder1.log' }),
        //         //         new winston.transports.Http({ // https://github.com/winstonjs/winston/blob/HEAD/docs/transports.md#http-transport
        //         //             host: 'localhost',
        //         //             port: 1880,
        //         //             path: '/nr/winston',
        //         //             // auth, ssl
        //         //         }),
        //         //         new winston.transports.MqttTransport, {
        //         //             name: 'node-red',
        //         //             topic: 'log',
        //         //             host: 'mqtt://localhost:1883',
        //         //             // requestTracer: {
        //         //             //   instance: myRequestObject,
        //         //             //   property: 'requestId'
        //         //             // }
        //         //          }
        //         //     ],
        //         //     // https://github.com/winstonjs/logform#readme
        //         //     format: combine(
        //         //         //label({ label: 'right meow!' }),
        //         //         //timestamp(),
        //         //         colorize({ colors: myCustomLevels.colors, all:true }),
        //         //         prettyPrint(),
        //         //         myFormat
        //         //     ),
        //         // })

        //         // mylog.log({
        //         //     'level': 'TRACE',
        //         //     'message': 'Hello'
        //         // })

        //         // winston.stream().on('log', function (log) {
        //         //     console.log(log);
        //         // });

        //         // winston.query({ start: 10 }, function (err, results) {
        //         //     if (err) throw err;
        //         //     console.log(results);
        //         // });

        //         const nrLogLevels = {
        //             10: 'FATAL', 20: 'ERROR', 30: 'WARN ', 40: 'INFO ', 50: 'DEBUG', 60: 'TRACE', 98: 'AUDIT', 99: 'MTRIC'
        //         }

        //         // return function(msg) {
        //         //     if ( msg.level < 51 || msg.msg.includes('[uibuilder') || msg.msg.startsWith('+-') || msg.msg.startsWith('| ') || msg.msg.startsWith('>>') ) {
        //         //         mylog.log({
        //         //             'level': nrLogLevels[msg.level],
        //         //             'message': msg.msg
        //         //         })
        //         //     }
        //         // }
        //     }
        // },
        mqttLog: {
            level: 'trace',
            metrics: false,
            audit: false,
            handler: function(settings) {
                const nrLogLevels = {
                    10: 'FATAL', 20: 'ERROR', 30: 'WARN ', 40: 'INFO ', 50: 'DEBUG', 60: 'TRACE', 98: 'AUDIT', 99: 'MTRIC'
                }
                const myCustomLevels = {
                    levels: {
                        'FATAL':10, 
                        'ERROR':20, 
                        'WARN ':30, 
                        'INFO ':40, 
                        'DEBUG':50, 
                        'TRACE':60, 
                        'AUDIT':98, 
                        'MTRIC':99
                    },
                    colors: {
                        'FATAL':'redBG', 
                        'ERROR':'red', 
                        'WARN ':'orange', 
                        'INFO ':'yellow', 
                        'DEBUG':'green', 
                        'TRACE':'cyan', 
                        'AUDIT':'grey', 
                        'MTRIC':'grey'
                    } 
                }

                const mqtt = require('mqtt')
                const client  = mqtt.connect('mqtt://home.knightnet.co.uk')

                return function(msg) {
                    if ( msg.level < 51 || msg.msg.includes('[uibuilder') || msg.msg.startsWith('+-') || msg.msg.startsWith('| ') || msg.msg.startsWith('>>') ) {
                        client.publish( 'nrlog/dev', JSON.stringify(msg) )
                    }
                }
            }
        },
    },
1 Like

I use winston quite a bit.
I use a Node lib that allows adding Winston 'transports' to its framework - so added a transport to send logs out to a 2nd pin.

very versatile

@TotallyInformation I have done as per what you have said and it seems Im having trouble starting the Node-Red. I am trying with the winston instance and it would be a great help if you could let me know which part of code is necessary for that operation.

I think you will need to share what errors you are getting. I don't use Winston actively.

I am getting Error loading settings while I try to run the Script.

Sorry Josh but that doesn't really help. We would need to see the actual errors to have any hope of understanding what was happening.

Apologies for the late response. I did solve the problem using the 'Pino' Module. Anyways @TotallyInformation your approach led me straight in solving this problem.

Please find the attached code.

Note: Please install the required npm packages

var pino = require('pino');
var fs = require('fs');

var rotatingLogStream = require('file-stream-rotator').getStream({filename:"./path_%DATE%",frequency:"custom",verbose: false ,size:"100M", max_logs: "10d", audit_file:"./path/logaudit.json",date_format: "YYYY-MM-DD-A",extension:".log"});

rotatingLogStream.on('rotate',function(oldFile,newFile){
    console.log("Rotate",oldFile)
})

var logger = pino({}, rotatingLogStream);

module.exports ={
console: {
             /** Level of logging to be recorded. Options are:
              * fatal - only those errors which make the application unusable should be recorded
              * error - record errors which are deemed fatal for a particular request + fatal errors
              * warn - record problems which are non fatal + errors + fatal errors
              * info - record information about the general running of the application + warn + error + fatal errors
              * debug - record information which is more verbose than info + info + warn + error + fatal errors
              * trace - record very detailed logging + debug + info + warn + error + fatal errors
              * off - turn off all logging (doesn't affect metrics or audit)
              */
             level: "debug",
             /** Whether or not to include metric events in the log output */
             metrics: false,
             /** Whether or not to include audit events in the log output */
             audit: true
         },
         customlogger: {
            level: 'debug',
            metrics: false,
            audit: false,
            handler: function (settings) {
                return function (log) {
                    switch (log.level) {
                        case 'fatal':
                            logger.fatal(log.msg);
                            break;
                        case 'error':
                            logger.error(log.msg);
                            break;
                        case 'warn':
                            logger.warn(log.msg);
                            break;
                        case 'info':
                            logger.info(log.msg);
                            break;
                        case 'debug':
                            logger.debug(log.msg);
                            break;
                        case 'trace':
                            logger.trace(log.msg);
                            break;
                        default:
                            logger.info(log.msg);
                            break;
                    }
                };
            }
        }
}

This is something I did consider while developing. Thanks for the info :smiley:

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.