Skip to content

[WIP] Major Version 5 #1861

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 9 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,4 @@ lint-results.json

# legacy
!/packages/raven-js/dist
tmp.js
1 change: 1 addition & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ branches:
only:
- master
- /^release\/.+$/
- /^major\/.+$/

install: true
sudo: required
Expand Down
31 changes: 30 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,35 @@
# Changelog

## Unreleased
## v5

### Migration from v4

This major bump brings a lot of internal improvements. If you were using the SDK without any special abilities,
basically, the way we describe it in the docs, you should be fine by just updating it. This is a **breaking** release
since we removed some methods from the public API and removed some classes from the default export.

- **breaking** [node] fix: Events created from exception shouldn't have top-level message attribute
- [utils] ref: Update wrap method to hide internal sentry flags
- [utils] fix: Make internal Sentry flags non-enumerable in fill utils
- [utils] ref: Move `SentryError` + `PromiseBuffer` to utils
- **breaking** [core] ref: Use `SyncPromise` internally, this reduces memory pressure by a lot.
- **breaking** [browser] ref: Removed `BrowserBackend` from default export.
- **breaking** [node] ref: Removed `BrowserBackend` from default export.
- **breaking** [core] feat: Disable client once flushed using `close` method
- ref: Move internal `ExtendedError` to a types package
- **breaking** [core] ref: Pass `Event` to `sendEvent` instead of already stringified data
- [utils] feat: Introduce `isSyntheticEvent` util
- **breaking** [utils] ref: remove `isArray` util in favor of `Array.isArray`
- **breaking** [utils] ref: Remove `isNaN` util in favor of `Number.isNaN`
- **breaking** [utils] ref: Remove `isFunction` util in favor of `typeof === 'function'`
- **breaking** [utils] ref: Remove `isUndefined` util in favor of `=== void 0`
- **breaking** [utils] ref: Remove `assign` util in favor of `Object.assign`
- **breaking** [utils] ref: Remove `includes` util in favor of native `includes`
- **breaking** [utils] ref: Rename `serializeKeysToEventMessage` to `keysToEventMessage`
- **breaking** [utils] ref: Rename `limitObjectDepthToSize` to `normalizeToSize` and rewrite its internals
- **breaking** [utils] ref: Rename `safeNormalize` to `normalize` and rewrite its internals
- **breaking** [utils] ref: Remove `serialize`, `deserialize`, `clone` and `serializeObject` functions
- **breaking** [utils] ref: Rewrite normalization functions by removing most of them and leaving just `normalize` and `normalizeToSize`

## 4.6.3

