Skip to content

Commit da60dc2

Browse files
committed
runtime feature
1 parent 977db5c commit da60dc2

12 files changed

Lines changed: 220 additions & 46 deletions

File tree

lib/core/global.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { TraceoGlobal } from "../transport/base";
22

3-
export const getGlobalClientData = (): TraceoGlobal => global.__TRACEO__ || {};
3+
export const getGlobalClientData = (): TraceoGlobal =>
4+
global["__TRACEO__"] || {};
45

56
export const setGlobalClientData = (data: TraceoGlobal): void => {
67
global.__TRACEO__ = { ...data };

lib/core/http.ts

Lines changed: 36 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import * as http from "http";
22
import { sanitizeDsn } from "../node/helpers";
3-
import { EventResponse, TraceoEvent } from "../transport/events";
3+
import { EventResponse, Incident } from "../transport/events";
44
import { TraceoIncomingMessage, RequestOptions } from "../transport/http";
55
import { getGlobalClientData } from "./global";
66
import { isClientConnected } from "./is";
@@ -11,51 +11,71 @@ enum RequestStatus {
1111
ERROR = "error",
1212
}
1313

14-
const createHttpOptions = ({
15-
event,
16-
}: {
17-
event?: TraceoEvent;
18-
}): http.RequestOptions => {
14+
const createHttpOptions = (path: string): http.RequestOptions => {
1915
const client = getGlobalClientData();
2016

2117
const { dsn } = client;
22-
const { host, secretKey, appId } = sanitizeDsn(dsn);
18+
const { host, secretKey } = sanitizeDsn(dsn);
2319

2420
const baseOptions: RequestOptions = {
2521
hostname: host,
2622
method: "POST",
2723
headers: {
2824
"Content-Type": "application/json",
29-
"Content-Length": `${Buffer.byteLength(JSON.stringify(event))}`,
3025
"Traceo-Secret-Key": secretKey,
3126
},
3227
};
3328

3429
return {
35-
path: `/${appId}`,
30+
path,
3631
...baseOptions,
3732
};
3833
};
3934

4035
const statusFromCode = (code: number) =>
4136
code >= 200 && code <= 299 ? RequestStatus.SUCCESS : RequestStatus.ERROR;
4237

43-
export const sendEvent = async (
44-
event: TraceoEvent
45-
): Promise<EventResponse | void> => {
46-
const { environment, dsn } = getGlobalClientData();
38+
export const sendRuntimeMetrics = async (data: {}) => {
39+
const { appId, environment } = getGlobalClientData();
4740

48-
if (!environment || !dsn) {
41+
if (!appId) {
42+
return;
43+
}
44+
45+
const httpOptions = createHttpOptions(
46+
`/${appId}/${environment}/metrics/runtime`
47+
);
48+
await sendEvent(data, httpOptions);
49+
};
50+
51+
export const sendIncidentEvent = async (incident: Incident) => {
52+
const { environment, appId } = getGlobalClientData();
53+
54+
if (!environment || !appId) {
4955
return;
5056
}
5157

5258
const version = TRACEO_SDK_VERSION;
5359
const baseData = { version, env: environment };
5460

55-
const payload = Object.assign(event, baseData);
61+
const payload = Object.assign(incident, baseData);
62+
63+
const httpOptions = createHttpOptions(`/${appId}`);
64+
await sendEvent(payload, httpOptions);
65+
};
66+
67+
export const sendEvent = async (
68+
payload: any,
69+
httpOptions: http.RequestOptions
70+
): Promise<EventResponse | void> => {
71+
const { environment, dsn } = getGlobalClientData();
72+
73+
if (!environment || !dsn) {
74+
return;
75+
}
5676

5777
return new Promise<EventResponse>((resolve, reject) => {
58-
const httpOptions = createHttpOptions({ event });
78+
// const httpOptions = createHttpOptions({ payload });
5979
if (!httpOptions) {
6080
reject({
6181
statusCode: 400,

lib/node/metrics.ts

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
import * as os from "os";
2+
import * as v8 from "v8";
3+
import { sendRuntimeMetrics } from "../core/http";
4+
5+
const sanitizePackageName = (pkg: string, pkgType: string) => {
6+
let targetKey = pkg.replace(pkgType, "").replace("__", "@");
7+
if (targetKey.includes("@")) {
8+
const [lib, pkg] = targetKey.split("_");
9+
targetKey = `${lib}/${pkg}`;
10+
}
11+
12+
targetKey = targetKey.replace("_", "").replace("_", "-");
13+
14+
return targetKey;
15+
};
16+
17+
const collectMetricsDataOnRuntime = () => {
18+
const traceoVersion =
19+
process.env["npm_package_dependencies_traceo"] ||
20+
process.env["npm_package_devDependencies_traceo"];
21+
22+
const packageEngineNode = process.env["npm_package_engines_node"];
23+
const packageName = process.env["npm_package_name"];
24+
const packageDescription = process.env["npm_package_description"];
25+
const packageVersion = process.env["npm_package_version"];
26+
27+
const dependencies = {};
28+
const devDependencies = {};
29+
const scripts = {};
30+
31+
for (const [key, value] of Object.entries(process.env)) {
32+
if (key?.startsWith("npm_package_dependencies_")) {
33+
const targetKey = sanitizePackageName(key, "npm_package_dependencies");
34+
dependencies[targetKey] = value;
35+
}
36+
37+
if (key?.startsWith("npm_package_devDependencies_")) {
38+
const targetKey = sanitizePackageName(key, "npm_package_devDependencies");
39+
devDependencies[targetKey] = value;
40+
}
41+
42+
if (key?.startsWith("npm_package_scripts_")) {
43+
const targetKey = key.replace("npm_package_scripts_", "");
44+
scripts[targetKey] = value;
45+
}
46+
}
47+
48+
const osDataToScrap = [
49+
"arch",
50+
"platform",
51+
"release",
52+
"version",
53+
"homedir",
54+
"tmpdir",
55+
"type",
56+
"hostname",
57+
];
58+
const osData = {};
59+
for (const [key, _] of Object.entries(os)) {
60+
if (osDataToScrap.includes(key)) {
61+
osData[key] = os[key]();
62+
}
63+
}
64+
65+
const heap = {};
66+
for (const [key, value] of Object.entries(v8.getHeapCodeStatistics())) {
67+
heap[key] = value;
68+
}
69+
70+
const heapStats = v8.getHeapStatistics();
71+
const heapStatistics = {
72+
heap_size_limit: heapStats.heap_size_limit,
73+
total_heap_size_executable: heapStats.total_heap_size_executable,
74+
total_physical_size: heapStats.total_physical_size,
75+
};
76+
77+
const nodeVersion = process.versions;
78+
79+
const data = {
80+
node: {
81+
...heap,
82+
...heapStatistics,
83+
...nodeVersion,
84+
},
85+
os: osData,
86+
scripts,
87+
dependencies,
88+
devDependencies,
89+
npm: {
90+
packageEngineNode,
91+
packageName,
92+
packageDescription,
93+
packageVersion,
94+
},
95+
traceo: {
96+
version: traceoVersion,
97+
},
98+
};
99+
100+
sendRuntimeMetrics(data);
101+
};
102+
103+
export const metrics = {
104+
collectMetricsDataOnRuntime,
105+
};

lib/node/middlewares.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import { stacktrace } from "stacktrace-parser-node";
2-
import { sendEvent } from "../core/http";
2+
import { sendEvent, sendIncidentEvent } from "../core/http";
33
import { isClientConnected, isLocalhost } from "../core/is";
44
import { TraceoError } from "../transport/base";
5-
import { TraceoEvent } from "../transport/events";
5+
import { Incident } from "../transport/events";
66
import { TraceoIncomingMessage, TraceoServerResponse } from "../transport/http";
77
import { ErrorMiddlewareOptions } from "../transport/options";
88
import { getIp, getOsPlatform, getProtocol } from "./helpers";
@@ -113,19 +113,19 @@ export const catchException = async (error: any, catchOptions?: Catch) => {
113113

114114
const handleException = async (error: TraceoError) => {
115115
try {
116-
const event: TraceoEvent = await prepareException(error);
117-
await sendEvent(event);
116+
const event: Incident = await prepareException(error);
117+
await sendIncidentEvent(event);
118118
} catch (err) {
119119
//
120120
}
121121
};
122122

123-
const prepareException = async (error: TraceoError): Promise<TraceoEvent> => {
123+
const prepareException = async (error: TraceoError): Promise<Incident> => {
124124
const { stack } = error;
125125
const platform = getOsPlatform();
126126

127127
const { message, name, traces } = await stacktrace.parse(error);
128-
const event: TraceoEvent = {
128+
const event: Incident = {
129129
type: name,
130130
message,
131131
traces,

lib/node/process.ts

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// const getCpuUsage = () => process.cpuUsage();
2+
3+
// const getMemoryUsage = () => process.memoryUsage();
4+
5+
// // The process.platform property returns a string identifying
6+
// // the operating system platform for which the Node.js binary was compiled
7+
// const osPlatform = process.platform;
8+
// const resourceUsage = process.resourceUsage();
9+
// const internalNodeVersions = process.versions;
10+
11+
// interface Envs {
12+
// traceo: string;
13+
// }
14+
15+
// interface Version {
16+
// node: string,
17+
// v8: string,
18+
// uv: string,
19+
// zlib: string,
20+
// brotli: string,
21+
// ares: string,
22+
// modules: string,
23+
// nghttp2: string,
24+
// napi: string,
25+
// llhttp: string,
26+
// openssl: string,
27+
// cldr: string,
28+
// icu: string,
29+
// tz: string,
30+
// unicode: string
31+
// }

lib/node/sdk.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { setGlobalClientData } from "../core/global";
22
import { isClientConnected } from "../core/is";
33
import { TraceoOptions } from "../transport/options";
4+
import { metrics } from "./metrics";
45

56
/**
67
*
@@ -27,4 +28,8 @@ export const init = (options: TraceoOptions): void => {
2728
...options,
2829
});
2930
}
31+
32+
metrics.collectMetricsDataOnRuntime();
3033
};
34+
35+
export const collectMetricsData = () => {};

lib/node/v8.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import * as v8 from "v8";
2+
3+
/**
4+
* https://www.geeksforgeeks.org/node-js-v8-getheapstatistics-method/
5+
*
6+
*/
7+
const getHeapStatistics = () => v8.getHeapStatistics();
8+
9+
const getUsedHeapSize = () => getHeapStatistics().used_heap_size;
10+
11+
const getNumberOfNativeContexts = () =>
12+
getHeapStatistics().number_of_native_contexts;
13+
14+
const getNumberOfDetachedContexts = () =>
15+
getHeapStatistics().number_of_detached_contexts;
16+
17+
export const v8Metrics = {
18+
usedHeapSize: getUsedHeapSize(),
19+
numberOfNativeContexts: getNumberOfNativeContexts(),
20+
numberOfDetachedContexts: getNumberOfDetachedContexts(),
21+
};

lib/transport/base.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import { Environment } from "./types";
22

33
export interface TraceoGlobal {
4-
dsn: string;
5-
appId?: string;
6-
environment: Environment;
4+
dsn?: string;
5+
appId?: number;
6+
environment?: Environment;
77
}
88

99
export interface TraceoError extends Error {}

lib/transport/events.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ export interface EventResponse {
77
body?: string;
88
}
99

10-
export interface TraceoEvent {
10+
export interface Incident {
1111
type: string;
1212
message: string;
1313
stack: string;

lib/transport/options.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ export interface TraceoOptions {
44
offline?: boolean;
55
environment: Environment;
66
dsn: string;
7+
appId: number;
78
}
89

910
export interface ErrorMiddlewareOptions {

0 commit comments

Comments
 (0)