@aurostack/stacks 0.1.1 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +59 -0
- package/cli/src/generate.mjs +13 -1
- package/package.json +1 -1
- package/templates/nest-api/files/.env.example +29 -2
- package/templates/nest-api/files/.env.test.example +1 -1
- package/templates/nest-api/files/compose.yml +16 -0
- package/templates/nest-api/files/package.json +18 -3
- package/templates/nest-api/files/src/app.module.ts +9 -1
- package/templates/nest-api/files/src/app.setup.ts +5 -6
- package/templates/nest-api/files/src/common/__tests__/temporal.service.spec.ts +66 -0
- package/templates/nest-api/files/src/common/common.module.ts +4 -3
- package/templates/nest-api/files/src/common/controllers/index.ts +0 -1
- package/templates/nest-api/files/src/common/modules/index.ts +0 -1
- package/templates/nest-api/files/src/common/modules/logger.module.ts +2 -6
- package/templates/nest-api/files/src/common/services/config.service.ts +43 -5
- package/templates/nest-api/files/src/common/services/index.ts +1 -0
- package/templates/nest-api/files/src/common/services/temporal.service.ts +66 -0
- package/templates/nest-api/files/src/instrumentation.ts +117 -0
- package/templates/nest-api/files/src/main.ts +3 -1
- package/templates/nest-api/files/src/telemetry/__tests__/config.spec.ts +67 -0
- package/templates/nest-api/files/src/telemetry/config.ts +62 -0
- package/templates/nest-api/template.json +36 -10
- package/templates/node-worker/files/.env.example +27 -0
- package/templates/node-worker/files/Dockerfile +25 -2
- package/templates/node-worker/files/Dockerfile.dev +25 -2
- package/templates/node-worker/files/ecosystem.config.cjs +2 -0
- package/templates/node-worker/files/package.json +23 -4
- package/templates/node-worker/files/src/config.ts +23 -0
- package/templates/node-worker/files/src/index.ts +13 -0
- package/templates/node-worker/files/src/instrumentation.ts +110 -0
- package/templates/node-worker/files/src/telemetry/config.ts +61 -0
- package/templates/node-worker/files/src/temporal/activities/index.ts +14 -0
- package/templates/node-worker/files/src/temporal/worker.ts +84 -0
- package/templates/node-worker/files/src/temporal/workflows/index.ts +23 -0
- package/templates/node-worker/files/src/utils/worker.ts +9 -1
- package/templates/node-worker/template.json +43 -1
- package/templates/py-worker/files/.env.example +28 -0
- package/templates/py-worker/files/config.py +32 -1
- package/templates/py-worker/files/requirements.txt +16 -0
- package/templates/py-worker/files/temporal/__init__.py +0 -0
- package/templates/py-worker/files/temporal/activities.py +13 -0
- package/templates/py-worker/files/temporal/workflows.py +38 -0
- package/templates/py-worker/files/utils/telemetry.py +154 -0
- package/templates/py-worker/files/utils/temporal.py +55 -0
- package/templates/py-worker/files/utils/worker.py +12 -1
- package/templates/py-worker/files/worker.py +16 -0
- package/templates/py-worker/template.json +36 -0
- package/templates/react-app/derive.sh +2 -1
- package/templates/react-app/files/.env.example +11 -0
- package/templates/react-app/files/package.json +2 -0
- package/templates/react-app/files/src/lib/env.ts +10 -0
- package/templates/react-app/files/src/main.tsx +4 -0
- package/templates/react-app/files/src/shared/auth/provider.tsx +2 -0
- package/templates/react-app/files/src/shared/layouts/error-boundary.tsx +2 -0
- package/templates/react-app/files/src/shared/telemetry/index.ts +80 -0
- package/templates/react-app/template.json +14 -0
- package/templates/react-monorepo/files/apps/admin/.env.example +11 -0
- package/templates/react-monorepo/files/apps/admin/package.json +1 -0
- package/templates/react-monorepo/files/apps/admin/src/lib/env.ts +10 -0
- package/templates/react-monorepo/files/apps/admin/src/main.tsx +4 -0
- package/templates/react-monorepo/files/apps/auth/.env.example +11 -0
- package/templates/react-monorepo/files/apps/auth/package.json +1 -0
- package/templates/react-monorepo/files/apps/auth/src/lib/env.ts +10 -0
- package/templates/react-monorepo/files/apps/auth/src/main.tsx +4 -0
- package/templates/react-monorepo/files/apps/client/.env.example +11 -0
- package/templates/react-monorepo/files/apps/client/package.json +1 -0
- package/templates/react-monorepo/files/apps/client/src/lib/env.ts +10 -0
- package/templates/react-monorepo/files/apps/client/src/main.tsx +4 -0
- package/templates/react-monorepo/files/apps/landing/.env.example +11 -0
- package/templates/react-monorepo/files/apps/landing/package.json +1 -0
- package/templates/react-monorepo/files/apps/landing/src/lib/env.ts +10 -0
- package/templates/react-monorepo/files/apps/landing/src/main.tsx +4 -0
- package/templates/react-monorepo/files/packages/auth/package.json +1 -0
- package/templates/react-monorepo/files/packages/auth/src/provider.tsx +2 -0
- package/templates/react-monorepo/files/packages/layouts/package.json +1 -0
- package/templates/react-monorepo/files/packages/layouts/src/error-boundary.tsx +2 -0
- package/templates/react-monorepo/files/packages/telemetry/eslint.config.mjs +3 -0
- package/templates/react-monorepo/files/packages/telemetry/package.json +20 -0
- package/templates/react-monorepo/files/packages/telemetry/src/index.ts +80 -0
- package/templates/react-monorepo/files/packages/telemetry/tsconfig.json +4 -0
- package/templates/react-monorepo/template.json +46 -0
- package/templates/nest-api/files/src/common/controllers/metrics.controller.ts +0 -21
- package/templates/nest-api/files/src/common/interceptors/index.ts +0 -1
- package/templates/nest-api/files/src/common/interceptors/metrics.interceptor.ts +0 -37
- package/templates/nest-api/files/src/common/modules/metrics.module.ts +0 -28
|
@@ -10,3 +10,13 @@ export const CLIENT_URL = env.VITE_APP_CLIENT_HOST as string;
|
|
|
10
10
|
export const ADMIN_URL = env.VITE_APP_ADMIN_HOST as string;
|
|
11
11
|
/** The public marketing site (logout destination). */
|
|
12
12
|
export const LANDING_URL = env.VITE_APP_LANDING as string;
|
|
13
|
+
|
|
14
|
+
// @feature:start telemetry
|
|
15
|
+
/** OpenObserve browser monitoring (see @acme/telemetry); unset keeps it off. */
|
|
16
|
+
export const TELEMETRY = {
|
|
17
|
+
url: env.VITE_OPENOBSERVE_URL as string | undefined,
|
|
18
|
+
org: env.VITE_OPENOBSERVE_ORG as string | undefined,
|
|
19
|
+
clientToken: env.VITE_OPENOBSERVE_CLIENT_TOKEN as string | undefined,
|
|
20
|
+
environment: env.MODE
|
|
21
|
+
};
|
|
22
|
+
// @feature:end
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { StrictMode } from 'react';
|
|
2
2
|
import { createRoot } from 'react-dom/client';
|
|
3
|
+
import { initTelemetry } from '@acme/telemetry'; // @feature telemetry
|
|
4
|
+
import { API_URL, TELEMETRY } from './lib/env'; // @feature telemetry
|
|
3
5
|
import { RouterProvider } from 'react-router';
|
|
4
6
|
import '@acme/ui/globals.css';
|
|
5
7
|
import { Providers } from './app/providers';
|
|
@@ -10,6 +12,8 @@ import { router } from './app/router';
|
|
|
10
12
|
// evaluating and `providers` has already called `configureApi` at module scope,
|
|
11
13
|
// so the fetch races the session check instead of queueing behind it.
|
|
12
14
|
|
|
15
|
+
initTelemetry({ service: 'acme-client', ...TELEMETRY, apiUrls: [API_URL] }); // @feature telemetry
|
|
16
|
+
|
|
13
17
|
createRoot(document.getElementById('root')!).render(
|
|
14
18
|
<StrictMode>
|
|
15
19
|
<Providers>
|
|
@@ -18,3 +18,14 @@ PORT='3000'
|
|
|
18
18
|
# Canonical public URL, used for sitemap/robots/OG tags at build time.
|
|
19
19
|
VITE_APP_SITE_URL='http://localhost:3000'
|
|
20
20
|
VITE_APP_SUPPORT_EMAIL='support@example.com'
|
|
21
|
+
|
|
22
|
+
# @feature:start telemetry
|
|
23
|
+
# OpenObserve browser monitoring (RUM): page views, errors, slow requests, and
|
|
24
|
+
# trace headers on API calls. Leave empty and it stays off. The client token is
|
|
25
|
+
# a RUM token (OpenObserve → Ingestion → RUM): write-only and meant to ship in
|
|
26
|
+
# the bundle — never the backend's ingestion token.
|
|
27
|
+
# The instance must list this app's origin in ZO_CORS_ALLOWED_ORIGINS.
|
|
28
|
+
VITE_OPENOBSERVE_URL='https://o2.aurostack.co'
|
|
29
|
+
VITE_OPENOBSERVE_ORG=''
|
|
30
|
+
VITE_OPENOBSERVE_CLIENT_TOKEN=''
|
|
31
|
+
# @feature:end
|
|
@@ -8,3 +8,13 @@ export const CLIENT_HOST = env.VITE_APP_CLIENT_HOST;
|
|
|
8
8
|
* actually posts. Falsy when the build arg is missing; the UI hides the block
|
|
9
9
|
* rather than rendering `mailto:undefined`. */
|
|
10
10
|
export const SUPPORT_EMAIL = env.VITE_APP_SUPPORT_EMAIL;
|
|
11
|
+
|
|
12
|
+
// @feature:start telemetry
|
|
13
|
+
/** OpenObserve browser monitoring (see @acme/telemetry); unset keeps it off. */
|
|
14
|
+
export const TELEMETRY = {
|
|
15
|
+
url: env.VITE_OPENOBSERVE_URL as string | undefined,
|
|
16
|
+
org: env.VITE_OPENOBSERVE_ORG as string | undefined,
|
|
17
|
+
clientToken: env.VITE_OPENOBSERVE_CLIENT_TOKEN as string | undefined,
|
|
18
|
+
environment: env.MODE
|
|
19
|
+
};
|
|
20
|
+
// @feature:end
|
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
import { StrictMode } from 'react';
|
|
2
2
|
import { createRoot } from 'react-dom/client';
|
|
3
|
+
import { initTelemetry } from '@acme/telemetry'; // @feature telemetry
|
|
4
|
+
import { API_URL, TELEMETRY } from './lib/env'; // @feature telemetry
|
|
3
5
|
import { RouterProvider } from 'react-router';
|
|
4
6
|
import '@acme/ui/globals.css';
|
|
5
7
|
import { Providers } from './app/providers';
|
|
6
8
|
import { router } from './app/router';
|
|
7
9
|
|
|
10
|
+
initTelemetry({ service: 'acme-landing', ...TELEMETRY, apiUrls: [API_URL] }); // @feature telemetry
|
|
11
|
+
|
|
8
12
|
createRoot(document.getElementById('root')!).render(
|
|
9
13
|
<StrictMode>
|
|
10
14
|
<Providers>
|
|
@@ -3,6 +3,7 @@ import { useDispatch } from 'react-redux';
|
|
|
3
3
|
import { getAuthClient } from './client';
|
|
4
4
|
import { sessionCleared, sessionLoaded, sessionLoading, type AuthUser } from './slice';
|
|
5
5
|
import { AUTH_BROADCAST_CHANNEL } from './logout';
|
|
6
|
+
import { setTelemetryUser } from '@acme/telemetry'; // @feature telemetry
|
|
6
7
|
|
|
7
8
|
function toAuthUser(user: Record<string, unknown> | null | undefined): AuthUser | null {
|
|
8
9
|
if (!user) return null;
|
|
@@ -33,6 +34,7 @@ export function AuthProvider({ children }: { children: ReactNode }) {
|
|
|
33
34
|
}
|
|
34
35
|
const user = (session.data?.user as Record<string, unknown> | undefined) ?? null;
|
|
35
36
|
dispatch(sessionLoaded(toAuthUser(user)));
|
|
37
|
+
setTelemetryUser(user ? { id: String(user.id) } : null); // @feature telemetry
|
|
36
38
|
}, [session.isPending, session.data, dispatch]);
|
|
37
39
|
|
|
38
40
|
useEffect(() => {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Component, type ErrorInfo, type ReactNode } from 'react';
|
|
2
2
|
import { Button } from '@acme/ui';
|
|
3
3
|
import { StateScreen } from './states/state-screen';
|
|
4
|
+
import { reportError } from '@acme/telemetry'; // @feature telemetry
|
|
4
5
|
|
|
5
6
|
type ErrorBoundaryProps = {
|
|
6
7
|
children: ReactNode;
|
|
@@ -21,6 +22,7 @@ export class ErrorBoundary extends Component<ErrorBoundaryProps, ErrorBoundarySt
|
|
|
21
22
|
|
|
22
23
|
componentDidCatch(error: Error, info: ErrorInfo): void {
|
|
23
24
|
console.error('ErrorBoundary caught an error', error, info);
|
|
25
|
+
reportError(error, { componentStack: info.componentStack }); // @feature telemetry
|
|
24
26
|
}
|
|
25
27
|
|
|
26
28
|
render(): ReactNode {
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@acme/telemetry",
|
|
3
|
+
"version": "0.0.0",
|
|
4
|
+
"private": true,
|
|
5
|
+
"type": "module",
|
|
6
|
+
"exports": {
|
|
7
|
+
".": "./src/index.ts"
|
|
8
|
+
},
|
|
9
|
+
"scripts": {
|
|
10
|
+
"lint": "eslint .",
|
|
11
|
+
"typecheck": "tsc --noEmit"
|
|
12
|
+
},
|
|
13
|
+
"dependencies": {
|
|
14
|
+
"@openobserve/browser-logs": "^0.4.3",
|
|
15
|
+
"@openobserve/browser-rum": "^0.4.3"
|
|
16
|
+
},
|
|
17
|
+
"devDependencies": {
|
|
18
|
+
"@acme/config": "workspace:*"
|
|
19
|
+
}
|
|
20
|
+
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
// @acme/telemetry — browser monitoring (RUM) and logs, sent to OpenObserve.
|
|
2
|
+
//
|
|
3
|
+
// Page views, errors, slow resources and user actions, plus console errors as
|
|
4
|
+
// logs. Requests to the app's own API carry a W3C `traceparent` header, so a
|
|
5
|
+
// click links to the backend trace it caused. The SDK finishes starting a
|
|
6
|
+
// moment after init (its session store is async), so the first request or two
|
|
7
|
+
// of a page load (typically the session check) go out without the header.
|
|
8
|
+
// Off until connection settings are passed; everything here is then a no-op.
|
|
9
|
+
import { DefaultPrivacyLevel, openobserveRum } from '@openobserve/browser-rum';
|
|
10
|
+
import { openobserveLogs } from '@openobserve/browser-logs';
|
|
11
|
+
|
|
12
|
+
export interface TelemetryOptions {
|
|
13
|
+
/** Service name, e.g. `acme-client` — one per app. */
|
|
14
|
+
service: string;
|
|
15
|
+
/** OpenObserve base URL, e.g. `https://o2.example.com`. */
|
|
16
|
+
url?: string;
|
|
17
|
+
/** The project's organization identifier. */
|
|
18
|
+
org?: string;
|
|
19
|
+
/**
|
|
20
|
+
* A RUM client token (Ingestion → RUM). Write-only and built for shipping
|
|
21
|
+
* in a bundle — never the backend's ingestion token.
|
|
22
|
+
*/
|
|
23
|
+
clientToken?: string;
|
|
24
|
+
/** `development`, `production`, … — Vite's `import.meta.env.MODE`. */
|
|
25
|
+
environment?: string;
|
|
26
|
+
version?: string;
|
|
27
|
+
/** Backend origin(s) whose requests should carry trace headers. */
|
|
28
|
+
apiUrls?: string[];
|
|
29
|
+
/** Share of sessions to record for replay, 0–100. Off by default. */
|
|
30
|
+
sessionReplaySampleRate?: number;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
let started = false;
|
|
34
|
+
|
|
35
|
+
export function initTelemetry(options: TelemetryOptions): boolean {
|
|
36
|
+
const { url, org, clientToken } = options;
|
|
37
|
+
if (started || !url || !org || !clientToken) return false;
|
|
38
|
+
|
|
39
|
+
// The SDK takes a bare host (no scheme) plus an explicit plain-HTTP flag.
|
|
40
|
+
const { host, protocol } = new URL(url);
|
|
41
|
+
const common = {
|
|
42
|
+
clientToken,
|
|
43
|
+
site: host,
|
|
44
|
+
organizationIdentifier: org,
|
|
45
|
+
insecureHTTP: protocol === 'http:',
|
|
46
|
+
service: options.service,
|
|
47
|
+
env: options.environment,
|
|
48
|
+
version: options.version
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
openobserveRum.init({
|
|
52
|
+
...common,
|
|
53
|
+
applicationId: options.service,
|
|
54
|
+
sessionSampleRate: 100,
|
|
55
|
+
sessionReplaySampleRate: options.sessionReplaySampleRate ?? 0,
|
|
56
|
+
defaultPrivacyLevel: DefaultPrivacyLevel.MASK_USER_INPUT,
|
|
57
|
+
trackResources: true,
|
|
58
|
+
trackLongTasks: true,
|
|
59
|
+
trackUserInteractions: true,
|
|
60
|
+
allowedTracingUrls: (options.apiUrls ?? []).filter(Boolean).map((match) => ({
|
|
61
|
+
match,
|
|
62
|
+
propagatorTypes: ['tracecontext' as const]
|
|
63
|
+
}))
|
|
64
|
+
});
|
|
65
|
+
openobserveLogs.init({ ...common, forwardErrorsToLogs: true });
|
|
66
|
+
started = true;
|
|
67
|
+
return true;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/** Report a handled error — e.g. from an error boundary. */
|
|
71
|
+
export function reportError(error: unknown, context?: object): void {
|
|
72
|
+
if (started) openobserveRum.addError(error, context);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/** Tie the session to a signed-in user (id only), or clear it on logout. */
|
|
76
|
+
export function setTelemetryUser(user: { id: string } | null): void {
|
|
77
|
+
if (!started) return;
|
|
78
|
+
if (user) openobserveRum.setUser({ id: user.id });
|
|
79
|
+
else openobserveRum.clearUser();
|
|
80
|
+
}
|
|
@@ -81,6 +81,52 @@
|
|
|
81
81
|
"packages/types/**"
|
|
82
82
|
]
|
|
83
83
|
},
|
|
84
|
+
"telemetry": {
|
|
85
|
+
"title": "Browser monitoring → OpenObserve",
|
|
86
|
+
"description": "The @acme/telemetry package: OpenObserve RUM and logs in every app — page views, errors (including the error boundary's), slow resources, user actions, the signed-in user id, and traceparent headers on API calls so frontend and backend traces link up. Session replay is off unless a project turns it on. Off at runtime until VITE_OPENOBSERVE_* are set.",
|
|
87
|
+
"default": true,
|
|
88
|
+
"files": [
|
|
89
|
+
"packages/telemetry/**"
|
|
90
|
+
],
|
|
91
|
+
"packageJson": [
|
|
92
|
+
{
|
|
93
|
+
"file": "apps/admin/package.json",
|
|
94
|
+
"dependencies": [
|
|
95
|
+
"@acme/telemetry"
|
|
96
|
+
]
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
"file": "apps/auth/package.json",
|
|
100
|
+
"dependencies": [
|
|
101
|
+
"@acme/telemetry"
|
|
102
|
+
]
|
|
103
|
+
},
|
|
104
|
+
{
|
|
105
|
+
"file": "apps/client/package.json",
|
|
106
|
+
"dependencies": [
|
|
107
|
+
"@acme/telemetry"
|
|
108
|
+
]
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
"file": "apps/landing/package.json",
|
|
112
|
+
"dependencies": [
|
|
113
|
+
"@acme/telemetry"
|
|
114
|
+
]
|
|
115
|
+
},
|
|
116
|
+
{
|
|
117
|
+
"file": "packages/layouts/package.json",
|
|
118
|
+
"dependencies": [
|
|
119
|
+
"@acme/telemetry"
|
|
120
|
+
]
|
|
121
|
+
},
|
|
122
|
+
{
|
|
123
|
+
"file": "packages/auth/package.json",
|
|
124
|
+
"dependencies": [
|
|
125
|
+
"@acme/telemetry"
|
|
126
|
+
]
|
|
127
|
+
}
|
|
128
|
+
]
|
|
129
|
+
},
|
|
84
130
|
"app-auth": {
|
|
85
131
|
"title": "Auth app",
|
|
86
132
|
"description": "Login, signup, forgot/reset password, email verification. The one app that owns the session; the others redirect here.",
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import { Controller, Get, Res } from '@nestjs/common';
|
|
2
|
-
import { ApiExcludeEndpoint, ApiTags } from '@nestjs/swagger';
|
|
3
|
-
import { SkipThrottle } from '@nestjs/throttler'; // @feature rate-limit
|
|
4
|
-
import { AllowAnonymous } from '@thallesp/nestjs-better-auth';
|
|
5
|
-
import { PrometheusController } from '@willsoto/nestjs-prometheus';
|
|
6
|
-
import type { Response } from 'express';
|
|
7
|
-
|
|
8
|
-
@ApiTags('App')
|
|
9
|
-
@Controller()
|
|
10
|
-
// @feature:start rate-limit
|
|
11
|
-
// Scraped on a fixed interval by Prometheus; already gated by basic auth.
|
|
12
|
-
@SkipThrottle()
|
|
13
|
-
// @feature:end
|
|
14
|
-
export class MetricsController extends PrometheusController {
|
|
15
|
-
@Get()
|
|
16
|
-
@ApiExcludeEndpoint()
|
|
17
|
-
@AllowAnonymous()
|
|
18
|
-
async index(@Res({ passthrough: true }) response: Response): Promise<string> {
|
|
19
|
-
return super.index(response);
|
|
20
|
-
}
|
|
21
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from './metrics.interceptor'; // @feature observability
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
Injectable,
|
|
3
|
-
NestInterceptor,
|
|
4
|
-
ExecutionContext,
|
|
5
|
-
CallHandler
|
|
6
|
-
} from '@nestjs/common';
|
|
7
|
-
import { InjectMetric } from '@willsoto/nestjs-prometheus';
|
|
8
|
-
import { Histogram } from 'prom-client';
|
|
9
|
-
import { Observable, tap } from 'rxjs';
|
|
10
|
-
|
|
11
|
-
@Injectable()
|
|
12
|
-
export class MetricsInterceptor implements NestInterceptor {
|
|
13
|
-
constructor(
|
|
14
|
-
@InjectMetric('http_request_duration_seconds')
|
|
15
|
-
private readonly histogram: Histogram<string>
|
|
16
|
-
) {}
|
|
17
|
-
|
|
18
|
-
intercept(context: ExecutionContext, next: CallHandler): Observable<unknown> {
|
|
19
|
-
if (context.getType() !== 'http') {
|
|
20
|
-
return next.handle();
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
const http = context.switchToHttp();
|
|
24
|
-
const req = http.getRequest();
|
|
25
|
-
const res = http.getResponse();
|
|
26
|
-
const stop = this.histogram.startTimer();
|
|
27
|
-
|
|
28
|
-
const observe = () =>
|
|
29
|
-
stop({
|
|
30
|
-
method: req.method,
|
|
31
|
-
route: req.route?.path ?? 'unmatched',
|
|
32
|
-
status: res.statusCode
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
return next.handle().pipe(tap({ next: observe, error: observe }));
|
|
36
|
-
}
|
|
37
|
-
}
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
import { Module } from '@nestjs/common';
|
|
2
|
-
import { APP_INTERCEPTOR } from '@nestjs/core';
|
|
3
|
-
import {
|
|
4
|
-
makeHistogramProvider,
|
|
5
|
-
PrometheusModule
|
|
6
|
-
} from '@willsoto/nestjs-prometheus';
|
|
7
|
-
import { MetricsController } from '../controllers';
|
|
8
|
-
import { MetricsInterceptor } from '../interceptors';
|
|
9
|
-
|
|
10
|
-
@Module({
|
|
11
|
-
imports: [
|
|
12
|
-
PrometheusModule.register({
|
|
13
|
-
defaultLabels: { app: 'acme-api' },
|
|
14
|
-
defaultMetrics: { enabled: true },
|
|
15
|
-
controller: MetricsController
|
|
16
|
-
})
|
|
17
|
-
],
|
|
18
|
-
providers: [
|
|
19
|
-
makeHistogramProvider({
|
|
20
|
-
name: 'http_request_duration_seconds',
|
|
21
|
-
help: 'Duration of HTTP requests in seconds',
|
|
22
|
-
labelNames: ['method', 'route', 'status'],
|
|
23
|
-
buckets: [0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1, 2.5, 5]
|
|
24
|
-
}),
|
|
25
|
-
{ provide: APP_INTERCEPTOR, useClass: MetricsInterceptor }
|
|
26
|
-
]
|
|
27
|
-
})
|
|
28
|
-
export class MetricsModule {}
|