Expand Down
20 changes: 10 additions & 10 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,30 +25,30 @@
"devDependencies": {
"@google-cloud/storage": "^2.3.1",
"@types/chai": "^4.1.3",
"@types/jest": "^23.3.9",
"@types/jest": "^24.0.6",
"@types/mocha": "^5.2.0",
"@types/node": "^10.0.2",
"@types/node": "^11.9.4",
"@types/raven": "^2.5.1",
"@types/sinon": "^5.0.7",
"@types/sinon": "^7.0.6",
"chai": "^4.1.2",
"codecov": "^3.0.2",
"danger": "^6.1.5",
"danger": "^7.0.12",
"danger-plugin-tslint": "^2.0.0",
"jest": "^23.6.0",
"jest": "^24.1.0",
"karma-sinon": "^1.0.5",
"lerna": "3.5.0",
"mocha": "^4.1.0",
"lerna": "3.13.0",
"mocha": "^5.2.0",
"npm-run-all": "^4.1.2",
"prettier": "^1.14.0",
"prettier-check": "^2.0.0",
"replace-in-file": "^3.4.2",
"rimraf": "^2.6.2",
"rimraf": "^2.6.3",
"sinon": "^7.1.1",
"ts-jest": "^23.10.5",
"tslint": "^5.11.0",
"typedoc": "^0.13.0",
"typedoc": "^0.14.2",
"typedoc-plugin-monorepo": "^0.1.0",
"typescript": "^3.2.0",
"typescript-tslint-plugin": "^0.2.1"
"typescript-tslint-plugin": "^0.3.1"
}
}
26 changes: 14 additions & 12 deletions packages/browser/LICENSE
Original file line number Diff line number Diff line change
@@ -1,23 +1,25 @@
Copyright (c) 2018 Sentry (https://sentry.io) and individual contributors.
BSD 3-Clause License

Copyright (c) 2019, Sentry
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.

2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.

3. Neither the name of the Sentry nor the names of its contributors may be
used to endorse or promote products derived from this software without specific
prior written permission.
* Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
Expand Down
37 changes: 19 additions & 18 deletions packages/browser/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,35 +21,36 @@
"tslib": "^1.9.3"
},
"devDependencies": {
"@types/md5": "2.1.32",
"@types/md5": "2.1.33",
"chai": "^4.1.2",
"jsdom": "^11.12.0",
"karma": "^2.0.2",
"jest": "^24.1.0",
"jsdom": "^13.2.0",
"karma": "^4.0.0",
"karma-chai": "^0.1.0",
"karma-chrome-launcher": "^2.2.0",
"karma-failed-reporter": "0.0.3",
"karma-firefox-launcher": "^1.1.0",
"karma-mocha": "^1.3.0",
"karma-mocha-reporter": "^2.2.5",
"karma-rollup-preprocessor": "^6.0.0",
"karma-sauce-launcher": "^1.2.0",
"karma-typescript": "^3.0.12",
"karma-typescript-es6-transform": "^1.0.4",
"karma-rollup-preprocessor": "^7.0.0",
"karma-sauce-launcher": "^2.0.2",
"karma-typescript": "^4.0.0",
"karma-typescript-es6-transform": "^4.0.0",
"npm-run-all": "^4.1.2",
"prettier": "^1.14.0",
"prettier": "^1.16.4",
"prettier-check": "^2.0.0",
"rimraf": "^2.6.2",
"rollup": "^0.58.2",
"rimraf": "^2.6.3",
"rollup": "^1.2.1",
"rollup-plugin-commonjs": "^9.1.3",
"rollup-plugin-license": "^0.6.0",
"rollup-plugin-node-resolve": "^3.3.0",
"rollup-plugin-license": "^0.8.1",
"rollup-plugin-node-resolve": "^4.0.0",
"rollup-plugin-npm": "^2.0.0",
"rollup-plugin-typescript2": "^0.13.0",
"rollup-plugin-uglify": "^3.0.0",
"sinon": "^5.0.3",
"tslint": "^5.11.0",
"typescript": "^3.2.0",
"webpack": "^4.26.0"
"rollup-plugin-typescript2": "^0.19.2",
"rollup-plugin-uglify": "^6.0.2",
"sinon": "^7.2.3",
"tslint": "^5.12.1",
"typescript": "^3.3.3",
"webpack": "^4.29.5"
},
"scripts": {
"build": "run-p build:esm build:es5",
Expand Down
4 changes: 3 additions & 1 deletion packages/browser/rollup.config.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import commonjs from 'rollup-plugin-commonjs';
import uglify from 'rollup-plugin-uglify';
import { uglify } from 'rollup-plugin-uglify';
import resolve from 'rollup-plugin-node-resolve';
import typescript from 'rollup-plugin-typescript2';
import license from 'rollup-plugin-license';
Expand Down Expand Up @@ -32,6 +32,7 @@ const bundleConfig = {
tsconfigOverride: {
compilerOptions: {
declaration: false,
module: 'ES2015',
paths: {
'@sentry/utils/*': ['../utils/src/*'],
'@sentry/core': ['../core/src'],
Expand Down Expand Up @@ -72,6 +73,7 @@ export default [
tsconfig: 'tsconfig.build.json',
tsconfigOverride: {
compilerOptions: {
module: 'ES2015',
rootDir: 'src',
},
},
Expand Down
97 changes: 45 additions & 52 deletions packages/browser/src/backend.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { BaseBackend, Options, SentryError } from '@sentry/core';
import { SentryEvent, SentryEventHint, Severity, Transport } from '@sentry/types';
import { BaseBackend } from '@sentry/core';
import { Event, EventHint, Options, Severity, Transport } from '@sentry/types';
import { isDOMError, isDOMException, isError, isErrorEvent, isPlainObject } from '@sentry/utils/is';
import { supportsBeacon, supportsFetch } from '@sentry/utils/supports';
import { SyncPromise } from '@sentry/utils/syncpromise';
import { addExceptionTypeValue, eventFromPlainObject, eventFromStacktrace, prepareFramesForEvent } from './parsers';
import { computeStackTrace } from './tracekit';
import { BeaconTransport, FetchTransport, XHRTransport } from './transports';
Expand All @@ -26,25 +27,11 @@ export interface BrowserOptions extends Options {
whitelistUrls?: Array<string | RegExp>;
}

/** The Sentry Browser SDK Backend. */
/**
* The Sentry Browser SDK Backend.
* @hidden
*/
export class BrowserBackend extends BaseBackend<BrowserOptions> {
/**
* @inheritDoc
*/
public install(): boolean {
// We are only called by the client if the SDK is enabled and a valid Dsn
// has been configured. If no Dsn is present, this indicates a programming
// error.
const dsn = this.options.dsn;
if (!dsn) {
throw new SentryError('Invariant exception: install() must not be called when disabled');
}

Error.stackTraceLimit = 50;

return true;
}

/**
* @inheritdoc
*/
Expand All @@ -69,48 +56,60 @@ export class BrowserBackend extends BaseBackend<BrowserOptions> {
/**
* @inheritDoc
*/
public async eventFromException(exception: any, hint?: SentryEventHint): Promise<SentryEvent> {
let event;
public eventFromException(exception: any, hint?: EventHint): SyncPromise<Event> {
let event: Event;

if (isErrorEvent(exception as ErrorEvent) && (exception as ErrorEvent).error) {
// If it is an ErrorEvent with `error` property, extract it to get actual Error
const ex = exception as ErrorEvent;
exception = ex.error; // tslint:disable-line:no-parameter-reassignment
const errorEvent = exception as ErrorEvent;
exception = errorEvent.error; // tslint:disable-line:no-parameter-reassignment
event = eventFromStacktrace(computeStackTrace(exception as Error));
return SyncPromise.resolve(this.buildEvent(event));
} else if (isDOMError(exception as DOMError) || isDOMException(exception as DOMException)) {
// If it is a DOMError or DOMException (which are legacy APIs, but still supported in some browsers)
// then we just extract the name and message, as they don't provide anything else
// https://developer.mozilla.org/en-US/docs/Web/API/DOMError
// https://developer.mozilla.org/en-US/docs/Web/API/DOMException
const ex = exception as DOMException;
const name = ex.name || (isDOMError(ex) ? 'DOMError' : 'DOMException');
const message = ex.message ? `${name}: ${ex.message}` : name;

event = await this.eventFromMessage(message, Severity.Error, hint);
addExceptionTypeValue(event, message);
const domException = exception as DOMException;
const name = domException.name || (isDOMError(domException) ? 'DOMError' : 'DOMException');
const message = domException.message ? `${name}: ${domException.message}` : name;

return this.eventFromMessage(message, Severity.Error, hint).then(messageEvent => {
addExceptionTypeValue(messageEvent, message);
return SyncPromise.resolve(this.buildEvent(messageEvent));
});
} else if (isError(exception as Error)) {
// we have a real Error object, do nothing
event = eventFromStacktrace(computeStackTrace(exception as Error));
return SyncPromise.resolve(this.buildEvent(event));
} else if (isPlainObject(exception as {}) && hint && hint.syntheticException) {
// If it is plain Object, serialize it manually and extract options
// This will allow us to group events based on top-level keys
// which is much better than creating new group when any key/value change
const ex = exception as {};
event = eventFromPlainObject(ex, hint.syntheticException);
const objectException = exception as {};
event = eventFromPlainObject(objectException, hint.syntheticException);
addExceptionTypeValue(event, 'Custom Object');
} else {
// If none of previous checks were valid, then it means that
// it's not a DOMError/DOMException
// it's not a plain Object
// it's not a valid ErrorEvent (one with an error property)
// it's not an Error
// So bail out and capture it as a simple message:
const ex = exception as string;
event = await this.eventFromMessage(ex, undefined, hint);
addExceptionTypeValue(event, `${ex}`);
return SyncPromise.resolve(this.buildEvent(event));
}

event = {
// If none of previous checks were valid, then it means that
// it's not a DOMError/DOMException
// it's not a plain Object
// it's not a valid ErrorEvent (one with an error property)
// it's not an Error
// So bail out and capture it as a simple message:
const stringException = exception as string;
return this.eventFromMessage(stringException, undefined, hint).then(messageEvent => {
addExceptionTypeValue(messageEvent, `${stringException}`);
return SyncPromise.resolve(this.buildEvent(messageEvent));
});
}

/**
* This is an internal helper function that creates an event.
*/
private buildEvent(event: Event, hint?: EventHint): Event {
return {
...event,
event_id: hint && hint.event_id,
exception: {
Expand All @@ -121,19 +120,13 @@ export class BrowserBackend extends BaseBackend<BrowserOptions> {
},
},
};

return event;
}

/**
* @inheritDoc
*/
public async eventFromMessage(
message: string,
level: Severity = Severity.Info,
hint?: SentryEventHint,
): Promise<SentryEvent> {
const event: SentryEvent = {
public eventFromMessage(message: string, level: Severity = Severity.Info, hint?: EventHint): SyncPromise<Event> {
const event: Event = {
event_id: hint && hint.event_id,
level,
message,
Expand All @@ -147,6 +140,6 @@ export class BrowserBackend extends BaseBackend<BrowserOptions> {
};
}

return event;
return SyncPromise.resolve(event);
}
}
7 changes: 4 additions & 3 deletions packages/browser/src/client.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { API, BaseClient, Scope } from '@sentry/core';
import { DsnLike, SentryEvent, SentryEventHint } from '@sentry/types';
import { DsnLike, Event, EventHint } from '@sentry/types';
import { logger } from '@sentry/utils/logger';
import { getGlobalObject } from '@sentry/utils/misc';
import { SyncPromise } from '@sentry/utils/syncpromise';
import { BrowserBackend, BrowserOptions } from './backend';
import { SDK_NAME, SDK_VERSION } from './version';

Expand Down Expand Up @@ -42,14 +43,14 @@ export class BrowserClient extends BaseClient<BrowserBackend, BrowserOptions> {
*
* @param options Configuration options for this SDK.
*/
public constructor(options: BrowserOptions) {
public constructor(options: BrowserOptions = {}) {
super(BrowserBackend, options);
}

/**
* @inheritDoc
*/
protected async prepareEvent(event: SentryEvent, scope?: Scope, hint?: SentryEventHint): Promise<SentryEvent | null> {
protected prepareEvent(event: Event, scope?: Scope, hint?: EventHint): SyncPromise<Event | null> {
event.platform = event.platform || 'javascript';
event.sdk = {
...event.sdk,
Expand Down
Loading