@ttt-productions/monitoring-core 0.0.1
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/package.json +16 -0
- package/src/adapter.ts +16 -0
- package/src/adapters/noop.ts +21 -0
- package/src/adapters/sentry.ts +96 -0
- package/src/api.ts +31 -0
- package/src/index.ts +4 -0
- package/src/init.ts +33 -0
- package/src/types.ts +23 -0
- package/tsconfig.json +11 -0
package/package.json
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@ttt-productions/monitoring-core",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"repository": {
|
|
5
|
+
"type": "git",
|
|
6
|
+
"url": "git+https://github.com/ttt-productions/ttt-packages.git",
|
|
7
|
+
"directory": "packages/monitoring-core"
|
|
8
|
+
},
|
|
9
|
+
"main": "dist/index.js",
|
|
10
|
+
"types": "dist/index.d.ts",
|
|
11
|
+
"sideEffects": false,
|
|
12
|
+
"dependencies": {},
|
|
13
|
+
"peerDependencies": {
|
|
14
|
+
"@sentry/nextjs": "^8.0.0"
|
|
15
|
+
}
|
|
16
|
+
}
|
package/src/adapter.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { MonitoringInitOptions, MonitoringUser, ScopeLike } from "./types";
|
|
2
|
+
|
|
3
|
+
export interface MonitoringAdapter {
|
|
4
|
+
init(options: MonitoringInitOptions): void | Promise<void>;
|
|
5
|
+
|
|
6
|
+
captureException(error: unknown, context?: Record<string, unknown>): void;
|
|
7
|
+
captureMessage(
|
|
8
|
+
message: string,
|
|
9
|
+
level?: "fatal" | "error" | "warning" | "info" | "debug"
|
|
10
|
+
): void;
|
|
11
|
+
|
|
12
|
+
setUser(user: MonitoringUser | null): void;
|
|
13
|
+
setTag(key: string, value: string): void;
|
|
14
|
+
|
|
15
|
+
withScope?<T>(fn: (scope: ScopeLike) => T): T;
|
|
16
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { MonitoringAdapter } from "../adapter";
|
|
2
|
+
import type { MonitoringInitOptions, MonitoringUser, ScopeLike } from "../types";
|
|
3
|
+
|
|
4
|
+
const noopScope: ScopeLike = {
|
|
5
|
+
setTag: () => {},
|
|
6
|
+
setUser: () => {},
|
|
7
|
+
setExtra: () => {},
|
|
8
|
+
setContext: () => {},
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export const NoopAdapter: MonitoringAdapter = {
|
|
12
|
+
init: (_options: MonitoringInitOptions) => {},
|
|
13
|
+
|
|
14
|
+
captureException: (_error: unknown, _context?: Record<string, unknown>) => {},
|
|
15
|
+
captureMessage: (_message: string, _level?: any) => {},
|
|
16
|
+
|
|
17
|
+
setUser: (_user: MonitoringUser | null) => {},
|
|
18
|
+
setTag: (_key: string, _value: string) => {},
|
|
19
|
+
|
|
20
|
+
withScope: <T>(fn: (scope: ScopeLike) => T) => fn(noopScope),
|
|
21
|
+
};
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import type { MonitoringAdapter } from "../adapter";
|
|
2
|
+
import type { MonitoringInitOptions, MonitoringUser, ScopeLike } from "../types";
|
|
3
|
+
|
|
4
|
+
type SentryLike = {
|
|
5
|
+
init: (opts: any) => void;
|
|
6
|
+
captureException: (e: unknown) => void;
|
|
7
|
+
captureMessage: (m: string, level?: any) => void;
|
|
8
|
+
setUser: (u: any) => void;
|
|
9
|
+
setTag: (k: string, v: string) => void;
|
|
10
|
+
withScope?: (fn: (scope: any) => void) => void;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
let sentryPromise: Promise<SentryLike> | null = null;
|
|
14
|
+
|
|
15
|
+
function getSentry(): Promise<SentryLike> {
|
|
16
|
+
if (!sentryPromise) {
|
|
17
|
+
// keep the import fully dynamic and untyped so TS doesn't require the module at build time
|
|
18
|
+
sentryPromise = (Function("return import('@sentry/nextjs')")() as Promise<any>).then(
|
|
19
|
+
(m) => m as SentryLike
|
|
20
|
+
);
|
|
21
|
+
}
|
|
22
|
+
return sentryPromise;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export const SentryAdapter: MonitoringAdapter = {
|
|
26
|
+
async init(options: MonitoringInitOptions) {
|
|
27
|
+
const enabled = options.enabled ?? true;
|
|
28
|
+
if (!enabled || !options.dsn) return;
|
|
29
|
+
|
|
30
|
+
const S = await getSentry();
|
|
31
|
+
S.init({
|
|
32
|
+
dsn: options.dsn,
|
|
33
|
+
environment: options.environment,
|
|
34
|
+
enabled: true,
|
|
35
|
+
release: options.release,
|
|
36
|
+
});
|
|
37
|
+
},
|
|
38
|
+
|
|
39
|
+
captureException(error: unknown, context?: Record<string, unknown>) {
|
|
40
|
+
void (async () => {
|
|
41
|
+
const S = await getSentry();
|
|
42
|
+
|
|
43
|
+
if (context && S.withScope) {
|
|
44
|
+
S.withScope((scope) => {
|
|
45
|
+
for (const [k, v] of Object.entries(context)) {
|
|
46
|
+
if (typeof scope?.setExtra === "function") scope.setExtra(k, v);
|
|
47
|
+
}
|
|
48
|
+
S.captureException(error);
|
|
49
|
+
});
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
S.captureException(error);
|
|
54
|
+
})();
|
|
55
|
+
},
|
|
56
|
+
|
|
57
|
+
captureMessage(message: string, level?: any) {
|
|
58
|
+
void (async () => {
|
|
59
|
+
const S = await getSentry();
|
|
60
|
+
S.captureMessage(message, level);
|
|
61
|
+
})();
|
|
62
|
+
},
|
|
63
|
+
|
|
64
|
+
setUser(user: MonitoringUser | null) {
|
|
65
|
+
void (async () => {
|
|
66
|
+
const S = await getSentry();
|
|
67
|
+
S.setUser(user as any);
|
|
68
|
+
})();
|
|
69
|
+
},
|
|
70
|
+
|
|
71
|
+
setTag(key: string, value: string) {
|
|
72
|
+
void (async () => {
|
|
73
|
+
const S = await getSentry();
|
|
74
|
+
S.setTag(key, value);
|
|
75
|
+
})();
|
|
76
|
+
},
|
|
77
|
+
|
|
78
|
+
withScope<T>(fn: (scope: ScopeLike) => T): T {
|
|
79
|
+
// run immediately (sync) with a minimal scope.
|
|
80
|
+
// also try to run in real Sentry scope when available.
|
|
81
|
+
const minimalScope: ScopeLike = {
|
|
82
|
+
setTag: () => {},
|
|
83
|
+
setUser: () => {},
|
|
84
|
+
setExtra: () => {},
|
|
85
|
+
setContext: () => {},
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
void (async () => {
|
|
89
|
+
const S = await getSentry();
|
|
90
|
+
if (!S.withScope) return;
|
|
91
|
+
S.withScope((scope) => fn(scope as any));
|
|
92
|
+
})();
|
|
93
|
+
|
|
94
|
+
return fn(minimalScope);
|
|
95
|
+
},
|
|
96
|
+
};
|
package/src/api.ts
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { MonitoringUser } from "./types";
|
|
2
|
+
import { getMonitoringAdapter } from "./init";
|
|
3
|
+
|
|
4
|
+
export function captureException(error: unknown, context?: Record<string, unknown>) {
|
|
5
|
+
return getMonitoringAdapter().captureException(error, context);
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export function captureMessage(
|
|
9
|
+
message: string,
|
|
10
|
+
level?: "fatal" | "error" | "warning" | "info" | "debug"
|
|
11
|
+
) {
|
|
12
|
+
return getMonitoringAdapter().captureMessage(message, level);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function setUser(user: MonitoringUser | null) {
|
|
16
|
+
return getMonitoringAdapter().setUser(user);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function setTag(key: string, value: string) {
|
|
20
|
+
return getMonitoringAdapter().setTag(key, value);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function withScope(fn: (scope: any) => any) {
|
|
24
|
+
const a = getMonitoringAdapter();
|
|
25
|
+
return a.withScope ? a.withScope(fn as any) : fn({
|
|
26
|
+
setTag: () => {},
|
|
27
|
+
setUser: () => {},
|
|
28
|
+
setExtra: () => {},
|
|
29
|
+
setContext: () => {},
|
|
30
|
+
});
|
|
31
|
+
}
|
package/src/index.ts
ADDED
package/src/init.ts
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { MonitoringAdapter } from "./adapter";
|
|
2
|
+
import type { MonitoringInitOptions } from "./types";
|
|
3
|
+
import { NoopAdapter } from "./adapters/noop";
|
|
4
|
+
import { SentryAdapter } from "./adapters/sentry";
|
|
5
|
+
|
|
6
|
+
let adapter: MonitoringAdapter = NoopAdapter;
|
|
7
|
+
let initialized = false;
|
|
8
|
+
|
|
9
|
+
export function getMonitoringAdapter(): MonitoringAdapter {
|
|
10
|
+
return adapter;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export async function initMonitoring(options: MonitoringInitOptions): Promise<void> {
|
|
14
|
+
if (initialized) return;
|
|
15
|
+
|
|
16
|
+
const enabled = options.enabled ?? true;
|
|
17
|
+
|
|
18
|
+
if (!enabled || options.provider === "noop") {
|
|
19
|
+
adapter = NoopAdapter;
|
|
20
|
+
initialized = true;
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
if (options.provider === "sentry") {
|
|
25
|
+
adapter = SentryAdapter;
|
|
26
|
+
await adapter.init(options);
|
|
27
|
+
initialized = true;
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
adapter = NoopAdapter;
|
|
32
|
+
initialized = true;
|
|
33
|
+
}
|
package/src/types.ts
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export type MonitoringProvider = "sentry" | "noop";
|
|
2
|
+
|
|
3
|
+
export type MonitoringInitOptions = {
|
|
4
|
+
provider: MonitoringProvider;
|
|
5
|
+
dsn?: string;
|
|
6
|
+
environment?: string;
|
|
7
|
+
enabled?: boolean; // default true
|
|
8
|
+
release?: string;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export type MonitoringUser = {
|
|
12
|
+
id?: string;
|
|
13
|
+
email?: string;
|
|
14
|
+
username?: string;
|
|
15
|
+
ip_address?: string;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export type ScopeLike = {
|
|
19
|
+
setTag: (key: string, value: string) => void;
|
|
20
|
+
setUser: (user: MonitoringUser | null) => void;
|
|
21
|
+
setExtra: (key: string, value: unknown) => void;
|
|
22
|
+
setContext: (key: string, context: Record<string, unknown>) => void;
|
|
23
|
+
};
|