Format functions may return objects for streams in objectMode #272
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Currently Morgan converts the return value of a format function to string (by means of concatenating it with a new-line). In some cases it would be convenient to allow objects returned by the format function to be passed directly to the stream, provided that the underlying stream can consume objects.
A stream that operates in "object mode" can operate on objects other than just strings and buffers. (See https://nodejs.org/docs/latest-v19.x/api/stream.html#object-mode) The
writableObjectMode
flag of a stream can be used to determine whether a stream is operating in object mode. (See https://nodejs.org/docs/latest-v19.x/api/stream.html#writablewritableobjectmode) This has been part of the Node API since version 12.This change simply alters Morgan so that it does not concatenate the return value of a format function with a new-line as long as (1) the return value is an object, and (2) the underlying stream's
writableObjectMode
flag is truthy. It also adds two unit tests: the first verifies that an object will be passed to the stream without modification if it is in object mode; the second verifies that an object will be converted to a string if the stream is not in object mode (as is the current behavior). I did not make any changes to the README, but I would be willing to if you were intending to accept this request.As an example of why this is useful, the following code snippet shows how this change allows Morgan to work in conjunction with Winston to create an access log in JSON format. By providing the data as an object instead of a string, the individual pieces of data can be easily utilized by the underlying logger.
This change does alter existing behavior. However, the
objectMode
option for streams is false by default. (See https://nodejs.org/docs/latest-v19.x/api/stream.html#stream_new_stream_writable_options) More specifically, it is false inprocess.stdout
, in streams created byfs.createWriteStream
, and in streams created byrequire('rotating-file-stream').createStream
-- which are the three types of streams mentioned in the README. Furthermore, using built-in formats and format strings always results in a string value. Therefore, the only way this could be a breaking change is if a user (1) used a custom format function that returned an object, (2) used an underlying stream that hadwritableObjectMode
set to true, and (3) was relying on Morgan to convert the object to a string. This seems highly unlikely, and, even if it did happen, could be fixed by merely updating the format function to convert its return value to string.Note that there is currently a work-around for this issue, which is to make the format function return JSON, and the underlying stream parse the JSON, as described in https://betterstack.com/community/guides/logging/how-to-install-setup-and-use-winston-and-morgan-to-log-node-js-applications/#logging-in-an-express-application-using-winston-and-morgan. This works, but is inefficient and inelegant.