@voltro/plugin-prometheus 0.1.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/CHANGELOG.md +52 -0
- package/LICENSE +57 -0
- package/README.md +26 -0
- package/SECURITY.md +56 -0
- package/THIRD-PARTY-NOTICES.md +4596 -0
- package/dist/index.d.ts +28 -0
- package/dist/index.js +121 -0
- package/package.json +45 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { MetricSample } from '@voltro/runtime';
|
|
2
|
+
import { VoltroPlugin } from '@voltro/protocol';
|
|
3
|
+
|
|
4
|
+
/** Render MetricSample[] to Prometheus text. Samples are grouped by name so
|
|
5
|
+
* each family emits exactly one HELP + TYPE header. */
|
|
6
|
+
export declare const formatPrometheus: (samples: ReadonlyArray<MetricSample>) => string;
|
|
7
|
+
|
|
8
|
+
export declare const processMetrics: (version?: string) => ReadonlyArray<MetricSample>;
|
|
9
|
+
|
|
10
|
+
export declare const prometheusPlugin: (options?: PrometheusPluginOptions) => VoltroPlugin;
|
|
11
|
+
|
|
12
|
+
export declare interface PrometheusPluginOptions {
|
|
13
|
+
/** Scrape path. Default `/metrics`. */
|
|
14
|
+
readonly path?: string;
|
|
15
|
+
/** Require `Authorization: Bearer <token>` (Prometheus `bearer_token`).
|
|
16
|
+
* Default `PROMETHEUS_TOKEN` env; unset → open (gate at the network layer). */
|
|
17
|
+
readonly token?: string;
|
|
18
|
+
/** Include node `process_*` metrics. Default true. */
|
|
19
|
+
readonly processMetrics?: boolean;
|
|
20
|
+
/** Value for the `voltro_build_info{version}` gauge. */
|
|
21
|
+
readonly version?: string;
|
|
22
|
+
/** Disambiguates multiple plugin instances within one process (suffixes the
|
|
23
|
+
* plugin name). Does NOT identify replicas — replica identity comes from
|
|
24
|
+
* the Prometheus scrape target (`instance` label). */
|
|
25
|
+
readonly name?: string;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export { }
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import { Effect as e } from "effect";
|
|
2
|
+
import { definePlugin as t } from "@voltro/protocol";
|
|
3
|
+
import { checkBearer as n } from "@voltro/protocol/session";
|
|
4
|
+
import { snapshotMetrics as r } from "@voltro/runtime";
|
|
5
|
+
import { pluginEnv as i } from "@voltro/env";
|
|
6
|
+
//#region src/format.ts
|
|
7
|
+
var a = (e) => e.replace(/\\/g, "\\\\").replace(/\n/g, "\\n").replace(/"/g, "\\\""), o = (e, t) => {
|
|
8
|
+
let n = {
|
|
9
|
+
...e,
|
|
10
|
+
...t
|
|
11
|
+
}, r = Object.keys(n);
|
|
12
|
+
return r.length === 0 ? "" : "{" + r.map((e) => `${e}="${a(String(n[e]))}"`).join(",") + "}";
|
|
13
|
+
}, s = (e) => Number.isFinite(e) ? String(e) : e > 0 ? "+Inf" : "-Inf", c = {
|
|
14
|
+
counter: "counter",
|
|
15
|
+
gauge: "gauge",
|
|
16
|
+
histogram: "histogram",
|
|
17
|
+
summary: "summary",
|
|
18
|
+
frequency: "gauge"
|
|
19
|
+
}, l = (e, t) => {
|
|
20
|
+
switch (e.type) {
|
|
21
|
+
case "counter":
|
|
22
|
+
case "gauge":
|
|
23
|
+
t.push(`${e.name}${o(e.labels)} ${s(e.value ?? 0)}`);
|
|
24
|
+
break;
|
|
25
|
+
case "histogram":
|
|
26
|
+
for (let n of e.buckets ?? []) t.push(`${e.name}_bucket${o(e.labels, { le: s(n.le) })} ${s(n.count)}`);
|
|
27
|
+
t.push(`${e.name}_bucket${o(e.labels, { le: "+Inf" })} ${s(e.count ?? 0)}`), t.push(`${e.name}_sum${o(e.labels)} ${s(e.sum ?? 0)}`), t.push(`${e.name}_count${o(e.labels)} ${s(e.count ?? 0)}`);
|
|
28
|
+
break;
|
|
29
|
+
case "summary":
|
|
30
|
+
for (let n of e.quantiles ?? []) t.push(`${e.name}${o(e.labels, { quantile: s(n.quantile) })} ${s(n.value)}`);
|
|
31
|
+
t.push(`${e.name}_sum${o(e.labels)} ${s(e.sum ?? 0)}`), t.push(`${e.name}_count${o(e.labels)} ${s(e.count ?? 0)}`);
|
|
32
|
+
break;
|
|
33
|
+
case "frequency":
|
|
34
|
+
for (let [n, r] of Object.entries(e.occurrences ?? {})) t.push(`${e.name}${o(e.labels, { bucket: n })} ${s(r)}`);
|
|
35
|
+
break;
|
|
36
|
+
}
|
|
37
|
+
}, u = (e) => {
|
|
38
|
+
let t = /* @__PURE__ */ new Map();
|
|
39
|
+
for (let n of e) {
|
|
40
|
+
let e = t.get(n.name);
|
|
41
|
+
e ? e.push(n) : t.set(n.name, [n]);
|
|
42
|
+
}
|
|
43
|
+
let n = [];
|
|
44
|
+
for (let [e, r] of t) {
|
|
45
|
+
let t = r[0], i = t.description ?? e;
|
|
46
|
+
n.push(`# HELP ${e} ${i.replace(/\\/g, "\\\\").replace(/\n/g, " ")}`), n.push(`# TYPE ${e} ${c[t.type]}`);
|
|
47
|
+
for (let e of r) l(e, n);
|
|
48
|
+
}
|
|
49
|
+
return n.join("\n") + "\n";
|
|
50
|
+
}, d = (e) => {
|
|
51
|
+
let t = process.memoryUsage(), n = process.cpuUsage(), r = [
|
|
52
|
+
{
|
|
53
|
+
name: "process_resident_memory_bytes",
|
|
54
|
+
type: "gauge",
|
|
55
|
+
labels: {},
|
|
56
|
+
value: t.rss,
|
|
57
|
+
description: "Resident memory size in bytes."
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
name: "process_heap_bytes",
|
|
61
|
+
type: "gauge",
|
|
62
|
+
labels: {},
|
|
63
|
+
value: t.heapUsed,
|
|
64
|
+
description: "Used V8 heap size in bytes."
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
name: "process_cpu_seconds_total",
|
|
68
|
+
type: "counter",
|
|
69
|
+
labels: {},
|
|
70
|
+
value: (n.user + n.system) / 1e6,
|
|
71
|
+
description: "Total user + system CPU time spent in seconds."
|
|
72
|
+
}
|
|
73
|
+
];
|
|
74
|
+
return e && r.push({
|
|
75
|
+
name: "voltro_build_info",
|
|
76
|
+
type: "gauge",
|
|
77
|
+
labels: { version: e },
|
|
78
|
+
value: 1,
|
|
79
|
+
description: "Voltro build info (constant 1, version in the label)."
|
|
80
|
+
}), r;
|
|
81
|
+
}, f = "text/plain; version=0.0.4; charset=utf-8", p = i([{
|
|
82
|
+
name: "PROMETHEUS_TOKEN",
|
|
83
|
+
required: !1,
|
|
84
|
+
secret: !0,
|
|
85
|
+
description: "Bearer token required on the scrape endpoint; unset leaves /metrics open."
|
|
86
|
+
}]), m = (i = {}) => {
|
|
87
|
+
let a = i.path ?? "/metrics", o = p.read("PROMETHEUS_TOKEN", i.token), s = i.processMetrics ?? !0, c = {
|
|
88
|
+
method: "GET",
|
|
89
|
+
path: a,
|
|
90
|
+
handle: async (t) => {
|
|
91
|
+
if (!n(t.headers, o)) return {
|
|
92
|
+
status: 401,
|
|
93
|
+
body: "unauthorized",
|
|
94
|
+
contentType: "text/plain"
|
|
95
|
+
};
|
|
96
|
+
let a = await e.runPromise(r);
|
|
97
|
+
return {
|
|
98
|
+
status: 200,
|
|
99
|
+
body: u(s ? [...a, ...d(i.version)] : a),
|
|
100
|
+
contentType: f,
|
|
101
|
+
headers: { "cache-control": "no-store" }
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
};
|
|
105
|
+
return t({
|
|
106
|
+
name: i.name ? `@voltro/plugin-prometheus#${i.name}` : "@voltro/plugin-prometheus",
|
|
107
|
+
description: "Prometheus exporter — scrapes the unified Metrics-API at a /metrics endpoint in text exposition format.",
|
|
108
|
+
declaredEnv: p.declared,
|
|
109
|
+
httpRoutes: [c],
|
|
110
|
+
onActivate: (t) => e.sync(() => {
|
|
111
|
+
t.logger.info("prometheus exporter active", {
|
|
112
|
+
path: a,
|
|
113
|
+
tokenGated: !!o,
|
|
114
|
+
processMetrics: s
|
|
115
|
+
});
|
|
116
|
+
}),
|
|
117
|
+
onDeactivate: () => e.void
|
|
118
|
+
});
|
|
119
|
+
};
|
|
120
|
+
//#endregion
|
|
121
|
+
export { u as formatPrometheus, d as processMetrics, m as prometheusPlugin };
|
package/package.json
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@voltro/plugin-prometheus",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Prometheus exporter — scrapes the framework's unified Metrics-API (Effect MetricRegistry) at GET /metrics in Prometheus text exposition format. Counters, histograms (with buckets), gauges + custom metrics; optional bearer-token gate + node process metrics.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"voltro",
|
|
7
|
+
"typescript",
|
|
8
|
+
"framework"
|
|
9
|
+
],
|
|
10
|
+
"license": "SEE LICENSE IN LICENSE",
|
|
11
|
+
"homepage": "https://voltro.dev",
|
|
12
|
+
"bugs": {
|
|
13
|
+
"email": "support@voltro.dev"
|
|
14
|
+
},
|
|
15
|
+
"author": {
|
|
16
|
+
"name": "Voltro UG",
|
|
17
|
+
"url": "https://voltro.dev"
|
|
18
|
+
},
|
|
19
|
+
"type": "module",
|
|
20
|
+
"exports": {
|
|
21
|
+
".": {
|
|
22
|
+
"types": "./dist/index.d.ts",
|
|
23
|
+
"import": "./dist/index.js",
|
|
24
|
+
"default": "./dist/index.js"
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
"main": "./dist/index.js",
|
|
28
|
+
"module": "./dist/index.js",
|
|
29
|
+
"types": "./dist/index.d.ts",
|
|
30
|
+
"sideEffects": false,
|
|
31
|
+
"engines": {
|
|
32
|
+
"node": ">=24.0.0"
|
|
33
|
+
},
|
|
34
|
+
"dependencies": {
|
|
35
|
+
"@voltro/env": "0.1.0",
|
|
36
|
+
"@voltro/protocol": "0.1.0",
|
|
37
|
+
"@voltro/runtime": "0.1.0"
|
|
38
|
+
},
|
|
39
|
+
"peerDependencies": {
|
|
40
|
+
"effect": "^3.21.4"
|
|
41
|
+
},
|
|
42
|
+
"publishConfig": {
|
|
43
|
+
"access": "public"
|
|
44
|
+
}
|
|
45
|
+
}
|