Skip to content

Commit

Permalink
feat: Add @sentry/tracing
Browse files Browse the repository at this point in the history
  • Loading branch information
AbhiPrasad committed Jul 3, 2020
1 parent 30e710d commit 14eba60
Show file tree
Hide file tree
Showing 21 changed files with 2,795 additions and 0 deletions.
4 changes: 4 additions & 0 deletions packages/tracing/apm/.npmignore
@@ -0,0 +1,4 @@
*
!/dist/**/*
!/esm/**/*
*.tsbuildinfo
22 changes: 22 additions & 0 deletions packages/tracing/apm/README.md
@@ -0,0 +1,22 @@
<p align="center">
<a href="https://sentry.io" target="_blank" align="center">
<img src="https://sentry-brand.storage.googleapis.com/sentry-logo-black.png" width="280">
</a>
<br />
</p>

# Sentry Tracing Extensions

[![npm version](https://img.shields.io/npm/v/@sentry/tracing.svg)](https://www.npmjs.com/package/@sentry/tracing)
[![npm dm](https://img.shields.io/npm/dm/@sentry/tracing.svg)](https://www.npmjs.com/package/@sentry/tracing)
[![npm dt](https://img.shields.io/npm/dt/@sentry/tracing.svg)](https://www.npmjs.com/package/@sentry/tracing)
[![typedoc](https://img.shields.io/badge/docs-typedoc-blue.svg)](http://getsentry.github.io/sentry-javascript/)

## Links

- [Official SDK Docs](https://docs.sentry.io/quickstart/)
- [TypeDoc](http://getsentry.github.io/sentry-javascript/)

## General

This package contains extensions to the `@sentry/hub` to enable Sentry AM related functionality. It also provides integrations for Browser and Node that provide a good experience out of the box.
84 changes: 84 additions & 0 deletions packages/tracing/apm/package.json
@@ -0,0 +1,84 @@
{
"name": "@sentry/tracing",
"version": "5.19.0",
"description": "Extensions for Sentry AM",
"repository": "git://github.com/getsentry/sentry-javascript.git",
"homepage": "https://github.com/getsentry/sentry-javascript/tree/master/packages/tracing",
"author": "Sentry",
"license": "BSD-3-Clause",
"engines": {
"node": ">=6"
},
"main": "dist/index.js",
"module": "esm/index.js",
"types": "dist/index.d.ts",
"publishConfig": {
"access": "public"
},
"dependencies": {
"@sentry/browser": "5.19.0",
"@sentry/hub": "5.19.0",
"@sentry/minimal": "5.19.0",
"@sentry/types": "5.19.0",
"@sentry/utils": "5.19.0",
"tslib": "^1.9.3"
},
"devDependencies": {
"@types/express": "^4.17.1",
"jest": "^24.7.1",
"npm-run-all": "^4.1.2",
"prettier": "^1.17.0",
"prettier-check": "^2.0.0",
"rimraf": "^2.6.3",
"rollup": "^1.10.1",
"rollup-plugin-commonjs": "^9.3.4",
"rollup-plugin-license": "^0.8.1",
"rollup-plugin-node-resolve": "^4.2.3",
"rollup-plugin-terser": "^4.0.4",
"rollup-plugin-typescript2": "^0.21.0",
"tslint": "^5.16.0",
"typescript": "^3.4.5"
},
"scripts": {
"build": "run-p build:es5 build:esm build:bundle",
"build:bundle": "rollup --config",
"build:bundle:watch": "rollup --config --watch",
"build:es5": "tsc -p tsconfig.build.json",
"build:esm": "tsc -p tsconfig.esm.json",
"build:watch": "run-p build:watch:es5 build:watch:esm",
"build:watch:es5": "tsc -p tsconfig.build.json -w --preserveWatchOutput",
"build:watch:esm": "tsc -p tsconfig.esm.json -w --preserveWatchOutput",
"clean": "rimraf dist coverage build esm",
"link:yarn": "yarn link",
"lint": "run-s lint:prettier lint:tslint",
"lint:prettier": "prettier-check \"{src,test}/**/*.ts\"",
"lint:tslint": "tslint -t stylish -p .",
"lint:tslint:json": "tslint --format json -p . | tee lint-results.json",
"fix": "run-s fix:tslint fix:prettier",
"fix:prettier": "prettier --write \"{src,test}/**/*.ts\"",
"fix:tslint": "tslint --fix -t stylish -p .",
"test": "jest",
"test:watch": "jest --watch"
},
"jest": {
"collectCoverage": true,
"transform": {
"^.+\\.ts$": "ts-jest"
},
"moduleFileExtensions": [
"js",
"ts"
],
"testEnvironment": "node",
"testMatch": [
"**/*.test.ts"
],
"globals": {
"ts-jest": {
"tsConfig": "./tsconfig.json",
"diagnostics": false
}
}
},
"sideEffects": false
}
93 changes: 93 additions & 0 deletions packages/tracing/apm/rollup.config.js
@@ -0,0 +1,93 @@
import { terser } from 'rollup-plugin-terser';
import typescript from 'rollup-plugin-typescript2';
import license from 'rollup-plugin-license';
import resolve from 'rollup-plugin-node-resolve';
import commonjs from 'rollup-plugin-commonjs';

const commitHash = require('child_process')
.execSync('git rev-parse --short HEAD', { encoding: 'utf-8' })
.trim();

const terserInstance = terser({
mangle: {
// captureExceptions and captureMessage are public API methods and they don't need to be listed here
// as mangler doesn't touch user-facing thing, however sentryWrapped is not, and it would be mangled into a minified version.
// We need those full names to correctly detect our internal frames for stripping.
// I listed all of them here just for the clarity sake, as they are all used in the frames manipulation process.
reserved: ['captureException', 'captureMessage', 'sentryWrapped'],
properties: {
regex: /^_[^_]/,
},
},
});

const paths = {
'@sentry/utils': ['../utils/src'],
'@sentry/core': ['../core/src'],
'@sentry/hub': ['../hub/src'],
'@sentry/types': ['../types/src'],
'@sentry/minimal': ['../minimal/src'],
};

const plugins = [
typescript({
tsconfig: 'tsconfig.build.json',
tsconfigOverride: {
compilerOptions: {
declaration: false,
declarationMap: false,
module: 'ES2015',
paths,
},
},
include: ['*.ts+(|x)', '**/*.ts+(|x)', '../**/*.ts+(|x)'],
}),
resolve({
mainFields: ['module'],
}),
commonjs(),
];

const bundleConfig = {
input: 'src/index.ts',
output: {
format: 'iife',
name: 'Sentry',
sourcemap: true,
strict: false,
},
context: 'window',
plugins: [
...plugins,
license({
sourcemap: true,
banner: `/*! @sentry/tracing & @sentry/browser <%= pkg.version %> (${commitHash}) | https://github.com/getsentry/sentry-javascript */`,
}),
],
};

export default [
// ES5 Browser Tracing Bundle
{
...bundleConfig,
input: 'src/index.bundle.ts',
output: {
...bundleConfig.output,
file: 'build/bundle.tracing.js',
},
plugins: bundleConfig.plugins,
},
{
...bundleConfig,
input: 'src/index.bundle.ts',
output: {
...bundleConfig.output,
file: 'build/bundle.tracing.min.js',
},
// Uglify has to be at the end of compilation, BUT before the license banner
plugins: bundleConfig.plugins
.slice(0, -1)
.concat(terserInstance)
.concat(bundleConfig.plugins.slice(-1)),
},
];
103 changes: 103 additions & 0 deletions packages/tracing/apm/src/hubextensions.ts
@@ -0,0 +1,103 @@
import { getMainCarrier, Hub } from '@sentry/hub';
import { SpanContext, TransactionContext } from '@sentry/types';
import { logger } from '@sentry/utils';

import { Span } from './span';
import { Transaction } from './transaction';

/** Returns all trace headers that are currently on the top scope. */
function traceHeaders(this: Hub): { [key: string]: string } {
const scope = this.getScope();
if (scope) {
const span = scope.getSpan();
if (span) {
return {
'sentry-trace': span.toTraceparent(),
};
}
}
return {};
}

/**
* {@see Hub.startTransaction}
*/
function startTransaction(this: Hub, context: TransactionContext): Transaction {
const transaction = new Transaction(context, this);

const client = this.getClient();
// Roll the dice for sampling transaction, all child spans inherit the sampling decision.
if (transaction.sampled === undefined) {
const sampleRate = (client && client.getOptions().tracesSampleRate) || 0;
// if true = we want to have the transaction
// if false = we don't want to have it
// Math.random (inclusive of 0, but not 1)
transaction.sampled = Math.random() < sampleRate;
}

// We only want to create a span list if we sampled the transaction
// If sampled == false, we will discard the span anyway, so we can save memory by not storing child spans
if (transaction.sampled) {
const experimentsOptions = (client && client.getOptions()._experiments) || {};
transaction.initSpanRecorder(experimentsOptions.maxSpans as number);
}

return transaction;
}

/**
* {@see Hub.startSpan}
*/
function startSpan(this: Hub, context: SpanContext): Transaction | Span {
/**
* @deprecated
* TODO: consider removing this in a future release.
*
* This is for backwards compatibility with releases before startTransaction
* existed, to allow for a smoother transition.
*/
{
// The `TransactionContext.name` field used to be called `transaction`.
const transactionContext = context as Partial<TransactionContext & { transaction: string }>;
if (transactionContext.transaction !== undefined) {
transactionContext.name = transactionContext.transaction;
}
// Check for not undefined since we defined it's ok to start a transaction
// with an empty name.
if (transactionContext.name !== undefined) {
logger.warn('Deprecated: Use startTransaction to start transactions and Transaction.startChild to start spans.');
return this.startTransaction(transactionContext as TransactionContext);
}
}

const scope = this.getScope();
if (scope) {
// If there is a Span on the Scope we start a child and return that instead
const parentSpan = scope.getSpan();
if (parentSpan) {
return parentSpan.startChild(context);
}
}

// Otherwise we return a new Span
return new Span(context);
}

/**
* This patches the global object and injects the Tracing extensions methods
*/
export function addExtensionMethods(): void {
const carrier = getMainCarrier();
if (carrier.__SENTRY__) {
carrier.__SENTRY__.extensions = carrier.__SENTRY__.extensions || {};
if (!carrier.__SENTRY__.extensions.startTransaction) {
carrier.__SENTRY__.extensions.startTransaction = startTransaction;
}
if (!carrier.__SENTRY__.extensions.startSpan) {
carrier.__SENTRY__.extensions.startSpan = startSpan;
}
if (!carrier.__SENTRY__.extensions.traceHeaders) {
carrier.__SENTRY__.extensions.traceHeaders = traceHeaders;
}
}
}
79 changes: 79 additions & 0 deletions packages/tracing/apm/src/index.bundle.ts
@@ -0,0 +1,79 @@
export {
Breadcrumb,
Request,
SdkInfo,
Event,
Exception,
Response,
Severity,
StackFrame,
Stacktrace,
Status,
Thread,
User,
} from '@sentry/types';

export {
addGlobalEventProcessor,
addBreadcrumb,
captureException,
captureEvent,
captureMessage,
configureScope,
getHubFromCarrier,
getCurrentHub,
Hub,
Scope,
setContext,
setExtra,
setExtras,
setTag,
setTags,
setUser,
Transports,
withScope,
} from '@sentry/browser';

export { BrowserOptions } from '@sentry/browser';
export { BrowserClient, ReportDialogOptions } from '@sentry/browser';
export {
defaultIntegrations,
forceLoad,
init,
lastEventId,
onLoad,
showReportDialog,
flush,
close,
wrap,
} from '@sentry/browser';
export { SDK_NAME, SDK_VERSION } from '@sentry/browser';

import { Integrations as BrowserIntegrations } from '@sentry/browser';
import { getGlobalObject } from '@sentry/utils';

import { addExtensionMethods } from './hubextensions';
import * as ApmIntegrations from './integrations';

export { Span, TRACEPARENT_REGEXP } from './span';

let windowIntegrations = {};

// This block is needed to add compatibility with the integrations packages when used with a CDN
// tslint:disable: no-unsafe-any
const _window = getGlobalObject<Window>();
if (_window.Sentry && _window.Sentry.Integrations) {
windowIntegrations = _window.Sentry.Integrations;
}
// tslint:enable: no-unsafe-any

const INTEGRATIONS = {
...windowIntegrations,
...BrowserIntegrations,
Tracing: ApmIntegrations.Tracing,
};

export { INTEGRATIONS as Integrations };

// We are patching the global object with our hub extension methods
addExtensionMethods();

0 comments on commit 14eba60

Please sign in to comment.