Skip to content

Commit

Permalink
feat: export SwingSet metrics to Prometheus via local HTTP port
Browse files Browse the repository at this point in the history
Run: `AG_CHAIN_COSMOS_PROMETHEUS=9464 ag-chain-cosmos start`
to export via http://localhost:9464/metrics
  • Loading branch information
michaelfig committed Feb 9, 2021
1 parent 94e0078 commit 78160fe
Show file tree
Hide file tree
Showing 5 changed files with 264 additions and 0 deletions.
23 changes: 23 additions & 0 deletions packages/cosmic-swingset/lib/chain-main.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ import {
exportMailbox,
} from '@agoric/swingset-vat/src/devices/mailbox';

import { MeterProvider } from '@opentelemetry/metrics';
import { PrometheusExporter } from '@opentelemetry/exporter-prometheus';

import { launch } from './launch-chain';
import makeBlockManager from './block-manager';

Expand Down Expand Up @@ -220,12 +223,32 @@ export default async function main(progname, args, { path, env, agcc }) {
ROLE: 'chain',
noFakeCurrencies: process.env.NO_FAKE_CURRENCIES,
};
let meterProvider;
if (process.env.AG_CHAIN_COSMOS_PROMETHEUS) {
const port =
Number(process.env.AG_CHAIN_COSMOS_PROMETHEUS) ||
PrometheusExporter.DEFAULT_OPTIONS.port;
const exporter = new PrometheusExporter(
{
startServer: true,
port,
},
() => {
console.log(
`prometheus scrape endpoint: http://localhost:${port}${PrometheusExporter.DEFAULT_OPTIONS.endpoint}`,
);
},
);
meterProvider = new MeterProvider({ exporter, interval: 1000 });
}
const s = await launch(
stateDBDir,
mailboxStorage,
doOutboundBridge,
vatsdir,
argv,
undefined,
meterProvider,
);
return s;
}
Expand Down
150 changes: 150 additions & 0 deletions packages/cosmic-swingset/lib/kernel-stats.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
// All the kernel metrics we are prepared for.
const KERNEL_STATS_SUM_METRICS = [
{
key: 'syscalls',
name: 'syscall_total',
description: 'Total number of SwingSet kernel calls',
},
{
key: 'syscallSend',
name: 'syscall_send_total',
description: 'Total number of SwingSet message send kernel calls',
},
{
key: 'syscallCallNow',
name: 'syscall_call_now_total',
description: 'Total number of SwingSet synchronous device kernel calls',
},
{
key: 'syscallSubscribe',
name: 'syscall_subscribe_total',
description: 'Total number of SwingSet promise subscription kernel calls',
},
{
key: 'syscallResolve',
name: 'syscall_resolve_total',
description: 'Total number of SwingSet promise resolution kernel calls',
},
{
key: 'dispatches',
name: 'dispatch_total',
description: 'Total number of SwingSet vat calls',
},
{
key: 'dispatchDeliver',
name: 'dispatch_deliver_total',
description: 'Total number of SwingSet vat message deliveries',
},
{
key: 'dispatchNotify',
name: 'dispatch_notify_total',
description: 'Total number of SwingSet vat promise notifications',
},
];

const KERNEL_STATS_UPDOWN_METRICS = [
{
key: 'kernelObjects',
name: 'swingset_kernel_objects',
description: 'Active kernel objects',
},
{
key: 'kernelDevices',
name: 'swingset_kernel_devices',
description: 'Active kernel devices',
},
{
key: 'kernelPromises',
name: 'swingset_kernel_promises',
description: 'Active kernel promises',
},
{
key: 'kpUnresolved',
name: 'swingset_unresolved_kernel_promises',
description: 'Unresolved kernel promises',
},
{
key: 'kpFulfilledToPresence',
name: 'swingset_presence_kernel_promises',
description: 'Kernel promises fulfilled to presences',
},
{
key: 'kpFulfilledToData',
name: 'swingset_data_kernel_promises',
description: 'Kernel promises fulfilled to data',
},
{
key: 'kpRejected',
name: 'swingset_rejected_kernel_promises',
description: 'Rejected kernel promises',
},
{
key: 'runQueueLength',
name: 'swingset_run_queue_length',
description: 'Length of the kernel run queue',
},
{
key: 'clistEntries',
name: 'clist_entries',
description: 'Number of entries in the kernel c-list',
},
];

