Use @tryghost/logging instead of injected argument

This commit is contained in:
Sam Lord 2021-12-02 14:46:58 +00:00
parent 9f7a1fa50d
commit ba2c0818e0
12 changed files with 80 additions and 143 deletions

View File

@ -1,7 +1,8 @@
const {Router} = require('express');
const body = require('body-parser');
const MagicLink = require('@tryghost/magic-link');
const common = require('./common');
const errors = require('@tryghost/errors');
const logging = require('@tryghost/logging');
const MemberAnalyticsService = require('@tryghost/member-analytics-service');
const MembersAnalyticsIngress = require('@tryghost/members-analytics-ingress');
@ -59,13 +60,8 @@ module.exports = function MembersAPI({
},
stripeAPIService,
offersAPI,
logger,
labsService
}) {
if (logger) {
common.logging.setLogger(logger);
}
const tokenService = new TokenService({
privateKey,
publicKey,
@ -83,8 +79,7 @@ module.exports = function MembersAPI({
StripeProduct,
StripePrice,
Product,
Settings,
logger
Settings
});
const productRepository = new ProductRepository({
@ -96,7 +91,6 @@ module.exports = function MembersAPI({
const memberRepository = new MemberRepository({
stripeAPIService,
logger,
tokenService,
productRepository,
Member,
@ -111,7 +105,6 @@ module.exports = function MembersAPI({
});
const eventRepository = new EventRepository({
logger,
MemberSubscribeEvent,
MemberPaidSubscriptionEvent,
MemberPaymentEvent,
@ -204,13 +197,11 @@ module.exports = function MembersAPI({
checkoutCancelUrl: stripeConfig.checkoutCancelUrl,
billingSuccessUrl: stripeConfig.billingSuccessUrl,
billingCancelUrl: stripeConfig.billingCancelUrl
},
logging: common.logging
}
});
const wellKnownController = new WellKnownController({
tokenService,
logging: common.logging
tokenService
});
async function disconnectStripe() {
@ -348,7 +339,7 @@ module.exports = function MembersAPI({
async function setMemberGeolocationFromIp(email, ip) {
if (!email || !ip) {
throw new common.errors.IncorrectUsageError({
throw new errors.IncorrectUsageError({
message: 'setMemberGeolocationFromIp() expects email and ip arguments to be present'
});
}
@ -358,7 +349,7 @@ module.exports = function MembersAPI({
const member = (await users.get({email})).toJSON();
if (!member) {
throw new common.errors.NotFoundError({
throw new errors.NotFoundError({
message: `Member with email address ${email} does not exist`
});
}
@ -407,7 +398,7 @@ module.exports = function MembersAPI({
middleware.handleStripeWebhook.use(body.raw({type: 'application/json'}), async function (req, res) {
if (!stripeAPIService.configured) {
common.logging.error(`Stripe not configured, not handling webhook`);
logging.error(`Stripe not configured, not handling webhook`);
res.writeHead(400);
return res.end();
}
@ -420,17 +411,17 @@ module.exports = function MembersAPI({
try {
event = stripeWebhookService.parseWebhook(req.body, req.headers['stripe-signature']);
} catch (err) {
common.logging.error(err);
logging.error(err);
res.writeHead(401);
return res.end();
}
common.logging.info(`Handling webhook ${event.type}`);
logging.info(`Handling webhook ${event.type}`);
try {
await stripeWebhookService.handleWebhook(event);
res.writeHead(200);
res.end();
} catch (err) {
common.logging.error(`Error handling webhook ${event.type}`, err);
logging.error(`Error handling webhook ${event.type}`, err);
res.writeHead(err.statusCode || 500);
res.end();
}

View File

@ -1,22 +0,0 @@
let currentLogger = {
error: global.console.error,
info: global.console.info,
warn: global.console.warn
};
module.exports = {
get logging() {
const loggerInterface = Object.create(currentLogger);
return Object.assign(loggerInterface, {
setLogger(newLogger) {
currentLogger = newLogger;
// Overwrite any existing reference to loggerInterface
Object.assign(loggerInterface, Object.create(newLogger));
}
});
},
get errors() {
return require('@tryghost/ignition-errors');
}
};

View File

@ -1,4 +1,4 @@
const errors = require('@tryghost/ignition-errors');
const errors = require('@tryghost/errors');
module.exports = class MemberController {
/**

View File

@ -1,4 +1,4 @@
const common = require('../../lib/common');
const logging = require('@tryghost/logging');
const _ = require('lodash');
module.exports = class RouterController {
@ -17,7 +17,6 @@ module.exports = class RouterController {
* @param {any} deps.tokenService
* @param {{isSet(name: string): boolean}} deps.labsService
* @param {any} deps.config
* @param {any} deps.logging
*/
constructor({
offersAPI,
@ -31,8 +30,7 @@ module.exports = class RouterController {
tokenService,
sendEmailWithMagicLink,
labsService,
config,
logging
config
}) {
this._offersAPI = offersAPI;
this._paymentsService = paymentsService;
@ -46,7 +44,6 @@ module.exports = class RouterController {
this._sendEmailWithMagicLink = sendEmailWithMagicLink;
this.labsService = labsService;
this._config = config;
this._logging = logging;
}
async ensureStripe(_req, res, next) {
@ -248,7 +245,7 @@ module.exports = class RouterController {
break;
}
} catch (err) {
this._logging.info('Ignoring error for fetching customer for checkout');
logging.info('Ignoring error for fetching customer for checkout');
}
}
@ -304,7 +301,7 @@ module.exports = class RouterController {
return res.end('Created.');
} catch (err) {
const statusCode = (err && err.statusCode) || 500;
common.logging.error(err);
logging.error(err);
res.writeHead(statusCode);
return res.end('Internal Server Error.');
}

View File

@ -1,4 +1,5 @@
const errors = require('@tryghost/errors');
const logging = require('@tryghost/logging');
const tpl = require('@tryghost/tpl');
const messages = {
@ -14,22 +15,13 @@ const messages = {
* @prop {() => Promise<JWKS>} getPublicKeys
*/
/**
* @typedef {object} ILogging
* @prop {(msg) => void} info
* @prop {(msg) => void} warn
* @prop {(msg) => void} error
*/
module.exports = class WellKnownController {
/**
*
* @param {object} deps
* @param {ITokenService} deps.tokenService
* @param {ILogging} deps.logging
* @param {ITokenService} deps.tokenService
*/
constructor(deps) {
this._logging = deps.logging;
this._tokenService = deps.tokenService;
}
@ -47,7 +39,7 @@ module.exports = class WellKnownController {
message: tpl(messages.keyStoreError),
err
});
this._logging.error(error);
logging.error(error);
throw error;
}
}

View File

@ -1,18 +1,12 @@
const _ = require('lodash');
const logging = require('@tryghost/logging');
/**
* @typedef {object} ILogger
* @prop {(x: any) => void} error
* @prop {(x: any) => void} info
* @prop {(x: any) => void} warn
*/
module.exports = class StripeMigrations {
/**
* StripeMigrations
*
* @param {object} params
*
* @param {ILogger} params.logger
* @param {any} params.StripeCustomerSubscription
* @param {any} params.StripeProduct
* @param {any} params.StripePrice
@ -26,10 +20,8 @@ module.exports = class StripeMigrations {
StripePrice,
Product,
Settings,
stripeAPIService,
logger
stripeAPIService
}) {
this._logging = logger;
this._StripeCustomerSubscription = StripeCustomerSubscription;
this._StripeProduct = StripeProduct;
this._StripePrice = StripePrice;
@ -52,7 +44,7 @@ module.exports = class StripeMigrations {
if (subscriptions.length > 0 && products.length === 0 && prices.length === 0 && defaultProduct) {
try {
this._logging.info(`Populating products and prices for existing stripe customers`);
logging.info(`Populating products and prices for existing stripe customers`);
const uniquePlans = _.uniq(subscriptions.map(d => _.get(d, 'plan.id')));
let stripePrices = [];
@ -64,13 +56,13 @@ module.exports = class StripeMigrations {
stripePrices.push(stripePrice);
} catch (err) {
if (err && err.statusCode === 404) {
this._logging.warn(`Plan ${plan} not found on Stripe - ignoring`);
logging.warn(`Plan ${plan} not found on Stripe - ignoring`);
} else {
throw err;
}
}
}
this._logging.info(`Adding ${stripePrices.length} prices from Stripe`);
logging.info(`Adding ${stripePrices.length} prices from Stripe`);
for (const stripePrice of stripePrices) {
// We expanded the product when fetching this price.
/** @type {import('stripe').Stripe.Product} */
@ -93,8 +85,8 @@ module.exports = class StripeMigrations {
});
}
} catch (e) {
this._logging.error(`Failed to populate products/prices from stripe`);
this._logging.error(e);
logging.error(`Failed to populate products/prices from stripe`);
logging.error(e);
}
}
}
@ -129,7 +121,7 @@ module.exports = class StripeMigrations {
async populateStripePricesFromStripePlansSetting(plans) {
if (!plans) {
this._logging.info('Skipping stripe_plans -> stripe_prices migration');
logging.info('Skipping stripe_plans -> stripe_prices migration');
return;
}
let defaultStripeProduct;
@ -137,14 +129,14 @@ module.exports = class StripeMigrations {
defaultStripeProduct = stripeProductsPage.data[0];
if (!defaultStripeProduct) {
this._logging.info('Could not find Stripe Product - creating one');
logging.info('Could not find Stripe Product - creating one');
const productsPage = await this._Product.findPage({limit: 1});
const defaultProduct = productsPage.data[0];
const stripeProduct = await this._stripeAPIService.createProduct({
name: defaultProduct.get('name')
});
if (!defaultProduct) {
this._logging.error('Could not find Product - skipping stripe_plans -> stripe_prices migration');
logging.error('Could not find Product - skipping stripe_plans -> stripe_prices migration');
return;
}
defaultStripeProduct = await this._StripeProduct.add({
@ -157,10 +149,10 @@ module.exports = class StripeMigrations {
const price = await this.findPriceByPlan(plan);
if (!price) {
this._logging.info(`Could not find Stripe Price ${JSON.stringify(plan)}`);
logging.info(`Could not find Stripe Price ${JSON.stringify(plan)}`);
try {
this._logging.info(`Creating Stripe Price ${JSON.stringify(plan)}`);
logging.info(`Creating Stripe Price ${JSON.stringify(plan)}`);
const price = await this._stripeAPIService.createPrice({
currency: plan.currency,
amount: plan.amount,
@ -182,21 +174,21 @@ module.exports = class StripeMigrations {
interval: price.recurring.interval
});
} catch (err) {
this._logging.error({err, message: 'Adding price failed'});
logging.error({err, message: 'Adding price failed'});
}
}
}
}
async updatePortalPlansSetting(plans) {
this._logging.info('Migrating portal_plans setting from names to ids');
logging.info('Migrating portal_plans setting from names to ids');
const portalPlansSetting = await this._Settings.findOne({key: 'portal_plans'});
let portalPlans;
try {
portalPlans = JSON.parse(portalPlansSetting.get('value'));
} catch (err) {
this._logging.error({
logging.error({
message: 'Could not parse portal_plans setting, skipping migration',
err
});
@ -208,7 +200,7 @@ module.exports = class StripeMigrations {
});
if (!containsOldValues) {
this._logging.info('Could not find names in portal_plans setting, skipping migration');
logging.info('Could not find names in portal_plans setting, skipping migration');
return;
}
@ -238,7 +230,7 @@ module.exports = class StripeMigrations {
return newPortalPlans.concat(newPlan);
}, []);
this._logging.info(`Updating portal_plans setting to ${JSON.stringify(newPortalPlans)}`);
logging.info(`Updating portal_plans setting to ${JSON.stringify(newPortalPlans)}`);
await this._Settings.edit({
key: 'portal_plans',
value: JSON.stringify(newPortalPlans)
@ -248,11 +240,11 @@ module.exports = class StripeMigrations {
}
async populateMembersMonthlyPriceIdSettings() {
this._logging.info('Populating members_monthly_price_id from stripe_plans');
logging.info('Populating members_monthly_price_id from stripe_plans');
const monthlyPriceId = await this._Settings.findOne({key: 'members_monthly_price_id'});
if (monthlyPriceId.get('value')) {
this._logging.info('Skipping population of members_monthly_price_id, already populated');
logging.info('Skipping population of members_monthly_price_id, already populated');
return;
}
@ -261,7 +253,7 @@ module.exports = class StripeMigrations {
try {
plans = JSON.parse(stripePlans.get('value'));
} catch (err) {
this._logging.warn('Skipping population of members_monthly_price_id, could not parse stripe_plans');
logging.warn('Skipping population of members_monthly_price_id, could not parse stripe_plans');
return;
}
@ -270,7 +262,7 @@ module.exports = class StripeMigrations {
});
if (!monthlyPlan) {
this._logging.warn('Skipping population of members_monthly_price_id, could not find Monthly plan');
logging.warn('Skipping population of members_monthly_price_id, could not find Monthly plan');
return;
}
@ -284,13 +276,13 @@ module.exports = class StripeMigrations {
});
if (!monthlyPrice) {
this._logging.info('Could not find active Monthly price from stripe_plans - searching by interval');
logging.info('Could not find active Monthly price from stripe_plans - searching by interval');
monthlyPrice = await this._StripePrice.where('amount', '>', 0)
.where({interval: 'month', active: true}).fetch();
}
if (!monthlyPrice) {
this._logging.info('Could not any active Monthly price - creating a new one');
logging.info('Could not any active Monthly price - creating a new one');
let defaultStripeProduct;
const stripeProductsPage = await this._StripeProduct.findPage({limit: 1});
defaultStripeProduct = stripeProductsPage.data[0];
@ -320,11 +312,11 @@ module.exports = class StripeMigrations {
}
async populateMembersYearlyPriceIdSettings() {
this._logging.info('Populating members_yearly_price_id from stripe_plans');
logging.info('Populating members_yearly_price_id from stripe_plans');
const yearlyPriceId = await this._Settings.findOne({key: 'members_yearly_price_id'});
if (yearlyPriceId.get('value')) {
this._logging.info('Skipping population of members_yearly_price_id, already populated');
logging.info('Skipping population of members_yearly_price_id, already populated');
return;
}
@ -333,7 +325,7 @@ module.exports = class StripeMigrations {
try {
plans = JSON.parse(stripePlans.get('value'));
} catch (err) {
this._logging.warn('Skipping population of members_yearly_price_id, could not parse stripe_plans');
logging.warn('Skipping population of members_yearly_price_id, could not parse stripe_plans');
}
const yearlyPlan = plans.find((plan) => {
@ -341,7 +333,7 @@ module.exports = class StripeMigrations {
});
if (!yearlyPlan) {
this._logging.warn('Skipping population of members_yearly_price_id, could not find yearly plan');
logging.warn('Skipping population of members_yearly_price_id, could not find yearly plan');
return;
}
@ -355,13 +347,13 @@ module.exports = class StripeMigrations {
});
if (!yearlyPrice) {
this._logging.info('Could not find active yearly price from stripe_plans - searching by interval');
logging.info('Could not find active yearly price from stripe_plans - searching by interval');
yearlyPrice = await this._StripePrice.where('amount', '>', 0)
.where({interval: 'year', active: true}).fetch();
}
if (!yearlyPrice) {
this._logging.info('Could not any active yearly price - creating a new one');
logging.info('Could not any active yearly price - creating a new one');
let defaultStripeProduct;
const stripeProductsPage = await this._StripeProduct.findPage({limit: 1});
defaultStripeProduct = stripeProductsPage.data[0];
@ -391,12 +383,12 @@ module.exports = class StripeMigrations {
}
async populateDefaultProductMonthlyPriceId() {
this._logging.info('Migrating members_monthly_price_id setting to monthly_price_id column');
logging.info('Migrating members_monthly_price_id setting to monthly_price_id column');
const productsPage = await this._Product.findPage({limit: 1});
const defaultProduct = productsPage.data[0];
if (defaultProduct.get('monthly_price_id')) {
this._logging.warn('Skipping migration, monthly_price_id already set');
logging.warn('Skipping migration, monthly_price_id already set');
return;
}
@ -407,12 +399,12 @@ module.exports = class StripeMigrations {
}
async populateDefaultProductYearlyPriceId() {
this._logging.info('Migrating members_yearly_price_id setting to yearly_price_id column');
logging.info('Migrating members_yearly_price_id setting to yearly_price_id column');
const productsPage = await this._Product.findPage({limit: 1});
const defaultProduct = productsPage.data[0];
if (defaultProduct.get('yearly_price_id')) {
this._logging.warn('Skipping migration, yearly_price_id already set');
logging.warn('Skipping migration, yearly_price_id already set');
return;
}
@ -423,14 +415,14 @@ module.exports = class StripeMigrations {
}
async revertPortalPlansSetting() {
this._logging.info('Migrating portal_plans setting from ids to names');
logging.info('Migrating portal_plans setting from ids to names');
const portalPlansSetting = await this._Settings.findOne({key: 'portal_plans'});
let portalPlans;
try {
portalPlans = JSON.parse(portalPlansSetting.get('value'));
} catch (err) {
this._logging.error({
logging.error({
message: 'Could not parse portal_plans setting, skipping migration',
err
});
@ -442,7 +434,7 @@ module.exports = class StripeMigrations {
});
if (containsNamedValues) {
this._logging.info('The portal_plans setting already contains names, skipping migration');
logging.info('The portal_plans setting already contains names, skipping migration');
return;
}
const portalPlanIds = portalPlans.filter((plan) => {
@ -450,7 +442,7 @@ module.exports = class StripeMigrations {
});
if (portalPlanIds.length === 0) {
this._logging.info('No price ids found in portal_plans setting, skipping migration');
logging.info('No price ids found in portal_plans setting, skipping migration');
return;
}
const defaultPortalPlans = portalPlans.filter((plan) => {
@ -469,7 +461,7 @@ module.exports = class StripeMigrations {
return updatedPortalPlans;
}, defaultPortalPlans);
this._logging.info(`Updating portal_plans setting to ${JSON.stringify(newPortalPlans)}`);
logging.info(`Updating portal_plans setting to ${JSON.stringify(newPortalPlans)}`);
await this._Settings.edit({
key: 'portal_plans',
value: JSON.stringify(newPortalPlans)
@ -486,13 +478,13 @@ module.exports = class StripeMigrations {
return !sub.toJSON().price;
});
if (invalidSubscriptions.length > 0) {
this._logging.warn(`Deleting ${invalidSubscriptions.length} invalid subscription(s)`);
logging.warn(`Deleting ${invalidSubscriptions.length} invalid subscription(s)`);
for (let sub of invalidSubscriptions) {
this._logging.warn(`Deleting subscription - ${sub.id} - no price found`);
logging.warn(`Deleting subscription - ${sub.id} - no price found`);
await sub.destroy();
}
} else {
this._logging.info(`No invalid subscriptions, skipping migration`);
logging.info(`No invalid subscriptions, skipping migration`);
}
}
};

View File

@ -4,15 +4,13 @@ module.exports = class EventRepository {
MemberPaymentEvent,
MemberStatusEvent,
MemberLoginEvent,
MemberPaidSubscriptionEvent,
logger
MemberPaidSubscriptionEvent
}) {
this._MemberSubscribeEvent = MemberSubscribeEvent;
this._MemberPaidSubscriptionEvent = MemberPaidSubscriptionEvent;
this._MemberPaymentEvent = MemberPaymentEvent;
this._MemberStatusEvent = MemberStatusEvent;
this._MemberLoginEvent = MemberLoginEvent;
this._logging = logger;
}
async registerPayment(data) {

View File

@ -1,5 +1,6 @@
const _ = require('lodash');
const errors = require('@tryghost/errors');
const logging = require('@tryghost/logging');
const tpl = require('@tryghost/tpl');
const DomainEvents = require('@tryghost/domain-events');
const {SubscriptionCreatedEvent} = require('@tryghost/member-events');
@ -33,7 +34,6 @@ module.exports = class MemberRepository {
* @param {any} deps.productRepository
* @param {import('../../services/stripe-api')} deps.stripeAPIService
* @param {ITokenService} deps.tokenService
* @param {any} deps.logger
*/
constructor({
Member,
@ -47,8 +47,7 @@ module.exports = class MemberRepository {
OfferRedemption,
stripeAPIService,
productRepository,
tokenService,
logger
tokenService
}) {
this._Member = Member;
this._MemberSubscribeEvent = MemberSubscribeEvent;
@ -61,7 +60,6 @@ module.exports = class MemberRepository {
this._stripeAPIService = stripeAPIService;
this._productRepository = productRepository;
this.tokenService = tokenService;
this._logging = logger;
DomainEvents.subscribe(SubscriptionCreatedEvent, async function (event) {
if (!event.data.offerId) {
@ -586,11 +584,11 @@ module.exports = class MemberRepository {
}, options);
} else {
// Log error if no Ghost products found
this._logging.error(`There was an error linking subscription - ${subscription.id}, no Products exist.`);
logging.error(`There was an error linking subscription - ${subscription.id}, no Products exist.`);
}
} catch (e) {
this._logging.error(`Failed to handle prices and product for - ${subscription.id}.`);
this._logging.error(e);
logging.error(`Failed to handle prices and product for - ${subscription.id}.`);
logging.error(e);
}
const subscriptionData = {
@ -679,8 +677,8 @@ module.exports = class MemberRepository {
activeSubscriptionForChangedProduct = true;
}
} catch (e) {
this._logging.error(`Failed to attach products to member - ${data.id}`);
this._logging.error(e);
logging.error(`Failed to attach products to member - ${data.id}`);
logging.error(e);
}
}
}
@ -704,8 +702,8 @@ module.exports = class MemberRepository {
activeSubscriptionForGhostProduct = true;
}
} catch (e) {
this._logging.error(`Failed to attach products to member - ${data.id}`);
this._logging.error(e);
logging.error(`Failed to attach products to member - ${data.id}`);
logging.error(e);
}
}
}
@ -730,8 +728,8 @@ module.exports = class MemberRepository {
// Edit member with updated products assoicated
updatedMember = await this._Member.edit({status: status, products: memberProducts}, {...options, id: data.id});
} catch (e) {
this._logging.error(`Failed to update member - ${data.id} - with related products`);
this._logging.error(e);
logging.error(`Failed to update member - ${data.id} - with related products`);
logging.error(e);
updatedMember = await this._Member.edit({status: status}, {...options, id: data.id});
}
@ -909,7 +907,7 @@ module.exports = class MemberRepository {
const fetchedCustomer = await this._stripeAPIService.getCustomer(customer.get('customer_id'));
stripeCustomer = fetchedCustomer;
} catch (err) {
this._logging.info('Ignoring error for fetching customer for checkout');
logging.info('Ignoring error for fetching customer for checkout');
}
}
@ -1072,8 +1070,8 @@ module.exports = class MemberRepository {
subscription: updatedSubscription
});
} catch (err) {
this._logging.error(`There was an error cancelling subscription ${subscription.get('subscription_id')}`);
this._logging.error(err);
logging.error(`There was an error cancelling subscription ${subscription.get('subscription_id')}`);
logging.error(err);
}
}
}

View File

@ -28,8 +28,8 @@
"dependencies": {
"@tryghost/debug": "^0.1.2",
"@tryghost/domain-events": "^0.1.3",
"@tryghost/errors": "^0.2.9",
"@tryghost/ignition-errors": "^0.1.2",
"@tryghost/errors": "^1.1.0",
"@tryghost/logging": "^1.0.2",
"@tryghost/magic-link": "^1.0.14",
"@tryghost/member-analytics-service": "^0.1.4",
"@tryghost/member-events": "^0.3.1",

View File

@ -5,7 +5,7 @@ const debug = require('@tryghost/debug')('members-ssr');
const {
BadRequestError,
IncorrectUsageError
} = require('@tryghost/ignition-errors');
} = require('@tryghost/errors');
/**
* @typedef {import('http').IncomingMessage} Request

View File

@ -26,7 +26,7 @@
},
"dependencies": {
"@tryghost/debug": "^0.1.2",
"@tryghost/ignition-errors": "^0.1.2",
"@tryghost/errors": "^1.1.0",
"bluebird": "^3.5.3",
"concat-stream": "^2.0.0",
"cookies": "^0.8.0",

View File

@ -15,13 +15,6 @@ const STRIPE_API_VERSION = '2020-08-27';
* @typedef {import('stripe').Stripe.WebhookEndpoint} IWebhookEndpoint
*/
/**
* @typedef {object} ILogger
* @prop {(x: any) => void} error
* @prop {(x: any) => void} info
* @prop {(x: any) => void} warn
*/
/**
* @typedef {object} IStripeServiceConfig
* @prop {string} secretKey
@ -39,13 +32,11 @@ module.exports = class StripeService {
* StripeService
*
* @param {object} params
* @param {ILogger} params.logger
* @param {IStripeServiceConfig} params.config
*/
constructor({config, logger}) {
constructor({config}) {
/** @type {Stripe} */
this._stripe = null;
this.logging = logger;
this._configured = false;
if (config.secretKey) {
this.configure(config);