diff --git a/packages/logging/lib/GhostLogger.js b/packages/logging/lib/GhostLogger.js index 0691d4aa7..a91f82737 100644 --- a/packages/logging/lib/GhostLogger.js +++ b/packages/logging/lib/GhostLogger.js @@ -23,12 +23,11 @@ class GhostLogger { * mode: Is used to print short or long log. * level: The level defines the default level of all transports except of stderr. * logBody: Disable or enable if the body of a request should be logged to the target stream. - * transports: An array of comma separated transports (e.g. stdout, stderr, geld, loggly, file) + * transports: An array of comma separated transports (e.g. stdout, stderr, gelf, file) * rotation: Enable or disable file rotation. * path: Path where to store log files. * filename: Optional filename template for log files. Supports {env} and {domain} placeholders. * If not provided, defaults to {domain}_{env} format. - * loggly: Loggly transport configuration. * elasticsearch: Elasticsearch transport configuration * gelf: Gelf transport configuration. * http: HTTP transport configuration @@ -48,7 +47,6 @@ class GhostLogger { this.mode = process.env.MODE || options.mode || 'short'; this.path = options.path || process.cwd(); this.filename = options.filename || '{domain}_{env}'; - this.loggly = options.loggly || {}; this.elasticsearch = options.elasticsearch || {}; this.gelf = options.gelf || {}; this.http = options.http || {}; @@ -179,35 +177,6 @@ class GhostLogger { }; } - /** - * @description Setup loggly. - */ - setLogglyStream() { - const Bunyan2Loggly = require('bunyan-loggly'); - - const logglyStream = new Bunyan2Loggly({ - token: this.loggly.token, - subdomain: this.loggly.subdomain, - tags: this.loggly.tags, - }); - - this.streams.loggly = { - name: 'loggly', - match: this.loggly.match, - log: bunyan.createLogger({ - name: this.name, - streams: [ - { - type: 'raw', - stream: logglyStream, - level: 'error', - }, - ], - serializers: this.serializers, - }), - }; - } - /** * @description Setup ElasticSearch. */ @@ -599,37 +568,7 @@ class GhostLogger { return; } - /** - * @NOTE - * Only `loggly` offers the `match` option. - * And currently `loggly` is by default configured to only send errors (not configureable). - * e.g. level info would get ignored. - * - * @NOTE - * The `match` feature is not completed. We hardcode checking if the level/type is `error` for now. - * Otherwise each `level:info` would has to run through the matching logic. - * - * @NOTE - * Matching a string in the whole req/res object massively slows down the process, because it's a sync - * operation. - * - * If we want to extend the feature, we can only offer matching certain keys e.g. status code, headers. - * If we want to extend the feature, we have to do proper performance testing. - * - * `jsonStringifySafe` can match a string in an object, which has circular dependencies. - * https://github.com/moll/json-stringify-safe - */ - if (logger.match && type === 'error') { - if ( - new RegExp(logger.match).test( - jsonStringifySafe(modifiedArguments[0].err || null).replace(/"/g, ''), - ) - ) { - logger.log[type](...modifiedArguments); - } - } else { - logger.log[type](...modifiedArguments); - } + logger.log[type](...modifiedArguments); }); } diff --git a/packages/logging/package.json b/packages/logging/package.json index 93c8ff1db..b2bc3a877 100644 --- a/packages/logging/package.json +++ b/packages/logging/package.json @@ -29,7 +29,6 @@ "@tryghost/pretty-stream": "workspace:*", "@tryghost/root-utils": "workspace:*", "bunyan": "1.8.15", - "bunyan-loggly": "2.0.1", "fs-extra": "11.3.5", "gelf-stream": "1.1.1", "json-stringify-safe": "5.0.1", diff --git a/packages/logging/test/logging.test.js b/packages/logging/test/logging.test.js index cadd76fe8..d1a231bc1 100644 --- a/packages/logging/test/logging.test.js +++ b/packages/logging/test/logging.test.js @@ -6,7 +6,6 @@ const includes = require('lodash/includes'); const errors = require('@tryghost/errors'); const sinon = require('sinon'); const assert = require('assert/strict'); -const Bunyan2Loggly = require('bunyan-loggly'); const GelfStream = require('gelf-stream').GelfStream; const ElasticSearch = require('@tryghost/elasticsearch').BunyanStream; const HttpStream = require('@tryghost/http-stream'); @@ -251,201 +250,6 @@ describe('Logging', function () { assert.equal(GelfStream.prototype._write.called, false); }); - it('loggly does only stream certain errors', async function () { - await new Promise((resolve) => { - sandbox.stub(Bunyan2Loggly.prototype, 'write').callsFake(function (data) { - assert.notEqual(data.err, null); - resolve(); - }); - - var ghostLogger = new GhostLogger({ - transports: ['loggly'], - loggly: { - token: 'invalid', - subdomain: 'invalid', - match: 'level:critical', - }, - }); - - ghostLogger.error(new errors.InternalServerError()); - assert.equal(Bunyan2Loggly.prototype.write.called, true); - }); - }); - - it('loggly does not stream non-critical errors when matching critical', function () { - sandbox.spy(Bunyan2Loggly.prototype, 'write'); - - var ghostLogger = new GhostLogger({ - transports: ['loggly'], - loggly: { - token: 'invalid', - subdomain: 'invalid', - match: 'level:critical', - }, - }); - - ghostLogger.error(new errors.NotFoundError()); - assert.equal(Bunyan2Loggly.prototype.write.called, false); - }); - - it('loggly does not stream errors that do not match regex', function () { - sandbox.spy(Bunyan2Loggly.prototype, 'write'); - - var ghostLogger = new GhostLogger({ - transports: ['loggly'], - loggly: { - token: 'invalid', - subdomain: 'invalid', - match: '^((?!statusCode:4\\d{2}).)*$', - }, - }); - - ghostLogger.error(new errors.NotFoundError()); - assert.equal(Bunyan2Loggly.prototype.write.called, false); - }); - - it('loggly does not stream errors when not nested correctly', function () { - sandbox.spy(Bunyan2Loggly.prototype, 'write'); - - var ghostLogger = new GhostLogger({ - transports: ['loggly'], - loggly: { - token: 'invalid', - subdomain: 'invalid', - match: '^((?!statusCode:4\\d{2}).)*$', - }, - }); - - ghostLogger.error(new errors.NoPermissionError()); - assert.equal(Bunyan2Loggly.prototype.write.called, false); - }); - - it('loggly does stream errors that match regex', function () { - sandbox.stub(Bunyan2Loggly.prototype, 'write').callsFake(function () {}); - - var ghostLogger = new GhostLogger({ - transports: ['loggly'], - loggly: { - token: 'invalid', - subdomain: 'invalid', - match: '^((?!statusCode:4\\d{2}).)*$', - }, - }); - - ghostLogger.error(new errors.InternalServerError()); - assert.equal(Bunyan2Loggly.prototype.write.called, true); - }); - - it('loggly does stream errors that match normal level', async function () { - await new Promise((resolve) => { - sandbox.stub(Bunyan2Loggly.prototype, 'write').callsFake(function (data) { - assert.notEqual(data.err, null); - resolve(); - }); - - var ghostLogger = new GhostLogger({ - transports: ['loggly'], - loggly: { - token: 'invalid', - subdomain: 'invalid', - match: 'level:normal', - }, - }); - - ghostLogger.error(new errors.NotFoundError()); - assert.equal(Bunyan2Loggly.prototype.write.called, true); - }); - }); - - it('loggly match can evaluate with null err payload', function () { - sandbox.stub(Bunyan2Loggly.prototype, 'write').callsFake(function () {}); - - const ghostLogger = new GhostLogger({ - transports: ['loggly'], - loggly: { - token: 'invalid', - subdomain: 'invalid', - match: '^null$', - }, - }); - - ghostLogger.error('plain error message'); - assert.equal(Bunyan2Loggly.prototype.write.called, true); - }); - - it('loggly does stream errors that match an one of multiple match statements', async function () { - await new Promise((resolve) => { - sandbox.stub(Bunyan2Loggly.prototype, 'write').callsFake(function (data) { - assert.notEqual(data.err, null); - resolve(); - }); - - var ghostLogger = new GhostLogger({ - transports: ['loggly'], - loggly: { - token: 'invalid', - subdomain: 'invalid', - match: 'level:critical|statusCode:404', - }, - }); - - ghostLogger.error(new errors.NotFoundError()); - assert.equal(Bunyan2Loggly.prototype.write.called, true); - }); - }); - - it('loggly does stream errors that match status code: full example', async function () { - await new Promise((resolve) => { - sandbox.stub(Bunyan2Loggly.prototype, 'write').callsFake(function (data) { - assert.notEqual(data.err, null); - assert.notEqual(data.req, null); - assert.notEqual(data.res, null); - resolve(); - }); - - var ghostLogger = new GhostLogger({ - transports: ['loggly'], - loggly: { - token: 'invalid', - subdomain: 'invalid', - match: 'statusCode:404', - }, - }); - - ghostLogger.error({ - err: new errors.NotFoundError(), - req: { - body: { - password: '12345678', - data: { attributes: { pin: '1234', test: 'ja' } }, - }, - }, - res: { getHeaders: () => ({}) }, - }); - assert.equal(Bunyan2Loggly.prototype.write.called, true); - }); - }); - - it('loggly does only stream certain errors: match is not defined -> log everything', async function () { - await new Promise((resolve) => { - sandbox.stub(Bunyan2Loggly.prototype, 'write').callsFake(function (data) { - assert.notEqual(data.err, null); - resolve(); - }); - - var ghostLogger = new GhostLogger({ - transports: ['loggly'], - loggly: { - token: 'invalid', - subdomain: 'invalid', - }, - }); - - ghostLogger.error(new errors.NotFoundError()); - assert.equal(Bunyan2Loggly.prototype.write.called, true); - }); - }); - it('elasticsearch should make a stream', function () { const es = new ElasticSearch( { @@ -751,7 +555,7 @@ describe('Logging', function () { await new Promise((resolve) => { const err = new errors.NotFoundError(); - sandbox.stub(Bunyan2Loggly.prototype, 'write').callsFake(function (data) { + sandbox.stub(HttpStream.prototype, 'write').callsFake(function (data) { assert.notEqual(data.err, null); assert.equal(data.err.id, err.id); assert.equal(data.err.domain, 'localhost'); @@ -769,23 +573,22 @@ describe('Logging', function () { }); const ghostLogger = new GhostLogger({ - transports: ['loggly'], - loggly: { - token: 'invalid', - subdomain: 'invalid', + transports: ['http'], + http: { + url: 'http://localhost', }, }); ghostLogger.error({ err, }); - assert.equal(Bunyan2Loggly.prototype.write.called, true); + assert.equal(HttpStream.prototype.write.called, true); }); }); it('stringifies meta properties', async function () { await new Promise((resolve) => { - sandbox.stub(Bunyan2Loggly.prototype, 'write').callsFake(function (data) { + sandbox.stub(HttpStream.prototype, 'write').callsFake(function (data) { assert.notEqual(data.err, null); assert.equal(data.err.context, '{"a":"b"}'); assert.equal(data.err.errorDetails, '{"c":"d"}'); @@ -794,10 +597,9 @@ describe('Logging', function () { }); const ghostLogger = new GhostLogger({ - transports: ['loggly'], - loggly: { - token: 'invalid', - subdomain: 'invalid', + transports: ['http'], + http: { + url: 'http://localhost', }, }); ghostLogger.error({ @@ -814,7 +616,7 @@ describe('Logging', function () { }), }); - assert.equal(Bunyan2Loggly.prototype.write.called, true); + assert.equal(HttpStream.prototype.write.called, true); }); }); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 8c8886a0c..699e46250 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -14,7 +14,6 @@ catalogs: version: 6.0.3 overrides: - node-loggly-bulk: ^4.0.2 axios: ^1.15.0 fast-xml-parser: ^5.7.0 @@ -438,9 +437,6 @@ importers: bunyan: specifier: 1.8.15 version: 1.8.15 - bunyan-loggly: - specifier: 2.0.1 - version: 2.0.1 fs-extra: specifier: 11.3.5 version: 11.3.5 @@ -2807,9 +2803,6 @@ packages: buffer@6.0.3: resolution: {integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==} - bunyan-loggly@2.0.1: - resolution: {integrity: sha512-9F+BYVqqtrYHmWfDE2JLoQmQmZod7AQQuRtAS41qaXa5wjiOviFNnMlY56gZmv5SZ2czbeuWeX+xSAEFcktsXw==} - bunyan@1.8.15: resolution: {integrity: sha512-0tECWShh6wUysgucJcBAoYegf3JJoZWibxdqhTm7OHPeT42qdjkZ29QCMcKwbgU1kiH+auSIasNRXMLWXafXig==} engines: {'0': node >=0.10.0} @@ -4306,9 +4299,6 @@ packages: moment-timezone@0.5.48: resolution: {integrity: sha512-f22b8LV1gbTO2ms2j2z13MuPogNoh5UzxL3nzNAYKGraILnbGc9NEE6dyiiiLv46DGRb8A4kg8UKWLjPthxBHw==} - moment@2.29.4: - resolution: {integrity: sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==} - moment@2.30.1: resolution: {integrity: sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==} @@ -4375,10 +4365,6 @@ packages: node-int64@0.4.0: resolution: {integrity: sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==} - node-loggly-bulk@4.0.2: - resolution: {integrity: sha512-4hLNDaW4f2MjIvPh1/HQ+3g5bL19Hl3Q2cyUER93GrscjEdjA1nX61ekrm616NI5emHJT9lBUBFJiS2uoXq5Rw==} - engines: {node: '>= 0.8.0'} - node-releases@2.0.44: resolution: {integrity: sha512-5WUyunoPMsvvEhS8AxHtRzP+oA8UCkJ7YRxatWKjngndhDGLiqEVAQKWjFAiAiuL8zMRGzGSJxFnLetoa43qGQ==} @@ -7680,14 +7666,6 @@ snapshots: base64-js: 1.5.1 ieee754: 1.2.1 - bunyan-loggly@2.0.1: - dependencies: - json-stringify-safe: 5.0.1 - node-loggly-bulk: 4.0.2 - transitivePeerDependencies: - - debug - - supports-color - bunyan@1.8.15: optionalDependencies: dtrace-provider: 0.8.8 @@ -9022,8 +9000,6 @@ snapshots: dependencies: moment: 2.30.1 - moment@2.29.4: {} - moment@2.30.1: {} ms@2.0.0: {} @@ -9095,15 +9071,6 @@ snapshots: node-int64@0.4.0: {} - node-loggly-bulk@4.0.2: - dependencies: - axios: 1.16.1(supports-color@7.2.0) - json-stringify-safe: 5.0.1 - moment: 2.29.4 - transitivePeerDependencies: - - debug - - supports-color - node-releases@2.0.44: {} nodemailer-mailgun-transport@2.1.5(lodash@4.18.1): diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 92b1c7fda..da6b3f8e7 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -1,7 +1,6 @@ packages: - 'packages/*' overrides: - node-loggly-bulk: ^4.0.2 axios: ^1.15.0 fast-xml-parser: ^5.7.0 allowBuilds: