Skip to content

Commit efe9436

Browse files
committed
polish(shared): Move fxa-shared/monitoring to libs
1 parent a413f76 commit efe9436

12 files changed

Lines changed: 337 additions & 0 deletions

File tree

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
{
2+
"extends": ["../../../.eslintrc.json"],
3+
"ignorePatterns": ["!**/*"],
4+
"overrides": [
5+
{
6+
"files": ["*.ts", "*.tsx", "*.js", "*.jsx"],
7+
"rules": {}
8+
},
9+
{
10+
"files": ["*.ts", "*.tsx"],
11+
"rules": {}
12+
},
13+
{
14+
"files": ["*.js", "*.jsx"],
15+
"rules": {}
16+
}
17+
]
18+
}

libs/shared/monitoring/.swcrc

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
{
2+
"jsc": {
3+
"target": "es2017",
4+
"parser": {
5+
"syntax": "typescript",
6+
"decorators": true,
7+
"dynamicImport": true
8+
},
9+
"transform": {
10+
"decoratorMetadata": true,
11+
"legacyDecorator": true
12+
}
13+
}
14+
}

libs/shared/monitoring/README.md

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# shared-monitoring
2+
3+
This library provides monitoring functionality including error tracking with Sentry and distributed tracing.
4+
5+
It exports the `initMonitoring` function which initializes both error monitoring (Sentry) and performance monitoring (tracing) for server applications.
6+
7+
## Usage
8+
9+
```typescript
10+
import { initMonitoring } from '@fxa/shared/monitoring';
11+
12+
initMonitoring({
13+
log: logger,
14+
config: {
15+
tracing: {
16+
/* tracing config */
17+
},
18+
sentry: {
19+
/* sentry config */
20+
},
21+
},
22+
});
23+
```
24+
25+
## Exported APIs
26+
27+
- `initMonitoring(opts: MonitoringConfig)` - Initialize monitoring components
28+
- `MonitoringConfig` - Type definition for monitoring configuration
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import { Config } from 'jest';
2+
/* eslint-disable */
3+
import { readFileSync } from 'fs';
4+
5+
// Reading the SWC compilation config and remove the "exclude"
6+
// for the test files to be compiled by SWC
7+
const { exclude: _, ...swcJestConfig } = JSON.parse(
8+
readFileSync(`${__dirname}/.swcrc`, 'utf-8')
9+
);
10+
11+
// disable .swcrc look-up by SWC core because we're passing in swcJestConfig ourselves.
12+
// If we do not disable this, SWC Core will read .swcrc and won't transform our test files due to "exclude"
13+
if (swcJestConfig.swcrc === undefined) {
14+
swcJestConfig.swcrc = false;
15+
}
16+
17+
// Uncomment if using global setup/teardown files being transformed via swc
18+
// https://nx.dev/packages/jest/documents/overview#global-setup/teardown-with-nx-libraries
19+
// jest needs EsModule Interop to find the default exported setup/teardown functions
20+
// swcJestConfig.module.noInterop = false;
21+
22+
const config: Config = {
23+
displayName: 'shared-monitoring',
24+
preset: '../../../jest.preset.js',
25+
transform: {
26+
'^.+\\.[tj]s$': ['@swc/jest', swcJestConfig],
27+
},
28+
moduleFileExtensions: ['ts', 'js', 'html'],
29+
testEnvironment: 'node',
30+
coverageDirectory: '../../../coverage/libs/shared/monitoring',
31+
reporters: [
32+
'default',
33+
[
34+
'jest-junit',
35+
{
36+
outputDirectory: 'artifacts/tests/shared-monitoring',
37+
outputName: 'shared-monitoring-jest-unit-results.xml',
38+
},
39+
],
40+
],
41+
};
42+
export default config;
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"name": "@fxa/shared/monitoring",
3+
"version": "0.0.0"
4+
}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
{
2+
"name": "shared-monitoring",
3+
"$schema": "../../../node_modules/nx/schemas/project-schema.json",
4+
"sourceRoot": "libs/shared/monitoring/src",
5+
"projectType": "library",
6+
"tags": ["scope:shared:lib"],
7+
"targets": {
8+
"build": {
9+
"executor": "@nx/esbuild:esbuild",
10+
"outputs": ["{options.outputPath}"],
11+
"defaultConfiguration": "production",
12+
"options": {
13+
"main": "libs/shared/monitoring/src/index.ts",
14+
"outputPath": "dist/libs/shared/monitoring",
15+
"outputFileName": "main.js",
16+
"tsConfig": "libs/shared/monitoring/tsconfig.lib.json",
17+
"declaration": true,
18+
"external": [
19+
"@nestjs/websockets/socket-module",
20+
"@nestjs/microservices/microservices-module",
21+
"@nestjs/microservices"
22+
],
23+
"assets": [
24+
{
25+
"glob": "libs/shared/monitoring/README.md",
26+
"input": ".",
27+
"output": "."
28+
}
29+
],
30+
"platform": "node"
31+
},
32+
"configurations": {
33+
"development": {
34+
"minify": false
35+
},
36+
"production": {
37+
"minify": true
38+
}
39+
}
40+
},
41+
"lint": {
42+
"executor": "@nx/eslint:lint",
43+
"outputs": ["{options.outputFile}"],
44+
"options": {
45+
"lintFilePatterns": ["libs/shared/monitoring/**/*.ts"]
46+
}
47+
},
48+
"test-unit": {
49+
"executor": "@nx/jest:jest",
50+
"outputs": ["{workspaceRoot}/coverage/{projectRoot}"],
51+
"options": {
52+
"jestConfig": "libs/shared/monitoring/jest.config.ts"
53+
}
54+
}
55+
}
56+
}
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
/* This Source Code Form is subject to the terms of the Mozilla Public
2+
* License, v. 2.0. If a copy of the MPL was not distributed with this
3+
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4+
5+
import { initTracing } from '@fxa/shared/otel';
6+
import { initSentry } from '@fxa/shared/sentry-node';
7+
import { initMonitoring } from './index';
8+
9+
jest.mock('@fxa/shared/otel', () => ({ initTracing: jest.fn() }));
10+
jest.mock('@fxa/shared/sentry-node', () => ({ initSentry: jest.fn() }));
11+
12+
describe('shared-monitoring', () => {
13+
beforeEach(() => {
14+
jest.resetAllMocks();
15+
jest.resetModules();
16+
});
17+
18+
it('initializes tracing and sentry when config contains them', () => {
19+
const log = {
20+
info: jest.fn(),
21+
warn: jest.fn(),
22+
error: jest.fn(),
23+
debug: jest.fn(),
24+
};
25+
const opts = {
26+
log,
27+
config: {
28+
sentry: { dsn: 'https://example.com' },
29+
tracing: {
30+
enabled: true,
31+
serviceName: 'test',
32+
batchSpanProcessor: true,
33+
clientName: 'test-client',
34+
corsUrls: 'http://localhost:\\d*/',
35+
filterPii: true,
36+
sampleRate: 1,
37+
batchProcessor: false,
38+
},
39+
},
40+
};
41+
42+
initMonitoring(opts);
43+
44+
expect(initTracing).toHaveBeenCalledWith(opts.config.tracing, log);
45+
expect(initSentry).toHaveBeenCalledWith(opts.config, log);
46+
});
47+
48+
it('does not call tracing or sentry when not configured', () => {
49+
const log = {
50+
warn: jest.fn(),
51+
error: jest.fn(),
52+
info: jest.fn(),
53+
debug: jest.fn(),
54+
};
55+
const opts = { log, config: {} };
56+
57+
initMonitoring(opts);
58+
59+
expect(initTracing).not.toHaveBeenCalled();
60+
expect(initSentry).not.toHaveBeenCalled();
61+
});
62+
63+
it('warns and skips when initialized more than once', () => {
64+
const log = {
65+
warn: jest.fn(),
66+
error: jest.fn(),
67+
info: jest.fn(),
68+
debug: jest.fn(),
69+
};
70+
const opts = {
71+
log,
72+
config: {
73+
sentry: { dsn: 'https://example.com' },
74+
tracing: {
75+
enabled: true,
76+
serviceName: 'test',
77+
batchSpanProcessor: true,
78+
clientName: 'test-client',
79+
corsUrls: 'http://localhost:\\d*/',
80+
filterPii: true,
81+
sampleRate: 1,
82+
batchProcessor: false,
83+
},
84+
},
85+
};
86+
87+
initMonitoring(opts);
88+
initMonitoring(opts);
89+
90+
expect(log.warn).toHaveBeenCalledWith(
91+
'monitoring',
92+
'Monitoring can only be initialized once'
93+
);
94+
});
95+
});
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
/* This Source Code Form is subject to the terms of the Mozilla Public
2+
* License, v. 2.0. If a copy of the MPL was not distributed with this
3+
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4+
5+
import { initTracing } from '@fxa/shared/otel';
6+
import { initSentry } from '@fxa/shared/sentry-node';
7+
import { TracingOpts } from '@fxa/shared/otel';
8+
import { ILogger } from '@fxa/shared/log';
9+
import { InitSentryOpts } from '@fxa/shared/sentry-utils';
10+
11+
export type MonitoringConfig = {
12+
log?: ILogger;
13+
config: InitSentryOpts & { tracing?: TracingOpts };
14+
};
15+
16+
let initialized = false;
17+
18+
// IMPORTANT! This initialization function must be called first thing when a server starts. If it's called after server
19+
// frameworks initialized instrumentation might not work properly.
20+
/**
21+
* Initializes modules related to error monitoring, performance monitoring, and tracing.
22+
* @param opts - Initialization options. See underlying implementations for more details.
23+
*/
24+
export function initMonitoring(opts: MonitoringConfig) {
25+
const { log, config } = opts;
26+
if (initialized) {
27+
opts.log?.warn('monitoring', 'Monitoring can only be initialized once');
28+
return;
29+
}
30+
initialized = true;
31+
32+
if (config.tracing) {
33+
initTracing(config.tracing, log || console);
34+
}
35+
if (config && config.sentry) {
36+
initSentry(config, log || console);
37+
}
38+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
{
2+
"extends": "../../../tsconfig.base.json",
3+
"compilerOptions": {
4+
"module": "commonjs"
5+
},
6+
"files": [],
7+
"include": [],
8+
"references": [
9+
{
10+
"path": "./tsconfig.lib.json"
11+
},
12+
{
13+
"path": "./tsconfig.spec.json"
14+
}
15+
]
16+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"extends": "./tsconfig.json",
3+
"compilerOptions": {
4+
"module": "commonjs",
5+
"outDir": "../../../dist/out-tsc",
6+
"declaration": true,
7+
"types": ["node"]
8+
},
9+
"exclude": ["jest.config.ts", "src/**/*.spec.ts", "src/**/*.test.ts"],
10+
"include": ["src/**/*.ts"]
11+
}

0 commit comments

Comments
 (0)