Skip to content

Commit

Permalink
Review update
Browse files Browse the repository at this point in the history
  • Loading branch information
chtushar committed Apr 25, 2024
1 parent fafef79 commit c63e831
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 24 deletions.
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Added

- Optional `enableMetricsServer` option to enable of disable the metrics server.
- Optional `enableMetricsServer` option to enable or disable the metrics server.
- Exposed `getMetrics` function to get the metrics in prometheus exposition format.
- Add support to instrument applications based on `Next.js` framework in Node.js environment.

Expand Down
43 changes: 30 additions & 13 deletions src/OpenAPM.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@ export type DefaultLabels =
| 'host';

export interface OpenAPMOptions {
/**
* Enable the OpenAPM
*/
enabled?: boolean;
/**
* Enable the metrics server
* @default true
Expand Down Expand Up @@ -84,12 +88,13 @@ export class OpenAPM extends LevitateEvents {
private simpleCache: Record<string, any> = {};
private path: string;
private metricsServerPort: number;
private enabled: boolean;
private enableMetricsServer: boolean;
readonly environment: string;
readonly program: string;
private defaultLabels?: Record<string, string>;
private requestsCounterConfig: CounterConfiguration<string>;
private requestDurationHistogramConfig: HistogramConfiguration<string>;
readonly requestsCounterConfig: CounterConfiguration<string>;
readonly requestDurationHistogramConfig: HistogramConfiguration<string>;
private requestsCounter?: Counter;
private requestsDurationHistogram?: Histogram;
private extractLabels?: Record<string, ExtractFromParams>;
Expand All @@ -101,6 +106,7 @@ export class OpenAPM extends LevitateEvents {
constructor(options?: OpenAPMOptions) {
super(options);
// Initializing all the options
this.enabled = options?.enabled ?? true;
this.path = options?.path ?? '/metrics';
this.metricsServerPort = options?.metricsServerPort ?? 9097;
this.enableMetricsServer = options?.enableMetricsServer ?? true;
Expand Down Expand Up @@ -134,8 +140,10 @@ export class OpenAPM extends LevitateEvents {
this.customPathsToMask = options?.customPathsToMask;
this.excludeDefaultLabels = options?.excludeDefaultLabels;

this.initiateMetricsRoute();
this.initiatePromClient();
if (this.enabled) {
this.initiateMetricsRoute();
this.initiatePromClient();
}
}

private getDefaultLabels = () => {
Expand Down Expand Up @@ -174,6 +182,9 @@ export class OpenAPM extends LevitateEvents {

public shutdown = async () => {
return new Promise((resolve, reject) => {
if (!this.enabled) {
resolve(undefined);
}
if (this.enableMetricsServer) {
console.log('Shutting down metrics server gracefully.');
}
Expand Down Expand Up @@ -276,6 +287,9 @@ export class OpenAPM extends LevitateEvents {
res: ServerResponse<IncomingMessage>,
time: number
) => {
if (!this.enabled) {
return;
}
const sanitizedPathname = getSanitizedPath(req.originalUrl ?? '/');
// Extract labels from the request params
const { pathname, labels: parsedLabelsFromPathname } =
Expand All @@ -290,11 +304,7 @@ export class OpenAPM extends LevitateEvents {
}

// Make sure you copy baseURL in case of nested routes.
const path = req.route
? req.route?.path !== '*'
? req.baseUrl + req.route?.path
: pathname
: pathname;
const path = req.route ? req.baseUrl + req.route?.path : pathname;

const labels: Record<string, string> = {
path,
Expand Down Expand Up @@ -353,6 +363,9 @@ export class OpenAPM extends LevitateEvents {
};

public instrument(moduleName: SupportedModules) {
if (!this.enabled) {
return;
}
try {
if (moduleName === 'express') {
const express = require('express');
Expand All @@ -368,10 +381,14 @@ export class OpenAPM extends LevitateEvents {
}
if (moduleName === 'nextjs') {
const nextServer = require('next/dist/server/next-server');
instrumentNextjs(nextServer.default, {
counter: this.requestsCounter,
histogram: this.requestsDurationHistogram
});
instrumentNextjs(
nextServer.default,
{
counter: this.requestsCounter,
histogram: this.requestsDurationHistogram
},
this
);
}
} catch (error) {
if (Object.keys(moduleNames).includes(moduleName)) {
Expand Down
29 changes: 19 additions & 10 deletions src/clients/nextjs.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import type NextNodeServer from 'next/dist/server/next-server';
import prom, { Counter, Histogram } from 'prom-client';
import chokidar from 'chokidar';
import type { Counter, Histogram } from 'prom-client';
import { wrap } from '../shimmer';
import { loadManifest } from 'next/dist/server/load-manifest';
import { join } from 'path';
import { getRouteRegex } from 'next/dist/shared/lib/router/utils/route-regex';
import { getRouteMatcher } from 'next/dist/shared/lib/router/utils/route-matcher';
import OpenAPM from '../OpenAPM';

const DOT_NEXT = join(process.cwd(), '.next');

Expand Down Expand Up @@ -84,8 +85,8 @@ const wrappedHandler = (
handler: ReturnType<NextNodeServer['getRequestHandler']>,
ctx: {
getParameterizedRoute: (route: string) => string;
counter: Counter;
histogram: Histogram;
counter?: Counter;
histogram?: Histogram;
}
) => {
return async function (
Expand All @@ -104,15 +105,15 @@ const wrappedHandler = (
);

ctx.counter
.labels(
?.labels(
parsedPath !== '' ? parsedPath : '/',
req.method ?? 'GET',
res.statusCode?.toString() ?? '500'
)
.inc();

ctx.histogram
.labels(
?.labels(
parsedPath !== '' ? parsedPath : '/',
req.method ?? 'GET',
res.statusCode?.toString() ?? '500'
Expand All @@ -125,12 +126,20 @@ const wrappedHandler = (

export const instrumentNextjs = (
nextServer: typeof NextNodeServer,
{ counter, histogram }: { counter?: Counter; histogram?: Histogram }
{ counter, histogram }: { counter?: Counter; histogram?: Histogram },
openapm: OpenAPM
) => {
if (!counter || !histogram) {
throw new Error(
'counter and histogram are required. Make sure you are using openmetrics mode.'
);
const ctx = {
counter,
histogram
};

if (typeof ctx.counter === 'undefined') {
ctx.counter = new prom.Counter(openapm.requestsCounterConfig);
}

if (typeof ctx.histogram === 'undefined') {
ctx.histogram = new prom.Histogram(openapm.requestDurationHistogramConfig);
}

PATHS_CACHE.setValue();
Expand Down

0 comments on commit c63e831

Please sign in to comment.