/**
* @param {Object} param0
* @param {any} param0.controller
* @param {import('@opentelemetry/metrics').Meter} param0.metricMeter
* @param {Console} param0.log
*/
export function exportKernelStats({ controller, metricMeter, log = console }) {
const kernelStatsMetrics = new Map();
const expectedKernelStats = new Set();

KERNEL_STATS_SUM_METRICS.forEach(({ key, name, ...options }) => {
expectedKernelStats.add(key);
kernelStatsMetrics.set(key, metricMeter.createSumObserver(name, options));
});

KERNEL_STATS_UPDOWN_METRICS.forEach(({ key, name, ...options }) => {
expectedKernelStats.add(key);
expectedKernelStats.add(`${key}Up`);
expectedKernelStats.add(`${key}Down`);
expectedKernelStats.add(`${key}Max`);
kernelStatsMetrics.set(
key,
metricMeter.createUpDownSumObserver(name, options),
);
});

function warnUnexpectedKernelStat(key) {
if (!expectedKernelStats.has(key)) {
log.warn(`Unexpected SwingSet kernel statistic`, key);
expectedKernelStats.add(key);
}
}

function checkKernelStats(stats) {
const notYetFoundKernelStats = new Set(kernelStatsMetrics.keys());
Object.keys(stats).forEach(key => {
notYetFoundKernelStats.delete(key);
warnUnexpectedKernelStat(key);
});
notYetFoundKernelStats.forEach(key => {
log.warn(`Expected SwingSet kernel statistic`, key, `not found`);
});
}

// We check everything on initialization. Other checks happen when scraping.
checkKernelStats(controller.getStats());
metricMeter.createBatchObserver(batchObserverResult => {
const observations = [];
Object.entries(controller.getStats()).forEach(([key, value]) => {
warnUnexpectedKernelStat(key);
if (kernelStatsMetrics.has(key)) {
const metric = kernelStatsMetrics.get(key);
observations.push(metric.observation(value));
}
});
batchObserverResult.observe({ app: 'ag-chain-cosmos' }, observations);
});
}
8 changes: 8 additions & 0 deletions packages/cosmic-swingset/lib/launch-chain.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import path from 'path';
import anylogger from 'anylogger';

import { MeterProvider } from '@opentelemetry/metrics';

