From 4024e76873910138b46c460f59546aea43a865a9 Mon Sep 17 00:00:00 2001 From: Laurynas Keturakis Date: Wed, 10 May 2023 17:37:26 +0200 Subject: [PATCH 01/10] replace error throw with a log --- packages/autometrics-lib/src/wrappers.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/autometrics-lib/src/wrappers.ts b/packages/autometrics-lib/src/wrappers.ts index 62893513..21f204ee 100644 --- a/packages/autometrics-lib/src/wrappers.ts +++ b/packages/autometrics-lib/src/wrappers.ts @@ -97,9 +97,10 @@ export function autometrics( } if (!functionName) { - throw new Error( - "Autometrics decorated function must have a name to successfully create a metric", + console.trace( + "Autometrics decorated function must have a name to successfully create a metric. Function will not be instrumented.", ); + return fn; } const counterObjectiveAttributes: Attributes = {}; From 0710f5e5fc288c0b2f9f0f26dbd756ebcb7a07c0 Mon Sep 17 00:00:00 2001 From: Laurynas Keturakis Date: Wed, 10 May 2023 17:38:30 +0200 Subject: [PATCH 02/10] add a way to register build_info data to the metrics --- packages/autometrics-lib/src/buildInfo.ts | 40 +++++++++++++++++++++++ packages/autometrics-lib/src/wrappers.ts | 2 ++ 2 files changed, 42 insertions(+) create mode 100644 packages/autometrics-lib/src/buildInfo.ts diff --git a/packages/autometrics-lib/src/buildInfo.ts b/packages/autometrics-lib/src/buildInfo.ts new file mode 100644 index 00000000..6db4cc1a --- /dev/null +++ b/packages/autometrics-lib/src/buildInfo.ts @@ -0,0 +1,40 @@ +import { getMeter } from "./instrumentation"; + +type BuildInfo = { + version?: string; + commit?: string; + branch?: string; +}; + +let buildInfo: BuildInfo | undefined; + +export function registerBuildInfo() { + if (buildInfo) { + return; + } else { + buildInfo = { + version: getVersion(), + commit: getCommit(), + branch: getBranch(), + }; + + const gauge = getMeter().createUpDownCounter("build_info"); + gauge.add(1, buildInfo); + } +} + +function getVersion() { + if (process.env.npm_package_version) { + return process.env.npm_package_version; + } else { + return process.env.PACKAGE_VERSION; + } +} + +function getCommit() { + return process.env.COMMIT_SHA; +} + +function getBranch() { + return process.env.BRANCH_NAME; +} diff --git a/packages/autometrics-lib/src/wrappers.ts b/packages/autometrics-lib/src/wrappers.ts index 21f204ee..210af9ef 100644 --- a/packages/autometrics-lib/src/wrappers.ts +++ b/packages/autometrics-lib/src/wrappers.ts @@ -8,6 +8,7 @@ import { getModulePath, isPromise, } from "./utils"; +import { registerBuildInfo } from "./buildInfo"; // Function Wrapper // This seems to be the preferred way for defining functions in TypeScript @@ -125,6 +126,7 @@ export function autometrics( return function (...params) { const meter = getMeter(); + registerBuildInfo(); const autometricsStart = performance.now(); const counter = meter.createCounter("function.calls.count"); const histogram = meter.createHistogram("function.calls.duration"); From 26f301bd9723f2b2cf48e2762e3ebadbf2db6151 Mon Sep 17 00:00:00 2001 From: Laurynas Keturakis Date: Thu, 11 May 2023 10:05:49 +0200 Subject: [PATCH 03/10] README update --- README.md | 46 ++++++++++++++++++++++++++++------------------ 1 file changed, 28 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index 5869db94..b703e312 100644 --- a/README.md +++ b/README.md @@ -49,28 +49,12 @@ The Autometrics library: - Uses a Prometheus Exporter to write metrics to a `/metrics` endpoint (by default on port `:9464`) or pushes them to a specified gateway (if used in browser) -- Uses a TypeScript plugin to automatically add useful Prometheus queries in the doc comments for instrumented functions +- Uses a TypeScript plugin / VSCode extension to automatically add useful Prometheus queries in the doc comments for instrumented functions ## Quickstart ```shell npm install --save autometrics -npm install --save-dev @autometrics/typescript-plugin -``` - -Enable the TypeScript plugin by adding it to `tsconfig.json`: - -```json -{ - "compilerOptions": { - "plugins": [ - { - "name": "@autometrics/typescript-plugin", - "prometheusUrl": "" - } - ] - } -} ``` Use the library in your code: @@ -98,10 +82,27 @@ The default `autometrics` package bundles `@opentelemetry/sdk-metrics` and these in your codebase or want to use other custom metrics, use the following installation option. -Install the wrappers and the language service plugin: +Install the wrappers: ```shell npm install --save @autometrics/autometrics +``` + +Import and use the library in your code: + +```typescript +import { autometrics } from "@autometrics/autometrics" +``` + +## Getting PromQL queries + +In order to get PromQL query links in your IDE download the [Autometrics VSCode +extension](https://marketplace.visualstudio.com/items?itemName=Fiberplane.autometrics). + +If you're on any other IDE you can install and add the TypeScript plugin +directly: + +```bash npm install --save-dev @autometrics/typescript-plugin ``` @@ -124,6 +125,15 @@ Add the language service plugin to the `tsconfig.json` file: Autometrics provides [Grafana dashboards](https://github.com/autometrics-dev/autometrics-shared#dashboards) that will work for any project instrumented with the library. +## Identifying commits that introduce errors + +Autometrics makes it easy to [spot versions and commits that introduce errors or latency](https://fiberplane.com/blog/autometrics-rs-0-4-spot-commits-that-introduce-errors-or-slow-down-your-application). + +| Label | Run-Time Environment Variables | Default value | +|---|---|---| +| `version` | `AUTOMETRICS_VERSION` or `PACKAGE_VERSION` | `npm_package_version` (set by npm/yarn/pnpm by default) | +| `commit` | `AUTOMETRICS_COMMIT` or `COMMIT_SHA` | `""` | +| `branch` | `AUTOMETRICS_BRANCH` or `BRANCH_NAME` | `""` | ## Alerts / SLOs From 75698ed7e1376934ecda5582fd3e9d3665fe95e1 Mon Sep 17 00:00:00 2001 From: Laurynas Keturakis Date: Thu, 11 May 2023 10:07:32 +0200 Subject: [PATCH 04/10] update env variables --- packages/autometrics-lib/src/buildInfo.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/autometrics-lib/src/buildInfo.ts b/packages/autometrics-lib/src/buildInfo.ts index 6db4cc1a..f6cf842c 100644 --- a/packages/autometrics-lib/src/buildInfo.ts +++ b/packages/autometrics-lib/src/buildInfo.ts @@ -27,14 +27,14 @@ function getVersion() { if (process.env.npm_package_version) { return process.env.npm_package_version; } else { - return process.env.PACKAGE_VERSION; + return process.env.PACKAGE_VERSION || process.env.AUTOMETRICS_VERSION; } } function getCommit() { - return process.env.COMMIT_SHA; + return process.env.COMMIT_SHA || process.env.AUTOMETRICS_COMMIT; } function getBranch() { - return process.env.BRANCH_NAME; + return process.env.BRANCH_NAME || process.env.AUTOMETRICS_BRANCH; } From d37fe5db60c40ee960aebbeb5e7bb1ec066922aa Mon Sep 17 00:00:00 2001 From: Laurynas Keturakis Date: Thu, 11 May 2023 10:30:40 +0200 Subject: [PATCH 05/10] update ts plugin queries --- .../src/queryHelpers.ts | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/autometrics-typescript-plugin/src/queryHelpers.ts b/packages/autometrics-typescript-plugin/src/queryHelpers.ts index 842732ae..5feac06f 100644 --- a/packages/autometrics-typescript-plugin/src/queryHelpers.ts +++ b/packages/autometrics-typescript-plugin/src/queryHelpers.ts @@ -1,25 +1,25 @@ /* Functions below template creation of relevant queries and encode them in URL */ import type { NodeType } from "./types"; +const BUILD_INFO_LABELS = + "* on (instance, job) group_left(version, commit) (last_over_time(build_info[1s]) or on (instance, job) up)"; -export function createLatencyQuery(nodeIdentifier: string, nodeType: string) { - const latency = `sum by (le, function, module) (rate(${nodeType}_calls_duration_bucket{${nodeType}="${nodeIdentifier}"}[5m]))`; +export function createLatencyQuery(nodeIdentifier: string) { + const latency = `sum by (le, function, module, commit, version) (rate(function_calls_duration_bucket{function="${nodeIdentifier}"}[5m]) ${BUILD_INFO_LABELS})`; return `histogram_quantile(0.99, ${latency}) or histogram_quantile(0.95, ${latency})`; } export function createRequestRateQuery( nodeIdentifier: string, - nodeType: NodeType, ) { - return `sum by (function, module) (rate(${nodeType}_calls_count_total{${nodeType}="${nodeIdentifier}"}[5m]))`; + return `sum by (function, module, commit, version) (rate(function_calls_count_total{function="${nodeIdentifier}"}[5m]) ${BUILD_INFO_LABELS})`; } export function createErrorRatioQuery( nodeIdentifier: string, - nodeType: NodeType, ) { - const requestQuery = createRequestRateQuery(nodeIdentifier, nodeType); - return `sum by (function, module) (rate(${nodeType}_calls_count_total{${nodeType}="${nodeIdentifier}",result="error"}[5m])) / ${requestQuery}`; + const requestQuery = createRequestRateQuery(nodeIdentifier); + return `sum by (function, module, commit, version) (rate(function_calls_count_total{function="${nodeIdentifier}",result="error"}[5m]) ${BUILD_INFO_LABELS}) / ${requestQuery}`; } const DEFAULT_URL = "http://localhost:9090/"; From baea8abee0df10e4a24adb468b405843c79ddfe3 Mon Sep 17 00:00:00 2001 From: Laurynas Keturakis Date: Thu, 11 May 2023 10:31:18 +0200 Subject: [PATCH 06/10] remove redundant nodeType variable from query templates (all metrics are function metrics) --- packages/autometrics-typescript-plugin/src/index.ts | 6 +++--- packages/autometrics-typescript-plugin/src/queryHelpers.ts | 1 - 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/packages/autometrics-typescript-plugin/src/index.ts b/packages/autometrics-typescript-plugin/src/index.ts index 9936c959..54359c94 100644 --- a/packages/autometrics-typescript-plugin/src/index.ts +++ b/packages/autometrics-typescript-plugin/src/index.ts @@ -67,9 +67,9 @@ function init(modules: { typescript: typeof tsserver }) { typechecker, ); - const requestRate = createRequestRateQuery(nodeIdentifier, nodeType); - const errorRatio = createErrorRatioQuery(nodeIdentifier, nodeType); - const latency = createLatencyQuery(nodeIdentifier, nodeType); + const requestRate = createRequestRateQuery(nodeIdentifier); + const errorRatio = createErrorRatioQuery(nodeIdentifier); + const latency = createLatencyQuery(nodeIdentifier); const requestRateUrl = makePrometheusUrl(requestRate, prometheusBase); const errorRatioUrl = makePrometheusUrl(errorRatio, prometheusBase); diff --git a/packages/autometrics-typescript-plugin/src/queryHelpers.ts b/packages/autometrics-typescript-plugin/src/queryHelpers.ts index 5feac06f..94cd5e3a 100644 --- a/packages/autometrics-typescript-plugin/src/queryHelpers.ts +++ b/packages/autometrics-typescript-plugin/src/queryHelpers.ts @@ -1,6 +1,5 @@ /* Functions below template creation of relevant queries and encode them in URL */ -import type { NodeType } from "./types"; const BUILD_INFO_LABELS = "* on (instance, job) group_left(version, commit) (last_over_time(build_info[1s]) or on (instance, job) up)"; From 1802001cfb0ac29ebe4b21f87bc1d652281f7776 Mon Sep 17 00:00:00 2001 From: Laurynas Keturakis Date: Thu, 11 May 2023 10:38:40 +0200 Subject: [PATCH 07/10] fix formatting --- .../autometrics-typescript-plugin/src/queryHelpers.ts | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/packages/autometrics-typescript-plugin/src/queryHelpers.ts b/packages/autometrics-typescript-plugin/src/queryHelpers.ts index 94cd5e3a..ac00d9ea 100644 --- a/packages/autometrics-typescript-plugin/src/queryHelpers.ts +++ b/packages/autometrics-typescript-plugin/src/queryHelpers.ts @@ -8,15 +8,11 @@ export function createLatencyQuery(nodeIdentifier: string) { return `histogram_quantile(0.99, ${latency}) or histogram_quantile(0.95, ${latency})`; } -export function createRequestRateQuery( - nodeIdentifier: string, -) { +export function createRequestRateQuery(nodeIdentifier: string) { return `sum by (function, module, commit, version) (rate(function_calls_count_total{function="${nodeIdentifier}"}[5m]) ${BUILD_INFO_LABELS})`; } -export function createErrorRatioQuery( - nodeIdentifier: string, -) { +export function createErrorRatioQuery(nodeIdentifier: string) { const requestQuery = createRequestRateQuery(nodeIdentifier); return `sum by (function, module, commit, version) (rate(function_calls_count_total{function="${nodeIdentifier}",result="error"}[5m]) ${BUILD_INFO_LABELS}) / ${requestQuery}`; } From 8be458c44280276d5ad2692cd72f4a04aaf1bd75 Mon Sep 17 00:00:00 2001 From: Laurynas Keturakis Date: Thu, 11 May 2023 12:32:30 +0200 Subject: [PATCH 08/10] update InMemoryMetricExporter to add actual enum for reading clarity --- packages/autometrics-lib/src/instrumentation.ts | 3 ++- packages/autometrics-lib/tests/integration.test.ts | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/autometrics-lib/src/instrumentation.ts b/packages/autometrics-lib/src/instrumentation.ts index 5270c390..7f88ddbf 100644 --- a/packages/autometrics-lib/src/instrumentation.ts +++ b/packages/autometrics-lib/src/instrumentation.ts @@ -3,6 +3,7 @@ import { PrometheusSerializer, } from "@opentelemetry/exporter-prometheus"; import { + AggregationTemporality, InMemoryMetricExporter, MeterProvider, MetricReader, @@ -43,7 +44,7 @@ export function init(options: initOptions) { exporter = new PeriodicExportingMetricReader({ // 0 - using delta aggregation temporality setting // to ensure data submitted to the gateway is accurate - exporter: new InMemoryMetricExporter(0), + exporter: new InMemoryMetricExporter(AggregationTemporality.DELTA), }); // Make sure the provider is initialized and exporter is registered getMetricsProvider(); diff --git a/packages/autometrics-lib/tests/integration.test.ts b/packages/autometrics-lib/tests/integration.test.ts index d7e1ba75..5ec748d2 100644 --- a/packages/autometrics-lib/tests/integration.test.ts +++ b/packages/autometrics-lib/tests/integration.test.ts @@ -1,6 +1,7 @@ import { autometrics, init } from "../src"; import { describe, test, expect, beforeAll, afterEach } from "vitest"; import { + AggregationTemporality, InMemoryMetricExporter, PeriodicExportingMetricReader, } from "@opentelemetry/sdk-metrics"; @@ -14,7 +15,7 @@ describe("Autometrics integration test", () => { exporter = new PeriodicExportingMetricReader({ // 0 - using delta aggregation temporality setting // to ensure data submitted to the gateway is accurate - exporter: new InMemoryMetricExporter(0), + exporter: new InMemoryMetricExporter(AggregationTemporality.DELTA), }); init({ exporter }); From 0ba5fac2906c3b3118aebe7305340fe5cbefcfb4 Mon Sep 17 00:00:00 2001 From: Laurynas Keturakis Date: Thu, 11 May 2023 17:12:06 +0200 Subject: [PATCH 09/10] fix latency query - as per autometrics-rs#79 --- packages/autometrics-typescript-plugin/src/queryHelpers.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/autometrics-typescript-plugin/src/queryHelpers.ts b/packages/autometrics-typescript-plugin/src/queryHelpers.ts index ac00d9ea..d1ba915e 100644 --- a/packages/autometrics-typescript-plugin/src/queryHelpers.ts +++ b/packages/autometrics-typescript-plugin/src/queryHelpers.ts @@ -5,7 +5,7 @@ const BUILD_INFO_LABELS = export function createLatencyQuery(nodeIdentifier: string) { const latency = `sum by (le, function, module, commit, version) (rate(function_calls_duration_bucket{function="${nodeIdentifier}"}[5m]) ${BUILD_INFO_LABELS})`; - return `histogram_quantile(0.99, ${latency}) or histogram_quantile(0.95, ${latency})`; + return `histogram_quantile(0.99, ${latency}, \"percentile_latency\", \"99\", \"\",\"\") or histogram_quantile(0.95, ${latency}), \"percentile_latency\", \"95\", \"\", \"\")`; } export function createRequestRateQuery(nodeIdentifier: string) { From 0a64e3baec33d52f3e8b82a5f80e50111a3189ad Mon Sep 17 00:00:00 2001 From: Laurynas Keturakis Date: Fri, 12 May 2023 11:55:40 +0200 Subject: [PATCH 10/10] remove redundant elses --- packages/autometrics-lib/src/buildInfo.ts | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/packages/autometrics-lib/src/buildInfo.ts b/packages/autometrics-lib/src/buildInfo.ts index f6cf842c..279a2f0c 100644 --- a/packages/autometrics-lib/src/buildInfo.ts +++ b/packages/autometrics-lib/src/buildInfo.ts @@ -11,24 +11,24 @@ let buildInfo: BuildInfo | undefined; export function registerBuildInfo() { if (buildInfo) { return; - } else { - buildInfo = { - version: getVersion(), - commit: getCommit(), - branch: getBranch(), - }; - - const gauge = getMeter().createUpDownCounter("build_info"); - gauge.add(1, buildInfo); } + + buildInfo = { + version: getVersion(), + commit: getCommit(), + branch: getBranch(), + }; + + const gauge = getMeter().createUpDownCounter("build_info"); + gauge.add(1, buildInfo); } function getVersion() { if (process.env.npm_package_version) { return process.env.npm_package_version; - } else { - return process.env.PACKAGE_VERSION || process.env.AUTOMETRICS_VERSION; } + + return process.env.PACKAGE_VERSION || process.env.AUTOMETRICS_VERSION; } function getCommit() {