ããã¯ããªã«ãããããŠæžãããã®ïŒ
Prometheusã®Node.jsåãã®ã¯ã©ã€ã¢ã³ãã©ã€ãã©ãªïŒãµãŒãããŒãã£è£œã®ãã®ã§ããïŒããããããªã®ã§ããã¡ããè©ŠããŠ
ã¿ããããšã
Prometheus client for node.js
ãã¡ãã®ã©ã€ãã©ãªã§ãã
GitHub - siimon/prom-client: Prometheus client for node.js
ãµãŒãããŒãã£è£œã§ãããPrometheusã®ããã¥ã¡ã³ãã«ãèšèŒããããŸãã
Client libraries | Prometheus
ãã¡ãã䜿ãããšã§ãNode.jsã¢ããªã±ãŒã·ã§ã³ã§ããPrometheusã§æ±ãã4çš®é¡ã®ã¡ããªã¯ã¹ïŒCounterãGauseãHistogramãSummaryïŒã
ç¬èªã«åºåãããããŸããã®ã©ã€ãã©ãªãããã©ã«ãã§Node.jsã©ã³ã¿ã€ã ãOSããååŸããã¡ããªã¯ã¹ããšã¯ã¹ããŒãã§ããããã«
ãªãããã§ãã
Prometheusã®ããŒã¿ã¢ãã«ããã¡ããªã¯ã¹ã®çš®é¡ã«ã€ããŠã¯ãã¡ãã
Data model | Prometheus
Metric types | Prometheus
ãã®ããã°ã§ã¯ã以åã«JVM Clientã䜿ã£ãæã«ãã®ãããã®çšèªã«ã€ããŠã¯æžããŠãããŸããã
PrometheusのJVM Clientを試してみる - CLOVER🍀
ããã§ããã®Node.jsã¯ã©ã€ã¢ã³ãã§ãããä»åã¯Expressãšäžç·ã«äœ¿ãããšæããŸãããšã¯ããããã®ã©ã€ãã©ãªã
ç¹ã«Webã¢ããªã±ãŒã·ã§ã³çšããšããããã§ã¯ãããŸãããRegistryã®ã¡ãœããã䜿ãããšã§ããã€ã§ãã¡ããªã¯ã¹ã
åºåããããšãã§ããŸãã
ããã§ã¯ã䜿ã£ãŠãã£ãŠã¿ãŸãããããé¡ã¯ã以åã«æžããJVM Clientã®ãµã³ãã«ã®ç°¡æçã«ããŸãã
ç°å¢
ä»åã®ç°å¢ã¯ããã¡ãã§ãã
$ node -v
v10.15.3
$ npm -v
6.4.1
Prometheus client for node.jsãã€ã³ã¹ããŒã«ã
$ npm i prom-client
Expressãã€ã³ã¹ããŒã«ããŸãã
$ npm i express
ã€ã³ã¹ããŒã«ãããããŒãžã§ã³ã¯ãã¡ãã
"dependencies": {
"express": "^4.16.4",
"prom-client": "^11.2.1"
},
ãµã³ãã«ããã°ã©ã
äœæããããã°ã©ã ã¯ããã¡ãã
server.js
const prometheusClient = require("prom-client");
const collectDefaultMetrics = prometheusClient.collectDefaultMetrics;
collectDefaultMetrics();
const express = require("express");
const app = express();
let counter = 0;
const callCounter = new prometheusClient.Counter({
name: "method_call_counter",
help: "counter for method call count",
labelNames: ["method", "path"]
});
const incRequestSummary = new prometheusClient.Summary({
name: "inc_request_summary",
help: "summary for inc method call summary",
});
app.get("/metrics", (req, res) => {
res.set("Content-Type", "text/plain");
res.send(prometheusClient.register.metrics());
});
app.get("/counter/current", (req, res) => {
callCounter.labels("inc", "/counter/current").inc();
res.send(`current counter = ${counter}`);
});
app.get("/counter/inc", (req, res) => {
const end = incRequestSummary.startTimer();
try {
counter++;
callCounter.labels("inc", "/counter/inc").inc();
res.send(`increment counter = ${counter}`);
} finally {
end();
}
});
app.listen(3000, () => console.log(`[${new Date()}] server startup.`));
ããã¥ã¡ã³ãã«æ²¿ã£ãŠãèŠãŠãããŸãã
API
å©çšããã¢ãžã¥ãŒã«ãrequireããŠãããŸãã
const prometheusClient = require("prom-client");
ãŸããããã©ã«ãã§å©çšã§ããã¡ããªã¯ã¹ãæå¹ã«ããŸãã
const collectDefaultMetrics = prometheusClient.collectDefaultMetrics;
collectDefaultMetrics();
ããã©ã«ãã§åéãããã¡ããªã¯ã¹ã¯ãæå¹ã«ããŠããããšãæšå¥šãããŠããŸãã
Default metrics
ããã§ããããããã©ã«ãã®ã¡ããªã¯ã¹ããšã¯ããã®ãããã§ããã
const metrics = {
processCpuTotal,
processStartTime,
osMemoryHeap,
processOpenFileDescriptors,
processMaxFileDescriptors,
eventLoopLag,
processHandles,
processRequests,
heapSizeAndUsed,
heapSpacesSizeAndUsed,
version
};
ã€ãã³ãã«ãŒããããã»ã¹ãã³ãã«ãNode.jsã®ããŒãžã§ã³ãªã©ãNode.jsåºæã®ã¡ããªã¯ã¹ãå«ãŸããŠããŸãã
https://github.com/siimon/prom-client/blob/v11.2.1/lib/defaultMetrics.js#L3-L13
https://github.com/siimon/prom-client/blob/v11.2.1/lib/defaultMetrics.js#L17-L29
ããã©ã«ãã®ã¡ããªã¯ã¹ã¯å®è¡ããéã«ãªãã·ã§ã³ãæå®ããããšãã§ããä»åã®ã³ã¡ã³ãã§ã¯ã¡ããªã¯ã¹ã®ååŸééã
ããŠãããµã³ãã«ã«ããŠããŸãããä»ã«ã¯ã¡ããªã¯ã¹ã®prefixãã¡ããªã¯ã¹ã®ç»é²å¯Ÿè±¡ã®Registryãæå®ãããã§ããããã§ãã
collectDefaultMetrics();
ã§ãä»åã¯Expressã䜿ãã€ã€ãã«ãŠã³ã¿ãŒãçšæããŠã«ãŠã³ãã¢ããããAPIãšçŸåšã®ã«ãŠã³ã¿ãŒã®å€ãååŸããAPIã
çšæããŠã¿ãŸãããã
app.get("/counter/current", (req, res) => {
callCounter.labels("inc", "/counter/current").inc();
res.send(`current counter = ${counter}`);
});
app.get("/counter/inc", (req, res) => {
const end = incRequestSummary.startTimer();
try {
counter++;
callCounter.labels("inc", "/counter/inc").inc();
res.send(`increment counter = ${counter}`);
} finally {
end();
}
});
ãã®æãã¡ããªã¯ã¹ãç»é²ããŠããããã«ããŸããä»åã¯ãCounterãšSummaryã®2ã€ã䜿çšããŸããã
let counter = 0;
const callCounter = new prometheusClient.Counter({
name: "method_call_counter",
help: "counter for method call count",
labelNames: ["method", "path"]
});
const incRequestSummary = new prometheusClient.Summary({
name: "inc_request_summary",
help: "summary for inc method call summary",
});
Counter
Summary
Counterã¯çšæãã2ã€ã®ã¡ãœããåŒã³åºãã®åæ°ããã©ãã«ã䜿ãã€ã€èšé²ããŸããSummaryã¯ã«ãŠã³ãã¢ããã®ã¿ã察象ã«ã
ã©ãã«ã¯ãªãã§äœ¿ããŸãã
ã©ãã«ã䜿ãå Žåã¯ããã®ããã«labelsã¡ãœãããä»ããŠç®çã®ã¡ãœãããåŒã³åºããŸãïŒCounterãªãincãªã©ïŒã
app.get("/counter/current", (req, res) => {
callCounter.labels("inc", "/counter/current").inc();
res.send(`current counter = ${counter}`);
});
ãŸããããã¥ã¡ã³ããèŠããšå€ã®èšå®ãšãšãã«ã©ãã«ãæå®ããããšãã§ããããã§ããã
Labels
Summaryã¯startïŒendæ¹åŒã®ããã§ããã©ãã«ã¯äœ¿ã£ãŠããŸããã
â»äžç·ã«Counterã䜿ã£ãŠããŸãã
app.get("/counter/inc", (req, res) => {
const end = incRequestSummary.startTimer();
try {
counter++;
callCounter.labels("inc", "/counter/inc").inc();
res.send(`increment counter = ${counter}`);
} finally {
end();
}
});
ä»ã«ãSummary#observeãªã©ããã®ã§ãããã¥ã¡ã³ããåç
§ããŠã¿ãŠãã ããã
Summary
ç»é²ããŠããã¡ããªã¯ã¹ã®åºåã«ã¯ãRegistry#metricsã¡ãœããã䜿ããŸãã
ä»åã¯ãExpressã䜿ã£ãŠãšã³ããã€ã³ããèšããŸããã
app.get("/metrics", (req, res) => {
res.set("Content-Type", "text/plain");
res.send(prometheusClient.register.metrics());
});
ããšã¯ããã®ã¯ã©ã¹ããnpm startãã§èµ·åã§ããããã«ããŸãããã
"scripts": {
"start": "node server.js",
"test": "echo \"Error: no test specified\" && exit 1"
},
ããã§ããµã³ãã«ããã°ã©ã ã®æºåã¯å®äºã§ãã
確èª
ãšãããããèµ·åããŠã¿ãŸãã
$ npm start
ãŸãã¯ãã¡ããªã¯ã¹ãååŸããŠã¿ãŸãã
$ curl localhost:3000/metrics
$ curl localhost:3000/metrics
# HELP process_cpu_user_seconds_total Total user CPU time spent in seconds.
# TYPE process_cpu_user_seconds_total counter
process_cpu_user_seconds_total 0.001038 1552119478037
# HELP process_cpu_system_seconds_total Total system CPU time spent in seconds.
# TYPE process_cpu_system_seconds_total counter
process_cpu_system_seconds_total 0.00026 1552119478037
# HELP process_cpu_seconds_total Total user and system CPU time spent in seconds.
# TYPE process_cpu_seconds_total counter
process_cpu_seconds_total 0.001298 1552119478037
# HELP process_start_time_seconds Start time of the process since unix epoch in seconds.
# TYPE process_start_time_seconds gauge
process_start_time_seconds 1552119478
# HELP process_resident_memory_bytes Resident memory size in bytes.
# TYPE process_resident_memory_bytes gauge
process_resident_memory_bytes 41758720 1552119478090
ãçç¥ã
# HELP method_call_counter counter for method call count
# TYPE method_call_counter counter
# HELP inc_request_summary summary for inc method call summary
# TYPE inc_request_summary summary
inc_request_summary{quantile="0.01"} 0
inc_request_summary{quantile="0.05"} 0
inc_request_summary{quantile="0.5"} 0
inc_request_summary{quantile="0.9"} 0
inc_request_summary{quantile="0.95"} 0
inc_request_summary{quantile="0.99"} 0
inc_request_summary{quantile="0.999"} 0
inc_request_summary_sum 0
inc_request_summary_count 0
ãããããã£ã€ããŠããŸãããæåŸã«èªåãç»é²ããã¡ããªã¯ã¹ããã§ã«äžéšèŠããŠããŸãã
ããã©ã«ãã®ã¡ããªã¯ã¹ã®æåŸã«ã€ããŠããæ°åã§ãããããã¯å€ãèšå®ããéã®ã¿ã€ã ã¹ã¿ã³ãã§ãã
Timestamps
ããã¯ãèªåã§äœæããã¡ããªã¯ã¹ã«ãèšé²ããããšãã§ããŸãïŒæ瀺çã«æå®ãå¿
èŠã§ãä»åã¯æå®ããŠããŸããïŒã
Register#metricsãåŒã³åºãéã«ãã¿ã€ã ã¹ã¿ã³ããåºåããªãããã«ããããšãã§ããããã§ãã
Register
ããã§ã¯ãä»åäœæããAPIãåŒã³åºããŠã¿ãŸãããã
$ curl localhost:3000/counter/inc
increment counter = 1
$ curl localhost:3000/counter/inc
increment counter = 2
$ curl localhost:3000/counter/inc
increment counter = 3
$ curl localhost:3000/counter/current
current counter = 3
$ curl localhost:3000/counter/inc
increment counter = 4
$ curl localhost:3000/counter/inc
increment counter = 5
$ curl localhost:3000/counter/inc
increment counter = 6
$ curl localhost:3000/counter/current
current counter = 6
ã/counter/incãã6åãã/counter/currentãã2ååŒã³åºããŠã¿ãŸããã
ã¡ããªã¯ã¹ãååŸããŠã¿ãŸãã
$ curl localhost:3000/metrics
ãçç¥ã
# HELP method_call_counter counter for method call count
# TYPE method_call_counter counter
method_call_counter{method="inc",path="/counter/inc"} 6
method_call_counter{method="inc",path="/counter/current"} 2
# HELP inc_request_summary summary for inc method call summary
# TYPE inc_request_summary summary
inc_request_summary{quantile="0.01"} 0.000247481
inc_request_summary{quantile="0.05"} 0.000247481
inc_request_summary{quantile="0.5"} 0.000328285
inc_request_summary{quantile="0.9"} 0.002689974700000001
inc_request_summary{quantile="0.95"} 0.002912271
inc_request_summary{quantile="0.99"} 0.002912271
inc_request_summary{quantile="0.999"} 0.002912271
inc_request_summary_sum 0.004805055
inc_request_summary_count 6
ä»åäœæããCounterã§ã¯ãåã¡ãœããã®åŒã³åºãåæ°ãã©ãã«ãšãšãã«è¡šç€ºãã
method_call_counter{method="inc",path="/counter/inc"} 6
method_call_counter{method="inc",path="/counter/current"} 2
Summaryã§ã¯åŒã³åºãåæ°ãšåäœæ°ïŒquantileïŒã衚瀺ãããŠããŸãã
inc_request_summary{quantile="0.01"} 0.000247481
inc_request_summary{quantile="0.05"} 0.000247481
inc_request_summary{quantile="0.5"} 0.000328285
inc_request_summary{quantile="0.9"} 0.002689974700000001
inc_request_summary{quantile="0.95"} 0.002912271
inc_request_summary{quantile="0.99"} 0.002912271
inc_request_summary{quantile="0.999"} 0.002912271
inc_request_summary_sum 0.004805055
inc_request_summary_count 6
ãŸãšã
ä»åã¯ãPrometheusã®Node.jsåãã®ã¯ã©ã€ã¢ã³ãïŒPrometheus client for node.jsïŒãè©ŠããŠã¿ãŸããã
ã¡ããªã¯ã¹ã®åºåæ¹æ³ãæåãããã«ããããªïŒãšæã£ããããã§ãæ±ã£ãŠããæŠå¿µã¯Prometheusã®ãã®ãªã®ã§ããã»ã©èŠåŽãã
䜿ããŸããã
ããã§ãNode.jsã¢ããªã±ãŒã·ã§ã³ã§ãPrometheusåãã«ã¡ããªã¯ã¹ããšã¯ã¹ããŒãã§ããããã«ãªããŸãããã