Skip to content
Draft
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
18 changes: 18 additions & 0 deletions libs/shared/monitoring/.eslintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"extends": ["../../../.eslintrc.json"],
"ignorePatterns": ["!**/*"],
"overrides": [
{
"files": ["*.ts", "*.tsx", "*.js", "*.jsx"],
"rules": {}
},
{
"files": ["*.ts", "*.tsx"],
"rules": {}
},
{
"files": ["*.js", "*.jsx"],
"rules": {}
}
]
}
14 changes: 14 additions & 0 deletions libs/shared/monitoring/.swcrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"jsc": {
"target": "es2017",
"parser": {
"syntax": "typescript",
"decorators": true,
"dynamicImport": true
},
"transform": {
"decoratorMetadata": true,
"legacyDecorator": true
}
}
}
28 changes: 28 additions & 0 deletions libs/shared/monitoring/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# shared-monitoring

This library provides monitoring functionality including error tracking with Sentry and distributed tracing.

It exports the `initMonitoring` function which initializes both error monitoring (Sentry) and performance monitoring (tracing) for server applications.

## Usage

```typescript
import { initMonitoring } from '@fxa/shared/monitoring';

initMonitoring({
log: logger,
config: {
tracing: {
/* tracing config */
},
sentry: {
/* sentry config */
},
},
});
```

## Exported APIs

- `initMonitoring(opts: MonitoringConfig)` - Initialize monitoring components
- `MonitoringConfig` - Type definition for monitoring configuration
42 changes: 42 additions & 0 deletions libs/shared/monitoring/jest.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { Config } from 'jest';
/* eslint-disable */
import { readFileSync } from 'fs';

// Reading the SWC compilation config and remove the "exclude"
// for the test files to be compiled by SWC
const { exclude: _, ...swcJestConfig } = JSON.parse(
readFileSync(`${__dirname}/.swcrc`, 'utf-8')
);

// disable .swcrc look-up by SWC core because we're passing in swcJestConfig ourselves.
// If we do not disable this, SWC Core will read .swcrc and won't transform our test files due to "exclude"
if (swcJestConfig.swcrc === undefined) {
swcJestConfig.swcrc = false;
}

// Uncomment if using global setup/teardown files being transformed via swc
// https://nx.dev/packages/jest/documents/overview#global-setup/teardown-with-nx-libraries
// jest needs EsModule Interop to find the default exported setup/teardown functions
// swcJestConfig.module.noInterop = false;

const config: Config = {
displayName: 'shared-monitoring',
preset: '../../../jest.preset.js',
transform: {
'^.+\\.[tj]s$': ['@swc/jest', swcJestConfig],
},
moduleFileExtensions: ['ts', 'js', 'html'],
testEnvironment: 'node',
coverageDirectory: '../../../coverage/libs/shared/monitoring',
reporters: [
'default',
[
'jest-junit',
{
outputDirectory: 'artifacts/tests/shared-monitoring',
outputName: 'shared-monitoring-jest-unit-results.xml',
},
],
],
};
export default config;
4 changes: 4 additions & 0 deletions libs/shared/monitoring/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"name": "@fxa/shared/monitoring",
"version": "0.0.0"
}
56 changes: 56 additions & 0 deletions libs/shared/monitoring/project.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
{
"name": "shared-monitoring",
"$schema": "../../../node_modules/nx/schemas/project-schema.json",
"sourceRoot": "libs/shared/monitoring/src",
"projectType": "library",
"tags": ["scope:shared:lib"],
"targets": {
"build": {
"executor": "@nx/esbuild:esbuild",
"outputs": ["{options.outputPath}"],
"defaultConfiguration": "production",
"options": {
"main": "libs/shared/monitoring/src/index.ts",
"outputPath": "dist/libs/shared/monitoring",
"outputFileName": "main.js",
"tsConfig": "libs/shared/monitoring/tsconfig.lib.json",
"declaration": true,
"external": [
"@nestjs/websockets/socket-module",
"@nestjs/microservices/microservices-module",
"@nestjs/microservices"
],
"assets": [
{
"glob": "libs/shared/monitoring/README.md",
"input": ".",
"output": "."
}
],
"platform": "node"
},
"configurations": {
"development": {
"minify": false
},
"production": {
"minify": true
}
}
},
"lint": {
"executor": "@nx/eslint:lint",
"outputs": ["{options.outputFile}"],
"options": {
"lintFilePatterns": ["libs/shared/monitoring/**/*.ts"]
}
},
"test-unit": {
"executor": "@nx/jest:jest",
"outputs": ["{workspaceRoot}/coverage/{projectRoot}"],
"options": {
"jestConfig": "libs/shared/monitoring/jest.config.ts"
}
}
}
}
95 changes: 95 additions & 0 deletions libs/shared/monitoring/src/index.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */

import { initTracing } from '@fxa/shared/otel';
import { initSentry } from '@fxa/shared/sentry-node';
import { initMonitoring } from './index';

jest.mock('@fxa/shared/otel', () => ({ initTracing: jest.fn() }));
jest.mock('@fxa/shared/sentry-node', () => ({ initSentry: jest.fn() }));

