Skip to content

Commit

Permalink
Merge pull request #5 from taurgis/develop
Browse files Browse the repository at this point in the history
Develop
  • Loading branch information
taurgis authored Mar 3, 2021
2 parents a147b5a + 6960b26 commit 8fb7b13
Show file tree
Hide file tree
Showing 8 changed files with 122 additions and 54 deletions.
23 changes: 23 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,29 @@ module.exports = {

Never used hooks before? Look at the documentation [here](https://documentation.b2c.commercecloud.salesforce.com/DOC1/topic/com.demandware.dochelp/content/b2c_commerce/topics/sfra/b2c_sfra_hooks.html?resultof=%22%68%6f%6f%6b%73%22%20%22%68%6f%6f%6b%22%20).

# Usage

Using the default configuration (Site Preferences)

```
var Sentry = require('*/cartridge/scripts/Sentry');
Sentry.captureMessage('Hello, world!');
Sentry.captureException(new Error('Good bye'));
```

Using your own configuration, ignoring Site Preferences

```
var Sentry = require('*\/cartridge/scripts/Sentry');
Sentry.init({
dsn: '__DSN__',
// ...
});
Sentry.captureException(new Error('Good bye'));
```

# Release management

# NPM scripts
Expand Down
2 changes: 1 addition & 1 deletion cartridges/lib_sentry/cartridge/models/SentryId.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ function generateSentryUUID() {
*/
function SentryId(uuid) {
if (uuid && uuid.length !== 32) {
throw new Error('UUID needs to be 32 characters long.');
throw new Error('UUID needs to be 32 characters long. Was given the value ' + uuid);
}

this.uuid = uuid || generateSentryUUID();
Expand Down
10 changes: 3 additions & 7 deletions cartridges/lib_sentry/cartridge/models/SentryOptions.js
Original file line number Diff line number Diff line change
@@ -1,21 +1,17 @@
'use strict';

var {
getDSN, getProjectName
} = require('*/cartridge/scripts/helpers/sentryHelper');
var SentryConfig = require('*/cartridge/config/sentry');
var DuplicateEventProcessor = require('*/cartridge/scripts/processors/duplicateEventProcessor');
var CookieProcessor = require('*/cartridge/scripts/processors/cookieProcessor');

/**
* Sentry SDK options
*
* @param {Object|null|undefined} config - The configuration
* @param {Object} config - The configuration
* @constructor
*/
function SentryOptions(config) {
this.dsn = (config && config.dsn) || getDSN();
this.release = (config && config.release) || (getProjectName() + '@' + SentryConfig['code-version']);
this.dsn = config.dsn;
this.release = config.release;
this.eventProcessors = [new DuplicateEventProcessor(this), new CookieProcessor(this)];
this.logger = require('dw/system/Logger').getLogger('sentry');
}
Expand Down
59 changes: 45 additions & 14 deletions cartridges/lib_sentry/cartridge/scripts/Sentry.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
'use strict';

var SentryEvent = require('*/cartridge/models/SentryEvent');
var SentryId = require('*/cartridge/models/SentryId');
var SentryOptions = require('*/cartridge/models/SentryOptions');
var {
sendEvent, getLastEventID
sendEvent, getLastEventID, getDSN, getProjectName
} = require('*/cartridge/scripts/helpers/sentryHelper');
var SentryConfig = require('*/cartridge/config/sentry');

var BEFORE_SEND_HOOK = 'com.sentry.beforesend';
var DEFAULT_OPTIONS = new SentryOptions({
dsn: getDSN(),
release: getProjectName() + '@' + SentryConfig['code-version']
});

/**
* The Sentry SFCC SDK Client.
Expand All @@ -18,56 +23,82 @@ var BEFORE_SEND_HOOK = 'com.sentry.beforesend';
* @example
* ```
*
* var { init } = require('*\/cartridge/scripts/Sentry');
* var Sentry = require('*\/cartridge/scripts/Sentry');
*
* Sentry.init();
* Sentry.captureException(new Error('Good bye'));
* ```
*
*
* init({
* @example
* ```
* var Sentry = require('*\/cartridge/scripts/Sentry');
*
* Sentry.init({
* dsn: '__DSN__',
* // ...
* });
*
* Sentry.captureException(new Error('Good bye'));
* ```
*
* @example
* ```
*
* var { init } = require('*\/cartridge/scripts/Sentry');
* var Sentry = require('*\/cartridge/scripts/Sentry');
* Sentry.captureMessage('Hello, world!');
* Sentry.captureException(new Error('Good bye'));
* ```
*/
function Sentry() {
// EMPTY CONSTRUCTOR
this.initialized = false;
}

/**
* Initializes Sentry with the given options
* Initializes Sentry with the given options. If no options are passed the default
* options will be used.
*
* @param {SentryOptions} sentryOptions - The Sentry Options
* @param {SentryOptions|null|undefined} sentryOptions - The Sentry Options
* @return {Sentry} - Sentry instance
*/
Sentry.prototype.init = function (sentryOptions) {
this.options = new SentryOptions(sentryOptions);
this.options = sentryOptions ? new SentryOptions(sentryOptions) : DEFAULT_OPTIONS;
this.initialized = true;

return this;
};

/**
* Captures the message.
*
* @param {string} message - The message to send.
* @return {SentryId} - The Id (SentryId object) of the event
*/
Sentry.prototype.captureMessage = function (message) {
if (!this.initialized) {
this.init(DEFAULT_OPTIONS);
}

var sentryEvent = new SentryEvent({
eventType: SentryEvent.TYPE_MESSAGE,
release: this.options.release,
message: message,
level: SentryEvent.LEVEL_INFO
});

sendEvent(sentryEvent, this.options.dsn);
return sendEvent(sentryEvent, this.options.dsn);
};

/**
* Captures an exception event and sends it to Sentry.
*
* @param {Error} error An exception-like object.
* @returns {string|null} The event id
* @param {Error} error - An exception-like object.
* @returns {SentryId|null} - The event id
*/
Sentry.prototype.captureException = function (error) {
if (!this.initialized) {
this.init(DEFAULT_OPTIONS);
}

var sentryEvent = new SentryEvent({
error: error,
eventType: SentryEvent.TYPE_EXCEPTION,
Expand Down Expand Up @@ -107,7 +138,7 @@ Sentry.prototype.getLastEventID = function () {
var lastEventId = getLastEventID();

if (lastEventId) {
return new SentryId(lastEventId);
return lastEventId;
}

return null;
Expand Down
29 changes: 21 additions & 8 deletions cartridges/lib_sentry/cartridge/scripts/helpers/sentryHelper.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
'use strict';

var Logger = require('dw/system/Logger').getLogger('sentry');
var SentryId = require('*/cartridge/models/SentryId');

var DSN_PREFERENCE = 'sentryDSN';
var PROJECT_NAME_PREFERENCE = 'sentryProjectID';
var COOKIES_PREFERENCE = 'sentryCookiesEnabled';
Expand All @@ -26,31 +28,40 @@ function getCachedPreference(key) {

/**
* Stores a Sentry ID in the cache.
* @param {string} id - The Event ID
* @param {SentryId} sentryId - The Sentry ID
*/
function storeEventID(id) {
if (empty(id)) {
function storeEventID(sentryId) {
if (!sentryId) {
return;
}

var configCache = require('dw/system/CacheMgr').getCache('sentryConfig');
var key = request.session.sessionID + 'lastEventID';
Logger.debug('Sentry :: Storing last Event ID in cache under key {0}.', key);

configCache.put(key, id);
configCache.put(key, sentryId.uuid);
}

/**
* Gets the last known event ID from the cache.
* @return {string|Object|null} - The Event ID
* @return {SentryId} - The Sentry ID
*/
function getLastEventID() {
var configCache = require('dw/system/CacheMgr').getCache('sentryConfig');
var key = request.session.sessionID + 'lastEventID';

Logger.debug('Sentry :: Fetching last Event ID in cache under key {0}.', key);

return configCache.get(request.session.sessionID + 'lastEventID');
/**
* @type {string}
*/
var result = configCache.get(request.session.sessionID + 'lastEventID');

if (result) {
return new SentryId(result);
}

return null;
}

/**
Expand Down Expand Up @@ -128,7 +139,7 @@ function canSendEvent() {
* @param {Object} sentryEvent - The Sentry Event to send
* @param {string} dsn - The DSN to use
*
* @returns {string|null} - The Sentry Event ID
* @returns {SentryId} - The Sentry Event ID
*/
function sendEvent(sentryEvent, dsn) {
if (!empty(sentryEvent) && canSendEvent()) {
Expand Down Expand Up @@ -164,7 +175,9 @@ function sendEvent(sentryEvent, dsn) {
blockSendingEvents(Number(180));
}

return result.errorMessage;
Logger.debug('Sentry :: Sentry received error {0}.', result.errorMessage);

return null;
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,10 @@ function sentryEventService(sentryEvent, dsn) {
parseResponse: function (svc, client) {
try {
if (client.statusCode === 200) {
var SentryId = require('*/cartridge/models/SentryId');
Logger.debug('Sentry :: Sentry successfully processed our request.');

return JSON.parse(client.text).id;
return new SentryId(JSON.parse(client.text).id);
}
} catch (e) {
Logger.error(e);
Expand Down
5 changes: 3 additions & 2 deletions cartridges/plugin_sentry/cartridge/controllers/Error.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ function logError(req, res, next) {
var error = req.error;

if (error) {
var Sentry = require('*/cartridge/scripts/Sentry').init();
var Sentry = require('*/cartridge/scripts/Sentry');

Sentry.captureException(new Error(error.errorText));
}
next();
Expand All @@ -29,7 +30,7 @@ server.prepend('ErrorCode', logError);
*/
server.prepend('Forbidden', function (req, res, next) {
if (req.currentCustomer.profile) {
var Sentry = require('*/cartridge/scripts/Sentry').init();
var Sentry = require('*/cartridge/scripts/Sentry');
var message = 'Forbidden access for customer ' + req.currentCustomer.profile.customerNo;

Sentry.captureException(new Error(message));
Expand Down
45 changes: 24 additions & 21 deletions test/unit/lib_sentry/models/SentryOptions.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,10 @@ require('app-module-path').addPath(process.cwd() + '/cartridges');

const defaultDSN = 'xxxxxxxxxxxxxXxxxxxxxxxxxx';
const defaultProject = 'project';
const defaultRelease = defaultProject + '@1.0.0';
const loggerSpy = sinon.spy();

var SentryOptions = proxyQuire('lib_sentry/cartridge/models/SentryOptions', {
'*/cartridge/scripts/helpers/sentryHelper': {
getDSN: () => defaultDSN,
getProjectName: () => defaultProject
},
'*/cartridge/config/sentry': require('lib_sentry/cartridge/config/sentry'),
'*/cartridge/scripts/processors/duplicateEventProcessor': function () { },
'*/cartridge/scripts/processors/cookieProcessor': function () { },
'dw/system/Logger': {
Expand All @@ -24,21 +20,12 @@ var SentryOptions = proxyQuire('lib_sentry/cartridge/models/SentryOptions', {
});

describe('Model - Sentry Options', () => {
it('Should fall back to the default if no options are passed.', () => {
var result = new SentryOptions();

expect(result.dsn).to.equal(defaultDSN);
expect(result.release).to.include(defaultProject);
expect(result.eventProcessors).to.be.length(2);
expect(loggerSpy.calledOnce).to.be.true;
expect(loggerSpy.calledWith('sentry')).to.be.true;
});

it('Should use the DSN provided in the passed config.', () => {
const dsn = 'my_dsn';

var result = new SentryOptions({
dsn
dsn,
release: defaultRelease
});

expect(result.dsn).to.equal(dsn);
Expand All @@ -48,6 +35,7 @@ describe('Model - Sentry Options', () => {
const release = 'my_release';

var result = new SentryOptions({
dsn: defaultDSN,
release
});

Expand All @@ -57,7 +45,10 @@ describe('Model - Sentry Options', () => {
it('Should be possible to register a custom event processor.', () => {
var eventProcessor = sinon.spy();

var result = new SentryOptions();
var result = new SentryOptions({
dsn: defaultDSN,
release: defaultRelease
});
result.addEventProcessor(eventProcessor);

expect(result.eventProcessors).to.be.length(3);
Expand All @@ -66,13 +57,19 @@ describe('Model - Sentry Options', () => {
});

it('Should be possible to get all event processors.', () => {
var result = new SentryOptions();
var result = new SentryOptions({
dsn: defaultDSN,
release: defaultProject
});

expect(result.getEventProcessors()).to.be.length(2);
});

it('Should be possible to override the logger.', () => {
var result = new SentryOptions();
var result = new SentryOptions({
dsn: defaultDSN,
release: defaultRelease
});
var customLogger = {
debug: function () {}
};
Expand All @@ -82,15 +79,21 @@ describe('Model - Sentry Options', () => {
});

it('Should not be possible to override the logger with something that is not a logger.', () => {
var result = new SentryOptions();
var result = new SentryOptions({
dsn: defaultDSN,
release: defaultRelease
});
var customLogger = {};
result.setLogger(customLogger);

expect(result.logger).to.not.equal(customLogger);
});

it('Should be possible to get the logger.', () => {
var result = new SentryOptions();
var result = new SentryOptions({
dsn: defaultDSN,
release: defaultRelease
});
var customLogger = {
debug: function () {}
};
Expand Down

0 comments on commit 8fb7b13

Please sign in to comment.