logIO - logging on steroids

Hello!

Preface

In the beginning of the year I decided to broaden my knowledge in ELK stack, thus I set up a local ElasticSearch and Kibana and then I needed some data ... lots of it.
Instead of using numerous meaningless data sets I though about leveraging my Node-Red instance and all the running flows inside it that produce thousands of messages per day. Should be enough to get me going.

And as we know how changing the light bulb leads to fixing everything else, ELK will wait and my first custom Node-Red node logIO is almost ready for release.

I'll appreciate if you take a look, maybe even test it if fits in your flows and give me some pointers or ideas before I make 1.0.0 release.

I'd aso like to thank everyone here, this forum was super helpful during development and I took some inspirations not only from official nodes but also nodes you built and shared here.

logIO

As the name suggests, logIO node logs INPUT and OUTPUT messages from nodes. Contrary to other nodes out there, you don't have to wire each and every node you want to log directly to logIO, but you can use it similar to core catch or status components. Of course you can use it also as core debug component with additional improvement here too.

Log outputs:
logIO currently supports following log outputs (multiple can be selected):

  • Node-Red debugger panel
  • System console (supports: colored output based on log level, json output, utc/local timestamps, additional meta data)
  • File (supports file rotation, compression and deletion of old logs, json output, utc/local timestamps, additional meta data)
  • ElasticSearch (sends logs directly to elasticsearch - tested with ES version > 8, supports: utc/local timestamps, additional meta data, custom index definition)

Log modes
inline [default] mode
In this mode, logIO behaves similar to core debug node, where you can pipe other nodes into logIO and input messages will be logged.

BUT you will notice that in inline mode, logIO has also an output, thus you can include in in the middle of the flow. if so, logIO will automatically log every input and output message of all the components that come after it.

flow, select, all modes
In these modes, logIO behaves similar to core catch or status components, meaning you don't have to wire other components into it, but it will still log input and output messages of all, current flow or selected nodes.

Controlling the node logging
By default, logIO will log messages of all connected or selected nodes from deploy onward.

You can disable this behavior by deselecting the Automatically start logging at startup and activate the logIO node through incoming message.

To activate logging, incoming message should have a _logIO_ object with key activate set to true:

{
  "payload" : "your payload",
  "topic": "your topic",
  "_logIO_" : { "activate": true }
}

To deactivate logging, incoming message should have a _logIO_ object with key activate set to false:

{
  "payload" : "your payload",
  "topic": "your topic",
  "_logIO_" : { "activate": false }
}

You can also toggle the logging through components button same as in core debug component.
Have in mind that those two actions are not the same and for example if you activated the logIO through incoming message but logIO is deactivated in editor, logging will still be paused.

Logging status and mode are also displayed in status of the component for easier visualization.

:pushpin: If logging is deactivated and logIO is in inline mode, logIO will act as a pass through component. It will not produce any logs, just pass the message onward as is.

Log levels: [error, warn, info, debug]

Default log level is set to debug.

If message doesn't have its own logLevel, it will be assigned one as defined in logIO and always logged. In this case logIO doesn't act as a filter, but only attaches the selected logLevel to the log entry.

Of course more common case is that you want to log you messages based on severity, so if the message contains _logIO_ object with key logLevel set to one of allowed levels, that one will be used for:

  1. displaying that log level in log entry
  2. omitting the message from logs, if current message logLevel priority is lower than logIO log level priority

e.g: logIO log level is set to warn

This message will be logged.

{
  "payload" : "your payload",
  "topic": "your topic",
  "_logIO_" : { "logLevel": "error" }
}

This message will be logged.

{
  "payload" : "your payload",
  "topic": "your topic",
  "_logIO_" : { "logLevel": "warn" }
}

This message will be logged with warn logLevel (same as logIO defined log level)

{
  "payload" : "your payload",
  "topic": "your topic",
}

This message will NOT be logged.

{
  "payload" : "your payload",
  "topic": "your topic",
  "_logIO_" : { "logLevel": "info" }
}

:question: Here I have a question, would it make more sense to put logLevel directly on message and not inside _logLevel_ key? What are you currently using - is there any convention?

{
  "payload" : "your payload",
  "topic": "your topic",
  "logLevel": "error" 
}

To install and try it out, search for @zigasebenik/node-red-log-io or install manually (as I don't know how long in takes to appear in Node-Red after submitting it).

npm install @zigasebenik/node-red-log-io

Github repo is here.

I have to polish the editor a bit and properly document everything in the following days based on potential upcoming changes. Nevertheless it's ready to test it out.

3 Likes

Hi, this looks like a great addition. thanks for your efforts. While i have not tried it out (yet) i did have a peek at the dependencies.

I noted that the @zigasebenik/node-red-log-io package depends on @zigasebenik/winston-daily-rotate-file which in turn depends on @zigasebenik/file-stream-rotator which has a dependency on moment. As I am sure you are aware, moment is pretty much dead in the water these days. However that is not my point, my point is that the @zigasebenik/node-red-log-io package itself already depends on dayjs (which is pretty much a recommended replacement for moment). Is there any reason the sub-dependency doesnt also use dayjs instead of moment?

Hi Steve, thanks for taking time to check and for your question.

I know about moment being deprecated for a while now thus we are switching to dayjs or other libraries whenever making something new. It's not even hard to refactor a project from moment to dayjs as APIs are basically the same.

Here in this case I was originally using following dependencies:
winston
winston-daily-rotate-file

Then I discovered a bug were if you are logging results to a file and that file gets deleted, new one is not created. It goes further than that, if inode of the file gets changed during save (some editors do that and it also might be OS dependent), logging to that file was also interrupted.

I inspected the dependencies of winston-daily-rotate-file and found a cause of the bug in one of it's dependencies file-stream-rotator.

Thus I created a fork of it fixing the bug (bug is already reported to original project, and in the future I plan to make a PR). But in the mean time I had to use my forks where bug seems to be fixed in my Node-Red plugin.

So to the answer about moment, as it's used in currently forked projects I don't plan to refactor those in order to replace it with dayjs. Hopefully though future PR will be accepted and I can switch logIO dependencies back to original ones. Although that will not resolve the moment library inclusion :slight_smile:

Nice. Thanks for contributing.

Personally, I would prefer the use of _logLevel as that is much less likely to cause a property clash.

Hi, thanks for your input. I formulated the question a bit odd and now not sure if we're aligned, so like this:

{
  "payload": ...,
  "_logLevel": "error"
}

or scoped inside _logIO_ key

{
  "payload": ...,
  "_logIO_": { "logLevel": "error" }
}

I have another question, is there a good or proper way to get all nodes connected to particular node? As now I can easily get nodes that come out of one node by following the wires (only out wires seem to be defined on node). To get all connected nodes that came into certain node would require some more loops over RED.nodes.eachNode.

Sorry, my bad for replying when I should have been working! :slight_smile:

Yes, _logIO or _logIO_ would be preferred I believe. With the level as a property.

1 Like

I figured it out with only 1 pass over RED.nodes.eachNode and then partial and selective passes over forward connection nodes - should be pretty efficient and is done only upon node deploy.

So now this enables me to do things a bit differently.

I got rid of logIOs output node (as it was a bit confusing tbh), so now inline mode behaves exactly the same as core debug node.

I introduced a new mode called wired and in this mode, all nodes that are in any way connected to logIO are being logged. Example included in 0.9.2 release.

Plus I added option to choose to log either only INPUT or both INPUT and OUTPUT messages.