Compare commits

1 Commits

Author SHA1 Message Date
Iain Sproat 7a983d2f3c WIP: broken imports; f'd up tsconfig & eslint; some prototypes of functionality 2024-07-05 12:56:42 +01:00
17 changed files with 529 additions and 1084 deletions
+9 -5
View File
@@ -1,10 +1,14 @@
root = true
[*]
end_of_line = lf
insert_final_newline = true
[*.{js,json,yml}]
charset = utf-8
indent_style = space
indent_size = 2
charset = utf-8
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
spaces_around_brackets = both
[*.py]
indent_style = space
indent_size = 4
+1
View File
@@ -6,6 +6,7 @@ yarn-debug.log*
yarn-error.log*
lerna-debug.log*
.pnpm-debug.log*
.yarn
# Diagnostic reports (https://nodejs.org/api/report.html)
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
+65 -4
View File
@@ -1,11 +1,72 @@
import globals from 'globals'
import pluginJs from '@eslint/js'
import tseslint from 'typescript-eslint'
import prettierConfig from 'eslint-config-prettier'
import { fileURLToPath } from 'url'
import { dirname } from 'path'
export const getESMDirname = (importMetaUrl) => {
return dirname(fileURLToPath(importMetaUrl))
}
export default [
{ files: ['**/*.{js,ts}'] },
{ languageOptions: { globals: globals.browser } },
{
files: ['**/*.mjs'],
languageOptions: {
ecmaVersion: 2022,
sourceType: 'module'
}
},
{
files: ['**/*.cjs'],
languageOptions: {
sourceType: 'commonjs'
}
},
{
files: ['**/*.{js,mjs,cjs}', '**/.*.{js,mjs,cjs}'],
...pluginJs.configs.recommended
},
{ ignores: ['node_modules', 'dist', '**/*.cjs'] },
{
files: ['**/*.{js,ts}'],
languageOptions: {
ecmaVersion: 2022,
sourceType: 'module',
globals: { ...globals.node },
parserOptions: {
tsconfigRootDir: getESMDirname(import.meta.url),
project: './tsconfig.json'
}
}
},
pluginJs.configs.recommended,
...tseslint.configs.recommended,
{ ignores: ['node_modules', 'dist', '**/*.cjs'] }
...tseslint.configs.recommendedTypeChecked.map((c) => ({
...c,
files: [...(c.files || []), '**/*.ts', '**/*.d.ts']
})),
{
files: ['**/*.ts', '**/*.d.ts', 'bin/www'],
languageOptions: {
ecmaVersion: 2022,
parserOptions: {
tsconfigRootDir: getESMDirname(import.meta.url),
project: './tsconfig.json'
}
},
rules: {
'@typescript-eslint/no-explicit-any': 'error',
'@typescript-eslint/no-unsafe-return': 'error'
}
},
{
files: ['**/*.spec.{js,ts}'],
languageOptions: {
ecmaVersion: 2022,
globals: {
...globals.node
}
}
},
prettierConfig
]
+13 -11
View File
@@ -3,19 +3,19 @@
"description": "Default metrics for prom-client with higher frequency collection to histogram",
"devDependencies": {
"@eslint/js": "^9.6.0",
"@typescript-eslint/eslint-plugin": "^7.14.1",
"@typescript-eslint/parser": "^7.14.1",
"@types/eslint": "^8.56.10",
"@types/node": "^20.14.9",
"@typescript-eslint/eslint-plugin": "^7.15.0",
"@typescript-eslint/parser": "^7.15.0",
"eslint": "9.x",
"eslint-config-prettier": "^9.1.0",
"eslint-config-standard-with-typescript": "^43.0.1",
"eslint-import-resolver-typescript": "^3.6.1",
"eslint-plugin-import": "^2.29.1",
"eslint-plugin-n": "^17.9.0",
"eslint-plugin-promise": "^6.4.0",
"globals": "^15.7.0",
"globals": "^15.8.0",
"lockfile-lint": "^4.14.0",
"prettier": "^3.3.2",
"prettier-plugin-organize-imports": "^3.2.4",
"ts-node": "^10.9.2",
"typescript": "^5.5.2",
"typescript-eslint": "^7.14.1"
},
@@ -23,12 +23,10 @@
"node": "18"
},
"license": "Apache 2.0",
"main": "./src/setup.ts",
"name": "prom-client-fine-grained-metrics",
"packageManager": "yarn@4.2.2",
"repository": "https://github.com/specklesystems/prom-client-fine-grained-metrics",
"peerDependencies": {
"prom-client": ">= 10 <= 15"
},
"scripts": {
"lint:eslint": "eslint .",
"lint:tsc": "tsc --noEmit",
@@ -41,7 +39,11 @@
"prettier:fix": "yarn prettier --write .",
"pre-commit:install": "pre-commit install",
"pre-commit": "pre-commit run --all-files",
"test": "yarn run test"
"test": "NODE_ENV=test LOG_LEVEL=silent LOG_PRETTY=true vitest --run"
},
"version": "0.0.1"
"type": "module",
"version": "0.0.1",
"dependencies": {
"prom-client": "^15.1.3"
}
}
+7
View File
@@ -0,0 +1,7 @@
import { Registry } from 'prom-client'
export type Config = {
register?: Registry
namePrefix?: string
collectionPeriodMilliseconds?: number
labels?: string[]
}
-3
View File
@@ -1,3 +0,0 @@
export default function () {
console.log('hello world!')
}
+6
View File
@@ -0,0 +1,6 @@
/**
* The default eventLoopLag metric in prom-client
* already collects the data in a histogram, running repeatedly from
* the start of the application.
* We do not need to re-implement it.
*/
+6
View File
@@ -0,0 +1,6 @@
/**
* The default gc metric in prom-client
* already collects the data in a histogram, running repeatedly from
* the start of the application.
* We do not need to re-implement it.
*/
+65
View File
@@ -0,0 +1,65 @@
import { Gauge, Histogram } from 'prom-client'
import { safeMemoryUsage } from '@/metrics/helpers/safeMemoryUsage'
import { Config } from '@/domain/types'
const NODEJS_HEAP_SIZE_TOTAL = 'nodejs_heap_size_total_bytes'
const NODEJS_HEAP_SIZE_USED = 'nodejs_heap_size_used_bytes'
const NODEJS_EXTERNAL_MEMORY = 'nodejs_external_memory_bytes'
const NODEJS_HEAP_SIZE_TOTAL_HISTOGRAM = 'nodejs_heap_size_total_bytes_histogram'
export const heapSizeAndUsed = (config: Config) => {
if (typeof process.memoryUsage !== 'function') {
return
}
const labels = config.labels ?? {}
const labelNames = Object.keys(labels)
const registers = config.register ? [config.register] : undefined
const namePrefix = config.namePrefix ?? ''
const collect = () => {
const memUsage = safeMemoryUsage()
if (memUsage) {
heapSizeTotal.set(labels, memUsage.heapTotal)
heapSizeUsed.set(labels, memUsage.heapUsed)
if (memUsage.external !== undefined) {
externalMemUsed.set(labels, memUsage.external)
}
}
}
const h = new Histogram({
name: namePrefix + NODEJS_HEAP_SIZE_TOTAL_HISTOGRAM,
help: 'Process heap size from Node.js in bytes.',
registers,
labelNames,
collect
})
const heapSizeTotal = new Gauge({
name: namePrefix + NODEJS_HEAP_SIZE_TOTAL,
help: 'Process heap size from Node.js in bytes.',
registers,
labelNames,
// Use this one metric's `collect` to set all metrics' values.
collect
})
const heapSizeUsed = new Gauge({
name: namePrefix + NODEJS_HEAP_SIZE_USED,
help: 'Process heap size used from Node.js in bytes.',
registers,
labelNames
})
const externalMemUsed = new Gauge({
name: namePrefix + NODEJS_EXTERNAL_MEMORY,
help: 'Node.js external memory size in bytes.',
registers,
labelNames
})
}
export const metricNames = [
NODEJS_HEAP_SIZE_TOTAL,
NODEJS_HEAP_SIZE_USED,
NODEJS_EXTERNAL_MEMORY
]
+8
View File
@@ -0,0 +1,8 @@
// process.memoryUsage() can throw on some platforms, see #67
export function safeMemoryUsage() {
try {
return process.memoryUsage()
} catch {
return
}
}
+39
View File
@@ -0,0 +1,39 @@
import { isObject } from '@/utils'
import { heapSizeAndUsed } from '@/metrics/heapSizeAndUsed'
import { Config } from '@/domain/types'
const metrics = [heapSizeAndUsed]
export default function (config: Config) {
console.log('registering metrics!')
//register metrics
if (config !== null && config !== undefined && !isObject(config)) {
throw new TypeError('config must be null, undefined, or an object')
}
for (const metric of Object.values(metrics)) {
metric(config)
}
return () => {
repeatAction({
action: collectMetrics,
period: config.collectionPeriodMilliseconds ?? 100
})
}
}
const shouldStopRepeatingAction = false
const repeatAction = (params: { action: () => Promise<void>; period: number }) => {
return async () => {
if (shouldStopRepeatingAction) return
setInterval(repeatAction(params), params.period)
await params.action()
}
}
const collectMetrics = () => {
console.log('collecting metrics')
return Promise.resolve()
}
+3
View File
@@ -0,0 +1,3 @@
export const isObject = (obj: unknown): boolean => {
return obj !== null && typeof obj === 'object'
}
View File
+1 -1
View File
@@ -1,4 +1,4 @@
{
"extends": "./tsconfig.json",
"exclude": ["**/*.spec.js", "**/*.spec.ts", "test/**/*"]
"exclude": ["**/*.spec.js", "**/*.spec.ts", "tests/**/*"]
}
-4
View File
@@ -1,4 +0,0 @@
{
"extends": "./tsconfig.json",
"include": [".*.cjs"]
}
+12 -11
View File
@@ -24,16 +24,17 @@
// "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */
/* Modules */
"module": "NodeNext" /* Specify what module code is generated. */,
// "rootDir": "./", /* Specify the root folder within your source files. */
"moduleResolution": "NodeNext" /* Specify how TypeScript looks up a file from a given module specifier. */,
"baseUrl": "." /* Specify the base directory to resolve non-relative module names. */,
"module": "Node16" /* Specify what module code is generated. */,
"rootDir": "./" /* Specify the root folder within your source files. */,
"moduleResolution": "Node16" /* Specify how TypeScript looks up a file from a given module specifier. */,
"baseUrl": "./" /* Specify the base directory to resolve non-relative module names. */,
"paths": {
"@/*": ["./*"]
"@/*": ["./src/*"],
"#/*": ["./tests/*"]
},
// "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */
// "typeRoots": [], /* Specify multiple folders that act like `./node_modules/@types`. */
// "types": [], /* Specify type package names to be included without being referenced in a source file. */
// "types": ["node"], /* Specify type package names to be included without being referenced in a source file. */
// "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
// "resolveJsonModule": true, /* Enable importing .json files */
// "noResolve": true, /* Disallow `import`s, `require`s or `<reference>`s from expanding the number of files TypeScript should add to a project. */
@@ -44,8 +45,8 @@
// "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from `node_modules`. Only applicable with `allowJs`. */
/* Emit */
"declaration": true /* Generate .d.ts files from TypeScript and JavaScript files in your project. */,
"declarationMap": true /* Create sourcemaps for d.ts files. */,
// "declaration": true /* Generate .d.ts files from TypeScript and JavaScript files in your project. */,
// "declarationMap": true /* Create sourcemaps for d.ts files. */,
// "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */
"sourceMap": true /* Create source map files for emitted JavaScript files. */,
// "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If `declaration` is true, also designates a file that bundles all .d.ts output. */
@@ -93,8 +94,8 @@
"noUncheckedIndexedAccess": true /* Include 'undefined' in index signature results */,
"noImplicitOverride": true /* Ensure overriding members in derived classes are marked with an override modifier. */,
"noPropertyAccessFromIndexSignature": true /* Enforces using indexed accessors for keys declared using an indexed type */,
// "allowUnusedLabels": true, /* Disable error reporting for unused labels. */
// "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */
// "allowUnusedLabels": true /* Disable error reporting for unused labels. */,
// "allowUnreachableCode": true /* Disable error reporting for unreachable code. */,
"noErrorTruncation": true,
/* Completeness */
@@ -104,6 +105,6 @@
"ts-node": {
"swc": true
},
"include": ["src/**/*.ts", "eslint.config.mjs"],
"include": ["tests/**/*.ts", "src/**/*.ts", "eslint.config.mjs"],
"exclude": ["node_modules", "dist/**/*"]
}
+294 -1045
View File
File diff suppressed because it is too large Load Diff