describe('shared-monitoring', () => {
beforeEach(() => {
jest.resetAllMocks();
jest.resetModules();
});

it('initializes tracing and sentry when config contains them', () => {
const log = {
info: jest.fn(),
warn: jest.fn(),
error: jest.fn(),
debug: jest.fn(),
};
const opts = {
log,
config: {
sentry: { dsn: 'https://example.com' },
tracing: {
enabled: true,
serviceName: 'test',
batchSpanProcessor: true,
clientName: 'test-client',
corsUrls: 'http://localhost:\\d*/',
filterPii: true,
sampleRate: 1,
batchProcessor: false,
},
},
};

initMonitoring(opts);

expect(initTracing).toHaveBeenCalledWith(opts.config.tracing, log);
expect(initSentry).toHaveBeenCalledWith(opts.config, log);
});

it('does not call tracing or sentry when not configured', () => {
const log = {
warn: jest.fn(),
error: jest.fn(),
info: jest.fn(),
debug: jest.fn(),
};
const opts = { log, config: {} };

initMonitoring(opts);

expect(initTracing).not.toHaveBeenCalled();
expect(initSentry).not.toHaveBeenCalled();
});

it('warns and skips when initialized more than once', () => {
const log = {
warn: jest.fn(),
error: jest.fn(),
info: jest.fn(),
debug: jest.fn(),
};
const opts = {
log,
config: {
sentry: { dsn: 'https://example.com' },
tracing: {
enabled: true,
serviceName: 'test',
batchSpanProcessor: true,
clientName: 'test-client',
corsUrls: 'http://localhost:\\d*/',
filterPii: true,
sampleRate: 1,
batchProcessor: false,
},
},
};

initMonitoring(opts);
initMonitoring(opts);

expect(log.warn).toHaveBeenCalledWith(
'monitoring',
'Monitoring can only be initialized once'
);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,20 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */

import { initTracing } from '../tracing/node-tracing';
import { InitSentryOpts, initSentry } from '../sentry/node';
import { TracingOpts } from '../tracing/config';
import { ILogger } from '../log';
import { initTracing } from '@fxa/shared/otel';
import { initSentry } from '@fxa/shared/sentry-node';
import { TracingOpts } from '@fxa/shared/otel';
import { ILogger } from '@fxa/shared/log';
import { InitSentryOpts } from '@fxa/shared/sentry-utils';

export type MonitoringConfig = {
log?: ILogger;
config: InitSentryOpts & { tracing: TracingOpts };
config: InitSentryOpts & { tracing?: TracingOpts };
};

let initialized = false;

// IMPORTANT! This initialization function must be called first thing when a server starts.If it's called after server
// IMPORTANT! This initialization function must be called first thing when a server starts. If it's called after server
// frameworks initialized instrumentation might not work properly.
/**
* Initializes modules related to error monitoring, performance monitoring, and tracing.
Expand Down
16 changes: 16 additions & 0 deletions libs/shared/monitoring/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"extends": "../../../tsconfig.base.json",
"compilerOptions": {
"module": "commonjs"
},
"files": [],
"include": [],
"references": [
{
"path": "./tsconfig.lib.json"
},
{
"path": "./tsconfig.spec.json"
}
]
}
11 changes: 11 additions & 0 deletions libs/shared/monitoring/tsconfig.lib.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"module": "commonjs",
"outDir": "../../../dist/out-tsc",
"declaration": true,
"types": ["node"]
},
"exclude": ["jest.config.ts", "src/**/*.spec.ts", "src/**/*.test.ts"],
"include": ["src/**/*.ts"]
}
14 changes: 14 additions & 0 deletions libs/shared/monitoring/tsconfig.spec.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "../../../dist/out-tsc",
"module": "commonjs",
"types": ["jest", "node"]
},
"include": [
"jest.config.ts",
"src/**/*.test.ts",
"src/**/*.spec.ts",
"src/**/*.d.ts"
]
}
24 changes: 20 additions & 4 deletions libs/shared/otel/project.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,30 @@
"build": {
"executor": "@nx/esbuild:esbuild",
"outputs": ["{options.outputPath}"],
"defaultConfiguration": "production",
"options": {
"outputPath": "dist/libs/shared/otel",
"main": "libs/shared/otel/src/index.ts",
"outputPath": "dist/libs/shared/otel",
"outputFileName": "main.js",
"tsConfig": "libs/shared/otel/tsconfig.lib.json",
"assets": ["libs/shared/otel/*.md"],
"generatePackageJson": true,
"declaration": true,
"platform": "node"
"assets": [
{
"glob": "libs/shared/otel/README.md",
"input": ".",
"output": "."
}
],
"platform": "node",
"format": ["cjs", "esm"]
},
"configurations": {
"development": {
"minify": false
},
"production": {
"minify": true
}
}
},
"test-unit": {
Expand Down
1 change: 1 addition & 0 deletions libs/shared/sentry-browser/src/lib/browser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ export function captureException(err: Error) {
);
}
});

Sentry.captureException(err);
});
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,12 @@ export type SentryConfigOpts = {

/** The tracing sample rate. Setting this above 0 will aso result in performance metrics being captured. */
tracesSampleRate?: number;

/** A function that determines the sample rate for a given event. Setting this will override tracesSampleRate. */
tracesSampler?: (context: { name?: string }) => number;

/** A list of errors to ignore. Can be strings, regexes, or functions that take an error and return a boolean. */
ignoreErrors?: Array<string | RegExp>;
};
};

Expand Down
Loading