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
}
}
}
34 changes: 34 additions & 0 deletions libs/shared/monitoring/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# 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.

## Installation

```bash
npm install @fxa/shared/monitoring
```

## 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"
}
51 changes: 51 additions & 0 deletions libs/shared/monitoring/project.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
{
"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,
"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"
}
}
}
}
63 changes: 63 additions & 0 deletions libs/shared/monitoring/src/index.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import { initTracing } from '@fxa/shared/otel';
import { initSentry } from '@fxa/sentry-node';
import { initMonitoring } from '@fxa/shared/monitoring';

jest.mock('@fxa/shared/otel', () => ({ initTracing: jest.fn() }));
jest.mock('@fxa/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' },
},
};

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() };
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() };
const opts = {
log,
config: {
sentry: { dsn: 'https://example.com' },
tracing: { enabled: true, serviceName: 'test' },
},
};

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,10 +2,10 @@
* 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 { InitSentryOpts, initSentry } from '@fxa/sentry-node';
import { TracingOpts } from '@fxa/shared/otel';
import { ILogger } from '@fxa/shared/log';

export type MonitoringConfig = {
log?: ILogger;
Expand All @@ -14,7 +14,7 @@ export type MonitoringConfig = {

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"
]
}
1 change: 1 addition & 0 deletions libs/shared/sentry-node/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export * from './lib/joi-message-overrides';
export * from './lib/node';
export * from './lib/report-validation-error';
export type { InitSentryOpts, Logger } from '@fxa/shared/sentry-utils';
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ export type SentryConfigOpts = {

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

/** The tracing sampler function. Allows dynamic sampling based on context. */
tracesSampler?: (context: any) => number;
};
};

Expand Down
3 changes: 3 additions & 0 deletions libs/shared/sentry/src/lib/models/SentryConfigOpts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@ export type SentryConfigOpts = {
/** The tracing sample rate. Setting this above 0 will aso result in performance metrics being captured. */
tracesSampleRate?: number;

/** The tracing sampler function. Allows dynamic sampling based on context. */
tracesSampler?: (context: any) => number;

/** Indicates if PII can be transeferred. e.g. Send the IP address. */
sendDefaultPii?: boolean;
};
Expand Down
2 changes: 1 addition & 1 deletion packages/fxa-admin-panel/server/lib/monitoring.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

import Config from '../config';
import mozLog from 'mozlog';
import { initMonitoring } from 'fxa-shared/monitoring';
import { initMonitoring } from '@fxa/shared/monitoring';
import { version } from '../../package.json';

const config = Config.getProperties();
Expand Down
2 changes: 1 addition & 1 deletion packages/fxa-admin-panel/src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import AppErrorBoundary from 'fxa-react/components/AppErrorBoundary';
import AppLocalizationProvider from 'fxa-react/lib/AppLocalizationProvider';
import { ApolloClient, createHttpLink, InMemoryCache } from '@apollo/client';
import { setContext } from '@apollo/client/link/context';
import sentryMetrics from 'fxa-shared/sentry/browser';
import sentryMetrics from '@fxa/shared/sentry/browser';
import { config, readConfigFromMeta, getExtraHeaders } from './lib/config';
import App from './App';
import './styles/tailwind.out.css';
Expand Down
2 changes: 1 addition & 1 deletion packages/fxa-auth-server/lib/monitoring.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* 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/. */

const { initMonitoring } = require('fxa-shared/monitoring');
const { initMonitoring } = require('@fxa/shared/monitoring');
const Sentry = require('@sentry/node');
const { config } = require('../config');
const logger = require('./log')(
Expand Down
17 changes: 13 additions & 4 deletions packages/fxa-auth-server/lib/payments/stripe.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ import { subscriptionProductMetadataValidator } from '../routes/validators';
import {
formatMetadataValidationErrorMessage,
reportValidationError,
} from 'fxa-shared/sentry/report-validation-error';
} from '@fxa/sentry-node';
import { AppConfig, AuthFirestore, AuthLogger, TaxAddress } from '../types';
import { PaymentConfigManager } from './configuration/manager';
import { CurrencyHelper } from './currencies';
Expand Down Expand Up @@ -3502,7 +3502,10 @@ export class StripeHelper extends StripeHelperBase {
return;
}

return this.stripeFirestore.fetchAndInsertCustomer(customerId, event.created);
return this.stripeFirestore.fetchAndInsertCustomer(
customerId,
event.created
);
}

/**
Expand All @@ -3525,7 +3528,10 @@ export class StripeHelper extends StripeHelperBase {
CUSTOMER_RESOURCE
);
if (!customer.deleted && !customer.currency) {
await this.stripeFirestore.fetchAndInsertCustomer(customerId, event.created);
await this.stripeFirestore.fetchAndInsertCustomer(
customerId,
event.created
);
const subscription =
await this.stripe.subscriptions.retrieve(subscriptionId);
return subscription;
Expand Down Expand Up @@ -3566,7 +3572,10 @@ export class StripeHelper extends StripeHelperBase {
);
} catch (err) {
if (err.name === FirestoreStripeError.FIRESTORE_CUSTOMER_NOT_FOUND) {
await this.stripeFirestore.fetchAndInsertCustomer(customerId, event.created);
await this.stripeFirestore.fetchAndInsertCustomer(
customerId,
event.created
);
await this.stripeFirestore.fetchAndInsertInvoice(
invoiceId,
event.created
Expand Down
Loading
Loading