@platformos/pos-cli
Version:
Manage your platformOS application
395 lines • 15.7 kB
JavaScript
Object.defineProperty(exports, "__esModule", { value: true });
var tslib_1 = require("tslib");
var utils_1 = require("@sentry/utils");
var integration_1 = require("./integration");
/**
* Base implementation for all JavaScript SDK clients.
*
* Call the constructor with the corresponding backend constructor and options
* specific to the client subclass. To access these options later, use
* {@link Client.getOptions}. Also, the Backend instance is available via
* {@link Client.getBackend}.
*
* If a Dsn is specified in the options, it will be parsed and stored. Use
* {@link Client.getDsn} to retrieve the Dsn at any moment. In case the Dsn is
* invalid, the constructor will throw a {@link SentryException}. Note that
* without a valid Dsn, the SDK will not send any events to Sentry.
*
* Before sending an event via the backend, it is passed through
* {@link BaseClient.prepareEvent} to add SDK information and scope data
* (breadcrumbs and context). To add more custom information, override this
* method and extend the resulting prepared event.
*
* To issue automatically created events (e.g. via instrumentation), use
* {@link Client.captureEvent}. It will prepare the event and pass it through
* the callback lifecycle. To issue auto-breadcrumbs, use
* {@link Client.addBreadcrumb}.
*
* @example
* class NodeClient extends BaseClient<NodeBackend, NodeOptions> {
* public constructor(options: NodeOptions) {
* super(NodeBackend, options);
* }
*
* // ...
* }
*/
var BaseClient = /** @class */ (function () {
/**
* Initializes this client instance.
*
* @param backendClass A constructor function to create the backend.
* @param options Options for the client.
*/
function BaseClient(backendClass, options) {
/** Array of used integrations. */
this._integrations = {};
/** Is the client still processing a call? */
this._processing = false;
this._backend = new backendClass(options);
this._options = options;
if (options.dsn) {
this._dsn = new utils_1.Dsn(options.dsn);
}
if (this._isEnabled()) {
this._integrations = integration_1.setupIntegrations(this._options);
}
}
/**
* @inheritDoc
*/
BaseClient.prototype.captureException = function (exception, hint, scope) {
var _this = this;
var eventId = hint && hint.event_id;
this._processing = true;
this._getBackend()
.eventFromException(exception, hint)
.then(function (event) { return _this._processEvent(event, hint, scope); })
.then(function (finalEvent) {
// We need to check for finalEvent in case beforeSend returned null
eventId = finalEvent && finalEvent.event_id;
_this._processing = false;
})
.then(null, function (reason) {
utils_1.logger.error(reason);
_this._processing = false;
});
return eventId;
};
/**
* @inheritDoc
*/
BaseClient.prototype.captureMessage = function (message, level, hint, scope) {
var _this = this;
var eventId = hint && hint.event_id;
this._processing = true;
var promisedEvent = utils_1.isPrimitive(message)
? this._getBackend().eventFromMessage("" + message, level, hint)
: this._getBackend().eventFromException(message, hint);
promisedEvent
.then(function (event) { return _this._processEvent(event, hint, scope); })
.then(function (finalEvent) {
// We need to check for finalEvent in case beforeSend returned null
eventId = finalEvent && finalEvent.event_id;
_this._processing = false;
})
.then(null, function (reason) {
utils_1.logger.error(reason);
_this._processing = false;
});
return eventId;
};
/**
* @inheritDoc
*/
BaseClient.prototype.captureEvent = function (event, hint, scope) {
var _this = this;
var eventId = hint && hint.event_id;
this._processing = true;
this._processEvent(event, hint, scope)
.then(function (finalEvent) {
// We need to check for finalEvent in case beforeSend returned null
eventId = finalEvent && finalEvent.event_id;
_this._processing = false;
})
.then(null, function (reason) {
utils_1.logger.error(reason);
_this._processing = false;
});
return eventId;
};
/**
* @inheritDoc
*/
BaseClient.prototype.getDsn = function () {
return this._dsn;
};
/**
* @inheritDoc
*/
BaseClient.prototype.getOptions = function () {
return this._options;
};
/**
* @inheritDoc
*/
BaseClient.prototype.flush = function (timeout) {
var _this = this;
return this._isClientProcessing(timeout).then(function (status) {
clearInterval(status.interval);
return _this._getBackend()
.getTransport()
.close(timeout)
.then(function (transportFlushed) { return status.ready && transportFlushed; });
});
};
/**
* @inheritDoc
*/
BaseClient.prototype.close = function (timeout) {
var _this = this;
return this.flush(timeout).then(function (result) {
_this.getOptions().enabled = false;
return result;
});
};
/**
* @inheritDoc
*/
BaseClient.prototype.getIntegrations = function () {
return this._integrations || {};
};
/**
* @inheritDoc
*/
BaseClient.prototype.getIntegration = function (integration) {
try {
return this._integrations[integration.id] || null;
}
catch (_oO) {
utils_1.logger.warn("Cannot retrieve integration " + integration.id + " from the current Client");
return null;
}
};
/** Waits for the client to be done with processing. */
BaseClient.prototype._isClientProcessing = function (timeout) {
var _this = this;
return new utils_1.SyncPromise(function (resolve) {
var ticked = 0;
var tick = 1;
var interval = 0;
clearInterval(interval);
interval = setInterval(function () {
if (!_this._processing) {
resolve({
interval: interval,
ready: true,
});
}
else {
ticked += tick;
if (timeout && ticked >= timeout) {
resolve({
interval: interval,
ready: false,
});
}
}
}, tick);
});
};
/** Returns the current backend. */
BaseClient.prototype._getBackend = function () {
return this._backend;
};
/** Determines whether this SDK is enabled and a valid Dsn is present. */
BaseClient.prototype._isEnabled = function () {
return this.getOptions().enabled !== false && this._dsn !== undefined;
};
/**
* Adds common information to events.
*
* The information includes release and environment from `options`,
* breadcrumbs and context (extra, tags and user) from the scope.
*
* Information that is already present in the event is never overwritten. For
* nested objects, such as the context, keys are merged.
*
* @param event The original event.
* @param hint May contain additional informartion about the original exception.
* @param scope A scope containing event metadata.
* @returns A new event with more information.
*/
BaseClient.prototype._prepareEvent = function (event, scope, hint) {
var _this = this;
var _a = this.getOptions(), environment = _a.environment, release = _a.release, dist = _a.dist, _b = _a.maxValueLength, maxValueLength = _b === void 0 ? 250 : _b, _c = _a.normalizeDepth, normalizeDepth = _c === void 0 ? 3 : _c;
var prepared = tslib_1.__assign({}, event);
if (prepared.environment === undefined && environment !== undefined) {
prepared.environment = environment;
}
if (prepared.release === undefined && release !== undefined) {
prepared.release = release;
}
if (prepared.dist === undefined && dist !== undefined) {
prepared.dist = dist;
}
if (prepared.message) {
prepared.message = utils_1.truncate(prepared.message, maxValueLength);
}
var exception = prepared.exception && prepared.exception.values && prepared.exception.values[0];
if (exception && exception.value) {
exception.value = utils_1.truncate(exception.value, maxValueLength);
}
var request = prepared.request;
if (request && request.url) {
request.url = utils_1.truncate(request.url, maxValueLength);
}
if (prepared.event_id === undefined) {
prepared.event_id = hint && hint.event_id ? hint.event_id : utils_1.uuid4();
}
this._addIntegrations(prepared.sdk);
// We prepare the result here with a resolved Event.
var result = utils_1.SyncPromise.resolve(prepared);
// This should be the last thing called, since we want that
// {@link Hub.addEventProcessor} gets the finished prepared event.
if (scope) {
// In case we have a hub we reassign it.
result = scope.applyToEvent(prepared, hint);
}
return result.then(function (evt) {
// tslint:disable-next-line:strict-type-predicates
if (typeof normalizeDepth === 'number' && normalizeDepth > 0) {
return _this._normalizeEvent(evt, normalizeDepth);
}
return evt;
});
};
/**
* Applies `normalize` function on necessary `Event` attributes to make them safe for serialization.
* Normalized keys:
* - `breadcrumbs.data`
* - `user`
* - `contexts`
* - `extra`
* @param event Event
* @returns Normalized event
*/
BaseClient.prototype._normalizeEvent = function (event, depth) {
if (!event) {
return null;
}
// tslint:disable:no-unsafe-any
return tslib_1.__assign({}, event, (event.breadcrumbs && {
breadcrumbs: event.breadcrumbs.map(function (b) { return (tslib_1.__assign({}, b, (b.data && {
data: utils_1.normalize(b.data, depth),
}))); }),
}), (event.user && {
user: utils_1.normalize(event.user, depth),
}), (event.contexts && {
contexts: utils_1.normalize(event.contexts, depth),
}), (event.extra && {
extra: utils_1.normalize(event.extra, depth),
}));
};
/**
* This function adds all used integrations to the SDK info in the event.
* @param sdkInfo The sdkInfo of the event that will be filled with all integrations.
*/
BaseClient.prototype._addIntegrations = function (sdkInfo) {
var integrationsArray = Object.keys(this._integrations);
if (sdkInfo && integrationsArray.length > 0) {
sdkInfo.integrations = integrationsArray;
}
};
/**
* Processes an event (either error or message) and sends it to Sentry.
*
* This also adds breadcrumbs and context information to the event. However,
* platform specific meta data (such as the User's IP address) must be added
* by the SDK implementor.
*
*
* @param event The event to send to Sentry.
* @param hint May contain additional informartion about the original exception.
* @param scope A scope containing event metadata.
* @returns A SyncPromise that resolves with the event or rejects in case event was/will not be send.
*/
BaseClient.prototype._processEvent = function (event, hint, scope) {
var _this = this;
var _a = this.getOptions(), beforeSend = _a.beforeSend, sampleRate = _a.sampleRate;
if (!this._isEnabled()) {
return utils_1.SyncPromise.reject('SDK not enabled, will not send event.');
}
// 1.0 === 100% events are sent
// 0.0 === 0% events are sent
if (typeof sampleRate === 'number' && Math.random() > sampleRate) {
return utils_1.SyncPromise.reject('This event has been sampled, will not send event.');
}
return new utils_1.SyncPromise(function (resolve, reject) {
_this._prepareEvent(event, scope, hint)
.then(function (prepared) {
if (prepared === null) {
reject('An event processor returned null, will not send event.');
return;
}
var finalEvent = prepared;
var isInternalException = hint && hint.data && hint.data.__sentry__ === true;
if (isInternalException || !beforeSend) {
_this._getBackend().sendEvent(finalEvent);
resolve(finalEvent);
return;
}
var beforeSendResult = beforeSend(prepared, hint);
// tslint:disable-next-line:strict-type-predicates
if (typeof beforeSendResult === 'undefined') {
utils_1.logger.error('`beforeSend` method has to return `null` or a valid event.');
}
else if (utils_1.isThenable(beforeSendResult)) {
_this._handleAsyncBeforeSend(beforeSendResult, resolve, reject);
}
else {
finalEvent = beforeSendResult;
if (finalEvent === null) {
utils_1.logger.log('`beforeSend` returned `null`, will not send event.');
resolve(null);
return;
}
// From here on we are really async
_this._getBackend().sendEvent(finalEvent);
resolve(finalEvent);
}
})
.then(null, function (reason) {
_this.captureException(reason, {
data: {
__sentry__: true,
},
originalException: reason,
});
reject("Event processing pipeline threw an error, original event will not be sent. Details have been sent as a new event.\nReason: " + reason);
});
});
};
/**
* Resolves before send Promise and calls resolve/reject on parent SyncPromise.
*/
BaseClient.prototype._handleAsyncBeforeSend = function (beforeSend, resolve, reject) {
var _this = this;
beforeSend
.then(function (processedEvent) {
if (processedEvent === null) {
reject('`beforeSend` returned `null`, will not send event.');
return;
}
// From here on we are really async
_this._getBackend().sendEvent(processedEvent);
resolve(processedEvent);
})
.then(null, function (e) {
reject("beforeSend rejected with " + e);
});
};
return BaseClient;
}());
exports.BaseClient = BaseClient;
//# sourceMappingURL=baseclient.js.map