Skip to content

Commit 300a4d7

Browse files
committed
logging-bunyan: make it a proper Writeable stream
Fixes: #1988
1 parent d04cf34 commit 300a4d7

3 files changed

Lines changed: 98 additions & 49 deletions

File tree

packages/logging-bunyan/src/index.js

Lines changed: 26 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@
2222

2323
var extend = require('extend');
2424
var logging = require('@google-cloud/logging');
25+
var util = require('util');
26+
var Writable = require('stream').Writable;
2527

2628
/**
2729
* Map of Stackdriver logging levels.
@@ -95,7 +97,12 @@ function LoggingBunyan(options) {
9597
this.log_ = logging(options).log(this.logName_, {
9698
removeCircular: true
9799
});
100+
101+
Writable.call(this, {
102+
objectMode: true
103+
});
98104
}
105+
util.inherits(LoggingBunyan, Writable);
99106

100107
/**
101108
* Convenience method that Builds a bunyan stream object that you can put in
@@ -121,13 +128,13 @@ LoggingBunyan.prototype.stream = function(level) {
121128
};
122129

123130
/**
124-
* Relay a log entry to the logging agent. This is normally called by bunyan.
131+
* Format a bunyan record into a Stackdriver log entry.
125132
*
126-
* @param {object} record - Bunyan log record.
133+
* @param {object} - Bunyan log record.
127134
*
128135
* @private
129136
*/
130-
LoggingBunyan.prototype.write = function(record) {
137+
LoggingBunyan.prototype._formatEntry = function(record) {
131138
if (typeof record === 'string') {
132139
throw new Error(
133140
'@google-cloud/logging-bunyan only works as a raw bunyan stream type.'
@@ -158,19 +165,29 @@ LoggingBunyan.prototype.write = function(record) {
158165
}
159166
}
160167

161-
var level = BUNYAN_TO_STACKDRIVER[record.level];
162-
163168
var entryMetadata = {
164169
resource: this.resource_,
165170
timestamp: record.time
166171
};
167172

168-
var entry = this.log_.entry(entryMetadata, record);
173+
return this.log_.entry(entryMetadata, record);
174+
};
169175

170-
this.log_[level](entry, function() {
171-
// no-op to avoid a promise being returned.
172-
});
176+
/**
177+
* Relay a log entry to the logging agent. This is called by bunyan through
178+
* Writable#write.
179+
*
180+
* @param {object} record - Bunyan log record.
181+
*
182+
* @private
183+
*/
184+
LoggingBunyan.prototype._write = function(record, encoding, callback) {
185+
var entry = this._formatEntry(record);
186+
var level = BUNYAN_TO_STACKDRIVER[record.level];
187+
this.log_[level](entry, callback);
173188
};
174189

190+
// TODO(ofrobots): implement _writev as well.
191+
175192
module.exports = LoggingBunyan;
176193
module.exports.BUNYAN_TO_STACKDRIVER = BUNYAN_TO_STACKDRIVER;

packages/logging-bunyan/system-test/logging-bunyan.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ var env = require('../../../system-test/env.js');
2424
var logging = require('@google-cloud/logging')(env);
2525
var loggingBunyan = require('../')(env);
2626

27-
describe.skip('LoggingBunyan', function() {
27+
describe('LoggingBunyan', function() {
2828
var WRITE_CONSISTENCY_DELAY_MS = 20000;
2929

3030
var logger = bunyan.createLogger({
@@ -57,9 +57,8 @@ describe.skip('LoggingBunyan', function() {
5757
],
5858
level: 'error',
5959
verify: function(entry) {
60-
assert.strictEqual(entry.data.msg, 'second');
60+
assert(entry.data.message.startsWith('Error: second'));
6161
assert.strictEqual(entry.data.pid, process.pid);
62-
assert.ok(entry.data.message.startsWith('Error: second'));
6362
}
6463
},
6564

@@ -70,8 +69,9 @@ describe.skip('LoggingBunyan', function() {
7069
},
7170
'third'
7271
],
72+
level: 'info',
7373
verify: function(entry) {
74-
assert.strictEqual(entry.data.msg, 'third');
74+
assert.strictEqual(entry.data.message, 'third');
7575
assert.strictEqual(entry.data.pid, process.pid);
7676
assert.deepStrictEqual(entry.data.test, {
7777
circular: '[Circular]'

packages/logging-bunyan/test/index.js

Lines changed: 68 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ describe('logging-bunyan', function() {
2525
var fakeLoggingOptions_;
2626
var fakeLogName_;
2727
var fakeLogOptions_;
28+
var fakeWritableOptions_;
2829

2930
function fakeLogging(options) {
3031
fakeLoggingOptions_ = options;
@@ -37,6 +38,18 @@ describe('logging-bunyan', function() {
3738
};
3839
}
3940

41+
function fakeWritable(options) {
42+
fakeWritableOptions_ = options;
43+
}
44+
45+
fakeWritable.prototype.write = function(chunk, encoding, callback) {
46+
setImmediate(callback);
47+
};
48+
49+
var fakeStream = {
50+
Writable: fakeWritable
51+
};
52+
4053
var LoggingBunyanCached;
4154
var LoggingBunyan;
4255
var loggingBunyan;
@@ -46,9 +59,15 @@ describe('logging-bunyan', function() {
4659
resource: {}
4760
};
4861

62+
var RECORD = {
63+
level: 30,
64+
time: '2012-06-19T21:34:19.906Z'
65+
};
66+
4967
before(function() {
5068
LoggingBunyan = proxyquire('../src/index.js', {
51-
'@google-cloud/logging': fakeLogging
69+
'@google-cloud/logging': fakeLogging,
70+
stream: fakeStream
5271
});
5372

5473
LoggingBunyanCached = extend(true, {}, LoggingBunyan);
@@ -70,6 +89,11 @@ describe('logging-bunyan', function() {
7089
assert(loggingBunyan instanceof LoggingBunyan);
7190
});
7291

92+
it('should be an object mode Writable', function() {
93+
assert(loggingBunyan instanceof fakeWritable);
94+
assert.deepStrictEqual(fakeWritableOptions_, { objectMode: true });
95+
});
96+
7397
it('should localize the provided resource', function() {
7498
assert.strictEqual(loggingBunyan.resource_, OPTIONS.resource);
7599
});
@@ -102,22 +126,11 @@ describe('logging-bunyan', function() {
102126
});
103127
});
104128

105-
describe('write', function() {
106-
var STACKDRIVER_LEVEL = 'info';
107-
108-
var RECORD = {
109-
level: 30,
110-
time: '2012-06-19T21:34:19.906Z'
111-
};
112-
113-
beforeEach(function() {
114-
fakeLogInstance.entry = function() {};
115-
loggingBunyan.log_[STACKDRIVER_LEVEL] = function() {};
116-
});
129+
describe('_formatEntry', function() {
117130

118131
it('should throw an error if record is a string', function() {
119132
assert.throws(function() {
120-
loggingBunyan.write('string record');
133+
loggingBunyan._formatEntry('string record');
121134
}, new RegExp(
122135
'@google-cloud/logging-bunyan only works as a raw bunyan stream type.'
123136
));
@@ -133,25 +146,7 @@ describe('logging-bunyan', function() {
133146
done();
134147
};
135148

136-
loggingBunyan.write(RECORD);
137-
});
138-
139-
it('should write to the correct log', function(done) {
140-
var customLevel = 'custom-level';
141-
var entry = {};
142-
143-
loggingBunyan.log_.entry = function() {
144-
return entry;
145-
};
146-
147-
LoggingBunyan.BUNYAN_TO_STACKDRIVER[RECORD.level] = customLevel;
148-
149-
loggingBunyan.log_[customLevel] = function(entry_) {
150-
assert.strictEqual(entry_, entry);
151-
done();
152-
};
153-
154-
loggingBunyan.write(RECORD);
149+
loggingBunyan._formatEntry(RECORD);
155150
});
156151

157152
it('should rename the msg property to message', function(done) {
@@ -163,7 +158,7 @@ describe('logging-bunyan', function() {
163158
done();
164159
};
165160

166-
loggingBunyan.write(recordWithMsg);
161+
loggingBunyan._formatEntry(recordWithMsg);
167162
});
168163

169164
it('should inject the error stack as the message', function(done) {
@@ -186,7 +181,7 @@ describe('logging-bunyan', function() {
186181
done();
187182
};
188183

189-
loggingBunyan.write(record);
184+
loggingBunyan._formatEntry(record);
190185
});
191186

192187
it('should leave message property intact when present', function(done) {
@@ -203,10 +198,47 @@ describe('logging-bunyan', function() {
203198
done();
204199
};
205200

206-
loggingBunyan.write(record);
201+
loggingBunyan._formatEntry(record);
207202
});
208203
});
209204

205+
describe('_write', function() {
206+
var STACKDRIVER_LEVEL = 'info';
207+
208+
beforeEach(function() {
209+
fakeLogInstance.entry = function() {};
210+
loggingBunyan.log_[STACKDRIVER_LEVEL] = function() {};
211+
});
212+
213+
it('should format the record', function(done) {
214+
loggingBunyan._formatEntry = function(record) {
215+
assert.strictEqual(record, RECORD);
216+
done();
217+
};
218+
219+
loggingBunyan._write(RECORD, '', assert.ifError);
220+
});
221+
222+
it('should write to the correct log', function(done) {
223+
var customLevel = 'custom-level';
224+
var entry = {};
225+
226+
loggingBunyan.log_.entry = function() {
227+
return entry;
228+
};
229+
230+
LoggingBunyan.BUNYAN_TO_STACKDRIVER[RECORD.level] = customLevel;
231+
232+
loggingBunyan.log_[customLevel] = function(entry_) {
233+
assert.strictEqual(entry_, entry);
234+
done();
235+
};
236+
237+
loggingBunyan._write(RECORD, '', assert.ifError);
238+
});
239+
});
240+
241+
210242
describe('BUNYAN_TO_STACKDRIVER', function() {
211243
it('should correctly map to Stackdriver Logging levels', function() {
212244
assert.deepEqual(LoggingBunyan.BUNYAN_TO_STACKDRIVER, {

0 commit comments

Comments
 (0)