Skip to content
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
22 changes: 22 additions & 0 deletions packages/angular/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,32 @@
"fix": "run-s fix:eslint fix:prettier",
"fix:prettier": "prettier --write \"{src,test}/**/*.ts\"",
"fix:eslint": "eslint . --format stylish --fix",
"test": "jest",
"test:watch": "jest --watch",
"pack": "npm pack"
},
"volta": {
"extends": "../../package.json"
},
"jest": {
"collectCoverage": true,
"transform": {
"^.+\\.ts$": "ts-jest"
},
"moduleFileExtensions": [
"js",
"ts"
],
"testEnvironment": "jsdom",
"testMatch": [
"**/*.test.ts"
],
"globals": {
"ts-jest": {
"tsConfig": "./tsconfig.json",
"diagnostics": false
}
}
},
Comment on lines +63 to +82
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks unrelated to the subject. If that's the case, can we move it off to a separate PR for clarity?

"sideEffects": false
}
5 changes: 5 additions & 0 deletions packages/angular/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
import { SDK_VERSION } from '@sentry/browser';
import { setSDKInfo } from '@sentry/utils';

export * from '@sentry/browser';
export { createErrorHandler, ErrorHandlerOptions } from './errorhandler';
export {
Expand All @@ -8,3 +11,5 @@ export {
TraceDirective,
TraceService,
} from './tracing';

setSDKInfo('sentry.javascript.angular', 'npm:@sentry/angular', SDK_VERSION);
23 changes: 23 additions & 0 deletions packages/angular/test/init.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { getGlobalObject } from '@sentry/utils';

import * as Sentry from '../src/index';

const global = getGlobalObject<Window>();

describe('global SDK metadata', () => {
it('sets correct SDK data', () => {
// the SDK data is set when we import from (and therefore run) `../src/index.ts` - it sets the angular part itself,
// and the browser part gets set when it imports from @sentry/browser - so no action is necessary here before we run
// the `expect`s

expect(global.__SENTRY__?.sdkInfo).toBeDefined();
expect(global.__SENTRY__?.sdkInfo?.name).toEqual('sentry.javascript.angular');
expect(global.__SENTRY__?.sdkInfo?.version).toEqual(Sentry.SDK_VERSION);
expect(global.__SENTRY__?.sdkInfo?.packages).toEqual(
expect.arrayContaining([
{ name: 'npm:@sentry/angular', version: Sentry.SDK_VERSION },
{ name: 'npm:@sentry/browser', version: Sentry.SDK_VERSION },
]),
);
});
});
5 changes: 3 additions & 2 deletions packages/angular/tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
{
"extends": "./tsconfig.build.json",
"include": ["src/**/*.ts"],
"include": ["src/**/*.ts", "test/**/*.ts"],
"exclude": ["dist"],
"compilerOptions": {
"rootDir": "."
"rootDir": ".",
"types": ["jest"]
}
}
5 changes: 4 additions & 1 deletion packages/browser/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
export * from './exports';

import { Integrations as CoreIntegrations } from '@sentry/core';
import { getGlobalObject } from '@sentry/utils';
import { getGlobalObject, setSDKInfo } from '@sentry/utils';

import * as BrowserIntegrations from './integrations';
import * as Transports from './transports';
import { SDK_VERSION } from './version';

setSDKInfo('sentry.javascript.browser', 'npm:@sentry/browser', SDK_VERSION, false);

let windowIntegrations = {};

Expand Down
11 changes: 11 additions & 0 deletions packages/browser/test/unit/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {
init,
Integrations,
Scope,
SDK_VERSION,
wrap,
} from '../../src';
import { SimpleTransport } from './mocks/simpletransport';
Expand Down Expand Up @@ -171,6 +172,16 @@ describe('SentryBrowser', () => {
});

describe('SentryBrowser initialization', () => {
it('should set SDK info globally', () => {
// the SDK data is set when we import from (and therefore run) `../src/index.ts`, so no action is necessary here
// before we run the `expect`s

expect(global.__SENTRY__.sdkInfo).to.exist;
expect(global.__SENTRY__.sdkInfo.name).to.equal('sentry.javascript.browser');
expect(global.__SENTRY__.sdkInfo.version).to.equal(SDK_VERSION);
expect(global.__SENTRY__.sdkInfo.packages).to.deep.equal([{ name: 'npm:@sentry/browser', version: SDK_VERSION }]);
});

it('should use window.SENTRY_RELEASE to set release on initialization if available', () => {
global.SENTRY_RELEASE = { id: 'foobar' };
init({ dsn });
Expand Down
6 changes: 6 additions & 0 deletions packages/core/src/request.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
import { Event, SentryRequest, Session } from '@sentry/types';
import { getGlobalObject } from '@sentry/utils';

import { API } from './api';

/** Creates a SentryRequest from an event. */
export function sessionToSentryRequest(session: Session, api: API): SentryRequest {
const { name, version } = getGlobalObject().__SENTRY__?.sdkInfo || {};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is better design to pass dependencies explicitly instead of using the global namespace. What Kamil keeps saying about pure functions and avoiding side-effects ;)

Functions like sessionToSentryRequest are easier to test and to reason about if their output depends solely on the inputs, and never on other external state like global variables.

const envelopeHeaders = JSON.stringify({
sent_at: new Date().toISOString(),
sdk: { name, version },
});
const itemHeaders = JSON.stringify({
type: 'session',
Expand Down Expand Up @@ -39,9 +42,12 @@ export function eventToSentryRequest(event: Event, api: API): SentryRequest {
// deserialization. Instead, we only implement a minimal subset of the spec to
// serialize events inline here.
if (useEnvelope) {
const { name, version } = getGlobalObject().__SENTRY__?.sdkInfo || {};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does Relay actually accept sending an sdk envelope header with an empty object? If it doesn't, the correct behavior would be to omit this header entry if we don't have SDK info.


const envelopeHeaders = JSON.stringify({
event_id: event.event_id,
sent_at: new Date().toISOString(),
sdk: { name, version },
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For events, we could take this info off event.sdk, so no need for using the global namespace. Note how eventToSentryRequest was a pure function before this change. The returned request could be computed solely based on the inputs.

Using event.sdk also guarantees by construction that both values match. For multi-language SDKs, like react-native, is there a case for reporting different SDKs in the event vs envelope? 🤔

});
const itemHeaders = JSON.stringify({
type: event.type,
Expand Down
19 changes: 19 additions & 0 deletions packages/core/test/lib/request.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Event, TransactionSamplingMethod } from '@sentry/types';
import { getGlobalObject } from '@sentry/utils';

import { API } from '../../src/api';
import { eventToSentryRequest } from '../../src/request';
Expand Down Expand Up @@ -53,4 +54,22 @@ describe('eventToSentryRequest', () => {
expect('dog' in envelope.event.tags).toBe(true);
});
});

it('adds sdk metadata to envelope header', () => {
getGlobalObject().__SENTRY__ = { sdkInfo: { name: 'sentry.javascript.browser', version: '12.31.12' } } as any;

const result = eventToSentryRequest(event as Event, api);

const [envelopeHeaderString, itemHeaderString, eventString] = result.body.split('\n');

const envelope = {
envelopeHeader: JSON.parse(envelopeHeaderString),
itemHeader: JSON.parse(itemHeaderString),
event: JSON.parse(eventString),
};

expect(envelope.envelopeHeader).toEqual(
expect.objectContaining({ sdk: { name: 'sentry.javascript.browser', version: '12.31.12' } }),
);
});
});
3 changes: 2 additions & 1 deletion packages/ember/addon/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { macroCondition, isDevelopingApp } from '@embroider/macros';
import { next } from '@ember/runloop';
import { assert, warn } from '@ember/debug';
import Ember from 'ember';
import { timestampWithMs } from '@sentry/utils';
import { setSDKInfo, timestampWithMs } from '@sentry/utils';

declare module '@ember/debug' {
export function assert(desc: string, test: unknown): void;
Expand All @@ -19,6 +19,7 @@ export function InitSentryForEmber(_runtimeConfig: BrowserOptions | undefined) {
const initConfig = Object.assign({}, config.sentry, _runtimeConfig || {});

createEmberEventProcessor();
setSDKInfo('sentry.javascript.ember', 'npm:@sentry/ember', SDK_VERSION);

Sentry.init(initConfig);

Expand Down
20 changes: 20 additions & 0 deletions packages/ember/tests/unit/init-test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { module, test } from 'qunit';
import * as Sentry from '@sentry/ember';
import { getGlobalObject } from '@sentry/utils';

const global = getGlobalObject<Window>();

module('Unit | SDK initialization', function() {
test('adds SDK metadata globally', function(assert) {
// the SDK data is set when we import from @sentry/ember (and therefore run `addon/index.ts`) - it sets the ember
// part itself, and the browser part gets set when it imports from @sentry/browser - so no action is necessary here
// before we run the `assert`s

assert.equal(global.__SENTRY__?.sdkInfo?.name, 'sentry.javascript.ember');
assert.equal(global.__SENTRY__?.sdkInfo?.version, Sentry.SDK_VERSION);
assert.deepEqual(global.__SENTRY__?.sdkInfo?.packages, [
{ name: 'npm:@sentry/browser', version: Sentry.SDK_VERSION },
{ name: 'npm:@sentry/ember', version: Sentry.SDK_VERSION },
]);
});
});
6 changes: 6 additions & 0 deletions packages/node/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,12 @@ export { NodeClient } from './client';
export { defaultIntegrations, init, lastEventId, flush, close } from './sdk';
export { SDK_NAME, SDK_VERSION } from './version';

import { setSDKInfo } from '@sentry/utils';

import { SDK_VERSION } from './version';

setSDKInfo('sentry.javascript.node', 'npm:@sentry/node', SDK_VERSION, false);

import { Integrations as CoreIntegrations } from '@sentry/core';
import { getMainCarrier } from '@sentry/hub';
import * as domain from 'domain';
Expand Down
11 changes: 11 additions & 0 deletions packages/node/test/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
init,
NodeClient,
Scope,
SDK_VERSION,
} from '../src';
import { NodeBackend } from '../src/backend';

Expand Down Expand Up @@ -270,6 +271,16 @@ describe('SentryNode', () => {
});

describe('SentryNode initialization', () => {
test('sets SDK info globally', () => {
// the SDK data is set when we import from (and therefore run) `../src/index.ts`, so no action is necessary here
// before we run the `expect`s

expect(global.__SENTRY__.sdkInfo).toBeDefined();
expect(global.__SENTRY__.sdkInfo.name).toEqual('sentry.javascript.node');
expect(global.__SENTRY__.sdkInfo.version).toEqual(SDK_VERSION);
expect(global.__SENTRY__.sdkInfo.packages).toEqual([{ name: 'npm:@sentry/node', version: SDK_VERSION }]);
});

test('global.SENTRY_RELEASE is used to set release on initialization if available', () => {
global.SENTRY_RELEASE = { id: 'foobar' };
init({ dsn });
Expand Down
3 changes: 3 additions & 0 deletions packages/react/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
import { addGlobalEventProcessor, SDK_VERSION } from '@sentry/browser';
import { setSDKInfo } from '@sentry/utils';

setSDKInfo('sentry.javascript.react', 'npm:@sentry/react', SDK_VERSION);

/**
* A global side effect that makes sure Sentry events that user
Expand Down
23 changes: 23 additions & 0 deletions packages/react/test/init.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { getGlobalObject } from '@sentry/utils';

import * as Sentry from '../src/index';

const global = getGlobalObject<Window>();

describe('event SDK info', () => {
it('adds SDK metadata globally', () => {
// the SDK data is set when we import from (and therefore run) `../src/index.ts` - it sets the react part itself,
// and the browser part gets set when it imports from @sentry/browser - so no action is necessary here before we run
// the `expect`s

expect(global.__SENTRY__?.sdkInfo).toBeDefined();
expect(global.__SENTRY__?.sdkInfo?.name).toEqual('sentry.javascript.react');
expect(global.__SENTRY__?.sdkInfo?.version).toEqual(Sentry.SDK_VERSION);
expect(global.__SENTRY__?.sdkInfo?.packages).toEqual(
expect.arrayContaining([
{ name: 'npm:@sentry/react', version: Sentry.SDK_VERSION },
{ name: 'npm:@sentry/browser', version: Sentry.SDK_VERSION },
]),
);
});
});
5 changes: 5 additions & 0 deletions packages/serverless/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,8 @@ export { AWSLambda, GCPFunction };

export * from './awsservices';
export * from '@sentry/node';

import { SDK_VERSION } from '@sentry/node';
import { setSDKInfo } from '@sentry/utils';

setSDKInfo('sentry.javascript.serverless', 'npm:@sentry/serverless', SDK_VERSION);
2 changes: 1 addition & 1 deletion packages/serverless/test/__mocks__/@sentry/node.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
const origSentry = jest.requireActual('@sentry/node');
export const defaultIntegrations = origSentry.defaultIntegrations; // eslint-disable-line @typescript-eslint/no-unsafe-member-access
export const Handlers = origSentry.Handlers; // eslint-disable-line @typescript-eslint/no-unsafe-member-access
export const SDK_VERSION = '6.6.6';
export const SDK_VERSION = origSentry.SDK_VERSION; // eslint-disable-line @typescript-eslint/no-unsafe-member-access
export const Severity = {
Warning: 'warning',
};
Expand Down
27 changes: 23 additions & 4 deletions packages/serverless/test/awslambda.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Event } from '@sentry/types';
import { getGlobalObject } from '@sentry/utils';
// NOTE: I have no idea how to fix this right now, and don't want to waste more time, as it builds just fine — Kamil
// eslint-disable-next-line import/no-unresolved
import { Callback, Handler } from 'aws-lambda';
Expand Down Expand Up @@ -341,6 +342,24 @@ describe('AWSLambda', () => {
});

describe('init()', () => {
it('sets SDK data globally', () => {
// the SDK data is set when we import from (and therefore run) `../src/index.ts` - it sets the serverless part itself,
// and the node part gets set when it imports from @sentry/node - so no action is necessary here before we run
// the `expect`s

const global = getGlobalObject();

expect(global.__SENTRY__?.sdkInfo).toBeDefined();
expect(global.__SENTRY__?.sdkInfo?.name).toEqual('sentry.javascript.serverless');
expect(global.__SENTRY__?.sdkInfo?.version).toEqual(Sentry.SDK_VERSION);
expect(global.__SENTRY__?.sdkInfo?.packages).toEqual(
expect.arrayContaining([
{ name: 'npm:@sentry/serverless', version: Sentry.SDK_VERSION },
{ name: 'npm:@sentry/node', version: Sentry.SDK_VERSION },
]),
);
});

test('enhance event with SDK info and correct mechanism value', async () => {
expect.assertions(1);

Expand Down Expand Up @@ -381,10 +400,10 @@ describe('AWSLambda', () => {
},
{
name: 'npm:@sentry/serverless',
version: '6.6.6',
version: Sentry.SDK_VERSION,
},
],
version: '6.6.6',
version: Sentry.SDK_VERSION,
},
});
});
Expand Down Expand Up @@ -416,10 +435,10 @@ describe('AWSLambda', () => {
packages: [
{
name: 'npm:@sentry/serverless',
version: '6.6.6',
version: Sentry.SDK_VERSION,
},
],
version: '6.6.6',
version: Sentry.SDK_VERSION,
},
});
});
Expand Down
Loading