2021-10-27 08:06:50 -04:00
|
|
|
const SandboxedModule = require('sandboxed-module')
|
|
|
|
const bunyan = require('bunyan')
|
|
|
|
const { expect } = require('chai')
|
2024-11-08 05:21:56 -05:00
|
|
|
const path = require('node:path')
|
2021-10-27 08:06:50 -04:00
|
|
|
const sinon = require('sinon')
|
|
|
|
|
|
|
|
const MODULE_PATH = path.join(__dirname, '../../logging-manager.js')
|
|
|
|
|
|
|
|
describe('LoggingManager', function () {
|
|
|
|
beforeEach(function () {
|
|
|
|
this.start = Date.now()
|
|
|
|
this.bunyanLogger = {
|
|
|
|
addStream: sinon.stub(),
|
|
|
|
debug: sinon.stub(),
|
|
|
|
error: sinon.stub(),
|
|
|
|
fatal: sinon.stub(),
|
|
|
|
info: sinon.stub(),
|
|
|
|
level: sinon.stub(),
|
2021-12-16 04:04:32 -05:00
|
|
|
warn: sinon.stub(),
|
2021-10-27 08:06:50 -04:00
|
|
|
}
|
|
|
|
this.Bunyan = {
|
|
|
|
createLogger: sinon.stub().returns(this.bunyanLogger),
|
2021-12-16 04:04:32 -05:00
|
|
|
RingBuffer: bunyan.RingBuffer,
|
2021-10-27 08:06:50 -04:00
|
|
|
}
|
|
|
|
this.stackdriverStreamConfig = { stream: 'stackdriver' }
|
|
|
|
this.stackdriverClient = {
|
2021-12-16 04:04:32 -05:00
|
|
|
stream: sinon.stub().returns(this.stackdriverStreamConfig),
|
2021-10-27 08:06:50 -04:00
|
|
|
}
|
|
|
|
this.GCPLogging = {
|
2021-12-16 04:04:32 -05:00
|
|
|
LoggingBunyan: sinon.stub().returns(this.stackdriverClient),
|
2021-10-27 08:06:50 -04:00
|
|
|
}
|
|
|
|
this.FileLogLevelChecker = {
|
|
|
|
start: sinon.stub(),
|
2021-12-16 04:04:32 -05:00
|
|
|
stop: sinon.stub(),
|
2021-10-27 08:06:50 -04:00
|
|
|
}
|
|
|
|
this.GCEMetadataLogLevelChecker = {
|
|
|
|
start: sinon.stub(),
|
2021-12-16 04:04:32 -05:00
|
|
|
stop: sinon.stub(),
|
2021-10-27 08:06:50 -04:00
|
|
|
}
|
|
|
|
this.LogLevelChecker = {
|
|
|
|
FileLogLevelChecker: sinon.stub().returns(this.FileLogLevelChecker),
|
|
|
|
GCEMetadataLogLevelChecker: sinon
|
|
|
|
.stub()
|
2021-12-16 04:04:32 -05:00
|
|
|
.returns(this.GCEMetadataLogLevelChecker),
|
2021-10-27 08:06:50 -04:00
|
|
|
}
|
|
|
|
this.SentryManager = {
|
|
|
|
captureException: sinon.stub(),
|
2021-12-16 04:04:32 -05:00
|
|
|
captureExceptionRateLimited: sinon.stub(),
|
2021-10-27 08:06:50 -04:00
|
|
|
}
|
|
|
|
this.LoggingManager = SandboxedModule.require(MODULE_PATH, {
|
|
|
|
requires: {
|
|
|
|
bunyan: this.Bunyan,
|
|
|
|
'./log-level-checker': this.LogLevelChecker,
|
2021-12-16 04:04:32 -05:00
|
|
|
'./sentry-manager': sinon.stub().returns(this.SentryManager),
|
|
|
|
},
|
2021-10-27 08:06:50 -04:00
|
|
|
})
|
|
|
|
this.loggerName = 'test'
|
|
|
|
this.logger = this.LoggingManager.initialize(this.loggerName)
|
|
|
|
this.logger.initializeErrorReporting('test_dsn')
|
|
|
|
})
|
|
|
|
|
2023-08-24 07:26:26 -04:00
|
|
|
afterEach(function () {
|
|
|
|
this.LoggingManager.removeWarningHandler()
|
|
|
|
})
|
|
|
|
|
2021-10-27 08:06:50 -04:00
|
|
|
describe('initialize', function () {
|
|
|
|
beforeEach(function () {
|
|
|
|
this.Bunyan.createLogger.reset()
|
|
|
|
})
|
|
|
|
|
|
|
|
describe('not in production', function () {
|
|
|
|
beforeEach(function () {
|
|
|
|
this.logger = this.LoggingManager.initialize(this.loggerName)
|
|
|
|
})
|
|
|
|
|
|
|
|
it('should default to log level debug', function () {
|
|
|
|
this.Bunyan.createLogger.firstCall.args[0].streams[0].level.should.equal(
|
|
|
|
'debug'
|
|
|
|
)
|
|
|
|
})
|
|
|
|
|
|
|
|
it('should not instantiate a log level checker', function () {
|
|
|
|
expect(this.LoggingManager.logLevelChecker).not.to.exist
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
|
|
|
describe('in production', function () {
|
|
|
|
beforeEach(function () {
|
|
|
|
process.env.NODE_ENV = 'production'
|
|
|
|
this.logger = this.LoggingManager.initialize(this.loggerName)
|
|
|
|
})
|
|
|
|
|
2021-12-16 04:04:32 -05:00
|
|
|
afterEach(function () {
|
|
|
|
delete process.env.NODE_ENV
|
|
|
|
})
|
2021-10-27 08:06:50 -04:00
|
|
|
|
2022-05-16 08:38:27 -04:00
|
|
|
it('should default to log level info', function () {
|
2021-10-27 08:06:50 -04:00
|
|
|
this.Bunyan.createLogger.firstCall.args[0].streams[0].level.should.equal(
|
2022-05-16 08:38:27 -04:00
|
|
|
'info'
|
2021-10-27 08:06:50 -04:00
|
|
|
)
|
|
|
|
})
|
|
|
|
|
|
|
|
it('should set up a file log level checker', function () {
|
|
|
|
expect(this.logger.logLevelChecker).to.equal(this.FileLogLevelChecker)
|
|
|
|
expect(this.FileLogLevelChecker.start).to.have.been.called
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
|
|
|
describe('when LOG_LEVEL set in env', function () {
|
|
|
|
beforeEach(function () {
|
|
|
|
process.env.LOG_LEVEL = 'trace'
|
|
|
|
this.LoggingManager.initialize()
|
|
|
|
})
|
|
|
|
|
2021-12-16 04:04:32 -05:00
|
|
|
afterEach(function () {
|
|
|
|
delete process.env.LOG_LEVEL
|
|
|
|
})
|
2021-10-27 08:06:50 -04:00
|
|
|
|
|
|
|
it('should use custom log level', function () {
|
|
|
|
this.Bunyan.createLogger.firstCall.args[0].streams[0].level.should.equal(
|
|
|
|
'trace'
|
|
|
|
)
|
|
|
|
})
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
|
|
|
describe('bunyan logging', function () {
|
|
|
|
beforeEach(function () {
|
|
|
|
this.logArgs = [{ foo: 'bar' }, 'foo', 'bar']
|
|
|
|
})
|
|
|
|
|
|
|
|
it('should log debug', function () {
|
|
|
|
this.logger.debug(this.logArgs)
|
|
|
|
this.bunyanLogger.debug.should.have.been.calledWith(this.logArgs)
|
|
|
|
})
|
|
|
|
|
|
|
|
it('should log error', function () {
|
|
|
|
this.logger.error(this.logArgs)
|
|
|
|
this.bunyanLogger.error.should.have.been.calledWith(this.logArgs)
|
|
|
|
})
|
|
|
|
|
|
|
|
it('should log fatal', function () {
|
|
|
|
this.logger.fatal(this.logArgs)
|
|
|
|
this.bunyanLogger.fatal.should.have.been.calledWith(this.logArgs)
|
|
|
|
})
|
|
|
|
|
|
|
|
it('should log info', function () {
|
|
|
|
this.logger.info(this.logArgs)
|
|
|
|
this.bunyanLogger.info.should.have.been.calledWith(this.logArgs)
|
|
|
|
})
|
|
|
|
|
|
|
|
it('should log warn', function () {
|
|
|
|
this.logger.warn(this.logArgs)
|
|
|
|
this.bunyanLogger.warn.should.have.been.calledWith(this.logArgs)
|
|
|
|
})
|
|
|
|
|
|
|
|
it('should log err', function () {
|
|
|
|
this.logger.err(this.logArgs)
|
|
|
|
this.bunyanLogger.error.should.have.been.calledWith(this.logArgs)
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
|
|
|
describe('logger.error', function () {
|
|
|
|
it('should report errors to Sentry', function () {
|
|
|
|
this.logger.error({ foo: 'bar' }, 'message')
|
|
|
|
expect(this.SentryManager.captureExceptionRateLimited).to.have.been.called
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
|
|
|
describe('ringbuffer', function () {
|
|
|
|
beforeEach(function () {
|
|
|
|
this.logBufferMock = [
|
|
|
|
{ msg: 'log 1' },
|
|
|
|
{ msg: 'log 2' },
|
2021-12-16 04:04:32 -05:00
|
|
|
{ level: 50, msg: 'error' },
|
2021-10-27 08:06:50 -04:00
|
|
|
]
|
|
|
|
})
|
|
|
|
|
|
|
|
describe('when ring buffer size is positive', function () {
|
|
|
|
beforeEach(function () {
|
|
|
|
process.env.LOG_RING_BUFFER_SIZE = '20'
|
|
|
|
this.logger = this.LoggingManager.initialize(this.loggerName)
|
|
|
|
this.logger.ringBuffer.records = this.logBufferMock
|
|
|
|
this.logger.error({}, 'error')
|
|
|
|
})
|
|
|
|
|
|
|
|
afterEach(function () {
|
|
|
|
process.env.LOG_RING_BUFFER_SIZE = undefined
|
|
|
|
})
|
|
|
|
|
|
|
|
it('should include buffered logs in error log and filter out error logs in buffer', function () {
|
|
|
|
this.bunyanLogger.error.lastCall.args[0].logBuffer.should.deep.equal([
|
|
|
|
{ msg: 'log 1' },
|
2021-12-16 04:04:32 -05:00
|
|
|
{ msg: 'log 2' },
|
2021-10-27 08:06:50 -04:00
|
|
|
])
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
|
|
|
describe('when ring buffer size is zero', function () {
|
|
|
|
beforeEach(function () {
|
|
|
|
process.env.LOG_RING_BUFFER_SIZE = '0'
|
|
|
|
this.logger = this.LoggingManager.initialize(this.loggerName)
|
|
|
|
this.logger.error({}, 'error')
|
|
|
|
})
|
|
|
|
|
|
|
|
afterEach(function () {
|
|
|
|
process.env.LOG_RING_BUFFER_SIZE = undefined
|
|
|
|
})
|
|
|
|
|
|
|
|
it('should not include buffered logs in error log', function () {
|
|
|
|
expect(this.bunyanLogger.error.lastCall.args[0].logBuffer).be.undefined
|
|
|
|
})
|
|
|
|
})
|
|
|
|
})
|
|
|
|
})
|