Skip to content

Commit

Permalink
docs: performance tracing (#111)
Browse files Browse the repository at this point in the history
Add performance tracing documentation, including custom trace exampes.
  • Loading branch information
matthewwalsh0 authored Nov 7, 2024
1 parent dd3c581 commit be44a89
Show file tree
Hide file tree
Showing 2 changed files with 231 additions and 2 deletions.
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
});

...
```

0 comments on commit be44a89

Please sign in to comment.