import {
buildMailbox,
buildMailboxStateMap,
Expand All @@ -13,6 +15,7 @@ import {
loadSwingsetConfigFile,
} from '@agoric/swingset-vat';
import { getBestSwingStore } from './check-lmdb';
import { exportKernelStats } from './kernel-stats';

const log = anylogger('launch-chain');

Expand Down Expand Up @@ -75,6 +78,7 @@ export async function launch(
vatsDir,
argv,
debugName = undefined,
meterProvider = new MeterProvider(),
) {
log.info('Launching SwingSet kernel');

Expand All @@ -96,6 +100,10 @@ export async function launch(
debugName,
);

// Not to be confused with the gas model, this meter is for OpenTelemetry.
const metricMeter = meterProvider.getMeter('ag-chain-cosmos');
exportKernelStats({ controller, metricMeter, log });

// ////////////////////////////
// TODO: This is where we would add the scheduler.
async function endBlock(_blockHeight, _blockTime) {
Expand Down
2 changes: 2 additions & 0 deletions packages/cosmic-swingset/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@
"@agoric/zoe": "^0.11.0",
"@babel/generator": "^7.6.4",
"@iarna/toml": "^2.2.3",
"@opentelemetry/exporter-prometheus": "^0.16.0",
"@opentelemetry/metrics": "^0.16.0",
"agoric": "^0.11.0",
"anylogger": "^0.21.0",
"chalk": "^2.4.2",
Expand Down
81 changes: 81 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1340,6 +1340,63 @@
dependencies:
"@types/node" ">= 8"

"@opentelemetry/api-metrics@^0.16.0":
version "0.16.0"
resolved "https://registry.yarnpkg.com/@opentelemetry/api-metrics/-/api-metrics-0.16.0.tgz#c9aae4b2ac1df11ff8671263739b5e1759b43434"
integrity sha512-Wzq2q+ebXNCYbDg3NCTFK9LrqOGYWwl8t6uWyGPRP+YtD6nrxD20QO1EY5DJ8F4Udw4IWfda/gv9G7FoyCpIyg==
dependencies:
"@opentelemetry/api" "^0.16.0"

"@opentelemetry/api@^0.16.0":
version "0.16.0"
resolved "https://registry.yarnpkg.com/@opentelemetry/api/-/api-0.16.0.tgz#bd89460626013fc2cc7702e51ebd537ee84350e9"
integrity sha512-y5mNFAiktm7Zyf0GrQ6kjsRqace/WCXk9gMo/sOOna4TtMW8NaZgJceKrsQZl3qiPY9Upu8O9VvdlETXDx4U5A==
dependencies:
"@opentelemetry/context-base" "^0.16.0"

"@opentelemetry/context-base@^0.16.0":
version "0.16.0"
resolved "https://registry.yarnpkg.com/@opentelemetry/context-base/-/context-base-0.16.0.tgz#f41ca27221f31247e8bccfdde87a5cbfd9b57679"
integrity sha512-2h2s+3P40wIu8ZaJiqBF6E0rEJPeSVOErFlkx2MfRGPs9Vs9Th+i5YSpgvCW4s5LeYTFAf2BRwut39JivEyH9w==

"@opentelemetry/core@^0.16.0":
version "0.16.0"
resolved "https://registry.yarnpkg.com/@opentelemetry/core/-/core-0.16.0.tgz#8423eb9a828b76653137447ddcd00641f1beffc1"
integrity sha512-NFZwEW5TeFIAUlNty9al0KU9AQzpEiBowem/33d3ftxYHZ7dG1JklFnyKLTVb+pAZFm/peTziVddfHoTsIY4Rg==
dependencies:
"@opentelemetry/api" "^0.16.0"
"@opentelemetry/context-base" "^0.16.0"
semver "^7.1.3"

"@opentelemetry/exporter-prometheus@^0.16.0":
version "0.16.0"
resolved "https://registry.yarnpkg.com/@opentelemetry/exporter-prometheus/-/exporter-prometheus-0.16.0.tgz#2623568ba520975d9441b5047f9c48554005efb6"
integrity sha512-iRgXovkl9TlJS5l8y3Mdm0bk6q4y1iluYJ0ujoKtJUHrxli23qLwC952/An1iDmWAiLt3a8C0s3wfnty4Xc4Zg==
dependencies:
"@opentelemetry/api" "^0.16.0"
"@opentelemetry/api-metrics" "^0.16.0"
"@opentelemetry/core" "^0.16.0"
"@opentelemetry/metrics" "^0.16.0"

"@opentelemetry/metrics@^0.16.0":
version "0.16.0"
resolved "https://registry.yarnpkg.com/@opentelemetry/metrics/-/metrics-0.16.0.tgz#783b766fa3ef332762869a50bdd2e12abb119404"
integrity sha512-Qpzy+qDyJeR6rIzyzfTpDX5Jh1MXRL785ctmY2c1kmRnk0pm+waw5BDkZM0l/B3YsshVlLKTTw0GPBLml7VXtQ==
dependencies:
"@opentelemetry/api" "^0.16.0"
"@opentelemetry/api-metrics" "^0.16.0"
"@opentelemetry/core" "^0.16.0"
"@opentelemetry/resources" "^0.16.0"
lodash.merge "^4.6.2"

"@opentelemetry/resources@^0.16.0":
version "0.16.0"
resolved "https://registry.yarnpkg.com/@opentelemetry/resources/-/resources-0.16.0.tgz#40d3737545e4cae8b9c46b42acac041711bda2bd"
integrity sha512-HOAmcRnZGbEhcddsjqvz3Q/mEg75PyEoH/CZZ3YGqYmwTPimTiusm8iz5nXMxp1UpT8rkzlEGei/E21SQ/Zh9g==
dependencies:
"@opentelemetry/api" "^0.16.0"
"@opentelemetry/core" "^0.16.0"

"@polka/url@^1.0.0-next.9":
version "1.0.0-next.11"
resolved "https://registry.yarnpkg.com/@polka/url/-/url-1.0.0-next.11.tgz#aeb16f50649a91af79dbe36574b66d0f9e4d9f71"
Expand Down Expand Up @@ -6241,6 +6298,11 @@ lodash.memoize@^4.1.2:
resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe"
integrity sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=

lodash.merge@^4.6.2:
version "4.6.2"
resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a"
integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==

lodash.set@^4.3.2:
version "4.3.2"
resolved "https://registry.yarnpkg.com/lodash.set/-/lodash.set-4.3.2.tgz#d8757b1da807dde24816b0d6a84bea1a76230b23"
Expand Down Expand Up @@ -6325,6 +6387,13 @@ lru-cache@^5.1.1:
dependencies:
yallist "^3.0.2"

lru-cache@^6.0.0:
version "6.0.0"
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94"
integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==
dependencies:
yallist "^4.0.0"

macos-release@^2.2.0:
version "2.3.0"
resolved "https://registry.yarnpkg.com/macos-release/-/macos-release-2.3.0.tgz#eb1930b036c0800adebccd5f17bc4c12de8bb71f"
Expand Down Expand Up @@ -9100,6 +9169,13 @@ semver@^6.0.0, semver@^6.1.2, semver@^6.2.0, semver@^6.3.0:
resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d"
integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==

semver@^7.1.3:
version "7.3.4"
resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.4.tgz#27aaa7d2e4ca76452f98d3add093a72c943edc97"
integrity sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw==
dependencies:
lru-cache "^6.0.0"

semver@^7.3.2:
version "7.3.2"
resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.2.tgz#604962b052b81ed0786aae84389ffba70ffd3938"
Expand Down Expand Up @@ -10976,6 +11052,11 @@ yallist@^3.0.0, yallist@^3.0.2, yallist@^3.0.3:
resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd"
integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==

yallist@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72"
integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==

yargs-parser@^10.0.0:
version "10.1.0"
resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-10.1.0.tgz#7202265b89f7e9e9f2e5765e0fe735a905edbaa8"
Expand Down

0 comments on commit 78160fe

Please sign in to comment.