Skip to content
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

docs: performance tracing #111

Merged
merged 3 commits into from
Nov 7, 2024
Merged
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
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,14 @@ This is a living repository — nothing is set in stone! If you're member of Met
- [Contributor Code of Conduct](https://github.com/MetaMask/.github/blob/main/CODE_OF_CONDUCT.md)
- [Engineering Principles](./docs/engineering-principles.md)
- [JavaScript Guidelines](./docs/javascript.md)
- [Performance Tracing Guidelines](./docs/performance-tracing.md)
- [Pull Requests Guide](./docs/pull-requests.md)
- [React Guidelines](./docs/react.md)
- [Secure Coding Guidelines](./docs/secure-coding-guidelines.md)
- [Redux Guidelines](./docs/redux.md)
- [Secure Coding Guidelines](./docs/secure-coding-guidelines.md)
- [Secure Development Lifecycle Policy](./docs/sdlc.md)
- [TypeScript Guidelines](./docs/typescript.md)
- [Testing Guidelines](./docs/testing/overview.md)
- [Unit Testing Guidelines](./docs/testing/unit-testing.md)
- [UI Integration Testing Guidelines](./docs/testing/ui-integration-testing.md)
- [E2E Testing Guidelines](./docs/testing/e2e-testing.md)
- [TypeScript Guidelines](./docs/typescript.md)
228 changes: 228 additions & 0 deletions docs/performance-tracing.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,228 @@
# Performance Tracing

## Overview

Performance tracing within MetaMask is the act of tracking the durations of user flows and code execution.

This can be debugged locally via developer builds, but also occurs in user production builds.

The resulting data is uploaded to Sentry where it can be aggregated, analysed, and trigger alerts to notify us of reduced performance.

### Automated Tracing

Automated tracing is provided by the `@sentry/browser` and `@sentry/react-native` packages.

They include the following integrations based on platform:

- [BrowserTracing](https://docs.sentry.io/platforms/javascript/configuration/integrations/browsertracing/)
- [ReactNativeTracing](https://docs.sentry.io/platforms/react-native/tracing/instrumentation/automatic-instrumentation/)

With no additional code, these automatically record the durations of operations such as:

- Browser Page Loads
- HTTP Callouts
- React Routing

### Custom Tracing

Custom tracing is when we manually update the code to invoke specific utility functions to record durations as we see fit to align with conceptual user flows such as:

- Ethereum Transaction Processing
- Signature Request Processing

Or alternatively to track more technical code stages such as:

- UI Initialisation

### Utilities

The [trace utilities](https://github.com/MetaMask/metamask-extension/blob/develop/shared/lib/trace.ts) provide an abstraction of the respective Sentry package to create Sentry transactions with minimum syntax, but maximum simplicity to support features such as:

- Tags
- Nested Traces
- Custom Timestamps

#### Trace Names

The `TraceName` enum provides a central definition of all traces in use within the MetaMask client.

It also simplifies the creation of traces that are started and stopped from different locations in the code.

### Examples

#### Trace the duration of a function.

```ts
import { trace, TraceName } from '...';

function someFunction() {
return 1 + 1;
}

function someOtherFunction() {
...

const value = trace(
{ name: TraceName.SomeTrace },
someFunction
);

...
}
```

#### Trace the duration of an asynchronous function.

The `trace` function automatically handles promises and records the duration until the promise is resolved or rejected.

```ts
import { trace, TraceName } from '...';

async function someFunction() {
return new Promise(resolve => {
...
resolve();
});
}

async function someOtherFunction() {
...

const value = await trace(
{ name: TraceName.SomeTrace },
someFunction
);

...
}
```

#### Trace the duration of a flow spanning multiple files.

```ts
// File1.ts

import { trace, TraceName } from '...';

function someFunction() {
...

trace({ name: TraceName.SomeTrace });

...
}

// File2.ts

import { endTrace, TraceName } from '...';

function someOtherFunction() {
...

endTrace({ name: TraceName.SomeTrace });

...
}
```

#### Generate a nested trace.

Nested traces are reflected in Sentry and allow the breakdown of a larger duration into smaller named durations.

```ts
import { trace, TraceName } from '...';

function someNestedFunction1() {
return 1 + 1;
}

function someNestedFunction2() {
return 2 + 2;
}

function someParentFunction(traceContext: TraceContext) {
...

const value1 = trace(
{
name: TraceName.SomeNestedTrace1,
parentContext: traceContext
},
someNestedFunction1
);

const value2 = trace(
{
name: TraceName.SomeNestedTrace2,
parentContext: traceContext
},
someNestedFunction2
);

...
}

function someOtherFunction() {
...

trace(
{ name: TraceName.ParentTrace },
(traceContext) => someParentFunction(traceContext)
);

...
}

```

#### Include tags in a trace.

```ts
import { trace, TraceName } from '...';

function someFunction() {
return 1 + 1;
}

function someOtherFunction() {
...

const value = trace(
{
name: TraceName.SomeTrace
tags: {
someBoolean: true,
someString: 'test',
// Number tags are converted to Sentry measurements
// to support search operations such as >= and <=.
someNumber: 123
}
},
someFunction
);

...
}
```

#### Use manual timestamps in a trace.

```ts
import { trace, endTrace, TraceName } from '...';

...

trace({
name: TraceName.SomeTrace,
startTime: Date.now() - 123
});

...

endTrace({
name: TraceName.SomeTrace,
timestamp: Date.now() + 456
});

...
```
Loading