commit 06522c9ec707bc36a8d393f6a1bf7422818d47e2
parent f87b8b51bf8d2ce40046c7ac826349e96f9af530
Author: mtmn <miro@haravara.org>
Date: Sun, 19 Apr 2026 13:22:57 +0200
feat!: remove otel, add cosine.club metrics
Diffstat:
9 files changed, 48 insertions(+), 1030 deletions(-)
diff --git a/README.md b/README.md
@@ -60,7 +60,5 @@ npx spago bundle --module Client --outfile client.js --platform browser
| `AWS_ENDPOINT_URL` | — | S3-compatible endpoint (e.g. for MinIO) |
| `AWS_S3_ADDRESSING_STYLE` | — | Set to `path` for path-style S3 URLs |
| `METRICS_ENABLED` | `false` | Set to `true` to expose Prometheus metrics at `/metrics` |
-| `OTEL_EXPORTER_OTLP_ENDPOINT` | — | If set, enables OpenTelemetry tracing and exports spans to this OTLP HTTP endpoint |
-| `OTEL_SERVICE_NAME` | `corpus` | Service name reported in OTel spans |
Per-user settings (`listenbrainzUser`, `lastfmUser`, `initialSync`, `coverCacheEnabled`, `backupEnabled`, `backupIntervalHours`, etc.) are configured in `users.json` (or `users.dhall`), not via environment variables.
diff --git a/docs/architecture.md b/docs/architecture.md
@@ -11,7 +11,7 @@ The server is built with PureScript running on Node.js. It handles several core
- **Last.fm Sync**: A background process that polls the Last.fm API every 60 seconds to fetch new scrobbles. Both syncs write to the same `scrobbles` table; duplicate timestamps are silently ignored.
- **Metadata Enrichment**: A background process that identifies scrobbles with missing metadata (genres, labels, release years) and fetches information from MusicBrainz, Last.fm, and Discogs.
- **Cover Art Proxy**: A specialized endpoint that fetches, caches, and serves cover art, utilizing a multi-source fallback strategy (CAA → Last.fm → Discogs).
-- **Observability**: Prometheus metrics exposed at `/metrics` and optional OpenTelemetry tracing of all HTTP requests.
+- **Observability**: Prometheus metrics exposed at `/metrics`.
### Frontend
A Single Page Application (SPA) built with [Elm](https://elm-lang.org).
@@ -67,8 +67,6 @@ Each user gets their own `UserContext` with an independent DuckDB connection, sy
| `AWS_S3_ADDRESSING_STYLE` | — | `virtual` or `path` |
| `PORT` | `8000` | HTTP listen port |
| `METRICS_ENABLED` | `false` | Set to `true` to enable the Prometheus `/metrics` endpoint |
-| `OTEL_EXPORTER_OTLP_ENDPOINT` | — | If set, enables OpenTelemetry tracing and exports spans to this OTLP HTTP endpoint |
-| `OTEL_SERVICE_NAME` | `corpus` | Service name reported in OTel spans |
### users.dhall Fields
@@ -137,10 +135,6 @@ Prometheus metrics are **disabled by default**. Set `METRICS_ENABLED=true` to en
Node.js default metrics (GC, event loop, memory) are also collected via `prom-client`'s `collectDefaultMetrics`.
-### OpenTelemetry Tracing
-
-Tracing is opt-in: the OTel SDK starts only when `OTEL_EXPORTER_OTLP_ENDPOINT` is set. Spans are exported over OTLP/HTTP. Each incoming HTTP request becomes a server span; outbound `fetch`/`undici` calls made during that request automatically become child spans via the `HttpInstrumentation` and `UndiciInstrumentation` auto-instrumentation packages. W3C `traceparent` headers are extracted from incoming requests for distributed trace propagation.
-
## Tech Stack
- **Language**: [PureScript](https://purescript.org) (server), [Elm](https://elm-lang.org) (frontend)
@@ -158,7 +152,7 @@ Corpus relies on FFI to interact with the Node.js ecosystem where native PureScr
- **Cloud Storage (`S3.js`)**: AWS SDK (`@aws-sdk/client-s3`) for cover art caching. Takes explicit config structs rather than reading `process.env`.
- **System Utilities (`Main.js`)**: Bridges PureScript with Node.js — `dotenv` loading and request helpers.
- **Config (`Config.js`)**: Reads and parses `users.json` from the path given by `CORPUS_USERS_FILE`.
-- **Observability (`Metrics.js`)**: Initialises `prom-client` (Prometheus) and the OpenTelemetry Node SDK. Exports metric-increment helpers called from PureScript and the `wrapRequest` function that wraps each HTTP handler in an OTel server span.
+- **Observability (`Metrics.js`)**: Initialises `prom-client` (Prometheus). Exports metric-increment helpers called from PureScript and the `wrapRequest` function that records metrics and logs each HTTP request.
## System Flow
diff --git a/flake.lock b/flake.lock
@@ -20,11 +20,11 @@
},
"nixpkgs": {
"locked": {
- "lastModified": 1776255774,
- "narHash": "sha256-psVTpH6PK3q1htMJpmdz1hLF5pQgEshu7gQWgKO6t6Y=",
+ "lastModified": 1776329215,
+ "narHash": "sha256-a8BYi3mzoJ/AcJP8UldOx8emoPRLeWqALZWu4ZvjPXw=",
"owner": "NixOS",
"repo": "nixpkgs",
- "rev": "566acc07c54dc807f91625bb286cb9b321b5f42a",
+ "rev": "b86751bc4085f48661017fa226dee99fab6c651b",
"type": "github"
},
"original": {
diff --git a/flake.nix b/flake.nix
@@ -128,10 +128,10 @@
corpus = pkgs.buildNpmPackage {
pname = "corpus";
- version = (builtins.fromJSON (builtins.readFile ./package.json)).version;
+ inherit ((builtins.fromJSON (builtins.readFile ./package.json))) version;
inherit src;
- npmDepsHash = "sha256-gBFhiRVXLRj+x0K2dj+JW9OOc2dEP97PoVkuchabWVk=";
+ npmDepsHash = "sha256-u+Z0zdHCfU/RXmK10g4IT/EJhnp3oG/BHP/yauQeviU=";
npmRebuildFlags = ["--ignore-scripts"];
nativeBuildInputs = with pkgs; [
diff --git a/package-lock.json b/package-lock.json
@@ -9,11 +9,6 @@
"version": "1.4.0",
"dependencies": {
"@aws-sdk/client-s3": "^3.1029.0",
- "@opentelemetry/api": "^1.9.1",
- "@opentelemetry/exporter-trace-otlp-http": "^0.215.0",
- "@opentelemetry/instrumentation-http": "^0.215.0",
- "@opentelemetry/instrumentation-undici": "^0.25.0",
- "@opentelemetry/sdk-node": "^0.215.0",
"dotenv": "^17.4.1",
"duckdb": "^1.4.4",
"prom-client": "^15.1.3"
@@ -1329,61 +1324,6 @@
"integrity": "sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==",
"license": "MIT"
},
- "node_modules/@grpc/grpc-js": {
- "version": "1.14.3",
- "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.14.3.tgz",
- "integrity": "sha512-Iq8QQQ/7X3Sac15oB6p0FmUg/klxQvXLeileoqrTRGJYLV+/9tubbr9ipz0GKHjmXVsgFPo/+W+2cA8eNcR+XA==",
- "license": "Apache-2.0",
- "dependencies": {
- "@grpc/proto-loader": "^0.8.0",
- "@js-sdsl/ordered-map": "^4.4.2"
- },
- "engines": {
- "node": ">=12.10.0"
- }
- },
- "node_modules/@grpc/proto-loader": {
- "version": "0.8.0",
- "resolved": "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.8.0.tgz",
- "integrity": "sha512-rc1hOQtjIWGxcxpb9aHAfLpIctjEnsDehj0DAiVfBlmT84uvR0uUtN2hEi/ecvWVjXUGf5qPF4qEgiLOx1YIMQ==",
- "license": "Apache-2.0",
- "dependencies": {
- "lodash.camelcase": "^4.3.0",
- "long": "^5.0.0",
- "protobufjs": "^7.5.3",
- "yargs": "^17.7.2"
- },
- "bin": {
- "proto-loader-gen-types": "build/bin/proto-loader-gen-types.js"
- },
- "engines": {
- "node": ">=6"
- }
- },
- "node_modules/@grpc/proto-loader/node_modules/protobufjs": {
- "version": "7.5.5",
- "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.5.5.tgz",
- "integrity": "sha512-3wY1AxV+VBNW8Yypfd1yQY9pXnqTAN+KwQxL8iYm3/BjKYMNg4i0owhEe26PWDOMaIrzeeF98Lqd5NGz4omiIg==",
- "hasInstallScript": true,
- "license": "BSD-3-Clause",
- "dependencies": {
- "@protobufjs/aspromise": "^1.1.2",
- "@protobufjs/base64": "^1.1.2",
- "@protobufjs/codegen": "^2.0.4",
- "@protobufjs/eventemitter": "^1.1.0",
- "@protobufjs/fetch": "^1.1.0",
- "@protobufjs/float": "^1.0.2",
- "@protobufjs/inquire": "^1.1.0",
- "@protobufjs/path": "^1.1.2",
- "@protobufjs/pool": "^1.1.0",
- "@protobufjs/utf8": "^1.1.0",
- "@types/node": ">=13.7.0",
- "long": "^5.0.0"
- },
- "engines": {
- "node": ">=12.0.0"
- }
- },
"node_modules/@isaacs/cliui": {
"version": "9.0.0",
"resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-9.0.0.tgz",
@@ -1415,16 +1355,6 @@
"node": ">=16 || 14 >=14.17"
}
},
- "node_modules/@js-sdsl/ordered-map": {
- "version": "4.4.2",
- "resolved": "https://registry.npmjs.org/@js-sdsl/ordered-map/-/ordered-map-4.4.2.tgz",
- "integrity": "sha512-iUKgm52T8HOE/makSxjqoWhe95ZJA1/G1sYsGev2JDKUSS14KAgg1LHb+Ba+IPow0xflbnSkOsZcO08C7w1gYw==",
- "license": "MIT",
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/js-sdsl"
- }
- },
"node_modules/@mapbox/node-pre-gyp": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-2.0.3.tgz",
@@ -1520,610 +1450,6 @@
"node": ">=8.0.0"
}
},
- "node_modules/@opentelemetry/api-logs": {
- "version": "0.215.0",
- "resolved": "https://registry.npmjs.org/@opentelemetry/api-logs/-/api-logs-0.215.0.tgz",
- "integrity": "sha512-xrFlqhdhUyO8wSRn6DjE0145/HPWSJ5Nm0C7vWua6TdL/FSEAZvEyvdsa9CRXuxo9ebb7j/NEPhEcO62IJ0qUA==",
- "license": "Apache-2.0",
- "dependencies": {
- "@opentelemetry/api": "^1.3.0"
- },
- "engines": {
- "node": ">=8.0.0"
- }
- },
- "node_modules/@opentelemetry/configuration": {
- "version": "0.215.0",
- "resolved": "https://registry.npmjs.org/@opentelemetry/configuration/-/configuration-0.215.0.tgz",
- "integrity": "sha512-FSWvDryxjinHROfzEVbJGBw10FqGzLEm2C1LPX6Lot6hvxq3lFJzNLlue8vm64C5yIbqSQVjWsPhYu56ThQS4Q==",
- "license": "Apache-2.0",
- "dependencies": {
- "@opentelemetry/core": "2.7.0",
- "yaml": "^2.0.0"
- },
- "engines": {
- "node": "^18.19.0 || >=20.6.0"
- },
- "peerDependencies": {
- "@opentelemetry/api": "^1.9.0"
- }
- },
- "node_modules/@opentelemetry/context-async-hooks": {
- "version": "2.7.0",
- "resolved": "https://registry.npmjs.org/@opentelemetry/context-async-hooks/-/context-async-hooks-2.7.0.tgz",
- "integrity": "sha512-MWXggArM+Y11mPS8VOrqxOj+YMGQSRuvhM91eSBX4xFpJa05mpkeVvM8pPux5ElkEjV5RMgrkisrlP/R83SpBQ==",
- "license": "Apache-2.0",
- "engines": {
- "node": "^18.19.0 || >=20.6.0"
- },
- "peerDependencies": {
- "@opentelemetry/api": ">=1.0.0 <1.10.0"
- }
- },
- "node_modules/@opentelemetry/core": {
- "version": "2.7.0",
- "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-2.7.0.tgz",
- "integrity": "sha512-DT12SXVwV2eoJrGf4nnsvZojxxeQo+LlNAsoYGRRObPWTeN6APiqZ2+nqDCQDvQX40eLi1AePONS0onoASp3yQ==",
- "license": "Apache-2.0",
- "dependencies": {
- "@opentelemetry/semantic-conventions": "^1.29.0"
- },
- "engines": {
- "node": "^18.19.0 || >=20.6.0"
- },
- "peerDependencies": {
- "@opentelemetry/api": ">=1.0.0 <1.10.0"
- }
- },
- "node_modules/@opentelemetry/exporter-logs-otlp-grpc": {
- "version": "0.215.0",
- "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-logs-otlp-grpc/-/exporter-logs-otlp-grpc-0.215.0.tgz",
- "integrity": "sha512-MVq+9ma/63XRXc0AcnS+XyWSD6VBYn39OucsvpzjqxTpzTOiGXNxTwsbV3zbnvgUexb5hc2ZjJlZUK2W/19UUw==",
- "license": "Apache-2.0",
- "dependencies": {
- "@grpc/grpc-js": "^1.14.3",
- "@opentelemetry/core": "2.7.0",
- "@opentelemetry/otlp-exporter-base": "0.215.0",
- "@opentelemetry/otlp-grpc-exporter-base": "0.215.0",
- "@opentelemetry/otlp-transformer": "0.215.0",
- "@opentelemetry/sdk-logs": "0.215.0"
- },
- "engines": {
- "node": "^18.19.0 || >=20.6.0"
- },
- "peerDependencies": {
- "@opentelemetry/api": "^1.3.0"
- }
- },
- "node_modules/@opentelemetry/exporter-logs-otlp-http": {
- "version": "0.215.0",
- "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-logs-otlp-http/-/exporter-logs-otlp-http-0.215.0.tgz",
- "integrity": "sha512-U7Qb+TVX2GZH5RSC+Gx9aE5zChKP1kPg87X3PlI/41lWVPJdBIzmgMmuE28MmQlrK84nLHCIqUOOben8YkSzBw==",
- "license": "Apache-2.0",
- "dependencies": {
- "@opentelemetry/api-logs": "0.215.0",
- "@opentelemetry/core": "2.7.0",
- "@opentelemetry/otlp-exporter-base": "0.215.0",
- "@opentelemetry/otlp-transformer": "0.215.0",
- "@opentelemetry/sdk-logs": "0.215.0"
- },
- "engines": {
- "node": "^18.19.0 || >=20.6.0"
- },
- "peerDependencies": {
- "@opentelemetry/api": "^1.3.0"
- }
- },
- "node_modules/@opentelemetry/exporter-logs-otlp-proto": {
- "version": "0.215.0",
- "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-logs-otlp-proto/-/exporter-logs-otlp-proto-0.215.0.tgz",
- "integrity": "sha512-vs2xKKTdt/vKWMuBzw+LZYYCKqulodCRoonWWiyToIQfa6JgbyWjTu/iy6qpBLhLi+t6fNc1bwJGwu3vkot2Jg==",
- "license": "Apache-2.0",
- "dependencies": {
- "@opentelemetry/api-logs": "0.215.0",
- "@opentelemetry/core": "2.7.0",
- "@opentelemetry/otlp-exporter-base": "0.215.0",
- "@opentelemetry/otlp-transformer": "0.215.0",
- "@opentelemetry/resources": "2.7.0",
- "@opentelemetry/sdk-logs": "0.215.0",
- "@opentelemetry/sdk-trace-base": "2.7.0"
- },
- "engines": {
- "node": "^18.19.0 || >=20.6.0"
- },
- "peerDependencies": {
- "@opentelemetry/api": "^1.3.0"
- }
- },
- "node_modules/@opentelemetry/exporter-metrics-otlp-grpc": {
- "version": "0.215.0",
- "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-metrics-otlp-grpc/-/exporter-metrics-otlp-grpc-0.215.0.tgz",
- "integrity": "sha512-1TAMliHQvzc+v1OtnLMHSk5sU8BSkJbxIKrWzuCWcQjajWrvem/r5ugLK6agI0PjPz/ADfZju5AVYedlNyeO9g==",
- "license": "Apache-2.0",
- "dependencies": {
- "@grpc/grpc-js": "^1.14.3",
- "@opentelemetry/core": "2.7.0",
- "@opentelemetry/exporter-metrics-otlp-http": "0.215.0",
- "@opentelemetry/otlp-exporter-base": "0.215.0",
- "@opentelemetry/otlp-grpc-exporter-base": "0.215.0",
- "@opentelemetry/otlp-transformer": "0.215.0",
- "@opentelemetry/resources": "2.7.0",
- "@opentelemetry/sdk-metrics": "2.7.0"
- },
- "engines": {
- "node": "^18.19.0 || >=20.6.0"
- },
- "peerDependencies": {
- "@opentelemetry/api": "^1.3.0"
- }
- },
- "node_modules/@opentelemetry/exporter-metrics-otlp-http": {
- "version": "0.215.0",
- "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-metrics-otlp-http/-/exporter-metrics-otlp-http-0.215.0.tgz",
- "integrity": "sha512-FRydO5j7MWnXK9ghfykKxiSM8I5UeiicK/UNl3/mv86xoEKkb+LKz1I3WXgkuYVOQf22VNqbPO58s2W1mVWtEQ==",
- "license": "Apache-2.0",
- "dependencies": {
- "@opentelemetry/core": "2.7.0",
- "@opentelemetry/otlp-exporter-base": "0.215.0",
- "@opentelemetry/otlp-transformer": "0.215.0",
- "@opentelemetry/resources": "2.7.0",
- "@opentelemetry/sdk-metrics": "2.7.0"
- },
- "engines": {
- "node": "^18.19.0 || >=20.6.0"
- },
- "peerDependencies": {
- "@opentelemetry/api": "^1.3.0"
- }
- },
- "node_modules/@opentelemetry/exporter-metrics-otlp-proto": {
- "version": "0.215.0",
- "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-metrics-otlp-proto/-/exporter-metrics-otlp-proto-0.215.0.tgz",
- "integrity": "sha512-d8/Sys9MtxLbn0S+RE1pUNcuoI9ZyI4SPfOO+yskSEQiPFoKCTMwwthB8MTY4S8qxCBAWyM+P7QMX+vEIT7PZw==",
- "license": "Apache-2.0",
- "dependencies": {
- "@opentelemetry/core": "2.7.0",
- "@opentelemetry/exporter-metrics-otlp-http": "0.215.0",
- "@opentelemetry/otlp-exporter-base": "0.215.0",
- "@opentelemetry/otlp-transformer": "0.215.0",
- "@opentelemetry/resources": "2.7.0",
- "@opentelemetry/sdk-metrics": "2.7.0"
- },
- "engines": {
- "node": "^18.19.0 || >=20.6.0"
- },
- "peerDependencies": {
- "@opentelemetry/api": "^1.3.0"
- }
- },
- "node_modules/@opentelemetry/exporter-prometheus": {
- "version": "0.215.0",
- "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-prometheus/-/exporter-prometheus-0.215.0.tgz",
- "integrity": "sha512-7ghCl1G84jccmxG3B8UwUMZ1OlequBzB1jt5tZ4DDiAyVKeA4Roz5D6VK8SQ0ZyBQffVyX/rtXrpVXKVzRCGfg==",
- "license": "Apache-2.0",
- "dependencies": {
- "@opentelemetry/core": "2.7.0",
- "@opentelemetry/resources": "2.7.0",
- "@opentelemetry/sdk-metrics": "2.7.0",
- "@opentelemetry/semantic-conventions": "^1.29.0"
- },
- "engines": {
- "node": "^18.19.0 || >=20.6.0"
- },
- "peerDependencies": {
- "@opentelemetry/api": "^1.3.0"
- }
- },
- "node_modules/@opentelemetry/exporter-trace-otlp-grpc": {
- "version": "0.215.0",
- "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-trace-otlp-grpc/-/exporter-trace-otlp-grpc-0.215.0.tgz",
- "integrity": "sha512-+SuWfPFVjPTvHJhlzTCBetLsPVu86xSFPR3fv8TN+H7lpe5aZzF96TUsfMHDR0lwpIwlJpG57CJnGalIfrpXkg==",
- "license": "Apache-2.0",
- "dependencies": {
- "@grpc/grpc-js": "^1.14.3",
- "@opentelemetry/core": "2.7.0",
- "@opentelemetry/otlp-exporter-base": "0.215.0",
- "@opentelemetry/otlp-grpc-exporter-base": "0.215.0",
- "@opentelemetry/otlp-transformer": "0.215.0",
- "@opentelemetry/resources": "2.7.0",
- "@opentelemetry/sdk-trace-base": "2.7.0"
- },
- "engines": {
- "node": "^18.19.0 || >=20.6.0"
- },
- "peerDependencies": {
- "@opentelemetry/api": "^1.3.0"
- }
- },
- "node_modules/@opentelemetry/exporter-trace-otlp-http": {
- "version": "0.215.0",
- "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-trace-otlp-http/-/exporter-trace-otlp-http-0.215.0.tgz",
- "integrity": "sha512-k4J9ISeGpb0Bm/wCrlcrbroMFTkiWMrdhNxQGrlktxLy127Yzd4/7nrTawn5d/ApktYTknvdixsE6++34Qfi1w==",
- "license": "Apache-2.0",
- "dependencies": {
- "@opentelemetry/core": "2.7.0",
- "@opentelemetry/otlp-exporter-base": "0.215.0",
- "@opentelemetry/otlp-transformer": "0.215.0",
- "@opentelemetry/resources": "2.7.0",
- "@opentelemetry/sdk-trace-base": "2.7.0"
- },
- "engines": {
- "node": "^18.19.0 || >=20.6.0"
- },
- "peerDependencies": {
- "@opentelemetry/api": "^1.3.0"
- }
- },
- "node_modules/@opentelemetry/exporter-trace-otlp-proto": {
- "version": "0.215.0",
- "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-trace-otlp-proto/-/exporter-trace-otlp-proto-0.215.0.tgz",
- "integrity": "sha512-+QclHuJmlp/I3Z2fNn+j1dAajMjJqJ4Sgo8ajwiK6Tzmg5SNwBGmBX66AZvTLe/3/bc3L7bo90m9gsaJBrzEsA==",
- "license": "Apache-2.0",
- "dependencies": {
- "@opentelemetry/core": "2.7.0",
- "@opentelemetry/otlp-exporter-base": "0.215.0",
- "@opentelemetry/otlp-transformer": "0.215.0",
- "@opentelemetry/resources": "2.7.0",
- "@opentelemetry/sdk-trace-base": "2.7.0"
- },
- "engines": {
- "node": "^18.19.0 || >=20.6.0"
- },
- "peerDependencies": {
- "@opentelemetry/api": "^1.3.0"
- }
- },
- "node_modules/@opentelemetry/exporter-zipkin": {
- "version": "2.7.0",
- "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-zipkin/-/exporter-zipkin-2.7.0.tgz",
- "integrity": "sha512-tbzcYDmZWtX4hgJn15qP7/iYFVd1yzbUloBuSYsQtn0XQTxJsG7vgwkPKEBellriH0XJmlZJxYtWkHpwzHBhaQ==",
- "license": "Apache-2.0",
- "dependencies": {
- "@opentelemetry/core": "2.7.0",
- "@opentelemetry/resources": "2.7.0",
- "@opentelemetry/sdk-trace-base": "2.7.0",
- "@opentelemetry/semantic-conventions": "^1.29.0"
- },
- "engines": {
- "node": "^18.19.0 || >=20.6.0"
- },
- "peerDependencies": {
- "@opentelemetry/api": "^1.0.0"
- }
- },
- "node_modules/@opentelemetry/instrumentation": {
- "version": "0.215.0",
- "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation/-/instrumentation-0.215.0.tgz",
- "integrity": "sha512-SyJONuqypQ2xWdYMy99vF7JhZ2kDTGx4oRmM/jZV+kRtZ96JTnJmEINbIJgHz7Gnhtw0bimHwbPy/pguA5wpPQ==",
- "license": "Apache-2.0",
- "dependencies": {
- "@opentelemetry/api-logs": "0.215.0",
- "import-in-the-middle": "^3.0.0",
- "require-in-the-middle": "^8.0.0"
- },
- "engines": {
- "node": "^18.19.0 || >=20.6.0"
- },
- "peerDependencies": {
- "@opentelemetry/api": "^1.3.0"
- }
- },
- "node_modules/@opentelemetry/instrumentation-http": {
- "version": "0.215.0",
- "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-http/-/instrumentation-http-0.215.0.tgz",
- "integrity": "sha512-ip9iNoRRVxDyP8LVfdqqI6OwbOwzxTl4SaP1WDKJq0sDsgpOr7rIOFj7gV8yKl4F5PdDOUYy8VqdgIOWZRlGBw==",
- "license": "Apache-2.0",
- "dependencies": {
- "@opentelemetry/core": "2.7.0",
- "@opentelemetry/instrumentation": "0.215.0",
- "@opentelemetry/semantic-conventions": "^1.29.0",
- "forwarded-parse": "2.1.2"
- },
- "engines": {
- "node": "^18.19.0 || >=20.6.0"
- },
- "peerDependencies": {
- "@opentelemetry/api": "^1.3.0"
- }
- },
- "node_modules/@opentelemetry/instrumentation-undici": {
- "version": "0.25.0",
- "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-undici/-/instrumentation-undici-0.25.0.tgz",
- "integrity": "sha512-yPc3sZ3gwlxArBoW0LXpyE0GA4gORSajFBuME2jAo3YXgwSMI86SmQwFhYlRlYgx9LPWH8LIMDZ4J7cYFfyaBg==",
- "license": "Apache-2.0",
- "dependencies": {
- "@opentelemetry/core": "^2.0.0",
- "@opentelemetry/instrumentation": "^0.215.0",
- "@opentelemetry/semantic-conventions": "^1.24.0"
- },
- "engines": {
- "node": "^18.19.0 || >=20.6.0"
- },
- "peerDependencies": {
- "@opentelemetry/api": "^1.7.0"
- }
- },
- "node_modules/@opentelemetry/otlp-exporter-base": {
- "version": "0.215.0",
- "resolved": "https://registry.npmjs.org/@opentelemetry/otlp-exporter-base/-/otlp-exporter-base-0.215.0.tgz",
- "integrity": "sha512-lHrfbmeLSmesGSkkHiqDwOzfaEMSWXdc7q6UoLfbW8byONCb+bE/zkAr0kapN4US1baT/2nbpNT7Cn9XoB96Vg==",
- "license": "Apache-2.0",
- "dependencies": {
- "@opentelemetry/core": "2.7.0",
- "@opentelemetry/otlp-transformer": "0.215.0"
- },
- "engines": {
- "node": "^18.19.0 || >=20.6.0"
- },
- "peerDependencies": {
- "@opentelemetry/api": "^1.3.0"
- }
- },
- "node_modules/@opentelemetry/otlp-grpc-exporter-base": {
- "version": "0.215.0",
- "resolved": "https://registry.npmjs.org/@opentelemetry/otlp-grpc-exporter-base/-/otlp-grpc-exporter-base-0.215.0.tgz",
- "integrity": "sha512-WkuHkUrhwNxTKrm7Xuf6S+HmLNbk2T8S2YiZhN606RfgetSQb9xLp4NizWLwXvw63uxGsBaK262dirFO2yht2g==",
- "license": "Apache-2.0",
- "dependencies": {
- "@grpc/grpc-js": "^1.14.3",
- "@opentelemetry/core": "2.7.0",
- "@opentelemetry/otlp-exporter-base": "0.215.0",
- "@opentelemetry/otlp-transformer": "0.215.0"
- },
- "engines": {
- "node": "^18.19.0 || >=20.6.0"
- },
- "peerDependencies": {
- "@opentelemetry/api": "^1.3.0"
- }
- },
- "node_modules/@opentelemetry/otlp-transformer": {
- "version": "0.215.0",
- "resolved": "https://registry.npmjs.org/@opentelemetry/otlp-transformer/-/otlp-transformer-0.215.0.tgz",
- "integrity": "sha512-cWwBvaV+vkXHkSoTYR8hGw+AW03UlgTr6xtrUKOMeum3T+8vffYXIfXu6KY5MLu8O9QtoBKqaKWw9I5xoOepng==",
- "license": "Apache-2.0",
- "dependencies": {
- "@opentelemetry/api-logs": "0.215.0",
- "@opentelemetry/core": "2.7.0",
- "@opentelemetry/resources": "2.7.0",
- "@opentelemetry/sdk-logs": "0.215.0",
- "@opentelemetry/sdk-metrics": "2.7.0",
- "@opentelemetry/sdk-trace-base": "2.7.0",
- "protobufjs": "^8.0.1"
- },
- "engines": {
- "node": "^18.19.0 || >=20.6.0"
- },
- "peerDependencies": {
- "@opentelemetry/api": "^1.3.0"
- }
- },
- "node_modules/@opentelemetry/propagator-b3": {
- "version": "2.7.0",
- "resolved": "https://registry.npmjs.org/@opentelemetry/propagator-b3/-/propagator-b3-2.7.0.tgz",
- "integrity": "sha512-HNm+tdXY5i8dzAo4YankchNWdZ4Z1Boop7lhbb3wltWT0MwEMo0QADRJwrF83pXEeDT+5Bmq4J8sStFaUywE3g==",
- "license": "Apache-2.0",
- "dependencies": {
- "@opentelemetry/core": "2.7.0"
- },
- "engines": {
- "node": "^18.19.0 || >=20.6.0"
- },
- "peerDependencies": {
- "@opentelemetry/api": ">=1.0.0 <1.10.0"
- }
- },
- "node_modules/@opentelemetry/propagator-jaeger": {
- "version": "2.7.0",
- "resolved": "https://registry.npmjs.org/@opentelemetry/propagator-jaeger/-/propagator-jaeger-2.7.0.tgz",
- "integrity": "sha512-lKMAjekRkFYWrjmPTaxUJt+V8Mr1iB94sP3HDZZCmdZ/LUV/wtqAGqXhgnkIbdlnWxxvEs9MGEIMdJC+xObMFg==",
- "license": "Apache-2.0",
- "dependencies": {
- "@opentelemetry/core": "2.7.0"
- },
- "engines": {
- "node": "^18.19.0 || >=20.6.0"
- },
- "peerDependencies": {
- "@opentelemetry/api": ">=1.0.0 <1.10.0"
- }
- },
- "node_modules/@opentelemetry/resources": {
- "version": "2.7.0",
- "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-2.7.0.tgz",
- "integrity": "sha512-K+oi0hNMv94EpZbnW3eyu2X6SGVpD3O5DhG2NIp65Hc7lhAj9brRXTAVzh3wB82+q3ThakEf7Zd7RsFUqcTc7A==",
- "license": "Apache-2.0",
- "dependencies": {
- "@opentelemetry/core": "2.7.0",
- "@opentelemetry/semantic-conventions": "^1.29.0"
- },
- "engines": {
- "node": "^18.19.0 || >=20.6.0"
- },
- "peerDependencies": {
- "@opentelemetry/api": ">=1.3.0 <1.10.0"
- }
- },
- "node_modules/@opentelemetry/sdk-logs": {
- "version": "0.215.0",
- "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-logs/-/sdk-logs-0.215.0.tgz",
- "integrity": "sha512-y3ucOmphzc4vgBTyIGchs+N/1rkACmoka8QalT2z1LBNM232Z17zMYayHcMl+dgMoOadZ0b72UZv7mDtqy1cFA==",
- "license": "Apache-2.0",
- "dependencies": {
- "@opentelemetry/api-logs": "0.215.0",
- "@opentelemetry/core": "2.7.0",
- "@opentelemetry/resources": "2.7.0",
- "@opentelemetry/semantic-conventions": "^1.29.0"
- },
- "engines": {
- "node": "^18.19.0 || >=20.6.0"
- },
- "peerDependencies": {
- "@opentelemetry/api": ">=1.4.0 <1.10.0"
- }
- },
- "node_modules/@opentelemetry/sdk-metrics": {
- "version": "2.7.0",
- "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-metrics/-/sdk-metrics-2.7.0.tgz",
- "integrity": "sha512-Vd7h95av/LYRsAVN7wbprvvJnHkq7swMXAo7Uad0Uxf9jl6NSReLa0JNivrcc5BVIx/vl2t+cgdVQQbnVhsR9w==",
- "license": "Apache-2.0",
- "dependencies": {
- "@opentelemetry/core": "2.7.0",
- "@opentelemetry/resources": "2.7.0"
- },
- "engines": {
- "node": "^18.19.0 || >=20.6.0"
- },
- "peerDependencies": {
- "@opentelemetry/api": ">=1.9.0 <1.10.0"
- }
- },
- "node_modules/@opentelemetry/sdk-node": {
- "version": "0.215.0",
- "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-node/-/sdk-node-0.215.0.tgz",
- "integrity": "sha512-YunKvZOMhYNMBJ66YRjbGShuoV/w1y21U7MGPRx0iPJenPszOddtYEQFJv8piAEOn94BUFIfJHtHjptrHsGiIA==",
- "license": "Apache-2.0",
- "dependencies": {
- "@opentelemetry/api-logs": "0.215.0",
- "@opentelemetry/configuration": "0.215.0",
- "@opentelemetry/context-async-hooks": "2.7.0",
- "@opentelemetry/core": "2.7.0",
- "@opentelemetry/exporter-logs-otlp-grpc": "0.215.0",
- "@opentelemetry/exporter-logs-otlp-http": "0.215.0",
- "@opentelemetry/exporter-logs-otlp-proto": "0.215.0",
- "@opentelemetry/exporter-metrics-otlp-grpc": "0.215.0",
- "@opentelemetry/exporter-metrics-otlp-http": "0.215.0",
- "@opentelemetry/exporter-metrics-otlp-proto": "0.215.0",
- "@opentelemetry/exporter-prometheus": "0.215.0",
- "@opentelemetry/exporter-trace-otlp-grpc": "0.215.0",
- "@opentelemetry/exporter-trace-otlp-http": "0.215.0",
- "@opentelemetry/exporter-trace-otlp-proto": "0.215.0",
- "@opentelemetry/exporter-zipkin": "2.7.0",
- "@opentelemetry/instrumentation": "0.215.0",
- "@opentelemetry/otlp-exporter-base": "0.215.0",
- "@opentelemetry/propagator-b3": "2.7.0",
- "@opentelemetry/propagator-jaeger": "2.7.0",
- "@opentelemetry/resources": "2.7.0",
- "@opentelemetry/sdk-logs": "0.215.0",
- "@opentelemetry/sdk-metrics": "2.7.0",
- "@opentelemetry/sdk-trace-base": "2.7.0",
- "@opentelemetry/sdk-trace-node": "2.7.0",
- "@opentelemetry/semantic-conventions": "^1.29.0"
- },
- "engines": {
- "node": "^18.19.0 || >=20.6.0"
- },
- "peerDependencies": {
- "@opentelemetry/api": ">=1.3.0 <1.10.0"
- }
- },
- "node_modules/@opentelemetry/sdk-trace-base": {
- "version": "2.7.0",
- "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-2.7.0.tgz",
- "integrity": "sha512-Yg9zEXJB50DLVLpsKPk7NmNqlPlS+OvqhJGh0A8oawIOTPOwlm4eXs9BMJV7L79lvEwI+dWtAj+YjTyddV336A==",
- "license": "Apache-2.0",
- "dependencies": {
- "@opentelemetry/core": "2.7.0",
- "@opentelemetry/resources": "2.7.0",
- "@opentelemetry/semantic-conventions": "^1.29.0"
- },
- "engines": {
- "node": "^18.19.0 || >=20.6.0"
- },
- "peerDependencies": {
- "@opentelemetry/api": ">=1.3.0 <1.10.0"
- }
- },
- "node_modules/@opentelemetry/sdk-trace-node": {
- "version": "2.7.0",
- "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-node/-/sdk-trace-node-2.7.0.tgz",
- "integrity": "sha512-RrFHOXw0IYp/OThew6QORdybnnLitUAUMCJKcQNBYS0hDkCYarO2vTkVxfrGxCIqd5XHSMvbCpBd/T8ZMw8oSg==",
- "license": "Apache-2.0",
- "dependencies": {
- "@opentelemetry/context-async-hooks": "2.7.0",
- "@opentelemetry/core": "2.7.0",
- "@opentelemetry/sdk-trace-base": "2.7.0"
- },
- "engines": {
- "node": "^18.19.0 || >=20.6.0"
- },
- "peerDependencies": {
- "@opentelemetry/api": ">=1.0.0 <1.10.0"
- }
- },
- "node_modules/@opentelemetry/semantic-conventions": {
- "version": "1.40.0",
- "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.40.0.tgz",
- "integrity": "sha512-cifvXDhcqMwwTlTK04GBNeIe7yyo28Mfby85QXFe1Yk8nmi36Ab/5UQwptOx84SsoGNRg+EVSjwzfSZMy6pmlw==",
- "license": "Apache-2.0",
- "engines": {
- "node": ">=14"
- }
- },
- "node_modules/@protobufjs/aspromise": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz",
- "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==",
- "license": "BSD-3-Clause"
- },
- "node_modules/@protobufjs/base64": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz",
- "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==",
- "license": "BSD-3-Clause"
- },
- "node_modules/@protobufjs/codegen": {
- "version": "2.0.4",
- "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz",
- "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==",
- "license": "BSD-3-Clause"
- },
- "node_modules/@protobufjs/eventemitter": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz",
- "integrity": "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==",
- "license": "BSD-3-Clause"
- },
- "node_modules/@protobufjs/fetch": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz",
- "integrity": "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==",
- "license": "BSD-3-Clause",
- "dependencies": {
- "@protobufjs/aspromise": "^1.1.1",
- "@protobufjs/inquire": "^1.1.0"
- }
- },
- "node_modules/@protobufjs/float": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz",
- "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==",
- "license": "BSD-3-Clause"
- },
- "node_modules/@protobufjs/inquire": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz",
- "integrity": "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==",
- "license": "BSD-3-Clause"
- },
- "node_modules/@protobufjs/path": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz",
- "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==",
- "license": "BSD-3-Clause"
- },
- "node_modules/@protobufjs/pool": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz",
- "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==",
- "license": "BSD-3-Clause"
- },
- "node_modules/@protobufjs/utf8": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz",
- "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==",
- "license": "BSD-3-Clause"
- },
"node_modules/@smithy/chunked-blob-reader": {
"version": "5.2.2",
"resolved": "https://registry.npmjs.org/@smithy/chunked-blob-reader/-/chunked-blob-reader-5.2.2.tgz",
@@ -2852,15 +2178,6 @@
"node": ">= 10"
}
},
- "node_modules/@types/node": {
- "version": "25.6.0",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-25.6.0.tgz",
- "integrity": "sha512-+qIYRKdNYJwY3vRCZMdJbPLJAtGjQBudzZzdzwQYkEPQd+PJGixUL5QfvCLDaULoLv+RhT3LDkwEfKaAkgSmNQ==",
- "license": "MIT",
- "dependencies": {
- "undici-types": "~7.19.0"
- }
- },
"node_modules/abbrev": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/abbrev/-/abbrev-3.0.1.tgz",
@@ -2870,27 +2187,6 @@
"node": "^18.17.0 || >=20.5.0"
}
},
- "node_modules/acorn": {
- "version": "8.16.0",
- "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz",
- "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==",
- "license": "MIT",
- "bin": {
- "acorn": "bin/acorn"
- },
- "engines": {
- "node": ">=0.4.0"
- }
- },
- "node_modules/acorn-import-attributes": {
- "version": "1.9.5",
- "resolved": "https://registry.npmjs.org/acorn-import-attributes/-/acorn-import-attributes-1.9.5.tgz",
- "integrity": "sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ==",
- "license": "MIT",
- "peerDependencies": {
- "acorn": "^8"
- }
- },
"node_modules/agent-base": {
"version": "7.1.4",
"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz",
@@ -3290,12 +2586,6 @@
"node": ">=10"
}
},
- "node_modules/cjs-module-lexer": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-2.2.0.tgz",
- "integrity": "sha512-4bHTS2YuzUvtoLjdy+98ykbNB5jS0+07EvFNXerqZQJ89F7DI6ET7OQo/HJuW6K0aVsKA9hj9/RVb2kQVOrPDQ==",
- "license": "MIT"
- },
"node_modules/clean-stack": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz",
@@ -3318,70 +2608,6 @@
"node": ">=8"
}
},
- "node_modules/cliui": {
- "version": "8.0.1",
- "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz",
- "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==",
- "license": "ISC",
- "dependencies": {
- "string-width": "^4.2.0",
- "strip-ansi": "^6.0.1",
- "wrap-ansi": "^7.0.0"
- },
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/cliui/node_modules/ansi-styles": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
- "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
- "license": "MIT",
- "dependencies": {
- "color-convert": "^2.0.1"
- },
- "engines": {
- "node": ">=8"
- },
- "funding": {
- "url": "https://github.com/chalk/ansi-styles?sponsor=1"
- }
- },
- "node_modules/cliui/node_modules/color-convert": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
- "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
- "license": "MIT",
- "dependencies": {
- "color-name": "~1.1.4"
- },
- "engines": {
- "node": ">=7.0.0"
- }
- },
- "node_modules/cliui/node_modules/color-name": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
- "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
- "license": "MIT"
- },
- "node_modules/cliui/node_modules/wrap-ansi": {
- "version": "7.0.0",
- "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
- "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
- "license": "MIT",
- "dependencies": {
- "ansi-styles": "^4.0.0",
- "string-width": "^4.1.0",
- "strip-ansi": "^6.0.0"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
- }
- },
"node_modules/color-convert": {
"version": "1.9.3",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
@@ -3878,15 +3104,6 @@
"@esbuild/win32-x64": "0.28.0"
}
},
- "node_modules/escalade": {
- "version": "3.2.0",
- "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz",
- "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==",
- "license": "MIT",
- "engines": {
- "node": ">=6"
- }
- },
"node_modules/escape-string-regexp": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
@@ -4130,12 +3347,6 @@
"node": ">= 0.12"
}
},
- "node_modules/forwarded-parse": {
- "version": "2.1.2",
- "resolved": "https://registry.npmjs.org/forwarded-parse/-/forwarded-parse-2.1.2.tgz",
- "integrity": "sha512-alTFZZQDKMporBH77856pXgzhEzaUVmLCDk+egLgIgHst3Tpndzz8MnKe+GzRJRfvVdn69HhpW7cmXzvtLvJAw==",
- "license": "MIT"
- },
"node_modules/from2": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz",
@@ -4294,15 +3505,6 @@
"node": "^12.13.0 || ^14.15.0 || >=16.0.0"
}
},
- "node_modules/get-caller-file": {
- "version": "2.0.5",
- "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
- "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
- "license": "ISC",
- "engines": {
- "node": "6.* || 8.* || >= 10.*"
- }
- },
"node_modules/get-stream": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz",
@@ -4487,21 +3689,6 @@
"dev": true,
"license": "MIT"
},
- "node_modules/import-in-the-middle": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/import-in-the-middle/-/import-in-the-middle-3.0.1.tgz",
- "integrity": "sha512-pYkiyXVL2Mf3pozdlDGV6NAObxQx13Ae8knZk1UJRJ6uRW/ZRmTGHlQYtrsSl7ubuE5F8CD1z+s1n4RHNuTtuA==",
- "license": "Apache-2.0",
- "dependencies": {
- "acorn": "^8.15.0",
- "acorn-import-attributes": "^1.9.5",
- "cjs-module-lexer": "^2.2.0",
- "module-details-from-path": "^1.0.4"
- },
- "engines": {
- "node": ">=18"
- }
- },
"node_modules/imurmurhash": {
"version": "0.1.4",
"resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
@@ -4761,12 +3948,6 @@
"uc.micro": "^2.0.0"
}
},
- "node_modules/lodash.camelcase": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz",
- "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==",
- "license": "MIT"
- },
"node_modules/log-symbols": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-3.0.0.tgz",
@@ -4799,12 +3980,6 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/long": {
- "version": "5.3.2",
- "resolved": "https://registry.npmjs.org/long/-/long-5.3.2.tgz",
- "integrity": "sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==",
- "license": "Apache-2.0"
- },
"node_modules/lru-cache": {
"version": "7.18.3",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz",
@@ -5104,12 +4279,6 @@
"node": ">=10"
}
},
- "node_modules/module-details-from-path": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/module-details-from-path/-/module-details-from-path-1.0.4.tgz",
- "integrity": "sha512-EGWKgxALGMgzvxYF1UyGTy0HXX/2vHLkw6+NvDKW2jypWbHpjQuj4UMcqQWXHERJhVGKikolT06G3bcKe4fi7w==",
- "license": "MIT"
- },
"node_modules/move-concurrently": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz",
@@ -5587,30 +4756,6 @@
"node": ">=10"
}
},
- "node_modules/protobufjs": {
- "version": "8.0.1",
- "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-8.0.1.tgz",
- "integrity": "sha512-NWWCCscLjs+cOKF/s/XVNFRW7Yih0fdH+9brffR5NZCy8k42yRdl5KlWKMVXuI1vfCoy4o1z80XR/W/QUb3V3w==",
- "hasInstallScript": true,
- "license": "BSD-3-Clause",
- "dependencies": {
- "@protobufjs/aspromise": "^1.1.2",
- "@protobufjs/base64": "^1.1.2",
- "@protobufjs/codegen": "^2.0.4",
- "@protobufjs/eventemitter": "^1.1.0",
- "@protobufjs/fetch": "^1.1.0",
- "@protobufjs/float": "^1.0.2",
- "@protobufjs/inquire": "^1.1.0",
- "@protobufjs/path": "^1.1.2",
- "@protobufjs/pool": "^1.1.0",
- "@protobufjs/utf8": "^1.1.0",
- "@types/node": ">=13.7.0",
- "long": "^5.0.0"
- },
- "engines": {
- "node": ">=12.0.0"
- }
- },
"node_modules/psl": {
"version": "1.15.0",
"resolved": "https://registry.npmjs.org/psl/-/psl-1.15.0.tgz",
@@ -6000,28 +5145,6 @@
"uuid": "bin/uuid"
}
},
- "node_modules/require-directory": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
- "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==",
- "license": "MIT",
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/require-in-the-middle": {
- "version": "8.0.1",
- "resolved": "https://registry.npmjs.org/require-in-the-middle/-/require-in-the-middle-8.0.1.tgz",
- "integrity": "sha512-QT7FVMXfWOYFbeRBF6nu+I6tr2Tf3u0q8RIEjNob/heKY/nh7drD/k7eeMFmSQgnTtCzLDcCu/XEnpW2wk4xCQ==",
- "license": "MIT",
- "dependencies": {
- "debug": "^4.3.5",
- "module-details-from-path": "^1.0.3"
- },
- "engines": {
- "node": ">=9.3.0 || >=8.10.0 <9.0.0"
- }
- },
"node_modules/restore-cursor": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz",
@@ -6824,12 +5947,6 @@
"node": ">=0.8.0"
}
},
- "node_modules/undici-types": {
- "version": "7.19.2",
- "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.19.2.tgz",
- "integrity": "sha512-qYVnV5OEm2AW8cJMCpdV20CDyaN3g0AjDlOGf1OW4iaDEx8MwdtChUp4zu4H0VP3nDRF/8RKWH+IPp9uW0YGZg==",
- "license": "MIT"
- },
"node_modules/unique-filename": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-2.0.1.tgz",
@@ -7062,6 +6179,7 @@
"version": "2.8.3",
"resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.3.tgz",
"integrity": "sha512-AvbaCLOO2Otw/lW5bmh9d/WEdcDFdQp2Z2ZUH3pX9U2ihyUY0nvLv7J6TrWowklRGPYbB/IuIMfYgxaCPg5Bpg==",
+ "dev": true,
"license": "ISC",
"bin": {
"yaml": "bin.mjs"
@@ -7073,42 +6191,6 @@
"url": "https://github.com/sponsors/eemeli"
}
},
- "node_modules/yargs": {
- "version": "17.7.2",
- "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz",
- "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==",
- "license": "MIT",
- "dependencies": {
- "cliui": "^8.0.1",
- "escalade": "^3.1.1",
- "get-caller-file": "^2.0.5",
- "require-directory": "^2.1.1",
- "string-width": "^4.2.3",
- "y18n": "^5.0.5",
- "yargs-parser": "^21.1.1"
- },
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/yargs-parser": {
- "version": "21.1.1",
- "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz",
- "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==",
- "license": "ISC",
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/yargs/node_modules/y18n": {
- "version": "5.0.8",
- "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
- "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==",
- "license": "ISC",
- "engines": {
- "node": ">=10"
- }
- },
"node_modules/zen-observable": {
"version": "0.8.15",
"resolved": "https://registry.npmjs.org/zen-observable/-/zen-observable-0.8.15.tgz",
diff --git a/package.json b/package.json
@@ -5,8 +5,8 @@
"main": "index.js",
"type": "module",
"scripts": {
- "build": "npx spago build && npx esbuild output/Main/index.js --bundle --platform=node --format=esm --footer:js='main();' --outfile=server.js --external:http --external:https --external:dotenv --external:url --external:duckdb --external:@aws-sdk/client-s3 --external:prom-client --external:@opentelemetry/* && elm make src/Client.elm --output=client.js",
- "release": "npx spago build && npx purs-backend-es build && npx esbuild output-es/Main/index.js --bundle --platform=node --format=esm --footer:js='main();' --outfile=server.js --external:http --external:https --external:dotenv --external:url --external:duckdb --external:@aws-sdk/client-s3 --external:prom-client --external:@opentelemetry/* && elm make src/Client.elm --optimize --output=client.js && npx uglifyjs client.js --compress \"pure_funcs=[F2,F3,F4,F5,F6,F7,F8,F9,A2,A3,A4,A5,A6,A7,A8,A9],pure_getters,keep_fargs=false,unsafe_comps,unsafe\" | npx uglifyjs --mangle --output client.js",
+ "build": "npx spago build && npx esbuild output/Main/index.js --bundle --platform=node --format=esm --footer:js='main();' --outfile=server.js --external:http --external:https --external:dotenv --external:url --external:duckdb --external:@aws-sdk/client-s3 --external:prom-client && elm make src/Client.elm --output=client.js",
+ "release": "npx spago build && npx purs-backend-es build && npx esbuild output-es/Main/index.js --bundle --platform=node --format=esm --footer:js='main();' --outfile=server.js --external:http --external:https --external:dotenv --external:url --external:duckdb --external:@aws-sdk/client-s3 --external:prom-client && elm make src/Client.elm --optimize --output=client.js && npx uglifyjs client.js --compress \"pure_funcs=[F2,F3,F4,F5,F6,F7,F8,F9,A2,A3,A4,A5,A6,A7,A8,A9],pure_getters,keep_fargs=false,unsafe_comps,unsafe\" | npx uglifyjs --mangle --output client.js",
"test": "npx spago test",
"tidy": "purs-tidy format-in-place src/**/*.purs"
},
@@ -23,11 +23,6 @@
},
"dependencies": {
"@aws-sdk/client-s3": "^3.1029.0",
- "@opentelemetry/api": "^1.9.1",
- "@opentelemetry/exporter-trace-otlp-http": "^0.215.0",
- "@opentelemetry/instrumentation-http": "^0.215.0",
- "@opentelemetry/instrumentation-undici": "^0.25.0",
- "@opentelemetry/sdk-node": "^0.215.0",
"dotenv": "^17.4.1",
"duckdb": "^1.4.4",
"prom-client": "^15.1.3"
diff --git a/src/Main.purs b/src/Main.purs
@@ -357,7 +357,7 @@ handleRequest metricsEnabled contexts req res = do
"/cover" ->
withUser url \ctx -> serveCover ctx.config ctx.slug url res
"/similar" ->
- withUser url \ctx -> serveSimilar ctx.config url res
+ withUser url \ctx -> serveSimilar ctx.slug ctx.config url res
"/healthz" ->
withUser url \ctx -> serveHealthz ctx.conn res
_ ->
@@ -660,11 +660,12 @@ serveError res statusCode statusName message = do
void $ writeString w UTF8 (statusName <> ": " <> message)
end w
-fetchCosineSimilar :: UserConfig -> String -> Aff String
-fetchCosineSimilar cfg query = do
+fetchCosineSimilar :: String -> UserConfig -> String -> Aff String
+fetchCosineSimilar slug cfg query = do
let apiKey = fromMaybe "" cfg.cosineApiKey
if apiKey == "" then do
Log.warn "cosineApiKey not configured for similar tracks"
+ liftEffect $ Metrics.incCosineRequest slug "not_configured"
pure "{\"data\":{\"similar_tracks\":[]},\"success\":true}"
else do
let headers = { "User-Agent": "corpus/1.0 +https://codeberg.org/mtmn/corpus", "Authorization": "Bearer " <> apiKey }
@@ -672,14 +673,17 @@ fetchCosineSimilar cfg query = do
Log.info $ "Cosine Club: searching for: " <> query
searchResult <- try $ fetch searchUrl { method: GET, headers: headers }
case searchResult of
- Left err ->
+ Left err -> do
+ liftEffect $ Metrics.incCosineRequest slug "error"
throwError err
Right searchRes ->
if searchRes.status == 429 then do
Log.warn "Cosine Club: rate limited on search"
+ liftEffect $ Metrics.incCosineRequest slug "rate_limited"
throwError (Exception.error "Rate limit exceeded")
else if searchRes.status /= 200 then do
Log.warn $ "Cosine Club: search returned " <> show searchRes.status
+ liftEffect $ Metrics.incCosineRequest slug "error"
throwError (Exception.error "Search API error")
else do
searchBody <- searchRes.text
@@ -694,22 +698,27 @@ fetchCosineSimilar cfg query = do
case mTrackId of
Nothing -> do
Log.info $ "Cosine Club: track not indexed: " <> query
+ liftEffect $ Metrics.incCosineRequest slug "not_indexed"
pure "{\"data\":{\"similar_tracks\":[]},\"success\":true}"
Just trackId -> do
let similarUrl = "https://cosine.club/api/v1/tracks/" <> trackId <> "/similar?limit=10"
Log.info $ "Cosine Club: fetching similar for ID " <> trackId
similarResult <- try $ fetch similarUrl { method: GET, headers: headers }
case similarResult of
- Left err ->
+ Left err -> do
+ liftEffect $ Metrics.incCosineRequest slug "error"
throwError err
Right similarRes ->
if similarRes.status == 429 then do
Log.warn "Cosine Club: rate limited on similar"
+ liftEffect $ Metrics.incCosineRequest slug "rate_limited"
throwError (Exception.error "Rate limit exceeded")
else if similarRes.status /= 200 then do
Log.warn $ "Cosine Club: similar API returned " <> show similarRes.status
+ liftEffect $ Metrics.incCosineRequest slug "error"
throwError (Exception.error "Similar API error")
- else
+ else do
+ liftEffect $ Metrics.incCosineRequest slug "success"
similarRes.text
serveStats :: Connection -> URL -> Response -> Effect Unit
@@ -729,8 +738,8 @@ serveStats db url res = do
void $ writeString w UTF8 responseBody
end w
-serveSimilar :: UserConfig -> URL -> Response -> Effect Unit
-serveSimilar cfg url res = do
+serveSimilar :: String -> UserConfig -> URL -> Response -> Effect Unit
+serveSimilar slug cfg url res = do
setHeader "Content-Type" "application/json" (toOutgoingMessage res)
launchAff_ do
let artist = fromMaybe "" (getQueryParam "artist" url)
@@ -739,7 +748,7 @@ serveSimilar cfg url res = do
liftEffect $ serveBadRequest res "Artist and track parameters are required"
else do
let query = artist <> " - " <> track
- result <- try $ fetchCosineSimilar cfg query
+ result <- try $ fetchCosineSimilar slug cfg query
case result of
Left err -> do
diff --git a/src/Metrics.js b/src/Metrics.js
@@ -5,17 +5,6 @@ import {
Histogram,
collectDefaultMetrics,
} from "prom-client";
-import { NodeSDK } from "@opentelemetry/sdk-node";
-import { OTLPTraceExporter } from "@opentelemetry/exporter-trace-otlp-http";
-import { HttpInstrumentation } from "@opentelemetry/instrumentation-http";
-import { UndiciInstrumentation } from "@opentelemetry/instrumentation-undici";
-import {
- trace,
- context,
- propagation,
- SpanKind,
- SpanStatusCode,
-} from "@opentelemetry/api";
// ---------------------------------------------------------------------------
// Prometheus metrics — only active when METRICS_ENABLED=true
@@ -82,6 +71,13 @@ const makeActiveMetrics = () => {
registers: [registry],
});
+ const cosineRequestsTotal = new Counter({
+ name: "corpus_cosine_requests_total",
+ help: "Total Cosine Club API requests by user and result",
+ labelNames: ["user", "result"],
+ registers: [registry],
+ });
+
const dbBackupRunsTotal = new Counter({
name: "corpus_db_backup_runs_total",
help: "Total database backup runs",
@@ -109,6 +105,7 @@ const makeActiveMetrics = () => {
incEnrichmentFetch: (user, source, result) => enrichmentFetchesTotal.inc({ user, source, result }),
setEnrichmentQueueSize: (user, type, size) => enrichmentQueueSize.set({ user, type }, size),
incCoverRequest: (user, source, result) => coverRequestsTotal.inc({ user, source, result }),
+ incCosineRequest: (user, result) => cosineRequestsTotal.inc({ user, result }),
incDbBackupRun: (user, result) => dbBackupRunsTotal.inc({ user, result }),
setDbBackupLastSuccess: (user) => dbBackupLastSuccessSeconds.setToCurrentTime({ user }),
};
@@ -126,6 +123,7 @@ const makeNoOpMetrics = () => ({
incEnrichmentFetch: noOp,
setEnrichmentQueueSize: noOp,
incCoverRequest: noOp,
+ incCosineRequest: noOp,
incDbBackupRun: noOp,
setDbBackupLastSuccess: noOp,
});
@@ -134,58 +132,6 @@ const activeMetrics =
process.env.METRICS_ENABLED === "true" ? makeActiveMetrics() : makeNoOpMetrics();
// ---------------------------------------------------------------------------
-// OpenTelemetry — only active when OTEL_EXPORTER_OTLP_ENDPOINT is set
-// ---------------------------------------------------------------------------
-
-const makeTracer = () => {
- if (!process.env.OTEL_EXPORTER_OTLP_ENDPOINT) return null;
- const sdk = new NodeSDK({
- traceExporter: new OTLPTraceExporter(),
- instrumentations: [
- new HttpInstrumentation({
- // Incoming requests are traced manually via wrapRequest below
- ignoreIncomingRequestHook: () => true,
- }),
- new UndiciInstrumentation(),
- ],
- });
- sdk.start();
- const tracer = trace.getTracer(
- process.env.OTEL_SERVICE_NAME || "corpus",
- process.env.npm_package_version,
- );
- process.on("SIGTERM", () => sdk.shutdown().finally(() => process.exit(0)));
- return tracer;
-};
-
-const tracer = makeTracer();
-
-const startHttpSpan = (method, path, headers) => {
- if (!tracer) return null;
- const parentCtx = propagation.extract(context.active(), headers);
- return tracer.startSpan(
- `${method} ${path}`,
- {
- kind: SpanKind.SERVER,
- attributes: {
- "http.method": method,
- "http.target": path,
- },
- },
- parentCtx,
- );
-};
-
-const endHttpSpan = (span, statusCode) => {
- if (!span) return;
- span.setAttribute("http.status_code", statusCode);
- span.setStatus({
- code: statusCode >= 500 ? SpanStatusCode.ERROR : SpanStatusCode.OK,
- });
- span.end();
-};
-
-// ---------------------------------------------------------------------------
// Exports
// ---------------------------------------------------------------------------
@@ -198,28 +144,18 @@ export const getMetricsImpl = (onSuccess) => (onError) => () => {
export const getContentType = () => activeMetrics.contentType;
-// Runs `handler` inside the active context of a server span so that any
-// outbound HTTP/fetch calls made during handling automatically become child
-// spans. Attaches a 'finish' listener to record metrics and end the span.
+// Attaches a 'finish' listener to record metrics and log the request.
// logFn: String -> Effect Unit — structured logger called on completion.
-// req: Node IncomingMessage — used to extract W3C trace-context headers.
export const wrapRequest =
- (method) => (path) => (logFn) => (req) => (res) => (handler) => () => {
+ (method) => (path) => (logFn) => (_req) => (res) => (handler) => () => {
const startMs = Date.now();
- const span = startHttpSpan(method, path, req.headers || {});
res.once("finish", () => {
const durationMs = Date.now() - startMs;
const status = res.statusCode || 0;
activeMetrics.recordHttpRequest(method, path, status, durationMs);
- endHttpSpan(span, status);
logFn(`${method} ${path} ${status} ${durationMs}ms`)();
});
- if (span) {
- const ctx = trace.setSpan(context.active(), span);
- context.with(ctx, () => handler());
- } else {
- handler();
- }
+ handler();
};
export const incSyncRuns = (user) => (source) => (result) => () => {
@@ -246,6 +182,10 @@ export const incCoverRequest = (user) => (source) => (result) => () => {
activeMetrics.incCoverRequest(user, source, result);
};
+export const incCosineRequest = (user) => (result) => () => {
+ activeMetrics.incCosineRequest(user, result);
+};
+
export const incDbBackupRun = (user) => (result) => () => {
activeMetrics.incDbBackupRun(user, result);
};
diff --git a/src/Metrics.purs b/src/Metrics.purs
@@ -14,10 +14,7 @@ foreign import getMetricsImpl :: (String -> Effect Unit) -> (String -> Effect Un
-- | The MIME type to use for the /metrics response body.
foreign import getContentType :: Effect String
--- | Runs the given `Effect Unit` handler inside the active context of a server
--- | span, so outbound HTTP/fetch calls become child spans automatically.
--- | Attaches a 'finish' listener to record metrics and end the span.
--- | W3C trace-context headers are extracted from `req` for span parenting.
+-- | Attaches a 'finish' listener to record metrics and log the request.
foreign import wrapRequest :: String -> String -> (String -> Effect Unit) -> IncomingMessage IMServer -> ServerResponse -> Effect Unit -> Effect Unit
-- Sync
@@ -32,6 +29,9 @@ foreign import setEnrichmentQueueSize :: String -> String -> Int -> Effect Unit
-- Cover art
foreign import incCoverRequest :: String -> String -> String -> Effect Unit
+-- Cosine Club
+foreign import incCosineRequest :: String -> String -> Effect Unit
+
-- Database backup
foreign import incDbBackupRun :: String -> String -> Effect Unit
foreign import setDbBackupLastSuccess :: String -> Effect Unit