admin管理员组

文章数量:1303412

I want to wrap a array, e.g. an Uint8Array, into a NodeJS.WritableStream so I can read its content later. How can I do that?

Background: For testing my winston logger, I want to set up a custom transport which just holds all the logged data in a manner I can evaluate it later. The example reads like this:

logger.add(new winston.transports.Stream({
  stream: fs.createWriteStream('/dev/null')
  /* other options */
}));

But if I create the stream like fs.createWriteStream('/dev/null'), I cannot see its content, and it won't run under Windows (or at least I'm having issues here atm). And why would I need fs anyway?

To give another illustration where I'm coming from, let's take this arbitraty example from Go:

buf := bytes.Buffer{}
// zerolog.New() expects an io.Writable, similar to a NodeJS.WritableStream
logger := zerolog.New(&buf)
logger.Info().Msg("Hello World")
// I can access the written data by acessing the underlying buffer
assert.Equal(t, buf.String(), "{\"level\":\"info\",\"message\":\"Hello World\"}\n")

Note this isn't a specific thing for zerolog, but a illustration on how to set up an io.writer in manner to access the underlying, "written" data. This is what I hope to achieve with a NodeJS.WritableStream implementation as well.

I tried to find a way around with an event listener, but didn't suceed yet.

I want to wrap a array, e.g. an Uint8Array, into a NodeJS.WritableStream so I can read its content later. How can I do that?

Background: For testing my winston logger, I want to set up a custom transport which just holds all the logged data in a manner I can evaluate it later. The example reads like this:

logger.add(new winston.transports.Stream({
  stream: fs.createWriteStream('/dev/null')
  /* other options */
}));

But if I create the stream like fs.createWriteStream('/dev/null'), I cannot see its content, and it won't run under Windows (or at least I'm having issues here atm). And why would I need fs anyway?

To give another illustration where I'm coming from, let's take this arbitraty example from Go:

buf := bytes.Buffer{}
// zerolog.New() expects an io.Writable, similar to a NodeJS.WritableStream
logger := zerolog.New(&buf)
logger.Info().Msg("Hello World")
// I can access the written data by acessing the underlying buffer
assert.Equal(t, buf.String(), "{\"level\":\"info\",\"message\":\"Hello World\"}\n")

Note this isn't a specific thing for zerolog, but a illustration on how to set up an io.writer in manner to access the underlying, "written" data. This is what I hope to achieve with a NodeJS.WritableStream implementation as well.

I tried to find a way around with an event listener, but didn't suceed yet.

Share Improve this question edited Feb 5 at 10:31 NotX asked Feb 4 at 16:50 NotXNotX 2,4151 gold badge24 silver badges37 bronze badges 14
  • You want to read from a WriteStream? – Scott Hunter Commented Feb 4 at 16:52
  • @ScottHunter Yeah, but not necessarily via a stream api. I mean, I could write it to a file and read that file, and in this way avoid the limited write stream api. In the same manner I hoped I could just write the data into an array/buffer instead of a file. – NotX Commented Feb 4 at 16:55
  • Why not just log it to file if you need to do something with it later? You have more disk space than RAM, why would you keep it hanging around in memory when you're not using it? Streams need to "go somewhere", the whole point is that they don't hang around. – Mike 'Pomax' Kamermans Commented Feb 4 at 16:59
  • @Mike'Pomax'Kamermans Well, later is instantly b/c it's a unit test. Sure, I could do so, but it feels a bit weird that one has to go this route given the stream writer is a generic interface and from other languages I know straight forward solutions for this. – NotX Commented Feb 4 at 17:02
  • 1 Ah I had not seen it's deprecated; but I suppose it still works and can be used for testing. Or you can get a look at its implementation. As for implementing a writable stream yourself, there's only one method you need to implement: _write, like new Writable({ write(chunk, encoding, done) { …; done(); } }). – Bergi Commented Feb 5 at 11:32
 |  Show 9 more comments

1 Answer 1

Reset to default 0

For completeness sake, here the solution @Bergi provided. While it's not possible to set an underlying buffer as in Go oder Java, we work a callback to create a writable stream which can be evaluated. For that we have to create an own implementation of WritableStream with the help of the (abstract) implementation Writable:

import { Writable } from 'node:stream';
import * as winston from 'winston';

let logged: string = '';
const writable = new Writable({
  write(chunk: Buffer, _encoding, done) {
    logged += chunk.toString();
    done();
  },
});

// for my concrete use case
expect(logged).toEqual(winston.createLogger({transports: new winston.transports.Stream({ stream: writable })}).info('some text'))

本文标签: javascriptHow to create a writable byte stream I can evaluateStack Overflow